浏览代码

modifiers are allowed in libraries (#1273)

* modifiers are allowed in libraries
* Use par_bridge() so collect() can be avoided

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 2 年之前
父节点
当前提交
b02c90653b

+ 5 - 5
src/sema/functions.rs

@@ -346,7 +346,7 @@ pub fn contract_function(
             success = false;
         }
     } else if ns.contracts[contract_no].is_library() {
-        if func.ty != pt::FunctionTy::Function {
+        if func.ty != pt::FunctionTy::Function && func.ty != pt::FunctionTy::Modifier {
             ns.diagnostics.push(Diagnostic::error(
                 func.loc,
                 format!("{} not allowed in a library", func.ty),
@@ -355,19 +355,19 @@ pub fn contract_function(
         } else if func.body.is_none() {
             ns.diagnostics.push(Diagnostic::error(
                 func.loc,
-                "function in a library must have a body".to_string(),
+                format!("{} in a library must have a body", func.ty),
             ));
             success = false;
         } else if let Some((loc, _)) = is_override {
             ns.diagnostics.push(Diagnostic::error(
                 loc,
-                "function in a library cannot override".to_string(),
+                format!("{} in a library cannot override", func.ty),
             ));
             success = false;
         } else if let Some(pt::Mutability::Payable(_)) = mutability {
             ns.diagnostics.push(Diagnostic::error(
                 func.loc,
-                "function in a library cannot be payable".to_string(),
+                format!("{} in a library cannot be payable", func.ty),
             ));
             success = false;
         }
@@ -401,7 +401,7 @@ pub fn contract_function(
         is_virtual.is_some()
     };
 
-    if !is_virtual && func.body.is_none() {
+    if !is_virtual && func.body.is_none() && !ns.contracts[contract_no].is_library() {
         ns.diagnostics.push(Diagnostic::error(
             func.loc,
             "function with no body missing 'virtual'. This was permitted in older versions of the Solidity language, please update.".to_string(),

+ 6 - 2
tests/contract_testcases/substrate/libraries/restrictions_03.dot

@@ -1,8 +1,12 @@
 strict digraph "tests/contract_testcases/substrate/libraries/restrictions_03.sol" {
-	contract [label="contract c\ntests/contract_testcases/substrate/libraries/restrictions_03.sol:2:9-4:10"]
-	diagnostic [label="found library 'c'\nlevel Debug\ntests/contract_testcases/substrate/libraries/restrictions_03.sol:2:9-4:10"]
+	contract [label="contract c\ntests/contract_testcases/substrate/libraries/restrictions_03.sol:2:9-6:10"]
+	diagnostic [label="found library 'c'\nlevel Debug\ntests/contract_testcases/substrate/libraries/restrictions_03.sol:2:9-6:10"]
 	diagnostic_4 [label="function in a library cannot be payable\nlevel Error\ntests/contract_testcases/substrate/libraries/restrictions_03.sol:3:13-40"]
+	diagnostic_5 [label="modifier in a library cannot override\nlevel Error\ntests/contract_testcases/substrate/libraries/restrictions_03.sol:4:26-34"]
+	diagnostic_6 [label="modifier in a library must have a body\nlevel Error\ntests/contract_testcases/substrate/libraries/restrictions_03.sol:5:13-26"]
 	contracts -> contract
 	diagnostics -> diagnostic [label="Debug"]
 	diagnostics -> diagnostic_4 [label="Error"]
+	diagnostics -> diagnostic_5 [label="Error"]
+	diagnostics -> diagnostic_6 [label="Error"]
 }

+ 2 - 0
tests/contract_testcases/substrate/libraries/restrictions_03.sol

@@ -1,4 +1,6 @@
 
         library c {
             function f() public payable {}
+            modifier m() override {}
+            modifier m2();
         }

+ 11 - 15
tests/evm.rs

@@ -173,25 +173,21 @@ contract testing  {
 fn ethereum_solidity_tests() {
     let error_matcher = regex::Regex::new(r"// ----\r?\n// \w+Error( \d+)?:").unwrap();
 
-    let semantic_tests = WalkDir::new(
+    let entries = WalkDir::new(
         Path::new(env!("CARGO_MANIFEST_DIR"))
             .join("testdata/solidity/test/libsolidity/semanticTests"),
     )
-    .into_iter();
-
-    let syntax_tests = WalkDir::new(
-        Path::new(env!("CARGO_MANIFEST_DIR"))
-            .join("testdata/solidity/test/libsolidity/syntaxTests"),
-    )
-    .into_iter();
-
-    let entries: Vec<_> = semantic_tests
-        .into_iter()
-        .chain(syntax_tests.into_iter())
-        .collect();
+    .into_iter()
+    .chain(
+        WalkDir::new(
+            Path::new(env!("CARGO_MANIFEST_DIR"))
+                .join("testdata/solidity/test/libsolidity/syntaxTests"),
+        )
+        .into_iter(),
+    );
 
     let errors: usize = entries
-        .into_par_iter()
+        .par_bridge()
         .filter_map(|e| {
             let entry = e.unwrap();
             let file_name = entry.file_name().to_string_lossy();
@@ -258,7 +254,7 @@ fn ethereum_solidity_tests() {
         })
         .sum();
 
-    assert_eq!(errors, 1056);
+    assert_eq!(errors, 1053);
 }
 
 fn set_file_contents(source: &str, path: &Path) -> (FileResolver, Vec<String>) {

+ 33 - 0
tests/substrate_tests/modifier.rs

@@ -348,3 +348,36 @@ fn repeated_modifier() {
     runtime.function_expect_failure("contfunc", (0u64, 1u64).encode());
     runtime.function("contfunc", (1u64, 1u64).encode());
 }
+
+#[test]
+fn modifier_in_library() {
+    let mut runtime = build_solidity(
+        r##"
+        library LibWidthMod {
+            modifier m(uint64 v) {
+                require(v > 100);
+                _;
+            }
+
+            function withMod(uint64 self) m(self) internal view {
+                require(self > 10);
+            }
+        }
+
+        contract Test {
+            using LibWidthMod for uint64;
+
+            function test(uint64 n) external {
+                n.withMod();
+                LibWidthMod.withMod(n);
+            }
+        }"##,
+    );
+
+    runtime.constructor(0, Vec::new());
+
+    runtime.function_expect_failure("test", 0u64.encode());
+    runtime.function_expect_failure("test", 50u64.encode());
+    runtime.function_expect_failure("test", 100u64.encode());
+    runtime.function("test", 200u64.encode());
+}