Skip to content

Commit

Permalink
address literals
Browse files Browse the repository at this point in the history
  • Loading branch information
sbillig authored and cburgdorf committed Apr 5, 2023
1 parent 7c63789 commit a2037b2
Show file tree
Hide file tree
Showing 21 changed files with 94 additions and 57 deletions.
1 change: 1 addition & 0 deletions crates/analyzer/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ impl fmt::Display for CallType {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Constant {
Int(BigInt),
Address(BigInt),
Bool(bool),
Str(SmolStr),
}
4 changes: 4 additions & 0 deletions crates/analyzer/src/namespace/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ pub fn i256_min() -> BigInt {
BigInt::from(-2).pow(255)
}

pub fn address_max() -> BigInt {
BigInt::from(2).pow(160) - 1
}

/// Names that can be used to build identifiers without collision.
pub trait SafeNames {
/// Name in the lower snake format (e.g. lower_snake_case).
Expand Down
17 changes: 14 additions & 3 deletions crates/analyzer/src/traversal/const_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,21 @@ impl Constant {
typ: &Type,
span: Span,
) -> Result<Self, ConstEvalError> {
debug_assert!(matches!(typ, Type::Base(Base::Numeric(_))));

let literal = numeric::Literal::new(s);
Self::make_const_numeric_with_ty(context, literal.parse::<BigInt>().unwrap(), typ, span)
let num = literal.parse::<BigInt>().unwrap();
match typ {
Type::Base(Base::Numeric(_)) => {
Self::make_const_numeric_with_ty(context, num, typ, span)
}
Type::Base(Base::Address) => {
if num >= BigInt::zero() && num <= types::address_max() {
Ok(Constant::Address(num))
} else {
Err(overflow_error(context, span))
}
}
_ => unreachable!(),
}
}

/// Returns constant from numeric literal that fits type bits.
Expand Down
22 changes: 19 additions & 3 deletions crates/analyzer/src/traversal/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::namespace::items::{
};
use crate::namespace::scopes::{check_visibility, BlockScopeType};
use crate::namespace::types::{
Array, Base, FeString, Integer, TraitOrType, Tuple, Type, TypeDowncast, TypeId,
self, Array, Base, FeString, Integer, TraitOrType, Tuple, Type, TypeDowncast, TypeId,
};
use crate::operations;
use crate::traversal::call_args::{validate_arg_count, validate_named_args};
Expand All @@ -24,7 +24,7 @@ use fe_parser::ast as fe;
use fe_parser::ast::GenericArg;
use fe_parser::node::Node;
use num_bigint::BigInt;
use num_traits::ToPrimitive;
use num_traits::{ToPrimitive, Zero};
use smol_str::SmolStr;
use std::ops::RangeInclusive;
use std::str::FromStr;
Expand Down Expand Up @@ -552,10 +552,26 @@ fn expr_num(
_ => unreachable!(),
};

let literal = numeric::Literal::new(num);
let num = literal
.parse::<BigInt>()
.expect("the numeric literal contains a invalid digit");

if expected_type == Some(TypeId::address(context.db())) {
if num < BigInt::zero() && num > types::address_max() {
context.error(
"literal out of range for `address` type",
exp.span,
"does not fit into type `address`",
);
}
// TODO: error if literal.radix != Radix::Hexadecimal ?
return ExpressionAttributes::new(TypeId::address(context.db()));
}

let int_typ = expected_type
.and_then(|id| id.deref(context.db()).as_int(context.db()))
.unwrap_or(Integer::U256);
let num = to_bigint(num);
validate_numeric_literal_fits_type(context, num, exp.span, int_typ);
return ExpressionAttributes::new(TypeId::int(context.db(), int_typ));
}
Expand Down
9 changes: 6 additions & 3 deletions crates/analyzer/src/traversal/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,12 @@ pub fn apply_generic_type_args(
// TODO: Fix me when `GenericArg` can represent literals not only `Int`.
match const_value {
Constant::Int(val) => Ok(GenericArg::Int(val.try_into().unwrap())),
Constant::Bool(_) | Constant::Str(_) => Err(TypeError::new(
context.not_yet_implemented("non numeric type const generics", expr.span),
)),
Constant::Address(_) | Constant::Bool(_) | Constant::Str(_) => {
Err(TypeError::new(context.not_yet_implemented(
"non numeric type const generics",
expr.span,
)))
}
}
}

Expand Down
19 changes: 12 additions & 7 deletions crates/analyzer/tests/snapshots/analysis__const_local.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/analyzer/tests/analysis.rs
assertion_line: 302
expression: "build_snapshot(&db, module)"
---
note:
Expand All @@ -10,8 +11,8 @@ note:
4 │ │ const C2: i64 = 2
5 │ │ const C3: i64 = 10
· │
15 │ │ return C10
16 │ │ }
16 │ │ return C10
17 │ │ }
│ ╰─────^ params: [] -> u256

