GithubHelp home page GithubHelp logo

tokiwa-software / fuzion Goto Github PK

View Code? Open in Web Editor NEW
45.0 2.0 8.0 13.6 MB

The Fuzion Language Implementation

Home Page: https://fuzion-lang.dev

License: GNU General Public License v3.0

Java 87.60% Makefile 9.12% Shell 1.07% CSS 0.07% C 2.05% Dockerfile 0.02% JavaScript 0.08%
fuzion programming-language object-oriented-programming safety-critical-systems compiler static-analysis functional-programming

fuzion's Introduction

fuzion logo Fuzion

OpenSSF Scorecard syntax check fz files run tests on linux run tests on macOS run tests on windows

A language with a focus on simplicity, safety and correctness.

Please note that this language is work in progress.



Examples

hello_world is
  # read someone's name from standard input
  #
  get_name String =>
    match (io.stdin.with ()->
             io.buffered.read_line ? str String => str | io.end_of_file => "")
      name String => name
      e error => panic "Could not get your name!"

  # greet someone with the name given
  #
  greet(name String) is
    say "Hello, {name}!"

  # greet the user
  #
  x := greet get_name

  # you can access any feature - even argument features of other features
  # from outside
  #
  say "How are you, {x.name}?"

This hello_world example demonstrates one important concept in Fuzion quite well: Everything is a feature. Features are Fuzion's response to the mess that is created by classes, methods, interfaces, and various other concepts in other programming languages. Since everything is a feature, the programmer does not need to care and the compiler will do this work. As you can see, it is even possible to access the argument features of some feature from outside.

ex_gcd is
  max(a, b i32) i32 =>
    if a > b then a else b

  common_divisors_of(a, b i32) list i32 =>
    x := max a.abs b.abs
    y := 1..x
    y.flat_map i32 (i->
      if (a % i = 0) && (b % i = 0)
        [-i, i]
      else
        [])
     .as_list

  gcd(a, b i32) i32
    pre
      safety: (a != 0 || b != 0)
    post
      safety: a % result = 0
      safety: b % result = 0
      pedantic: (common_divisors_of a b).reduce bool true (tmp,cur->tmp && (gcd.this.result % cur = 0))
  =>
    if b = 0
      a
    else
      gcd b (a % b)


  say (gcd 8 12)
  say (gcd -8 12)
  say (gcd 28 0)

This example implements a simple variant of an algorithm that finds the greatest common divisor of two numbers. However, it also demonstrates one of Fuzion's notable features: design by contract. By specifying pre- and postconditions for features, correctness checks are made possible.

generator_effect is
  # define a generator effect with a yield operation
  #
  gen(T type,
      yield T->unit    # yield is called by code to yield values
      ) : simple_effect is

  # traverse a list and yield the elements
  #
  list.traverse unit =>
    match list.this
      c Cons => (generator_effect.gen A).env.yield c.head; c.tail.traverse
      nil =>

  # bind the yield operation dynamically
  #
  (gen i32 (i -> say "yielded $i")).use (()->
    [0,8,15].as_list.traverse)

Another major concept in Fuzion is that of the algebraic effect - a new approach to encapsulating code with side effects in a safe way.

In the example above, a custom effect has been used to implement a generator with a yield operation. In some other languages, this requires a keyword yield to be provided by the language, but in Fuzion this can be implemented without language support.

If you want to play around with Fuzion, try the interactive tutorial.

Documentation

Check fuzion-lang.dev for language and implementation design.

Clone

Note that the current directory must not contain any spaces.

git clone https://github.com/tokiwa-software/fuzion

Required packages

Linux

For Debian based systems this command should install all requirements:

sudo apt-get install make clang libgc1 libgc-dev openjdk-21-jdk
  • OpenJDK 21, e.g. Adoptium
  • clang LLVM C compiler
  • GNU make
  • libgc

MacOS

This command should install all requirements:

brew install bdw-gc gnu-sed make temurin llvm

Additionally you may need to update your PATH environment variable e.g.:

export PATH:"/usr/local/opt/gnu-sed/libexec/gnubin:/usr/local/opt/gnu-make/libexec/gnubin:$PATH"
  • OpenJDK 21, e.g. Adoptium
  • clang LLVM C compiler
  • GNU make
  • libgc

Windows

Note that building from powershell/cmd does not work yet.

  1. Install chocolatey: chocolatey.org
  2. In Powershell:
    1. choco install git openjdk make msys2 diffutils
    2. [Environment]::SetEnvironmentVariable("Path","c:\tools\msys64\ucrt64\bin;" + $env:Path , "User")
  3. In file C:\tools\msys64\msys2_shell.cmd change line: 'rem set MSYS2_PATH_TYPE=inherit' to 'set MSYS2_PATH_TYPE=inherit'
  4. In msys2 shell (execute C:\tools\msys64\msys2_shell.cmd):
    1. pacman -S mingw-w64-x86_64-clang
    2. make
  5. execute ./bin/windows_install_boehm_gc.sh

Build

Make sure java/javac and clang are in your $PATH.

cd fuzion
make

You should have a folder called build now.

Run

cd build
export PATH=$PWD/bin:$PATH
cd tests/rosettacode_factors_of_an_integer
fz factors

To compile the same example (requires clang C compiler):

fz -c factors
./factors

Have fun!

Install prebuilt

Packaging status

fuzion's People

Contributors

dependabot[bot] avatar fridis avatar maxteufel avatar michaellilltokiwa avatar miclill avatar step-security-bot avatar waelyoussfi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

fuzion's Issues

Syntax of index call using [] and array creation is confusing

Currently, a [1,2,3]is parses as as a call a.index[](1,2,3), even if a itself is a function that should be called with a list or array as an argument, i.e., a([1,2,3]).

To allow both, index calls and newly created arrays as arguments, we could distinguish them by white space as follows: A call to 'index[]' must not have any white space before '[', i.e.,

x := myArray[index]

would set x to the element at index, while

x := findMax [a,b,c]

would pass the array [a,b,c] as an argument to findMax, and the following would cause errors

x := myArray [index]    # error: would be parsed as myArray([index])
x := findMax[a,b,c]     # error: would be parsed as findMax.index[](a,b,c)

Small example using array causes cyclic type inference error in sys.array

 > echo "da := []; for x in da do" | ./build/bin/fz -

/home/fridi/fuzion/work/build/lib/sys/array.fz:46:12: error 1: Illegal forward or cyclic type inference
    get<T> data, i
-----------^
The definition of a field using ":=", or of a feature or function
using "=>" must not create cyclic type dependencies.
Referenced feature: sys.array.data at /home/fridi/fuzion/work/build/lib/sys/array.fz:32:3:
  data := alloc<T> length
--^

one error.

Modifying outer field within inner feature that inherits form outer feature causes broken C code

The following code

 > cat outerAccess.fz 
outerAccess is
  cnt := 0
  Z
  Z is
    B ref : Z { }
    B
    set cnt := cnt + 1

crashes the C backend

 > ./build/bin/fz -c outerAccess.fz 
outerAccess.c:1347:63: error: member reference type 'fzT_outerAccess' (aka 'struct fzT_outerAccess') is not a pointer; did you mean to use '.'?
  fzP_1i32__1infix_wp(fzCur->fields.fzF_0__H_c_outerAccess_o_Z->fzF_0_cnt,1);
                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
                                                              .
outerAccess.c:1349:71: error: member reference type 'fzT_outerAccess' (aka 'struct fzT_outerAccess') is not a pointer; did you mean to use '.'?
  fzM_5 = fzC_1i32__1infix_wp(fzCur->fields.fzF_0__H_c_outerAccess_o_Z->fzF_0_cnt,1);
                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
                                                                      .
outerAccess.c:1353:43: error: member reference type 'fzT_outerAccess' (aka 'struct fzT_outerAccess') is not a pointer; did you mean to use '.'?
  fzCur->fields.fzF_0__H_c_outerAccess_o_Z->fzF_0_cnt = fzM_5;
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
                                          .
outerAccess.c:1353:55: error: expression is not assignable
  fzCur->fields.fzF_0__H_c_outerAccess_o_Z->fzF_0_cnt = fzM_5;
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
4 errors generated.

error 1: C backend: C compiler failed
C compiler call 'clang -O3 -o outerAccess outerAccess.c' failed with exit code '1'

one error.

while it should results in an endless recursion as in the interpreter:

 > ./build/bin/fz outerAccess.fz 

error 1: *** java.lang.StackOverflowError
Call stack:
outerAccess.Z.ref B: outerAccess.fz:6:5:
    B
----^
...  repeated 1790 times  ...

outerAccess.Z: outerAccess.fz:6:5:
    B
----^
outerAccess: outerAccess.fz:3:3:
  Z
--^


*** fatal errors encountered, stopping.

Field initialization produces 'Block must end with a result expression' error

The following example produces unjustified errors:

 > echo "testInit is x := (1 < 1 < 1) || false " | ./build/bin/fz -

-:1:25: error 1: Block must end with a result expression
testInit is x := (1 < 1 < 1) || false 
------------------------^
This block must produce a value since its result is used by the enclosing statement.
Expected type of value: bool


<built-in>: error 2: Block must end with a result expression
This block must produce a value since its result is used by the enclosing statement.
Expected type of value: bool

2 errors.

Declaration of fields of type outcome<string> causes fz to crash with NullPointerException

This small example

 > cat testOutcome.fz
testOutcome is
  x outcome<string> := "string"

Causes a creash

 > ./build/bin/fz testOutcome

error 1: *** java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is null
Call stack:


java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is null
	at dev.flang.be.interpreter.Layout.offset(Layout.java:198)
	at dev.flang.be.interpreter.Interpreter.fieldSlot(Interpreter.java:1010)
	at dev.flang.be.interpreter.Interpreter.setField(Interpreter.java:1164)
	at dev.flang.be.interpreter.Interpreter.setChoiceField(Interpreter.java:843)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:466)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:235)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:262)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:262)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:779)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:679)
	at dev.flang.be.interpreter.Interpreter.run(Interpreter.java:177)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$3(Fuzion.java:484)
	at dev.flang.tools.Tool.run(Tool.java:163)
	at dev.flang.tools.Fuzion.main(Fuzion.java:209)

fz won't work on case insensitive filesystems

copied over from issue #4 created by @Achim63:

Cloning the repository, git puts out the following warning: "warning: the following paths have collided (e.g. case-sensitive paths
on a case-insensitive filesystem) and only one from the same colliding group is in the working tree:

'lib/FALSE.fz'
'lib/false.fz'
'lib/TRUE.fz'
'lib/true.fz'"

In Ubuntu 20 (wsl2 under Windows), this seems to be the cause for lots of errors trying to run an .fz file (": error 1: Internally referenced feature 'TRUE' not found"). Also unzipping the downloaded .zip gives errors on Windows regarding those files.

The case-sensitivity issue will be fixed when the standard types are moved to a global universe.fz (see the comments '# NYI: move to universe.fz' in FALSE.fz and similar files).

getting "java.lang.Error: check-condition failed!" when not using type inference

Code that fails

ex218 is
  intersection (a psSet<string>, b psSet<string>) psSet<string> is
    union := a ⋃ b
    result := union.filter(fun (x string) => a.has x && b.has x)
    result
    
  setOne := psSet<string>.addAll(["eins", "zwei", "drei"])
  setTwo := psSet<string>.addAll(["drei", "vier", "fünf"])
  
  say (intersection(setOne, setTwo))

Code that works

ex218 is
  intersection (a psSet<string>, b psSet<string>)  =>
    union := a ⋃ b
    result := union.filter(fun (x string) => a.has x && b.has x)
    result
    
  setOne := psSet<string>.addAll(["eins", "zwei", "drei"])
  setTwo := psSet<string>.addAll(["drei", "vier", "fünf"])
  
  say (intersection(setOne, setTwo))

Add syntactic sugar for defining fractions

It should be possible for fuzion to infer the type here:

fraction_test is
  x fraction<i64> := 1

Returns this error right now:

/home/not_synced/flang_dev/content/idioms/examples/idiom67ex.fz:2:3: error 1: Incompatible types in assignment
  x fraction<i64> := 1
--^
assignment to field : 'ex67.x'
expected formal type: 'fraction<i64>'
actual type found   : 'i32'
assignable to       : 'i32'
for value assigned  : '1'

one error.

java.lang.ClassCastException: class [B cannot be cast to class [I ([B and [I are in module java.base of loader 'bootstrap')

# http://rosettacode.org/wiki/Faulhaber's_formula
faulhaber_example is
  bernoulli (n i32) fraction<i32>
    pre
      n >= 0
  is
    a := array<fraction<i32>> n+1, fun (i i32) => 1 ⁄ 1
    for m in 0..n do
      set a := a.put m , (1  ⁄  (m + 1))
      for k in m..1 : -1 do
        set a := a.put (k - 1), ((a[k - 1] - a[k]) * (k ⁄ 1))
    if n != 1
      a[0]
    else
      -a[0]
//====
  binomial(n, k i32)
    pre
      n > 0, k >= 0
    => factorial(n) / (factorial(k) * factorial(n-k))
//====
  factorial(x i32)
    pre
      x >= 0
    =>
    res i32 := 1
    for
      i i32 := 1, i+1
    while i<=x
      set res:= res * i;
    res
//====
  faulhaber(p i32) =>
    res:= "$p : "
    q := 1  ⁄  (p+1)
    sign := -1⁄1
    for j in 0..p do
      set sign := sign * (-1⁄1)
      b := binomial(p+1, j)  ⁄  1
      coeff := q * (sign / (1⁄1)) * b * bernoulli(j)
      if coeff != (0⁄1)
        if j = 0
          if coeff = (1⁄1)
          else
            if coeff = (-1⁄1)
              set res:= res + "-"
            else
              set res:= res + "$coeff"
          else
            if coeff = (1⁄1)
              " + "
            else
              if coeff = (-1⁄1)
                set res:= res + " - "
              else
                if coeff > (0⁄1)
                  set res:= res + " + $coeff"
                else
                  minusCoeff := -coeff
                  set res:= res + " - $minusCoeff"
        pwr := p + 1 - j
        if pwr > 1
          set res:= res + "n^$pwr"
        else
          set res:= res + "n"
    res
//====
  for i in 0..11 do
    say(faulhaber(i))

error 1: *** java.lang.ClassCastException: class [B cannot be cast to class [I ([B and [I are in module java.base of loader 'bootstrap')
Call stack:
sys.array<i32>.index [ ]: /home/not_synced/fuzion/build/lib/sys/array.fz:46:5:
    get<T> data, i
----^
ref conststring.index [ ]: /home/not_synced/fuzion/build/lib/array.fz:40:18:
    internalArray[i]
-----------------^
ref array<i32>.ref asStream.next: /home/not_synced/fuzion/build/lib/array.fz:80:45:
    redef next => set x := x + 1; array_this[x-1]
--------------------------------------------^
strings.zeroChar: /home/not_synced/fuzion/build/lib/strings.fz:99:34:
  zeroChar  => "0".utf8.asStream.next
---------------------------------^
ref i32.asString.ref #anonymous0.ref utf8.asStream.ref #anonymous0.next: /home/not_synced/fuzion/build/lib/integer.fz:144:46:
                    r := if (d < 10) strings.zeroChar + d else strings.aChar + d -  10
---------------------------------------------^
strings.ref fromArray.ref utf8.ref asStream.next: /home/not_synced/fuzion/build/lib/strings.fz:84:60:
        redef next    => findNext; set gotNext := false; s.next
-----------------------------------------------------------^
fuzion.std.out.println: /home/not_synced/fuzion/build/lib/fuzion/std/out.fz:34:9:
    for c in s.asString.utf8 do
--------^
say: /home/not_synced/fuzion/build/lib/say.fz:29:29:
say(s ref Object) => stdout.println(s)
----------------------------^
faulhaber_example.#loop4: /home/not_synced/flang_dev/content/examples/examples/faulhaber.fz:69:5:
    say(faulhaber(i))
----^
faulhaber_example: /home/not_synced/flang_dev/content/examples/examples/faulhaber.fz:68:3:
  for i in 0..11 do
--^


java.lang.ClassCastException: class [B cannot be cast to class [I ([B and [I are in module java.base of loader 'bootstrap')
        at dev.flang.be.interpreter.Intrinsics.sysArrayGet(Intrinsics.java:635)
        at dev.flang.be.interpreter.Intrinsics.lambda$call$16(Intrinsics.java:370)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.executeArgs(Interpreter.java:557)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:241)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:304)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:304)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:264)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:253)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:304)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:295)
        at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:810)
        at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:710)
        at dev.flang.be.interpreter.Interpreter.run(Interpreter.java:177)
        at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$3(Fuzion.java:484)
        at dev.flang.tools.Tool.run(Tool.java:163)
        at dev.flang.tools.Fuzion.main(Fuzion.java:209)

Small example provokes check condition to fail during Call type resultion.

 > cat testCrash.fz
testCrash is

  next =>
    if 1 > 0
      res := 1
    else if 1 > 0
      res := 1
    else
      res =  1
 > ./build/bin/fz testCrash
java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ast.Call.loadCalledFeature(Call.java:680)
	at dev.flang.ast.Call.resolveTypes(Call.java:1279)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1258)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1250)
	at dev.flang.ast.Call.visit(Call.java:837)
	at dev.flang.ast.Call.visit(Call.java:835)
	at dev.flang.ast.Call.visit(Call.java:47)
	at dev.flang.ast.Block.visit(Block.java:186)
	at dev.flang.ast.If.visit(If.java:288)
	at dev.flang.ast.If.visit(If.java:292)
	at dev.flang.ast.If.visit(If.java:41)
	at dev.flang.ast.Block.visit(Block.java:186)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:314)
	at dev.flang.ast.Feature.visit(Feature.java:1011)
	at dev.flang.ast.Feature.resolveTypes(Feature.java:1305)
	at dev.flang.ast.Resolution.resolveOne(Resolution.java:412)
	at dev.flang.ast.Resolution.resolve(Resolution.java:378)
	at dev.flang.ast.Resolution.<init>(Resolution.java:216)
	at dev.flang.fe.FrontEnd.createMIR(FrontEnd.java:127)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:537)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)

make error message more specific ("Could not find called feature")

This program

ex67 is

  binom(n, k i64) =>
    factorial(n) / (factorial(k) * factorial(n-k))

  factorial(x i64) is
    res i64 := 1
    for
      i i64 := 1, i+1
    while i<=x
      set res := res * i;
    res

  say (binom 10, 4)

leads to the following error message:

/home/not_synced/flang_dev/content/idioms/examples/idiom67ex.fz:4:18: error 1: Could not find called feature
    factorial(n) / (factorial(k) * factorial(n-k))
-----------------^
Feature not found: infix / (one argument)
Target feature: 'ex67.factorial'
In call: 'deref(binom.this.#^ex67.binom).factorial(n).infix /(factorial(k).infix *(factorial(n.infix -(k))))'


/home/not_synced/flang_dev/content/idioms/examples/idiom67ex.fz:4:34: error 2: Could not find called feature
    factorial(n) / (factorial(k) * factorial(n-k))
---------------------------------^
Feature not found: infix * (one argument)
Target feature: 'ex67.factorial'
In call: 'deref(binom.this.#^ex67.binom).factorial(binom.this.k).infix *(deref(binom.this.#^ex67.binom).factorial(binom.this.n.infix -(binom.this.k)))'

This is correct since factorial is returning type unit but the error message does not mention this. In this case I would expect to be given the information where the missing feature was searched for. Something like

Could not find called feature in Feature unit

If it's not a top level feature maybe the inheritance chain can be given? Example:

Could not find called feature in say->stdout->fuzion.std.out

Following the readme does not work as expected (class not found error)

How to reproduce:
Follow the readme up to "fz factors"
Run "fz factors" or "fz -c factors"

Result:
"Error: Could not find or load main class dev.flang.tools.Fuzion
Caused by: java.lang.ClassNotFoundException: dev.flang.tools.Fuzion"

Expected result:
No error / addition of missing steps in readme

What about Ada?

Since you had a poster session at AdaEurope last week, we can assume you are aware of the strengths of the Ada programming language (simplicity, abstraction, consistency, safety, scalability, efficiency, extensibility, interoperability, analyzability and determinism). However, the purpose page names a couple of programming languages, but not Ada.

Fuzion has advantages, of course. I am not saying 'stop, Ada has all this' - because it doesn't, of course. Ada has legacy which means it can't move in certain directions, and certainly not as quickly as a new language. But the question is, does Fuzion also have all the advantages of Ada? We don't want a new language to be a step back in other areas which are already long solved, so I hope you will consider this:

Ranges on types

An aspect of safety and abstraction in the Ada language lies in the compiler's choice of the bit-representation;

type Buttons_On_Coat is range 1 .. 100;

Choosing the number of bits is an implementation detail, which the programmer might get wrong. So in Ada, the compiler chooses it correctly by default. If it is not possible (because the range is too big), a compile error is given. However, the programmer may specify some aspects; for instance, the underlying representation of the values, or the size of the type in bits, or both; but again, if the programmers gets these wrong, the compiler emits an error.

This also makes it impossible to confuse Buttons_On_Coat with other 'integerish' types.

The point is even more important for Real (i.e. non-integer) types, because there are so many more points of choice - do you want floating or fixed point? What's the range and precision required? Is the closest power-of-two for the precision good enough, since it gives a lot more speed on floating point hardware? In C++, for instance, you technically can do all this by making your own templated type, but considering the difficulty of writing template code in C++, it is doubtful that many of those implementations are correct.

In Ada, you simply state your answer to these questions, and the compiler provides you with the necessary conversions e.g. if you cast a fixed point decimal Real precise to 0.01 to Integer, it will multiply by 100 to get what you need, but this is abstracted away:

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
   type Money is delta 0.01 range -9_999.99 .. 9_999.99 with
      Small => 0.01;
   M : constant Money   := 550.49;
   I : constant Integer := Integer (M);
begin
   Put_Line (I'Image);
end Main;

Since compilers must satisfy ACATS, they have to get this right, and users don't have to.

Access (pointer) scope

In Ada, it is not permitted to store a pointer/reference/access/whatchamathingy to a variable which is out-of-scope. This program fails to compile with main.adb:9:17: error: non-local pointer cannot point to local object, although changing 'Access to 'Unchecked_Access overrides that and still does not print 42:

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
   Get_It : access Integer;
begin
   declare
      It : aliased Integer := 42;
      -- this is where we should declare Get_It
   begin
      Get_It := It'Access;
      -- this is where we should print it
   end;
   Put_Line (Get_It.all'Image);
end Main;

NullPointerExcpetion in front end when writing inherited field

Using this small example

 > cat fieldAccessesNPE.fz
fieldAccessesNPE is
  a is
    f := 47
  c : a is
    m is
      set f := 1000000

results in a front-end crash

 > ./build/bin/fz fieldAccessesNPE
java.lang.NullPointerException: Cannot read field "_featureName" because "<local7>" is null
	at dev.flang.ast.This.resolveTypes(This.java:249)
	at dev.flang.ast.This.thiz(This.java:151)
	at dev.flang.ast.Assign.resolveTypes(Assign.java:273)
	at dev.flang.ast.Assign.resolveTypes(Assign.java:236)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1255)
	at dev.flang.ast.Assign.visit(Assign.java:222)
	at dev.flang.ast.Assign.visit(Assign.java:39)
	at dev.flang.ast.Block.visit(Block.java:214)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:315)
	at dev.flang.ast.Feature.visit(Feature.java:1009)
	at dev.flang.ast.Feature.resolveTypes(Feature.java:1303)
	at dev.flang.ast.Resolution.resolveOne(Resolution.java:412)
	at dev.flang.ast.Resolution.resolve(Resolution.java:378)
	at dev.flang.ast.Resolution.<init>(Resolution.java:216)
	at dev.flang.fe.FrontEnd.createMIR(FrontEnd.java:127)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:565)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:240)
	at dev.flang.tools.Fuzion.main(Fuzion.java:223)

recursive function declared to return Option<V> can return false, resulting in runtime crash

 > cat bugOptionFalse.fz
bugOptionFalse is

  x<V>
  is
    b(l i32) Option<V> is
      if l > 0
        false  # SHOULD FLAG AN ERROR!
      else
        b l+1

  x<unit>.b 0
> ./build/bin/fz bugOptionFalse.fz 

error 1: *** java.lang.Error: check-condition failed!
Call stack:
bugOptionFalse.x<unit>.b: /home/fridi/fuzion/work/bugOptionFalse.fz:9:9:
        b l+1
--------^
bugOptionFalse: /home/fridi/fuzion/work/bugOptionFalse.fz:11:11:
  x<unit>.b 0
----------^


java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ir.Clazz.getChoiceTag(Clazz.java:1227)
	at dev.flang.be.interpreter.Interpreter.setChoiceField(Interpreter.java:886)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:490)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:239)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:280)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:239)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:837)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$7(Interpreter.java:737)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:227)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:239)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:284)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:239)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:837)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$7(Interpreter.java:737)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:227)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:837)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$7(Interpreter.java:737)
	at dev.flang.be.interpreter.Interpreter.run(Interpreter.java:178)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:547)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)
fridi@yoga:~/fuzion/work 11:44:22 > 

confusing error messages when using ⋂ as name of feature

this works

ex218 is
  intersection (a psSet<string>, b psSet<string>) =>
    (a ⋃ b).filter(fun (x string) => a.has x && b.has x)
    
  setOne := psSet<string>.addAll(["eins", "zwei", "drei"])
  setTwo := psSet<string>.addAll(["drei", "vier", "fünf"])
  
  say (intersection(setOne, setTwo))

when replacing 'intersection' by ⋂ fuzion gives 13 error messages. 'Inconsistent indentation' being the first. (Indention was not changed by replacement.)

ex218 is
  ⋂ (a psSet<string>, b psSet<string>) =>
    (a ⋃ b).filter(fun (x string) => a.has x && b.has x)
    
  setOne := psSet<string>.addAll(["eins", "zwei", "drei"])
  setTwo := psSet<string>.addAll(["drei", "vier", "fünf"])
  
  say (⋂(setOne, setTwo))

Confusing error message when using '.fuzion' as file name extension.

If I have a source file (with the unsupported file name extenstion'.fuzion')

> cat hello.fuzion
hello is
  say "Hello compiled World!"

and give it as an argument to fz as follows

 > ./build/bin/fz ./hello.fuzion

<built-in>: error 1: Internally referenced feature './hello.fuzion' not found
Feature not found: 

one error.

The error message is very confusing. The reason is that '../hello.fuzion' is parsed as qualified fuzion feature name, which means it is separated at '.' into four names '', '', '/hello' and 'fuzion' and fz attempts to load what it thinks is the outermost feature ''.

To improve this behavior, we should

  • not try to load a feature with an empty name
  • produce a warning or error if the 'fz' command is called with an existing file as an argument if the file name does not end in '.fz' and a feature with this name could not be loaded.

redefining a field within loop body does not work

In the following code, accesses to items 'items.take i' and 'items.drop i+1' should access the field declared before the loop and not cause an error during type inference:

 > cat idiom29ex.fz
ex29 is

  items := [0,1,2,3,4,5,6]
  for i in -2..10 do
    items := (items.take i) ++ items.drop i + 1
    say "dropping $i results in $items"
 > cat idiom29ex.fz | ./build/bin/fz -

-:5:15: error 1: Illegal forward or cyclic type inference
    items := (items.take i) ++ items.drop i + 1
--------------^
The definition of a field using ":=", or of a feature or function
using "=>" must not create cyclic type dependencies.
Referenced feature: ex29.#loop0.items at -:5:5:
    items := (items.take i) ++ items.drop i + 1
----^

one error.
 > 

C backend: Accessing inherited field results in C compilation failure

This example

> cat call_inherited_field.fz
call_field_inherited_from_parent is
  D(i i32) is say i
  B ref : D 12 is
  x(a ref D) is say a.i
  x B
  x (D 34)

