diff --git a/toolchain/semantics/semantics_context.cpp b/toolchain/semantics/semantics_context.cpp index e0b813e0da53..1ca8a3657eef 100644 --- a/toolchain/semantics/semantics_context.cpp +++ b/toolchain/semantics/semantics_context.cpp @@ -68,10 +68,7 @@ auto SemanticsContext::AddNodeAndPush(ParseTree::Node parse_node, auto SemanticsContext::AddNameToLookup(ParseTree::Node name_node, SemanticsStringId name_id, SemanticsNodeId target_id) -> void { - auto [it, inserted] = current_scope().names.insert(name_id); - if (inserted) { - name_lookup_[name_id].push_back(target_id); - } else { + if (!AddNameToLookupImpl(name_id, target_id)) { CARBON_DIAGNOSTIC(NameRedefined, Error, "Redefining {0} in the same scope.", llvm::StringRef); CARBON_DIAGNOSTIC(PreviousDefinition, Note, "Previous definition is here."); @@ -84,6 +81,16 @@ auto SemanticsContext::AddNameToLookup(ParseTree::Node name_node, } } +auto SemanticsContext::AddNameToLookupImpl(SemanticsStringId name_id, + SemanticsNodeId target_id) -> bool { + if (current_scope().names.insert(name_id).second) { + name_lookup_[name_id].push_back(target_id); + return true; + } else { + return false; + } +} + auto SemanticsContext::BindName(ParseTree::Node name_node, SemanticsNodeId type_id, SemanticsNodeId target_id) diff --git a/toolchain/semantics/semantics_context.h b/toolchain/semantics/semantics_context.h index 29d122264595..b5d4db56247c 100644 --- a/toolchain/semantics/semantics_context.h +++ b/toolchain/semantics/semantics_context.h @@ -38,10 +38,17 @@ class SemanticsContext { // result. auto AddNodeAndPush(ParseTree::Node parse_node, SemanticsNode node) -> void; - // Adds a name to name lookup. + // Adds a name to name lookup. Prints a diagnostic for name conflicts. auto AddNameToLookup(ParseTree::Node name_node, SemanticsStringId name_id, SemanticsNodeId target_id) -> void; + // Adds a name to name lookup. Ignores any name conflicts; the caller should + // ensure they were previously diagnosed by AddNameToLookup. + auto AddNameToLookupIgnoreConflicts(SemanticsStringId name_id, + SemanticsNodeId target_id) -> void { + AddNameToLookupImpl(name_id, target_id); + } + // Binds a DeclaredName to a target node with the given type. auto BindName(ParseTree::Node name_node, SemanticsNodeId type_id, SemanticsNodeId target_id) -> SemanticsStringId; @@ -170,6 +177,10 @@ class SemanticsContext { // TODO: This likely needs to track things which need to be destructed. }; + // Adds a name to lookup. Returns false on a name conflict. + auto AddNameToLookupImpl(SemanticsStringId name_id, SemanticsNodeId target_id) + -> bool; + // Runs ImplicitAs behavior to convert `value` to `as_type`, returning the // result type. The result will be the node to use to replace `value`. // diff --git a/toolchain/semantics/semantics_handle_function.cpp b/toolchain/semantics/semantics_handle_function.cpp index 43a5fcee61be..22141940dbf3 100644 --- a/toolchain/semantics/semantics_handle_function.cpp +++ b/toolchain/semantics/semantics_handle_function.cpp @@ -58,6 +58,11 @@ auto SemanticsHandleFunctionDefinitionStart(SemanticsContext& context, context.node_block_stack().Push(); context.PushScope(); + for (auto ref_id : context.semantics().GetNodeBlock(param_refs_id)) { + auto ref = context.semantics().GetNode(ref_id); + auto [name_id, target_id] = ref.GetAsBindName(); + context.AddNameToLookupIgnoreConflicts(name_id, target_id); + } context.return_scope_stack().push_back(decl_id); context.node_stack().Push(parse_node, decl_id); diff --git a/toolchain/semantics/testdata/function/call/empty_struct.carbon b/toolchain/semantics/testdata/function/call/empty_struct.carbon index 7524e7ee53e2..eb628dfa3b0e 100644 --- a/toolchain/semantics/testdata/function/call/empty_struct.carbon +++ b/toolchain/semantics/testdata/function/call/empty_struct.carbon @@ -5,7 +5,7 @@ // AUTOUPDATE // CHECK:STDOUT: cross_reference_irs_size: 1 // CHECK:STDOUT: callables: [ -// CHECK:STDOUT: {param_refs: block2}, +// CHECK:STDOUT: {param_refs: block2, return_type: nodeEmptyStructType}, // CHECK:STDOUT: {param_refs: block0}, // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ @@ -21,11 +21,12 @@ // CHECK:STDOUT: {kind: VarStorage, type: nodeEmptyStructType}, // CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node+0, type: nodeEmptyStructType}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str1, arg1: callable0}, -// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+2, arg1: block0}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+0, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+2, arg1: block4}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str2, arg1: callable1}, // CHECK:STDOUT: {kind: StubReference, arg0: nodeEmptyStruct, type: nodeEmptyStructType}, -// CHECK:STDOUT: {kind: Call, arg0: block5, arg1: callable0}, -// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+4, arg1: block4}, +// CHECK:STDOUT: {kind: Call, arg0: block6, arg1: callable0, type: nodeEmptyStructType}, +// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+5, arg1: block5}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ // CHECK:STDOUT: [ @@ -39,20 +40,24 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+2, -// CHECK:STDOUT: node+3, // CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+6, // CHECK:STDOUT: node+7, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+5, // CHECK:STDOUT: node+6, // CHECK:STDOUT: ], -// CHECK:STDOUT: [ -// CHECK:STDOUT: node+5, -// CHECK:STDOUT: ], // CHECK:STDOUT: ] -fn Echo(a: {}) { +fn Echo(a: {}) -> {} { + return a; } fn Main() { diff --git a/toolchain/semantics/testdata/function/call/i32.carbon b/toolchain/semantics/testdata/function/call/i32.carbon index adf206e13b3a..e20487e3277e 100644 --- a/toolchain/semantics/testdata/function/call/i32.carbon +++ b/toolchain/semantics/testdata/function/call/i32.carbon @@ -10,7 +10,6 @@ // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ // CHECK:STDOUT: 1, -// CHECK:STDOUT: 1, // CHECK:STDOUT: ] // CHECK:STDOUT: real_literals: [ // CHECK:STDOUT: ] @@ -24,17 +23,16 @@ // CHECK:STDOUT: {kind: VarStorage, type: nodeIntegerType}, // CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node+0, type: nodeIntegerType}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str1, arg1: callable0}, -// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, -// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+3, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+0, type: nodeIntegerType}, // CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+2, arg1: block4}, // CHECK:STDOUT: {kind: FunctionDeclaration, arg0: str2, arg1: callable1}, // CHECK:STDOUT: {kind: VarStorage, type: nodeIntegerType}, -// CHECK:STDOUT: {kind: BindName, arg0: str3, arg1: node+7, type: nodeIntegerType}, -// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: nodeIntegerType}, -// CHECK:STDOUT: {kind: StubReference, arg0: node+9, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: BindName, arg0: str3, arg1: node+6, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: nodeIntegerType}, // CHECK:STDOUT: {kind: Call, arg0: block6, arg1: callable0, type: nodeIntegerType}, -// CHECK:STDOUT: {kind: Assign, arg0: node+7, arg1: node+11, type: nodeIntegerType}, -// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+6, arg1: block5}, +// CHECK:STDOUT: {kind: Assign, arg0: node+6, arg1: node+10, type: nodeIntegerType}, +// CHECK:STDOUT: {kind: FunctionDefinition, arg0: node+5, arg1: block5}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ // CHECK:STDOUT: [ @@ -48,30 +46,28 @@ // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+4, // CHECK:STDOUT: node+5, -// CHECK:STDOUT: node+6, -// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+12, // CHECK:STDOUT: ], // CHECK:STDOUT: [ // CHECK:STDOUT: node+3, -// CHECK:STDOUT: node+4, // CHECK:STDOUT: ], // CHECK:STDOUT: [ +// CHECK:STDOUT: node+6, // CHECK:STDOUT: node+7, // CHECK:STDOUT: node+8, // CHECK:STDOUT: node+9, // CHECK:STDOUT: node+10, // CHECK:STDOUT: node+11, -// CHECK:STDOUT: node+12, // CHECK:STDOUT: ], // CHECK:STDOUT: [ -// CHECK:STDOUT: node+10, +// CHECK:STDOUT: node+9, // CHECK:STDOUT: ], // CHECK:STDOUT: ] fn Echo(a: i32) -> i32 { - // TODO: `return a;` requires the parameter to be in name lookup. - return 1; + return a; } fn Main() {