diff --git a/src/protocol/parser/pass_validation_linking.rs b/src/protocol/parser/pass_validation_linking.rs index 7c4ee025797c50873fbdc82094227c4d82931caf..9cf01b6658a57d968b13d4096b47b6966892ca01 100644 --- a/src/protocol/parser/pass_validation_linking.rs +++ b/src/protocol/parser/pass_validation_linking.rs @@ -1613,18 +1613,18 @@ impl PassValidationLinking { /// Adds a local variable to the current scope. It will also annotate the /// `Local` in the AST with its relative position in the block. - fn checked_add_local(&mut self, ctx: &mut Ctx, target_scope: Scope, relative_pos: i32, id: VariableId) -> Result<(), ParseError> { + fn checked_add_local(&mut self, ctx: &mut Ctx, target_scope: Scope, target_relative_pos: i32, id: VariableId) -> Result<(), ParseError> { debug_assert!(target_scope.is_block()); let local = &ctx.heap[id]; - println!("DEBUG: Adding local '{}' at relative_pos {} in scope {:?}", local.identifier.value.as_str(), relative_pos, target_scope); - - let mut scope = target_scope; + println!("DEBUG: Adding local '{}' at relative_pos {} in scope {:?}", local.identifier.value.as_str(), target_relative_pos, target_scope); + + // We immediately go to the parent scope. We check the target scope + // in the call at the end. That is also where we check for collisions + // with symbols. + let block = &ctx.heap[target_scope.to_block()]; + let mut scope = block.scope_node.parent; + let mut cur_relative_pos = block.scope_node.relative_pos_in_parent; loop { - // We immediately go to the parent scope. We check the current scope - // in the call at the end. Likewise for checking the symbol table. - let block = &ctx.heap[scope.to_block()]; - - scope = block.scope_node.parent; if let Scope::Definition(definition_id) = scope { // At outer scope, check parameters of function/component for parameter_id in ctx.heap[definition_id].parameters() { @@ -1645,7 +1645,7 @@ impl PassValidationLinking { } // If here then the parent scope is a block scope - let local_relative_pos = ctx.heap[scope.to_block()].scope_node.relative_pos_in_parent; + let block = &ctx.heap[scope.to_block()]; for other_local_id in &block.locals { let other_local = &ctx.heap[*other_local_id]; @@ -1653,7 +1653,7 @@ impl PassValidationLinking { // is defined in a higher-level scope, but later than the scope // in which the current variable resides. if local.this != *other_local_id && - local_relative_pos >= other_local.relative_pos_in_block && + cur_relative_pos >= other_local.relative_pos_in_block && local.identifier == other_local.identifier { // Collision within this scope return Err( @@ -1665,10 +1665,13 @@ impl PassValidationLinking { ); } } + + scope = block.scope_node.parent; + cur_relative_pos = block.scope_node.relative_pos_in_parent; } // No collisions in any of the parent scope, attempt to add to scope - self.checked_at_single_scope_add_local(ctx, target_scope, relative_pos, id) + self.checked_at_single_scope_add_local(ctx, target_scope, target_relative_pos, id) } /// Adds a local variable to the specified scope. Will check the specified diff --git a/src/protocol/tests/parser_validation.rs b/src/protocol/tests/parser_validation.rs index a6c63495b33f7bace49de11de94829744a70b7f1..f6cb386849c640aa79f36a3f3d96477e9161917b 100644 --- a/src/protocol/tests/parser_validation.rs +++ b/src/protocol/tests/parser_validation.rs @@ -651,14 +651,29 @@ fn test_incorrect_select_statement() { .assert_msg_has(0, "inside sync blocks"); }); - Tester::new_single_source_expect_ok( + Tester::new_single_source_expect_err( "variable in previous block", "primitive f() { channel tx -> rx; u32 a = 0; // this one will be shadowed sync select { auto a = get(rx) -> {} } }" - ); + ).error(|e| { e + .assert_num(2) + .assert_occurs_at(0, "a = get").assert_msg_has(0, "variable name conflicts") + .assert_occurs_at(1, "a = 0").assert_msg_has(1, "Previous variable"); + }); + + Tester::new_single_source_expect_err( + "put inside arm", + "primitive f() { + channel a -> b; + sync select { put(a) -> {} } + }" + ).error(|e| { e + .assert_occurs_at(0, "put") + .assert_msg_has(0, "may not occur"); + }); } #[test]