works nicely when interpreted

 > ./build/bin/fz call_inherited_field
12
12
34
34

but results in a C compiler error when compiled

 > ./build/bin/fz -c call_inherited_field
call_inherited_field.c:7822:17: error: no member named 'fzF_0_i' in 'struct fzT_call_u_inherited_u_field__B'; did you mean 'fzF_1_i'?
  fzCur->fields.fzF_0_i = 34;
                ^~~~~~~
                fzF_1_i
call_inherited_field.c:1672:12: note: 'fzF_1_i' declared here
  fzT_1i32 fzF_1_i;
           ^
1 error generated.

error 1: C backend: C compiler failed
C compiler call 'clang -O3 -o call_inherited_field call_inherited_field.c' failed with exit code '1'

one error.

C backend can generate dangling ref to data on stack for value type

The following small example

 > cat testValOuter.fz
testValOuter is
  a =>
    a := [ 1 ]
    a.map<i32>(fun (u i32) => u).asStream

  say a

works fine when interpreted

 > ./build/bin/fz testValOuter
1

but causes a crash in the code generated by the C backend:

 > ./build/bin/fz -c testValOuter
 > ./testValOuter 
Speicherzugriffsfehler (Speicherabzug geschrieben)

The problem is that the result of a.map is an instance of array, which is a value type, which is used as outer type of asStream. The resulting stream returned by 'a' is used after the call to 'a' has returned, while the its outer instance was held locally within the stack frame of 'a' only.

There are basically two possible solutions that have semantic implications:

  1. We could pass an outer value instance as a value. This means that mutations in the outer instance are not possible.
  2. We could detect the longer life-span of the outer instance an copy it to the heap

If we chose solution 2, the implementation could still use a copy as in solution 1 as an optimization if the outer instance is never mutated through the outer ref.

feature with declared unit type result may end with expression incompatible to unit

A feature with unit as result type is permitted end with an expression resulting in something different than unit such as i32, bool, or u64:

 > cat testUnit.fz
testUnit is
  x u64 is 1_000_000_000_000

  u0 unit is 42
  u1 unit is true
  u2 unit is x

  say u0
  say u1
  say u2
 > ./build/bin/fz testUnit
instance[ref unit]1192108080
instance[ref unit]864237698
instance[ref unit]380894366
 > 

It would be cleaner to produce a compile-time error in this case, even if this means that the developer would need to introduce an explicit unit type result in some cases.

feature declaration as last statement in routine returning Option causes check to fail

Using the following example:

> cat testAssignToChoice.fz
testAssignToChoice is

  x<K,V> is
    y(k K) Option<V> is
      retrieve 23

      retrieve (at i32) Option<V> is
        nil

  v := x<i32, bool>.y 3

I get this error at runtime:

 > ./build/bin/fz testAssignToChoice
error 1: *** java.lang.Error: check-condition failed!
Call stack:
testAssignToChoice: ./testAssignToChoice.fz:10:21:
  v := x<i32, bool>.y 3
--------------------^


java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ir.Clazz.getChoiceTag(Clazz.java:1235)
	at dev.flang.be.interpreter.Interpreter.setChoiceField(Interpreter.java:891)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:491)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:239)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:842)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$7(Interpreter.java:742)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:227)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:239)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:842)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$7(Interpreter.java:742)
	at dev.flang.be.interpreter.Interpreter.run(Interpreter.java:178)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:547)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)

Exchanging the declaration and the call to retrieve avoids the problem. Apparently, the declaration of retrieve is replaced by NOP which results in unit being returned instead of nil.

=> vs. :=

Just wanted to be the first to post an issue! 20 years further down the road I might be famous for that... :)

Looking at
aroutine => ... // type inference happening
vs.
afield := ... // type inference happening
just wondring if the syntax could be made somehow more consistent, for example with
aroutine :is ...

(I am throwing out this ideas through my "peephole" of very very limited understanding of Fuzion.)

insufficient javac version will not result in proper error

Cloning the repository, git puts out the following warning:
"warning: the following paths have collided (e.g. case-sensitive paths
on a case-insensitive filesystem) and only one from the same
colliding group is in the working tree:

'lib/FALSE.fz'
'lib/false.fz'
'lib/TRUE.fz'
'lib/true.fz'"

In Ubuntu 20 (wsl2 under Windows), this seems to be the cause for lots of errors trying to run an .fz file (": error 1: Internally referenced feature 'TRUE' not found"). Also unzipping the downloaded .zip gives errors on Windows regarding those files.

So I tried again on OSX, but unfortunately 'make' does not work (b.t.w. none of the used directory paths have any spaces in them, so I'm not sure what went wrong in my first tries). Installed are Apple clang v 12.0 and java version 1.8.0_261. Here's the output:
mkdir -p ./build/classes
javac -d ./build/classes ./src/dev/flang/util/ANY.java ./src/dev/flang/util/Errors.java ./src/dev/flang/util/FuzionOptions.java ./src/dev/flang/util/FuzionConstants.java ./src/dev/flang/util/Intervals.java ./src/dev/flang/util/List.java ./src/dev/flang/util/Map2Int.java ./src/dev/flang/util/MapComparable2Int.java ./src/dev/flang/util/SourceFile.java ./src/dev/flang/util/SourcePosition.java ./src/dev/flang/util/Terminal.java
./src/dev/flang/util/Errors.java:461: error: cannot find symbol
var legal = new StringBuilder();
^
symbol: class var
location: class Errors
./src/dev/flang/util/Errors.java:462: error: cannot find symbol
var comma = "";
^
symbol: class var
location: class Errors
./src/dev/flang/util/Errors.java:463: error: cannot find symbol
for (var c : escapes)
^
symbol: class var
location: class Errors
./src/dev/flang/util/SourceFile.java:107: error: cannot find symbol
public static Path STDIN = Path.of("-");
^
symbol: method of(String)
location: interface Path
./src/dev/flang/util/SourceFile.java:114: error: cannot find symbol
public static Path BUILT_IN = Path.of("--builtin--");
^
symbol: method of(String)
location: interface Path
./src/dev/flang/util/SourceFile.java:194: error: cannot find symbol
fileName == STDIN ? System.in.readAllBytes()
^
symbol: method readAllBytes()
location: variable in of type InputStream
./src/dev/flang/util/Intervals.java:79: error: cannot find symbol
for (var v : _map.subMap(min, max).keySet())
^
symbol: class var
location: class Intervals
where PROPERTY is a type-variable:
PROPERTY extends Object declared in class Intervals
./src/dev/flang/util/Map2Int.java:108: error: cannot find symbol
var res = _mapT2Int.get(t);
^
symbol: class var
location: class Map2Int
where T is a type-variable:
T extends Object declared in class Map2Int
./src/dev/flang/util/Map2Int.java:128: error: cannot find symbol
var res = _mapT2Int.get(t);
^
symbol: class var
location: class Map2Int
where T is a type-variable:
T extends Object declared in class Map2Int
Note: ./src/dev/flang/util/List.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
9 errors
make: *** [build/classes/dev/flang/util/marker_for_make] Error 1

C backend: missing unboxing of outer ref

This example code

testref is

  y (notUnitType i32) is
    g (v y) is
      vs := v.asString
      say "in g: $vs $notUnitType"
    f is
      g y.this  // when in 'ref y', we need to unbox 'y.this' here.

  v := y 42
  v.f
  r ref y := v
  r.f

results in a C compilation error

> ./build/bin/fz -c testref
testref.c:22358:65: error: passing 'fzT_testref_R1y *' (aka 'struct fzT_testref_R1y *') to parameter of incompatible type 'fzT_testref__1y' (aka 'struct fzT_testref__1y')
  fzM_0 = fzC_testref_R1y__1g(fzCur->fzF_0__H_c_testref_o_y_o_f,fzCur->fzF_0__H_c_testref_o_y_o_f);
                                                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
testref.c:4416:83: note: passing argument to parameter 'arg0' here
fzT_testref_R1y__1g fzC_testref_R1y__1g(fzT_testref_R1y* fzouter, fzT_testref__1y arg0);
                                                                                  ^
1 error generated.

error 1: C backend: C compiler failed
C compiler call 'clang -O3 -o testref testref.c' failed with exit code '1'

one error.

Because y.this is an outer ref that needs to be de-referenced when passed a y withing ref y. Changing

  fzM_0 = fzC_testref_R1y__1g(fzCur->fzF_0__H_c_testref_o_y_o_f,fzCur->fzF_0__H_c_testref_o_y_o_f);

into

  fzM_0 = fzC_testref_R1y__1g(fzCur->fzF_0__H_c_testref_o_y_o_f,fzCur->fzF_0__H_c_testref_o_y_o_f->fields);

avoids this problem.

lambda return string.asString on a non-ref heir of string results in interpreter crash

Likely reason for this is that boxing is missing when string.asString is called or returns.

 > cat testAsString.fz
testAsString is

  myString : string is
  f Function<string, myString> := fun (m myString) => m.asString
  say f myString
 > ./build/bin/fz testAsString

error 1: *** java.lang.ClassCastException: class dev.flang.be.interpreter.LValue cannot be cast to class dev.flang.be.interpreter.Instance (dev.flang.be.interpreter.LValue and dev.flang.be.interpreter.Instance are in unnamed module of loader 'app')
Call stack:
fuzion.std.out.println: /home/fridi/fuzion/work/build/lib/fuzion/std/out.fz:34:16:
    for c in s.asString.asBytes do
---------------^
say: /home/fridi/fuzion/work/build/lib/say.fz:29:29:
say(s ref Object) => stdout.println(s)
----------------------------^
testAsString: ./testAsString.fz:5:3:
  say f myString
--^


java.lang.ClassCastException: class dev.flang.be.interpreter.LValue cannot be cast to class dev.flang.be.interpreter.Instance (dev.flang.be.interpreter.LValue and dev.flang.be.interpreter.Instance are in unnamed module of loader 'app')
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:224)
	at dev.flang.be.interpreter.Interpreter.executeArgs(Interpreter.java:556)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:215)
	at dev.flang.be.interpreter.Interpreter.executeArgs(Interpreter.java:556)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:215)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:239)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:837)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$7(Interpreter.java:737)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:227)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:837)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$7(Interpreter.java:737)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:227)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:837)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$7(Interpreter.java:737)
	at dev.flang.be.interpreter.Interpreter.run(Interpreter.java:178)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:547)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)

Clazz.normalize causes NullPointerException if previous errors occurred

ex189 is
  P (number i32) is
    number < 3
  T (number i32) is
    "a"
  x := 1..100
  y := x.filter(P).map(T);
  say y

leads to this error:

java.lang.NullPointerException: Cannot invoke "dev.flang.ast.Feature.thisType()" because "<parameter1>" is null
        at dev.flang.ir.Clazz.normalize(Clazz.java:408)
        at dev.flang.ir.Clazz.normalizeOuter(Clazz.java:371)
        at dev.flang.ir.Clazz.<init>(Clazz.java:309)
        at dev.flang.ir.Clazzes.create(Clazzes.java:313)
        at dev.flang.ir.Clazzes.clazzWithSpecificOuter(Clazzes.java:986)
        at dev.flang.ir.Clazz.lookup(Clazz.java:845)
        at dev.flang.ir.Clazzes.findClazzes(Clazzes.java:691)
        at dev.flang.ir.Clazz$FindClassesVisitor.action(Clazz.java:1050)
        at dev.flang.ir.Clazz$FindClassesVisitor.action(Clazz.java:1044)
        at dev.flang.ast.Call.visit(Call.java:915)
        at dev.flang.ast.Assign.visit(Assign.java:217)
        at dev.flang.ast.Feature$12.visit(Feature.java:2612)
        at dev.flang.ast.Feature$12.visit(Feature.java:2590)
        at dev.flang.ast.Block.visit(Block.java:214)
        at dev.flang.ast.Block.visit(Block.java:41)
        at dev.flang.ast.Block.visit(Block.java:214)
        at dev.flang.ast.Block.visit(Block.java:41)
        at dev.flang.ast.Impl.visit(Impl.java:315)
        at dev.flang.ast.Feature.visit(Feature.java:1030)
        at dev.flang.ir.Clazz$FindClassesVisitor.visitAncestors(Clazz.java:1057)
        at dev.flang.ir.Clazz.findAllClassesWhenCalled(Clazz.java:1108)
        at dev.flang.ir.Clazzes.findAllClasses(Clazzes.java:386)
        at dev.flang.be.interpreter.Interpreter.<init>(Interpreter.java:156)
        at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$3(Fuzion.java:482)
        at dev.flang.tools.Tool.run(Tool.java:163)
        at dev.flang.tools.Fuzion.main(Fuzion.java:209)

Check failure in small example using asList

This example

 > cat checkFailure.fzfz 
checkFailure is

 m.keys.asList
 m.items2

 m is
  items2 List<tuple<i32, unit>> is
    res : List<tuple<i32,unit>> is
         redef asStream => do
    res
  items List<tuple<i32,unit>> is abstract
  keys List<i32> is do

causes fz to crash

 > cat checkFailure.fzfz | ./build/bin/fz -
java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ir.Clazz.findRedefinition(Clazz.java:686)
	at dev.flang.ir.Clazz.lookup(Clazz.java:760)
	at dev.flang.ir.Clazzes.findClazzes(Clazzes.java:689)
	at dev.flang.ir.Clazz$FindClassesVisitor.action(Clazz.java:987)
	at dev.flang.ir.Clazz$FindClassesVisitor.action(Clazz.java:981)
	at dev.flang.ast.Call.visit(Call.java:915)
	at dev.flang.ast.Call.visit(Call.java:47)
	at dev.flang.ast.Block.visit(Block.java:214)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Assign.visit(Assign.java:217)
	at dev.flang.ast.Assign.visit(Assign.java:39)
	at dev.flang.ast.Block.visit(Block.java:214)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:314)
	at dev.flang.ast.Feature.visit(Feature.java:1009)
	at dev.flang.ir.Clazz$FindClassesVisitor.visitAncestors(Clazz.java:994)
	at dev.flang.ir.Clazz.findAllClassesWhenCalled(Clazz.java:1045)
	at dev.flang.ir.Clazzes.findAllClasses(Clazzes.java:384)
	at dev.flang.be.interpreter.Interpreter.<init>(Interpreter.java:156)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:576)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:240)
	at dev.flang.tools.Fuzion.main(Fuzion.java:223)

If condition in parentheses followed by negative integer literal is parsed wrongly

The following small example

> cat testIf.fz
testIf is
  i := 42
  j := if (i=0) -1 else 1
  say j

results in errors:

 > ./build/bin/fz testIf.fz

/home/fridi/fuzion/work/testIf.fz:3:8: error 1: Incompatible types in branches of if statement
  j := if (i=0) -1 else 1
-------^
Incompatible result types in different branches:
block returns value of type unit at /home/fridi/fuzion/work/testIf.fz:3:20:
  j := if (i=0) -1 else 1
-------------------^
block returns value of type i32 at /home/fridi/fuzion/work/testIf.fz:3:25:
  j := if (i=0) -1 else 1
------------------------^


/home/fridi/fuzion/work/testIf.fz:3:17: error 2: Incompatible types when passing argument in a call
  j := if (i=0) -1 else 1
----------------^
Actual type for argument #1 'other' does not match expected type.
In call to          : bool.infix &&
expected formal type: bool
actual type found   : i32
assignable to       : i32
for value assigned  : testIf.this.#chainedBoolTemp19.infix -(1)

2 errors.

replacing -1 by (-1) fixes the problem. Need to check why this is the case.

actual type arguments in call are not checked against type constraint

The following example defines a feature hm with constrained type parameter and calls hm giving an argument that is not compatible with the constraint:

failFindRedef is
  m32 is
    h i32 is 3

  H is
    h i32 is abstract

  hm<T : H> (x T) is
    x.h

  m := hm<m32> m32     # should produce error, m32 is not compatible to H

running this results in a front end crash:

 > ./build/bin/fz failFindRedef
java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ir.Clazz.findRedefinition(Clazz.java:673)
	at dev.flang.ir.Clazz.lookup(Clazz.java:747)
	at dev.flang.ir.Clazzes.findClazzes(Clazzes.java:650)
	at dev.flang.ir.Clazz$FindClassesVisitor.action(Clazz.java:976)
	at dev.flang.ir.Clazz$FindClassesVisitor.action(Clazz.java:971)
	at dev.flang.ast.Call.visit(Call.java:836)
	at dev.flang.ast.Call.visit(Call.java:47)
	at dev.flang.ast.Block.visit(Block.java:186)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:314)
	at dev.flang.ast.Feature.visit(Feature.java:1011)
	at dev.flang.ir.Clazz$FindClassesVisitor.visitAncestors(Clazz.java:982)
	at dev.flang.ir.Clazz.findAllClassesWhenCalled(Clazz.java:1013)
	at dev.flang.ir.Clazzes.findAllClasses(Clazzes.java:382)
	at dev.flang.be.interpreter.Interpreter.<init>(Interpreter.java:157)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:547)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)

Adding the type argument fixes the problem:

failFindRedef2 is
  m32 : H is
    h i32 is 3

  H is
    h i32 is abstract

  hm<T : H> (x T) is
    x.h

  m := hm<m32> m32

and runs fine:

> ./build/bin/fz failFindRedef2
> 

recursive value type when using fromBytes within string.fz

Changing string.trim to

  # remove leading and traling white space from this string
  #
  trim string is
    s0 := utf8

    s1 := (s0.dropWhile (fun isAsciiWhiteSpace)).reverse
    s2 := (s1.dropWhile (fun isAsciiWhiteSpace)).reverse

    fromBytes s2

and running fz on

trim is
  say " abc ".trim

results in

> ./build/bin/fz trim

/home/fridi/fuzion/work/build/lib/strings.fz:89:3: error 1: Recursive value type is not allowed
  fromBytes(utf8Bytes List<u8>) string is
--^
Value type strings.fromBytes equals type of outer feature.
The chain of outer types that lead to this recursion is:
1: strings.fromBytes at /home/fridi/fuzion/work/build/lib/strings.fz:89:3:
  fromBytes(utf8Bytes List<u8>) string is
--^
2: strings.fromBytes.#anonymous0 at /home/fridi/fuzion/work/build/lib/strings.fz:90:5:
    ref : string {
----^
3: strings.fromBytes at /home/fridi/fuzion/work/build/lib/strings.fz:89:3:
  fromBytes(utf8Bytes List<u8>) string is
--^

To solve this, you could make add a 'ref' after the arguments list at /home/fridi/fuzion/work/build/lib/strings.fz:89:3:
  fromBytes(utf8Bytes List<u8>) string is
--^

one error.

using the original trim as follows works:

  # remove leading and traling white space from this string
  #
  trim string is
    s0 := utf8
    s1 := (s0.dropWhile (fun (c u8) => isAsciiWhiteSpace c)).reverse
    s2 := (s1.dropWhile (fun (c u8) => isAsciiWhiteSpace c)).reverse

    strings.fromBytes s2

Declaring inner feature with name 'Object' results in errors

Declaring an inner feature with name 'Object'

 > cat testObject.fz 
testObject is

  Object(absurd void) is

  x is
    say "Hi!"

  x

results in errors since Object is an implicit parent of x and testObject.Object is used instead of #universe.Object:

fridi@yoga:~/fuzion/work 11:46:37 > ./build/bin/fz testObject.fz 

testObject.fz:5:3: error 1: Could not find called feature
  x is
--^
Feature not found: Object (no arguments)
Target feature: 'testObject'
In call: 'testObject.this.Object'

one error.
 > 

java.lang.Error: check-condition failed!

might be similar to #50

# http://rosettacode.org/wiki/Faulhaber's_formula
faulhaber_example is
  bernoulli (n i32) fraction<i32>
    pre
      n >= 0
  is
    a := array<fraction<i32>> n+1, fun (i i32) => 1 ⁄ 1
    for m in 0..n do
      set a := a.put m , (1  ⁄  (m + 1))
      for k in m..1 : -1 do
        set a := a.put (k - 1), ((a[k - 1] - a[k]) * (k ⁄ 1))
    if n != 1
      a[0]
    else
      -a[0]
//====
  binomial(n, k i32)
    pre
      n > 0, k >= 0
    => factorial(n) / (factorial(k) * factorial(n-k))
//====
  factorial(x i32)
    pre
      x >= 0
    =>
    res i32 := 1
    for
      i i32 := 1, i+1
    while i<=x
      set res := res * i;
    res
//====
  faulhaber(p i32) =>
    res := "$p : "
    q := 1  ⁄  (p+1)
    sign := -1⁄1
    for j in 0..p do
      set sign := sign * (-1⁄1)
      b := binomial(p+1, j)  ⁄  1
      coeff := q * (sign / (1⁄1)) * b * bernoulli(j)
      if coeff != (0⁄1)
        if j = 0
          if coeff = (1⁄1)
          else
            if coeff = (-1⁄1)
              res := res + "-"
            else
              res := res + "$coeff"
          else
            if coeff = (1⁄1)
              " + "
            else
              if coeff = (-1⁄1)
                res := res + " - "
              else
                if coeff > (0⁄1)
                  res := res + " + $coeff"
                else
                  minusCoeff := -coeff
                  res := res + " - $minusCoeff"
        pwr := p + 1 - j
        if pwr > 1
          res := res + "n^$pwr"
        else
          res := res + "n"
    res
//====
  for i in 0..11 do
    say(faulhaber(i))


    java.lang.Error: check-condition failed!
    at dev.flang.util.ANY.check(ANY.java:371)
    at dev.flang.ast.Call.loadCalledFeature(Call.java:749)
    at dev.flang.ast.Call.resolveTypes(Call.java:1357)
    at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1277)
    at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1269)
    at dev.flang.ast.Call.visit(Call.java:915)
    at dev.flang.ast.Call.visit(Call.java:913)
    at dev.flang.ast.Feature.visit(Feature.java:2539)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.If.visit(If.java:293)
    at dev.flang.ast.If.visit(If.java:300)
    at dev.flang.ast.If.visit(If.java:41)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.If.visit(If.java:293)
    at dev.flang.ast.If.visit(If.java:41)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.If.visit(If.java:293)
    at dev.flang.ast.If.visit(If.java:41)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.Block.visit(Block.java:41)
    at dev.flang.ast.Impl.visit(Impl.java:315)
    at dev.flang.ast.Feature.visit(Feature.java:1030)
    at dev.flang.ast.Feature.resolveTypes(Feature.java:1324)
    at dev.flang.ast.Feature.resultTypeIfPresent(Feature.java:3208)
    at dev.flang.ast.Call.resolveTypes(Call.java:1379)
    at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1277)
    at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1269)
    at dev.flang.ast.Call.visit(Call.java:915)
    at dev.flang.ast.Call.visit(Call.java:47)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.If.visit(If.java:293)
    at dev.flang.ast.If.visit(If.java:41)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.Block.visit(Block.java:41)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.Block.visit(Block.java:41)
    at dev.flang.ast.Impl.visit(Impl.java:315)
    at dev.flang.ast.Feature.visit(Feature.java:1030)
    at dev.flang.ast.Feature.resolveTypes(Feature.java:1324)
    at dev.flang.ast.Feature.resultTypeIfPresent(Feature.java:3208)
    at dev.flang.ast.Call.resolveTypes(Call.java:1379)
    at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1277)
    at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1269)
    at dev.flang.ast.Call.visit(Call.java:915)
    at dev.flang.ast.Call.lambda$visit$0(Call.java:907)
    at dev.flang.ast.Feature.resolveTypes(Feature.java:1342)
    at dev.flang.ast.Feature.resultTypeIfPresent(Feature.java:3208)
    at dev.flang.ast.Call.resolveTypes(Call.java:1379)
    at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1277)
    at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1269)
    at dev.flang.ast.Call.visit(Call.java:915)
    at dev.flang.ast.Call.visit(Call.java:47)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.If.visit(If.java:293)
    at dev.flang.ast.If.visit(If.java:41)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.Block.visit(Block.java:41)
    at dev.flang.ast.Block.visit(Block.java:214)
    at dev.flang.ast.Block.visit(Block.java:41)
    at dev.flang.ast.Impl.visit(Impl.java:315)
    at dev.flang.ast.Feature.visit(Feature.java:1030)
    at dev.flang.ast.Feature.resolveTypes(Feature.java:1324)
    at dev.flang.ast.Resolution.resolveOne(Resolution.java:411)
    at dev.flang.ast.Resolution.resolve(Resolution.java:378)
    at dev.flang.ast.Resolution.<init>(Resolution.java:216)
    at dev.flang.fe.FrontEnd.createMIR(FrontEnd.java:142)
    at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$3(Fuzion.java:471)
    at dev.flang.tools.Tool.run(Tool.java:163)
    at dev.flang.tools.Fuzion.main(Fuzion.java:209)

Small example causes check to fail during Call.checkTypes

Run this code:

 > cat checkFailure.fz 
x is
  r := 1.max 1
  if r = 3

x
 > ./build/bin/fz checkFailure.fz
java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ast.Call.checkTypes(Call.java:1438)
	at dev.flang.ast.Feature$8.action(Feature.java:2061)
	at dev.flang.ast.Feature$8.action(Feature.java:2059)
	at dev.flang.ast.Call.visit(Call.java:836)
	at dev.flang.ast.Call.visit(Call.java:47)
	at dev.flang.ast.Block.visit(Block.java:186)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:314)
	at dev.flang.ast.Feature.visit(Feature.java:1011)
	at dev.flang.ast.Feature.checkTypes1and2(Feature.java:2059)
	at dev.flang.ast.Resolution.resolveOne(Resolution.java:436)
	at dev.flang.ast.Resolution.resolve(Resolution.java:378)
	at dev.flang.ast.Resolution.<init>(Resolution.java:216)
	at dev.flang.fe.FrontEnd.createMIR(FrontEnd.java:127)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:537)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)
fridi@yoga:~/fuzion/work 11:16:40 > 

post condition with type inference not working (confusing error message)

this works:

sort_partial array<i32>
  post
    result[0] = 0
  is
    arr := array<i32> 10000, fun (i i32) =>
      if i % 5 = 0
        i - 5
      i
    arr.sort(fun (a,b i32) => a <= b)
    arr

this does not work:

sort_partial
  post
    result[0] = 0
  =>
    arr := array<i32> 10000, fun (i i32) =>
      if i % 5 = 0
        i - 5
      i
    arr.sort(fun (a,b i32) => a <= b)
    arr

the error:

/home/not_synced/chronologer/tests/sort_partial.fz:3:5: error 1: Could not find called feature
    result[0] = 0
----^
Feature not found: result (no arguments)
Target feature: 'sort_partial'
In call: 'result'

one error.

check-condition failure when using fun-type in string.trim

Changing string.trim to

  # remove leading and traling white space from this string
  #
  trim string is
    s0 := utf8

    s1 := (s0.dropWhile (fun isAsciiWhiteSpace)).reverse
    s2 := (s1.dropWhile (fun isAsciiWhiteSpace)).reverse

    strings.fromBytes s2

and running fz on

trim is
  say " abc ".trim

results in

 > ./build/bin/fz trim
