From 292a9d3cb471cf03f7a4b74b5d8f489a2dffb9c3 Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Mon, 6 May 2024 14:27:21 -0700 Subject: [PATCH] Replace ResolvePrevInstForMerge with decl logic. (#3936) This addresses the const reliance of ResolvePrevInstForMerge by checking the imported instruction, testing with `alias` name conflicts. Given the need to examine structure, the helper function feels like it now gets in the way, so I'm just removing it. --------- Co-authored-by: Richard Smith --- toolchain/check/class.cpp | 6 +- toolchain/check/class.h | 2 +- toolchain/check/function.cpp | 6 +- toolchain/check/function.h | 2 +- toolchain/check/handle_class.cpp | 69 +++-- toolchain/check/handle_function.cpp | 61 +++-- toolchain/check/merge.cpp | 20 +- toolchain/check/merge.h | 17 +- .../class/no_prelude/implicit_import.carbon | 242 ++++++++++++++++++ .../no_prelude/implicit_import.carbon | 72 +++++- 10 files changed, 400 insertions(+), 97 deletions(-) create mode 100644 toolchain/check/testdata/class/no_prelude/implicit_import.carbon diff --git a/toolchain/check/class.cpp b/toolchain/check/class.cpp index c7dbcd45c4a0..05d3cdc00003 100644 --- a/toolchain/check/class.cpp +++ b/toolchain/check/class.cpp @@ -12,7 +12,7 @@ auto MergeClassRedecl(Context& context, SemIRLoc new_loc, SemIR::Class& new_class, bool new_is_import, bool new_is_definition, bool new_is_extern, SemIR::ClassId prev_class_id, bool prev_is_extern, - SemIR::ImportIRInstId prev_import_ir_inst_id) -> bool { + SemIR::ImportIRId prev_import_ir_id) -> bool { auto& prev_class = context.classes().Get(prev_class_id); SemIRLoc prev_loc = prev_class.is_defined() ? prev_class.definition_id : prev_class.decl_id; @@ -30,7 +30,7 @@ auto MergeClassRedecl(Context& context, SemIRLoc new_loc, {.loc = prev_loc, .is_definition = prev_class.is_defined(), .is_extern = prev_is_extern}, - prev_import_ir_inst_id); + prev_import_ir_id); // The introducer kind must match the previous declaration. // TODO: The rule here is not yet decided. See #3384. @@ -56,7 +56,7 @@ auto MergeClassRedecl(Context& context, SemIRLoc new_loc, prev_class.object_repr_id = new_class.object_repr_id; } - if ((prev_import_ir_inst_id.is_valid() && !new_is_import) || + if ((prev_import_ir_id.is_valid() && !new_is_import) || (prev_is_extern && !new_is_extern)) { prev_class.decl_id = new_class.decl_id; ReplacePrevInstForMerge( diff --git a/toolchain/check/class.h b/toolchain/check/class.h index 2a5265697706..ed1d56cd64b8 100644 --- a/toolchain/check/class.h +++ b/toolchain/check/class.h @@ -21,7 +21,7 @@ auto MergeClassRedecl(Context& context, SemIRLoc new_loc, SemIR::Class& new_class, bool new_is_import, bool new_is_definition, bool new_is_extern, SemIR::ClassId prev_class_id, bool prev_is_extern, - SemIR::ImportIRInstId prev_import_ir_inst_id) -> bool; + SemIR::ImportIRId prev_import_ir_id) -> bool; } // namespace Carbon::Check diff --git a/toolchain/check/function.cpp b/toolchain/check/function.cpp index cd5e4c1b584b..b614731b724b 100644 --- a/toolchain/check/function.cpp +++ b/toolchain/check/function.cpp @@ -95,7 +95,7 @@ auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc, SemIR::Function& new_function, bool new_is_import, bool new_is_definition, SemIR::FunctionId prev_function_id, - SemIR::ImportIRInstId prev_import_ir_inst_id) -> bool { + SemIR::ImportIRId prev_import_ir_id) -> bool { auto& prev_function = context.functions().Get(prev_function_id); if (!CheckRedecl(context, new_function, prev_function, {})) { @@ -111,7 +111,7 @@ auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc, : prev_function.decl_id, .is_definition = prev_function.definition_id.is_valid(), .is_extern = prev_function.is_extern}, - prev_import_ir_inst_id); + prev_import_ir_id); if (new_is_definition) { // Track the signature from the definition, so that IDs in the body @@ -125,7 +125,7 @@ auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc, // The new function might have return slot information if it was imported. prev_function.return_slot = MergeReturnSlot(prev_function.return_slot, new_function.return_slot); - if ((prev_import_ir_inst_id.is_valid() && !new_is_import) || + if ((prev_import_ir_id.is_valid() && !new_is_import) || (prev_function.is_extern && !new_function.is_extern)) { prev_function.is_extern = new_function.is_extern; prev_function.decl_id = new_function.decl_id; diff --git a/toolchain/check/function.h b/toolchain/check/function.h index 22fa24ed699e..fbfa39a07507 100644 --- a/toolchain/check/function.h +++ b/toolchain/check/function.h @@ -46,7 +46,7 @@ auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc, SemIR::Function& new_function, bool new_is_import, bool new_is_definition, SemIR::FunctionId prev_function_id, - SemIR::ImportIRInstId prev_import_ir_inst_id) -> bool; + SemIR::ImportIRId prev_import_ir_id) -> bool; // Checks that the return type of the specified function is complete, issuing an // error if not. This computes the return slot usage for the function if diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index c9d6c9be68b9..03fcc3c46093 100644 --- a/toolchain/check/handle_class.cpp +++ b/toolchain/check/handle_class.cpp @@ -48,38 +48,53 @@ static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id, bool is_extern) -> void { auto prev_id = context.decl_name_stack().LookupOrAddName(name_context, class_decl_id); - if (prev_id.is_valid()) { - auto prev_inst_for_merge = ResolvePrevInstForMerge(context, prev_id); + if (!prev_id.is_valid()) { + return; + } - auto prev_class_id = SemIR::ClassId::Invalid; - CARBON_KIND_SWITCH(prev_inst_for_merge.inst) { - case CARBON_KIND(SemIR::ClassDecl class_decl): { - prev_class_id = class_decl.class_id; - break; - } - case CARBON_KIND(SemIR::ClassType class_type): { - prev_class_id = class_type.class_id; - break; - } - default: - // This is a redeclaration of something other than a class. - context.DiagnoseDuplicateName(class_decl_id, prev_id); - break; + auto prev_class_id = SemIR::ClassId::Invalid; + auto prev_import_ir_id = SemIR::ImportIRId::Invalid; + CARBON_KIND_SWITCH(context.insts().Get(prev_id)) { + case CARBON_KIND(SemIR::ClassDecl class_decl): { + prev_class_id = class_decl.class_id; + break; } + case CARBON_KIND(SemIR::ImportRefLoaded import_ref): { + auto import_ir_inst = + context.import_ir_insts().Get(import_ref.import_ir_inst_id); - if (prev_class_id.is_valid()) { - // TODO: Fix prev_is_extern logic. - if (MergeClassRedecl(context, node_id, class_info, - /*new_is_import=*/false, is_definition, is_extern, - prev_class_id, /*prev_is_extern=*/false, - prev_inst_for_merge.import_ir_inst_id)) { - // When merging, use the existing entity rather than adding a new one. - class_decl.class_id = prev_class_id; + // Verify the decl so that things like aliases are name conflicts. + const auto* import_ir = + context.import_irs().Get(import_ir_inst.ir_id).sem_ir; + if (!import_ir->insts().Is(import_ir_inst.inst_id)) { + break; } - } else { - // This is a redeclaration of something other than a class. - context.DiagnoseDuplicateName(class_decl_id, prev_id); + + // Use the type to get the ID. + if (auto class_type = context.insts().TryGetAs( + context.constant_values().Get(prev_id).inst_id())) { + prev_class_id = class_type->class_id; + prev_import_ir_id = import_ir_inst.ir_id; + } + break; } + default: + break; + } + + if (!prev_class_id.is_valid()) { + // This is a redeclaration of something other than a class. + context.DiagnoseDuplicateName(class_decl_id, prev_id); + return; + } + + // TODO: Fix prev_is_extern logic. + if (MergeClassRedecl(context, node_id, class_info, + /*new_is_import=*/false, is_definition, is_extern, + prev_class_id, /*prev_is_extern=*/false, + prev_import_ir_id)) { + // When merging, use the existing entity rather than adding a new one. + class_decl.class_id = prev_class_id; } } diff --git a/toolchain/check/handle_function.cpp b/toolchain/check/handle_function.cpp index 3a27cbd2665e..3172ec3b7a63 100644 --- a/toolchain/check/handle_function.cpp +++ b/toolchain/check/handle_function.cpp @@ -61,28 +61,6 @@ static auto DiagnoseModifiers(Context& context, bool is_definition, return context.decl_state_stack().innermost().modifier_set; } -// Returns the function ID for the instruction, or invalid. -static auto GetRedeclFunctionId(Context& context, SemIR::Inst prev_inst) - -> SemIR::FunctionId { - CARBON_KIND_SWITCH(prev_inst) { - case CARBON_KIND(SemIR::StructValue struct_value): { - if (auto fn_type = context.types().TryGetAs( - struct_value.type_id)) { - return fn_type->function_id; - } - return SemIR::FunctionId::Invalid; - } - case CARBON_KIND(SemIR::FunctionDecl fn_decl): { - return fn_decl.function_id; - } - default: - // This is a redeclaration of something other than a function. This - // includes the case where an associated function redeclares another - // associated function. - return SemIR::FunctionId::Invalid; - } -} - // Check whether this is a redeclaration, merging if needed. static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id, SemIR::InstId prev_id, @@ -93,9 +71,39 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id, return; } - auto prev_inst_for_merge = ResolvePrevInstForMerge(context, prev_id); - auto prev_function_id = - GetRedeclFunctionId(context, prev_inst_for_merge.inst); + auto prev_function_id = SemIR::FunctionId::Invalid; + auto prev_import_ir_id = SemIR::ImportIRId::Invalid; + CARBON_KIND_SWITCH(context.insts().Get(prev_id)) { + case CARBON_KIND(SemIR::FunctionDecl function_decl): { + prev_function_id = function_decl.function_id; + break; + } + case CARBON_KIND(SemIR::ImportRefLoaded import_ref): { + auto import_ir_inst = + context.import_ir_insts().Get(import_ref.import_ir_inst_id); + + // Verify the decl so that things like aliases are name conflicts. + const auto* import_ir = + context.import_irs().Get(import_ir_inst.ir_id).sem_ir; + if (!import_ir->insts().Is(import_ir_inst.inst_id)) { + break; + } + + // Use the type to get the ID. + if (auto struct_value = context.insts().TryGetAs( + context.constant_values().Get(prev_id).inst_id())) { + if (auto function_type = context.types().TryGetAs( + struct_value->type_id)) { + prev_function_id = function_type->function_id; + prev_import_ir_id = import_ir_inst.ir_id; + } + } + break; + } + default: + break; + } + if (!prev_function_id.is_valid()) { context.DiagnoseDuplicateName(function_info.decl_id, prev_id); return; @@ -103,8 +111,7 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id, if (MergeFunctionRedecl(context, node_id, function_info, /*new_is_import=*/false, is_definition, - prev_function_id, - prev_inst_for_merge.import_ir_inst_id)) { + prev_function_id, prev_import_ir_id)) { // When merging, use the existing function rather than adding a new one. function_decl.function_id = prev_function_id; } diff --git a/toolchain/check/merge.cpp b/toolchain/check/merge.cpp index 88196f7bd09d..764fa8cde9a5 100644 --- a/toolchain/check/merge.cpp +++ b/toolchain/check/merge.cpp @@ -72,10 +72,9 @@ static auto DiagnoseNonExtern(Context& context, Lex::TokenKind decl_kind, // These all still merge. auto CheckIsAllowedRedecl(Context& context, Lex::TokenKind decl_kind, SemIR::NameId name_id, RedeclInfo new_decl, - RedeclInfo prev_decl, - SemIR::ImportIRInstId prev_import_ir_inst_id) + RedeclInfo prev_decl, SemIR::ImportIRId import_ir_id) -> void { - if (!prev_import_ir_inst_id.is_valid()) { + if (!import_ir_id.is_valid()) { // Check for disallowed redeclarations in the same file. if (!new_decl.is_definition) { DiagnoseRedundant(context, decl_kind, name_id, new_decl.loc, @@ -96,8 +95,6 @@ auto CheckIsAllowedRedecl(Context& context, Lex::TokenKind decl_kind, return; } - auto import_ir_id = - context.import_ir_insts().Get(prev_import_ir_inst_id).ir_id; if (import_ir_id == SemIR::ImportIRId::ApiForImpl) { // Check for disallowed redeclarations in the same library. Note that a // forward declaration in the impl is allowed. @@ -125,19 +122,6 @@ auto CheckIsAllowedRedecl(Context& context, Lex::TokenKind decl_kind, } } -auto ResolvePrevInstForMerge(Context& context, SemIR::InstId prev_inst_id) - -> InstForMerge { - InstForMerge result = {.inst = context.insts().Get(prev_inst_id), - .import_ir_inst_id = SemIR::ImportIRInstId::Invalid}; - if (auto import_ref = result.inst.TryAs()) { - // Follow the import ref. - result.import_ir_inst_id = import_ref->import_ir_inst_id; - result.inst = context.insts().Get( - context.constant_values().Get(prev_inst_id).inst_id()); - } - return result; -} - auto ReplacePrevInstForMerge(Context& context, SemIR::NameScopeId scope_id, SemIR::NameId name_id, SemIR::InstId new_inst_id) -> void { diff --git a/toolchain/check/merge.h b/toolchain/check/merge.h index 1b11ed4a3677..35191ab2e926 100644 --- a/toolchain/check/merge.h +++ b/toolchain/check/merge.h @@ -32,22 +32,7 @@ struct RedeclInfo { auto CheckIsAllowedRedecl(Context& context, Lex::TokenKind decl_kind, SemIR::NameId name_id, RedeclInfo new_decl, RedeclInfo prev_decl, - SemIR::ImportIRInstId prev_import_ir_inst_id) -> void; - -struct InstForMerge { - // The resolved instruction. - SemIR::Inst inst; - // The imported instruction, or invalid if not an import. This should - // typically only be used for the ImportIRId, but we only load it if needed. - SemIR::ImportIRInstId import_ir_inst_id; -}; - -// Resolves prev_inst_id for merging (or name conflicts). This handles imports -// to return the instruction relevant for a merge. If an import is found and was -// previously used, it notes it, although an invalid redeclaration may diagnose -// for other reasons too. -auto ResolvePrevInstForMerge(Context& context, SemIR::InstId prev_inst_id) - -> InstForMerge; + SemIR::ImportIRId prev_import_ir_id) -> void; // When the prior name lookup result is an import and we are successfully // merging, replace the name lookup result with the reference in the current diff --git a/toolchain/check/testdata/class/no_prelude/implicit_import.carbon b/toolchain/check/testdata/class/no_prelude/implicit_import.carbon new file mode 100644 index 000000000000..646359854716 --- /dev/null +++ b/toolchain/check/testdata/class/no_prelude/implicit_import.carbon @@ -0,0 +1,242 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +// --- basic.carbon + +library "basic" api; + +class C; + +// --- basic.impl.carbon + +library "basic" impl; + +class C {} + +// --- redecl_after_def.carbon + +library "redecl_after_def" api; + +class C {} + +// --- fail_redecl_after_def.impl.carbon + +library "redecl_after_def" impl; + +// CHECK:STDERR: fail_redecl_after_def.impl.carbon:[[@LINE+10]]:1: ERROR: Redeclaration of `class C` is redundant. +// CHECK:STDERR: class C; +// CHECK:STDERR: ^~~~~~~~ +// CHECK:STDERR: fail_redecl_after_def.impl.carbon:[[@LINE-5]]:1: In import. +// CHECK:STDERR: library "redecl_after_def" impl; +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: redecl_after_def.carbon:4:1: Previously declared here. +// CHECK:STDERR: class C {} +// CHECK:STDERR: ^~~~~~~~~ +// CHECK:STDERR: +class C; + +// --- redef_after_def.carbon + +library "redef_after_def" api; + +class C {} + +// --- fail_redef_after_def.impl.carbon + +library "redef_after_def" impl; + +// CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE+10]]:1: ERROR: Redefinition of `class C`. +// CHECK:STDERR: class C {} +// CHECK:STDERR: ^~~~~~~~~ +// CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE-5]]:1: In import. +// CHECK:STDERR: library "redef_after_def" impl; +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: redef_after_def.carbon:4:1: Previously defined here. +// CHECK:STDERR: class C {} +// CHECK:STDERR: ^~~~~~~~~ +// CHECK:STDERR: +class C {} + +// --- def_alias.carbon + +library "def_alias" api; + +class C; +alias B = C; + +// --- fail_def_alias.impl.carbon + +library "def_alias" impl; + +// CHECK:STDERR: fail_def_alias.impl.carbon:[[@LINE+9]]:1: ERROR: Duplicate name being declared in the same scope. +// CHECK:STDERR: class B {} +// CHECK:STDERR: ^~~~~~~~~ +// CHECK:STDERR: fail_def_alias.impl.carbon:[[@LINE-5]]:1: In import. +// CHECK:STDERR: library "def_alias" impl; +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: def_alias.carbon:5:7: Name is previously declared here. +// CHECK:STDERR: alias B = C; +// CHECK:STDERR: ^ +class B {} + +// CHECK:STDOUT: --- basic.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C; +// CHECK:STDOUT: +// CHECK:STDOUT: --- basic.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref: type = import_ref ir0, inst+1, loaded [template = constants.%C] +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- redecl_after_def.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_redecl_after_def.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: type = import_ref ir0, inst+1, loaded [template = constants.%C] +// CHECK:STDOUT: %import_ref.2 = import_ref ir0, inst+2, unloaded +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = file.%import_ref.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- redef_after_def.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_redef_after_def.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: type = import_ref ir0, inst+1, loaded [template = constants.%C] +// CHECK:STDOUT: %import_ref.2 = import_ref ir0, inst+2, unloaded +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- def_alias.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .B = %B +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} +// CHECK:STDOUT: %C.ref: type = name_ref C, %C.decl [template = constants.%C] +// CHECK:STDOUT: %B: type = bind_alias B, %C.decl [template = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C; +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_def_alias.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [template] +// CHECK:STDOUT: %.1: type = class_type @.1 [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .C = %import_ref.1 +// CHECK:STDOUT: .B = %import_ref.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1 = import_ref ir0, inst+1, unloaded +// CHECK:STDOUT: %import_ref.2: type = import_ref ir0, inst+4, loaded [template = constants.%C] +// CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.1] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C; +// CHECK:STDOUT: +// CHECK:STDOUT: class @.1 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/definition/no_prelude/implicit_import.carbon b/toolchain/check/testdata/function/definition/no_prelude/implicit_import.carbon index 68dfe37fd85e..2725e8d7601c 100644 --- a/toolchain/check/testdata/function/definition/no_prelude/implicit_import.carbon +++ b/toolchain/check/testdata/function/definition/no_prelude/implicit_import.carbon @@ -86,7 +86,7 @@ fn A() {} library "redef_after_def" impl; -// CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE+9]]:1: ERROR: Redefinition of `fn A`. +// CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE+10]]:1: ERROR: Redefinition of `fn A`. // CHECK:STDERR: fn A() {} // CHECK:STDERR: ^~~~~~~~ // CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE-5]]:1: In import. @@ -95,8 +95,31 @@ library "redef_after_def" impl; // CHECK:STDERR: redef_after_def.carbon:4:1: Previously defined here. // CHECK:STDERR: fn A() {} // CHECK:STDERR: ^~~~~~~~ +// CHECK:STDERR: fn A() {} +// --- def_alias.carbon + +library "def_alias" api; + +fn A(); +alias B = A; + +// --- fail_def_alias.impl.carbon + +library "def_alias" impl; + +// CHECK:STDERR: fail_def_alias.impl.carbon:[[@LINE+9]]:1: ERROR: Duplicate name being declared in the same scope. +// CHECK:STDERR: fn B() {} +// CHECK:STDERR: ^~~~~~~~ +// CHECK:STDERR: fail_def_alias.impl.carbon:[[@LINE-5]]:1: In import. +// CHECK:STDERR: library "def_alias" impl; +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: def_alias.carbon:5:7: Name is previously declared here. +// CHECK:STDERR: alias B = A; +// CHECK:STDERR: ^ +fn B() {} + // CHECK:STDOUT: --- basic.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -290,3 +313,50 @@ fn A() {} // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- def_alias.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %A: type = fn_type @A [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct: A = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .A = %A.decl +// CHECK:STDOUT: .B = %B +// CHECK:STDOUT: } +// CHECK:STDOUT: %A.decl: A = fn_decl @A [template = constants.%struct] {} +// CHECK:STDOUT: %A.ref: A = name_ref A, %A.decl [template = constants.%struct] +// CHECK:STDOUT: %B: A = bind_alias B, %A.decl [template = constants.%struct] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @A(); +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_def_alias.impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %A: type = fn_type @A [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct.1: A = struct_value () [template] +// CHECK:STDOUT: %.2: type = fn_type @.1 [template] +// CHECK:STDOUT: %struct.2: = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .A = %import_ref.1 +// CHECK:STDOUT: .B = %import_ref.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1 = import_ref ir0, inst+1, unloaded +// CHECK:STDOUT: %import_ref.2: A = import_ref ir0, inst+6, loaded [template = constants.%struct.1] +// CHECK:STDOUT: %.decl: = fn_decl @.1 [template = constants.%struct.2] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @A(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: