Explorar el Código

Parse `(new ty){value: 1}(args)` and similar syntax

Three different parse tree for callargs:

	(new D{value: 1})();
	(new D){value: 1}();
	new D{value: 1}();

solc accepts this syntax, so should we.

Fixes https://github.com/hyperledger-labs/solang/issues/818

Signed-off-by: Sean Young <sean@mess.org>
Sean Young hace 3 años
padre
commit
1c81845dda

+ 1 - 1
solang-parser/src/solidity.lalrpop

@@ -355,7 +355,7 @@ Precedence2: Expression = {
     <a:@L> "!" <b:@R> <e:Precedence2> => Expression::Not(Loc::File(file_no, a, b), Box::new(e)),
     <a:@L> "~" <b:@R> <e:Precedence2> => Expression::Complement(Loc::File(file_no, a, b), Box::new(e)),
     <a:@L> "delete" <b:@R> <e:Precedence2> => Expression::Delete(Loc::File(file_no, a, b), Box::new(e)),
-    <a:@L> "new" <call:FunctionCall> <b:@R> => Expression::New(Loc::File(file_no, a, b), Box::new(call)),
+    <a:@L> "new" <call:Precedence2> <b:@R> => Expression::New(Loc::File(file_no, a, b), Box::new(call)),
     <a:@L> "++" <b:@R> <e:Precedence2> => Expression::PreIncrement(Loc::File(file_no, a, b), Box::new(e)),
     <a:@L> "--" <b:@R> <e:Precedence2> => Expression::PreDecrement(Loc::File(file_no, a, b), Box::new(e)),
     <a:@L> "+" <e:Precedence2> <b:@R>  => Expression::UnaryPlus(Loc::File(file_no, a, b), Box::new(e)),

+ 24 - 10
src/sema/expression.rs

@@ -3471,6 +3471,12 @@ pub fn new(
 ) -> Result<Expression, ()> {
     let (ty, call_args, call_args_loc) = collect_call_args(ty, diagnostics)?;
 
+    let ty = if let pt::Expression::New(_, ty) = ty {
+        ty
+    } else {
+        ty
+    };
+
     let ty = ns.resolve_type(context.file_no, context.contract_no, false, ty, diagnostics)?;
 
     match &ty {
@@ -7285,16 +7291,24 @@ pub fn call_expr(
         Err(_) => (),
     }
 
-    let expr = function_call_expr(
-        loc,
-        ty,
-        args,
-        context,
-        ns,
-        symtable,
-        diagnostics,
-        resolve_to,
-    )?;
+    let expr = match ty {
+        pt::Expression::New(_, ty) => new(loc, ty, args, context, ns, symtable, diagnostics)?,
+        pt::Expression::FunctionCallBlock(loc, expr, _)
+            if matches!(expr.as_ref(), pt::Expression::New(..)) =>
+        {
+            new(loc, ty, args, context, ns, symtable, diagnostics)?
+        }
+        _ => function_call_expr(
+            loc,
+            ty,
+            args,
+            context,
+            ns,
+            symtable,
+            diagnostics,
+            resolve_to,
+        )?,
+    };
 
     check_function_call(ns, &expr, symtable);
     if expr.tys().len() > 1 && !is_destructible {

+ 20 - 10
src/sema/statements.rs

@@ -1789,16 +1789,26 @@ fn try_catch(
 
     let fcall = match expr {
         pt::Expression::FunctionCall(loc, ty, args) => {
-            let res = function_call_expr(
-                loc,
-                ty,
-                args,
-                context,
-                ns,
-                symtable,
-                diagnostics,
-                ResolveTo::Unknown,
-            )?;
+            let res = match ty.as_ref() {
+                pt::Expression::New(_, ty) => {
+                    new(loc, ty, args, context, ns, symtable, diagnostics)?
+                }
+                pt::Expression::FunctionCallBlock(loc, expr, _)
+                    if matches!(expr.as_ref(), pt::Expression::New(..)) =>
+                {
+                    new(loc, ty, args, context, ns, symtable, diagnostics)?
+                }
+                _ => function_call_expr(
+                    loc,
+                    ty,
+                    args,
+                    context,
+                    ns,
+                    symtable,
+                    diagnostics,
+                    ResolveTo::Unknown,
+                )?,
+            };
             check_function_call(ns, &res, symtable);
             res
         }

+ 74 - 0
tests/contract_testcases/solana/call/call_args_three_ways.dot

@@ -0,0 +1,74 @@
+strict digraph "tests/contract_testcases/solana/call/call_args_three_ways.sol" {
+	contract [label="contract C\ntests/contract_testcases/solana/call/call_args_three_ways.sol:1:1-12"]
+	f [label="function f\ncontract: C\ntests/contract_testcases/solana/call/call_args_three_ways.sol:2:2-21\nsignature f()\nvisibility public\nmutability nonpayable"]
+	var_decl [label="variable decl contract D d\ntests/contract_testcases/solana/call/call_args_three_ways.sol:4:3-28"]
+	constructor [label="constructor contract D\ntests/contract_testcases/solana/call/call_args_three_ways.sol:4:9-28"]
+	number_literal [label="uint64 literal: 1\ntests/contract_testcases/solana/call/call_args_three_ways.sol:4:23-24"]
+	var_decl_7 [label="variable decl contract D dd\ntests/contract_testcases/solana/call/call_args_three_ways.sol:5:3-29"]
+	constructor_8 [label="constructor contract D\ntests/contract_testcases/solana/call/call_args_three_ways.sol:5:17-27"]
+	number_literal_9 [label="uint64 literal: 1\ntests/contract_testcases/solana/call/call_args_three_ways.sol:5:25-26"]
+	var_decl_10 [label="variable decl contract D ddd\ntests/contract_testcases/solana/call/call_args_three_ways.sol:6:3-28"]
+	constructor_11 [label="constructor contract D\ntests/contract_testcases/solana/call/call_args_three_ways.sol:6:11-28"]
+	number_literal_12 [label="uint64 literal: 1\ntests/contract_testcases/solana/call/call_args_three_ways.sol:6:24-25"]
+	g [label="function g\ncontract: C\ntests/contract_testcases/solana/call/call_args_three_ways.sol:8:2-24\nsignature g(bytes32)\nvisibility public\nmutability nonpayable"]
+	parameters [label="parameters\ncontract D d"]
+	expr [label="expression\ntests/contract_testcases/solana/call/call_args_three_ways.sol:10:3-21"]
+	call_external_function [label="call external function\ntests/contract_testcases/solana/call/call_args_three_ways.sol:10:3-21"]
+	external_function [label="function() external payable returns (void)\nD.func\ntests/contract_testcases/solana/call/call_args_three_ways.sol:10:3-21"]
+	variable [label="variable: d\ncontract D\ntests/contract_testcases/solana/call/call_args_three_ways.sol:10:3-4"]
+	number_literal_19 [label="uint64 literal: 1\ntests/contract_testcases/solana/call/call_args_three_ways.sol:10:17-18"]
+	expr_20 [label="expression\ntests/contract_testcases/solana/call/call_args_three_ways.sol:11:3-23"]
+	call_external_function_21 [label="call external function\ntests/contract_testcases/solana/call/call_args_three_ways.sol:11:3-23"]
+	external_function_22 [label="function() external payable returns (void)\nD.func\ntests/contract_testcases/solana/call/call_args_three_ways.sol:11:3-23"]
+	variable_23 [label="variable: d\ncontract D\ntests/contract_testcases/solana/call/call_args_three_ways.sol:11:4-5"]
+	number_literal_24 [label="uint64 literal: 1\ntests/contract_testcases/solana/call/call_args_three_ways.sol:11:19-20"]
+	expr_25 [label="expression\ntests/contract_testcases/solana/call/call_args_three_ways.sol:12:3-23"]
+	call_external_function_26 [label="call external function\ntests/contract_testcases/solana/call/call_args_three_ways.sol:12:3-23"]
+	external_function_27 [label="function() external payable returns (void)\nD.func\ntests/contract_testcases/solana/call/call_args_three_ways.sol:12:3-23"]
+	variable_28 [label="variable: d\ncontract D\ntests/contract_testcases/solana/call/call_args_three_ways.sol:12:4-5"]
+	number_literal_29 [label="uint64 literal: 1\ntests/contract_testcases/solana/call/call_args_three_ways.sol:12:18-19"]
+	contract_30 [label="contract D\ntests/contract_testcases/solana/call/call_args_three_ways.sol:15:1-16:12"]
+	node_31 [label="constructor \ncontract: D\ntests/contract_testcases/solana/call/call_args_three_ways.sol:17:2-23\nsignature ()\nvisibility public\nmutability payable"]
+	func [label="function func\ncontract: D\ntests/contract_testcases/solana/call/call_args_three_ways.sol:18:2-32\nsignature func()\nvisibility public\nmutability payable"]
+	diagnostic [label="found contract 'C'\nlevel Debug\ntests/contract_testcases/solana/call/call_args_three_ways.sol:1:1-12"]
+	diagnostic_35 [label="found contract 'D'\nlevel Debug\ntests/contract_testcases/solana/call/call_args_three_ways.sol:15:1-16:12"]
+	diagnostic_36 [label="local variable 'd' has been assigned, but never read\nlevel Warning\ntests/contract_testcases/solana/call/call_args_three_ways.sol:4:5-6"]
+	diagnostic_37 [label="local variable 'dd' has been assigned, but never read\nlevel Warning\ntests/contract_testcases/solana/call/call_args_three_ways.sol:5:5-7"]
+	diagnostic_38 [label="local variable 'ddd' has been assigned, but never read\nlevel Warning\ntests/contract_testcases/solana/call/call_args_three_ways.sol:6:5-8"]
+	contracts -> contract
+	contract -> f [label="function"]
+	f -> var_decl [label="body"]
+	var_decl -> constructor [label="init"]
+	constructor -> number_literal [label="value"]
+	var_decl -> var_decl_7 [label="next"]
+	var_decl_7 -> constructor_8 [label="init"]
+	constructor_8 -> number_literal_9 [label="value"]
+	var_decl_7 -> var_decl_10 [label="next"]
+	var_decl_10 -> constructor_11 [label="init"]
+	constructor_11 -> number_literal_12 [label="value"]
+	contract -> g [label="function"]
+	g -> parameters [label="parameters"]
+	g -> expr [label="body"]
+	expr -> call_external_function [label="expr"]
+	call_external_function -> external_function [label="function"]
+	external_function -> variable [label="address"]
+	call_external_function -> number_literal_19 [label="value"]
+	expr -> expr_20 [label="next"]
+	expr_20 -> call_external_function_21 [label="expr"]
+	call_external_function_21 -> external_function_22 [label="function"]
+	external_function_22 -> variable_23 [label="address"]
+	call_external_function_21 -> number_literal_24 [label="value"]
+	expr_20 -> expr_25 [label="next"]
+	expr_25 -> call_external_function_26 [label="expr"]
+	call_external_function_26 -> external_function_27 [label="function"]
+	external_function_27 -> variable_28 [label="address"]
+	call_external_function_26 -> number_literal_29 [label="value"]
+	contracts -> contract_30
+	contract_30 -> node_31 [label="constructor"]
+	contract_30 -> func [label="function"]
+	diagnostics -> diagnostic [label="Debug"]
+	diagnostics -> diagnostic_35 [label="Debug"]
+	diagnostics -> diagnostic_36 [label="Warning"]
+	diagnostics -> diagnostic_37 [label="Warning"]
+	diagnostics -> diagnostic_38 [label="Warning"]
+}

+ 19 - 0
tests/contract_testcases/solana/call/call_args_three_ways.sol

@@ -0,0 +1,19 @@
+contract C {
+	function f() public {
+		// Three different parse tree for callargs with new
+		D d = (new D{value: 1})();
+		D dd = (new D){value: 1}();
+		D ddd = new D{value: 1}();
+	}
+	function g(D d) public {
+		// Three different parse tree for callargs
+		d.func{value: 1}();
+		(d.func){value: 1}();
+		(d.func{value: 1})();
+	}
+}
+
+contract D {
+	constructor() payable {}
+	function func() payable public {}
+}

+ 2 - 2
tests/substrate_tests/arrays.rs

@@ -743,7 +743,7 @@ fn dynamic_array_push() {
 
         contract foo {
             function test() public {
-                int[] bar = new int[](1);
+                int[] bar = (new int[])(1);
 
                 bar[0] = 128;
                 bar.push(64);
@@ -763,7 +763,7 @@ fn dynamic_array_push() {
 
         contract foo {
             function test() public {
-                bytes bar = new bytes(1);
+                bytes bar = (new bytes)(1);
 
                 bar[0] = 128;
                 bar.push(64);

+ 2 - 2
tests/substrate_tests/calls.rs

@@ -275,7 +275,7 @@ fn try_catch_external_calls() {
             child c;
 
             function create_child() public {
-                c = new child();
+                c = (new child)();
             }
 
             function call_child() public view returns (int64) {
@@ -332,7 +332,7 @@ fn try_catch_constructor() {
         contract c {
             function test() public {
                 int x;
-                try new other() {
+                try (new other)() {
                     x = 102;
                 } catch (bytes) {
                     x = 2;

+ 3 - 3
tests/substrate_tests/value.rs

@@ -102,7 +102,7 @@ fn constructor_value() {
         r##"
         contract b {
             function step1() public {
-                a f = new a{value: 0}();
+                a f = (new a){value: 0}();
             }
         }
 
@@ -154,7 +154,7 @@ fn constructor_value() {
         r##"
         contract b {
             function step1() public {
-                try new a{value: 511}() {
+                try (new a{value: 511})() {
                     //
                 }
                 catch (bytes) {
@@ -185,7 +185,7 @@ fn constructor_value() {
         r##"
         contract b {
             function step1() public {
-                try new a{value: 511}() returns (a) {
+                try (new a){value: 511}() returns (a) {
                     //
                 }
                 catch (bytes) {