diff --git a/toolchain/check/handle_impl.cpp b/toolchain/check/handle_impl.cpp index d80b0ad424843..e2ac36c33e0cd 100644 --- a/toolchain/check/handle_impl.cpp +++ b/toolchain/check/handle_impl.cpp @@ -104,7 +104,6 @@ auto HandleParseNode(Context& context, Parse::DefaultSelfImplAsId node_id) "`impl as` can only be used in a class"); context.emitter().Emit(node_id, ImplAsOutsideClass); self_type_id = SemIR::ErrorInst::SingletonTypeId; - return false; } // Build the implicit access to the enclosing `Self`. @@ -146,14 +145,14 @@ static auto ExtendImpl(Context& context, Parse::NodeId extend_node, DiagnoseExtendImplOutsideClass(context, node_id); return false; } - auto& parent_scope = context.name_scopes().Get(parent_scope_id); - // TODO: This is also valid in a mixin. if (!TryAsClassScope(context, parent_scope_id)) { DiagnoseExtendImplOutsideClass(context, node_id); return false; } + auto& parent_scope = context.name_scopes().Get(parent_scope_id); + if (params_node.has_value()) { CARBON_DIAGNOSTIC(ExtendImplForall, Error, "cannot `extend` a parameterized `impl`"); @@ -387,7 +386,8 @@ static auto BuildImplDecl(Context& context, Parse::AnyImplDeclId node_id, context.ReplaceInstBeforeConstantUse(impl_decl_id, impl_decl); // For an `extend impl` declaration, mark the impl as extending this `impl`. - if (introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) { + if (self_type_id != SemIR::ErrorInst::SingletonTypeId && + introducer.modifier_set.HasAnyOf(KeywordModifierSet::Extend)) { auto extend_node = introducer.modifier_node_id(ModifierOrder::Decl); if (impl_info.generic_id.has_value()) { SemIR::TypeId type_id = context.insts().Get(constraint_inst_id).type_id(); diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index 3a5b37a58ad9a..5931591edd884 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -84,6 +84,10 @@ auto ImplWitnessForDeclaration(Context& context, const SemIR::Impl& impl) -> SemIR::InstId { CARBON_CHECK(!impl.has_definition_started()); + if (impl.self_id == SemIR::ErrorInst::SingletonInstId) { + // When 'impl as' is invalid, the self type is an error. + return SemIR::ErrorInst::SingletonInstId; + } auto facet_type_id = context.GetTypeIdForTypeInst(impl.constraint_id); if (facet_type_id == SemIR::ErrorInst::SingletonTypeId) { return SemIR::ErrorInst::SingletonInstId; diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index 77a906c5a037b..cef737797e855 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -145,14 +145,11 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id, // constraint, the unique `interface` declaration.) auto specific_id = SemIR::SpecificId::None; - // This check comes first to avoid deduction when the witness_id is missing. - // We use an error value to indicate an error during creation of the impl, - // such as a recursive impl which will cause deduction to recurse - // infinitely. - if (!impl.witness_id.has_value() || - impl.witness_id == SemIR::ErrorInst::SingletonInstId) { - // TODO: Diagnose if the impl isn't defined yet? - return SemIR::InstId::None; + // This check comes first to avoid deduction with an invalid impl. We use an + // error value to indicate an error during creation of the impl, such as a + // recursive impl which will cause deduction to recurse infinitely. + if (impl.witness_id == SemIR::ErrorInst::SingletonInstId) { + continue; } if (impl.generic_id.has_value()) { specific_id = DeduceImplArguments(context, loc_id, impl, type_const_id, @@ -175,6 +172,10 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id, // the constraint's interfaces. continue; } + if (!impl.witness_id.has_value()) { + // TODO: Diagnose if the impl isn't defined yet? + return SemIR::InstId::None; + } LoadImportRef(context, impl.witness_id); if (specific_id.has_value()) { // We need a definition of the specific `impl` so we can access its diff --git a/toolchain/check/testdata/function/declaration/no_prelude/name_poisoning.carbon b/toolchain/check/testdata/function/declaration/no_prelude/name_poisoning.carbon index 4e5b0c02ed169..b589a7fb46229 100644 --- a/toolchain/check/testdata/function/declaration/no_prelude/name_poisoning.carbon +++ b/toolchain/check/testdata/function/declaration/no_prelude/name_poisoning.carbon @@ -311,10 +311,21 @@ interface A { class X { extend impl as A { fn F() { return; } - // CHECK:STDERR: fail_using_poisoned_name_in_impl_outside_class.carbon:[[@LINE+4]]:10: error: `impl as` can only be used in a class [ImplAsOutsideClass] + // CHECK:STDERR: fail_using_poisoned_name_in_impl_outside_class.carbon:[[@LINE+15]]:10: error: `impl as` can only be used in a class [ImplAsOutsideClass] // CHECK:STDERR: impl as B {} // CHECK:STDERR: ^~ // CHECK:STDERR: + // CHECK:STDERR: fail_using_poisoned_name_in_impl_outside_class.carbon:[[@LINE+11]]:13: error: `Core.ImplicitAs` implicitly referenced here, but package `Core` not found [CoreNotFound] + // CHECK:STDERR: impl as B {} + // CHECK:STDERR: ^ + // CHECK:STDERR: + // CHECK:STDERR: fail_using_poisoned_name_in_impl_outside_class.carbon:[[@LINE-10]]:3: error: missing implementation of B in impl of interface A [ImplMissingFunction] + // CHECK:STDERR: extend impl as A { + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_using_poisoned_name_in_impl_outside_class.carbon:[[@LINE-16]]:3: note: associated function B declared here [AssociatedFunctionHere] + // CHECK:STDERR: fn B(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: impl as B {} } } @@ -1189,9 +1200,21 @@ fn F() { // CHECK:STDOUT: %A.assoc_type: type = assoc_entity_type %A.type [template] // CHECK:STDOUT: %assoc0: %A.assoc_type = assoc_entity element0, @A.%B.decl [template] // CHECK:STDOUT: %X: type = class_type @X [template] +// CHECK:STDOUT: %impl_witness: = impl_witness () [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: file {} +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .A = %A.decl +// CHECK:STDOUT: .X = %X.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %A.decl: type = interface_decl @A [template = constants.%A.type] {} {} +// CHECK:STDOUT: %X.decl: type = class_decl @X [template = constants.%X] {} {} +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @A { // CHECK:STDOUT: %Self: %A.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] @@ -1204,21 +1227,46 @@ fn F() { // CHECK:STDOUT: witness = (%B.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: impl @impl: .inst26.loc8_15 as .inst27.loc8_18; +// CHECK:STDOUT: impl @impl.1: %Self.ref as %A.ref { +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} +// CHECK:STDOUT: %.loc25: type = converted @impl.2.%B.ref, [template = ] +// CHECK:STDOUT: impl_decl @impl.2 [template] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, [template = ] +// CHECK:STDOUT: %B.ref: %A.assoc_type = name_ref B, @A.%assoc0 [template = constants.%assoc0] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: witness = @X.%impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.2: %Self.ref as { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @X { -// CHECK:STDOUT: complete_type_witness = invalid +// CHECK:STDOUT: impl_decl @impl.1 [template] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%X [template = constants.%X] +// CHECK:STDOUT: %A.ref: type = name_ref A, file.%A.decl [template = constants.%A.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness: = impl_witness () [template = constants.%impl_witness] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%X -// CHECK:STDOUT: extend .inst27.loc8_18 +// CHECK:STDOUT: extend @impl.1.%A.ref // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: generic fn @B(@A.%Self: %A.type) { // CHECK:STDOUT: fn(); // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(); +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @B(constants.%Self) {} // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/fail_impl_as_scope.carbon b/toolchain/check/testdata/impl/fail_impl_as_scope.carbon index c930a7d038afa..1067c0c18c134 100644 --- a/toolchain/check/testdata/impl/fail_impl_as_scope.carbon +++ b/toolchain/check/testdata/impl/fail_impl_as_scope.carbon @@ -47,17 +47,39 @@ fn Function() { // CHECK:STDOUT: constants { // CHECK:STDOUT: %Simple.type: type = facet_type <@Simple> [template] // CHECK:STDOUT: %Self: %Simple.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: %F.type.e2e: type = fn_type @F.1 [template] +// CHECK:STDOUT: %F.df8: %F.type.e2e = struct_value () [template] // CHECK:STDOUT: %Simple.assoc_type: type = assoc_entity_type %Simple.type [template] // CHECK:STDOUT: %assoc0: %Simple.assoc_type = assoc_entity element0, @Simple.%F.decl [template] +// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%F.decl) [template] +// CHECK:STDOUT: %F.type.fe5: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.32d: %F.type.fe5 = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: file {} +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Simple = %Simple.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Simple.decl: type = interface_decl @Simple [template = constants.%Simple.type] {} {} +// CHECK:STDOUT: impl_decl @impl [template] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, [template = ] +// CHECK:STDOUT: %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%Simple.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%F.decl) [template = constants.%impl_witness] +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @Simple { // CHECK:STDOUT: %Self: %Simple.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] -// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} +// CHECK:STDOUT: %F.decl: %F.type.e2e = fn_decl @F.1 [template = constants.%F.df8] {} {} // CHECK:STDOUT: %assoc0: %Simple.assoc_type = assoc_entity element0, %F.decl [template = constants.%assoc0] // CHECK:STDOUT: // CHECK:STDOUT: !members: @@ -66,28 +88,64 @@ fn Function() { // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic fn @F(@Simple.%Self: %Simple.type) { +// CHECK:STDOUT: impl @impl: %Self.ref as %Simple.ref { +// CHECK:STDOUT: %F.decl: %F.type.fe5 = fn_decl @F.2 [template = constants.%F.32d] {} {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: witness = file.%impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F.1(@Simple.%Self: %Simple.type) { // CHECK:STDOUT: fn(); // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @F(constants.%Self) {} +// CHECK:STDOUT: fn @F.2() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%Self) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1() {} // CHECK:STDOUT: // CHECK:STDOUT: --- fail_function.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Simple.type: type = facet_type <@Simple> [template] // CHECK:STDOUT: %Self: %Simple.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: %F.type.e2e: type = fn_type @F.1 [template] +// CHECK:STDOUT: %F.df8: %F.type.e2e = struct_value () [template] // CHECK:STDOUT: %Simple.assoc_type: type = assoc_entity_type %Simple.type [template] // CHECK:STDOUT: %assoc0: %Simple.assoc_type = assoc_entity element0, @Simple.%F.decl [template] +// CHECK:STDOUT: %Function.type: type = fn_type @Function [template] +// CHECK:STDOUT: %Function: %Function.type = struct_value () [template] +// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%F.decl) [template] +// CHECK:STDOUT: %F.type.bc7: type = fn_type @F.2 [template] +// CHECK:STDOUT: %F.0a2: %F.type.bc7 = struct_value () [template] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: file {} +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [template] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Simple = %Simple.decl +// CHECK:STDOUT: .Function = %Function.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Simple.decl: type = interface_decl @Simple [template = constants.%Simple.type] {} {} +// CHECK:STDOUT: %Function.decl: %Function.type = fn_decl @Function [template = constants.%Function] {} {} +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @Simple { // CHECK:STDOUT: %Self: %Simple.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] -// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} +// CHECK:STDOUT: %F.decl: %F.type.e2e = fn_decl @F.1 [template = constants.%F.df8] {} {} // CHECK:STDOUT: %assoc0: %Simple.assoc_type = assoc_entity element0, %F.decl [template = constants.%assoc0] // CHECK:STDOUT: // CHECK:STDOUT: !members: @@ -96,11 +154,34 @@ fn Function() { // CHECK:STDOUT: witness = (%F.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic fn @F(@Simple.%Self: %Simple.type) { +// CHECK:STDOUT: impl @impl: %Self.ref as %Simple.ref { +// CHECK:STDOUT: %F.decl: %F.type.bc7 = fn_decl @F.2 [template = constants.%F.0a2] {} {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: witness = @Function.%impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F.1(@Simple.%Self: %Simple.type) { // CHECK:STDOUT: fn(); // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Function(); +// CHECK:STDOUT: fn @Function() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: impl_decl @impl [template] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, [template = ] +// CHECK:STDOUT: %Simple.ref: type = name_ref Simple, file.%Simple.decl [template = constants.%Simple.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%F.decl) [template = constants.%impl_witness] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F.2() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F.1(constants.%Self) {} // CHECK:STDOUT: -// CHECK:STDOUT: specific @F(constants.%Self) {} +// CHECK:STDOUT: specific @F.1() {} // CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/no_prelude/fail_extend_impl_scope.carbon b/toolchain/check/testdata/impl/no_prelude/fail_extend_impl_scope.carbon index 517bd309d519f..cdf6025d226d2 100644 --- a/toolchain/check/testdata/impl/no_prelude/fail_extend_impl_scope.carbon +++ b/toolchain/check/testdata/impl/no_prelude/fail_extend_impl_scope.carbon @@ -36,24 +36,27 @@ fn F() { library "[[@TEST_NAME]]"; interface Z { - fn Zero() -> Self; + fn Zero(); - // CHECK:STDERR: fail_extend_impl_self_interface.carbon:[[@LINE+4]]:15: error: `impl as` can only be used in a class [ImplAsOutsideClass] + // CHECK:STDERR: fail_extend_impl_self_interface.carbon:[[@LINE+11]]:15: error: `impl as` can only be used in a class [ImplAsOutsideClass] // CHECK:STDERR: extend impl as Z { // CHECK:STDERR: ^~ // CHECK:STDERR: + // CHECK:STDERR: fail_extend_impl_self_interface.carbon:[[@LINE+7]]:3: error: implementation of undefined interface Z [ImplOfUndefinedInterface] + // CHECK:STDERR: extend impl as Z { + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_extend_impl_self_interface.carbon:[[@LINE-10]]:1: note: interface is currently being defined [InterfaceUndefinedWithinDefinition] + // CHECK:STDERR: interface Z { + // CHECK:STDERR: ^~~~~~~~~~~~~ + // CHECK:STDERR: extend impl as Z { - fn Zero() -> Self { - return {}; - } + fn Zero() {} } } class Point { extend impl as Z { - fn Zero() -> Self { - return {}; - } + fn Zero() {} } } @@ -148,27 +151,133 @@ fn F() { // CHECK:STDOUT: constants { // CHECK:STDOUT: %Z.type: type = facet_type <@Z> [template] // CHECK:STDOUT: %Self: %Z.type = bind_symbolic_name Self, 0 [symbolic] -// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self [symbolic] +// CHECK:STDOUT: %Zero.type.822: type = fn_type @Zero.1 [template] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [template] +// CHECK:STDOUT: %Zero.d14: %Zero.type.822 = struct_value () [template] +// CHECK:STDOUT: %Z.assoc_type: type = assoc_entity_type %Z.type [template] +// CHECK:STDOUT: %assoc0: %Z.assoc_type = assoc_entity element0, @Z.%Zero.decl [template] +// CHECK:STDOUT: %Zero.type.db4: type = fn_type @Zero.2, @impl.1(%Self) [symbolic] +// CHECK:STDOUT: %Zero.8fb: %Zero.type.db4 = struct_value () [symbolic] +// CHECK:STDOUT: %Point: type = class_type @Point [template] +// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.2.%Zero.decl) [template] +// CHECK:STDOUT: %Zero.type.e33: type = fn_type @Zero.3 [template] +// CHECK:STDOUT: %Zero.dec: %Zero.type.e33 = struct_value () [template] +// CHECK:STDOUT: %Z.facet: %Z.type = facet_value %Point, %impl_witness [template] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [template] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [template] +// CHECK:STDOUT: %F: %F.type = struct_value () [template] +// CHECK:STDOUT: %Point.val: %Point = struct_value () [template] +// CHECK:STDOUT: %.c37: type = fn_type_with_self_type %Zero.type.822, %Z.facet [template] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: file {} +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [template] { +// CHECK:STDOUT: .Z = %Z.decl +// CHECK:STDOUT: .Point = %Point.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Z.decl: type = interface_decl @Z [template = constants.%Z.type] {} {} +// CHECK:STDOUT: %Point.decl: type = class_decl @Point [template = constants.%Point] {} {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [template = constants.%F] {} {} +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @Z { +// CHECK:STDOUT: %Self: %Z.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self] +// CHECK:STDOUT: %Zero.decl: %Zero.type.822 = fn_decl @Zero.1 [template = constants.%Zero.d14] {} {} +// CHECK:STDOUT: %assoc0: %Z.assoc_type = assoc_entity element0, %Zero.decl [template = constants.%assoc0] +// CHECK:STDOUT: impl_decl @impl.1 [template] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, [template = ] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [template = constants.%Z.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: !members: -// CHECK:STDOUT: .Self = .inst15 -// CHECK:STDOUT: .Zero = .inst32.loc4_20 -// CHECK:STDOUT: witness = invalid +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Zero = %assoc0 +// CHECK:STDOUT: witness = (%Zero.decl) // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic fn @Zero(.inst15: %Z.type) { +// CHECK:STDOUT: generic impl @impl.1(@Z.%Self: %Z.type) { +// CHECK:STDOUT: !definition: // CHECK:STDOUT: %Self: %Z.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self)] -// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self [symbolic = %Self.as_type (constants.%Self.as_type)] +// CHECK:STDOUT: %Zero.type: type = fn_type @Zero.2, @impl.1(%Self) [symbolic = %Zero.type (constants.%Zero.type.db4)] +// CHECK:STDOUT: %Zero: @impl.1.%Zero.type (%Zero.type.db4) = struct_value () [symbolic = %Zero (constants.%Zero.8fb)] // CHECK:STDOUT: -// CHECK:STDOUT: fn() -> @Zero.%Self.as_type (%Self.as_type); +// CHECK:STDOUT: impl: %Self.ref as %Z.ref { +// CHECK:STDOUT: %Zero.decl: @impl.1.%Zero.type (%Zero.type.db4) = fn_decl @Zero.2 [symbolic = @impl.1.%Zero (constants.%Zero.8fb)] {} {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Zero = %Zero.decl +// CHECK:STDOUT: witness = +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Zero(constants.%Self) { +// CHECK:STDOUT: impl @impl.2: %Self.ref as %Z.ref { +// CHECK:STDOUT: %Zero.decl: %Zero.type.e33 = fn_decl @Zero.3 [template = constants.%Zero.dec] {} {} +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Zero = %Zero.decl +// CHECK:STDOUT: witness = @Point.%impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Point { +// CHECK:STDOUT: impl_decl @impl.2 [template] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%Point [template = constants.%Point] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [template = constants.%Z.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.2.%Zero.decl) [template = constants.%impl_witness] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [template = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Point +// CHECK:STDOUT: extend @impl.2.%Z.ref +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @Zero.1(@Z.%Self: %Z.type) { +// CHECK:STDOUT: fn(); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @Zero.2(@Z.%Self: %Z.type) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Zero.3() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc32_5.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Point.ref: type = name_ref Point, file.%Point.decl [template = constants.%Point] +// CHECK:STDOUT: %.loc32_5.2: ref %Point = temporary_storage +// CHECK:STDOUT: %.loc32_5.3: init %Point = class_init (), %.loc32_5.2 [template = constants.%Point.val] +// CHECK:STDOUT: %.loc32_5.4: ref %Point = temporary %.loc32_5.2, %.loc32_5.3 +// CHECK:STDOUT: %.loc32_7: ref %Point = converted %.loc32_5.1, %.loc32_5.4 +// CHECK:STDOUT: %Zero.ref: %Z.assoc_type = name_ref Zero, @Z.%assoc0 [template = constants.%assoc0] +// CHECK:STDOUT: %impl.elem0: %.c37 = impl_witness_access constants.%impl_witness, element0 [template = constants.%Zero.dec] +// CHECK:STDOUT: %Zero.call: init %empty_tuple.type = call %impl.elem0() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Zero.1(constants.%Self) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.1(constants.%Self) { +// CHECK:STDOUT: !definition: // CHECK:STDOUT: %Self => constants.%Self -// CHECK:STDOUT: %Self.as_type => constants.%Self.as_type +// CHECK:STDOUT: %Zero.type => constants.%Zero.type.db4 +// CHECK:STDOUT: %Zero => constants.%Zero.8fb // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: specific @Zero.2(constants.%Self) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.1(%Self) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Zero.1(constants.%Z.facet) {} +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/impl/no_prelude/fail_impl_bad_type.carbon b/toolchain/check/testdata/impl/no_prelude/fail_impl_bad_type.carbon index 03a077f4f053c..0d022548e443f 100644 --- a/toolchain/check/testdata/impl/no_prelude/fail_impl_bad_type.carbon +++ b/toolchain/check/testdata/impl/no_prelude/fail_impl_bad_type.carbon @@ -22,7 +22,6 @@ impl true as I {} // CHECK:STDOUT: %I.type: type = facet_type <@I> [template] // CHECK:STDOUT: %Self: %I.type = bind_symbolic_name Self, 0 [symbolic] // CHECK:STDOUT: %true: bool = bool_literal true [template] -// CHECK:STDOUT: %impl_witness: = impl_witness () [template] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -35,7 +34,6 @@ impl true as I {} // CHECK:STDOUT: %.loc17: type = converted %true, [template = ] // CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [template = constants.%I.type] // CHECK:STDOUT: } -// CHECK:STDOUT: %impl_witness: = impl_witness () [template = constants.%impl_witness] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @I { @@ -48,6 +46,6 @@ impl true as I {} // CHECK:STDOUT: // CHECK:STDOUT: impl @impl: as %I.ref { // CHECK:STDOUT: !members: -// CHECK:STDOUT: witness = file.%impl_witness +// CHECK:STDOUT: witness = // CHECK:STDOUT: } // CHECK:STDOUT: