Skip to content

Releases: ethereum/fe

v0.16.0-alpha "Pyrope"

05 May 17:13
Compare
Choose a tag to compare
Pre-release

0.16.0-alpha (2022-05-05)

WARNING: All Fe releases are alpha releases and only meant to share the development progress with developers and enthusiasts. It is NOT yet ready for production usage.

Features

  • Change static function call syntax from Bar.foo() to Bar::foo() (#241)
  • Added support for retrieving the base fee via ctx.base_fee() (#503)

Bugfixes

  • Resolve functions on structs via path (e.g. bi::ba::bums()) (#241)

v0.15.0-alpha "Onyx"

04 Apr 15:30
316e6aa
Compare
Choose a tag to compare
v0.15.0-alpha "Onyx" Pre-release
Pre-release

WARNING: All Fe releases are alpha releases and only meant to share the development progress with developers and enthusiasts. It is NOT yet ready for production usage.

0.15.0-alpha "Onyx" (2022-04-04)

Features

  • Labels are now required on function arguments. Labels can be omitted if the
    argument is a variable with a name that matches the label, or if the function
    definition specifies that an argument should have no label. Functions often take
    several arguments of the same type; compiler-checked labels can help prevent
    accidentally providing arguments in the wrong order.

    Example:

    contract CoolCoin:
      balance: Map<address, i256>
      loans: Map<(address, address), i256>
    
      pub fn demo(self, ann: address, bob: address):
        let is_loan: bool = false
        self.give(from: ann, to: bob, 100, is_loan)
    
      fn transfer(self, from sender: address, to recipient: address, _ val: u256, is_loan: bool):
        self.cred[sender] -= val
        self.cred[recipient] += val
        if is_loan:
          self.loans[(sender, recipient)] += val
    

    Note that arguments must be provided in the order specified in the function
    definition.

    A parameter's label defaults to the parameter name, but can be changed by
    specifying a different label to the left of the parameter name. Labels should be
    clear and convenient for the caller, while parameter names are only used in the
    function body, and can thus be longer and more descriptive.
    In the example above, we choose to use sender and recipient as identifiers
    in the body of fn transfer, but use labels from: and to:.

    In cases where it's ideal to not have labels, e.g. if a function takes a single
    argument, or if types are sufficient to differentiate between arguments, use _
    to specify that a given parameter has no label. It's also fine to require labels
    for some arguments, but not others.

    Example:

    fn add(_ x: u256, _ y: u256) -> u256:
      return x + y
    
    contract Foo:
      fn transfer(self, _ to: address, wei: u256):
        pass
    
      pub fn demo(self):
        transfer(address(0), wei: add(1000, 42))
    

(#397)

Bugfixes

  • The region of memory used to compute the slot of a storage map value was not being allocated. (#684)

v0.14.0-alpha "Niter"

03 Mar 02:48
6fd6c89
Compare
Choose a tag to compare
v0.14.0-alpha "Niter" Pre-release
Pre-release

WARNING: All Fe releases are alpha releases and only meant to share the development progress with developers and enthusiasts. It is NOT yet ready for production usage.

0.14.0-alpha "Niter" (2022-03-02)

Features

  • Events can now be defined outside of contracts.

    Example:

    event Transfer:
        idx sender: address
        idx receiver: address
        value: u256
    
    contract Foo:
        fn transferFoo(to: address, value: u256):
            emit Transfer(sender: msg.sender, receiver: to, value)
    
    contract Bar:
        fn transferBar(to: address, value: u256):
            emit Transfer(sender: msg.sender, receiver: to, value)
    

(#80)

  • The Fe standard library now includes a std::evm module, which provides functions that perform low-level evm operations.
    Many of these are marked unsafe, and thus can only be used inside of an unsafe function or an unsafe block.

    Example:

    use std::evm::{mstore, mload}
    
    fn memory_shenanigans():
      unsafe:
        mstore(0x20, 42)
        let x: u256 = mload(0x20)
        assert x == 42
    

    The global functions balance and balance_of have been removed; these can now be called as std::evm::balance(), etc.
    The global function send_value has been ported to Fe, and is now available as std::send_value.
    (#629)

  • Support structs that have non-base type fields in storage.

    Example:

    struct Point:
        pub x: u256
        pub y: u256
    
    struct Bar:
        pub name: String<3>
        pub numbers: Array<u256, 2>
        pub point: Point
        pub something: (u256, bool)
    
    
    contract Foo:
        my_bar: Bar
    
        pub fn complex_struct_in_storage(self) -> String<3>:
            self.my_bar = Bar(
                name: "foo",
                numbers: [1, 2],
                point: Point(x: 100, y: 200),
                something: (1, true),
            )
    
            # Asserting the values as they were set initially
            assert self.my_bar.numbers[0] == 1
            assert self.my_bar.numbers[1] == 2
            assert self.my_bar.point.x == 100
            assert self.my_bar.point.y == 200
            assert self.my_bar.something.item0 == 1
            assert self.my_bar.something.item1
    
            # We can change the values of the array
            self.my_bar.numbers[0] = 10
            self.my_bar.numbers[1] = 20
            assert self.my_bar.numbers[0] == 10
            assert self.my_bar.numbers[1] == 20
            # We can set the array itself
            self.my_bar.numbers = [1, 2]
            assert self.my_bar.numbers[0] == 1
            assert self.my_bar.numbers[1] == 2
    
            # We can change the values of the Point
            self.my_bar.point.x = 1000
            self.my_bar.point.y = 2000
            assert self.my_bar.point.x == 1000
            assert self.my_bar.point.y == 2000
            # We can set the point itself
            self.my_bar.point = Point(x=100, y=200)
            assert self.my_bar.point.x == 100
            assert self.my_bar.point.y == 200
    
            # We can change the value of the tuple
            self.my_bar.something.item0 = 10
            self.my_bar.something.item1 = false
            assert self.my_bar.something.item0 == 10
            assert not self.my_bar.something.item1
            # We can set the tuple itself
            self.my_bar.something = (1, true)
            assert self.my_bar.something.item0 == 1
            assert self.my_bar.something.item1
    
            return self.my_bar.name.to_mem()
    

(#636)

  • Features that read and modify state outside of contracts are now implemented on a struct
    named "Context". Context is included in the standard library and can be imported with
    use std::context::Context. Instances of Context are created by calls to public functions
    that declare it in the signature or by unsafe code.

    Basic example:

    use std::context::Context
    
    contract Foo:
        my_num: u256
    
        pub fn baz(ctx: Context) -> u256:
            return ctx.block_number()
    
        pub fn bing(self, new_num: u256) -> u256:
            self.my_num = new_num
            return self.my_num
    
    
    contract Bar:
    
        pub fn call_baz(ctx: Context, foo_addr: address) -> u256:
            # future syntax: `let foo = ctx.load<Foo>(foo_addr)`
            let foo: Foo = Foo(ctx, foo_addr)
            return foo.baz()
    
        pub fn call_bing(ctx: Context) -> u256:
            # future syntax: `let foo = ctx.create<Foo>(0)`
            let foo: Foo = Foo.create(ctx, 0)
            return foo.bing(42)
    

    Example with __call__ and unsafe block:

    use std::context::Context
    use std::evm
    
    contract Foo:
    
        pub fn __call__():
            unsafe:
                # creating an instance of `Context` is unsafe
                let ctx: Context = Context()
                let value: u256 = u256(bar(ctx))
    
                # return `value`
                evm::mstore(0, value)
                evm::return_mem(0, 32)
    
        fn bar(ctx: Context) -> address:
            return ctx.self_address()
    

(#638)

  • Features

    Support local constant

    Example:

    contract Foo:
        pub fn bar():
            const LOCAL_CONST: i32 = 1

    Support constant expression

    Example:

    const GLOBAL: i32 = 8
    
    contract Foo:
        pub fn bar():
            const LOCAL: i32 = GLOBAL * 8

    Support constant generics expression

    Example:

    const GLOBAL: u256= 8
    const USE_GLOBAL: bool = false
    type MY_ARRAY = Array<i32, { GLOBAL / 4 }>
    
    contract Foo:
        pub fn bar():
            let my_array: Array<i32, { GLOBAL if USE_GLOBAL else 4 }>

    Bug fixes

    Fix ICE when constant type is mismatch

    Example:

    const GLOBAL: i32 = "FOO"
    
    contract Foo:
        pub fn bar():
            let FOO: i32 = GLOBAL

    Fix ICE when assigning value to constant twice

    Example:

    const BAR: i32 = 1
    
    contract FOO:
        pub fn bar():
            BAR = 10

(#649)

  • Argument label syntax now uses : instead of =. Example:

    struct Foo:
      x: u256
      y: u256
    
    let x: MyStruct = MyStruct(x: 10, y: 11)
    # previously:     MyStruct(x = 10, y = 11)
    

(#665)

  • Support module-level pub modifier, now default visibility of items in a module is private.

    Example:

    # This constant can be used outside of the module.
    pub const PUBLIC:i32 = 1
    
    # This constant can NOT be used outside of the module.
    const PRIVATE: i32 = 1

(#677)

Internal Changes - for Fe Contributors

    • Source files are now managed by a (salsa) SourceDb. A SourceFileId now corresponds to a salsa-interned File with a path. File content is a salsa input function. This is mostly so that the future (LSP) language server can update file content when the user types or saves, which will trigger a re-analysis of anything that changed.
    • An ingot's set of modules and dependencies are also salsa inputs, so that when the user adds/removes a file or dependency, analysis is rerun.
    • Standalone modules (eg a module compiled with fe fee.fe) now have a fake ingot parent. Each Ingot has an IngotMode (Lib, Main, StandaloneModule), which is used to disallow ingot::whatever paths in standalone modules, and to determine the correct root module file.
    • parse_module now always returns an ast::Module, and thus a ModuleId will always exist for a source file, even if it contains fatal parse errors. If the parsing fails, the body will end with a ModuleStmt::ParseError node. The parsing will stop at all but the simplest of syntax errors, but this at least allows partial analysis of source file with bad syntax.
    • ModuleId::ast(db) is now a query that parses the module's file on demand, rather than the AST being interned into salsa. This makes handling parse diagnostics cleaner, and removes the up-front parsing of every module at ingot creation time.

(#628)

v0.13.0-alpha "Mixite"

01 Feb 03:44
50443eb
Compare
Choose a tag to compare
Pre-release

WARNING: All Fe releases are alpha releases and only meant to share the development progress with developers and enthusiasts. It is NOT yet ready for production usage.

0.13.0-alpha "Mixite" (2022-01-31)

Features

  • Support private fields on structs

    Public fields now need to be declared with the pub modifier, otherwise they default to private fields.
    If a struct contains private fields it can not be constructed directly except from within the
    struct itself. The recommended way is to implement a method new(...) as demonstrated in the
    following example.

    struct House:
        pub price: u256
        pub size: u256
        vacant: bool
        pub fn new(price: u256, size: u256) -> House
          return House(price=price, size=size, vacant=true)
    contract Manager:
      house: House
      pub fn create_house(price: u256, size: u256):
        self.house = House::new(price, size)
        let can_access_price: u256 = self.house.price
        # can not access `self.house.vacant` because the field is private
    

(#214)

  • Support non-base type fields in structs
    Support is currently limited in two ways:
    • Structs with complex fields can not be returned from public functions
    • Structs with complex fields can not be stored in storage (#343)
  • Addresses can now be explicitly cast to u256. For example:
    fn f(addr: address) -> u256:
      return u256(addr)
    ``` ([#621](https://github.com/ethereum/fe/issues/621))
    
  • A special function named __call__ can now be defined in contracts.
    The body of this function will execute in place of the standard dispatcher when the contract is called.
    example (with intrinsics):
    contract Foo:
        pub fn __call__(self):
            unsafe:
                if __calldataload(0) == 1:
                    __revert(0, 0)
                else:
                    __return(0, 0)
    

(#622)

Bugfixes

  • Fixed a crash that happend when using a certain unprintable ASCII char (#551)
  • The argument to revert wasn't being lowered by the compiler,
    meaning that some revert calls would cause a compiler panic
    in later stages. For example:
    const BAD_MOJO: u256 = 0xdeaddead
    
    struct Error:
      code: u256
    
    fn fail():
      revert Error(code = BAD_MOJO)
    

(#619)

  • Fixed a regression where an empty list expression ([]) would lead to a compiler crash. (#623)
  • Fixed a bug where int array elements were not sign extended in their ABI encodings. (#633)

v0.12.0-alpha "Lyonsite"

01 Jan 00:37
17950f2
Compare
Choose a tag to compare
Pre-release

WARNING: All Fe releases are alpha releases and only meant to share the development progress with developers and enthusiasts. It is NOT yet ready for production usage.

0.12.0-alpha "Lyonsite" (2021-12-31)

Features

  • Added unsafe low-level "intrinsic" functions, that perform raw evm operations.
    For example:

    fn foo():
      unsafe:
        __mtore(0, 5000)
        assert __mload(0) == 5000
    

    The functions available are exactly those defined in yul's "evm dialect":
    https://docs.soliditylang.org/en/v0.8.11/yul.html#evm-dialect
    but with a double-underscore prefix. Eg selfdestruct -> __selfdestruct.

    These are intended to be used for implementing basic standard library functionality,
    and shouldn't typically be needed in normal contract code.

    Note: some intrinsic functions don't return a value (eg __log0); using these
    functions in a context that assumes a return value of unit type (eg let x: () = __log0(a, b))
    will currently result in a compiler panic in the yul compilation phase. (#603)

  • Added an out of bounds check for accessing array items.
    If an array index is retrieved at an index that is not within
    the bounds of the array it now reverts with Panic(0x32). (#606)

Bugfixes

  • Ensure ternary expression short circuit.

    Example:

    contract Foo:
        pub fn bar(input: u256) -> u256:
            return 1 if input > 5 else revert_me()
        fn revert_me() -> u256:
            revert
            return 0
    

    Previous to this change, the code above would always revert no matter
    which branch of the ternary expressions it would resolve to. That is because
    both sides were evaluated and then one side was discarded. With this change,
    only the branch that doesn't get picked won't get evaluated at all.

    The same is true for the boolean operations and and or. (#488)

Internal Changes - for Fe Contributors

  • Added a globally available dummy std lib.

    This library contains a single get_42 function, which can be called using std::get_42(). Once
    low-level intrinsics have been added to the language, we can delete get_42 and start adding
    useful code. (#601)

v0.11.0-alpha "Karlite"

02 Dec 11:56
Compare
Choose a tag to compare
Pre-release

WARNING: All Fe releases are alpha releases and only meant to share the development progress with developers and enthusiasts. It is NOT yet ready for production usage.

0.11.0-alpha "Karlite" (2021-12-02)

Features

  • Added support for multi-file inputs.

    Implementation details:

    Mostly copied Rust's crate system, but use the the term ingot instead of crate.

    Below is an example of an ingot's file tree, as supported by the current implementation.

    `-- basic_ingot
        `-- src
            |-- bar
            |   `-- baz.fe
            |-- bing.fe
            |-- ding
            |   |-- dang.fe
            |   `-- dong.fe
            `-- main.fe
    

    There are still a few features that will be worked on over the coming months:

    • source files accompanying each directory module (e.g. my_mod.fe)
    • configuration files and the ability to create library ingots
    • test directories
    • module-level pub modifier (all items in a module are public)
    • mod statements (all fe files in the input tree are public modules)

    These things will be implemented in order of importance over the next few months. (#562)

  • The syntax for array types has changed to match other generic types.
    For example, u8[4] is now written Array<u8, 4>. (#571)

  • Functions can now be defined on struct types. Example:

    struct Point:
      x: u64
      y: u64
    
      # Doesn't take `self`. Callable as `Point.origin()`.
      # Note that the syntax for this will soon be changed to `Point::origin()`.
      pub fn origin() -> Point:
        return Point(x=0, y=0)
    
      # Takes `self`. Callable on a value of type `Point`.
      pub fn translate(self, x: u64, y: u64):
        self.x += x
        self.y += y
    
      pub fn add(self, other: Point) -> Point:
        let x: u64 = self.x + other.x
        let y: u64 = self.y + other.y
        return Point(x, y)
    
      pub fn hash(self) -> u256:
        return keccak256(self.abi_encode())
    
    pub fn do_pointy_things():
      let p1: Point = Point.origin()
      p1.translate(5, 10)
    
      let p2: Point = Point(x=1, y=2)
      let p3: Point = p1.add(p2)
    
      assert p3.x == 6 and p3.y == 12
    ``` ([#577](https://github.com/ethereum/fe/issues/577))
    
    
    

Bugfixes

  • Fixed a rare compiler crash.

    Example:

    let my_array: i256[1] = [-1 << 1] 
    

    Previous to this fix, the given example would lead to an ICE. (#550)

  • Contracts can now create an instance of a contract defined later in a file.
    This issue was caused by a weakness in the way we generated yul. (#596)

Internal Changes - for Fe Contributors

  • File IDs are now attached to Spans. (#587)

  • The fe analyzer now builds a dependency graph of source code "items" (functions, contracts, structs, etc).
    This is used in the yulgen phase to determine which items are needed in the yul (intermediate representation)
    output. Note that the yul output is still cluttered with utility functions that may or may not be needed by
    a given contract. These utility functions are defined in the yulgen phase and aren't tracked in the dependency
    graph, so it's not yet possible to filter out the unused functions. We plan to move the definition of many
    of these utility functions into fe; when this happens they'll become part of the dependency graph and will only
    be included in the yul output when needed.

    The dependency graph will also enable future analyzer warnings about unused code. (#596)

v0.10.0-alpha "Jade"

01 Nov 01:56
49e2ce9
Compare
Choose a tag to compare
v0.10.0-alpha "Jade" Pre-release
Pre-release

Features

  • Support for module level constants for base types

    Example:

    const TEN = 10
    contract
      pub fn do_moon_math(self) -> u256:
        return 4711 * TEN
    

    The values of base type constants are always inlined. (#192)

  • Encode revert errors for ABI decoding as Error(0x103) not Panic(0x99) (#492)

  • Replaced import statements with use statements.

    Example:

    use foo::{bar::*, baz as baz26}
    

    Note: this only adds support for parsing use statements. (#547)

  • Functions can no be defined outside of contracts. Example:

    fn add_bonus(x: u256) -> u256:
        return x + 10
    contract PointTracker:
        points: Map<address, u256>
        pub fn add_points(self, user: address, val: u256):
            self.points[user] += add_bonus(val)
    ``` ([#566](https://github.com/ethereum/fe/issues/566))
    
  • Implemented a send_value(to: address, value_in_wei: u256) function.
    The function is similar to the sendValue function by OpenZeppelin with the differences being that:

    1. It reverts with Error(0x100) instead of Error("Address: insufficient balance") to
      safe more gas.
    2. It uses selfbalance() instead of balance(address()) to safe more gas
    3. It reverts with Error(0x101) instead of Error("Address: unable to send value, recipient may have reverted") also to safe more gas. (#567)
  • Added support for unsafe functions and unsafe blocks within functions.
    Note that there's currently no functionality within Fe that requires the use
    of unsafe, but we plan to add built-in unsafe functions that perform raw
    evm operations which will only callable within an unsafe block or function. (#569)

  • Added balance() and balance_of(account: address) methods. (#572)

  • Added support for explicit casting between numeric types.
    Example:

    let a: i8 = i8(-1)
    let a1: i16 = i16(a)
    let a2: u16 = u16(a1)
    
    assert a2 == u16(65535)
    
    let b: i8 = i8(-1)
    let b1: u8 = u8(b)
    let b2: u16 = u16(b1)
    
    assert b2 == u16(255)
    

    Notice that Fe allows casting between any two numeric types but does not allow
    to change both the sign and the size of the type in one step as that would leave
    room for ambiguity as the example above demonstrates. (#576)

Bugfixes

  • Adjust numeric values loaded from memory or storage
    Previous to this fix numeric values that were loaded from either memory or storage
    were not properly loaded on the stack which could result in numeric values not
    treated as intended.
    Example:
    contract Foo:
    
        pub fn bar() -> i8:
            let in_memory: i8[1] = [-3]
            return in_memory[0]
    
    In the example above bar() would not return -3 but 253 instead. (#524)
  • Propagate reverts from external contract calls.
    Before this fix the following code to should_revert() or should_revert2()
    would succeed even though it clearly should not.
    contract A:
      contract_b: B
      pub fn __init__(contract_b: address):
        self.contract_b = B(contract_b)
    
      pub fn should_revert():
        self.contract_b.fail()
    
      pub fn should_revert2():
        self.contract_b.fail_with_custom_error()
    
    struct SomeError:
      pass
    
    contract B:
    
      pub fn fail():
        revert
    
      pub fn fail_with_custom_error():
        revert SomeError()
    
    With this fix the revert errors are properly passed upwards the call hierachy. (#574)
  • Fixed bug in left shift operation.
    Example:
    Let's consider the value 1 as an u8 which is represented as
    the following 256 bit item on the EVM stack 00..|00000001|.
    A left shift of 8 bits (val << 8) turns that into 00..01|00000000|.
    Previous to this fix this resulted in the compiler taking 256 as the
    value for the u8 when clearly 256 is not even in the range of u8
    anymore. With this fix the left shift operations was fixed to properly
    "clean up" the result of the shift so that 00..01|00000000| turns into
    00..00|00000000|. (#575)
  • Ensure negation is checked and reverts with over/underflow if needed.
    Example:
    The minimum value for an i8 is -128 but the maximum value of an i8
    is 127 which means that negating -128 should lead to an overflow since
    128 does not fit into an i8. Before this fix, negation operations where
    not checked for over/underflow resulting in returning the oversized value. (#578)

Internal Changes - for Fe Contributors

  • In the analysis stage, all name resolution (of variable names, function names,
    type names, etc used in code) now happens via a single resolve_name pathway,
    so we can catch more cases of name collisions and log more helpful error messages. (#555)
  • Added a new category of tests: differential contract testing.
    Each of these tests is pased on a pair of contracts where one implementation
    is written in Fe and the other one is written in Solidity. The implementations
    should have the same public APIs and are assumed to always return identical
    results given equal inputs. The inputs are randomly generated using proptest
    and hence are expected to discover unknown bugs. (#578)

v0.9.0-alpha "Iridium"

29 Sep 19:37
e23abe3
Compare
Choose a tag to compare
Pre-release

0.9.0-alpha "Iridium"

Features

  • The self variable is no longer implicitly defined in code blocks. It must now be declared
    as the first parameter in a function signature.

    Example:

    contract Foo:
        my_stored_num: u256
        pub fn bar(self, my_num: u256):
            self.my_stored_num = my_num
          
        pub fn baz(self):
            self.bar(my_pure_func())
          
        pub fn my_pure_func() -> u256:
            return 42 + 26
    

(#520)

  • The analyzer now disallows defining a type, variable, or function whose
    name conflicts with a built-in type, function, or object.
    Example:
    error: type name conflicts with built-in type
    ┌─ compile_errors/shadow_builtin_type.fe:1:6
    │
    1 │ type u256 = u8
    │      ^^^^ `u256` is a built-in type
    

(#539)

Bugfixes

  • Fixed cases where the analyzer would correctly reject code, but would panic instead of logging an error message. (#534)
  • Non-fatal parser errors (eg missing parentheses when defining a function that takes no arguments: fn foo:)
    are no longer ignored if the semantic analysis stage succeeds. (#535)
  • Fixed issue #531 by adding a $ to the front of lowered tuple names. (#546)

Internal Changes - for Fe Contributors

  • Implemented pretty printing of Fe AST. (#540)

v0.8.0-alpha "Haxonite"

31 Aug 15:41
Compare
Choose a tag to compare
Pre-release

0.8.0-alpha "Haxonite" (2021-08-31)

WARNING: All Fe releases are alpha releases and only meant to share the development progress with developers and enthusiasts. It is NOT yet ready for production usage.

Features

  • Support quotes, tabs and carriage returns in string literals and otherwise
    restrict string literals to the printable subset of the ASCII table. (#329)

  • The analyzer now uses a query-based system, which fixes some shortcomings of the previous implementation.

    • Types can now refer to other types defined later in the file.
      Example:
    type Posts = Map<PostId, PostBody>
    type PostId = u256
    type PostBody = String<140>
    
    • Duplicate definition errors now show the location of the original definition.
    • The analysis of each function, type definition, etc happens independently, so an error in one
      doesn't stop the analysis pass. This means fe can report more user errors in a single run of the compiler. (#468)
  • Function definitions are now denoted with the keyword fn instead of def. (#496)

  • Variable declarations are now preceded by the let keyword. Example: let x: u8 = 1. (#509)

  • Implemented support for numeric unary invert operator (~) (#526)

Bugfixes

  • Calling self.__init__() now results in a nice error instead of a panic in the yul compilation stage. (#468)

  • Fixed an issue where certain expressions were not being moved to the correct location. (#493)

  • Fixed an issue with a missing return statement not properly detected.

    Previous to this fix, the following code compiles but it should not:

    contract Foo:
        pub fn bar(val: u256) -> u256:
            if val > 1:
                return 5
    

    With this change, the compiler rightfully detects that the code is missing
    a return or revert statement after the if statement since it is not
    guaranteed that the path of execution always follows the arm of the if statement. (#497)

  • Fixed a bug in the analyzer which allowed tuple item accessor names with a leading 0,
    resulting in an internal compiler error in a later pass. Example: my_tuple.item001.
    These are now rejected with an error message. (#510)

  • Check call argument labels for function calls.

    Previously the compiler would not check any labels that were used
    when making function calls on self or external contracts.

    This can be especially problematic if gives developers the impression
    that they could apply function arguments in any order as long as they
    are named which is not the case.

    contract Foo:
    
        pub fn baz():
            self.bar(val2=1, doesnt_even_exist=2)
      
        pub fn bar(val1: u256, val2: u256):
            pass
    

    Code as the one above is now rightfully rejected by the compiler. (#517)

Improved Documentation

  • Various improvements and bug fixes to both the content and layout of the specification. (#489)

  • Document all remaining statements and expressions in the spec.

    Also added a CI check to ensure code examples in the documentation
    are validated against the latest compiler. (#514)

Internal Changes - for Fe Contributors

  • Separated Fe type traits between crates. (#485)

v0.7.0-alpha "Galaxite"

27 Jul 10:49
Compare
Choose a tag to compare
Pre-release

WARNING: All Fe releases are alpha releases and only meant to share the development progress with developers and enthusiasts. It is NOT yet ready for production usage.

0.7.0-alpha "Galaxite" (2021-07-27)

Features

  • Enable the optimizer by default. The optimizer can still be disabled
    by supplying --optimize=false as an argument. (#439)

  • The following checks are now performed while decoding data:

    • The size of the encoded data fits within the size range known at compile-time.
    • Values are correctly padded.
      • unsigned integers, addresses, and bools are checked to have correct left zero padding
      • the size of signed integers are checked
      • bytes and strings are checked to have correct right padding
    • Data section offsets are consistent with the size of preceding values in the data section.
    • The dynamic size of strings does not exceed their maximum size.
    • The dynamic size of byte arrays (u8[n]) is equal to the size of the array. (#440)
  • Type aliases can now include tuples. Example:

    type InternetPoints = (address, u256)
    

    (#459)

  • Revert with custom errors

    Example:

    struct PlatformError:
      code: u256
    
    pub def do_something():
      revert PlatformError(code=4711)
    

    Error encoding follows Solidity which is based on EIP-838. This means that custom errors returned from Fe are fully compatible with Solidity. (#464)

    • The builtin value msg.sig now has type u256.
    • Removed the bytes[n] type. The type u8[n] can be used in its placed and will be encoded as a dynamically-sized, but checked, bytes component. (#472)
  • Encode certain reverts as panics.

    With this change, the following reverts are encoded as Panic(uint256) with
    the following panic codes:

    • 0x01: An assertion that failed and did not specify an error message
    • 0x11: An arithmetic expression resulted in an over- or underflow
    • 0x12: An arithmetic expression divided or modulo by zero

    The panic codes are aligned with the panic codes that Solidity uses. (#476)

Bugfixes

  • Fixed a crash when trying to access an invalid attribute on a string.

    Example:

    contract Foo:
    
      pub def foo():
        "".does_not_exist
    

    The above now yields a proper user error. (#444)

  • Ensure String<N> type is capitalized in error messages (#445)

  • Fixed ICE when using a static string that spans over multiple lines.

    Previous to this fix, the following code would lead to a compiler crash:

    contract Foo:
        pub def return_with_newline() -> String<16>:
            return "foo
            balu"
    

    The above code now works as intended. (#448)

  • Fixed ICE when using a tuple declaration and specifying a non-tuple type.
    Fixed a second ICE when using a tuple declaration where the number of
    target items doesn't match the number of items in the declared type. (#469)

Internal Changes - for Fe Contributors

    • Cleaned up ABI encoding internals.
    • Improved yulc panic formatting. (#472)