Bladeren bron

Allow .wrap() and .unwrap() user defined type methods in constants (#1340)

* wrap() and unwrap() should be allowed in constant context
* solc does not complain about deleting local variables

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 2 jaren geleden
bovenliggende
commit
aacc4b2926

+ 2 - 2
src/sema/builtin.rs

@@ -292,7 +292,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
             ret: vec![Type::UserType(0)],
             target: vec![],
             doc: "wrap type into user defined type",
-            constant: false,
+            constant: true,
         },
         Prototype {
             builtin: Builtin::UserTypeUnwrap,
@@ -303,7 +303,7 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
             ret: vec![],
             target: vec![],
             doc: "unwrap user defined type",
-            constant: false,
+            constant: true,
         },
     ]
 });

+ 29 - 23
src/sema/expression/function_call.rs

@@ -250,6 +250,14 @@ pub fn function_call_pos_args(
     let mut name_matches = 0;
     let mut errors = Diagnostics::default();
 
+    if context.constant {
+        diagnostics.push(Diagnostic::error(
+            *loc,
+            "cannot call function in constant expression".to_string(),
+        ));
+        return Err(());
+    }
+
     // Try to resolve as a function call
     for function_no in &function_nos {
         let func = &ns.functions[*function_no];
@@ -1387,6 +1395,14 @@ pub(super) fn method_call_pos_args(
         return Ok(resolved_call);
     }
 
+    if context.constant {
+        diagnostics.push(Diagnostic::error(
+            *loc,
+            "cannot call function in constant expression".to_string(),
+        ));
+        return Err(());
+    }
+
     if let Some(mut path) = ns.expr_to_identifier_path(var) {
         path.identifiers.push(func.clone());
 
@@ -2339,29 +2355,19 @@ pub fn function_call_expr(
     let (ty, call_args, call_args_loc) = collect_call_args(ty, diagnostics)?;
 
     match ty.remove_parenthesis() {
-        pt::Expression::MemberAccess(_, member, func) => {
-            if context.constant {
-                diagnostics.push(Diagnostic::error(
-                    *loc,
-                    "cannot call function in constant expression".to_string(),
-                ));
-                return Err(());
-            }
-
-            method_call_pos_args(
-                loc,
-                member,
-                func,
-                args,
-                &call_args,
-                call_args_loc,
-                context,
-                ns,
-                symtable,
-                diagnostics,
-                resolve_to,
-            )
-        }
+        pt::Expression::MemberAccess(_, member, func) => method_call_pos_args(
+            loc,
+            member,
+            func,
+            args,
+            &call_args,
+            call_args_loc,
+            context,
+            ns,
+            symtable,
+            diagnostics,
+            resolve_to,
+        ),
         pt::Expression::Variable(id) => {
             // is it a builtin
             if builtin::is_builtin_call(None, &id.name, ns) {

+ 1 - 1
src/sema/statements.rs

@@ -752,7 +752,7 @@ fn statement(
 
                         Ok(true)
                     } else {
-                        ns.diagnostics.push(Diagnostic::error(
+                        ns.diagnostics.push(Diagnostic::warning(
                             *loc,
                             "argument to 'delete' should be storage reference".to_string(),
                         ));

+ 3 - 1
tests/contract_testcases/substrate/arrays/storage_delete.sol

@@ -7,4 +7,6 @@
             }
         }
 // ---- Expect: diagnostics ----
-// error: 6:17-27: argument to 'delete' should be storage reference
+// warning: 3:13-24: storage variable 'bar' has never been used
+// warning: 5:13-35: function can be declared 'pure'
+// warning: 6:17-27: argument to 'delete' should be storage reference

+ 1 - 1
tests/evm.rs

@@ -248,7 +248,7 @@ fn ethereum_solidity_tests() {
         })
         .sum();
 
-    assert_eq!(errors, 1068);
+    assert_eq!(errors, 1055);
 }
 
 fn set_file_contents(source: &str, path: &Path) -> (FileResolver, Vec<String>) {