java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ir.Clazz.lookup(Clazz.java:834)
	at dev.flang.ir.Clazz.lookup(Clazz.java:792)
	at dev.flang.ir.Clazz.lambda$findAllClassesWhenCalled$0(Clazz.java:1125)
	at dev.flang.ir.Clazzes.calledDynamically(Clazzes.java:492)
	at dev.flang.ir.Clazzes.findClazzes(Clazzes.java:695)
	at dev.flang.ir.Clazz$FindClassesVisitor.action(Clazz.java:1059)
	at dev.flang.ir.Clazz$FindClassesVisitor.action(Clazz.java:1053)
	at dev.flang.ast.Call.visit(Call.java:930)
	at dev.flang.ast.Call.lambda$visit$0(Call.java:922)
	at dev.flang.ast.FeatureVisitor.visitActuals(FeatureVisitor.java:87)
	at dev.flang.ast.Call.visit(Call.java:918)
	at dev.flang.ast.Call.visit(Call.java:928)
	at dev.flang.ast.Assign.visit(Assign.java:217)
	at dev.flang.ast.Feature$12.visit(Feature.java:2612)
	at dev.flang.ast.Feature$12.visit(Feature.java:2590)
	at dev.flang.ast.Block.visit(Block.java:214)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Block.visit(Block.java:214)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Assign.visit(Assign.java:217)
	at dev.flang.ast.Assign.visit(Assign.java:39)
	at dev.flang.ast.Block.visit(Block.java:214)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:315)
	at dev.flang.ast.Feature.visit(Feature.java:1026)
	at dev.flang.ir.Clazz$FindClassesVisitor.visitAncestors(Clazz.java:1066)
	at dev.flang.ir.Clazz.findAllClassesWhenCalled(Clazz.java:1117)
	at dev.flang.ir.Clazzes.findAllClasses(Clazzes.java:394)
	at dev.flang.be.interpreter.Interpreter.<init>(Interpreter.java:156)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$3(Fuzion.java:482)
	at dev.flang.tools.Tool.run(Tool.java:163)
	at dev.flang.tools.Fuzion.main(Fuzion.java:209)

using the original trim as follows works:

  # remove leading and traling white space from this string
  #
  trim string is
    s0 := utf8
    s1 := (s0.dropWhile (fun (c u8) => isAsciiWhiteSpace c)).reverse
    s2 := (s1.dropWhile (fun (c u8) => isAsciiWhiteSpace c)).reverse

    strings.fromBytes s2

C backend crash due to call to clazz that does not need code according to FUIR

Using the example

cbackendCallsNoCodeClazz is

 psSet2<string>.asString

 psSet2<K : ordered<K>> : Set<K>, List<K> is
  psm := psMap2<K,unit>
  redef asList => psm.keys.asList

 psMap2<K : ordered<K>, V> : map<K, V> is
  index [] (k K) option<V> is do
  asKeyArray array<K> is do
  redef items List<tuple<K,V>> is
    res : List<tuple<K,V>> is
      redef asStream =>
        asKeyArray.map<tuple<K,V>>(fun (k K) => (k, psMap2.this[k].unwrap)).asStream
    res

results in a precondition failure in the C backend due to a call to ref stream<tuple<string, unit>>.map<string> while, !_fuir.clazzNeedsCode(cc) for this clazz:

 > PRECONDITIONS=true ./build/bin/fz -c cbackendCallsNoCodeClazz
clazzNeedsCode2: ref stream<tuple<string, unit>>.map<string> is  not instantiated  && true
Called ref stream<tuple<string, unit>>.map<string> on ref stream<tuple<string, unit>> but does not need code!
while compiling cbackendCallsNoCodeClazz.psMap2<string, unit>.keys.ref res.asStream
java.lang.Error: require-condition1 failed!
	at dev.flang.util.ANY.require(ANY.java:66)
	at dev.flang.be.c.C.call(C.java:652)
	at dev.flang.be.c.C.createCode(C.java:450)
	at dev.flang.be.c.C.createCode(C.java:292)
	at dev.flang.be.c.C.codeForRoutine(C.java:899)
	at dev.flang.be.c.C.code(C.java:837)
	at dev.flang.be.c.C$CompilePhase$4.compile(C.java:67)
	at dev.flang.be.c.C.lambda$createCode$0(C.java:207)
	at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
	at java.base/java.util.stream.ReferencePipeline$Head.forEachOrdered(ReferencePipeline.java:772)
	at dev.flang.be.c.C.createCode(C.java:203)
	at dev.flang.be.c.C.compile(C.java:152)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:580)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:240)
	at dev.flang.tools.Fuzion.main(Fuzion.java:223)

chaining more than three bool expressions a <= b <= c <= d does not work

 > echo "say 0<=1<=2" | ./build/bin/fz -
true
 > echo "say 0<=1<=2<=3" | ./build/bin/fz -

-:1:12: error 1: Could not find called feature
say 0<=1<=2<=3
-----------^
Feature not found: infix <= (one argument)
Target feature: bool
In call: #universe.this.#chainedBoolTemp1.infix <=(3)

one error.

Fuzion community

People who wish to speak about things related to the development of fuzion can use gitter. It is essentially Slack for GitHub developers.

interpreter produces 'Cannot create LValue' when converting u64-expression to string

 > cat testU64inString.fz 
testU64inString is
  "" + (1.as_u64&1)
 > ./build/bin/fz testU64inString.fz 

error 1: *** java.lang.Error: Cannot create LValue from class dev.flang.be.interpreter.u64Value
Call stack:


java.lang.Error: Cannot create LValue from class dev.flang.be.interpreter.u64Value
	at dev.flang.be.interpreter.Value.at(Value.java:157)
	at dev.flang.be.interpreter.Interpreter.fieldSlot(Interpreter.java:1066)
	at dev.flang.be.interpreter.Interpreter.getField(Interpreter.java:1140)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:421)
	at dev.flang.be.interpreter.Interpreter.executeArgs(Interpreter.java:554)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:215)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:269)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:830)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$7(Interpreter.java:730)
	at dev.flang.be.interpreter.Interpreter.run(Interpreter.java:178)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:547)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)

array of unit type values causes C backend to generate broken code

This small test

testUnitArray is
  a := [ unit ]
  say a

causes the C compiler to report an error for the code generated by C backend

 > ./build/bin/fz -c testUnitArray
testUnitArray.c:19926:29: error: use of undeclared identifier 'arg2'
  ((fzT_unit*)arg0)[arg1] = arg2;
                            ^
1 error generated.

error 1: C backend: C compiler failed
C compiler call 'clang -O3 -o testUnitArray testUnitArray.c' failed with exit code '1'

one error.

Declaring and using array constant in universe causes strange type inference error

> echo "[0][0]" | ./build/bin/fz -

/home/fridi/fuzion/work/build/lib/sys/array.fz:46:12: error 1: Illegal forward or cyclic type inference
    get<T> data, i
-----------^
The definition of a field using ":=", or of a feature or function
using "=>" must not create cyclic type dependencies.
Referenced feature: sys.array.data at /home/fridi/fuzion/work/build/lib/sys/array.fz:32:3:
  data := alloc<T> length
--^

one error.

redefining feature with different result type causes interpreter crash instead of front end error

See this example, that should flag errors for bad1.get and bad2.get having wrong result type:

 > cat testRedefine.fz
testRedefine is

  getter <A> ref is
    get A is abstract

  good : getter<string | i32 | nil> is
    get string | i32 | nil is 42

  bad1 : getter<string | i32 | nil> is
    get i32 is 42

  bad2 : getter<string | i32 | nil> is
    get => 42

  show(g getter<string | i32 | nil>) is
    say g.get

  yak "good: "; show good
  yak "bad1: "; show bad1
  yak "bad2: "; show bad2
 > ./build/bin/fz testRedefine
good: instance[ref choice<string, i32, nil>]1617791695
bad1: 
error 1: *** java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
Call stack:
testRedefine: ./testRedefine.fz:19:17:
  yak "bad1: "; show bad1
----------------^


java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:453)
	at dev.flang.be.interpreter.Interpreter.executeArgs(Interpreter.java:553)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:214)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:268)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:792)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:692)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:226)
	at dev.flang.be.interpreter.Interpreter.execute(Interpreter.java:268)
	at dev.flang.be.interpreter.Interpreter.callOnInstance(Interpreter.java:792)
	at dev.flang.be.interpreter.Interpreter.lambda$callable$6(Interpreter.java:692)
	at dev.flang.be.interpreter.Interpreter.run(Interpreter.java:177)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:552)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)
 > 

Redefining feature with type arguments causes error

The following example calls g.b dynamically with different type parameters

 > cat dynamicallyCallGeneric.fz 
dynamicallyCallGeneric is

  g ref is
    where string is abstract
    b<X> (x X) X is where + x.asString

  h1 : g is
    where => "in h1: "

  h2 : g is
    where => "in h2: "

  test(v g) is
    say v.b "hello"
    say v.b<i32> 1234
    say v.b<u64> 1234
    say v.b true
    say v.b false

  test h1
  test h2

but at runtime, all non-ref type parameters are treated wrong:

 > ./build/bin/fz dynamicallyCallGeneric
in h1: hello
-555555555
12329346333
true
true
in h2: hello
-555555555
12329346333
true
true

and when compiled, there are even calls to undefined C functions:

 > ./build/bin/fz -c dynamicallyCallGeneric
dynamicallyCallGeneric.c:7494:11: warning: implicit declaration of function 'fzC__L2176dynamicall___string_g' is invalid in C99 [-Wimplicit-function-declaration]
  fzM_1 = fzC__L2176dynamicall___string_g(fzCur->fzF_0_v,(fzT__Rstring*)fzM_0);
          ^
dynamicallyCallGeneric.c:7494:9: warning: incompatible integer to pointer conversion assigning to 'fzT__Rstring *' (aka 'struct fzT__Rstring *') from 'int' [-Wint-conversion]
  fzM_1 = fzC__L2176dynamicall___string_g(fzCur->fzF_0_v,(fzT__Rstring*)fzM_0);
        ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dynamicallyCallGeneric.c:7503:11: warning: implicit declaration of function 'fzC__L2175dynamicall__b_l_i32_g' is invalid in C99 [-Wimplicit-function-declaration]
  fzM_2 = fzC__L2175dynamicall__b_l_i32_g(fzCur->fzF_0_v,1234);
          ^