note:
Expand Down Expand Up @@ -39,7 +40,9 @@ note:
^^ bool
13const C10: u256 = 42 if C9 else 0 // 42
^^^ u256
14let _arr: Array<bool, { C10 }> = [true; { C10 }]
14const C11: address = 0xfefe
^^^ address
15let _arr: Array<bool, { C10 }> = [true; { C10 }]
^^^^ Array<bool, 42>

note:
Expand Down Expand Up @@ -144,18 +147,20 @@ note:
13const C10: u256 = 42 if C9 else 0 // 42
^^^^^^^^^^^^^^^ u256 = Int(42)
14let _arr: Array<bool, { C10 }> = [true; { C10 }]
14const C11: address = 0xfefe
^^^^^^ address = Address(65278)
15let _arr: Array<bool, { C10 }> = [true; { C10 }]
^^^ ^^^^ ^^^ u256
│ │ │
│ │ bool
u256

note:
┌─ const_local.fe:14:42
┌─ const_local.fe:15:42
14let _arr: Array<bool, { C10 }> = [true; { C10 }]
15let _arr: Array<bool, { C10 }> = [true; { C10 }]
^^^^^^^^^^^^^^^ Array<bool, 42>
15return C10
16return C10
^^^ u256


37 changes: 13 additions & 24 deletions crates/analyzer/tests/snapshots/analysis__erc20_token.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/analyzer/tests/analysis.rs
assertion_line: 183
expression: "build_snapshot(&db, module)"
---
note:
Expand Down Expand Up @@ -536,8 +537,8 @@ note:
┌─ erc20_token.fe:83:5
83 │ ╭ fn _transfer(mut self, mut ctx: Context, sender: address, recipient: address, value: u256) {
84 │ │ assert sender != address(0)
85 │ │ assert recipient != address(0)
84 │ │ assert sender != 0
85 │ │ assert recipient != 0
86 │ │ _before_token_transfer(from: sender, to: recipient, value)
· │
89 │ │ ctx.emit(Transfer(from: sender, to: recipient, value))
Expand All @@ -547,38 +548,26 @@ note:
note:
┌─ erc20_token.fe:84:16
84 │ assert sender != address(0)
│ ^^^^^^ ^ u256
│ │
84 │ assert sender != 0
│ ^^^^^^ ^ address
│ │
│ address

note:
┌─ erc20_token.fe:84:26
84 │ assert sender != address(0)
│ ^^^^^^^^^^ address

note:
┌─ erc20_token.fe:84:16
84 │ assert sender != address(0)
│ ^^^^^^^^^^^^^^^^^^^^ bool
85 │ assert recipient != address(0)
│ ^^^^^^^^^ ^ u256
│ │
84 │ assert sender != 0
│ ^^^^^^^^^^^ bool
85 │ assert recipient != 0
│ ^^^^^^^^^ ^ address
│ │
│ address

note:
┌─ erc20_token.fe:85:29
85 │ assert recipient != address(0)
│ ^^^^^^^^^^ address

note:
┌─ erc20_token.fe:85:16
85 │ assert recipient != address(0)
│ ^^^^^^^^^^^^^^^^^^^^^^^ bool
85 │ assert recipient != 0
│ ^^^^^^^^^^^^^^ bool
86 │ _before_token_transfer(from: sender, to: recipient, value)
│ ^^^^^^ ^^^^^^^^^ ^^^^^ u256
│ │ │
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
---
source: crates/analyzer/tests/errors.rs
assertion_line: 281
expression: "error_string(&path, test_files::fixture(path))"
---
error: expected function to return `address` but was `u256`
┌─ compile_errors/mismatch_return_type.fe:3:9
3 │ return 1
│ ^^^^^^^^
3 │ return u256(1)
│ ^^^^^^^^^^^^^^


Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
---
source: crates/analyzer/tests/errors.rs
assertion_line: 295
expression: "error_string(&path, test_files::fixture(path))"
---
error: incorrect type for `foo` argument at position 0
┌─ compile_errors/return_call_to_fn_with_param_type_mismatch.fe:7:20
7return foo(100)
│ ^^^ this has type `u256`; expected type `address`
│ ^^^ this has type `u256`; expected type `bool`


2 changes: 1 addition & 1 deletion crates/mir/src/ir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub enum ConstantValue {
impl From<context::Constant> for ConstantValue {
fn from(value: context::Constant) -> Self {
match value {
context::Constant::Int(num) => Self::Immediate(num),
context::Constant::Int(num) | context::Constant::Address(num) => Self::Immediate(num),
context::Constant::Str(s) => Self::Str(s),
context::Constant::Bool(b) => Self::Bool(b),
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
source: crates/parser/tests/cases/print_ast.rs
assertion_line: 45
expression: "parse_and_print(\"demos/erc20_token.fe\", src)"

---
struct Approval {
pub owner: address
Expand Down Expand Up @@ -82,8 +82,8 @@ contract ERC20 {
}

fn _transfer(mut self, mut ctx: Context, sender: address, recipient: address, value: u256) {
assert sender != address(0)
assert recipient != address(0)
assert sender != 0
assert recipient != 0
_before_token_transfer(from: sender, to: recipient, value)
self._balances[sender] = self._balances[sender] - value
self._balances[recipient] = self._balances[recipient] + value
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
contract Foo {
pub fn bar() -> address {
return 1
return u256(1)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
contract Foo {
pub fn foo(_ val: address) -> u256 {
pub fn foo(_ val: bool) -> u256 {
return 42
}

Expand Down
4 changes: 2 additions & 2 deletions crates/test-files/fixtures/demos/erc20_token.fe
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ contract ERC20 {
}

fn _transfer(mut self, mut ctx: Context, sender: address, recipient: address, value: u256) {
assert sender != address(0)
assert recipient != address(0)
assert sender != 0
assert recipient != 0
_before_token_transfer(from: sender, to: recipient, value)
self._balances[sender] = self._balances[sender] - value
self._balances[recipient] = self._balances[recipient] + value
Expand Down
1 change: 1 addition & 0 deletions crates/test-files/fixtures/features/const_local.fe
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ contract Foo {
const C8: bool = false
const C9: bool = C8 < C7 // true
const C10: u256 = 42 if C9 else 0 // 42
const C11: address = 0xfefe
let _arr: Array<bool, { C10 }> = [true; { C10 }]
return C10
}
Expand Down
1 change: 1 addition & 0 deletions crates/tests/fixtures/files/const_local.fe
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ fn bar() -> u256 {
const C8: bool = false
const C9: bool = C8 < C7 // true
const C10: u256 = 42 if C9 else 0 // 42
const C11: address = 0xfefe
let _arr: Array<bool, { C10 }> = [true; { C10 }]
return C10
}
Expand Down
4 changes: 2 additions & 2 deletions docs/src/spec/expressions/call.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ Example:
contract Foo {
pub fn demo(self) {
let ann: address = address(0xaa)
let bob: address = address(0xbb)
let ann: address = 0xaa
let bob: address = 0xbb
self.transfer(from: ann, to: bob, 25)
}
Expand Down
4 changes: 2 additions & 2 deletions docs/src/spec/items/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ contract CoolCoin {
return true
}
pub fn demo(mut self) {
let ann: address = address(0xaa)
let bob: address = address(0xbb)
let ann: address = 0xaa
let bob: address = 0xbb
self.balance[ann] = 100
let bonus: u256 = 2
Expand Down
2 changes: 1 addition & 1 deletion docs/src/spec/items/visibility_and_privacy.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use ding::dong::Dang
contract Foo {
pub fn hot_dang() -> Dang {
return Dang(
my_address: address(8),
my_address: 8,
my_u256: 42,
my_i8: -1
)
Expand Down
2 changes: 1 addition & 1 deletion docs/src/spec/type_system/types/address.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ contract Example {
fn do_something() {
// A plain address (not part of a tuple, struct etc) remains on the stack
let dai_contract: address = address(0x6b175474e89094c44da98b954eedeac495271d0f)
let dai_contract: address = 0x6b175474e89094c44da98b954eedeac495271d0f
}
}
```
4 changes: 4 additions & 0 deletions newsfragments/864.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
`address` values can now be specified with a number literal, with no explicit
cast. So instead of `let t: address = address(0xfe)`, one can now write
`let t: address = 0xfe`. This also means that it's possible to define `const`
addresses: `const SOME_KNOWN_CONTRACT: address = 0xfefefefe`

0 comments on commit a2037b2

Please sign in to comment.