From 7792e5fce35a414c4f38c5f5f50f9aa36f7cf0dc Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 5 Jun 2024 11:52:17 -0700 Subject: [PATCH] Support out-of-line definitions of members of generic classes and interfaces. (#4029) Check the parameters specified in a name qualifier against the parameters of the entity that the qualifier refers to. For interfaces, this required adding minimal support for parameterized interface names. --------- Co-authored-by: Jon Ross-Perkins --- toolchain/check/decl_name_stack.cpp | 325 +++++++------- toolchain/check/decl_name_stack.h | 25 +- toolchain/check/handle_class.cpp | 2 +- toolchain/check/handle_interface.cpp | 29 +- toolchain/check/handle_namespace.cpp | 16 +- toolchain/check/import_ref.cpp | 24 +- toolchain/check/merge.cpp | 20 +- toolchain/check/merge.h | 15 +- .../testdata/class/fail_generic_method.carbon | 105 +++++ .../fail_todo_member_out_of_line.carbon | 75 ---- .../class/generic/member_out_of_line.carbon | 412 ++++++++++++++++++ ...ic_method.carbon => generic_method.carbon} | 23 +- .../impl/fail_extend_impl_forall.carbon | 34 +- .../fail_generic_redeclaration.carbon | 114 +++++ .../fail_todo_generic_default_fn.carbon | 90 ++++ ...ail_todo_generic.carbon => generic.carbon} | 21 +- .../testdata/namespace/fail_params.carbon | 35 +- .../no_prelude/cross_package_import.carbon | 50 ++- toolchain/sem_ir/interface.h | 4 + 19 files changed, 1096 insertions(+), 323 deletions(-) create mode 100644 toolchain/check/testdata/class/fail_generic_method.carbon delete mode 100644 toolchain/check/testdata/class/generic/fail_todo_member_out_of_line.carbon create mode 100644 toolchain/check/testdata/class/generic/member_out_of_line.carbon rename toolchain/check/testdata/class/{fail_todo_generic_method.carbon => generic_method.carbon} (79%) create mode 100644 toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon create mode 100644 toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon rename toolchain/check/testdata/interface/no_prelude/{fail_todo_generic.carbon => generic.carbon} (51%) diff --git a/toolchain/check/decl_name_stack.cpp b/toolchain/check/decl_name_stack.cpp index b845c1415ffe..1648d6588235 100644 --- a/toolchain/check/decl_name_stack.cpp +++ b/toolchain/check/decl_name_stack.cpp @@ -7,6 +7,8 @@ #include "toolchain/base/kind_switch.h" #include "toolchain/check/context.h" #include "toolchain/check/diagnostic_helpers.h" +#include "toolchain/check/merge.h" +#include "toolchain/check/name_component.h" #include "toolchain/diagnostics/diagnostic.h" #include "toolchain/sem_ir/ids.h" @@ -24,7 +26,6 @@ auto DeclNameStack::NameContext::prev_inst_id() -> SemIR::InstId { "that may change based on error handling)."; case NameContext::State::Resolved: - case NameContext::State::ResolvedNonScope: return resolved_inst_id; case NameContext::State::Unresolved: @@ -44,7 +45,7 @@ auto DeclNameStack::MakeEmptyNameContext() -> NameContext { auto DeclNameStack::MakeUnqualifiedName(SemIR::LocId loc_id, SemIR::NameId name_id) -> NameContext { NameContext context = MakeEmptyNameContext(); - ApplyAndLookupName(context, loc_id, name_id, /*is_unqualified=*/true); + ApplyAndLookupName(context, loc_id, name_id); return context; } @@ -59,8 +60,7 @@ auto DeclNameStack::FinishName(const NameComponent& name) -> NameContext { CARBON_CHECK(decl_name_stack_.back().state != NameContext::State::Finished) << "Finished name twice"; - ApplyAndLookupName(decl_name_stack_.back(), name.name_loc_id, name.name_id, - /*is_unqualified=*/false); + ApplyAndLookupName(decl_name_stack_.back(), name.name_loc_id, name.name_id); NameContext result = decl_name_stack_.back(); decl_name_stack_.back().state = NameContext::State::Finished; @@ -179,24 +179,43 @@ auto DeclNameStack::LookupOrAddName(NameContext name_context, return SemIR::InstId::Invalid; } -auto DeclNameStack::ApplyNameQualifier(const NameComponent& name) -> void { - if (name.implicit_params_id.is_valid() || name.params_id.is_valid()) { - context_->TODO(name.params_loc_id, "name qualifier with parameters"); - } +// Push a scope corresponding to a name qualifier. For example, for +// `fn Class(T:! type).F(n: i32)` we will push the scope for `Class(T:! type)` +// between the scope containing the declaration of `T` and the scope +// containing the declaration of `n`. +static auto PushNameQualifierScope(Context& context, + SemIR::InstId scope_inst_id, + SemIR::NameScopeId scope_id, + bool has_error = false) -> void { + // If the qualifier has no parameters, we don't need to keep around a + // parameter scope. + context.scope_stack().PopIfEmpty(); + context.scope_stack().Push(scope_inst_id, scope_id, has_error); + + // Enter a parameter scope in case the qualified name itself has parameters. + context.scope_stack().Push(); +} + +auto DeclNameStack::ApplyNameQualifier(const NameComponent& name) -> void { auto& name_context = decl_name_stack_.back(); - ApplyAndLookupName(name_context, name.name_loc_id, name.name_id, - /*is_unqualified=*/false); + ApplyAndLookupName(name_context, name.name_loc_id, name.name_id); name_context.has_qualifiers = true; - if (!CheckValidAsQualifier(name_context)) { + + // Resolve the qualifier as a scope and enter the new scope. + auto scope_id = ResolveAsScope(name_context, name); + if (scope_id.is_valid()) { + PushNameQualifierScope(*context_, name_context.resolved_inst_id, scope_id, + context_->name_scopes().Get(scope_id).has_error); + name_context.parent_scope_id = scope_id; + } else { name_context.state = NameContext::State::Error; } } auto DeclNameStack::ApplyAndLookupName(NameContext& name_context, SemIR::LocId loc_id, - SemIR::NameId name_id, - bool is_unqualified) -> void { + SemIR::NameId name_id) -> void { // The location of the name is the location of the last name token we've // processed so far. name_context.loc_id = loc_id; @@ -215,165 +234,167 @@ auto DeclNameStack::ApplyAndLookupName(NameContext& name_context, // Invalid indicates an unresolved name. Store it and return. name_context.unresolved_name_id = name_id; name_context.state = NameContext::State::Unresolved; - return; } else { // Store the resolved instruction and continue for the target scope // update. name_context.resolved_inst_id = resolved_inst_id; + name_context.state = NameContext::State::Resolved; + } +} + +// Checks and returns whether name_context, which is used as a name qualifier, +// was successfully resolved. Issues a suitable diagnostic if not. +static auto CheckQualifierIsResolved( + Context& context, const DeclNameStack::NameContext& name_context) -> bool { + switch (name_context.state) { + case DeclNameStack::NameContext::State::Empty: + CARBON_FATAL() << "No qualifier to resolve"; + + case DeclNameStack::NameContext::State::Resolved: + return true; + + case DeclNameStack::NameContext::State::Unresolved: + // Because more qualifiers were found, we diagnose that the earlier + // qualifier failed to resolve. + context.DiagnoseNameNotFound(name_context.loc_id, + name_context.unresolved_name_id); + return false; + + case DeclNameStack::NameContext::State::Finished: + CARBON_FATAL() << "Added a qualifier after calling FinishName"; + + case DeclNameStack::NameContext::State::Error: + // Already in an error state, so return without examining. + return false; + } +} + +// Diagnose that a qualified declaration name specifies an incomplete class as +// its scope. +static auto DiagnoseQualifiedDeclInIncompleteClassScope(Context& context, + SemIRLoc loc, + SemIR::ClassId class_id) + -> void { + CARBON_DIAGNOSTIC(QualifiedDeclInIncompleteClassScope, Error, + "Cannot declare a member of incomplete class `{0}`.", + SemIR::TypeId); + auto builder = + context.emitter().Build(loc, QualifiedDeclInIncompleteClassScope, + context.classes().Get(class_id).self_type_id); + context.NoteIncompleteClass(class_id, builder); + builder.Emit(); +} + +// Diagnose that a qualified declaration name specifies an undefined interface +// as its scope. +static auto DiagnoseQualifiedDeclInUndefinedInterfaceScope( + Context& context, SemIRLoc loc, SemIR::InterfaceId interface_id, + SemIR::InstId interface_inst_id) -> void { + CARBON_DIAGNOSTIC(QualifiedDeclInUndefinedInterfaceScope, Error, + "Cannot declare a member of undefined interface `{0}`.", + std::string); + auto builder = context.emitter().Build( + loc, QualifiedDeclInUndefinedInterfaceScope, + context.sem_ir().StringifyTypeExpr( + context.sem_ir().constant_values().Get(interface_inst_id).inst_id())); + context.NoteUndefinedInterface(interface_id, builder); + builder.Emit(); +} + +// Diagnose that a qualified declaration name specifies a different package as +// its scope. +static auto DiagnoseQualifiedDeclInImportedPackage(Context& context, + SemIRLoc use_loc, + SemIRLoc import_loc) + -> void { + CARBON_DIAGNOSTIC(QualifiedDeclOutsidePackage, Error, + "Imported packages cannot be used for declarations."); + CARBON_DIAGNOSTIC(QualifiedDeclOutsidePackageSource, Note, + "Package imported here."); + context.emitter() + .Build(use_loc, QualifiedDeclOutsidePackage) + .Note(import_loc, QualifiedDeclOutsidePackageSource) + .Emit(); +} + +// Diagnose that a qualified declaration name specifies a non-scope entity as +// its scope. +static auto DiagnoseQualifiedDeclInNonScope(Context& context, SemIRLoc use_loc, + SemIRLoc non_scope_entity_loc) + -> void { + CARBON_DIAGNOSTIC(QualifiedNameInNonScope, Error, + "Name qualifiers are only allowed for entities that " + "provide a scope."); + CARBON_DIAGNOSTIC(QualifiedNameNonScopeEntity, Note, + "Referenced non-scope entity declared here."); + context.emitter() + .Build(use_loc, QualifiedNameInNonScope) + .Note(non_scope_entity_loc, QualifiedNameNonScopeEntity) + .Emit(); +} + +auto DeclNameStack::ResolveAsScope(const NameContext& name_context, + const NameComponent& name) const + -> SemIR::NameScopeId { + if (!CheckQualifierIsResolved(*context_, name_context)) { + return SemIR::NameScopeId::Invalid; } - // Enter the scope of the existing entity. - UpdateScopeIfNeeded(name_context, is_unqualified); -} + auto new_params = + DeclParams(name.name_loc_id, name.implicit_params_id, name.params_id); -// Push a scope corresponding to a name qualifier. For example, for -// -// fn Class(T:! type).F(n: i32) -// -// we will push the scope for `Class(T:! type)` between the scope containing the -// declaration of `T` and the scope containing the declaration of `n`. -static auto PushNameQualifierScope(Context& context, - SemIR::InstId scope_inst_id, - SemIR::NameScopeId scope_id, - bool has_error = false) -> void { - // If the qualifier has no parameters, we don't need to keep around a - // parameter scope. - context.scope_stack().PopIfEmpty(); - - context.scope_stack().Push(scope_inst_id, scope_id, has_error); - - // Enter a parameter scope in case the qualified name itself has parameters. - context.scope_stack().Push(); -} - -auto DeclNameStack::UpdateScopeIfNeeded(NameContext& name_context, - bool is_unqualified) -> void { - // This will only be reached for resolved instructions. We update the target - // scope based on the resolved type. + // Find the scope corresponding to the resolved instruction. CARBON_KIND_SWITCH(context_->insts().Get(name_context.resolved_inst_id)) { - case CARBON_KIND(SemIR::ClassDecl resolved_inst): { - const auto& class_info = context_->classes().Get(resolved_inst.class_id); - if (class_info.is_defined()) { - name_context.state = NameContext::State::Resolved; - name_context.parent_scope_id = class_info.scope_id; - if (!is_unqualified) { - PushNameQualifierScope(*context_, name_context.resolved_inst_id, - class_info.scope_id); - } - } else { - name_context.state = NameContext::State::ResolvedNonScope; + case CARBON_KIND(SemIR::ClassDecl class_decl): { + const auto& class_info = context_->classes().Get(class_decl.class_id); + if (!CheckRedeclParamsMatch(*context_, new_params, + DeclParams(class_info))) { + return SemIR::NameScopeId::Invalid; } - break; + if (!class_info.is_defined()) { + DiagnoseQualifiedDeclInIncompleteClassScope( + *context_, name_context.loc_id, class_decl.class_id); + return SemIR::NameScopeId::Invalid; + } + return class_info.scope_id; } - case CARBON_KIND(SemIR::InterfaceDecl resolved_inst): { + case CARBON_KIND(SemIR::InterfaceDecl interface_decl): { const auto& interface_info = - context_->interfaces().Get(resolved_inst.interface_id); - if (interface_info.is_defined()) { - name_context.state = NameContext::State::Resolved; - name_context.parent_scope_id = interface_info.scope_id; - if (!is_unqualified) { - PushNameQualifierScope(*context_, name_context.resolved_inst_id, - interface_info.scope_id); - } - } else { - name_context.state = NameContext::State::ResolvedNonScope; + context_->interfaces().Get(interface_decl.interface_id); + if (!CheckRedeclParamsMatch(*context_, new_params, + DeclParams(interface_info))) { + return SemIR::NameScopeId::Invalid; } - break; + if (!interface_info.is_defined()) { + DiagnoseQualifiedDeclInUndefinedInterfaceScope( + *context_, name_context.loc_id, interface_decl.interface_id, + name_context.resolved_inst_id); + return SemIR::NameScopeId::Invalid; + } + return interface_info.scope_id; } case CARBON_KIND(SemIR::Namespace resolved_inst): { auto scope_id = resolved_inst.name_scope_id; - name_context.state = NameContext::State::Resolved; - name_context.parent_scope_id = scope_id; auto& scope = context_->name_scopes().Get(scope_id); + if (!CheckRedeclParamsMatch(*context_, new_params, + DeclParams(name_context.resolved_inst_id, + SemIR::InstBlockId::Invalid, + SemIR::InstBlockId::Invalid))) { + return SemIR::NameScopeId::Invalid; + } if (scope.is_closed_import) { - CARBON_DIAGNOSTIC(QualifiedDeclOutsidePackage, Error, - "Imported packages cannot be used for declarations."); - CARBON_DIAGNOSTIC(QualifiedDeclOutsidePackageSource, Note, - "Package imported here."); - context_->emitter() - .Build(name_context.loc_id, QualifiedDeclOutsidePackage) - .Note(scope.inst_id, QualifiedDeclOutsidePackageSource) - .Emit(); - // Only error once per package. + DiagnoseQualifiedDeclInImportedPackage(*context_, name_context.loc_id, + scope.inst_id); + // Only error once per package. Recover by allowing this package name to + // be used as a name qualifier. scope.is_closed_import = false; } - if (!is_unqualified) { - PushNameQualifierScope(*context_, name_context.resolved_inst_id, - scope_id, - context_->name_scopes().Get(scope_id).has_error); - } - break; + return scope_id; } - default: - name_context.state = NameContext::State::ResolvedNonScope; - break; - } -} - -auto DeclNameStack::CheckValidAsQualifier(const NameContext& name_context) - -> bool { - switch (name_context.state) { - case NameContext::State::Error: - // Already in an error state, so return without examining. - return false; - - case NameContext::State::Resolved: - return true; - - case NameContext::State::Empty: - CARBON_FATAL() << "No qualifier to resolve"; - - case NameContext::State::Finished: - CARBON_FATAL() << "Added a qualifier after calling FinishName"; - - case NameContext::State::Unresolved: - // Because more qualifiers were found, we diagnose that the earlier - // qualifier failed to resolve. - context_->DiagnoseNameNotFound(name_context.loc_id, - name_context.unresolved_name_id); - return false; - - case NameContext::State::ResolvedNonScope: { - // Because more qualifiers were found, we diagnose that the earlier - // qualifier didn't resolve to a scoped entity. - if (auto class_decl = context_->insts().TryGetAs( - name_context.resolved_inst_id)) { - CARBON_DIAGNOSTIC(QualifiedDeclInIncompleteClassScope, Error, - "Cannot declare a member of incomplete class `{0}`.", - SemIR::TypeId); - auto builder = context_->emitter().Build( - name_context.loc_id, QualifiedDeclInIncompleteClassScope, - context_->classes().Get(class_decl->class_id).self_type_id); - context_->NoteIncompleteClass(class_decl->class_id, builder); - builder.Emit(); - } else if (auto interface_decl = - context_->insts().TryGetAs( - name_context.resolved_inst_id)) { - CARBON_DIAGNOSTIC( - QualifiedDeclInUndefinedInterfaceScope, Error, - "Cannot declare a member of undefined interface `{0}`.", - std::string); - auto builder = context_->emitter().Build( - name_context.loc_id, QualifiedDeclInUndefinedInterfaceScope, - context_->sem_ir().StringifyTypeExpr( - context_->sem_ir() - .constant_values() - .Get(name_context.resolved_inst_id) - .inst_id())); - context_->NoteUndefinedInterface(interface_decl->interface_id, builder); - builder.Emit(); - } else { - CARBON_DIAGNOSTIC(QualifiedNameInNonScope, Error, - "Name qualifiers are only allowed for entities that " - "provide a scope."); - CARBON_DIAGNOSTIC(QualifiedNameNonScopeEntity, Note, - "Referenced non-scope entity declared here."); - context_->emitter() - .Build(name_context.loc_id, QualifiedNameInNonScope) - .Note(name_context.resolved_inst_id, QualifiedNameNonScopeEntity) - .Emit(); - } - return false; + default: { + DiagnoseQualifiedDeclInNonScope(*context_, name_context.loc_id, + name_context.resolved_inst_id); + return SemIR::NameScopeId::Invalid; } } } diff --git a/toolchain/check/decl_name_stack.h b/toolchain/check/decl_name_stack.h index be8ac0e02b32..8daef64e361a 100644 --- a/toolchain/check/decl_name_stack.h +++ b/toolchain/check/decl_name_stack.h @@ -70,15 +70,9 @@ class DeclNameStack { // A context that has not processed any parts of the qualifier. Empty, - // An instruction ID has been resolved, whether through an identifier or - // expression. This provided a new scope, such as a type. + // The name has been resolved to an instruction ID. Resolved, - // An instruction ID has been resolved, whether through an identifier or - // expression. It did not provide a new scope, so must be the final part, - // such as an out-of-line function definition. - ResolvedNonScope, - // An identifier didn't resolve. Unresolved, @@ -231,18 +225,13 @@ class DeclNameStack { // Appends a name to the given name context, and performs a lookup to find // what, if anything, the name refers to. auto ApplyAndLookupName(NameContext& name_context, SemIR::LocId loc_id, - SemIR::NameId name_id, bool is_unqualified) -> void; + SemIR::NameId name_id) -> void; - // Checks and returns whether the given name context can be used as a - // qualifier. A suitable diagnostic is issued if not. - auto CheckValidAsQualifier(const NameContext& name_context) -> bool; - - // Updates the scope on name_context as needed. This is called after - // resolution is complete, whether for Name or expression. When updating for - // an unqualified name, the resolution is noted without pushing scopes; it's - // instead expected this will become a name conflict. - auto UpdateScopeIfNeeded(NameContext& name_context, bool is_unqualified) - -> void; + // Attempts to resolve the given name context as a scope, and returns the + // corresponding scope. Issues a suitable diagnostic and returns Invalid if + // the name doesn't resolve to a scope. + auto ResolveAsScope(const NameContext& name_context, + const NameComponent& name) const -> SemIR::NameScopeId; // The linked context. Context* context_; diff --git a/toolchain/check/handle_class.cpp b/toolchain/check/handle_class.cpp index 7b92449b9eeb..da2f8316d1ae 100644 --- a/toolchain/check/handle_class.cpp +++ b/toolchain/check/handle_class.cpp @@ -58,7 +58,7 @@ static auto MergeClassRedecl(Context& context, SemIRLoc new_loc, // Check the generic parameters match, if they were specified. if (!CheckRedeclParamsMatch(context, DeclParams(new_class), - DeclParams(prev_class), {})) { + DeclParams(prev_class))) { return false; } diff --git a/toolchain/check/handle_interface.cpp b/toolchain/check/handle_interface.cpp index 03d8f20cfefe..91d4c792520f 100644 --- a/toolchain/check/handle_interface.cpp +++ b/toolchain/check/handle_interface.cpp @@ -5,6 +5,7 @@ #include "toolchain/check/context.h" #include "toolchain/check/handle.h" #include "toolchain/check/interface.h" +#include "toolchain/check/merge.h" #include "toolchain/check/modifiers.h" #include "toolchain/check/name_component.h" #include "toolchain/sem_ir/typed_insts.h" @@ -28,10 +29,6 @@ static auto BuildInterfaceDecl(Context& context, Parse::AnyInterfaceDeclId node_id) -> std::tuple { auto name = PopNameComponent(context); - if (name.params_id.is_valid() || name.implicit_params_id.is_valid()) { - context.TODO(node_id, "generic interface"); - } - auto name_context = context.decl_name_stack().FinishName(name); context.node_stack() .PopAndDiscardSoloNodeId(); @@ -63,11 +60,20 @@ static auto BuildInterfaceDecl(Context& context, if (existing_id.is_valid()) { if (auto existing_interface_decl = context.insts().Get(existing_id).TryAs()) { - // This is a redeclaration of an existing interface. - interface_decl.interface_id = existing_interface_decl->interface_id; - - // TODO: Check that the generic parameter list agrees with the prior - // declaration. + // TODO: Implement full redeclaration checking. See `MergeClassDecl`. For + // now we just check the generic parameters match. + if (CheckRedeclParamsMatch( + context, + DeclParams(interface_decl_id, name.implicit_params_id, + name.params_id), + DeclParams(context.interfaces().Get( + existing_interface_decl->interface_id)))) { + // This is a redeclaration of an existing interface. + interface_decl.interface_id = existing_interface_decl->interface_id; + // TODO: If the new declaration is a definition, keep its parameter + // and implicit parameter lists rather than the ones from the + // previous declaration. + } } else { // This is a redeclaration of something other than a interface. context.DiagnoseDuplicateName(interface_decl_id, existing_id); @@ -83,9 +89,14 @@ static auto BuildInterfaceDecl(Context& context, interface_decl.interface_id = context.interfaces().Add( {.name_id = name_context.name_id_for_new_inst(), .parent_scope_id = name_context.parent_scope_id_for_new_inst(), + .implicit_param_refs_id = name.implicit_params_id, + .param_refs_id = name.params_id, .decl_id = interface_decl_id}); } + // TODO: For a generic interface declaration, set the `type_id` to a suitable + // generic interface type rather than `type`. + // Write the interface ID into the InterfaceDecl. context.ReplaceInstBeforeConstantUse(interface_decl_id, interface_decl); diff --git a/toolchain/check/handle_namespace.cpp b/toolchain/check/handle_namespace.cpp index 9d5efc9b924d..004d26536447 100644 --- a/toolchain/check/handle_namespace.cpp +++ b/toolchain/check/handle_namespace.cpp @@ -45,10 +45,18 @@ auto HandleNamespace(Context& context, Parse::NamespaceId node_id) -> bool { // previous declaration. Otherwise, diagnose the issue. if (auto existing = context.insts().TryGetAs(existing_inst_id)) { - // When the name conflict is an imported namespace, fill the location ID - // so that future diagnostics point at this declaration. - if (existing->import_id.is_valid() && - !context.insts().GetLocId(existing_inst_id).is_valid()) { + if (context.name_scopes().Get(existing->name_scope_id).is_closed_import) { + // The existing name is a package name, so this is a name conflict. + context.DiagnoseDuplicateName(namespace_id, existing_inst_id); + + // Treat this as a local namespace name from now on to avoid further + // diagnostics. + context.name_scopes().Get(existing->name_scope_id).is_closed_import = + false; + } else if (existing->import_id.is_valid() && + !context.insts().GetLocId(existing_inst_id).is_valid()) { + // When the name conflict is an imported namespace, fill the location ID + // so that future diagnostics point at this declaration. context.SetNamespaceNodeId(existing_inst_id, node_id); } } else { diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 45e628c99195..b6d8670ec65a 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -832,6 +832,9 @@ class ImportRefResolver { auto TryResolveTypedInst(SemIR::ClassDecl inst, SemIR::ConstantId class_const_id) -> ResolveResult { + // TODO: The handling of interfaces repeats a lot with the handling of + // classes, and will likely also be repeated for named constraints and + // choice types. Factor out some of this functionality. const auto& import_class = import_ir_.classes().Get(inst.class_id); SemIR::ClassId class_id = SemIR::ClassId::Invalid; @@ -1070,8 +1073,19 @@ class ImportRefResolver { // Start with an incomplete interface. SemIR::Interface new_interface = { .name_id = GetLocalNameId(import_interface.name_id), - // Set in the second pass once we've imported it. + // These are set in the second pass once we've imported them. Import + // enough of the parameter lists that we know whether this interface is + // a generic interface and can build the right constant value for it. + // TODO: Add a better way to represent a generic `Interface` prior to + // importing the parameters. .parent_scope_id = SemIR::NameScopeId::Invalid, + .implicit_param_refs_id = + import_interface.implicit_param_refs_id.is_valid() + ? SemIR::InstBlockId::Empty + : SemIR::InstBlockId::Invalid, + .param_refs_id = import_interface.param_refs_id.is_valid() + ? SemIR::InstBlockId::Empty + : SemIR::InstBlockId::Invalid, .decl_id = interface_decl_id, }; @@ -1122,6 +1136,10 @@ class ImportRefResolver { auto parent_scope_id = GetLocalNameScopeId(import_interface.parent_scope_id); + llvm::SmallVector implicit_param_const_ids = + GetLocalParamConstantIds(import_interface.implicit_param_refs_id); + llvm::SmallVector param_const_ids = + GetLocalParamConstantIds(import_interface.param_refs_id); auto self_param_id = GetLocalConstantId(import_interface.self_param_id); if (HasNewWork(initial_work)) { @@ -1133,6 +1151,10 @@ class ImportRefResolver { .GetAs(interface_const_id.inst_id()) .interface_id); new_interface.parent_scope_id = parent_scope_id; + new_interface.implicit_param_refs_id = GetLocalParamRefsId( + import_interface.implicit_param_refs_id, implicit_param_const_ids); + new_interface.param_refs_id = + GetLocalParamRefsId(import_interface.param_refs_id, param_const_ids); if (import_interface.is_defined()) { AddInterfaceDefinition(import_interface, new_interface, self_param_id); diff --git a/toolchain/check/merge.cpp b/toolchain/check/merge.cpp index 7e9ea126fa32..9df43ebfb7bf 100644 --- a/toolchain/check/merge.cpp +++ b/toolchain/check/merge.cpp @@ -210,9 +210,9 @@ static auto CheckRedeclParam(Context& context, } // Returns false if the param refs differ for a redeclaration. -static auto CheckRedeclParams(Context& context, SemIR::InstId new_decl_id, +static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc, SemIR::InstBlockId new_param_refs_id, - SemIR::InstId prev_decl_id, + SemIRLoc prev_decl_loc, SemIR::InstBlockId prev_param_refs_id, llvm::StringLiteral param_diag_label, Substitutions substitutions) -> bool { @@ -231,9 +231,9 @@ static auto CheckRedeclParams(Context& context, SemIR::InstId new_decl_id, llvm::StringLiteral, llvm::StringLiteral); context.emitter() .Build( - new_decl_id, RedeclParamListDiffers, param_diag_label, + new_decl_loc, RedeclParamListDiffers, param_diag_label, new_param_refs_id.is_valid() ? llvm::StringLiteral("") : "missing ") - .Note(prev_decl_id, RedeclParamListPrevious, param_diag_label, + .Note(prev_decl_loc, RedeclParamListPrevious, param_diag_label, prev_param_refs_id.is_valid() ? llvm::StringLiteral("") : "out") .Emit(); return false; @@ -251,9 +251,9 @@ static auto CheckRedeclParams(Context& context, SemIR::InstId new_decl_id, "Previously declared with {0}parameter count of {1}.", llvm::StringLiteral, int32_t); context.emitter() - .Build(new_decl_id, RedeclParamCountDiffers, param_diag_label, + .Build(new_decl_loc, RedeclParamCountDiffers, param_diag_label, new_param_ref_ids.size()) - .Note(prev_decl_id, RedeclParamCountPrevious, param_diag_label, + .Note(prev_decl_loc, RedeclParamCountPrevious, param_diag_label, prev_param_ref_ids.size()) .Emit(); return false; @@ -275,12 +275,12 @@ auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity, EntityHasParamError(context, prev_entity)) { return false; } - if (!CheckRedeclParams(context, new_entity.decl_id, - new_entity.implicit_param_refs_id, prev_entity.decl_id, + if (!CheckRedeclParams(context, new_entity.loc, + new_entity.implicit_param_refs_id, prev_entity.loc, prev_entity.implicit_param_refs_id, "implicit ", substitutions) || - !CheckRedeclParams(context, new_entity.decl_id, new_entity.param_refs_id, - prev_entity.decl_id, prev_entity.param_refs_id, "", + !CheckRedeclParams(context, new_entity.loc, new_entity.param_refs_id, + prev_entity.loc, prev_entity.param_refs_id, "", substitutions)) { return false; } diff --git a/toolchain/check/merge.h b/toolchain/check/merge.h index 35191ab2e926..d7a96b9a94d8 100644 --- a/toolchain/check/merge.h +++ b/toolchain/check/merge.h @@ -46,12 +46,18 @@ auto ReplacePrevInstForMerge(Context& context, SemIR::NameScopeId scope_id, struct DeclParams { template explicit DeclParams(const Entity& entity) - : decl_id(entity.decl_id), + : loc(entity.decl_id), implicit_param_refs_id(entity.implicit_param_refs_id), param_refs_id(entity.param_refs_id) {} - // The declaration of the entity. - SemIR::InstId decl_id; + DeclParams(SemIRLoc loc, SemIR::InstBlockId implicit_params_id, + SemIR::InstBlockId params_id) + : loc(loc), + implicit_param_refs_id(implicit_params_id), + param_refs_id(params_id) {} + + // The location of the declaration of the entity. + SemIRLoc loc; // The implicit parameters of the entity. Can be Invalid if there is no // implicit parameter list. SemIR::InstBlockId implicit_param_refs_id; @@ -65,7 +71,8 @@ struct DeclParams { // returns false. auto CheckRedeclParamsMatch(Context& context, const DeclParams& new_entity, const DeclParams& prev_entity, - Substitutions substitutions) -> bool; + Substitutions substitutions = Substitutions()) + -> bool; } // namespace Carbon::Check diff --git a/toolchain/check/testdata/class/fail_generic_method.carbon b/toolchain/check/testdata/class/fail_generic_method.carbon new file mode 100644 index 000000000000..6f603165cd7b --- /dev/null +++ b/toolchain/check/testdata/class/fail_generic_method.carbon @@ -0,0 +1,105 @@ +// 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 +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/fail_generic_method.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_generic_method.carbon + +class Class(T:! type) { + var a: T; + fn F[self: Self](n: T); +} + +// TODO: The follow-on errors here aren't great. Investigate whether we can +// enter the scope anyway if the parameters don't match. +// CHECK:STDERR: fail_generic_method.carbon:[[@LINE+14]]:10: ERROR: Redeclaration differs at parameter 1. +// CHECK:STDERR: fn Class(N:! i32).F[self: Self](n: T) {} +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_generic_method.carbon:[[@LINE-10]]:13: Previous declaration's corresponding parameter here. +// CHECK:STDERR: class Class(T:! type) { +// CHECK:STDERR: ^ +// CHECK:STDERR: +// CHECK:STDERR: fail_generic_method.carbon:[[@LINE+7]]:27: ERROR: Name `Self` not found. +// CHECK:STDERR: fn Class(N:! i32).F[self: Self](n: T) {} +// CHECK:STDERR: ^~~~ +// CHECK:STDERR: +// CHECK:STDERR: fail_generic_method.carbon:[[@LINE+3]]:36: ERROR: Name `T` not found. +// CHECK:STDERR: fn Class(N:! i32).F[self: Self](n: T) {} +// CHECK:STDERR: ^ +fn Class(N:! i32).F[self: Self](n: T) {} + +// CHECK:STDOUT: --- fail_generic_method.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct.1: Class = struct_value () [template] +// CHECK:STDOUT: %Class.2: type = class_type @Class [template] +// CHECK:STDOUT: %.2: type = unbound_element_type Class, T [symbolic] +// CHECK:STDOUT: %F: type = fn_type @F [template] +// CHECK:STDOUT: %struct.2: F = struct_value () [template] +// CHECK:STDOUT: %.3: type = struct_type {.a: T} [symbolic] +// CHECK:STDOUT: %Int32: type = fn_type @Int32 [template] +// CHECK:STDOUT: %struct.3: Int32 = struct_value () [template] +// CHECK:STDOUT: %N: i32 = bind_symbolic_name N 0 [symbolic] +// CHECK:STDOUT: %.4: type = fn_type @.1 [template] +// CHECK:STDOUT: %struct.4: = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Class = %Class.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct.1] { +// CHECK:STDOUT: %T.loc11_13.1: type = param T +// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T] +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref: Int32 = import_ref ir3, inst+3, loaded [template = constants.%struct.3] +// CHECK:STDOUT: %.decl: = fn_decl @.1 [template = constants.%struct.4] { +// CHECK:STDOUT: %int.make_type_32: init type = call constants.%struct.3() [template = i32] +// CHECK:STDOUT: %.loc32_14.1: type = value_of_initializer %int.make_type_32 [template = i32] +// CHECK:STDOUT: %.loc32_14.2: type = converted %int.make_type_32, %.loc32_14.1 [template = i32] +// CHECK:STDOUT: %N.loc32_10.1: i32 = param N +// CHECK:STDOUT: %N.loc32_10.2: i32 = bind_symbolic_name N 0, %N.loc32_10.1 [symbolic = constants.%N] +// CHECK:STDOUT: %Self.ref: = name_ref Self, [template = ] +// CHECK:STDOUT: %self.loc32_21.1: = param self +// CHECK:STDOUT: @.1.%self: = bind_name self, %self.loc32_21.1 +// CHECK:STDOUT: %T.ref: = name_ref T, [template = ] +// CHECK:STDOUT: %n.loc32_33.1: = param n +// CHECK:STDOUT: @.1.%n: = bind_name n, %n.loc32_33.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Class { +// CHECK:STDOUT: %T.ref.loc12: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T] +// CHECK:STDOUT: %.loc12: = field_decl a, element0 [template] +// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2] +// CHECK:STDOUT: %self.loc13_8.1: Class = param self +// CHECK:STDOUT: %self.loc13_8.2: Class = bind_name self, %self.loc13_8.1 +// CHECK:STDOUT: %T.ref.loc13: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T] +// CHECK:STDOUT: %n.loc13_20.1: T = param n +// CHECK:STDOUT: %n.loc13_20.2: T = bind_name n, %n.loc13_20.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Class.2 +// CHECK:STDOUT: .a = %.loc12 +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F[@Class.%self.loc13_8.2: Class](@Class.%n.loc13_20.2: T); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1[%self: ](%n: ) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/generic/fail_todo_member_out_of_line.carbon b/toolchain/check/testdata/class/generic/fail_todo_member_out_of_line.carbon deleted file mode 100644 index 0545d91804dd..000000000000 --- a/toolchain/check/testdata/class/generic/fail_todo_member_out_of_line.carbon +++ /dev/null @@ -1,75 +0,0 @@ -// 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 -// TIP: To test this file alone, run: -// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/generic/fail_todo_member_out_of_line.carbon -// TIP: To dump output, run: -// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic/fail_todo_member_out_of_line.carbon - -class Class(T:! type) { - fn F(n: T) -> T; -} - -// CHECK:STDERR: fail_todo_member_out_of_line.carbon:[[@LINE+3]]:9: ERROR: Semantics TODO: `name qualifier with parameters`. -// CHECK:STDERR: fn Class(T:! type).F(n: T) -> T { -// CHECK:STDERR: ^~~~~~~~~~ -fn Class(T:! type).F(n: T) -> T { - return n; -} - -// CHECK:STDOUT: --- fail_todo_member_out_of_line.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] -// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template] -// CHECK:STDOUT: %.1: type = tuple_type () [template] -// CHECK:STDOUT: %struct.1: Class = struct_value () [template] -// CHECK:STDOUT: %Class.2: type = class_type @Class [template] -// CHECK:STDOUT: %F: type = fn_type @F [template] -// CHECK:STDOUT: %struct.2: F = struct_value () [template] -// CHECK:STDOUT: %.2: type = struct_type {} [template] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace [template] { -// CHECK:STDOUT: .Core = %Core -// CHECK:STDOUT: .Class = %Class.decl -// CHECK:STDOUT: } -// CHECK:STDOUT: %Core: = namespace [template] {} -// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct.1] { -// CHECK:STDOUT: %T.loc11_13.1: type = param T -// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T] -// CHECK:STDOUT: } -// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] { -// CHECK:STDOUT: %T.loc18_10.1: type = param T -// CHECK:STDOUT: %T.loc18_10.2: type = bind_symbolic_name T 0, %T.loc18_10.1 [symbolic = constants.%T] -// CHECK:STDOUT: %T.ref.loc18_25: type = name_ref T, %T.loc18_10.2 [symbolic = constants.%T] -// CHECK:STDOUT: %n.loc18_22.1: T = param n -// CHECK:STDOUT: @F.%n: T = bind_name n, %n.loc18_22.1 -// CHECK:STDOUT: %T.ref.loc18_31: type = name_ref T, %T.loc18_10.2 [symbolic = constants.%T] -// CHECK:STDOUT: @F.%return: ref T = var -// CHECK:STDOUT: } -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: class @Class { -// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] { -// CHECK:STDOUT: %T.ref.loc12_11: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T] -// CHECK:STDOUT: %n.loc12_8.1: T = param n -// CHECK:STDOUT: %n.loc12_8.2: T = bind_name n, %n.loc12_8.1 -// CHECK:STDOUT: %T.ref.loc12_17: type = name_ref T, file.%T.loc11_13.2 [symbolic = constants.%T] -// CHECK:STDOUT: %return.var: ref T = var -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = constants.%Class.2 -// CHECK:STDOUT: .F = %F.decl -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%n: T) -> T { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: %n.ref: T = name_ref n, %n -// CHECK:STDOUT: return %n.ref -// CHECK:STDOUT: } -// CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/generic/member_out_of_line.carbon b/toolchain/check/testdata/class/generic/member_out_of_line.carbon new file mode 100644 index 000000000000..4a7e92126474 --- /dev/null +++ b/toolchain/check/testdata/class/generic/member_out_of_line.carbon @@ -0,0 +1,412 @@ +// 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 +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/generic/member_out_of_line.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic/member_out_of_line.carbon + +// --- basic.carbon + +library "basic"; + +class Class(T:! type) { + fn F(n: T) -> T; +} + +fn Class(T:! type).F(n: T) -> T { + return n; +} + +// --- nested.carbon + +library "nested"; + +class A(T:! type) { + class B(N:! T) { + fn F[self: Self](a: T); + } +} + +fn A(T:! type).B(N:! T).F[self: Self](a: T) {} + +// --- fail_mismatched_not_generic_vs_generic.carbon + +library "fail_mismatched_not_generic_vs_generic"; + +class NotGeneric { + fn F(); +} + +// CHECK:STDERR: fail_mismatched_not_generic_vs_generic.carbon:[[@LINE+7]]:4: ERROR: Redeclaration differs because of parameter list. +// CHECK:STDERR: fn NotGeneric(T:! type).F() {} +// CHECK:STDERR: ^~~~~~~~~~ +// CHECK:STDERR: fail_mismatched_not_generic_vs_generic.carbon:[[@LINE-7]]:1: Previously declared without parameter list. +// CHECK:STDERR: class NotGeneric { +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn NotGeneric(T:! type).F() {} + +// --- fail_mismatched_too_few_args.carbon + +library "fail_mismatched_too_few_args"; + +class Generic(T:! type) { + fn TooFew(); +} + +// CHECK:STDERR: fail_mismatched_too_few_args.carbon:[[@LINE+7]]:4: ERROR: Redeclaration differs because of parameter count of 0. +// CHECK:STDERR: fn Generic().TooFew() {} +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: fail_mismatched_too_few_args.carbon:[[@LINE-7]]:1: Previously declared with parameter count of 1. +// CHECK:STDERR: class Generic(T:! type) { +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn Generic().TooFew() {} + +// --- fail_mismatched_too_many_args.carbon + +library "fail_mismatched_too_many_args"; + +class Generic(T:! type) { + fn TooMany(); +} + +// CHECK:STDERR: fail_mismatched_too_many_args.carbon:[[@LINE+7]]:4: ERROR: Redeclaration differs because of parameter count of 2. +// CHECK:STDERR: fn Generic(T:! type, U:! type).TooMany() {} +// CHECK:STDERR: ^~~~~~~ +// CHECK:STDERR: fail_mismatched_too_many_args.carbon:[[@LINE-7]]:1: Previously declared with parameter count of 1. +// CHECK:STDERR: class Generic(T:! type) { +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn Generic(T:! type, U:! type).TooMany() {} + +// --- fail_mismatched_wrong_arg_type.carbon + +library "fail_mismatched_wrong_arg_type"; + +class Generic(T:! type) { + fn WrongType(); +} + +// CHECK:STDERR: fail_mismatched_wrong_arg_type.carbon:[[@LINE+6]]:12: ERROR: Redeclaration differs at parameter 1. +// CHECK:STDERR: fn Generic(T:! ()).WrongType() {} +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_mismatched_wrong_arg_type.carbon:[[@LINE-7]]:15: Previous declaration's corresponding parameter here. +// CHECK:STDERR: class Generic(T:! type) { +// CHECK:STDERR: ^ +fn Generic(T:! ()).WrongType() {} + +// CHECK:STDOUT: --- basic.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %Class.1: type = generic_class_type @Class [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct.1: Class = struct_value () [template] +// CHECK:STDOUT: %Class.2: type = class_type @Class [template] +// CHECK:STDOUT: %F: type = fn_type @F [template] +// CHECK:STDOUT: %struct.2: F = struct_value () [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Class = %Class.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Class.decl: Class = class_decl @Class [template = constants.%struct.1] { +// CHECK:STDOUT: %T.loc4_13.1: type = param T +// CHECK:STDOUT: %T.loc4_13.2: type = bind_symbolic_name T 0, %T.loc4_13.1 [symbolic = constants.%T] +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] { +// CHECK:STDOUT: %T.loc8_10.1: type = param T +// CHECK:STDOUT: %T.loc8_10.2: type = bind_symbolic_name T 0, %T.loc8_10.1 [symbolic = constants.%T] +// CHECK:STDOUT: %T.ref.loc8_25: type = name_ref T, %T.loc8_10.2 [symbolic = constants.%T] +// CHECK:STDOUT: %n.loc8_22.1: T = param n +// CHECK:STDOUT: @F.%n: T = bind_name n, %n.loc8_22.1 +// CHECK:STDOUT: %T.ref.loc8_31: type = name_ref T, %T.loc8_10.2 [symbolic = constants.%T] +// CHECK:STDOUT: @F.%return: ref T = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Class { +// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] { +// CHECK:STDOUT: %T.ref.loc5_11: type = name_ref T, file.%T.loc4_13.2 [symbolic = constants.%T] +// CHECK:STDOUT: %n.loc5_8.1: T = param n +// CHECK:STDOUT: %n.loc5_8.2: T = bind_name n, %n.loc5_8.1 +// CHECK:STDOUT: %T.ref.loc5_17: type = name_ref T, file.%T.loc4_13.2 [symbolic = constants.%T] +// CHECK:STDOUT: %return.var: ref T = var +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Class.2 +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%n: T) -> T { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %n.ref: T = name_ref n, %n +// CHECK:STDOUT: return %n.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- nested.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %A.1: type = generic_class_type @A [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct.1: A = struct_value () [template] +// CHECK:STDOUT: %A.2: type = class_type @A [template] +// CHECK:STDOUT: %N: T = bind_symbolic_name N 1 [symbolic] +// CHECK:STDOUT: %B.1: type = generic_class_type @B [template] +// CHECK:STDOUT: %struct.2: B = struct_value () [template] +// CHECK:STDOUT: %B.2: type = class_type @B [template] +// CHECK:STDOUT: %F: type = fn_type @F [template] +// CHECK:STDOUT: %struct.3: F = struct_value () [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %.3: type = ptr_type {} [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .A = %A.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %A.decl: A = class_decl @A [template = constants.%struct.1] { +// CHECK:STDOUT: %T.loc4_9.1: type = param T +// CHECK:STDOUT: %T.loc4_9.2: type = bind_symbolic_name T 0, %T.loc4_9.1 [symbolic = constants.%T] +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.3] { +// CHECK:STDOUT: %T.loc10_6.1: type = param T +// CHECK:STDOUT: %T.loc10_6.2: type = bind_symbolic_name T 0, %T.loc10_6.1 [symbolic = constants.%T] +// CHECK:STDOUT: %T.ref.loc10_22: type = name_ref T, %T.loc10_6.2 [symbolic = constants.%T] +// CHECK:STDOUT: %N.loc10_18.1: T = param N +// CHECK:STDOUT: %N.loc10_18.2: T = bind_symbolic_name N 1, %N.loc10_18.1 [symbolic = constants.%N] +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B.2 [template = constants.%B.2] +// CHECK:STDOUT: %self.loc10_27.1: B = param self +// CHECK:STDOUT: @F.%self: B = bind_name self, %self.loc10_27.1 +// CHECK:STDOUT: %T.ref.loc10_42: type = name_ref T, %T.loc10_6.2 [symbolic = constants.%T] +// CHECK:STDOUT: %a.loc10_39.1: T = param a +// CHECK:STDOUT: @F.%a: T = bind_name a, %a.loc10_39.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @A { +// CHECK:STDOUT: %B.decl: B = class_decl @B [template = constants.%struct.2] { +// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc4_9.2 [symbolic = constants.%T] +// CHECK:STDOUT: %N.loc5_11.1: T = param N +// CHECK:STDOUT: %N.loc5_11.2: T = bind_symbolic_name N 1, %N.loc5_11.1 [symbolic = constants.%N] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%A.2 +// CHECK:STDOUT: .B = %B.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @B { +// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.3] { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B.2 [template = constants.%B.2] +// CHECK:STDOUT: %self.loc6_10.1: B = param self +// CHECK:STDOUT: %self.loc6_10.2: B = bind_name self, %self.loc6_10.1 +// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc4_9.2 [symbolic = constants.%T] +// CHECK:STDOUT: %a.loc6_22.1: T = param a +// CHECK:STDOUT: %a.loc6_22.2: T = bind_name a, %a.loc6_22.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%B.2 +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F[%self: B](%a: T) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_mismatched_not_generic_vs_generic.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %NotGeneric: type = class_type @NotGeneric [template] +// CHECK:STDOUT: %F: type = fn_type @F [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct.1: F = struct_value () [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %.3: 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: .Core = %Core +// CHECK:STDOUT: .NotGeneric = %NotGeneric.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %NotGeneric.decl: type = class_decl @NotGeneric [template = constants.%NotGeneric] {} +// CHECK:STDOUT: %.decl: = fn_decl @.1 [template = constants.%struct.2] { +// CHECK:STDOUT: %T.loc15_15.1: type = param T +// CHECK:STDOUT: %T.loc15_15.2: type = bind_symbolic_name T 0, %T.loc15_15.1 [symbolic = constants.%T] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @NotGeneric { +// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.1] {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%NotGeneric +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_mismatched_too_few_args.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %Generic.1: type = generic_class_type @Generic [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct.1: Generic = struct_value () [template] +// CHECK:STDOUT: %Generic.2: type = class_type @Generic [template] +// CHECK:STDOUT: %TooFew: type = fn_type @TooFew [template] +// CHECK:STDOUT: %struct.2: TooFew = struct_value () [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %.3: type = fn_type @.1 [template] +// CHECK:STDOUT: %struct.3: = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Generic = %Generic.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Generic.decl: Generic = class_decl @Generic [template = constants.%struct.1] { +// CHECK:STDOUT: %T.loc4_15.1: type = param T +// CHECK:STDOUT: %T.loc4_15.2: type = bind_symbolic_name T 0, %T.loc4_15.1 [symbolic = constants.%T] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.decl: = fn_decl @.1 [template = constants.%struct.3] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Generic { +// CHECK:STDOUT: %TooFew.decl: TooFew = fn_decl @TooFew [template = constants.%struct.2] {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Generic.2 +// CHECK:STDOUT: .TooFew = %TooFew.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooFew(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_mismatched_too_many_args.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %Generic.1: type = generic_class_type @Generic [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct.1: Generic = struct_value () [template] +// CHECK:STDOUT: %Generic.2: type = class_type @Generic [template] +// CHECK:STDOUT: %TooMany: type = fn_type @TooMany [template] +// CHECK:STDOUT: %struct.2: TooMany = struct_value () [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %U: type = bind_symbolic_name U 1 [symbolic] +// CHECK:STDOUT: %.3: type = fn_type @.1 [template] +// CHECK:STDOUT: %struct.3: = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Generic = %Generic.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Generic.decl: Generic = class_decl @Generic [template = constants.%struct.1] { +// CHECK:STDOUT: %T.loc4_15.1: type = param T +// CHECK:STDOUT: %T.loc4_15.2: type = bind_symbolic_name T 0, %T.loc4_15.1 [symbolic = constants.%T] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.decl: = fn_decl @.1 [template = constants.%struct.3] { +// CHECK:STDOUT: %T.loc15_12.1: type = param T +// CHECK:STDOUT: %T.loc15_12.2: type = bind_symbolic_name T 0, %T.loc15_12.1 [symbolic = constants.%T] +// CHECK:STDOUT: %U.loc15_22.1: type = param U +// CHECK:STDOUT: %U.loc15_22.2: type = bind_symbolic_name U 1, %U.loc15_22.1 [symbolic = constants.%U] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Generic { +// CHECK:STDOUT: %TooMany.decl: TooMany = fn_decl @TooMany [template = constants.%struct.2] {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Generic.2 +// CHECK:STDOUT: .TooMany = %TooMany.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @TooMany(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_mismatched_wrong_arg_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T.1: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %Generic.1: type = generic_class_type @Generic [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct.1: Generic = struct_value () [template] +// CHECK:STDOUT: %Generic.2: type = class_type @Generic [template] +// CHECK:STDOUT: %WrongType: type = fn_type @WrongType [template] +// CHECK:STDOUT: %struct.2: WrongType = struct_value () [template] +// CHECK:STDOUT: %.2: type = struct_type {} [template] +// CHECK:STDOUT: %T.2: () = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %.3: type = fn_type @.1 [template] +// CHECK:STDOUT: %struct.3: = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = %Core +// CHECK:STDOUT: .Generic = %Generic.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core: = namespace [template] {} +// CHECK:STDOUT: %Generic.decl: Generic = class_decl @Generic [template = constants.%struct.1] { +// CHECK:STDOUT: %T.loc4_15.1: type = param T +// CHECK:STDOUT: %T.loc4_15.2: type = bind_symbolic_name T 0, %T.loc4_15.1 [symbolic = constants.%T.1] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.decl: = fn_decl @.1 [template = constants.%struct.3] { +// CHECK:STDOUT: %.loc14_17.1: () = tuple_literal () +// CHECK:STDOUT: %.loc14_17.2: type = converted %.loc14_17.1, constants.%.1 [template = constants.%.1] +// CHECK:STDOUT: %T.loc14_12.1: () = param T +// CHECK:STDOUT: %T.loc14_12.2: () = bind_symbolic_name T 0, %T.loc14_12.1 [symbolic = constants.%T.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Generic { +// CHECK:STDOUT: %WrongType.decl: WrongType = fn_decl @WrongType [template = constants.%struct.2] {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Generic.2 +// CHECK:STDOUT: .WrongType = %WrongType.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @WrongType(); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/class/fail_todo_generic_method.carbon b/toolchain/check/testdata/class/generic_method.carbon similarity index 79% rename from toolchain/check/testdata/class/fail_todo_generic_method.carbon rename to toolchain/check/testdata/class/generic_method.carbon index a9fb5e325e8a..deafa8123a27 100644 --- a/toolchain/check/testdata/class/fail_todo_generic_method.carbon +++ b/toolchain/check/testdata/class/generic_method.carbon @@ -4,21 +4,18 @@ // // AUTOUPDATE // TIP: To test this file alone, run: -// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/fail_todo_generic_method.carbon +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/class/generic_method.carbon // TIP: To dump output, run: -// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/fail_todo_generic_method.carbon +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/class/generic_method.carbon class Class(T:! type) { var a: T; fn F[self: Self](n: T); } -// CHECK:STDERR: fail_todo_generic_method.carbon:[[@LINE+3]]:9: ERROR: Semantics TODO: `name qualifier with parameters`. -// CHECK:STDERR: fn Class(T:! type).F[self: Self](n: T) {} -// CHECK:STDERR: ^~~~~~~~~~ fn Class(T:! type).F[self: Self](n: T) {} -// CHECK:STDOUT: --- fail_todo_generic_method.carbon +// CHECK:STDOUT: --- generic_method.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] @@ -44,14 +41,14 @@ fn Class(T:! type).F[self: Self](n: T) {} // CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T] // CHECK:STDOUT: } // CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.2] { -// CHECK:STDOUT: %T.loc19_10.1: type = param T -// CHECK:STDOUT: %T.loc19_10.2: type = bind_symbolic_name T 0, %T.loc19_10.1 [symbolic = constants.%T] +// CHECK:STDOUT: %T.loc16_10.1: type = param T +// CHECK:STDOUT: %T.loc16_10.2: type = bind_symbolic_name T 0, %T.loc16_10.1 [symbolic = constants.%T] // CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Class.2 [template = constants.%Class.2] -// CHECK:STDOUT: %self.loc19_22.1: Class = param self -// CHECK:STDOUT: @F.%self: Class = bind_name self, %self.loc19_22.1 -// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc19_10.2 [symbolic = constants.%T] -// CHECK:STDOUT: %n.loc19_34.1: T = param n -// CHECK:STDOUT: @F.%n: T = bind_name n, %n.loc19_34.1 +// CHECK:STDOUT: %self.loc16_22.1: Class = param self +// CHECK:STDOUT: @F.%self: Class = bind_name self, %self.loc16_22.1 +// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc16_10.2 [symbolic = constants.%T] +// CHECK:STDOUT: %n.loc16_34.1: T = param n +// CHECK:STDOUT: @F.%n: T = bind_name n, %n.loc16_34.1 // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon b/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon index 900c18216692..1b6f2cea3126 100644 --- a/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon +++ b/toolchain/check/testdata/impl/fail_extend_impl_forall.carbon @@ -8,10 +8,6 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/fail_extend_impl_forall.carbon -// CHECK:STDERR: fail_extend_impl_forall.carbon:[[@LINE+4]]:1: ERROR: Semantics TODO: `generic interface`. -// CHECK:STDERR: interface GenericInterface(T:! type) { -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: interface GenericInterface(T:! type) { fn F(x: T); } @@ -58,8 +54,8 @@ class C { // CHECK:STDOUT: } // CHECK:STDOUT: %Core: = namespace [template] {} // CHECK:STDOUT: %GenericInterface.decl: type = interface_decl @GenericInterface [template = constants.%.1] { -// CHECK:STDOUT: %T.loc15_28.1: type = param T -// CHECK:STDOUT: %T.loc15_28.2: type = bind_symbolic_name T 0, %T.loc15_28.1 [symbolic = constants.%T] +// CHECK:STDOUT: %T.loc11_28.1: type = param T +// CHECK:STDOUT: %T.loc11_28.2: type = bind_symbolic_name T 0, %T.loc11_28.1 [symbolic = constants.%T] // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {} // CHECK:STDOUT: } @@ -67,23 +63,23 @@ class C { // CHECK:STDOUT: interface @GenericInterface { // CHECK:STDOUT: %Self: GenericInterface = bind_symbolic_name Self 1 [symbolic = constants.%Self] // CHECK:STDOUT: %F.decl: F = fn_decl @F.1 [template = constants.%struct.1] { -// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc15_28.2 [symbolic = constants.%T] -// CHECK:STDOUT: %x.loc16_8.1: T = param x -// CHECK:STDOUT: %x.loc16_8.2: T = bind_name x, %x.loc16_8.1 +// CHECK:STDOUT: %T.ref: type = name_ref T, file.%T.loc11_28.2 [symbolic = constants.%T] +// CHECK:STDOUT: %x.loc12_8.1: T = param x +// CHECK:STDOUT: %x.loc12_8.2: T = bind_name x, %x.loc12_8.1 // CHECK:STDOUT: } -// CHECK:STDOUT: %.loc16: = assoc_entity element0, %F.decl [template = constants.%.4] +// CHECK:STDOUT: %.loc12: = assoc_entity element0, %F.decl [template = constants.%.4] // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = %Self -// CHECK:STDOUT: .F = %.loc16 +// CHECK:STDOUT: .F = %.loc12 // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: impl @impl: C as { // CHECK:STDOUT: %F.decl: F = fn_decl @F.2 [template = constants.%struct.2] { -// CHECK:STDOUT: %T.ref: type = name_ref T, @C.%T.loc31_23.2 [symbolic = constants.%T] -// CHECK:STDOUT: %x.loc32_10.1: T = param x -// CHECK:STDOUT: %x.loc32_10.2: T = bind_name x, %x.loc32_10.1 +// CHECK:STDOUT: %T.ref: type = name_ref T, @C.%T.loc27_23.2 [symbolic = constants.%T] +// CHECK:STDOUT: %x.loc28_10.1: T = param x +// CHECK:STDOUT: %x.loc28_10.2: T = bind_name x, %x.loc28_10.1 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: !members: @@ -93,10 +89,10 @@ class C { // CHECK:STDOUT: // CHECK:STDOUT: class @C { // CHECK:STDOUT: impl_decl @impl { -// CHECK:STDOUT: %T.loc31_23.1: type = param T -// CHECK:STDOUT: %T.loc31_23.2: type = bind_symbolic_name T 0, %T.loc31_23.1 [symbolic = constants.%T] +// CHECK:STDOUT: %T.loc27_23.1: type = param T +// CHECK:STDOUT: %T.loc27_23.2: type = bind_symbolic_name T 0, %T.loc27_23.1 [symbolic = constants.%T] // CHECK:STDOUT: %GenericInterface.ref: type = name_ref GenericInterface, file.%GenericInterface.decl [template = constants.%.1] -// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc31_23.2 [symbolic = constants.%T] +// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc27_23.2 [symbolic = constants.%T] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: !members: @@ -104,9 +100,9 @@ class C { // CHECK:STDOUT: has_error // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc16_8.2: T); +// CHECK:STDOUT: fn @F.1(@GenericInterface.%x.loc12_8.2: T); // CHECK:STDOUT: -// CHECK:STDOUT: fn @F.2(@impl.%x.loc32_10.2: T) { +// CHECK:STDOUT: fn @F.2(@impl.%x.loc28_10.2: T) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon b/toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon new file mode 100644 index 000000000000..401742af7849 --- /dev/null +++ b/toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon @@ -0,0 +1,114 @@ +// 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 +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_generic_redeclaration.carbon + +interface NotGeneric; +// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE+7]]:1: ERROR: Redeclaration differs because of parameter list. +// CHECK:STDERR: interface NotGeneric(T:! type) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE-4]]:1: Previously declared without parameter list. +// CHECK:STDERR: interface NotGeneric; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +interface NotGeneric(T:! type) {} + +interface Generic(T:! type); +// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE+7]]:1: ERROR: Redeclaration differs because of missing parameter list. +// CHECK:STDERR: interface Generic {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE-4]]:1: Previously declared with parameter list. +// CHECK:STDERR: interface Generic(T:! type); +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +interface Generic {} + +interface DifferentParams(T:! type); +// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE+6]]:27: ERROR: Redeclaration differs at parameter 1. +// CHECK:STDERR: interface DifferentParams(T:! ()) {} +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_generic_redeclaration.carbon:[[@LINE-4]]:27: Previous declaration's corresponding parameter here. +// CHECK:STDERR: interface DifferentParams(T:! type); +// CHECK:STDERR: ^ +interface DifferentParams(T:! ()) {} + +// CHECK:STDOUT: --- fail_generic_redeclaration.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %.1: type = interface_type @NotGeneric [template] +// CHECK:STDOUT: %T.1: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %.2: type = interface_type @.1 [template] +// CHECK:STDOUT: %Self.1: = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %.3: type = interface_type @Generic [template] +// CHECK:STDOUT: %.4: type = interface_type @.2 [template] +// CHECK:STDOUT: %Self.2: = bind_symbolic_name Self 0 [symbolic] +// CHECK:STDOUT: %.5: type = interface_type @DifferentParams [template] +// CHECK:STDOUT: %.6: type = tuple_type () [template] +// CHECK:STDOUT: %T.2: () = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %.7: type = interface_type @.3 [template] +// CHECK:STDOUT: %Self.3: = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .NotGeneric = %NotGeneric.decl +// CHECK:STDOUT: .Generic = %Generic.decl +// CHECK:STDOUT: .DifferentParams = %DifferentParams.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %NotGeneric.decl: type = interface_decl @NotGeneric [template = constants.%.1] {} +// CHECK:STDOUT: %.decl.loc19: type = interface_decl @.1 [template = constants.%.2] { +// CHECK:STDOUT: %T.loc19_22.1: type = param T +// CHECK:STDOUT: %T.loc19_22.2: type = bind_symbolic_name T 0, %T.loc19_22.1 [symbolic = constants.%T.1] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Generic.decl: type = interface_decl @Generic [template = constants.%.3] { +// CHECK:STDOUT: %T.loc21_19.1: type = param T +// CHECK:STDOUT: %T.loc21_19.2: type = bind_symbolic_name T 0, %T.loc21_19.1 [symbolic = constants.%T.1] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.decl.loc29: type = interface_decl @.2 [template = constants.%.4] {} +// CHECK:STDOUT: %DifferentParams.decl: type = interface_decl @DifferentParams [template = constants.%.5] { +// CHECK:STDOUT: %T.loc31_27.1: type = param T +// CHECK:STDOUT: %T.loc31_27.2: type = bind_symbolic_name T 0, %T.loc31_27.1 [symbolic = constants.%T.1] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.decl.loc38: type = interface_decl @.3 [template = constants.%.7] { +// CHECK:STDOUT: %.loc38_32.1: () = tuple_literal () +// CHECK:STDOUT: %.loc38_32.2: type = converted %.loc38_32.1, constants.%.6 [template = constants.%.6] +// CHECK:STDOUT: %T.loc38_27.1: () = param T +// CHECK:STDOUT: %T.loc38_27.2: () = bind_symbolic_name T 0, %T.loc38_27.1 [symbolic = constants.%T.2] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @NotGeneric; +// CHECK:STDOUT: +// CHECK:STDOUT: interface @.1 { +// CHECK:STDOUT: %Self: = bind_symbolic_name Self 1 [symbolic = constants.%Self.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Generic; +// CHECK:STDOUT: +// CHECK:STDOUT: interface @.2 { +// CHECK:STDOUT: %Self: = bind_symbolic_name Self 0 [symbolic = constants.%Self.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @DifferentParams; +// CHECK:STDOUT: +// CHECK:STDOUT: interface @.3 { +// CHECK:STDOUT: %Self: = bind_symbolic_name Self 1 [symbolic = constants.%Self.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon b/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon new file mode 100644 index 000000000000..b59e97b60e70 --- /dev/null +++ b/toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon @@ -0,0 +1,90 @@ +// 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 +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic_default_fn.carbon + +interface I(T:! type) { + // TODO: Use `default` here. + fn F[self: Self]() -> Self; +} + +// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE+6]]:1: ERROR: Duplicate name being declared in the same scope. +// CHECK:STDERR: fn I(T:! type).F[self: Self]() -> Self { return self; } +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_todo_generic_default_fn.carbon:[[@LINE-6]]:3: Name is previously declared here. +// CHECK:STDERR: fn F[self: Self]() -> Self; +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +fn I(T:! type).F[self: Self]() -> Self { return self; } + +// CHECK:STDOUT: --- fail_todo_generic_default_fn.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %.1: type = interface_type @I [template] +// CHECK:STDOUT: %Self: I = bind_symbolic_name Self 1 [symbolic] +// CHECK:STDOUT: %F: type = fn_type @F [template] +// CHECK:STDOUT: %.2: type = tuple_type () [template] +// CHECK:STDOUT: %struct.1: F = struct_value () [template] +// CHECK:STDOUT: %.3: type = assoc_entity_type @I, F [template] +// CHECK:STDOUT: %.4: = assoc_entity element0, @I.%F.decl [template] +// CHECK:STDOUT: %.5: 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: .I = %I.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%.1] { +// CHECK:STDOUT: %T.loc11_13.1: type = param T +// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.decl: = fn_decl @.1 [template = constants.%struct.2] { +// CHECK:STDOUT: %T.loc22_6.1: type = param T +// CHECK:STDOUT: %T.loc22_6.2: type = bind_symbolic_name T 0, %T.loc22_6.1 [symbolic = constants.%T] +// CHECK:STDOUT: %Self.ref.loc22_24: I = name_ref Self, @I.%Self [symbolic = constants.%Self] +// CHECK:STDOUT: %.loc22_24.1: type = facet_type_access %Self.ref.loc22_24 [symbolic = constants.%Self] +// CHECK:STDOUT: %.loc22_24.2: type = converted %Self.ref.loc22_24, %.loc22_24.1 [symbolic = constants.%Self] +// CHECK:STDOUT: %self.loc22_18.1: Self = param self +// CHECK:STDOUT: @.1.%self: Self = bind_name self, %self.loc22_18.1 +// CHECK:STDOUT: %Self.ref.loc22_35: I = name_ref Self, @I.%Self [symbolic = constants.%Self] +// CHECK:STDOUT: %.loc22_35.1: type = facet_type_access %Self.ref.loc22_35 [symbolic = constants.%Self] +// CHECK:STDOUT: %.loc22_35.2: type = converted %Self.ref.loc22_35, %.loc22_35.1 [symbolic = constants.%Self] +// CHECK:STDOUT: @.1.%return: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I { +// CHECK:STDOUT: %Self: I = bind_symbolic_name Self 1 [symbolic = constants.%Self] +// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct.1] { +// CHECK:STDOUT: %Self.ref.loc13_14: I = name_ref Self, %Self [symbolic = constants.%Self] +// CHECK:STDOUT: %.loc13_14.1: type = facet_type_access %Self.ref.loc13_14 [symbolic = constants.%Self] +// CHECK:STDOUT: %.loc13_14.2: type = converted %Self.ref.loc13_14, %.loc13_14.1 [symbolic = constants.%Self] +// CHECK:STDOUT: %self.loc13_8.1: Self = param self +// CHECK:STDOUT: %self.loc13_8.2: Self = bind_name self, %self.loc13_8.1 +// CHECK:STDOUT: %Self.ref.loc13_25: I = name_ref Self, %Self [symbolic = constants.%Self] +// CHECK:STDOUT: %.loc13_25.1: type = facet_type_access %Self.ref.loc13_25 [symbolic = constants.%Self] +// CHECK:STDOUT: %.loc13_25.2: type = converted %Self.ref.loc13_25, %.loc13_25.1 [symbolic = constants.%Self] +// CHECK:STDOUT: %return.var: ref Self = var +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc13_29: = assoc_entity element0, %F.decl [template = constants.%.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = %.loc13_29 +// CHECK:STDOUT: witness = (%F.decl) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F[@I.%self.loc13_8.2: Self]() -> Self; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @.1[%self: Self]() -> Self { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %self.ref: Self = name_ref self, %self +// CHECK:STDOUT: return %self.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interface/no_prelude/fail_todo_generic.carbon b/toolchain/check/testdata/interface/no_prelude/generic.carbon similarity index 51% rename from toolchain/check/testdata/interface/no_prelude/fail_todo_generic.carbon rename to toolchain/check/testdata/interface/no_prelude/generic.carbon index cc2fdff96766..5e08b7fb4a6d 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_todo_generic.carbon +++ b/toolchain/check/testdata/interface/no_prelude/generic.carbon @@ -4,18 +4,17 @@ // // AUTOUPDATE // TIP: To test this file alone, run: -// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic.carbon +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interface/no_prelude/generic.carbon // TIP: To dump output, run: -// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/fail_todo_generic.carbon +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/no_prelude/generic.carbon -// CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+3]]:1: ERROR: Semantics TODO: `generic interface`. -// CHECK:STDERR: interface I[](); -// CHECK:STDERR: ^~~~~~~~~~~~~~~~ -interface I[](); +interface I[T:! type](N:! T); -// CHECK:STDOUT: --- fail_todo_generic.carbon +// CHECK:STDOUT: --- generic.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %N: T = bind_symbolic_name N 1 [symbolic] // CHECK:STDOUT: %.1: type = interface_type @I [template] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -23,7 +22,13 @@ interface I[](); // CHECK:STDOUT: package: = namespace [template] { // CHECK:STDOUT: .I = %I.decl // CHECK:STDOUT: } -// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%.1] {} +// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%.1] { +// CHECK:STDOUT: %T.loc11_13.1: type = param T +// CHECK:STDOUT: %T.loc11_13.2: type = bind_symbolic_name T 0, %T.loc11_13.1 [symbolic = constants.%T] +// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc11_13.2 [symbolic = constants.%T] +// CHECK:STDOUT: %N.loc11_23.1: T = param N +// CHECK:STDOUT: %N.loc11_23.2: T = bind_symbolic_name N 1, %N.loc11_23.1 [symbolic = constants.%N] +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @I; diff --git a/toolchain/check/testdata/namespace/fail_params.carbon b/toolchain/check/testdata/namespace/fail_params.carbon index 19f845a09a82..1b36a4e3ba29 100644 --- a/toolchain/check/testdata/namespace/fail_params.carbon +++ b/toolchain/check/testdata/namespace/fail_params.carbon @@ -23,11 +23,21 @@ fn A.F() {} // CHECK:STDERR: namespace B(n: i32); -// CHECK:STDERR: fail_params.carbon:[[@LINE+3]]:12: ERROR: `namespace` declaration cannot have parameters. +// CHECK:STDERR: fail_params.carbon:[[@LINE+4]]:12: ERROR: `namespace` declaration cannot have parameters. // CHECK:STDERR: namespace C[T:! type](x: T); // CHECK:STDERR: ^~~~~~~~~~ +// CHECK:STDERR: namespace C[T:! type](x: T); +namespace D; +// CHECK:STDERR: fail_params.carbon:[[@LINE+6]]:4: ERROR: Redeclaration differs because of parameter list. +// CHECK:STDERR: fn D(T:! type).F() {} +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_params.carbon:[[@LINE-4]]:1: Previously declared without parameter list. +// CHECK:STDERR: namespace D; +// CHECK:STDERR: ^~~~~~~~~~~~ +fn D(T:! type).F() {} + // CHECK:STDOUT: --- fail_params.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -37,6 +47,8 @@ namespace C[T:! type](x: T); // CHECK:STDOUT: %Int32: type = fn_type @Int32 [template] // CHECK:STDOUT: %struct.2: Int32 = struct_value () [template] // CHECK:STDOUT: %T: type = bind_symbolic_name T 0 [symbolic] +// CHECK:STDOUT: %.2: type = fn_type @.1 [template] +// CHECK:STDOUT: %struct.3: = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -45,6 +57,7 @@ namespace C[T:! type](x: T); // CHECK:STDOUT: .A = %A // CHECK:STDOUT: .B = %B // CHECK:STDOUT: .C = %C +// CHECK:STDOUT: .D = %D // CHECK:STDOUT: } // CHECK:STDOUT: %Core: = namespace [template] {} // CHECK:STDOUT: %A: = namespace [template] { @@ -58,12 +71,17 @@ namespace C[T:! type](x: T); // CHECK:STDOUT: %n.loc24_13.1: i32 = param n // CHECK:STDOUT: %n.loc24_13.2: i32 = bind_name n, %n.loc24_13.1 // CHECK:STDOUT: %B: = namespace [template] {} -// CHECK:STDOUT: %T.loc29_13.1: type = param T -// CHECK:STDOUT: %T.loc29_13.2: type = bind_symbolic_name T 0, %T.loc29_13.1 [symbolic = constants.%T] -// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc29_13.2 [symbolic = constants.%T] -// CHECK:STDOUT: %x.loc29_23.1: T = param x -// CHECK:STDOUT: %x.loc29_23.2: T = bind_name x, %x.loc29_23.1 +// CHECK:STDOUT: %T.loc30_13.1: type = param T +// CHECK:STDOUT: %T.loc30_13.2: type = bind_symbolic_name T 0, %T.loc30_13.1 [symbolic = constants.%T] +// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc30_13.2 [symbolic = constants.%T] +// CHECK:STDOUT: %x.loc30_23.1: T = param x +// CHECK:STDOUT: %x.loc30_23.2: T = bind_name x, %x.loc30_23.1 // CHECK:STDOUT: %C: = namespace [template] {} +// CHECK:STDOUT: %D: = namespace [template] {} +// CHECK:STDOUT: %.decl: = fn_decl @.1 [template = constants.%struct.3] { +// CHECK:STDOUT: %T.loc39_6.1: type = param T +// CHECK:STDOUT: %T.loc39_6.2: type = bind_symbolic_name T 0, %T.loc39_6.1 [symbolic = constants.%T] +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { @@ -73,3 +91,8 @@ namespace C[T:! type](x: T); // CHECK:STDOUT: // CHECK:STDOUT: fn @Int32() -> type = "int.make_type_32"; // CHECK:STDOUT: +// CHECK:STDOUT: fn @.1() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/packages/no_prelude/cross_package_import.carbon b/toolchain/check/testdata/packages/no_prelude/cross_package_import.carbon index 30fdf965276d..94ce6aeb1e4e 100644 --- a/toolchain/check/testdata/packages/no_prelude/cross_package_import.carbon +++ b/toolchain/check/testdata/packages/no_prelude/cross_package_import.carbon @@ -162,10 +162,10 @@ library "reopen_other"; import Other library "fn"; -// CHECK:STDERR: fail_main_reopen_other.carbon:[[@LINE+7]]:11: ERROR: Imported packages cannot be used for declarations. +// CHECK:STDERR: fail_main_reopen_other.carbon:[[@LINE+7]]:1: ERROR: Duplicate name being declared in the same scope. // CHECK:STDERR: namespace Other; -// CHECK:STDERR: ^~~~~ -// CHECK:STDERR: fail_main_reopen_other.carbon:[[@LINE-5]]:1: Package imported here. +// CHECK:STDERR: ^~~~~~~~~~~~~~~~ +// CHECK:STDERR: fail_main_reopen_other.carbon:[[@LINE-5]]:1: Name is previously declared here. // CHECK:STDERR: import Other library "fn"; // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: @@ -174,6 +174,24 @@ namespace Other; // This is not diagnosed after the diagnostic on `namespace Other;`. fn Other.G() {} +// --- fail_main_reopen_other_nested.carbon + +library "reopen_other_nested"; + +import Other library "fn"; + +// CHECK:STDERR: fail_main_reopen_other_nested.carbon:[[@LINE+7]]:11: ERROR: Imported packages cannot be used for declarations. +// CHECK:STDERR: namespace Other.Nested; +// CHECK:STDERR: ^~~~~ +// CHECK:STDERR: fail_main_reopen_other_nested.carbon:[[@LINE-5]]:1: Package imported here. +// CHECK:STDERR: import Other library "fn"; +// CHECK:STDERR: ^~~~~~ +// CHECK:STDERR: +namespace Other.Nested; + +// This is not diagnosed after the diagnostic on `namespace Other;`. +fn Other.Nested.F() {} + // --- fail_main_add_to_other.carbon library "add_to_other"; @@ -475,6 +493,32 @@ fn UseF() { Other.F(); } // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- fail_main_reopen_other_nested.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %F: type = fn_type @F [template] +// CHECK:STDOUT: %.1: type = tuple_type () [template] +// CHECK:STDOUT: %struct: F = struct_value () [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Other = %Other +// CHECK:STDOUT: } +// CHECK:STDOUT: %Other: = namespace [template] { +// CHECK:STDOUT: .Nested = %Nested +// CHECK:STDOUT: } +// CHECK:STDOUT: %Nested: = namespace [template] { +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: F = fn_decl @F [template = constants.%struct] {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- fail_main_add_to_other.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/sem_ir/interface.h b/toolchain/sem_ir/interface.h index 1fcee5f0cdf0..9f2c8b3feee5 100644 --- a/toolchain/sem_ir/interface.h +++ b/toolchain/sem_ir/interface.h @@ -32,6 +32,10 @@ struct Interface : public Printable { NameId name_id; // The parent scope. NameScopeId parent_scope_id; + // A block containing a single reference instruction per implicit parameter. + InstBlockId implicit_param_refs_id; + // A block containing a single reference instruction per parameter. + InstBlockId param_refs_id; // The first declaration of the interface. This is a InterfaceDecl. InstId decl_id;