diff --git a/crates/analyzer/src/namespace/types.rs b/crates/analyzer/src/namespace/types.rs index a662398141..ecf275203a 100644 --- a/crates/analyzer/src/namespace/types.rs +++ b/crates/analyzer/src/namespace/types.rs @@ -98,6 +98,7 @@ impl TypeId { self.typ(db).has_fixed_size(db) } + // XXX is Contract type usable everywhere Base types are? /// `true` if Type::Base or Type::Contract (which is just an Address) pub fn is_primitive(&self, db: &dyn AnalyzerDb) -> bool { matches!(self.typ(db), Type::Base(_) | Type::Contract(_)) diff --git a/crates/analyzer/src/traversal/call_args.rs b/crates/analyzer/src/traversal/call_args.rs index 08979bed30..33e9fd8ee7 100644 --- a/crates/analyzer/src/traversal/call_args.rs +++ b/crates/analyzer/src/traversal/call_args.rs @@ -47,7 +47,8 @@ impl LabeledParameter for (Option, Result) { fn typ(&self) -> Result { self.1.clone() } - fn is_sink(&self) -> bool { // XXX + fn is_sink(&self) -> bool { + // XXX true } } diff --git a/crates/analyzer/src/traversal/expressions.rs b/crates/analyzer/src/traversal/expressions.rs index a73246f8e4..7387ea24d4 100644 --- a/crates/analyzer/src/traversal/expressions.rs +++ b/crates/analyzer/src/traversal/expressions.rs @@ -1616,21 +1616,21 @@ fn expr_call_builtin_value_method( }; match method { ValueMethod::ToMem => { - if ty.is_base(context.db()) { - context.fancy_error( - "`to_mem()` called on primitive type", - vec![ - Label::primary( - value.span, - "this value does not need to be explicitly copied to memory", - ), - Label::secondary(method_name.span, "hint: remove `.to_mem()`"), - ], - vec![], - ); - } else if ty.is_sptr(context.db()) { + if ty.is_sptr(context.db()) { let inner = ty.deref(context.db()); - if inner.is_map(context.db()) { + if inner.is_primitive(context.db()) { + context.fancy_error( + "`to_mem()` called on primitive type", + vec![ + Label::primary( + value.span, + "this value does not need to be explicitly copied to memory", + ), + Label::secondary(method_name.span, "hint: remove `.to_mem()`"), + ], + vec![], + ); + } else if inner.is_map(context.db()) { context.fancy_error( "`to_mem()` called on a Map", vec![ @@ -1639,18 +1639,21 @@ fn expr_call_builtin_value_method( ], vec![], ); + + // TODO: this restriction should be removed + } else if ty.is_generic(context.db()) { + context.fancy_error( + "`to_mem()` called on generic type", + vec![ + Label::primary(value.span, "this value can not be copied to memory"), + Label::secondary(method_name.span, "hint: remove `.to_mem()`"), + ], + vec![], + ); } + value_attrs.typ = inner; return Ok((value_attrs, calltype)); - } else if ty.is_generic(context.db()) { - context.fancy_error( - "`to_mem()` called on generic type", - vec![ - Label::primary(value.span, "this value can not be copied to memory"), - Label::secondary(method_name.span, "hint: remove `.to_mem()`"), - ], - vec![], - ); } else { context.fancy_error( "`to_mem()` called on value in memory", @@ -1951,13 +1954,22 @@ fn expr_comp_operation( context: &mut dyn AnalyzerContext, exp: &Node, ) -> Result { - if let fe::Expr::CompOperation { left, op: _, right } = &exp.kind { + if let fe::Expr::CompOperation { left, op, right } = &exp.kind { // comparison operands should be moved to the stack let left_ty = value_expr_type(context, left, None)?; - expect_expr_type(context, right, left_ty, false)?; - - // XXX test: struct < struct, array != array - + if left_ty.is_primitive(context.db()) { + expect_expr_type(context, right, left_ty, false)?; + } else { + context.error( + &format!( + "`{}` type can't be compared with the `{}` operator", + left_ty.display(context.db()), + op.kind + ), + exp.span, + "invalid comparison", + ); + } return Ok(ExpressionAttributes::new(TypeId::bool(context.db()))); } diff --git a/crates/analyzer/src/traversal/functions.rs b/crates/analyzer/src/traversal/functions.rs index df02de59b5..c5f0980634 100644 --- a/crates/analyzer/src/traversal/functions.rs +++ b/crates/analyzer/src/traversal/functions.rs @@ -734,7 +734,7 @@ fn func_return(scope: &mut BlockScope, stmt: &Node) -> Result<(), &format!( "expected function to return `{}` but was `{}`", expected_type.display(scope.db()), - value_attr.typ.display(scope.db()) + value_attr.typ.deref(scope.db()).display(scope.db()) ), stmt.span, "", diff --git a/crates/analyzer/src/traversal/types.rs b/crates/analyzer/src/traversal/types.rs index 667c6bf5ed..83e195f66e 100644 --- a/crates/analyzer/src/traversal/types.rs +++ b/crates/analyzer/src/traversal/types.rs @@ -112,7 +112,6 @@ pub fn try_cast_type( }; } -// XXX assert inner is_primitive? pub fn deref_type(context: &mut dyn AnalyzerContext, expr: &Node, ty: TypeId) -> TypeId { match ty.typ(context.db()) { Type::SPtr(inner) => adjust_type(context, expr, inner, AdjustmentKind::Load), @@ -157,6 +156,8 @@ fn coerce( should_copy: bool, chain: Vec, ) -> Result, TypeCoercionError> { + // Cut down on some obviously unnecessary copy operations, + // because we don't currently optimize MIR. let should_copy = should_copy && !into.is_sptr(context.db()) && !into.deref(context.db()).is_primitive(context.db()) @@ -301,9 +302,16 @@ fn add_adjustment_if( fn is_temporary(context: &dyn AnalyzerContext, expr: &Node) -> bool { match &expr.kind { ast::Expr::Tuple { .. } | ast::Expr::List { .. } | ast::Expr::Repeat { .. } => true, + ast::Expr::Path(path) => { + matches!( + context.resolve_path(path, expr.span), + Ok(NamedThing::EnumVariant(_)) + ) + } ast::Expr::Call { func, .. } => matches!( context.get_call(func), Some(CallType::TypeConstructor(_)) + | Some(CallType::EnumConstructor(_)) | Some(CallType::BuiltinValueMethod { method: ValueMethod::ToMem | ValueMethod::AbiEncode, .. diff --git a/crates/analyzer/tests/errors.rs b/crates/analyzer/tests/errors.rs index 03e7c555f7..58e109a8a1 100644 --- a/crates/analyzer/tests/errors.rs +++ b/crates/analyzer/tests/errors.rs @@ -349,3 +349,4 @@ test_file! { uninit_values } test_file! { invalid_repeat_length } test_file! { invalid_struct_pub_qualifier } test_file! { mut_mistakes } +test_file! { invalid_comparisons } diff --git a/crates/analyzer/tests/snapshots/analysis__enum_match.snap b/crates/analyzer/tests/snapshots/analysis__enum_match.snap index 49967b283d..b3e0bb15b9 100644 --- a/crates/analyzer/tests/snapshots/analysis__enum_match.snap +++ b/crates/analyzer/tests/snapshots/analysis__enum_match.snap @@ -145,7 +145,7 @@ note: ┌─ enum_match.fe:49:57 │ 49 │ let nested: MyEnumNested = MyEnumNested::Nested(MyEnum::Tuple(x, y)) - │ ^^^^^^^^^^^^^^^^^^^ MyEnum -Copy-> MyEnum + │ ^^^^^^^^^^^^^^^^^^^ MyEnum note: ┌─ enum_match.fe:49:36 @@ -207,9 +207,9 @@ note: ┌─ enum_match.fe:61:41 │ 61 │ let tup: Tuple2 = Tuple2::Value(MyEnum::Tuple(1, 2), MyEnum::UnitTuple()) - │ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ MyEnum -Copy-> MyEnum + │ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ MyEnum │ │ - │ MyEnum -Copy-> MyEnum + │ MyEnum note: ┌─ enum_match.fe:61:27 @@ -365,7 +365,7 @@ note: ┌─ enum_match.fe:103:57 │ 103 │ let nested: MyEnumNested = MyEnumNested::Nested(MyEnum::Unit) - │ ^^^^^^^^^^^^ MyEnum -Copy-> MyEnum + │ ^^^^^^^^^^^^ MyEnum note: ┌─ enum_match.fe:103:36 @@ -486,7 +486,7 @@ note: 137 │ let mut res: u256 = 0 │ ^ u256 138 │ let mut state: State = State::Continue - │ ^^^^^^^^^^^^^^^ State -Copy-> State + │ ^^^^^^^^^^^^^^^ State 139 │ 140 │ let mut my_array: Array = [0; 3] │ ^ ^ u256 @@ -555,7 +555,7 @@ note: 154 │ if res == 15 { │ ^^^^^^^^^ bool 155 │ state = State::Done - │ ^^^^^ ^^^^^^^^^^^ State -Copy-> State + │ ^^^^^ ^^^^^^^^^^^ State │ │ │ mut State · @@ -565,25 +565,69 @@ note: note: ┌─ enum_match.fe:162:5 │ -162 │ ╭ pub fn rest_pattern_head(x: u32, y: u256) -> u256 { -163 │ │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) -164 │ │ match pat { -165 │ │ (.., MyEnum::Tuple(x1, y1)) => { +162 │ ╭ pub fn match_in_loop_simple() -> u256 { +163 │ │ let mut state: State = State::Continue +164 │ │ let mut count: u256 = 0 +165 │ │ while true { · │ -171 │ │ } -172 │ │ } +175 │ │ return count +176 │ │ } + │ ╰─────^ params: [] -> u256 + +note: + ┌─ enum_match.fe:163:17 + │ +163 │ let mut state: State = State::Continue + │ ^^^^^ mut State +164 │ let mut count: u256 = 0 + │ ^^^^^ mut u256 + +note: + ┌─ enum_match.fe:163:32 + │ +163 │ let mut state: State = State::Continue + │ ^^^^^^^^^^^^^^^ State +164 │ let mut count: u256 = 0 + │ ^ u256 +165 │ while true { + │ ^^^^ bool +166 │ match state { + │ ^^^^^ mut State + · +172 │ count += 1 + │ ^^^^^ ^ u256 + │ │ + │ mut u256 +173 │ state = State::Done + │ ^^^^^ ^^^^^^^^^^^ State + │ │ + │ mut State +174 │ } +175 │ return count + │ ^^^^^ mut u256 + +note: + ┌─ enum_match.fe:179:5 + │ +179 │ ╭ pub fn rest_pattern_head(x: u32, y: u256) -> u256 { +180 │ │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +181 │ │ match pat { +182 │ │ (.., MyEnum::Tuple(x1, y1)) => { + · │ +188 │ │ } +189 │ │ } │ ╰─────^ params: [{ label: None, name: x, typ: u32 }, { label: None, name: y, typ: u256 }] -> u256 note: - ┌─ enum_match.fe:163:13 + ┌─ enum_match.fe:180:13 │ -163 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +180 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) │ ^^^ (MyEnum, MyEnum, MyEnum, MyEnum) note: - ┌─ enum_match.fe:163:54 + ┌─ enum_match.fe:180:54 │ -163 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +180 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) │ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^ ^ u256 │ │ │ │ │ │ │ │ │ u32 @@ -592,69 +636,69 @@ note: │ MyEnum note: - ┌─ enum_match.fe:163:96 + ┌─ enum_match.fe:180:96 │ -163 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +180 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) │ ^^^^^^^^^^^^^^^^^^^ MyEnum note: - ┌─ enum_match.fe:163:53 + ┌─ enum_match.fe:180:53 │ -163 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +180 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (MyEnum, MyEnum, MyEnum, MyEnum) -164 │ match pat { +181 │ match pat { │ ^^^ (MyEnum, MyEnum, MyEnum, MyEnum) -165 │ (.., MyEnum::Tuple(x1, y1)) => { -166 │ return u256(x1) + y1 +182 │ (.., MyEnum::Tuple(x1, y1)) => { +183 │ return u256(x1) + y1 │ ^^ u32 note: - ┌─ enum_match.fe:166:24 + ┌─ enum_match.fe:183:24 │ -166 │ return u256(x1) + y1 +183 │ return u256(x1) + y1 │ ^^^^^^^^ ^^ u256 │ │ │ u256 note: - ┌─ enum_match.fe:166:24 + ┌─ enum_match.fe:183:24 │ -166 │ return u256(x1) + y1 +183 │ return u256(x1) + y1 │ ^^^^^^^^^^^^^ u256 · -169 │ return 0 +186 │ return 0 │ ^ u256 note: - ┌─ enum_match.fe:174:5 + ┌─ enum_match.fe:191:5 │ -174 │ ╭ pub fn rest_pattern_tail(x: u32, y: u256) -> u256 { -175 │ │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) -176 │ │ match pat { -177 │ │ (MyEnum::Tuple(x1, y1), ..) => { +191 │ ╭ pub fn rest_pattern_tail(x: u32, y: u256) -> u256 { +192 │ │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) +193 │ │ match pat { +194 │ │ (MyEnum::Tuple(x1, y1), ..) => { · │ -183 │ │ } -184 │ │ } +200 │ │ } +201 │ │ } │ ╰─────^ params: [{ label: None, name: x, typ: u32 }, { label: None, name: y, typ: u256 }] -> u256 note: - ┌─ enum_match.fe:175:13 + ┌─ enum_match.fe:192:13 │ -175 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) +192 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) │ ^^^ (MyEnum, MyEnum, MyEnum, MyEnum) note: - ┌─ enum_match.fe:175:68 + ┌─ enum_match.fe:192:68 │ -175 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) +192 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) │ ^ ^ u256 │ │ │ u32 note: - ┌─ enum_match.fe:175:54 + ┌─ enum_match.fe:192:54 │ -175 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) +192 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) │ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ MyEnum │ │ │ │ │ │ │ MyEnum @@ -662,63 +706,63 @@ note: │ MyEnum note: - ┌─ enum_match.fe:175:53 + ┌─ enum_match.fe:192:53 │ -175 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) +192 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Unit) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (MyEnum, MyEnum, MyEnum, MyEnum) -176 │ match pat { +193 │ match pat { │ ^^^ (MyEnum, MyEnum, MyEnum, MyEnum) -177 │ (MyEnum::Tuple(x1, y1), ..) => { -178 │ return u256(x1) + y1 +194 │ (MyEnum::Tuple(x1, y1), ..) => { +195 │ return u256(x1) + y1 │ ^^ u32 note: - ┌─ enum_match.fe:178:24 + ┌─ enum_match.fe:195:24 │ -178 │ return u256(x1) + y1 +195 │ return u256(x1) + y1 │ ^^^^^^^^ ^^ u256 │ │ │ u256 note: - ┌─ enum_match.fe:178:24 + ┌─ enum_match.fe:195:24 │ -178 │ return u256(x1) + y1 +195 │ return u256(x1) + y1 │ ^^^^^^^^^^^^^ u256 · -181 │ return 0 +198 │ return 0 │ ^ u256 note: - ┌─ enum_match.fe:186:5 + ┌─ enum_match.fe:203:5 │ -186 │ ╭ pub fn rest_pattern_middle(x: u32, y: u256) -> u256 { -187 │ │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) -188 │ │ match pat { -189 │ │ (MyEnum::Tuple(x1, y1), .., MyEnum::Tuple(x2, y2)) => { +203 │ ╭ pub fn rest_pattern_middle(x: u32, y: u256) -> u256 { +204 │ │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +205 │ │ match pat { +206 │ │ (MyEnum::Tuple(x1, y1), .., MyEnum::Tuple(x2, y2)) => { · │ -195 │ │ } -196 │ │ } +212 │ │ } +213 │ │ } │ ╰─────^ params: [{ label: None, name: x, typ: u32 }, { label: None, name: y, typ: u256 }] -> u256 note: - ┌─ enum_match.fe:187:13 + ┌─ enum_match.fe:204:13 │ -187 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +204 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) │ ^^^ (MyEnum, MyEnum, MyEnum, MyEnum) note: - ┌─ enum_match.fe:187:68 + ┌─ enum_match.fe:204:68 │ -187 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +204 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) │ ^ ^ u256 │ │ │ u32 note: - ┌─ enum_match.fe:187:54 + ┌─ enum_match.fe:204:54 │ -187 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +204 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) │ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^ ^ u256 │ │ │ │ │ │ │ │ │ u32 @@ -727,286 +771,286 @@ note: │ MyEnum note: - ┌─ enum_match.fe:187:103 + ┌─ enum_match.fe:204:103 │ -187 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +204 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) │ ^^^^^^^^^^^^^^^^^^^ MyEnum note: - ┌─ enum_match.fe:187:53 + ┌─ enum_match.fe:204:53 │ -187 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) +204 │ let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Tuple(x, y), MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (MyEnum, MyEnum, MyEnum, MyEnum) -188 │ match pat { +205 │ match pat { │ ^^^ (MyEnum, MyEnum, MyEnum, MyEnum) -189 │ (MyEnum::Tuple(x1, y1), .., MyEnum::Tuple(x2, y2)) => { -190 │ return u256(x1) + y1 + u256(x2) + y2 +206 │ (MyEnum::Tuple(x1, y1), .., MyEnum::Tuple(x2, y2)) => { +207 │ return u256(x1) + y1 + u256(x2) + y2 │ ^^ u32 note: - ┌─ enum_match.fe:190:24 + ┌─ enum_match.fe:207:24 │ -190 │ return u256(x1) + y1 + u256(x2) + y2 +207 │ return u256(x1) + y1 + u256(x2) + y2 │ ^^^^^^^^ ^^ u256 │ │ │ u256 note: - ┌─ enum_match.fe:190:24 + ┌─ enum_match.fe:207:24 │ -190 │ return u256(x1) + y1 + u256(x2) + y2 +207 │ return u256(x1) + y1 + u256(x2) + y2 │ ^^^^^^^^^^^^^ ^^ u32 │ │ │ u256 note: - ┌─ enum_match.fe:190:40 + ┌─ enum_match.fe:207:40 │ -190 │ return u256(x1) + y1 + u256(x2) + y2 +207 │ return u256(x1) + y1 + u256(x2) + y2 │ ^^^^^^^^ u256 note: - ┌─ enum_match.fe:190:24 + ┌─ enum_match.fe:207:24 │ -190 │ return u256(x1) + y1 + u256(x2) + y2 +207 │ return u256(x1) + y1 + u256(x2) + y2 │ ^^^^^^^^^^^^^^^^^^^^^^^^ ^^ u256 │ │ │ u256 note: - ┌─ enum_match.fe:190:24 + ┌─ enum_match.fe:207:24 │ -190 │ return u256(x1) + y1 + u256(x2) + y2 +207 │ return u256(x1) + y1 + u256(x2) + y2 │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ u256 · -193 │ return 0 +210 │ return 0 │ ^ u256 note: - ┌─ enum_match.fe:198:5 + ┌─ enum_match.fe:215:5 │ -198 │ ╭ pub fn simple_struct(x: i32, y: i32, b: bool) -> i32 { -199 │ │ let s: SimpleStruct = SimpleStruct(x, y, b) -200 │ │ match s { -201 │ │ SimpleStruct{x: x1, y: y1, b: true} => { +215 │ ╭ pub fn simple_struct(x: i32, y: i32, b: bool) -> i32 { +216 │ │ let s: SimpleStruct = SimpleStruct(x, y, b) +217 │ │ match s { +218 │ │ SimpleStruct{x: x1, y: y1, b: true} => { · │ -208 │ │ } -209 │ │ } +225 │ │ } +226 │ │ } │ ╰─────^ params: [{ label: None, name: x, typ: i32 }, { label: None, name: y, typ: i32 }, { label: None, name: b, typ: bool }] -> i32 note: - ┌─ enum_match.fe:199:13 + ┌─ enum_match.fe:216:13 │ -199 │ let s: SimpleStruct = SimpleStruct(x, y, b) +216 │ let s: SimpleStruct = SimpleStruct(x, y, b) │ ^ SimpleStruct note: - ┌─ enum_match.fe:199:44 + ┌─ enum_match.fe:216:44 │ -199 │ let s: SimpleStruct = SimpleStruct(x, y, b) +216 │ let s: SimpleStruct = SimpleStruct(x, y, b) │ ^ ^ ^ bool │ │ │ │ │ i32 │ i32 note: - ┌─ enum_match.fe:199:31 + ┌─ enum_match.fe:216:31 │ -199 │ let s: SimpleStruct = SimpleStruct(x, y, b) +216 │ let s: SimpleStruct = SimpleStruct(x, y, b) │ ^^^^^^^^^^^^^^^^^^^^^ SimpleStruct -200 │ match s { +217 │ match s { │ ^ SimpleStruct -201 │ SimpleStruct{x: x1, y: y1, b: true} => { -202 │ return x1 + y1 +218 │ SimpleStruct{x: x1, y: y1, b: true} => { +219 │ return x1 + y1 │ ^^ ^^ i32 │ │ │ i32 note: - ┌─ enum_match.fe:202:24 + ┌─ enum_match.fe:219:24 │ -202 │ return x1 + y1 +219 │ return x1 + y1 │ ^^^^^^^ i32 · -206 │ return x1 - y1 +223 │ return x1 - y1 │ ^^ ^^ i32 │ │ │ i32 note: - ┌─ enum_match.fe:206:24 + ┌─ enum_match.fe:223:24 │ -206 │ return x1 - y1 +223 │ return x1 - y1 │ ^^^^^^^ i32 note: - ┌─ enum_match.fe:211:5 + ┌─ enum_match.fe:228:5 │ -211 │ ╭ pub fn nested_struct() -> u256 { -212 │ │ let e: MyEnum = MyEnum::Tuple(1, 2) -213 │ │ let s: NestedStruct = NestedStruct(x: 3, y: 4, e) -214 │ │ match s { +228 │ ╭ pub fn nested_struct() -> u256 { +229 │ │ let e: MyEnum = MyEnum::Tuple(1, 2) +230 │ │ let s: NestedStruct = NestedStruct(x: 3, y: 4, e) +231 │ │ match s { · │ -222 │ │ } -223 │ │ } +239 │ │ } +240 │ │ } │ ╰─────^ params: [] -> u256 note: - ┌─ enum_match.fe:212:13 + ┌─ enum_match.fe:229:13 │ -212 │ let e: MyEnum = MyEnum::Tuple(1, 2) +229 │ let e: MyEnum = MyEnum::Tuple(1, 2) │ ^ MyEnum -213 │ let s: NestedStruct = NestedStruct(x: 3, y: 4, e) +230 │ let s: NestedStruct = NestedStruct(x: 3, y: 4, e) │ ^ NestedStruct note: - ┌─ enum_match.fe:212:39 + ┌─ enum_match.fe:229:39 │ -212 │ let e: MyEnum = MyEnum::Tuple(1, 2) +229 │ let e: MyEnum = MyEnum::Tuple(1, 2) │ ^ ^ u256 │ │ │ u32 note: - ┌─ enum_match.fe:212:25 + ┌─ enum_match.fe:229:25 │ -212 │ let e: MyEnum = MyEnum::Tuple(1, 2) +229 │ let e: MyEnum = MyEnum::Tuple(1, 2) │ ^^^^^^^^^^^^^^^^^^^ MyEnum -213 │ let s: NestedStruct = NestedStruct(x: 3, y: 4, e) +230 │ let s: NestedStruct = NestedStruct(x: 3, y: 4, e) │ ^ ^ ^ MyEnum -Copy-> MyEnum │ │ │ │ │ u256 │ u256 note: - ┌─ enum_match.fe:213:31 + ┌─ enum_match.fe:230:31 │ -213 │ let s: NestedStruct = NestedStruct(x: 3, y: 4, e) +230 │ let s: NestedStruct = NestedStruct(x: 3, y: 4, e) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ NestedStruct -214 │ match s { +231 │ match s { │ ^ NestedStruct -215 │ NestedStruct{e: MyEnum::Unit | MyEnum::UnitTuple(), ..} => { -216 │ return 0 +232 │ NestedStruct{e: MyEnum::Unit | MyEnum::UnitTuple(), ..} => { +233 │ return 0 │ ^ u256 · -220 │ return x1 + y1 + u256(x2) + y2 +237 │ return x1 + y1 + u256(x2) + y2 │ ^^ ^^ u256 │ │ │ u256 note: - ┌─ enum_match.fe:220:24 + ┌─ enum_match.fe:237:24 │ -220 │ return x1 + y1 + u256(x2) + y2 +237 │ return x1 + y1 + u256(x2) + y2 │ ^^^^^^^ ^^ u32 │ │ │ u256 note: - ┌─ enum_match.fe:220:34 + ┌─ enum_match.fe:237:34 │ -220 │ return x1 + y1 + u256(x2) + y2 +237 │ return x1 + y1 + u256(x2) + y2 │ ^^^^^^^^ u256 note: - ┌─ enum_match.fe:220:24 + ┌─ enum_match.fe:237:24 │ -220 │ return x1 + y1 + u256(x2) + y2 +237 │ return x1 + y1 + u256(x2) + y2 │ ^^^^^^^^^^^^^^^^^^ ^^ u256 │ │ │ u256 note: - ┌─ enum_match.fe:220:24 + ┌─ enum_match.fe:237:24 │ -220 │ return x1 + y1 + u256(x2) + y2 +237 │ return x1 + y1 + u256(x2) + y2 │ ^^^^^^^^^^^^^^^^^^^^^^^ u256 note: - ┌─ enum_match.fe:225:5 + ┌─ enum_match.fe:242:5 │ -225 │ ╭ pub fn enum_storage(mut self, x:u32, y: u256, b: bool) -> u256 { -226 │ │ if b { -227 │ │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) -228 │ │ } else { +242 │ ╭ pub fn enum_storage(mut self, x:u32, y: u256, b: bool) -> u256 { +243 │ │ if b { +244 │ │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) +245 │ │ } else { · │ -239 │ │ } -240 │ │ } +256 │ │ } +257 │ │ } │ ╰─────^ params: [mut self, { label: None, name: x, typ: u32 }, { label: None, name: y, typ: u256 }, { label: None, name: b, typ: bool }] -> u256 note: - ┌─ enum_match.fe:226:12 + ┌─ enum_match.fe:243:12 │ -226 │ if b { +243 │ if b { │ ^ bool -227 │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) +244 │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) │ ^^^^ mut Foo note: - ┌─ enum_match.fe:227:13 + ┌─ enum_match.fe:244:13 │ -227 │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) +244 │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) │ ^^^^^^^^^^^^ ^ ^ u256 │ │ │ │ │ u32 │ mut SPtr note: - ┌─ enum_match.fe:227:49 + ┌─ enum_match.fe:244:49 │ -227 │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) - │ ^^^^^^^^^^^^^^^^^^^ MyEnum -Copy-> MyEnum +244 │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) + │ ^^^^^^^^^^^^^^^^^^^ MyEnum note: - ┌─ enum_match.fe:227:28 + ┌─ enum_match.fe:244:28 │ -227 │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) +244 │ self.my_enum = MyEnumNested::Nested(MyEnum::Tuple(x, y)) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MyEnumNested -228 │ } else { -229 │ self.my_enum = MyEnumNested::Nested(MyEnum::Unit) +245 │ } else { +246 │ self.my_enum = MyEnumNested::Nested(MyEnum::Unit) │ ^^^^ mut Foo note: - ┌─ enum_match.fe:229:13 + ┌─ enum_match.fe:246:13 │ -229 │ self.my_enum = MyEnumNested::Nested(MyEnum::Unit) - │ ^^^^^^^^^^^^ ^^^^^^^^^^^^ MyEnum -Copy-> MyEnum +246 │ self.my_enum = MyEnumNested::Nested(MyEnum::Unit) + │ ^^^^^^^^^^^^ ^^^^^^^^^^^^ MyEnum │ │ │ mut SPtr note: - ┌─ enum_match.fe:229:28 + ┌─ enum_match.fe:246:28 │ -229 │ self.my_enum = MyEnumNested::Nested(MyEnum::Unit) +246 │ self.my_enum = MyEnumNested::Nested(MyEnum::Unit) │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MyEnumNested · -232 │ match self.my_enum { +249 │ match self.my_enum { │ ^^^^ mut Foo note: - ┌─ enum_match.fe:232:15 + ┌─ enum_match.fe:249:15 │ -232 │ match self.my_enum { +249 │ match self.my_enum { │ ^^^^^^^^^^^^ mut SPtr -233 │ MyEnumNested::Tuple(x1, y1) | MyEnumNested::Nested(MyEnum::Tuple(x1, y1)) => { -234 │ return u256(x1) + y1 +250 │ MyEnumNested::Tuple(x1, y1) | MyEnumNested::Nested(MyEnum::Tuple(x1, y1)) => { +251 │ return u256(x1) + y1 │ ^^ u32 note: - ┌─ enum_match.fe:234:24 + ┌─ enum_match.fe:251:24 │ -234 │ return u256(x1) + y1 +251 │ return u256(x1) + y1 │ ^^^^^^^^ ^^ u256 │ │ │ u256 note: - ┌─ enum_match.fe:234:24 + ┌─ enum_match.fe:251:24 │ -234 │ return u256(x1) + y1 +251 │ return u256(x1) + y1 │ ^^^^^^^^^^^^^ u256 · -237 │ return 100 +254 │ return 100 │ ^^^ u256 diff --git a/crates/analyzer/tests/snapshots/errors__call_to_mem_on_primitive.snap b/crates/analyzer/tests/snapshots/errors__call_to_mem_on_primitive.snap index 10202ada85..0cb8952cf7 100644 --- a/crates/analyzer/tests/snapshots/errors__call_to_mem_on_primitive.snap +++ b/crates/analyzer/tests/snapshots/errors__call_to_mem_on_primitive.snap @@ -9,6 +9,6 @@ error: `to_mem()` called on primitive type 5 │ return self.bar.to_mem() │ ^^^^^^^^ ------ hint: remove `.to_mem()` │ │ - │ this value does not need to be copied to memory + │ this value does not need to be explicitly copied to memory diff --git a/crates/analyzer/tests/snapshots/errors__invalid_comparisons.snap b/crates/analyzer/tests/snapshots/errors__invalid_comparisons.snap new file mode 100644 index 0000000000..b77c086b89 --- /dev/null +++ b/crates/analyzer/tests/snapshots/errors__invalid_comparisons.snap @@ -0,0 +1,18 @@ +--- +source: crates/analyzer/tests/errors.rs +expression: "error_string(&path, test_files::fixture(path))" + +--- +error: `Point` type can't be compared with the `==` operator + ┌─ compile_errors/invalid_comparisons.fe:13:10 + │ +13 │ return p == Point(x: 10, y: 20) + │ ^^^^^^^^^^^^^^^^^^^^^^^^ invalid comparison + +error: `State` type can't be compared with the `==` operator + ┌─ compile_errors/invalid_comparisons.fe:18:10 + │ +18 │ return s == State::Done + │ ^^^^^^^^^^^^^^^^ invalid comparison + + diff --git a/crates/driver/src/lib.rs b/crates/driver/src/lib.rs index b3cc61b017..77d6d9c186 100644 --- a/crates/driver/src/lib.rs +++ b/crates/driver/src/lib.rs @@ -157,8 +157,8 @@ fn compile_module_id( } Ok(CompiledModule { - src_ast: format!("{:?}", module_id.ast(db)), - lowered_ast: format!("{:?}", module_id.ast(db)), + src_ast: format!("{:#?}", module_id.ast(db)), + lowered_ast: format!("{:#?}", module_id.ast(db)), contracts, }) } @@ -186,8 +186,8 @@ fn compile_module_id( } Ok(CompiledModule { - src_ast: format!("{:?}", module_id.ast(db)), - lowered_ast: format!("{:?}", module_id.ast(db)), + src_ast: format!("{:#?}", module_id.ast(db)), + lowered_ast: format!("{:#?}", module_id.ast(db)), contracts, }) } diff --git a/crates/mir/src/lower/function.rs b/crates/mir/src/lower/function.rs index 6d820a34b9..b2b85db39d 100644 --- a/crates/mir/src/lower/function.rs +++ b/crates/mir/src/lower/function.rs @@ -262,12 +262,13 @@ impl<'db, 'a> BodyLowerHelper<'db, 'a> { ) { match &var.kind { ast::VarDeclTarget::Name(name) => { - // XXX use lower_expr ty if available let ty = self.lower_analyzer_type(self.analyzer_body.var_types[&var.id]); let value = self.declare_var(name, ty, var.into()); if let Some(init) = init { - let (init, _) = self.lower_expr(init); - // XXX debug_assert_eq!(ty.deref(self.db), init_ty); + let (init, _init_ty) = self.lower_expr(init); + // debug_assert_eq!(ty.deref(self.db), init_ty, "vardecl init type mismatch: {} != {}", + // ty.as_string(self.db), + // init_ty.as_string(self.db)); self.builder.map_result(init, value.into()); } } @@ -497,28 +498,15 @@ impl<'db, 'a> BodyLowerHelper<'db, 'a> { match kind { AdjustmentKind::Copy => { - let val = self - .builder - .inst_result(inst) - .and_then(|res| res.value_id()) - .unwrap_or_else(|| self.map_to_tmp(inst, ty)); + let val = self.inst_result_or_tmp(inst, ty); inst = self.builder.mem_copy(val, expr.into()); } AdjustmentKind::Load => { - let val = self - .builder - .inst_result(inst) - .and_then(|res| res.value_id()) - .unwrap_or_else(|| self.map_to_tmp(inst, ty)); + let val = self.inst_result_or_tmp(inst, ty); inst = self.builder.load(val, expr.into()); } AdjustmentKind::IntSizeIncrease => { - let val = self - .builder - .inst_result(inst) - .and_then(|res| res.value_id()) - .unwrap_or_else(|| self.map_to_tmp(inst, ty)); - + let val = self.inst_result_or_tmp(inst, ty); inst = self.builder.primitive_cast(val, into_ty, expr.into()) } AdjustmentKind::StringSizeIncrease => {} // XXX @@ -528,6 +516,13 @@ impl<'db, 'a> BodyLowerHelper<'db, 'a> { (inst, ty) } + fn inst_result_or_tmp(&mut self, inst: InstId, ty: TypeId) -> ValueId { + self.builder + .inst_result(inst) + .and_then(AssignableValue::value_id) + .unwrap_or_else(|| self.map_to_tmp(inst, ty)) + } + pub(super) fn lower_expr_to_value(&mut self, expr: &Node) -> ValueId { let (inst, ty) = self.lower_expr(expr); self.map_to_tmp(inst, ty) diff --git a/crates/mir/src/lower/pattern_match/mod.rs b/crates/mir/src/lower/pattern_match/mod.rs index 44481ceb0b..abed83617b 100644 --- a/crates/mir/src/lower/pattern_match/mod.rs +++ b/crates/mir/src/lower/pattern_match/mod.rs @@ -228,7 +228,7 @@ impl<'db, 'a, 'b> DecisionTreeLowerHelper<'db, 'a, 'b> { fn extract_disc(&mut self, value: ValueId) -> ValueId { let value_ty = self.builder().value_ty(value); match value_ty { - _ if value_ty.is_enum(self.helper.db) => { + _ if value_ty.deref(self.helper.db).is_enum(self.helper.db) => { let disc_ty = value_ty.enum_disc_type(self.helper.db); let disc_index = self.helper.make_u256_imm(0); let inst = diff --git a/crates/mir/src/lower/types.rs b/crates/mir/src/lower/types.rs index d4bc143177..905c339670 100644 --- a/crates/mir/src/lower/types.rs +++ b/crates/mir/src/lower/types.rs @@ -35,7 +35,7 @@ pub fn lower_type(db: &dyn MirDb, analyzer_ty: analyzer_types::TypeId) -> TypeId } }; - intern_type(db, ty_kind, Some(analyzer_ty)) + intern_type(db, ty_kind, Some(analyzer_ty.deref(db.upcast()))) } fn lower_base(base: analyzer_types::Base) -> TypeKind { diff --git a/crates/test-files/fixtures/compile_errors/invalid_comparisons.fe b/crates/test-files/fixtures/compile_errors/invalid_comparisons.fe new file mode 100644 index 0000000000..fbcfcda6dc --- /dev/null +++ b/crates/test-files/fixtures/compile_errors/invalid_comparisons.fe @@ -0,0 +1,19 @@ +struct Point { + pub x: i32 + pub y: i32 +} + +enum State { + Continue + Done +} + +pub fn f() -> bool { + let p: Point = Point(x: 1, y: 2) + return p == Point(x: 10, y: 20) +} + +pub fn g() -> bool { + let s: State = State::Continue + return s == State::Done +} diff --git a/crates/test-files/fixtures/features/enum_match.fe b/crates/test-files/fixtures/features/enum_match.fe index 5d02f3d038..5b6e08cea1 100644 --- a/crates/test-files/fixtures/features/enum_match.fe +++ b/crates/test-files/fixtures/features/enum_match.fe @@ -159,6 +159,23 @@ contract Foo { return res } + pub fn match_in_loop_simple() -> u256 { + let mut state: State = State::Continue + let mut count: u256 = 0 + while true { + match state { + State::Continue => {} + State::Done => { + break + } + } + count += 1 + state = State::Done + } + return count + } + + pub fn rest_pattern_head(x: u32, y: u256) -> u256 { let pat: (MyEnum, MyEnum, MyEnum, MyEnum) = (MyEnum::Unit, MyEnum::Unit, MyEnum::Unit, MyEnum::Tuple(x, y)) match pat { diff --git a/crates/tests/src/features.rs b/crates/tests/src/features.rs index 81dc627625..d8952aa8e8 100644 --- a/crates/tests/src/features.rs +++ b/crates/tests/src/features.rs @@ -855,11 +855,14 @@ fn enum_match() { ); harness.test_function(&mut executor, "wild_card", &[], Some(&uint_token(0))); - harness.test_function(&mut executor, "match_in_if", &[], Some(&uint_token(3))); - - // XXX broken - // harness.test_function(&mut executor, "match_in_loop", &[], Some(&uint_token(15))); + harness.test_function(&mut executor, "match_in_loop", &[], Some(&uint_token(15))); + harness.test_function( + &mut executor, + "match_in_loop_simple", + &[], + Some(&uint_token(1)), + ); harness.test_function( &mut executor, @@ -895,12 +898,12 @@ fn enum_match() { harness.test_function(&mut executor, "nested_struct", &[], Some(&uint_token(10))); - // harness.test_function( - // &mut executor, - // "enum_storage", - // &[uint_token(1), uint_token(2), bool_token(true)], - // Some(&uint_token(3)), - // ); + harness.test_function( + &mut executor, + "enum_storage", + &[uint_token(1), uint_token(2), bool_token(true)], + Some(&uint_token(3)), + ); // harness.test_function( // &mut executor, // "enum_storage", diff --git a/crates/tests/src/snapshots/fe_compiler_tests__demo_uniswap__uniswap_contracts.snap b/crates/tests/src/snapshots/fe_compiler_tests__demo_uniswap__uniswap_contracts.snap index 622522f138..1aacd9e53b 100644 --- a/crates/tests/src/snapshots/fe_compiler_tests__demo_uniswap__uniswap_contracts.snap +++ b/crates/tests/src/snapshots/fe_compiler_tests__demo_uniswap__uniswap_contracts.snap @@ -12,7 +12,7 @@ balanceOf([Address(0x0000000000000000000000000000000000000000)]) used 621 gas get_reserves([]) used 797 gas swap([Uint(1993), Uint(0), Address(0x0000000000000000000000000000000000000042)]) used 36362 gas get_reserves([]) used 797 gas -transfer([Address(0x6be0237455af1a0f7a22f964523a6cb5ddf50f42), Uint(141421356237309503880)]) used 5795 gas +transfer([Address(0x1e5a8bf4270c9ed3be04fe19fc875bd758132f4f), Uint(141421356237309503880)]) used 5795 gas burn([Address(0x1000000000000000000000000000000000000001)]) used 3669 gas get_reserves([]) used 797 gas diff --git a/crates/tests/src/snapshots/fe_compiler_tests__features__enum_match.snap b/crates/tests/src/snapshots/fe_compiler_tests__features__enum_match.snap index 88fa7b1b7e..557709f94b 100644 --- a/crates/tests/src/snapshots/fe_compiler_tests__features__enum_match.snap +++ b/crates/tests/src/snapshots/fe_compiler_tests__features__enum_match.snap @@ -4,19 +4,22 @@ expression: "format!(\"{}\", harness.gas_reporter)" --- simple_match([Uint(1), Uint(2)]) used 573 gas -nested_match([Uint(1), Uint(2)]) used 1914 gas -nested_match2([]) used 2710 gas +nested_match([Uint(1), Uint(2)]) used 1502 gas +nested_match2([]) used 1885 gas tuple_match([]) used 1765 gas boolean_literal_match([Bool(true), Bool(true)]) used 585 gas boolean_literal_match([Bool(true), Bool(false)]) used 611 gas boolean_literal_match([Bool(false), Bool(true)]) used 600 gas boolean_literal_match([Bool(false), Bool(false)]) used 596 gas -wild_card([]) used 1539 gas +wild_card([]) used 1127 gas match_in_if([]) used 647 gas -rest_pattern_head([Uint(1), Uint(2)]) used 2765 gas -rest_pattern_tail([Uint(1), Uint(2)]) used 2778 gas -rest_pattern_middle([Uint(1), Uint(2)]) used 3234 gas -simple_struct([Int(1), Int(2), Bool(true)]) used 1024 gas -simple_struct([Int(1), Int(2), Bool(false)]) used 1038 gas -nested_struct([]) used 1873 gas +match_in_loop([]) used 1567 gas +match_in_loop_simple([]) used 794 gas +rest_pattern_head([Uint(1), Uint(2)]) used 2787 gas +rest_pattern_tail([Uint(1), Uint(2)]) used 2800 gas +rest_pattern_middle([Uint(1), Uint(2)]) used 3256 gas +simple_struct([Int(1), Int(2), Bool(true)]) used 1046 gas +simple_struct([Int(1), Int(2), Bool(false)]) used 1060 gas +nested_struct([]) used 1895 gas +enum_storage([Uint(1), Uint(2), Bool(true)]) used 90860 gas diff --git a/crates/tests/src/snapshots/fe_compiler_tests__features__for_loop_with_complex_elem_array.snap b/crates/tests/src/snapshots/fe_compiler_tests__features__for_loop_with_complex_elem_array.snap index 4a110b609b..14bc39a4b4 100644 --- a/crates/tests/src/snapshots/fe_compiler_tests__features__for_loop_with_complex_elem_array.snap +++ b/crates/tests/src/snapshots/fe_compiler_tests__features__for_loop_with_complex_elem_array.snap @@ -3,5 +3,5 @@ source: crates/tests/src/features.rs expression: "format!(\"{}\", harness.gas_reporter)" --- -bar([]) used 4068 gas +bar([]) used 5055 gas diff --git a/crates/tests/src/snapshots/fe_compiler_tests__features__struct_fns.snap b/crates/tests/src/snapshots/fe_compiler_tests__features__struct_fns.snap index 9b6a53c067..4a9c9c465d 100644 --- a/crates/tests/src/snapshots/fe_compiler_tests__features__struct_fns.snap +++ b/crates/tests/src/snapshots/fe_compiler_tests__features__struct_fns.snap @@ -3,5 +3,5 @@ source: crates/tests/src/features.rs expression: "format!(\"{}\", harness.gas_reporter)" --- -bar([Uint(10), Uint(20)]) used 2082 gas +bar([Uint(10), Uint(20)]) used 2418 gas diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 5c2dff2f22..365db70a6b 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -32,7 +32,6 @@ * [Augmenting Assignment Statement](spec/statements/augassign.md) * [`revert` Statement](spec/statements/revert.md) * [`return` Statement](spec/statements/return.md) - * [`emit` Statement](spec/statements/emit.md) * [`if` Statement](spec/statements/if.md) * [`for` Statement](spec/statements/for.md) * [`while` Statement](spec/statements/while.md) @@ -77,7 +76,6 @@ * [`to_mem()` function](spec/data_layout/storage/to_mem_function.md) * [Memory](spec/data_layout/memory/index.md) * [Sequence types in memory](spec/data_layout/memory/sequence_types_in_memory.md) - * [`clone()` function](spec/data_layout/memory/clone_function.md) * [Function calls](spec/function_calls.md) * [Release Notes](release_notes.md) diff --git a/docs/src/spec/data_layout/memory/clone_function.md b/docs/src/spec/data_layout/memory/clone_function.md deleted file mode 100644 index 45e4e2c868..0000000000 --- a/docs/src/spec/data_layout/memory/clone_function.md +++ /dev/null @@ -1,27 +0,0 @@ -# The `clone` function - -Reference type values in memory can be cloned using the `clone` function. - -Example: - -```fe -fn f() { - - // with clone - let bar: Array = [1, 2, 3, 4] - let mut foo: Array = bar.clone() // `foo` points to a new segment of memory - assert foo[1] == bar[1] - foo[1] = 42 - assert foo[1] != bar[1] // modifying `foo` does not modify bar -} - -// XXX change or remove this -fn g() { - // without clone - let bar: Array = [1, 2, 3, 4] - let foo: Array = bar // `foo` and `bar` point to the same segment of memory - assert foo[1] == bar[1] - foo[1] = 42 - assert foo[1] == bar[1] // modifying `foo` also modifies `bar` -} -``` diff --git a/docs/src/spec/index.md b/docs/src/spec/index.md index 7b932ccfd2..bcae53cbc8 100644 --- a/docs/src/spec/index.md +++ b/docs/src/spec/index.md @@ -64,5 +64,4 @@ * [`to_mem()` function](data_layout/storage/to_mem_function.md) * [Memory](data_layout/memory/index.md) * [Sequence types in memory](data_layout/memory/sequence_types_in_memory.md) - * [`clone()` function](data_layout/memory/clone_function.md) * [Function calls](function_calls.md) diff --git a/docs/src/spec/items/contracts.md b/docs/src/spec/items/contracts.md index 01be0fd493..2894525e33 100644 --- a/docs/src/spec/items/contracts.md +++ b/docs/src/spec/items/contracts.md @@ -35,7 +35,7 @@ struct Signed { contract GuestBook { messages: Map> - pub fn sign(self, ctx: Context, book_msg: String<100>) { + pub fn sign(mut self, mut ctx: Context, book_msg: String<100>) { self.messages[ctx.msg_sender()] = book_msg ctx.emit(Signed(book_msg: book_msg)) } diff --git a/docs/src/spec/items/events.md b/docs/src/spec/items/events.md deleted file mode 100644 index fba754ea47..0000000000 --- a/docs/src/spec/items/events.md +++ /dev/null @@ -1,39 +0,0 @@ -# Events - -> **Syntax**\ -> _Event_ :\ ->    `event` [IDENTIFIER] `{` ->    _EventField_\*\ ->    `}` -> -> _EventField_ :\ ->    _EventIndexability_ [IDENTIFIER] `:` [_Type_]\ -> -> _EventIndexability_ :\ ->    `idx`? - -An _event_ is a nominal [event type] defined with the keyword `event`. It is emitted with the keyword `emit`. - -An example of a `event` item and its use: - -```fe -contract Foo { - event Transfer { - idx sender: address - idx receiver: address - value: u256 - } - - - fn transfer(mut ctx: Context, to: address, value: u256) { - // Heavy logic here - // All done, log the event for listeners - emit Transfer(ctx, sender: ctx.msg_sender(), receiver: to, value) - } -} -``` - -[NEWLINE]: ../lexical_structure/tokens.md#newline -[IDENTIFIER]: ../lexical_structure/identifiers.md -[_Type_]: ../type_system/types/index.md -[event type]: ../type_system/types/event.md diff --git a/docs/src/spec/items/functions.md b/docs/src/spec/items/functions.md index 7e8ff7ba5e..46e0c6b1a7 100644 --- a/docs/src/spec/items/functions.md +++ b/docs/src/spec/items/functions.md @@ -21,7 +21,6 @@ >       | [_WhileStatement_]\ >       | [_IfStatement_]\ >       | [_AssertStatement_]\ ->       | [_EmitStatement_]\ >       | [_BreakStatement_]\ >       | [_ContinueStatement_]\ >       | [_RevertStatement_]\ @@ -159,7 +158,6 @@ let ok: bool = self.transfer(from, to, value) [_WhileStatement_]: ../statements/for.md [_IfStatement_]: ../statements/if.md [_AssertStatement_]: ../statements/assert.md -[_EmitStatement_]: ../statements/emit.md [_BreakStatement_]: ../statements/break.md [_ContinueStatement_]: ../statements/continue.md [_RevertStatement_]: ../statements/revert.md diff --git a/docs/src/spec/lexical_structure/keywords.md b/docs/src/spec/lexical_structure/keywords.md index f083ad06aa..122afc9c6a 100644 --- a/docs/src/spec/lexical_structure/keywords.md +++ b/docs/src/spec/lexical_structure/keywords.md @@ -18,7 +18,6 @@ be used as the [identifiers](./identifiers.md). > KW_CONST : `contract`\ > KW_FN : `fn`\ > KW_ELSE : `else`\ -> KW_EMIT : `emit`\ > KW_ENUM : `enum`\ > KW_EVENT : `event`\ > KW_FALSE : `false`\ diff --git a/docs/src/spec/statements/assign.md b/docs/src/spec/statements/assign.md index 53c58467c0..0d165c42ac 100644 --- a/docs/src/spec/statements/assign.md +++ b/docs/src/spec/statements/assign.md @@ -14,7 +14,7 @@ contract Foo { some_array: Array - pub fn bar(self) { + pub fn bar(mut self) { let mut val1: u256 = 10 // Assignment of stack variable val1 = 10 diff --git a/docs/src/spec/statements/emit.md b/docs/src/spec/statements/emit.md deleted file mode 100644 index cc412f44f0..0000000000 --- a/docs/src/spec/statements/emit.md +++ /dev/null @@ -1,43 +0,0 @@ -# `emit` statement - - -> **Syntax**\ -> _EmitStatement_ :\ ->    `emit` _EventLiteral_ `(` _CallParams_? `)` -> -> _EventLiteral_ :\ ->    [IDENTIFIER]Name of event defined in current module -> -> _CallParams_ :\ ->    _CallArg_ ( `,` _CallArg_ )\* `,`? -> -> _CallArg_ :\ ->    (_CallArgLabel_ `:`)? [_Expression_] -> -> _CallArgLabel_ :\ ->    [IDENTIFIER]Label must correspond to the name of the event property at the given position. It can be omitted if parameter name and event property name are equal. - -The `emit` statement is used to create [log entries] in the blockchain. The `emit` keyword is followed by a literal that corresponds to a defined event, followed by a parenthesized comma-separated list of expressions. - - -Examples: - -```fe -contract Foo { - event Mix { - num1: u256 - idx addr: address - num2: u256 - my_bytes: Array - } - pub fn emit_mix(mut ctx: Context, addr: address, my_bytes: Array) { - emit Mix(ctx, num1: 26, addr, num2: 42, my_bytes) - } -} -``` - -[_Expression_]: ../expressions/index.md -[IDENTIFIER]: ../lexical_structure/identifiers.md -[struct]: ../items/structs.md -[EIP-838]: https://github.com/ethereum/EIPs/issues/838 -[log entries]: https://ethereum.stackexchange.com/questions/12950/what-are-solidity-events-and-how-they-are-related-to-topics-and-logs/12951#12951