Browse Source

Fix assigning to array subscript when array element is array

Dereferencing an array did not make the array writable.

Fixes issue found here:

https://stackoverflow.com/questions/71789212/solang-panicked-at-type-not-allowed

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 3 years ago
parent
commit
b1bac41dff

+ 2 - 7
src/sema/expression.rs

@@ -4140,7 +4140,7 @@ fn enum_value(
     }
     }
 }
 }
 
 
-/// Resolve an array subscript expression
+/// Resolve an member access expression
 fn member_access(
 fn member_access(
     loc: &pt::Loc,
     loc: &pt::Loc,
     e: &pt::Expression,
     e: &pt::Expression,
@@ -4698,12 +4698,7 @@ fn array_subscript(
                     Box::new(index),
                     Box::new(index),
                 ))
                 ))
             } else {
             } else {
-                let mut elem_ty = array_ty.array_deref();
-
-                if elem_ty.builtin_struct(ns) == BuiltinStruct::AccountInfo {
-                    // AccountInfo is an array of structures, not an array of pointers to structures
-                    elem_ty = elem_ty.deref_any().clone();
-                }
+                let elem_ty = array_ty.array_deref();
 
 
                 let array = array.cast(
                 let array = array.cast(
                     &array.loc(),
                     &array.loc(),

+ 4 - 3
src/sema/types.rs

@@ -863,9 +863,10 @@ impl Type {
         match self {
         match self {
             Type::String | Type::DynamicBytes => Type::Ref(Box::new(Type::Uint(8))),
             Type::String | Type::DynamicBytes => Type::Ref(Box::new(Type::Uint(8))),
             Type::Ref(t) => t.array_deref(),
             Type::Ref(t) => t.array_deref(),
-            Type::Array(ty, dim) if dim.len() > 1 => {
-                Type::Array(ty.clone(), dim[..dim.len() - 1].to_vec())
-            }
+            Type::Array(ty, dim) if dim.len() > 1 => Type::Ref(Box::new(Type::Array(
+                ty.clone(),
+                dim[..dim.len() - 1].to_vec(),
+            ))),
             Type::Array(ty, dim) if dim.len() == 1 => Type::Ref(ty.clone()),
             Type::Array(ty, dim) if dim.len() == 1 => Type::Ref(ty.clone()),
             Type::Bytes(_) => Type::Bytes(1),
             Type::Bytes(_) => Type::Bytes(1),
             _ => panic!("deref on non-array"),
             _ => panic!("deref on non-array"),

+ 102 - 0
tests/contract_testcases/solana/assign_array_in_array.dot

@@ -0,0 +1,102 @@
+strict digraph "tests/contract_testcases/solana/assign_array_in_array.sol" {
+	Sfixed [label="name:Sfixed\ncontract: C\ntests/contract_testcases/solana/assign_array_in_array.sol:13:9-15\nfield name:f1 ty:uint256[3]"]
+	Sdynamic [label="name:Sdynamic\ncontract: C\ntests/contract_testcases/solana/assign_array_in_array.sol:14:9-17\nfield name:f1 ty:uint256[]"]
+	contract [label="contract C\ntests/contract_testcases/solana/assign_array_in_array.sol:1:60-2:12"]
+	fixed [label="function fixed\ncontract: C\ntests/contract_testcases/solana/assign_array_in_array.sol:3:2-25\nsignature fixed()\nvisibility public\nmutability nonpayable"]
+	var_decl [label="variable decl uint256[3][4] iPj\ntests/contract_testcases/solana/assign_array_in_array.sol:4:3-27"]
+	expr [label="expression\ntests/contract_testcases/solana/assign_array_in_array.sol:5:3-19"]
+	assign [label="assign\nuint256[3]\ntests/contract_testcases/solana/assign_array_in_array.sol:5:10-11"]
+	subscript [label="subscript uint256[3][4]\ntests/contract_testcases/solana/assign_array_in_array.sol:5:3-9"]
+	variable [label="variable: iPj\nuint256[3][4]\ntests/contract_testcases/solana/assign_array_in_array.sol:5:3-6"]
+	number_literal [label="uint32 literal: 0\ntests/contract_testcases/solana/assign_array_in_array.sol:5:7-8"]
+	array_literal [label="array literal: uint256[3]\ntests/contract_testcases/solana/assign_array_in_array.sol:5:12-19"]
+	number_literal_13 [label="uint256 literal: 1\ntests/contract_testcases/solana/assign_array_in_array.sol:5:13-14"]
+	number_literal_14 [label="uint256 literal: 2\ntests/contract_testcases/solana/assign_array_in_array.sol:5:15-16"]
+	number_literal_15 [label="uint256 literal: 3\ntests/contract_testcases/solana/assign_array_in_array.sol:5:17-18"]
+	dynamic [label="function dynamic\ncontract: C\ntests/contract_testcases/solana/assign_array_in_array.sol:8:2-27\nsignature dynamic()\nvisibility public\nmutability nonpayable"]
+	var_decl_17 [label="variable decl uint256[][4] iPj\ntests/contract_testcases/solana/assign_array_in_array.sol:9:3-26"]
+	expr_18 [label="expression\ntests/contract_testcases/solana/assign_array_in_array.sol:10:3-28"]
+	assign_19 [label="assign\nuint256[]\ntests/contract_testcases/solana/assign_array_in_array.sol:10:10-11"]
+	subscript_20 [label="subscript uint256[][4]\ntests/contract_testcases/solana/assign_array_in_array.sol:10:3-9"]
+	variable_21 [label="variable: iPj\nuint256[][4]\ntests/contract_testcases/solana/assign_array_in_array.sol:10:3-6"]
+	number_literal_22 [label="uint32 literal: 0\ntests/contract_testcases/solana/assign_array_in_array.sol:10:7-8"]
+	alloc_array [label="alloc array uint256[]\ntests/contract_testcases/solana/assign_array_in_array.sol:10:12-28"]
+	number_literal_24 [label="uint32 literal: 4\ntests/contract_testcases/solana/assign_array_in_array.sol:10:26-27"]
+	fixed_struct [label="function fixed_struct\ncontract: C\ntests/contract_testcases/solana/assign_array_in_array.sol:16:2-32\nsignature fixed_struct()\nvisibility public\nmutability nonpayable"]
+	var_decl_26 [label="variable decl struct C.Sfixed iPj\ntests/contract_testcases/solana/assign_array_in_array.sol:17:3-13"]
+	expr_27 [label="expression\ntests/contract_testcases/solana/assign_array_in_array.sol:18:3-19"]
+	assign_28 [label="assign\nuint256[3]\ntests/contract_testcases/solana/assign_array_in_array.sol:18:10-11"]
+	structmember [label="struct member #0 uint256[3]\ntests/contract_testcases/solana/assign_array_in_array.sol:18:7-9"]
+	variable_30 [label="variable: iPj\nstruct C.Sfixed\ntests/contract_testcases/solana/assign_array_in_array.sol:18:3-6"]
+	array_literal_31 [label="array literal: uint256[3]\ntests/contract_testcases/solana/assign_array_in_array.sol:18:12-19"]
+	number_literal_32 [label="uint256 literal: 1\ntests/contract_testcases/solana/assign_array_in_array.sol:18:13-14"]
+	number_literal_33 [label="uint256 literal: 2\ntests/contract_testcases/solana/assign_array_in_array.sol:18:15-16"]
+	number_literal_34 [label="uint256 literal: 3\ntests/contract_testcases/solana/assign_array_in_array.sol:18:17-18"]
+	dynamic_struct [label="function dynamic_struct\ncontract: C\ntests/contract_testcases/solana/assign_array_in_array.sol:21:2-34\nsignature dynamic_struct()\nvisibility public\nmutability nonpayable"]
+	var_decl_36 [label="variable decl struct C.Sdynamic iPj\ntests/contract_testcases/solana/assign_array_in_array.sol:22:3-15"]
+	expr_37 [label="expression\ntests/contract_testcases/solana/assign_array_in_array.sol:23:3-28"]
+	assign_38 [label="assign\nuint256[]\ntests/contract_testcases/solana/assign_array_in_array.sol:23:10-11"]
+	structmember_39 [label="struct member #0 uint256[]\ntests/contract_testcases/solana/assign_array_in_array.sol:23:7-9"]
+	variable_40 [label="variable: iPj\nstruct C.Sdynamic\ntests/contract_testcases/solana/assign_array_in_array.sol:23:3-6"]
+	alloc_array_41 [label="alloc array uint256[]\ntests/contract_testcases/solana/assign_array_in_array.sol:23:12-28"]
+	number_literal_42 [label="uint32 literal: 4\ntests/contract_testcases/solana/assign_array_in_array.sol:23:26-27"]
+	diagnostic [label="found contract ‘C’\nlevel Debug\ntests/contract_testcases/solana/assign_array_in_array.sol:1:60-2:12"]
+	diagnostic_45 [label="local variable ‘iPj‘ has been assigned, but never read\nlevel Warning\ntests/contract_testcases/solana/assign_array_in_array.sol:4:24-27"]
+	diagnostic_46 [label="local variable ‘iPj‘ has been assigned, but never read\nlevel Warning\ntests/contract_testcases/solana/assign_array_in_array.sol:9:23-26"]
+	diagnostic_47 [label="local variable ‘iPj‘ has been assigned, but never read\nlevel Warning\ntests/contract_testcases/solana/assign_array_in_array.sol:17:10-13"]
+	diagnostic_48 [label="local variable ‘iPj‘ has been assigned, but never read\nlevel Warning\ntests/contract_testcases/solana/assign_array_in_array.sol:22:12-15"]
+	diagnostic_49 [label="function can be declared ‘pure’\nlevel Warning\ntests/contract_testcases/solana/assign_array_in_array.sol:3:2-25"]
+	diagnostic_50 [label="function can be declared ‘pure’\nlevel Warning\ntests/contract_testcases/solana/assign_array_in_array.sol:8:2-27"]
+	diagnostic_51 [label="function can be declared ‘pure’\nlevel Warning\ntests/contract_testcases/solana/assign_array_in_array.sol:16:2-32"]
+	diagnostic_52 [label="function can be declared ‘pure’\nlevel Warning\ntests/contract_testcases/solana/assign_array_in_array.sol:21:2-34"]
+	structs -> Sfixed
+	structs -> Sdynamic
+	contracts -> contract
+	contract -> fixed [label="function"]
+	fixed -> var_decl [label="body"]
+	var_decl -> expr [label="next"]
+	expr -> assign [label="expr"]
+	assign -> subscript [label="left"]
+	subscript -> variable [label="array"]
+	subscript -> number_literal [label="index"]
+	assign -> array_literal [label="right"]
+	array_literal -> number_literal_13 [label="arg #0"]
+	array_literal -> number_literal_14 [label="arg #1"]
+	array_literal -> number_literal_15 [label="arg #2"]
+	contract -> dynamic [label="function"]
+	dynamic -> var_decl_17 [label="body"]
+	var_decl_17 -> expr_18 [label="next"]
+	expr_18 -> assign_19 [label="expr"]
+	assign_19 -> subscript_20 [label="left"]
+	subscript_20 -> variable_21 [label="array"]
+	subscript_20 -> number_literal_22 [label="index"]
+	assign_19 -> alloc_array [label="right"]
+	alloc_array -> number_literal_24 [label="length"]
+	contract -> fixed_struct [label="function"]
+	fixed_struct -> var_decl_26 [label="body"]
+	var_decl_26 -> expr_27 [label="next"]
+	expr_27 -> assign_28 [label="expr"]
+	assign_28 -> structmember [label="left"]
+	structmember -> variable_30 [label="var"]
+	assign_28 -> array_literal_31 [label="right"]
+	array_literal_31 -> number_literal_32 [label="arg #0"]
+	array_literal_31 -> number_literal_33 [label="arg #1"]
+	array_literal_31 -> number_literal_34 [label="arg #2"]
+	contract -> dynamic_struct [label="function"]
+	dynamic_struct -> var_decl_36 [label="body"]
+	var_decl_36 -> expr_37 [label="next"]
+	expr_37 -> assign_38 [label="expr"]
+	assign_38 -> structmember_39 [label="left"]
+	structmember_39 -> variable_40 [label="var"]
+	assign_38 -> alloc_array_41 [label="right"]
+	alloc_array_41 -> number_literal_42 [label="length"]
+	diagnostics -> diagnostic [label="Debug"]
+	diagnostics -> diagnostic_45 [label="Warning"]
+	diagnostics -> diagnostic_46 [label="Warning"]
+	diagnostics -> diagnostic_47 [label="Warning"]
+	diagnostics -> diagnostic_48 [label="Warning"]
+	diagnostics -> diagnostic_49 [label="Warning"]
+	diagnostics -> diagnostic_50 [label="Warning"]
+	diagnostics -> diagnostic_51 [label="Warning"]
+	diagnostics -> diagnostic_52 [label="Warning"]
+}

+ 25 - 0
tests/contract_testcases/solana/assign_array_in_array.sol

@@ -0,0 +1,25 @@
+// Ensure that subscript is assignable when member is array
+contract C {
+	function fixed() public {
+		uint256[3][4] memory iPj;
+		iPj[0] = [1,2,3];
+	}
+
+	function dynamic() public {
+		uint256[][4] memory iPj;
+		iPj[0] = new uint256[](4);
+	}
+
+	struct Sfixed { uint[3] f1; }
+	struct Sdynamic { uint[] f1; }
+
+	function fixed_struct() public {
+		Sfixed iPj;
+		iPj.f1 = [1,2,3];
+	}
+
+	function dynamic_struct() public {
+		Sdynamic iPj;
+		iPj.f1 = new uint256[](4);
+	}
+}