From 0238bb58f43f1189f258c408f35e96679740bdd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Wed, 21 Aug 2024 11:31:33 -0400 Subject: [PATCH] Rules for name resolution in Yul functions --- .../inputs/language/bindings/rules.msgb | 55 ++++++++++++++++ .../bindings/generated/binding_rules.rs | 55 ++++++++++++++++ .../src/bindings_assertions/generated/yul.rs | 10 +++ .../src/bindings_output/generated/yul.rs | 5 ++ .../bindings_assertions/yul/fun_scopes.sol | 33 ++++++++++ .../bindings_assertions/yul/functions.sol | 32 ++++++++++ .../functions/generated/0.4.11-success.txt | 62 +++++++++++++++++++ .../bindings_output/yul/functions/input.sol | 14 +++++ 8 files changed, 266 insertions(+) create mode 100644 crates/solidity/testing/snapshots/bindings_assertions/yul/fun_scopes.sol create mode 100644 crates/solidity/testing/snapshots/bindings_assertions/yul/functions.sol create mode 100644 crates/solidity/testing/snapshots/bindings_output/yul/functions/generated/0.4.11-success.txt create mode 100644 crates/solidity/testing/snapshots/bindings_output/yul/functions/input.sol diff --git a/crates/solidity/inputs/language/bindings/rules.msgb b/crates/solidity/inputs/language/bindings/rules.msgb index 1916ca7f7..5ea1032d0 100644 --- a/crates/solidity/inputs/language/bindings/rules.msgb +++ b/crates/solidity/inputs/language/bindings/rules.msgb @@ -1076,6 +1076,9 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i @block [YulBlock] { node @block.lexical_scope node @block.defs + node @block.fundefs + + edge @block.lexical_scope -> @block.fundefs } @block [YulBlock [YulStatements . @stmt [YulStatement]]] { @@ -1099,6 +1102,12 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge @block.lexical_scope -> @stmt.lexical_scope } +@parent_block [YulBlock [YulStatements [YulStatement @child_block [YulBlock]]]] { + ;; Child blocks have direct access to the parent's function definitions (to + ;; allow propagation to inner function definitions) + edge @child_block.fundefs -> @parent_block.fundefs +} + ;;; Expression as statements @stmt [YulStatement @expr_stmt [YulExpression]] { @@ -1149,6 +1158,52 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge @expr.lexical_scope -> @var_assign.lexical_scope } +;;; Function definitions + +@block [YulBlock [YulStatements [YulStatement @fundef [YulFunctionDefinition]]]] { + ;; Function definitions are hoisted in the enclosing block + edge @block.fundefs -> @fundef.def + ;; The only definitions available in the function's lexical scope (other than + ;; parameters) are functions (ie. the body of the function doesn't have access + ;; to any outside variables) + edge @fundef.lexical_scope -> @block.fundefs +} + +@fundef [YulFunctionDefinition + @name name: [YulIdentifier] + @body body: [YulBlock] +] { + node @fundef.lexical_scope + node @fundef.def + + node def + attr (def) node_definition = @name + attr (def) definiens_node = @fundef + + edge @fundef.def -> def + edge @body.lexical_scope -> @fundef.lexical_scope +} + +@fundef [YulFunctionDefinition [YulParametersDeclaration [YulParameters + @param [YulIdentifier] +]]] { + node def + attr (def) node_definition = @param + attr (def) definiens_node = @param + + edge @fundef.lexical_scope -> def +} + +@fundef [YulFunctionDefinition [YulReturnsDeclaration [YulVariableNames + @return_param [YulIdentifier] +]]] { + node def + attr (def) node_definition = @return_param + attr (def) definiens_node = @return_param + + edge @fundef.lexical_scope -> def +} + ;;; Expressions @expr [YulExpression] { diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs index 46f4973e8..bea10bbe9 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/bindings/generated/binding_rules.rs @@ -1081,6 +1081,9 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i @block [YulBlock] { node @block.lexical_scope node @block.defs + node @block.fundefs + + edge @block.lexical_scope -> @block.fundefs } @block [YulBlock [YulStatements . @stmt [YulStatement]]] { @@ -1104,6 +1107,12 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge @block.lexical_scope -> @stmt.lexical_scope } +@parent_block [YulBlock [YulStatements [YulStatement @child_block [YulBlock]]]] { + ;; Child blocks have direct access to the parent's function definitions (to + ;; allow propagation to inner function definitions) + edge @child_block.fundefs -> @parent_block.fundefs +} + ;;; Expression as statements @stmt [YulStatement @expr_stmt [YulExpression]] { @@ -1154,6 +1163,52 @@ attribute symbol_reference = symbol => type = "push_symbol", symbol = symbol, i edge @expr.lexical_scope -> @var_assign.lexical_scope } +;;; Function definitions + +@block [YulBlock [YulStatements [YulStatement @fundef [YulFunctionDefinition]]]] { + ;; Function definitions are hoisted in the enclosing block + edge @block.fundefs -> @fundef.def + ;; The only definitions available in the function's lexical scope (other than + ;; parameters) are functions (ie. the body of the function doesn't have access + ;; to any outside variables) + edge @fundef.lexical_scope -> @block.fundefs +} + +@fundef [YulFunctionDefinition + @name name: [YulIdentifier] + @body body: [YulBlock] +] { + node @fundef.lexical_scope + node @fundef.def + + node def + attr (def) node_definition = @name + attr (def) definiens_node = @fundef + + edge @fundef.def -> def + edge @body.lexical_scope -> @fundef.lexical_scope +} + +@fundef [YulFunctionDefinition [YulParametersDeclaration [YulParameters + @param [YulIdentifier] +]]] { + node def + attr (def) node_definition = @param + attr (def) definiens_node = @param + + edge @fundef.lexical_scope -> def +} + +@fundef [YulFunctionDefinition [YulReturnsDeclaration [YulVariableNames + @return_param [YulIdentifier] +]]] { + node def + attr (def) node_definition = @return_param + attr (def) definiens_node = @return_param + + edge @fundef.lexical_scope -> def +} + ;;; Expressions @expr [YulExpression] { diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/yul.rs b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/yul.rs index 22af228be..45724629d 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/yul.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_assertions/generated/yul.rs @@ -9,6 +9,16 @@ fn blocks() -> Result<()> { run("yul", "blocks") } +#[test] +fn fun_scopes() -> Result<()> { + run("yul", "fun_scopes") +} + +#[test] +fn functions() -> Result<()> { + run("yul", "functions") +} + #[test] fn variables() -> Result<()> { run("yul", "variables") diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/yul.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/yul.rs index 4ea316210..d16e315ce 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/yul.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/generated/yul.rs @@ -4,6 +4,11 @@ use anyhow::Result; use crate::bindings_output::runner::run; +#[test] +fn functions() -> Result<()> { + run("yul", "functions") +} + #[test] fn variables() -> Result<()> { run("yul", "variables") diff --git a/crates/solidity/testing/snapshots/bindings_assertions/yul/fun_scopes.sol b/crates/solidity/testing/snapshots/bindings_assertions/yul/fun_scopes.sol new file mode 100644 index 000000000..7f202c679 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_assertions/yul/fun_scopes.sol @@ -0,0 +1,33 @@ +contract AssemblyFunctions { + function test(uint256 a) public returns (uint256 r) { + // ^def:4 + // ^def:3 + assembly { + { + function inner(x_i) -> x { + // ^def:1 + x := add(x_i, 1) + } + + r := inner(a) + // ^ref:3 + // ^ref:1 + // y { + // ^def:2 + y := inner() + // ^ref:! -- function is not visible here + r := add(a, 1) + // ^ref:! -- assembly functions cannot access Solidity variables + // b { + // ^def:1 + b := add(a, 1) + } + + { + r := add(outer1(x), inner(x)) + // ^ref:2 + // ^ref:1 + function inner(f) -> g { + // ^def:2 + g:= mul(f, outer2(f)) + // ^ref:3 + } + } + + function outer2(c) -> d { + // ^def:3 + d := mul(c, outer2_inner(c)) + // ^ref:4 + + function outer2_inner(e) -> f { + // ^def:4 + f := e + } + } + } + } +} diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/functions/generated/0.4.11-success.txt b/crates/solidity/testing/snapshots/bindings_output/yul/functions/generated/0.4.11-success.txt new file mode 100644 index 000000000..4d553b050 --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/functions/generated/0.4.11-success.txt @@ -0,0 +1,62 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +References and definitions: + ╭─[input.sol:1:1] + │ + 1 │ contract AssemblyFunctions { + │ ────────┬──────── + │ ╰────────── def: 1 + 2 │ function test(uint256 x) public returns (uint256 r) { + │ ──┬─ ┬ ┬ + │ ╰──────────────────────────────────────── def: 2 + │ │ │ + │ ╰───────────────────────────── def: 3 + │ │ + │ ╰── def: 4 + │ + 4 │ let y := add(x, 5) + │ ┬ ┬ + │ ╰─────────── def: 5 + │ │ + │ ╰── ref: 3 + 5 │ x, y := swap(x, y) + │ ┬ ┬ ──┬─ ┬ ┬ + │ ╰────────────────── ref: 3 + │ │ │ │ │ + │ ╰─────────────── ref: 5 + │ │ │ │ + │ ╰──────── ref: 6 + │ │ │ + │ ╰───── ref: 3 + │ │ + │ ╰── ref: 5 + 6 │ r := add(x, y) + │ ┬ ┬ ┬ + │ ╰────────────── ref: 4 + │ │ │ + │ ╰───── ref: 3 + │ │ + │ ╰── ref: 5 + │ + 8 │ function swap(a, b) -> c, d { + │ ──┬─ ┬ ┬ ┬ ┬ + │ ╰───────────────── def: 6 + │ │ │ │ │ + │ ╰────────────── def: 7 + │ │ │ │ + │ ╰─────────── def: 8 + │ │ │ + │ ╰───── def: 9 + │ │ + │ ╰── def: 10 + 9 │ c := b + │ ┬ ┬ + │ ╰─────── ref: 9 + │ │ + │ ╰── ref: 8 + 10 │ d := a + │ ┬ ┬ + │ ╰─────── ref: 10 + │ │ + │ ╰── ref: 7 +────╯ diff --git a/crates/solidity/testing/snapshots/bindings_output/yul/functions/input.sol b/crates/solidity/testing/snapshots/bindings_output/yul/functions/input.sol new file mode 100644 index 000000000..dab773cee --- /dev/null +++ b/crates/solidity/testing/snapshots/bindings_output/yul/functions/input.sol @@ -0,0 +1,14 @@ +contract AssemblyFunctions { + function test(uint256 x) public returns (uint256 r) { + assembly { + let y := add(x, 5) + x, y := swap(x, y) + r := add(x, y) + + function swap(a, b) -> c, d { + c := b + d := a + } + } + } +}