dynamicallyCallGeneric.c:7518:11: warning: implicit declaration of function 'fzC__L2177dynamicall__b_l_u64_g' is invalid in C99 [-Wimplicit-function-declaration]
  fzM_4 = fzC__L2177dynamicall__b_l_u64_g(fzCur->fzF_0_v,1234ULL);
          ^
dynamicallyCallGeneric.c:7535:11: warning: implicit declaration of function 'fzC__L2174dynamicall___l_bool_g' is invalid in C99 [-Wimplicit-function-declaration]
  fzM_7 = fzC__L2174dynamicall___l_bool_g(fzCur->fzF_0_v,fzM_6);
          ^
dynamicallyCallGeneric.c:7535:9: error: assigning to 'fzT_bool' (aka 'struct fzT_bool') from incompatible type 'int'
  fzM_7 = fzC__L2174dynamicall___l_bool_g(fzCur->fzF_0_v,fzM_6);
        ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dynamicallyCallGeneric.c:7552:10: error: assigning to 'fzT_bool' (aka 'struct fzT_bool') from incompatible type 'int'
  fzM_10 = fzC__L2174dynamicall___l_bool_g(fzCur->fzF_0_v,fzM_9);
         ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 warnings and 2 errors generated.

error 1: C backend: C compiler failed
C compiler call 'clang -O3 -o dynamicallyCallGeneric dynamicallyCallGeneric.c' failed with exit code '1'

one error.

Attempts to redefine a feature with type parameters as in

> cat dynamicallyCallGeneric2.fz
dynamicallyCallGeneric2 is

  g ref is
    b<X> (x X) X is "in g: " + x.asString

  h1 : g is
    redef b<X> (x X) X is "in h1: " + x.asString

  h2 : g is
    redef b<X> (x X) X is "in h2: " + x.asString

  h3 : g is

  test(v g) is
    say v.b "hello"
    say v.b<i32> 1234
    say v.b<u64> 1234
    say v.b true
    say v.b false

  test h1
  test h2
  test h3

are even blocked with an error message

 > ./build/bin/fz dynamicallyCallGeneric2

./dynamicallyCallGeneric2.fz:7:5: error 1: Cannot redefine feature with generic arguments
    redef b<X> (x X) X is "in h1: " + x.asString
----^
Feature that redefines existing feature: dynamicallyCallGeneric2.h1
original feature: dynamicallyCallGeneric2.g.b
original feature defined in ./dynamicallyCallGeneric2.fz:4:5:
To solve this, ask the Fuzion team to remove this restriction :-).


./dynamicallyCallGeneric2.fz:10:5: error 2: Cannot redefine feature with generic arguments
    redef b<X> (x X) X is "in h2: " + x.asString
----^
Feature that redefines existing feature: dynamicallyCallGeneric2.h2
original feature: dynamicallyCallGeneric2.g.b
original feature defined in ./dynamicallyCallGeneric2.fz:4:5:
To solve this, ask the Fuzion team to remove this restriction :-).

2 errors.

match over type parameter causes front end crash

 > cat testMatch.fz
testMatch is
  x<A: Option<string>>(a A) is
    match a
      string => say "string"
      nil => say "nil"

  x<Option<string>> "bla"
 > ./build/bin/fz testMatch
java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ast.Type.featureOfType(Type.java:1074)
	at dev.flang.ast.Match.resolveTypes(Match.java:146)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1263)
	at dev.flang.ast.Match.visit(Match.java:127)
	at dev.flang.ast.Match.visit(Match.java:48)
	at dev.flang.ast.Block.visit(Block.java:186)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:314)
	at dev.flang.ast.Feature.visit(Feature.java:1011)
	at dev.flang.ast.Feature.resolveTypes(Feature.java:1305)
	at dev.flang.ast.Feature.resultTypeIfPresent(Feature.java:3183)
	at dev.flang.ast.Call.resolveTypes(Call.java:1300)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1258)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1250)
	at dev.flang.ast.Call.visit(Call.java:836)
	at dev.flang.ast.Call.visit(Call.java:47)
	at dev.flang.ast.Block.visit(Block.java:186)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:314)
	at dev.flang.ast.Feature.visit(Feature.java:1011)
	at dev.flang.ast.Feature.resolveTypes(Feature.java:1305)
	at dev.flang.ast.Resolution.resolveOne(Resolution.java:412)
	at dev.flang.ast.Resolution.resolve(Resolution.java:378)
	at dev.flang.ast.Resolution.<init>(Resolution.java:216)
	at dev.flang.fe.FrontEnd.createMIR(FrontEnd.java:127)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:537)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)

Matching over an i32 results in a crash

Trying to run these examples:

 > cat matchI32a.fuzion 
matchI32a is
  match 42
    TRUE => say "T"
    FALSE => say "F"
 > cat matchI32b.fuzion 
matchI32b is
  j := 42 ? TRUE => true
          | FALSE => false
 > cat matchI32a.fuzion | ./build/bin/fz -
java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ast.Match.resolveTypes(Match.java:153)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1261)
	at dev.flang.ast.Match.visit(Match.java:127)
	at dev.flang.ast.Match.visit(Match.java:48)
	at dev.flang.ast.Block.visit(Block.java:186)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:314)
	at dev.flang.ast.Feature.visit(Feature.java:1009)
	at dev.flang.ast.Feature.resolveTypes(Feature.java:1303)
	at dev.flang.ast.Resolution.resolveOne(Resolution.java:412)
	at dev.flang.ast.Resolution.resolve(Resolution.java:378)
	at dev.flang.ast.Resolution.<init>(Resolution.java:216)
	at dev.flang.fe.FrontEnd.createMIR(FrontEnd.java:127)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:565)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:240)
	at dev.flang.tools.Fuzion.main(Fuzion.java:223)
 > cat matchI32b.fuzion | ./build/bin/fz -
java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ast.Match.resolveTypes(Match.java:153)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1261)
	at dev.flang.ast.Match.visit(Match.java:127)
	at dev.flang.ast.Match.visit(Match.java:48)
	at dev.flang.ast.Feature.visit(Feature.java:2515)
	at dev.flang.ast.Block.visit(Block.java:186)
	at dev.flang.ast.Block.visit(Block.java:41)
	at dev.flang.ast.Impl.visit(Impl.java:314)
	at dev.flang.ast.Feature.visit(Feature.java:1009)
	at dev.flang.ast.Feature.resolveTypes(Feature.java:1303)
	at dev.flang.ast.Resolution.resolveOne(Resolution.java:412)
	at dev.flang.ast.Resolution.resolve(Resolution.java:378)
	at dev.flang.ast.Resolution.<init>(Resolution.java:216)
	at dev.flang.fe.FrontEnd.createMIR(FrontEnd.java:127)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:565)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:240)
	at dev.flang.tools.Fuzion.main(Fuzion.java:223)

check failure when accessing one of several fields early

 > cat testVars.fz 
testVars is
  b := 1 + b
  b := 1 + b
 > ./build/bin/fz testVars
  b := 1 + b
-----------^
java.lang.Error: check-condition failed!
	at dev.flang.util.ANY.check(ANY.java:371)
	at dev.flang.ast.Call.loadCalledFeature(Call.java:680)
	at dev.flang.ast.Call.resolveTypes(Call.java:1279)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1258)
	at dev.flang.ast.Feature$ResolveTypes.action(Feature.java:1250)
	at dev.flang.ast.Call.visit(Call.java:837)
	at dev.flang.ast.Call.lambda$visit$0(Call.java:829)
	at dev.flang.ast.Feature.resolveTypes(Feature.java:1323)
	at dev.flang.ast.Resolution.resolveOne(Resolution.java:412)
	at dev.flang.ast.Resolution.resolve(Resolution.java:378)
	at dev.flang.ast.Resolution.<init>(Resolution.java:216)
	at dev.flang.fe.FrontEnd.createMIR(FrontEnd.java:127)
	at dev.flang.tools.Fuzion.lambda$parseArgsForBackend$2(Fuzion.java:537)
	at dev.flang.tools.Fuzion.<init>(Fuzion.java:236)
	at dev.flang.tools.Fuzion.main(Fuzion.java:219)
 > 

compiler prints one error but then does not seem to halt

Compiling the following code prints an error but the compiler then seems to go into an infinite loop.

# example of an abstract feature with formal arguments
arg_abstr is

  # foo has formal arguments
  foo (i i32, j u64, b bool) string is abstract

  # foo2 has many formal arguments
  foo2 (a,b,c,d,e,f,g,h,i,j,k,l,m i32) string is abstract

  # foo3 is an absurd abstract
  foo3 (absurd void) s abstract

  say (foo 42, 9999999.as_u64, true)           # will cause runtime error (NYI: compile time analysis missing)
  say (foo2 1,2,3,4,5,6,7,8,9,10,11,12,13)     # will cause runtime error (NYI: compile time analysis missing)
  say (foo3 (do {}))                           # will cause runtime error (NYI: compile time analysis missing)

Consider creating a grammar for tree-sitter

What

Tree-sitter is a parser generator tool and an incremental parsing library. It can build a concrete syntax tree for a source file and efficiently update the syntax tree as the source file is edited.

Why

How

Other

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.