From de9b7d282a3c7c9923ee07f62a3795887a366311 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 11 Nov 2024 16:50:10 -0800 Subject: [PATCH] Fix use-after-free printing the name of an interface that might have been invalidated by lazy import. (#4509) While here, also change the diagnostic emission to pass the interface type rather than the interface name. This prepares us to include the arguments in the diagnostic. --- toolchain/check/context.cpp | 6 + toolchain/check/context.h | 4 + toolchain/check/member_access.cpp | 15 +- .../impl/lookup/no_prelude/import.carbon | 433 ++++++++++++++++++ 4 files changed, 451 insertions(+), 7 deletions(-) diff --git a/toolchain/check/context.cpp b/toolchain/check/context.cpp index f26997e2cac4c..aba29e2243575 100644 --- a/toolchain/check/context.cpp +++ b/toolchain/check/context.cpp @@ -1299,6 +1299,12 @@ auto Context::GetGenericInterfaceType(SemIR::InterfaceId interface_id, *this, interface_id, enclosing_specific_id); } +auto Context::GetInterfaceType(SemIR::InterfaceId interface_id, + SemIR::SpecificId specific_id) -> SemIR::TypeId { + return GetTypeImpl( + *this, FacetTypeFromInterface(interface_id, specific_id).facet_type_id); +} + auto Context::GetPointerType(SemIR::TypeId pointee_type_id) -> SemIR::TypeId { return GetTypeImpl(*this, pointee_type_id); } diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 3e6bb17abbedc..170552c2d2463 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -397,6 +397,10 @@ class Context { SemIR::SpecificId enclosing_specific_id) -> SemIR::TypeId; + // Gets the facet type corresponding to a particular interface. + auto GetInterfaceType(SemIR::InterfaceId interface_id, + SemIR::SpecificId specific_id) -> SemIR::TypeId; + // Returns a pointer type whose pointee type is `pointee_type_id`. auto GetPointerType(SemIR::TypeId pointee_type_id) -> SemIR::TypeId; diff --git a/toolchain/check/member_access.cpp b/toolchain/check/member_access.cpp index 1499535064854..a9f1032d25741 100644 --- a/toolchain/check/member_access.cpp +++ b/toolchain/check/member_access.cpp @@ -193,28 +193,29 @@ static auto PerformImplLookup( return SemIR::InstId::BuiltinError; } - auto& interface = context.interfaces().Get(interface_type->interface_id); auto witness_id = LookupInterfaceWitness(context, loc_id, type_const_id, assoc_type.interface_type_id.AsConstantId()); if (!witness_id.is_valid()) { + auto interface_type_id = context.GetInterfaceType( + interface_type->interface_id, interface_type->specific_id); if (missing_impl_diagnoser) { // TODO: Pass in the expression whose type we are printing. CARBON_DIAGNOSTIC(MissingImplInMemberAccessNote, Note, - "type {1} does not implement interface `{0}`", - SemIR::NameId, SemIR::TypeId); + "type {1} does not implement interface {0}", + SemIR::TypeId, SemIR::TypeId); missing_impl_diagnoser() - .Note(loc_id, MissingImplInMemberAccessNote, interface.name_id, + .Note(loc_id, MissingImplInMemberAccessNote, interface_type_id, context.GetTypeIdForTypeConstant(type_const_id)) .Emit(); } else { // TODO: Pass in the expression whose type we are printing. CARBON_DIAGNOSTIC(MissingImplInMemberAccess, Error, - "cannot access member of interface `{0}` in type {1} " + "cannot access member of interface {0} in type {1} " "that does not implement that interface", - SemIR::NameId, SemIR::TypeId); + SemIR::TypeId, SemIR::TypeId); context.emitter().Emit(loc_id, MissingImplInMemberAccess, - interface.name_id, + interface_type_id, context.GetTypeIdForTypeConstant(type_const_id)); } return SemIR::InstId::BuiltinError; diff --git a/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon b/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon index ba33094d1155e..679c07f89c8e1 100644 --- a/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon +++ b/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon @@ -71,6 +71,40 @@ fn TestDG(d: PackageB.D) { d.(PackageB.HasG.G)(); } +// --- has_extra_interfaces.carbon + +package HasExtraInterfaces; + +interface Extra1 {} +interface Extra2 {} +interface Extra3 {} +interface Extra4 {} +interface Extra5 {} +interface Extra6 {} +interface Extra7 {} +interface Extra8 {} + +class C(T:! type) {} +interface I { fn F(); } + +impl C((Extra1, Extra2, Extra3, Extra4, Extra5, Extra6, Extra7, Extra8)) as I { + fn F() {} +} + +// --- fail_use_has_extra_interfaces.carbon + +package UseHasExtraInterfaces; +import HasExtraInterfaces; + +fn Test(c: HasExtraInterfaces.C(type)) { + // This triggers the import of a bunch more interfaces, which reallocates the + // interface ValueStore. Ensure that doesn't result in a use-after-free crash. + // CHECK:STDERR: fail_use_has_extra_interfaces.carbon:[[@LINE+3]]:3: error: cannot access member of interface `I` in type `C` that does not implement that interface [MissingImplInMemberAccess] + // CHECK:STDERR: c.(HasExtraInterfaces.I.F)(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ + c.(HasExtraInterfaces.I.F)(); +} + // CHECK:STDOUT: --- package_a.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -544,3 +578,402 @@ fn TestDG(d: PackageB.D) { // CHECK:STDOUT: // CHECK:STDOUT: specific @G.1(constants.%Self.2) {} // CHECK:STDOUT: +// CHECK:STDOUT: --- has_extra_interfaces.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Extra1.type: type = facet_type <@Extra1> [template] +// CHECK:STDOUT: %Self.1: %Extra1.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra2.type: type = facet_type <@Extra2> [template] +// CHECK:STDOUT: %Self.2: %Extra2.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra3.type: type = facet_type <@Extra3> [template] +// CHECK:STDOUT: %Self.3: %Extra3.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra4.type: type = facet_type <@Extra4> [template] +// CHECK:STDOUT: %Self.4: %Extra4.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra5.type: type = facet_type <@Extra5> [template] +// CHECK:STDOUT: %Self.5: %Extra5.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra6.type: type = facet_type <@Extra6> [template] +// CHECK:STDOUT: %Self.6: %Extra6.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra7.type: type = facet_type <@Extra7> [template] +// CHECK:STDOUT: %Self.7: %Extra7.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra8.type: type = facet_type <@Extra8> [template] +// CHECK:STDOUT: %Self.8: %Extra8.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %C.type: type = generic_class_type @C [template] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [template] +// CHECK:STDOUT: %C.1: %C.type = struct_value () [template] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%T) [symbolic] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %I.type: type = facet_type <@I> [template] +// CHECK:STDOUT: %Self.9: %I.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %F.type.1: type = fn_type @F.1 [template] +// CHECK:STDOUT: %F.1: %F.type.1 = struct_value () [template] +// CHECK:STDOUT: %.3: type = assoc_entity_type %I.type, %F.type.1 [template] +// CHECK:STDOUT: %.4: %.3 = assoc_entity element0, @I.%F.decl [template] +// CHECK:STDOUT: %tuple.type.1: type = tuple_type (type, type, type, type, type, type, type, type) [template] +// CHECK:STDOUT: %tuple.type.2: type = tuple_type (%Extra1.type, %Extra2.type, %Extra3.type, %Extra4.type, %Extra5.type, %Extra6.type, %Extra7.type, %Extra8.type) [template] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(%tuple.type.2) [template] +// CHECK:STDOUT: %F.type.2: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.2: %F.type.2 = struct_value () [template] +// CHECK:STDOUT: %.5: = interface_witness (%F.2) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Extra1 = %Extra1.decl +// CHECK:STDOUT: .Extra2 = %Extra2.decl +// CHECK:STDOUT: .Extra3 = %Extra3.decl +// CHECK:STDOUT: .Extra4 = %Extra4.decl +// CHECK:STDOUT: .Extra5 = %Extra5.decl +// CHECK:STDOUT: .Extra6 = %Extra6.decl +// CHECK:STDOUT: .Extra7 = %Extra7.decl +// CHECK:STDOUT: .Extra8 = %Extra8.decl +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .I = %I.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Extra1.decl: type = interface_decl @Extra1 [template = constants.%Extra1.type] {} {} +// CHECK:STDOUT: %Extra2.decl: type = interface_decl @Extra2 [template = constants.%Extra2.type] {} {} +// CHECK:STDOUT: %Extra3.decl: type = interface_decl @Extra3 [template = constants.%Extra3.type] {} {} +// CHECK:STDOUT: %Extra4.decl: type = interface_decl @Extra4 [template = constants.%Extra4.type] {} {} +// CHECK:STDOUT: %Extra5.decl: type = interface_decl @Extra5 [template = constants.%Extra5.type] {} {} +// CHECK:STDOUT: %Extra6.decl: type = interface_decl @Extra6 [template = constants.%Extra6.type] {} {} +// CHECK:STDOUT: %Extra7.decl: type = interface_decl @Extra7 [template = constants.%Extra7.type] {} {} +// CHECK:STDOUT: %Extra8.decl: type = interface_decl @Extra8 [template = constants.%Extra8.type] {} {} +// CHECK:STDOUT: %C.decl: %C.type = class_decl @C [template = constants.%C.1] { +// CHECK:STDOUT: %T.patt.loc13_9.1: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc13_9.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.param_patt: type = value_param_pattern %T.patt.loc13_9.1, runtime_param [symbolic = %T.patt.loc13_9.2 (constants.%T.patt)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.param: type = value_param runtime_param +// CHECK:STDOUT: %T.loc13_9.1: type = bind_symbolic_name T, 0, %T.param [symbolic = %T.loc13_9.2 (constants.%T)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %I.decl: type = interface_decl @I [template = constants.%I.type] {} {} +// CHECK:STDOUT: impl_decl @impl [template] {} { +// CHECK:STDOUT: %C.ref: %C.type = name_ref C, file.%C.decl [template = constants.%C.1] +// CHECK:STDOUT: %Extra1.ref: type = name_ref Extra1, file.%Extra1.decl [template = constants.%Extra1.type] +// CHECK:STDOUT: %Extra2.ref: type = name_ref Extra2, file.%Extra2.decl [template = constants.%Extra2.type] +// CHECK:STDOUT: %Extra3.ref: type = name_ref Extra3, file.%Extra3.decl [template = constants.%Extra3.type] +// CHECK:STDOUT: %Extra4.ref: type = name_ref Extra4, file.%Extra4.decl [template = constants.%Extra4.type] +// CHECK:STDOUT: %Extra5.ref: type = name_ref Extra5, file.%Extra5.decl [template = constants.%Extra5.type] +// CHECK:STDOUT: %Extra6.ref: type = name_ref Extra6, file.%Extra6.decl [template = constants.%Extra6.type] +// CHECK:STDOUT: %Extra7.ref: type = name_ref Extra7, file.%Extra7.decl [template = constants.%Extra7.type] +// CHECK:STDOUT: %Extra8.ref: type = name_ref Extra8, file.%Extra8.decl [template = constants.%Extra8.type] +// CHECK:STDOUT: %.loc16_71: %tuple.type.1 = tuple_literal (%Extra1.ref, %Extra2.ref, %Extra3.ref, %Extra4.ref, %Extra5.ref, %Extra6.ref, %Extra7.ref, %Extra8.ref) +// CHECK:STDOUT: %.loc16_7: type = converted %.loc16_71, constants.%tuple.type.2 [template = constants.%tuple.type.2] +// CHECK:STDOUT: %C: type = class_type @C, @C(constants.%tuple.type.2) [template = constants.%C.3] +// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%I.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra1 { +// CHECK:STDOUT: %Self: %Extra1.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra2 { +// CHECK:STDOUT: %Self: %Extra2.type = 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 @Extra3 { +// CHECK:STDOUT: %Self: %Extra3.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.3] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra4 { +// CHECK:STDOUT: %Self: %Extra4.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra5 { +// CHECK:STDOUT: %Self: %Extra5.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.5] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra6 { +// CHECK:STDOUT: %Self: %Extra6.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra7 { +// CHECK:STDOUT: %Self: %Extra7.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.7] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra8 { +// CHECK:STDOUT: %Self: %Extra8.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.8] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I { +// CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.9] +// CHECK:STDOUT: %F.decl: %F.type.1 = fn_decl @F.1 [template = constants.%F.1] {} {} +// CHECK:STDOUT: %.loc14: %.3 = assoc_entity element0, %F.decl [template = constants.%.4] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = %.loc14 +// CHECK:STDOUT: witness = (%F.decl) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: %C as %I.ref { +// CHECK:STDOUT: %F.decl: %F.type.2 = fn_decl @F.2 [template = constants.%F.2] {} {} +// CHECK:STDOUT: %.loc16_79: = interface_witness (%F.decl) [template = constants.%.5] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: witness = %.loc16_79 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @C(%T.loc13_9.1: type) { +// CHECK:STDOUT: %T.loc13_9.2: type = bind_symbolic_name T, 0 [symbolic = %T.loc13_9.2 (constants.%T)] +// CHECK:STDOUT: %T.patt.loc13_9.2: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc13_9.2 (constants.%T.patt)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %.loc13: = complete_type_witness %.1 [template = constants.%.2] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F.1(@I.%Self: %I.type) { +// CHECK:STDOUT: +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.2() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(constants.%T) { +// CHECK:STDOUT: %T.loc13_9.2 => constants.%T +// CHECK:STDOUT: %T.patt.loc13_9.2 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%Self.9) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(constants.%tuple.type.2) { +// CHECK:STDOUT: %T.loc13_9.2 => constants.%tuple.type.2 +// CHECK:STDOUT: %T.patt.loc13_9.2 => constants.%tuple.type.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%C.3) {} +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_use_has_extra_interfaces.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C.type: type = generic_class_type @C [template] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [template] +// CHECK:STDOUT: %C.1: %C.type = struct_value () [template] +// CHECK:STDOUT: %.1: type = struct_type {} [template] +// CHECK:STDOUT: %.2: = complete_type_witness %.1 [template] +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %C.2: type = class_type @C, @C(%T) [symbolic] +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %C.3: type = class_type @C, @C(type) [template] +// CHECK:STDOUT: %Test.type: type = fn_type @Test [template] +// CHECK:STDOUT: %Test: %Test.type = struct_value () [template] +// CHECK:STDOUT: %.3: type = ptr_type %.1 [template] +// CHECK:STDOUT: %I.type: type = facet_type <@I> [template] +// CHECK:STDOUT: %Self.1: %I.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %.4: type = assoc_entity_type %I.type, %F.type [template] +// CHECK:STDOUT: %.5: %.4 = assoc_entity element0, imports.%import_ref.7 [template] +// CHECK:STDOUT: %Extra8.type: type = facet_type <@Extra8> [template] +// CHECK:STDOUT: %Self.2: %Extra8.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra7.type: type = facet_type <@Extra7> [template] +// CHECK:STDOUT: %Self.3: %Extra7.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra6.type: type = facet_type <@Extra6> [template] +// CHECK:STDOUT: %Self.4: %Extra6.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra5.type: type = facet_type <@Extra5> [template] +// CHECK:STDOUT: %Self.5: %Extra5.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra4.type: type = facet_type <@Extra4> [template] +// CHECK:STDOUT: %Self.6: %Extra4.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra3.type: type = facet_type <@Extra3> [template] +// CHECK:STDOUT: %Self.7: %Extra3.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra2.type: type = facet_type <@Extra2> [template] +// CHECK:STDOUT: %Self.8: %Extra2.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Extra1.type: type = facet_type <@Extra1> [template] +// CHECK:STDOUT: %Self.9: %Extra1.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %tuple.type: type = tuple_type (%Extra1.type, %Extra2.type, %Extra3.type, %Extra4.type, %Extra5.type, %Extra6.type, %Extra7.type, %Extra8.type) [template] +// CHECK:STDOUT: %C.4: type = class_type @C, @C(%tuple.type) [template] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %HasExtraInterfaces: = namespace file.%HasExtraInterfaces.import, [template] { +// CHECK:STDOUT: .C = %import_ref.1 +// CHECK:STDOUT: .I = %import_ref.3 +// CHECK:STDOUT: import HasExtraInterfaces//default +// CHECK:STDOUT: } +// CHECK:STDOUT: %import_ref.1: %C.type = import_ref HasExtraInterfaces//default, inst+39, loaded [template = constants.%C.1] +// CHECK:STDOUT: %import_ref.2 = import_ref HasExtraInterfaces//default, inst+45, unloaded +// CHECK:STDOUT: %import_ref.3: type = import_ref HasExtraInterfaces//default, inst+49, loaded [template = constants.%I.type] +// CHECK:STDOUT: %import_ref.4 = import_ref HasExtraInterfaces//default, inst+51, unloaded +// CHECK:STDOUT: %import_ref.5: %.4 = import_ref HasExtraInterfaces//default, inst+57, loaded [template = constants.%.5] +// CHECK:STDOUT: %import_ref.6 = import_ref HasExtraInterfaces//default, inst+53, unloaded +// CHECK:STDOUT: %import_ref.7 = import_ref HasExtraInterfaces//default, inst+53, unloaded +// CHECK:STDOUT: %import_ref.8 = import_ref HasExtraInterfaces//default, inst+31, unloaded +// CHECK:STDOUT: %import_ref.9 = import_ref HasExtraInterfaces//default, inst+27, unloaded +// CHECK:STDOUT: %import_ref.10 = import_ref HasExtraInterfaces//default, inst+23, unloaded +// CHECK:STDOUT: %import_ref.11 = import_ref HasExtraInterfaces//default, inst+19, unloaded +// CHECK:STDOUT: %import_ref.12 = import_ref HasExtraInterfaces//default, inst+15, unloaded +// CHECK:STDOUT: %import_ref.13 = import_ref HasExtraInterfaces//default, inst+11, unloaded +// CHECK:STDOUT: %import_ref.14 = import_ref HasExtraInterfaces//default, inst+7, unloaded +// CHECK:STDOUT: %import_ref.15 = import_ref HasExtraInterfaces//default, inst+3, unloaded +// CHECK:STDOUT: %import_ref.16: type = import_ref HasExtraInterfaces//default, inst+72, loaded [template = constants.%C.4] +// CHECK:STDOUT: %import_ref.17: type = import_ref HasExtraInterfaces//default, inst+74, loaded [template = constants.%I.type] +// CHECK:STDOUT: %import_ref.18 = import_ref HasExtraInterfaces//default, inst+79, unloaded +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .HasExtraInterfaces = imports.%HasExtraInterfaces +// CHECK:STDOUT: .Test = %Test.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %HasExtraInterfaces.import = import HasExtraInterfaces +// CHECK:STDOUT: %Test.decl: %Test.type = fn_decl @Test [template = constants.%Test] { +// CHECK:STDOUT: %c.patt: %C.3 = binding_pattern c +// CHECK:STDOUT: %c.param_patt: %C.3 = value_param_pattern %c.patt, runtime_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %HasExtraInterfaces.ref.loc5: = name_ref HasExtraInterfaces, imports.%HasExtraInterfaces [template = imports.%HasExtraInterfaces] +// CHECK:STDOUT: %C.ref: %C.type = name_ref C, imports.%import_ref.1 [template = constants.%C.1] +// CHECK:STDOUT: %C: type = class_type @C, @C(type) [template = constants.%C.3] +// CHECK:STDOUT: %c.param: %C.3 = value_param runtime_param0 +// CHECK:STDOUT: %c: %C.3 = bind_name c, %c.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.4 +// CHECK:STDOUT: .F = imports.%import_ref.5 +// CHECK:STDOUT: witness = (imports.%import_ref.6) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra8 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.8 +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra7 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.9 +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra6 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.10 +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra5 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.11 +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra4 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.12 +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra3 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.13 +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra2 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.14 +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Extra1 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.15 +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: imports.%import_ref.16 as imports.%import_ref.17 { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = imports.%import_ref.18 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @C(constants.%T: type) { +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic = %T (constants.%T)] +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic = %T.patt (constants.%T.patt)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%import_ref.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Test(%c.param_patt: %C.3) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %c.ref: %C.3 = name_ref c, %c +// CHECK:STDOUT: %HasExtraInterfaces.ref.loc11: = name_ref HasExtraInterfaces, imports.%HasExtraInterfaces [template = imports.%HasExtraInterfaces] +// CHECK:STDOUT: %I.ref: type = name_ref I, imports.%import_ref.3 [template = constants.%I.type] +// CHECK:STDOUT: %F.ref: %.4 = name_ref F, imports.%import_ref.5 [template = constants.%.5] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F(constants.%Self.1: %I.type) { +// CHECK:STDOUT: +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(constants.%T) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %T.patt => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(type) { +// CHECK:STDOUT: %T => type +// CHECK:STDOUT: %T.patt => type +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%Self.1) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @C(constants.%tuple.type) { +// CHECK:STDOUT: %T => constants.%tuple.type +// CHECK:STDOUT: %T.patt => constants.%tuple.type +// CHECK:STDOUT: } +// CHECK:STDOUT: