diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 4f04edf38128..1a69acb4eee6 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -48,6 +48,7 @@ cc_library( "subst.cpp", "type.cpp", "type_completion.cpp", + "type_structure.cpp", ], hdrs = [ "action.h", @@ -89,6 +90,7 @@ cc_library( "subst.h", "type.h", "type_completion.h", + "type_structure.h", ], deps = [ ":node_stack", diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index e158273f1a31..927595e16c58 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -4,6 +4,9 @@ #include "toolchain/check/impl_lookup.h" +#include + +#include "toolchain/base/kind_switch.h" #include "toolchain/check/deduce.h" #include "toolchain/check/diagnostic_helpers.h" #include "toolchain/check/generic.h" @@ -11,6 +14,7 @@ #include "toolchain/check/inst.h" #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" +#include "toolchain/check/type_structure.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/impl.h" #include "toolchain/sem_ir/inst.h" @@ -300,14 +304,26 @@ static auto FindWitnessInFacet( return SemIR::InstId::None; } +// Finds the best impl among all available impls that provides the +// `specific_interface` for the type in `type_const_id`, and returns a witness +// for that impl. Returns `None` if no match was found. static auto FindWitnessInImpls( Context& context, SemIR::LocId loc_id, SemIR::ConstantId query_self_const_id, const SemIR::SpecificInterface& specific_interface) -> SemIR::InstId { auto& stack = context.impl_lookup_stack(); - // TODO: Build this candidate list by matching against type structures to - // narrow it down. - llvm::SmallVector> candidate_impl_ids; + + struct CandidateImpl { + SemIR::ImplId impl_id; + SemIR::InstId loc_inst_id; + TypeStructure type_structure; + }; + + auto query_type_structure = BuildTypeStructure( + context, context.constant_values().GetInstId(query_self_const_id), + specific_interface); + + llvm::SmallVector candidate_impl_ids; for (auto [id, impl] : context.impls().enumerate()) { // If the impl's interface_id differs from the query, then this impl can not // possibly provide the queried interface. @@ -338,18 +354,38 @@ static auto FindWitnessInImpls( } CARBON_CHECK(impl.witness_id.has_value()); - candidate_impl_ids.push_back({id, impl.definition_id}); + auto type_structure = + BuildTypeStructure(context, impl.self_id, impl.interface); + if (!query_type_structure.IsCompatibleWith(type_structure)) { + continue; + } + + candidate_impl_ids.push_back( + {id, impl.definition_id, std::move(type_structure)}); } - for (auto [impl_id, loc_inst_id] : candidate_impl_ids) { - stack.back().impl_loc = loc_inst_id; + auto compare = [](auto& lhs, auto& rhs) -> bool { + // TODO: Allow Carbon code to provide a priority ordering explicitly. For + // now they have all the same priority, so the priority is the order in + // which they are found in code. + + // Sort by their type structures. Higher value in type structure comes + // first, so we use `>` comparison. + return lhs.type_structure > rhs.type_structure; + }; + // Stable sort is used so that impls that are seen first are preferred when + // they have an equal priority ordering. + std::ranges::stable_sort(candidate_impl_ids, compare); + + for (const auto& candidate : candidate_impl_ids) { + stack.back().impl_loc = candidate.loc_inst_id; // NOTE: GetWitnessIdForImpl() does deduction, which can cause new impls to // be imported, invalidating any pointer into `context.impls()`. - auto result_witness_id = GetWitnessIdForImpl( - context, loc_id, query_self_const_id, specific_interface, impl_id); - if (result_witness_id.has_value()) { - // We found a matching impl; don't keep looking for this interface. - return result_witness_id; + auto witness_id = + GetWitnessIdForImpl(context, loc_id, query_self_const_id, + specific_interface, candidate.impl_id); + if (witness_id.has_value()) { + return witness_id; } } return SemIR::InstId::None; diff --git a/toolchain/check/testdata/function/generic/deduce.carbon b/toolchain/check/testdata/function/generic/deduce.carbon index 41beae4742c2..f87d9e7686b0 100644 --- a/toolchain/check/testdata/function/generic/deduce.carbon +++ b/toolchain/check/testdata/function/generic/deduce.carbon @@ -191,6 +191,49 @@ fn CallImplicitNotDeducible() { ImplicitNotDeducible(42, {.x = 12}); } +// --- deduce_nested_generic_class.carbon +library "[[@TEST_NAME]]"; + +interface Z {} + +class EE {} +impl EE as Z {} + +class DD(E:! type) {} +impl forall [E:! type] DD(E) as Z {} + +class CC(D:! Z) {} +impl forall [E:! type] CC(DD(E)) as Z {} + +fn F() { + CC(DD(EE)) as Z; +} + +// --- deduce_nested_facet_value.carbon +library "[[@TEST_NAME]]"; + +interface Y {} +interface W {} + +// DD implements both Y and W. +class DD {} +impl DD as Y {} +impl DD as W {} + +// CC requires D to implement Y. +class CC(D:! Y) {} + +interface Z {} + +// The `D` interface provides `Y` but not `W`, so we need to see that the +// parameter to `CC` is `DD` which provides `Y & W`, not just a FacetValue +// abstractly providing `Y. +impl forall [E:! Y & W] CC(E) as Z {} + +fn F() { + (CC(DD)) as Z; +} + // CHECK:STDOUT: --- deduce_explicit.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -1456,3 +1499,510 @@ fn CallImplicitNotDeducible() { // CHECK:STDOUT: %T.patt.loc4_25.2 => constants.%T // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- deduce_nested_generic_class.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Z.type: type = facet_type <@Z> [concrete] +// CHECK:STDOUT: %Self: %Z.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %EE: type = class_type @EE [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] +// CHECK:STDOUT: %impl_witness.1bc: = impl_witness () [concrete] +// CHECK:STDOUT: %E: type = bind_symbolic_name E, 0 [symbolic] +// CHECK:STDOUT: %E.patt: type = symbolic_binding_pattern E, 0 [symbolic] +// CHECK:STDOUT: %DD.type: type = generic_class_type @DD [concrete] +// CHECK:STDOUT: %DD.generic: %DD.type = struct_value () [concrete] +// CHECK:STDOUT: %DD.296: type = class_type @DD, @DD(%E) [symbolic] +// CHECK:STDOUT: %impl_witness.d1b: = impl_witness (), @impl.266(%E) [symbolic] +// CHECK:STDOUT: %D: %Z.type = bind_symbolic_name D, 0 [symbolic] +// CHECK:STDOUT: %D.patt: %Z.type = symbolic_binding_pattern D, 0 [symbolic] +// CHECK:STDOUT: %CC.type: type = generic_class_type @CC [concrete] +// CHECK:STDOUT: %CC.generic: %CC.type = struct_value () [concrete] +// CHECK:STDOUT: %CC.a2f: type = class_type @CC, @CC(%D) [symbolic] +// CHECK:STDOUT: %Z.facet.42e: %Z.type = facet_value %DD.296, (%impl_witness.d1b) [symbolic] +// CHECK:STDOUT: %CC.379: type = class_type @CC, @CC(%Z.facet.42e) [symbolic] +// CHECK:STDOUT: %impl_witness.b93: = impl_witness (), @impl.c35(%E) [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: %DD.689: type = class_type @DD, @DD(%EE) [concrete] +// CHECK:STDOUT: %impl_witness.f62: = impl_witness (), @impl.266(%EE) [concrete] +// CHECK:STDOUT: %Z.facet.85b: %Z.type = facet_value %DD.689, (%impl_witness.f62) [concrete] +// CHECK:STDOUT: %CC.4de: type = class_type @CC, @CC(%Z.facet.85b) [concrete] +// CHECK:STDOUT: %impl_witness.baa: = impl_witness (), @impl.c35(%EE) [concrete] +// CHECK:STDOUT: %Z.facet.fb6: %Z.type = facet_value %CC.4de, (%impl_witness.baa) [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Z = %Z.decl +// CHECK:STDOUT: .EE = %EE.decl +// CHECK:STDOUT: .DD = %DD.decl +// CHECK:STDOUT: .CC = %CC.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Z.decl: type = interface_decl @Z [concrete = constants.%Z.type] {} {} +// CHECK:STDOUT: %EE.decl: type = class_decl @EE [concrete = constants.%EE] {} {} +// CHECK:STDOUT: impl_decl @impl.a6b [concrete] {} { +// CHECK:STDOUT: %EE.ref: type = name_ref EE, file.%EE.decl [concrete = constants.%EE] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness.loc6: = impl_witness () [concrete = constants.%impl_witness.1bc] +// CHECK:STDOUT: %DD.decl: %DD.type = class_decl @DD [concrete = constants.%DD.generic] { +// CHECK:STDOUT: %E.patt.loc8_10.1: type = symbolic_binding_pattern E, 0 [symbolic = %E.patt.loc8_10.2 (constants.%E.patt)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %E.loc8_10.1: type = bind_symbolic_name E, 0 [symbolic = %E.loc8_10.2 (constants.%E)] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.266 [concrete] { +// CHECK:STDOUT: %E.patt.loc9_14.1: type = symbolic_binding_pattern E, 0 [symbolic = %E.patt.loc9_14.2 (constants.%E.patt)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %DD.ref: %DD.type = name_ref DD, file.%DD.decl [concrete = constants.%DD.generic] +// CHECK:STDOUT: %E.ref: type = name_ref E, %E.loc9_14.1 [symbolic = %E.loc9_14.2 (constants.%E)] +// CHECK:STDOUT: %DD.loc9_28.1: type = class_type @DD, @DD(constants.%E) [symbolic = %DD.loc9_28.2 (constants.%DD.296)] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type] +// CHECK:STDOUT: %E.loc9_14.1: type = bind_symbolic_name E, 0 [symbolic = %E.loc9_14.2 (constants.%E)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness.loc9: = impl_witness (), @impl.266(constants.%E) [symbolic = @impl.266.%impl_witness (constants.%impl_witness.d1b)] +// CHECK:STDOUT: %CC.decl: %CC.type = class_decl @CC [concrete = constants.%CC.generic] { +// CHECK:STDOUT: %D.patt.loc11_10.1: %Z.type = symbolic_binding_pattern D, 0 [symbolic = %D.patt.loc11_10.2 (constants.%D.patt)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type] +// CHECK:STDOUT: %D.loc11_10.1: %Z.type = bind_symbolic_name D, 0 [symbolic = %D.loc11_10.2 (constants.%D)] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl.c35 [concrete] { +// CHECK:STDOUT: %E.patt.loc12_14.1: type = symbolic_binding_pattern E, 0 [symbolic = %E.patt.loc12_14.2 (constants.%E.patt)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %CC.ref: %CC.type = name_ref CC, file.%CC.decl [concrete = constants.%CC.generic] +// CHECK:STDOUT: %DD.ref: %DD.type = name_ref DD, file.%DD.decl [concrete = constants.%DD.generic] +// CHECK:STDOUT: %E.ref: type = name_ref E, %E.loc12_14.1 [symbolic = %E.loc12_14.2 (constants.%E)] +// CHECK:STDOUT: %DD.loc12_31.1: type = class_type @DD, @DD(constants.%E) [symbolic = %DD.loc12_31.2 (constants.%DD.296)] +// CHECK:STDOUT: %Z.facet.loc12_32.1: %Z.type = facet_value constants.%DD.296, (constants.%impl_witness.d1b) [symbolic = %Z.facet.loc12_32.2 (constants.%Z.facet.42e)] +// CHECK:STDOUT: %.loc12: %Z.type = converted %DD.loc12_31.1, %Z.facet.loc12_32.1 [symbolic = %Z.facet.loc12_32.2 (constants.%Z.facet.42e)] +// CHECK:STDOUT: %CC.loc12_32.1: type = class_type @CC, @CC(constants.%Z.facet.42e) [symbolic = %CC.loc12_32.2 (constants.%CC.379)] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type] +// CHECK:STDOUT: %E.loc12_14.1: type = bind_symbolic_name E, 0 [symbolic = %E.loc12_14.2 (constants.%E)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness.loc12: = impl_witness (), @impl.c35(constants.%E) [symbolic = @impl.c35.%impl_witness.loc12_39 (constants.%impl_witness.b93)] +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = 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: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.a6b: %EE.ref as %Z.ref { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = file.%impl_witness.loc6 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic impl @impl.266(%E.loc9_14.1: type) { +// CHECK:STDOUT: %E.loc9_14.2: type = bind_symbolic_name E, 0 [symbolic = %E.loc9_14.2 (constants.%E)] +// CHECK:STDOUT: %E.patt.loc9_14.2: type = symbolic_binding_pattern E, 0 [symbolic = %E.patt.loc9_14.2 (constants.%E.patt)] +// CHECK:STDOUT: %DD.loc9_28.2: type = class_type @DD, @DD(%E.loc9_14.2) [symbolic = %DD.loc9_28.2 (constants.%DD.296)] +// CHECK:STDOUT: %impl_witness: = impl_witness (), @impl.266(%E.loc9_14.2) [symbolic = %impl_witness (constants.%impl_witness.d1b)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: impl: %DD.loc9_28.1 as %Z.ref { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = file.%impl_witness.loc9 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic impl @impl.c35(%E.loc12_14.1: type) { +// CHECK:STDOUT: %E.loc12_14.2: type = bind_symbolic_name E, 0 [symbolic = %E.loc12_14.2 (constants.%E)] +// CHECK:STDOUT: %E.patt.loc12_14.2: type = symbolic_binding_pattern E, 0 [symbolic = %E.patt.loc12_14.2 (constants.%E.patt)] +// CHECK:STDOUT: %DD.loc12_31.2: type = class_type @DD, @DD(%E.loc12_14.2) [symbolic = %DD.loc12_31.2 (constants.%DD.296)] +// CHECK:STDOUT: %impl_witness.loc12_32: = impl_witness (), @impl.266(%E.loc12_14.2) [symbolic = %impl_witness.loc12_32 (constants.%impl_witness.d1b)] +// CHECK:STDOUT: %Z.facet.loc12_32.2: %Z.type = facet_value %DD.loc12_31.2, (%impl_witness.loc12_32) [symbolic = %Z.facet.loc12_32.2 (constants.%Z.facet.42e)] +// CHECK:STDOUT: %CC.loc12_32.2: type = class_type @CC, @CC(%Z.facet.loc12_32.2) [symbolic = %CC.loc12_32.2 (constants.%CC.379)] +// CHECK:STDOUT: %impl_witness.loc12_39: = impl_witness (), @impl.c35(%E.loc12_14.2) [symbolic = %impl_witness.loc12_39 (constants.%impl_witness.b93)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: impl: %CC.loc12_32.1 as %Z.ref { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = file.%impl_witness.loc12 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @EE { +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%EE +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @DD(%E.loc8_10.1: type) { +// CHECK:STDOUT: %E.loc8_10.2: type = bind_symbolic_name E, 0 [symbolic = %E.loc8_10.2 (constants.%E)] +// CHECK:STDOUT: %E.patt.loc8_10.2: type = symbolic_binding_pattern E, 0 [symbolic = %E.patt.loc8_10.2 (constants.%E.patt)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%DD.296 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @CC(%D.loc11_10.1: %Z.type) { +// CHECK:STDOUT: %D.loc11_10.2: %Z.type = bind_symbolic_name D, 0 [symbolic = %D.loc11_10.2 (constants.%D)] +// CHECK:STDOUT: %D.patt.loc11_10.2: %Z.type = symbolic_binding_pattern D, 0 [symbolic = %D.patt.loc11_10.2 (constants.%D.patt)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%CC.a2f +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %CC.ref: %CC.type = name_ref CC, file.%CC.decl [concrete = constants.%CC.generic] +// CHECK:STDOUT: %DD.ref: %DD.type = name_ref DD, file.%DD.decl [concrete = constants.%DD.generic] +// CHECK:STDOUT: %EE.ref: type = name_ref EE, file.%EE.decl [concrete = constants.%EE] +// CHECK:STDOUT: %DD: type = class_type @DD, @DD(constants.%EE) [concrete = constants.%DD.689] +// CHECK:STDOUT: %Z.facet.loc15_12: %Z.type = facet_value constants.%DD.689, (constants.%impl_witness.f62) [concrete = constants.%Z.facet.85b] +// CHECK:STDOUT: %.loc15_12: %Z.type = converted %DD, %Z.facet.loc15_12 [concrete = constants.%Z.facet.85b] +// CHECK:STDOUT: %CC: type = class_type @CC, @CC(constants.%Z.facet.85b) [concrete = constants.%CC.4de] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type] +// CHECK:STDOUT: %Z.facet.loc15_14: %Z.type = facet_value constants.%CC.4de, (constants.%impl_witness.baa) [concrete = constants.%Z.facet.fb6] +// CHECK:STDOUT: %.loc15_14: %Z.type = converted %CC, %Z.facet.loc15_14 [concrete = constants.%Z.facet.fb6] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @DD(constants.%E) { +// CHECK:STDOUT: %E.loc8_10.2 => constants.%E +// CHECK:STDOUT: %E.patt.loc8_10.2 => constants.%E +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.266(constants.%E) { +// CHECK:STDOUT: %E.loc9_14.2 => constants.%E +// CHECK:STDOUT: %E.patt.loc9_14.2 => constants.%E +// CHECK:STDOUT: %DD.loc9_28.2 => constants.%DD.296 +// CHECK:STDOUT: %impl_witness => constants.%impl_witness.d1b +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @DD(@impl.266.%E.loc9_14.2) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.266(%E.loc9_14.2) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CC(constants.%D) { +// CHECK:STDOUT: %D.loc11_10.2 => constants.%D +// CHECK:STDOUT: %D.patt.loc11_10.2 => constants.%D +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CC(constants.%Z.facet.42e) { +// CHECK:STDOUT: %D.loc11_10.2 => constants.%Z.facet.42e +// CHECK:STDOUT: %D.patt.loc11_10.2 => constants.%Z.facet.42e +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.c35(constants.%E) { +// CHECK:STDOUT: %E.loc12_14.2 => constants.%E +// CHECK:STDOUT: %E.patt.loc12_14.2 => constants.%E +// CHECK:STDOUT: %DD.loc12_31.2 => constants.%DD.296 +// CHECK:STDOUT: %impl_witness.loc12_32 => constants.%impl_witness.d1b +// CHECK:STDOUT: %Z.facet.loc12_32.2 => constants.%Z.facet.42e +// CHECK:STDOUT: %CC.loc12_32.2 => constants.%CC.379 +// CHECK:STDOUT: %impl_witness.loc12_39 => constants.%impl_witness.b93 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @DD(@impl.c35.%E.loc12_14.2) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.266(@impl.c35.%E.loc12_14.2) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CC(@impl.c35.%Z.facet.loc12_32.2) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.c35(%E.loc12_14.2) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @DD(constants.%EE) { +// CHECK:STDOUT: %E.loc8_10.2 => constants.%EE +// CHECK:STDOUT: %E.patt.loc8_10.2 => constants.%EE +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.266(constants.%EE) { +// CHECK:STDOUT: %E.loc9_14.2 => constants.%EE +// CHECK:STDOUT: %E.patt.loc9_14.2 => constants.%EE +// CHECK:STDOUT: %DD.loc9_28.2 => constants.%DD.689 +// CHECK:STDOUT: %impl_witness => constants.%impl_witness.f62 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CC(constants.%Z.facet.85b) { +// CHECK:STDOUT: %D.loc11_10.2 => constants.%Z.facet.85b +// CHECK:STDOUT: %D.patt.loc11_10.2 => constants.%Z.facet.85b +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.c35(constants.%EE) { +// CHECK:STDOUT: %E.loc12_14.2 => constants.%EE +// CHECK:STDOUT: %E.patt.loc12_14.2 => constants.%EE +// CHECK:STDOUT: %DD.loc12_31.2 => constants.%DD.689 +// CHECK:STDOUT: %impl_witness.loc12_32 => constants.%impl_witness.f62 +// CHECK:STDOUT: %Z.facet.loc12_32.2 => constants.%Z.facet.85b +// CHECK:STDOUT: %CC.loc12_32.2 => constants.%CC.4de +// CHECK:STDOUT: %impl_witness.loc12_39 => constants.%impl_witness.baa +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- deduce_nested_facet_value.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Y.type: type = facet_type <@Y> [concrete] +// CHECK:STDOUT: %Self.b29: %Y.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %W.type: type = facet_type <@W> [concrete] +// CHECK:STDOUT: %Self.f12: %W.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %DD: type = class_type @DD [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] +// CHECK:STDOUT: %impl_witness.1bc: = impl_witness () [concrete] +// CHECK:STDOUT: %D: %Y.type = bind_symbolic_name D, 0 [symbolic] +// CHECK:STDOUT: %D.patt: %Y.type = symbolic_binding_pattern D, 0 [symbolic] +// CHECK:STDOUT: %CC.type: type = generic_class_type @CC [concrete] +// CHECK:STDOUT: %CC.generic: %CC.type = struct_value () [concrete] +// CHECK:STDOUT: %CC.3ba: type = class_type @CC, @CC(%D) [symbolic] +// CHECK:STDOUT: %Z.type: type = facet_type <@Z> [concrete] +// CHECK:STDOUT: %Self.6e6: %Z.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %BitAnd.type: type = facet_type <@BitAnd> [concrete] +// CHECK:STDOUT: %Op.type.27a: type = fn_type @Op.1 [concrete] +// CHECK:STDOUT: %impl_witness.ec2: = impl_witness (imports.%Core.import_ref.d90) [concrete] +// CHECK:STDOUT: %BitAnd.facet: %BitAnd.type = facet_value type, (%impl_witness.ec2) [concrete] +// CHECK:STDOUT: %.3a2: type = fn_type_with_self_type %Op.type.27a, %BitAnd.facet [concrete] +// CHECK:STDOUT: %Op.type.c1b: type = fn_type @Op.2 [concrete] +// CHECK:STDOUT: %Op.0a6: %Op.type.c1b = struct_value () [concrete] +// CHECK:STDOUT: %Op.bound: = bound_method %Y.type, %Op.0a6 [concrete] +// CHECK:STDOUT: %facet_type: type = facet_type <@Y & @W> [concrete] +// CHECK:STDOUT: %E: %facet_type = bind_symbolic_name E, 0 [symbolic] +// CHECK:STDOUT: %E.patt: %facet_type = symbolic_binding_pattern E, 0 [symbolic] +// CHECK:STDOUT: %E.as_wit.iface0: = facet_access_witness %E, element0 [symbolic] +// CHECK:STDOUT: %E.as_type: type = facet_access_type %E [symbolic] +// CHECK:STDOUT: %Y.facet.15a: %Y.type = facet_value %E.as_type, (%E.as_wit.iface0) [symbolic] +// CHECK:STDOUT: %CC.ed1: type = class_type @CC, @CC(%Y.facet.15a) [symbolic] +// CHECK:STDOUT: %impl_witness.b63: = impl_witness (), @impl.0ce(%E) [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: %Y.facet.885: %Y.type = facet_value %DD, (%impl_witness.1bc) [concrete] +// CHECK:STDOUT: %CC.49f: type = class_type @CC, @CC(%Y.facet.885) [concrete] +// CHECK:STDOUT: %facet_value: %facet_type = facet_value %DD, (%impl_witness.1bc, %impl_witness.1bc) [concrete] +// CHECK:STDOUT: %impl_witness.454: = impl_witness (), @impl.0ce(%facet_value) [concrete] +// CHECK:STDOUT: %Z.facet: %Z.type = facet_value %CC.49f, (%impl_witness.454) [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .BitAnd = %Core.BitAnd +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Y = %Y.decl +// CHECK:STDOUT: .W = %W.decl +// CHECK:STDOUT: .DD = %DD.decl +// CHECK:STDOUT: .CC = %CC.decl +// CHECK:STDOUT: .Z = %Z.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Y.decl: type = interface_decl @Y [concrete = constants.%Y.type] {} {} +// CHECK:STDOUT: %W.decl: type = interface_decl @W [concrete = constants.%W.type] {} {} +// CHECK:STDOUT: %DD.decl: type = class_decl @DD [concrete = constants.%DD] {} {} +// CHECK:STDOUT: impl_decl @impl.3d7 [concrete] {} { +// CHECK:STDOUT: %DD.ref: type = name_ref DD, file.%DD.decl [concrete = constants.%DD] +// CHECK:STDOUT: %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness.loc8: = impl_witness () [concrete = constants.%impl_witness.1bc] +// CHECK:STDOUT: impl_decl @impl.e11 [concrete] {} { +// CHECK:STDOUT: %DD.ref: type = name_ref DD, file.%DD.decl [concrete = constants.%DD] +// CHECK:STDOUT: %W.ref: type = name_ref W, file.%W.decl [concrete = constants.%W.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness.loc9: = impl_witness () [concrete = constants.%impl_witness.1bc] +// CHECK:STDOUT: %CC.decl: %CC.type = class_decl @CC [concrete = constants.%CC.generic] { +// CHECK:STDOUT: %D.patt.loc12_10.1: %Y.type = symbolic_binding_pattern D, 0 [symbolic = %D.patt.loc12_10.2 (constants.%D.patt)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type] +// CHECK:STDOUT: %D.loc12_10.1: %Y.type = bind_symbolic_name D, 0 [symbolic = %D.loc12_10.2 (constants.%D)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Z.decl: type = interface_decl @Z [concrete = constants.%Z.type] {} {} +// CHECK:STDOUT: impl_decl @impl.0ce [concrete] { +// CHECK:STDOUT: %E.patt.loc19_14.1: %facet_type = symbolic_binding_pattern E, 0 [symbolic = %E.patt.loc19_14.2 (constants.%E.patt)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %CC.ref: %CC.type = name_ref CC, file.%CC.decl [concrete = constants.%CC.generic] +// CHECK:STDOUT: %E.ref: %facet_type = name_ref E, %E.loc19_14.1 [symbolic = %E.loc19_14.2 (constants.%E)] +// CHECK:STDOUT: %E.as_wit.iface0.loc19_29.1: = facet_access_witness constants.%E, element0 [symbolic = %E.as_wit.iface0.loc19_29.2 (constants.%E.as_wit.iface0)] +// CHECK:STDOUT: %E.as_type.loc19_29.1: type = facet_access_type constants.%E [symbolic = %E.as_type.loc19_29.2 (constants.%E.as_type)] +// CHECK:STDOUT: %Y.facet.loc19_29.1: %Y.type = facet_value %E.as_type.loc19_29.1, (%E.as_wit.iface0.loc19_29.1) [symbolic = %Y.facet.loc19_29.2 (constants.%Y.facet.15a)] +// CHECK:STDOUT: %.loc19_29: %Y.type = converted %E.ref, %Y.facet.loc19_29.1 [symbolic = %Y.facet.loc19_29.2 (constants.%Y.facet.15a)] +// CHECK:STDOUT: %CC.loc19_29.1: type = class_type @CC, @CC(constants.%Y.facet.15a) [symbolic = %CC.loc19_29.2 (constants.%CC.ed1)] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type] +// CHECK:STDOUT: %.loc19_20.1: type = splice_block %.loc19_20.3 [concrete = constants.%facet_type] { +// CHECK:STDOUT: %Y.ref: type = name_ref Y, file.%Y.decl [concrete = constants.%Y.type] +// CHECK:STDOUT: %W.ref: type = name_ref W, file.%W.decl [concrete = constants.%W.type] +// CHECK:STDOUT: %impl.elem0: %.3a2 = impl_witness_access constants.%impl_witness.ec2, element0 [concrete = constants.%Op.0a6] +// CHECK:STDOUT: %bound_method: = bound_method %Y.ref, %impl.elem0 [concrete = constants.%Op.bound] +// CHECK:STDOUT: %type.and: init type = call %bound_method(%Y.ref, %W.ref) [concrete = constants.%facet_type] +// CHECK:STDOUT: %.loc19_20.2: type = value_of_initializer %type.and [concrete = constants.%facet_type] +// CHECK:STDOUT: %.loc19_20.3: type = converted %type.and, %.loc19_20.2 [concrete = constants.%facet_type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %E.loc19_14.1: %facet_type = bind_symbolic_name E, 0 [symbolic = %E.loc19_14.2 (constants.%E)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness.loc19: = impl_witness (), @impl.0ce(constants.%E) [symbolic = @impl.0ce.%impl_witness (constants.%impl_witness.b63)] +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Y { +// CHECK:STDOUT: %Self: %Y.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.b29] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @W { +// CHECK:STDOUT: %Self: %W.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.f12] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Z { +// CHECK:STDOUT: %Self: %Z.type = bind_symbolic_name Self, 0 [symbolic = constants.%Self.6e6] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: witness = () +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.3d7: %DD.ref as %Y.ref { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = file.%impl_witness.loc8 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl.e11: %DD.ref as %W.ref { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = file.%impl_witness.loc9 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic impl @impl.0ce(%E.loc19_14.1: %facet_type) { +// CHECK:STDOUT: %E.loc19_14.2: %facet_type = bind_symbolic_name E, 0 [symbolic = %E.loc19_14.2 (constants.%E)] +// CHECK:STDOUT: %E.patt.loc19_14.2: %facet_type = symbolic_binding_pattern E, 0 [symbolic = %E.patt.loc19_14.2 (constants.%E.patt)] +// CHECK:STDOUT: %E.as_wit.iface0.loc19_29.2: = facet_access_witness %E.loc19_14.2, element0 [symbolic = %E.as_wit.iface0.loc19_29.2 (constants.%E.as_wit.iface0)] +// CHECK:STDOUT: %E.as_type.loc19_29.2: type = facet_access_type %E.loc19_14.2 [symbolic = %E.as_type.loc19_29.2 (constants.%E.as_type)] +// CHECK:STDOUT: %Y.facet.loc19_29.2: %Y.type = facet_value %E.as_type.loc19_29.2, (%E.as_wit.iface0.loc19_29.2) [symbolic = %Y.facet.loc19_29.2 (constants.%Y.facet.15a)] +// CHECK:STDOUT: %CC.loc19_29.2: type = class_type @CC, @CC(%Y.facet.loc19_29.2) [symbolic = %CC.loc19_29.2 (constants.%CC.ed1)] +// CHECK:STDOUT: %impl_witness: = impl_witness (), @impl.0ce(%E.loc19_14.2) [symbolic = %impl_witness (constants.%impl_witness.b63)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: impl: %CC.loc19_29.1 as %Z.ref { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = file.%impl_witness.loc19 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @DD { +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%DD +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @CC(%D.loc12_10.1: %Y.type) { +// CHECK:STDOUT: %D.loc12_10.2: %Y.type = bind_symbolic_name D, 0 [symbolic = %D.loc12_10.2 (constants.%D)] +// CHECK:STDOUT: %D.patt.loc12_10.2: %Y.type = symbolic_binding_pattern D, 0 [symbolic = %D.patt.loc12_10.2 (constants.%D.patt)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%CC.3ba +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %CC.ref: %CC.type = name_ref CC, file.%CC.decl [concrete = constants.%CC.generic] +// CHECK:STDOUT: %DD.ref: type = name_ref DD, file.%DD.decl [concrete = constants.%DD] +// CHECK:STDOUT: %Y.facet: %Y.type = facet_value constants.%DD, (constants.%impl_witness.1bc) [concrete = constants.%Y.facet.885] +// CHECK:STDOUT: %.loc22_9: %Y.type = converted %DD.ref, %Y.facet [concrete = constants.%Y.facet.885] +// CHECK:STDOUT: %CC: type = class_type @CC, @CC(constants.%Y.facet.885) [concrete = constants.%CC.49f] +// CHECK:STDOUT: %Z.ref: type = name_ref Z, file.%Z.decl [concrete = constants.%Z.type] +// CHECK:STDOUT: %facet_value: %facet_type = facet_value constants.%DD, (constants.%impl_witness.1bc, constants.%impl_witness.1bc) [concrete = constants.%facet_value] +// CHECK:STDOUT: %.loc22_12.1: %facet_type = converted constants.%DD, %facet_value [concrete = constants.%facet_value] +// CHECK:STDOUT: %Z.facet: %Z.type = facet_value constants.%CC.49f, (constants.%impl_witness.454) [concrete = constants.%Z.facet] +// CHECK:STDOUT: %.loc22_12.2: %Z.type = converted %CC, %Z.facet [concrete = constants.%Z.facet] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CC(constants.%D) { +// CHECK:STDOUT: %D.loc12_10.2 => constants.%D +// CHECK:STDOUT: %D.patt.loc12_10.2 => constants.%D +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CC(constants.%Y.facet.15a) { +// CHECK:STDOUT: %D.loc12_10.2 => constants.%Y.facet.15a +// CHECK:STDOUT: %D.patt.loc12_10.2 => constants.%Y.facet.15a +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.0ce(constants.%E) { +// CHECK:STDOUT: %E.loc19_14.2 => constants.%E +// CHECK:STDOUT: %E.patt.loc19_14.2 => constants.%E +// CHECK:STDOUT: %E.as_wit.iface0.loc19_29.2 => constants.%E.as_wit.iface0 +// CHECK:STDOUT: %E.as_type.loc19_29.2 => constants.%E.as_type +// CHECK:STDOUT: %Y.facet.loc19_29.2 => constants.%Y.facet.15a +// CHECK:STDOUT: %CC.loc19_29.2 => constants.%CC.ed1 +// CHECK:STDOUT: %impl_witness => constants.%impl_witness.b63 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CC(@impl.0ce.%Y.facet.loc19_29.2) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.0ce(%E.loc19_14.2) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @CC(constants.%Y.facet.885) { +// CHECK:STDOUT: %D.loc12_10.2 => constants.%Y.facet.885 +// CHECK:STDOUT: %D.patt.loc12_10.2 => constants.%Y.facet.885 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @impl.0ce(constants.%facet_value) { +// CHECK:STDOUT: %E.loc19_14.2 => constants.%facet_value +// CHECK:STDOUT: %E.patt.loc19_14.2 => constants.%facet_value +// CHECK:STDOUT: %E.as_wit.iface0.loc19_29.2 => constants.%impl_witness.1bc +// CHECK:STDOUT: %E.as_type.loc19_29.2 => constants.%DD +// CHECK:STDOUT: %Y.facet.loc19_29.2 => constants.%Y.facet.885 +// CHECK:STDOUT: %CC.loc19_29.2 => constants.%CC.49f +// CHECK:STDOUT: %impl_witness => constants.%impl_witness.454 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/generic/template/unimplemented.carbon b/toolchain/check/testdata/generic/template/unimplemented.carbon index 5be9098366ad..ffb0c7ba4fee 100644 --- a/toolchain/check/testdata/generic/template/unimplemented.carbon +++ b/toolchain/check/testdata/generic/template/unimplemented.carbon @@ -12,8 +12,13 @@ library "[[@TEST_NAME]]"; -// Check that we get a reasonable diagnostic for an unimplemented operation on a template dependent expression. +// Check that we get a reasonable diagnostic for an unimplemented operation on a +// template dependent expression. fn F[template T:! type](x: T) -> i32 { + // CHECK:STDERR: fail_todo_unimplemented_operator.carbon:[[@LINE+8]]:10: error: semantics TODO: `Impl lookup on template-dependent type value` [SemanticsTodo] + // CHECK:STDERR: return x.n * 3; + // CHECK:STDERR: ^~~ + // CHECK:STDERR: // CHECK:STDERR: fail_todo_unimplemented_operator.carbon:[[@LINE+4]]:10: error: cannot access member of interface `Core.Mul` in type `` that does not implement that interface [MissingImplInMemberAccess] // CHECK:STDERR: return x.n * 3; // CHECK:STDERR: ^~~~~~~ @@ -21,6 +26,29 @@ fn F[template T:! type](x: T) -> i32 { return x.n * 3; } +// --- fail_todo_unimplemented_value.carbon + +library "[[@TEST_NAME]]"; + +class C { + var n: i32; +} + +// Check that we get a reasonable diagnostic for an unimplemented operation on a +// template dependent value where the type is concrete but determined through +// the template dependent value. +fn F(template c:! C) -> i32 { + // CHECK:STDERR: fail_todo_unimplemented_value.carbon:[[@LINE+8]]:10: error: semantics TODO: `Impl lookup on template-dependent type value` [SemanticsTodo] + // CHECK:STDERR: return c.n * 3; + // CHECK:STDERR: ^~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_unimplemented_value.carbon:[[@LINE+4]]:10: error: cannot access member of interface `Core.Mul` in type `` that does not implement that interface [MissingImplInMemberAccess] + // CHECK:STDERR: return c.n * 3; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + return c.n * 3; +} + // --- fail_todo_unimplemented_convert.carbon library "[[@TEST_NAME]]"; @@ -75,46 +103,129 @@ fn F[template T:! type](x: T) { // CHECK:STDOUT: } // CHECK:STDOUT: %Core.import = import Core // CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] { -// CHECK:STDOUT: %T.patt.loc5_15.1: type = symbolic_binding_pattern T, 0, template [template = %T.patt.loc5_15.2 (constants.%T.patt)] -// CHECK:STDOUT: %x.patt: @F.%T.loc5_15.2 (%T) = binding_pattern x -// CHECK:STDOUT: %x.param_patt: @F.%T.loc5_15.2 (%T) = value_param_pattern %x.patt, call_param0 +// CHECK:STDOUT: %T.patt.loc6_15.1: type = symbolic_binding_pattern T, 0, template [template = %T.patt.loc6_15.2 (constants.%T.patt)] +// CHECK:STDOUT: %x.patt: @F.%T.loc6_15.2 (%T) = binding_pattern x +// CHECK:STDOUT: %x.param_patt: @F.%T.loc6_15.2 (%T) = value_param_pattern %x.patt, call_param0 // CHECK:STDOUT: %return.patt: %i32 = return_slot_pattern // CHECK:STDOUT: %return.param_patt: %i32 = out_param_pattern %return.patt, call_param1 // CHECK:STDOUT: } { // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] -// CHECK:STDOUT: %T.loc5_15.1: type = bind_symbolic_name T, 0, template [template = %T.loc5_15.2 (constants.%T)] -// CHECK:STDOUT: %x.param: @F.%T.loc5_15.2 (%T) = value_param call_param0 -// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc5_15.1 [template = %T.loc5_15.2 (constants.%T)] -// CHECK:STDOUT: %x: @F.%T.loc5_15.2 (%T) = bind_name x, %x.param +// CHECK:STDOUT: %T.loc6_15.1: type = bind_symbolic_name T, 0, template [template = %T.loc6_15.2 (constants.%T)] +// CHECK:STDOUT: %x.param: @F.%T.loc6_15.2 (%T) = value_param call_param0 +// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc6_15.1 [template = %T.loc6_15.2 (constants.%T)] +// CHECK:STDOUT: %x: @F.%T.loc6_15.2 (%T) = bind_name x, %x.param // CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 // CHECK:STDOUT: %return: ref %i32 = return_slot %return.param // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic fn @F(%T.loc5_15.1: type) { -// CHECK:STDOUT: %T.loc5_15.2: type = bind_symbolic_name T, 0, template [template = %T.loc5_15.2 (constants.%T)] -// CHECK:STDOUT: %T.patt.loc5_15.2: type = symbolic_binding_pattern T, 0, template [template = %T.patt.loc5_15.2 (constants.%T.patt)] +// CHECK:STDOUT: generic fn @F(%T.loc6_15.1: type) { +// CHECK:STDOUT: %T.loc6_15.2: type = bind_symbolic_name T, 0, template [template = %T.loc6_15.2 (constants.%T)] +// CHECK:STDOUT: %T.patt.loc6_15.2: type = symbolic_binding_pattern T, 0, template [template = %T.patt.loc6_15.2 (constants.%T.patt)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: -// CHECK:STDOUT: %require_complete: = require_complete_type @F.%T.loc5_15.2 (%T) [template = %require_complete (constants.%require_complete.4ae)] -// CHECK:STDOUT: %.loc10_11.3: = refine_type_action %x.ref, @F.%T.loc5_15.2 (%T) [template] -// CHECK:STDOUT: %.loc10_11.4: = access_member_action %.loc10_11.1, n [template] -// CHECK:STDOUT: %.loc10_11.5: type = type_of_inst %.loc10_11.4 [template] +// CHECK:STDOUT: %require_complete: = require_complete_type @F.%T.loc6_15.2 (%T) [template = %require_complete (constants.%require_complete.4ae)] +// CHECK:STDOUT: %.loc15_11.3: = refine_type_action %x.ref, @F.%T.loc6_15.2 (%T) [template] +// CHECK:STDOUT: %.loc15_11.4: = access_member_action %.loc15_11.1, n [template] +// CHECK:STDOUT: %.loc15_11.5: type = type_of_inst %.loc15_11.4 [template] // CHECK:STDOUT: -// CHECK:STDOUT: fn[%T.patt.loc5_15.1: type](%x.param_patt: @F.%T.loc5_15.2 (%T)) -> %i32 { +// CHECK:STDOUT: fn[%T.patt.loc6_15.1: type](%x.param_patt: @F.%T.loc6_15.2 (%T)) -> %i32 { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %x.ref: @F.%T.loc5_15.2 (%T) = name_ref x, %x -// CHECK:STDOUT: %.loc10_11.1: @F.%T.loc5_15.2 (%T) = splice_inst %.loc10_11.3 -// CHECK:STDOUT: %.loc10_11.2: @F.%.loc10_11.5 (@F.%.loc10_11.5) = splice_inst %.loc10_11.4 +// CHECK:STDOUT: %x.ref: @F.%T.loc6_15.2 (%T) = name_ref x, %x +// CHECK:STDOUT: %.loc15_11.1: @F.%T.loc6_15.2 (%T) = splice_inst %.loc15_11.3 +// CHECK:STDOUT: %.loc15_11.2: @F.%.loc15_11.5 (@F.%.loc15_11.5) = splice_inst %.loc15_11.4 // CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3] // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @F(constants.%T) { -// CHECK:STDOUT: %T.loc5_15.2 => constants.%T -// CHECK:STDOUT: %T.patt.loc5_15.2 => constants.%T +// CHECK:STDOUT: %T.loc6_15.2 => constants.%T +// CHECK:STDOUT: %T.patt.loc6_15.2 => constants.%T +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_unimplemented_value.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %C.elem: type = unbound_element_type %C, %i32 [concrete] +// CHECK:STDOUT: %struct_type.n: type = struct_type {.n: %i32} [concrete] +// CHECK:STDOUT: %complete_type.54b: = complete_type_witness %struct_type.n [concrete] +// CHECK:STDOUT: %c: %C = bind_symbolic_name c, 0, template [template] +// CHECK:STDOUT: %c.patt: %C = symbolic_binding_pattern c, 0, template [template] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Int = %Core.Int +// CHECK:STDOUT: .Mul = %Core.Mul +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] { +// CHECK:STDOUT: %c.patt.loc11_15.1: %C = symbolic_binding_pattern c, 0, template [template = %c.patt.loc11_15.2 (constants.%c.patt)] +// CHECK:STDOUT: %return.patt: %i32 = return_slot_pattern +// CHECK:STDOUT: %return.param_patt: %i32 = out_param_pattern %return.patt, call_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %c.loc11_15.1: %C = bind_symbolic_name c, 0, template [template = %c.loc11_15.2 (constants.%c)] +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param0 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @C { +// CHECK:STDOUT: %.loc5_8: %C.elem = field_decl n, element0 [concrete] +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %.loc5_3: %C.elem = var_pattern %.loc5_8 +// CHECK:STDOUT: } +// CHECK:STDOUT: %.var: ref %C.elem = var +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.n [concrete = constants.%complete_type.54b] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%C +// CHECK:STDOUT: .n = %.loc5_8 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F(%c.loc11_15.1: %C) { +// CHECK:STDOUT: %c.loc11_15.2: %C = bind_symbolic_name c, 0, template [template = %c.loc11_15.2 (constants.%c)] +// CHECK:STDOUT: %c.patt.loc11_15.2: %C = symbolic_binding_pattern c, 0, template [template = %c.patt.loc11_15.2 (constants.%c.patt)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %.loc20_11.2: = access_member_action %c.ref, n [template] +// CHECK:STDOUT: %.loc20_11.3: type = type_of_inst %.loc20_11.2 [template] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%c.patt.loc11_15.1: %C) -> %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %c.ref: %C = name_ref c, %c.loc11_15.1 [template = %c.loc11_15.2 (constants.%c)] +// CHECK:STDOUT: %.loc20_11.1: @F.%.loc20_11.3 (@F.%.loc20_11.3) = splice_inst %.loc20_11.2 +// CHECK:STDOUT: %int_3: Core.IntLiteral = int_value 3 [concrete = constants.%int_3] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%c) { +// CHECK:STDOUT: %c.loc11_15.2 => constants.%c +// CHECK:STDOUT: %c.patt.loc11_15.2 => constants.%c // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- fail_todo_unimplemented_convert.carbon diff --git a/toolchain/check/testdata/impl/lookup/min_prelude/impl_cycle.carbon b/toolchain/check/testdata/impl/lookup/min_prelude/impl_cycle.carbon index 33d5cccde808..9b8d9e0406b4 100644 --- a/toolchain/check/testdata/impl/lookup/min_prelude/impl_cycle.carbon +++ b/toolchain/check/testdata/impl/lookup/min_prelude/impl_cycle.carbon @@ -19,36 +19,48 @@ interface Z {} // This creates a dependency cycle with itself. impl forall [T:! Z] T as Z {} -class Point { - impl as Z {} -} +class Point {} fn F() { - // CHECK:STDERR: fail_impl_simple_cycle.carbon:[[@LINE+7]]:21: error: cycle found in search for impl of `Z` for type `Point` [ImplLookupCycle] - // CHECK:STDERR: ({} as Point) as (Point as Z); - // CHECK:STDERR: ^~~~~~~~~~ - // CHECK:STDERR: fail_impl_simple_cycle.carbon:[[@LINE-10]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // TODO: We should just get one diagnostic here, either the conversion fails + // with a note about the cycle as the reason for impl lookup failing, or the + // cycle causes an error so the conversion is not diagnosed. + + // CHECK:STDERR: fail_impl_simple_cycle.carbon:[[@LINE+14]]:3: error: cycle found in search for impl of `Z` for type `Point` [ImplLookupCycle] + // CHECK:STDERR: Point as Z; + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: fail_impl_simple_cycle.carbon:[[@LINE-12]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [T:! Z] T as Z {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: - ({} as Point) as (Point as Z); + // CHECK:STDERR: fail_impl_simple_cycle.carbon:[[@LINE+7]]:3: error: cannot convert type `Point` into type implementing `Z` with `as` [ConversionFailureTypeToFacet] + // CHECK:STDERR: Point as Z; + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: fail_impl_simple_cycle.carbon:[[@LINE+4]]:3: note: type `type` does not implement interface `Core.As(Z)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: Point as Z; + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: + Point as Z; } // --- todo_fail_impl_simple_where_cycle.carbon library "[[@TEST_NAME]]"; +interface Y {} interface Z {} // This creates a dependency cycle with itself. impl forall [T:! type where .Self impls Z] T as Z {} +// TODO: Remove these two when the above impl can match Point as the self type +// (and makes a cycle). +impl forall [T:! Y] T as Z {} +impl forall [T:! type] T as Y {} -class Point { - impl as Z {} -} +class Point {} fn F() { // TODO: A cycle should be found in the `impl forall T as Z` above. - ({} as Point) as (Point as Z); + Point as Z; } // --- fail_impl_simple_two_interfaces.carbon @@ -60,20 +72,24 @@ interface Y {} // This creates a dependency cycle with itself. impl forall [T:! Z & Y] T as Z {} -class Point { - impl as Z {} -} +class Point {} fn F() { - // TODO: A cycle should be found in the `impl forall T as Z` above. - // CHECK:STDERR: fail_impl_simple_two_interfaces.carbon:[[@LINE+7]]:21: error: cycle found in search for impl of `Z & Y` for type `Point` [ImplLookupCycle] - // CHECK:STDERR: ({} as Point) as (Point as Z); - // CHECK:STDERR: ^~~~~~~~~~ - // CHECK:STDERR: fail_impl_simple_two_interfaces.carbon:[[@LINE-11]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // CHECK:STDERR: fail_impl_simple_two_interfaces.carbon:[[@LINE+14]]:3: error: cycle found in search for impl of `Z & Y` for type `Point` [ImplLookupCycle] + // CHECK:STDERR: Point as Z; + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: fail_impl_simple_two_interfaces.carbon:[[@LINE-8]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [T:! Z & Y] T as Z {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: - ({} as Point) as (Point as Z); + // CHECK:STDERR: fail_impl_simple_two_interfaces.carbon:[[@LINE+7]]:3: error: cannot convert type `Point` into type implementing `Z` with `as` [ConversionFailureTypeToFacet] + // CHECK:STDERR: Point as Z; + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: fail_impl_simple_two_interfaces.carbon:[[@LINE+4]]:3: note: type `type` does not implement interface `Core.As(Z)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: Point as Z; + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: + Point as Z; } // --- fail_impl_long_cycle.carbon @@ -89,23 +105,29 @@ impl forall [T:! Y] T as Z {} impl forall [T:! Z] T as X {} class C {} -impl C as Z {} fn F() { - // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE+13]]:17: error: cycle found in search for impl of `Z` for type `C` [ImplLookupCycle] - // CHECK:STDERR: ({} as C) as (C as Z); - // CHECK:STDERR: ^~~~~~ - // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE-10]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE+20]]:3: error: cycle found in search for impl of `Z` for type `C` [ImplLookupCycle] + // CHECK:STDERR: C as Z; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE-9]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [T:! Y] T as Z {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE-14]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE-13]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [T:! X] T as Y {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE-15]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE-14]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [T:! Z] T as X {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: - ({} as C) as (C as Z); + // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE+7]]:3: error: cannot convert type `C` into type implementing `Z` with `as` [ConversionFailureTypeToFacet] + // CHECK:STDERR: C as Z; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_impl_long_cycle.carbon:[[@LINE+4]]:3: note: type `type` does not implement interface `Core.As(Z)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: C as Z; + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: + C as Z; } // --- fail_impl_cycle_one_generic_param.carbon @@ -119,7 +141,6 @@ impl forall [U:! type, T:! ComparableWith(U)] class C {} class D {} -impl C as ComparableWith(D) {} fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {} @@ -127,7 +148,7 @@ fn F() { // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+20]]:3: error: cycle found in search for impl of `ComparableWith(C)` for type `C` [ImplLookupCycle] // CHECK:STDERR: Compare({} as C, {} as C); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-13]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-12]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [U:! type, T:! ComparableWith(U)] // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-9]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] @@ -146,31 +167,51 @@ fn F() { // CHECK:STDERR: Compare({} as C, {} as C); - // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+13]]:3: error: cycle found in search for impl of `ComparableWith(C)` for type `D` [ImplLookupCycle] + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+23]]:3: error: cycle found in search for impl of `ComparableWith(C)` for type `D` [ImplLookupCycle] // CHECK:STDERR: Compare({} as C, {} as D); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-35]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-34]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [U:! type, T:! ComparableWith(U)] // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-38]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-37]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [U:! type, T:! ComparableWith(U)] // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-34]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] // CHECK:STDERR: fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+10]]:3: error: cannot implicitly convert type `D` into type implementing `ComparableWith(C)` [ConversionFailureTypeToFacet] + // CHECK:STDERR: Compare({} as C, {} as D); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+7]]:3: note: type `type` does not implement interface `Core.ImplicitAs(ComparableWith(C))` [MissingImplInMemberAccessNote] + // CHECK:STDERR: Compare({} as C, {} as D); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-44]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: Compare({} as C, {} as D); - // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+13]]:3: error: cycle found in search for impl of `ComparableWith(D)` for type `C` [ImplLookupCycle] + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+23]]:3: error: cycle found in search for impl of `ComparableWith(D)` for type `C` [ImplLookupCycle] // CHECK:STDERR: Compare({} as D, {} as C); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-50]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-59]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [U:! type, T:! ComparableWith(U)] // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-53]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-62]]:1: note: determining if this impl clause matches [ImplLookupCycleNote] // CHECK:STDERR: impl forall [U:! type, T:! ComparableWith(U)] // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-49]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-59]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+10]]:3: error: cannot implicitly convert type `C` into type implementing `ComparableWith(D)` [ConversionFailureTypeToFacet] + // CHECK:STDERR: Compare({} as D, {} as C); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE+7]]:3: note: type `type` does not implement interface `Core.ImplicitAs(ComparableWith(D))` [MissingImplInMemberAccessNote] + // CHECK:STDERR: Compare({} as D, {} as C); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_impl_cycle_one_generic_param.carbon:[[@LINE-69]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] // CHECK:STDERR: fn Compare[T:! type, U:! ComparableWith(T)](t: T, u: U) {} // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: diff --git a/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon b/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon new file mode 100644 index 000000000000..a73e0646dd3d --- /dev/null +++ b/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon @@ -0,0 +1,307 @@ +// 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 +// +// INCLUDE-FILE: toolchain/testing/min_prelude/facet_types.carbon +// EXTRA-ARGS: --no-dump-sem-ir --custom-core +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon + +// --- specialized_self_first.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +class C {} +impl C as Z(C) where .X = C {} + +impl forall [T:! type] T as Z(T) where .X = () {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket impl + // of `Z(T)`. If the blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here. + let a: C.(Z(C).X) = {} as C; +} + +// --- specialized_self_second.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +impl forall [T:! type] T as Z(T) where .X = () {} + +class C {} +impl C as Z(C) where .X = C {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket impl + // of `Z(T)`. If the blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here. + let a: C.(Z(C).X) = {} as C; +} + +// --- specialized_constraint_first.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +class C {} + +impl C as Z(C) where .X = C {} +impl forall [T:! type] C as Z(T) where .X = () {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket impl + // of `Z(T)`. If the blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here. + let a: C.(Z(C).X) = {} as C; +} + +// --- specialized_constraint_second.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +class C {} + +impl forall [T:! type] C as Z(T) where .X = () {} +impl C as Z(C) where .X = C {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket impl + // of `Z(T)`. If the blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here. + let a: C.(Z(C).X) = {} as C; +} + +// --- specialized_self_vs_constraint_self_first.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +class C(T:! type) {} + +impl forall [T:! type] C(()) as Z(T) where .X = C(()) {} +impl forall [T:! type] C(T) as Z(C(())) where .X = () {} + +fn F() { + // The specialization of `C(())` should match in preference to the blanket impl + // of `C(T)`. If the blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here. + let a: C(()).(Z(C(())).X) = {} as C(()); +} + +// --- specialized_self_vs_constraint_self_second.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +class C(T:! type) {} + +impl forall [T:! type] C(T) as Z(C(())) where .X = () {} +impl forall [T:! type] C(()) as Z(T) where .X = C(()) {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket impl + // of `Z(T)`. If the blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here. + let a: C(()).(Z(C(())).X) = {} as C(()); +} + +// --- generic_class_with_fully_specified_impl.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +impl forall [T:! type] T as Z(T) where .X = {.a: ()} {} + +class C(T:! type) {} +impl C(()) as Z(()) where .X = C(()) {} + +impl forall [T:! type] C(T) as Z(T) where .X = {.b: ()} {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket + // impls of `Z(T)`. If a blanket impl is chosen, then `a` will have a struct + // type which will fail to typecheck here when constructed from a `C` value. + let a: C(()).(Z(()).X) = {} as C(()); +} + +// --- generic_class_with_blanket_impl_first.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +class C(T:! type) {} + +impl forall [T:! type] C(T) as Z(T) where .X = C(()) {} + +impl forall [T:! type] T as Z(T) where .X = () {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket + // impls of `Z(T)`. If a blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here when constructed from a `C` value. + let a: C(()).(Z(()).X) = {} as C(()); +} + +// --- generic_class_with_blanket_impl_second.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +impl forall [T:! type] T as Z(T) where .X = () {} + +class C(T:! type) {} + +impl forall [T:! type] C(T) as Z(T) where .X = C(()) {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket + // impls of `Z(T)`. If a blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here when constructed from a `C` value. + // + // TODO: C(T) is C(()) so this should work? + let a: C(()).(Z(()).X) = {} as C(()); +} + +// --- specialized_class_with_facet_value_param.carbon +library "[[@TEST_NAME]]"; + +interface Z { + let X:! type; +} + +class D(T:! type) {} +impl forall [T:! type] D(T) as Z where .X = D(()) {} + +class E {} +impl E as Z where .X = () {} + +class C(T:! Z, U:! Z) {} + +// This places a FacetValue of type FacetType(Z) at the position of `D` in the +// self type, because the class C requires a facet value satisfying Z. It tests +// that we correctly determine that this FacetType is not symbolic, and look at +// the parametes of D for symbolic references. +impl forall [T:! Z] C(T, D(E)) as Z where .X = () {} +impl forall [T:! Z] C(D(T), T) as Z where .X = () {} +// This is the best match, `T` is in the last position compared to the others. +impl forall [T:! Z] C(D(E), T) as Z where .X = C(E, E) {} +impl forall [T:! Z] C(T, T) as Z where .X = () {} + +fn F() { + let a: C(D(E), D(E)).(Z.X) = {} as C(E, E); +} + +// --- specialized_class_with_symbolic_facet_value_param.carbon + +interface Z { + let X:! type; +} + +impl forall [T:! type] T as Z where .X = T {} + +interface Y {} +class C(T:! Y) {} + +class D {} +impl D as Y {} + +// D can be either a concrete or symbolic FacetValue, depending on what the +// caller has. +impl forall [D:! Y] C(D) as Z where .X = () {} + +fn F[D:! Y](d: D) { + // The FacetValue deduced for the param of `C` will be a symbolic FacetValue + // because we are in a generic where `D` is an unknown type, which will cause + // the query and impl self type to be C(FacetValue) for a symbolic FacetValue. + // + // TODO: The type of `.X` should actually be symbolic here, unless the impl is + // effectively final (since the lookup query uses a symbolic `D` in its + // input). But we don't have support for either of those yet. + let a: C(D).(Z.X) = (); +} + +// --- pointer_specialization_first.carbon +library "[[@TEST_NAME]]"; + +interface Z { + let X:! type; +} + +class C {} +impl C* as Z where .X = C {} + +impl forall [T:! type] T* as Z where .X = () {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket impl + // of `Z(T)`. If the blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here. + let a: (C*).(Z.X) = {} as C; +} + +// --- pointer_specialization_second.carbon +library "[[@TEST_NAME]]"; + +interface Z { + let X:! type; +} + +impl forall [T:! type] T* as Z where .X = () {} + +class C {} +impl C* as Z where .X = C {} + +fn F() { + // The specialization of `Z(C)` should match in preference to the blanket impl + // of `Z(T)`. If the blanket impl is chosen, then `a` will have type `()` + // which will fail to typecheck here. + let a: (C*).(Z.X) = {} as C; +} + +// --- cycle_in_deduce_avoided_by_specialization.carbon +library "[[@TEST_NAME]]"; + +interface Z { + let X:! type; +} + +class C(T:! type) {} + +// This impl makes a cycle, but it's not considered at all for `C(())` since +// there is another impl with a better type structure, so no diagnostic is +// emitted. +impl forall [T:! Z] T as Z where .X = () {} +// Also a cycle, and also a worse match for `C(())`. +impl forall [T:! Z] C(T) as Z where .X = () {} + +impl C(()) as Z where .X = C(()) {} + +fn F() { + let a: C(()).(Z.X) = {} as C(()); +} diff --git a/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon b/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon index 86edc3d49869..6bbc365f5196 100644 --- a/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon +++ b/toolchain/check/testdata/impl/lookup/no_prelude/import.carbon @@ -155,6 +155,35 @@ fn M() { obj.(PackageHasParam.Y.K)(); } +// --- has_generic_class.carbon + +package PackageGenericClass; + +import PackageHasParam; + +class GenericClass(U:! type) {} + +impl PackageHasParam.AnyParam(GenericClass) as PackageHasParam.Y { + fn K[self: Self]() {} +} + +fn L() { + var obj: PackageHasParam.AnyParam(GenericClass) = {}; + obj.(PackageHasParam.Y.K)(); +} + +// --- use_generic_class_as_param.carbon + +library "[[@TEST_NAME]]"; + +import PackageHasParam; +import PackageGenericClass; + +fn M() { + var obj: PackageHasParam.AnyParam(PackageGenericClass.GenericClass) = {}; + obj.(PackageHasParam.Y.K)(); +} + // --- has_extra_interfaces.carbon package HasExtraInterfaces; @@ -1741,6 +1770,396 @@ fn Test(c: HasExtraInterfaces.C(type)) { // CHECK:STDOUT: %Self.as_type => constants.%Self.as_type // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- has_generic_class.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %U: type = bind_symbolic_name U, 0 [symbolic] +// CHECK:STDOUT: %U.patt: type = symbolic_binding_pattern U, 0 [symbolic] +// CHECK:STDOUT: %GenericClass.type: type = generic_class_type @GenericClass [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %GenericClass.generic: %GenericClass.type = struct_value () [concrete] +// CHECK:STDOUT: %GenericClass: type = class_type @GenericClass, @GenericClass(%U) [symbolic] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] +// CHECK:STDOUT: %AnyParam.type: type = generic_class_type @AnyParam [concrete] +// CHECK:STDOUT: %AnyParam.generic: %AnyParam.type = struct_value () [concrete] +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %X: %T = bind_symbolic_name X, 1 [symbolic] +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %X.patt.51ccc0.2: %T = symbolic_binding_pattern X, 1 [symbolic] +// CHECK:STDOUT: %AnyParam.0dd: type = class_type @AnyParam, @AnyParam(%GenericClass.type, %GenericClass.generic) [concrete] +// CHECK:STDOUT: %Y.type: type = facet_type <@Y> [concrete] +// CHECK:STDOUT: %Self: %Y.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %K.type.311: type = fn_type @K.1 [concrete] +// CHECK:STDOUT: %K.7a1: %K.type.311 = struct_value () [concrete] +// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self [symbolic] +// CHECK:STDOUT: %require_complete: = require_complete_type %Self.as_type [symbolic] +// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%K.decl) [concrete] +// CHECK:STDOUT: %K.type.965: type = fn_type @K.2 [concrete] +// CHECK:STDOUT: %K.5a9: %K.type.965 = struct_value () [concrete] +// CHECK:STDOUT: %Y.facet: %Y.type = facet_value %AnyParam.0dd, (%impl_witness) [concrete] +// CHECK:STDOUT: %L.type: type = fn_type @L [concrete] +// CHECK:STDOUT: %L: %L.type = struct_value () [concrete] +// CHECK:STDOUT: %AnyParam.val: %AnyParam.0dd = struct_value () [concrete] +// CHECK:STDOUT: %Y.assoc_type: type = assoc_entity_type %Y.type [concrete] +// CHECK:STDOUT: %assoc0: %Y.assoc_type = assoc_entity element0, imports.%PackageHasParam.import_ref.ce2 [concrete] +// CHECK:STDOUT: %.e27: type = fn_type_with_self_type %K.type.311, %Y.facet [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %PackageHasParam: = namespace file.%PackageHasParam.import, [concrete] { +// CHECK:STDOUT: .AnyParam = %PackageHasParam.AnyParam +// CHECK:STDOUT: .Y = %PackageHasParam.Y +// CHECK:STDOUT: import PackageHasParam//default +// CHECK:STDOUT: } +// CHECK:STDOUT: %PackageHasParam.AnyParam: %AnyParam.type = import_ref PackageHasParam//default, AnyParam, loaded [concrete = constants.%AnyParam.generic] +// CHECK:STDOUT: %PackageHasParam.import_ref.5ab: type = import_ref PackageHasParam//default, loc4_16, loaded [symbolic = @AnyParam.%T (constants.%T)] +// CHECK:STDOUT: %PackageHasParam.import_ref.34c: @AnyParam.%T (%T) = import_ref PackageHasParam//default, loc4_26, loaded [symbolic = @AnyParam.%X (constants.%X)] +// CHECK:STDOUT: %PackageHasParam.import_ref.8f2: = import_ref PackageHasParam//default, loc4_34, loaded [concrete = constants.%complete_type] +// CHECK:STDOUT: %PackageHasParam.import_ref.601 = import_ref PackageHasParam//default, inst31 [no loc], unloaded +// CHECK:STDOUT: %PackageHasParam.Y: type = import_ref PackageHasParam//default, Y, loaded [concrete = constants.%Y.type] +// CHECK:STDOUT: %PackageHasParam.import_ref.dc1 = import_ref PackageHasParam//default, inst37 [no loc], unloaded +// CHECK:STDOUT: %PackageHasParam.import_ref.5e7: %Y.assoc_type = import_ref PackageHasParam//default, loc7_22, loaded [concrete = constants.%assoc0] +// CHECK:STDOUT: %PackageHasParam.K: %K.type.311 = import_ref PackageHasParam//default, K, loaded [concrete = constants.%K.7a1] +// CHECK:STDOUT: %PackageHasParam.import_ref.292: %Y.type = import_ref PackageHasParam//default, inst37 [no loc], loaded [symbolic = constants.%Self] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .PackageHasParam = imports.%PackageHasParam +// CHECK:STDOUT: .GenericClass = %GenericClass.decl +// CHECK:STDOUT: .L = %L.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %PackageHasParam.import = import PackageHasParam +// CHECK:STDOUT: %GenericClass.decl: %GenericClass.type = class_decl @GenericClass [concrete = constants.%GenericClass.generic] { +// CHECK:STDOUT: %U.patt.loc6_20.1: type = symbolic_binding_pattern U, 0 [symbolic = %U.patt.loc6_20.2 (constants.%U.patt)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %U.loc6_20.1: type = bind_symbolic_name U, 0 [symbolic = %U.loc6_20.2 (constants.%U)] +// CHECK:STDOUT: } +// CHECK:STDOUT: impl_decl @impl [concrete] {} { +// CHECK:STDOUT: %PackageHasParam.ref.loc8_6: = name_ref PackageHasParam, imports.%PackageHasParam [concrete = imports.%PackageHasParam] +// CHECK:STDOUT: %AnyParam.ref: %AnyParam.type = name_ref AnyParam, imports.%PackageHasParam.AnyParam [concrete = constants.%AnyParam.generic] +// CHECK:STDOUT: %GenericClass.ref: %GenericClass.type = name_ref GenericClass, file.%GenericClass.decl [concrete = constants.%GenericClass.generic] +// CHECK:STDOUT: %AnyParam: type = class_type @AnyParam, @AnyParam(constants.%GenericClass.type, constants.%GenericClass.generic) [concrete = constants.%AnyParam.0dd] +// CHECK:STDOUT: %PackageHasParam.ref.loc8_48: = name_ref PackageHasParam, imports.%PackageHasParam [concrete = imports.%PackageHasParam] +// CHECK:STDOUT: %Y.ref: type = name_ref Y, imports.%PackageHasParam.Y [concrete = constants.%Y.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%K.decl) [concrete = constants.%impl_witness] +// CHECK:STDOUT: %L.decl: %L.type = fn_decl @L [concrete = constants.%L] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Y [from "has_param.carbon"] { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%PackageHasParam.import_ref.dc1 +// CHECK:STDOUT: .K = imports.%PackageHasParam.import_ref.5e7 +// CHECK:STDOUT: witness = (imports.%PackageHasParam.K) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: %AnyParam as %Y.ref { +// CHECK:STDOUT: %K.decl: %K.type.965 = fn_decl @K.2 [concrete = constants.%K.5a9] { +// CHECK:STDOUT: %self.patt: %AnyParam.0dd = binding_pattern self +// CHECK:STDOUT: %self.param_patt: %AnyParam.0dd = value_param_pattern %self.patt, call_param0 +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: %AnyParam.0dd = value_param call_param0 +// CHECK:STDOUT: %Self.ref: type = name_ref Self, @impl.%AnyParam [concrete = constants.%AnyParam.0dd] +// CHECK:STDOUT: %self: %AnyParam.0dd = bind_name self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .K = %K.decl +// CHECK:STDOUT: witness = file.%impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @GenericClass(%U.loc6_20.1: type) { +// CHECK:STDOUT: %U.loc6_20.2: type = bind_symbolic_name U, 0 [symbolic = %U.loc6_20.2 (constants.%U)] +// CHECK:STDOUT: %U.patt.loc6_20.2: type = symbolic_binding_pattern U, 0 [symbolic = %U.patt.loc6_20.2 (constants.%U.patt)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%GenericClass +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @AnyParam(imports.%PackageHasParam.import_ref.5ab: type, imports.%PackageHasParam.import_ref.34c: @AnyParam.%T (%T)) [from "has_param.carbon"] { +// 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: %X: %T = bind_symbolic_name X, 1 [symbolic = %X (constants.%X)] +// CHECK:STDOUT: %X.patt: %T = symbolic_binding_pattern X, 1 [symbolic = %X.patt (constants.%X.patt.51ccc0.2)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: complete_type_witness = imports.%PackageHasParam.import_ref.8f2 +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%PackageHasParam.import_ref.601 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @K.1(imports.%PackageHasParam.import_ref.292: %Y.type) [from "has_param.carbon"] { +// CHECK:STDOUT: %Self: %Y.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: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type @K.1.%Self.as_type (%Self.as_type) [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self.param_patt: @K.1.%Self.as_type (%Self.as_type)](); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @K.2[%self.param_patt: %AnyParam.0dd]() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @L() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %obj.patt: %AnyParam.0dd = binding_pattern obj +// CHECK:STDOUT: %.loc13_3.1: %AnyParam.0dd = var_pattern %obj.patt +// CHECK:STDOUT: } +// CHECK:STDOUT: %obj.var: ref %AnyParam.0dd = var obj +// CHECK:STDOUT: %.loc13_54.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc13_54.2: init %AnyParam.0dd = class_init (), %obj.var [concrete = constants.%AnyParam.val] +// CHECK:STDOUT: %.loc13_3.2: init %AnyParam.0dd = converted %.loc13_54.1, %.loc13_54.2 [concrete = constants.%AnyParam.val] +// CHECK:STDOUT: assign %obj.var, %.loc13_3.2 +// CHECK:STDOUT: %.loc13_49: type = splice_block %AnyParam [concrete = constants.%AnyParam.0dd] { +// CHECK:STDOUT: %PackageHasParam.ref.loc13: = name_ref PackageHasParam, imports.%PackageHasParam [concrete = imports.%PackageHasParam] +// CHECK:STDOUT: %AnyParam.ref: %AnyParam.type = name_ref AnyParam, imports.%PackageHasParam.AnyParam [concrete = constants.%AnyParam.generic] +// CHECK:STDOUT: %GenericClass.ref: %GenericClass.type = name_ref GenericClass, file.%GenericClass.decl [concrete = constants.%GenericClass.generic] +// CHECK:STDOUT: %AnyParam: type = class_type @AnyParam, @AnyParam(constants.%GenericClass.type, constants.%GenericClass.generic) [concrete = constants.%AnyParam.0dd] +// CHECK:STDOUT: } +// CHECK:STDOUT: %obj: ref %AnyParam.0dd = bind_name obj, %obj.var +// CHECK:STDOUT: %obj.ref: ref %AnyParam.0dd = name_ref obj, %obj +// CHECK:STDOUT: %PackageHasParam.ref.loc14: = name_ref PackageHasParam, imports.%PackageHasParam [concrete = imports.%PackageHasParam] +// CHECK:STDOUT: %Y.ref: type = name_ref Y, imports.%PackageHasParam.Y [concrete = constants.%Y.type] +// CHECK:STDOUT: %K.ref: %Y.assoc_type = name_ref K, imports.%PackageHasParam.import_ref.5e7 [concrete = constants.%assoc0] +// CHECK:STDOUT: %impl.elem0: %.e27 = impl_witness_access constants.%impl_witness, element0 [concrete = constants.%K.5a9] +// CHECK:STDOUT: %bound_method: = bound_method %obj.ref, %impl.elem0 +// CHECK:STDOUT: %.loc14: %AnyParam.0dd = bind_value %obj.ref +// CHECK:STDOUT: %K.call: init %empty_tuple.type = call %bound_method(%.loc14) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @GenericClass(constants.%U) { +// CHECK:STDOUT: %U.loc6_20.2 => constants.%U +// CHECK:STDOUT: %U.patt.loc6_20.2 => constants.%U +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @AnyParam(constants.%T, constants.%X) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %T.patt => constants.%T +// CHECK:STDOUT: %X => constants.%X +// CHECK:STDOUT: %X.patt => constants.%X +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @AnyParam(constants.%GenericClass.type, constants.%GenericClass.generic) { +// CHECK:STDOUT: %T => constants.%GenericClass.type +// CHECK:STDOUT: %T.patt => constants.%GenericClass.type +// CHECK:STDOUT: %X => constants.%GenericClass.generic +// CHECK:STDOUT: %X.patt => constants.%GenericClass.generic +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @K.1(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: %Self.as_type => constants.%Self.as_type +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @K.1(constants.%Y.facet) { +// CHECK:STDOUT: %Self => constants.%Y.facet +// CHECK:STDOUT: %Self.as_type => constants.%AnyParam.0dd +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- use_generic_class_as_param.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %M.type: type = fn_type @M [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %M: %M.type = struct_value () [concrete] +// CHECK:STDOUT: %AnyParam.type: type = generic_class_type @AnyParam [concrete] +// CHECK:STDOUT: %AnyParam.generic: %AnyParam.type = struct_value () [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] +// CHECK:STDOUT: %T: type = bind_symbolic_name T, 0 [symbolic] +// CHECK:STDOUT: %X: %T = bind_symbolic_name X, 1 [symbolic] +// CHECK:STDOUT: %T.patt: type = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %X.patt.51ccc0.2: %T = symbolic_binding_pattern X, 1 [symbolic] +// CHECK:STDOUT: %GenericClass.type: type = generic_class_type @GenericClass [concrete] +// CHECK:STDOUT: %GenericClass.generic: %GenericClass.type = struct_value () [concrete] +// CHECK:STDOUT: %U: type = bind_symbolic_name U, 0 [symbolic] +// CHECK:STDOUT: %U.patt: type = symbolic_binding_pattern U, 0 [symbolic] +// CHECK:STDOUT: %AnyParam.d71: type = class_type @AnyParam, @AnyParam(%GenericClass.type, %GenericClass.generic) [concrete] +// CHECK:STDOUT: %AnyParam.val: %AnyParam.d71 = struct_value () [concrete] +// CHECK:STDOUT: %Y.type: type = facet_type <@Y> [concrete] +// CHECK:STDOUT: %Self: %Y.type = bind_symbolic_name Self, 0 [symbolic] +// CHECK:STDOUT: %Y.assoc_type: type = assoc_entity_type %Y.type [concrete] +// CHECK:STDOUT: %assoc0: %Y.assoc_type = assoc_entity element0, imports.%PackageHasParam.import_ref.ce2 [concrete] +// CHECK:STDOUT: %K.type.311: type = fn_type @K.1 [concrete] +// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self [symbolic] +// CHECK:STDOUT: %require_complete: = require_complete_type %Self.as_type [symbolic] +// CHECK:STDOUT: %impl_witness: = impl_witness (imports.%PackageGenericClass.import_ref.fbf) [concrete] +// CHECK:STDOUT: %Y.facet: %Y.type = facet_value %AnyParam.d71, (%impl_witness) [concrete] +// CHECK:STDOUT: %.3b2: type = fn_type_with_self_type %K.type.311, %Y.facet [concrete] +// CHECK:STDOUT: %K.type.9cf: type = fn_type @K.2 [concrete] +// CHECK:STDOUT: %K.039: %K.type.9cf = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %PackageHasParam: = namespace file.%PackageHasParam.import, [concrete] { +// CHECK:STDOUT: .AnyParam = %PackageHasParam.AnyParam +// CHECK:STDOUT: .Y = %PackageHasParam.Y +// CHECK:STDOUT: import PackageHasParam//default +// CHECK:STDOUT: } +// CHECK:STDOUT: %PackageGenericClass: = namespace file.%PackageGenericClass.import, [concrete] { +// CHECK:STDOUT: .GenericClass = %PackageGenericClass.GenericClass +// CHECK:STDOUT: import PackageGenericClass//default +// CHECK:STDOUT: } +// CHECK:STDOUT: %PackageHasParam.AnyParam: %AnyParam.type = import_ref PackageHasParam//default, AnyParam, loaded [concrete = constants.%AnyParam.generic] +// CHECK:STDOUT: %PackageHasParam.import_ref.5ab: type = import_ref PackageHasParam//default, loc4_16, loaded [symbolic = @AnyParam.%T (constants.%T)] +// CHECK:STDOUT: %PackageHasParam.import_ref.34c: @AnyParam.%T (%T) = import_ref PackageHasParam//default, loc4_26, loaded [symbolic = @AnyParam.%X (constants.%X)] +// CHECK:STDOUT: %PackageHasParam.import_ref.8f2: = import_ref PackageHasParam//default, loc4_34, loaded [concrete = constants.%complete_type] +// CHECK:STDOUT: %PackageHasParam.import_ref.601 = import_ref PackageHasParam//default, inst31 [no loc], unloaded +// CHECK:STDOUT: %PackageGenericClass.GenericClass: %GenericClass.type = import_ref PackageGenericClass//default, GenericClass, loaded [concrete = constants.%GenericClass.generic] +// CHECK:STDOUT: %PackageGenericClass.import_ref.5ab: type = import_ref PackageGenericClass//default, loc6_20, loaded [symbolic = @GenericClass.%U (constants.%U)] +// CHECK:STDOUT: %PackageGenericClass.import_ref.8f2: = import_ref PackageGenericClass//default, loc6_31, loaded [concrete = constants.%complete_type] +// CHECK:STDOUT: %PackageGenericClass.import_ref.065 = import_ref PackageGenericClass//default, inst26 [no loc], unloaded +// CHECK:STDOUT: %PackageHasParam.Y: type = import_ref PackageHasParam//default, Y, loaded [concrete = constants.%Y.type] +// CHECK:STDOUT: %PackageHasParam.import_ref.dc1 = import_ref PackageHasParam//default, inst37 [no loc], unloaded +// CHECK:STDOUT: %PackageHasParam.import_ref.5e7: %Y.assoc_type = import_ref PackageHasParam//default, loc7_22, loaded [concrete = constants.%assoc0] +// CHECK:STDOUT: %PackageHasParam.K = import_ref PackageHasParam//default, K, unloaded +// CHECK:STDOUT: %PackageHasParam.import_ref.292: %Y.type = import_ref PackageHasParam//default, inst37 [no loc], loaded [symbolic = constants.%Self] +// CHECK:STDOUT: %PackageGenericClass.import_ref.f23: = import_ref PackageGenericClass//default, loc8_66, loaded [concrete = constants.%impl_witness] +// CHECK:STDOUT: %PackageGenericClass.import_ref.a0e: type = import_ref PackageGenericClass//default, loc8_43, loaded [concrete = constants.%AnyParam.d71] +// CHECK:STDOUT: %PackageGenericClass.import_ref.ca6: type = import_ref PackageGenericClass//default, loc8_63, loaded [concrete = constants.%Y.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .PackageHasParam = imports.%PackageHasParam +// CHECK:STDOUT: .PackageGenericClass = imports.%PackageGenericClass +// CHECK:STDOUT: .M = %M.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %PackageHasParam.import = import PackageHasParam +// CHECK:STDOUT: %PackageGenericClass.import = import PackageGenericClass +// CHECK:STDOUT: %M.decl: %M.type = fn_decl @M [concrete = constants.%M] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @Y [from "has_param.carbon"] { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%PackageHasParam.import_ref.dc1 +// CHECK:STDOUT: .K = imports.%PackageHasParam.import_ref.5e7 +// CHECK:STDOUT: witness = (imports.%PackageHasParam.K) +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @impl: imports.%PackageGenericClass.import_ref.a0e as imports.%PackageGenericClass.import_ref.ca6 [from "has_generic_class.carbon"] { +// CHECK:STDOUT: !members: +// CHECK:STDOUT: witness = imports.%PackageGenericClass.import_ref.f23 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @AnyParam(imports.%PackageHasParam.import_ref.5ab: type, imports.%PackageHasParam.import_ref.34c: @AnyParam.%T (%T)) [from "has_param.carbon"] { +// 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: %X: %T = bind_symbolic_name X, 1 [symbolic = %X (constants.%X)] +// CHECK:STDOUT: %X.patt: %T = symbolic_binding_pattern X, 1 [symbolic = %X.patt (constants.%X.patt.51ccc0.2)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: complete_type_witness = imports.%PackageHasParam.import_ref.8f2 +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%PackageHasParam.import_ref.601 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic class @GenericClass(imports.%PackageGenericClass.import_ref.5ab: type) [from "has_generic_class.carbon"] { +// CHECK:STDOUT: %U: type = bind_symbolic_name U, 0 [symbolic = %U (constants.%U)] +// CHECK:STDOUT: %U.patt: type = symbolic_binding_pattern U, 0 [symbolic = %U.patt (constants.%U.patt)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: class { +// CHECK:STDOUT: complete_type_witness = imports.%PackageGenericClass.import_ref.8f2 +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = imports.%PackageGenericClass.import_ref.065 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @M() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %obj.patt: %AnyParam.d71 = binding_pattern obj +// CHECK:STDOUT: %.loc8_3.1: %AnyParam.d71 = var_pattern %obj.patt +// CHECK:STDOUT: } +// CHECK:STDOUT: %obj.var: ref %AnyParam.d71 = var obj +// CHECK:STDOUT: %.loc8_74.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_74.2: init %AnyParam.d71 = class_init (), %obj.var [concrete = constants.%AnyParam.val] +// CHECK:STDOUT: %.loc8_3.2: init %AnyParam.d71 = converted %.loc8_74.1, %.loc8_74.2 [concrete = constants.%AnyParam.val] +// CHECK:STDOUT: assign %obj.var, %.loc8_3.2 +// CHECK:STDOUT: %.loc8_69: type = splice_block %AnyParam [concrete = constants.%AnyParam.d71] { +// CHECK:STDOUT: %PackageHasParam.ref.loc8: = name_ref PackageHasParam, imports.%PackageHasParam [concrete = imports.%PackageHasParam] +// CHECK:STDOUT: %AnyParam.ref: %AnyParam.type = name_ref AnyParam, imports.%PackageHasParam.AnyParam [concrete = constants.%AnyParam.generic] +// CHECK:STDOUT: %PackageGenericClass.ref: = name_ref PackageGenericClass, imports.%PackageGenericClass [concrete = imports.%PackageGenericClass] +// CHECK:STDOUT: %GenericClass.ref: %GenericClass.type = name_ref GenericClass, imports.%PackageGenericClass.GenericClass [concrete = constants.%GenericClass.generic] +// CHECK:STDOUT: %AnyParam: type = class_type @AnyParam, @AnyParam(constants.%GenericClass.type, constants.%GenericClass.generic) [concrete = constants.%AnyParam.d71] +// CHECK:STDOUT: } +// CHECK:STDOUT: %obj: ref %AnyParam.d71 = bind_name obj, %obj.var +// CHECK:STDOUT: %obj.ref: ref %AnyParam.d71 = name_ref obj, %obj +// CHECK:STDOUT: %PackageHasParam.ref.loc9: = name_ref PackageHasParam, imports.%PackageHasParam [concrete = imports.%PackageHasParam] +// CHECK:STDOUT: %Y.ref: type = name_ref Y, imports.%PackageHasParam.Y [concrete = constants.%Y.type] +// CHECK:STDOUT: %K.ref: %Y.assoc_type = name_ref K, imports.%PackageHasParam.import_ref.5e7 [concrete = constants.%assoc0] +// CHECK:STDOUT: %impl.elem0: %.3b2 = impl_witness_access constants.%impl_witness, element0 [concrete = constants.%K.039] +// CHECK:STDOUT: %bound_method: = bound_method %obj.ref, %impl.elem0 +// CHECK:STDOUT: %.loc9: %AnyParam.d71 = bind_value %obj.ref +// CHECK:STDOUT: %K.call: init %empty_tuple.type = call %bound_method(%.loc9) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @K.1(imports.%PackageHasParam.import_ref.292: %Y.type) [from "has_param.carbon"] { +// CHECK:STDOUT: %Self: %Y.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: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type @K.1.%Self.as_type (%Self.as_type) [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn[%self.param_patt: @K.1.%Self.as_type (%Self.as_type)](); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @K.2[%self.param_patt: %AnyParam.d71]() [from "has_generic_class.carbon"]; +// CHECK:STDOUT: +// CHECK:STDOUT: specific @AnyParam(constants.%T, constants.%X) { +// CHECK:STDOUT: %T => constants.%T +// CHECK:STDOUT: %T.patt => constants.%T +// CHECK:STDOUT: %X => constants.%X +// CHECK:STDOUT: %X.patt => constants.%X +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @GenericClass(constants.%U) { +// CHECK:STDOUT: %U => constants.%U +// CHECK:STDOUT: %U.patt => constants.%U +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @AnyParam(constants.%GenericClass.type, constants.%GenericClass.generic) { +// CHECK:STDOUT: %T => constants.%GenericClass.type +// CHECK:STDOUT: %T.patt => constants.%GenericClass.type +// CHECK:STDOUT: %X => constants.%GenericClass.generic +// CHECK:STDOUT: %X.patt => constants.%GenericClass.generic +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @K.1(constants.%Self) { +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: %Self.as_type => constants.%Self.as_type +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- has_extra_interfaces.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/check/type_structure.cpp b/toolchain/check/type_structure.cpp new file mode 100644 index 000000000000..a0e4ce112601 --- /dev/null +++ b/toolchain/check/type_structure.cpp @@ -0,0 +1,433 @@ +// 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 + +#include "toolchain/check/type_structure.h" + +#include + +#include "toolchain/base/kind_switch.h" +#include "toolchain/check/context.h" +#include "toolchain/sem_ir/constant.h" +#include "toolchain/sem_ir/facet_type_info.h" +#include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/impl.h" +#include "toolchain/sem_ir/typed_insts.h" + +namespace Carbon::Check { + +auto TypeStructure::IsCompatibleWith(const TypeStructure& other) const -> bool { + const auto& lhs = structure_; + const auto& rhs = other.structure_; + + const auto* lhs_cursor = lhs.begin(); + const auto* rhs_cursor = rhs.begin(); + + while (true) { + // If both structures end at the same time, they match. + if (lhs_cursor == lhs.end() && rhs_cursor == rhs.end()) { + return true; + } + // If one structure ends sooner than the other, they don't match. + if (lhs_cursor == lhs.end() || rhs_cursor == rhs.end()) { + return false; + } + // Same structural element on both sides, they match and both are consumed. + // + // TODO: If we kept the constant value of the concrete element in the type + // structure, then we could compare them and use that to eliminate matching + // impls that are not actually compatible. + if (*lhs_cursor == *rhs_cursor) { + ++lhs_cursor; + ++rhs_cursor; + continue; + } + // If the element on each side is concrete but they not the same structural + // shape, then the structures don't match. + if (*lhs_cursor != Structural::Symbolic && + *rhs_cursor != Structural::Symbolic) { + return false; + } + + // From here we know one side is a Symbolic and the other is not. We can + // match the Symbolic against either a single Concrete or a larger bracketed + // set of Concrete structural elements. + + // Returns false if the lhs and rhs can not match, true if we should + // continue checking for compatibility. + auto consume_symbolic = [](const auto*& lhs_cursor, + const auto*& rhs_cursor) -> bool { + // Consume the symbolic on the RHS. + ++rhs_cursor; + + // The symbolic on the RHS is in the same position as a close paren on the + // LHS, which means the structures can not match. + // + // Example: + // - ((c)) + // - ((c?)) + if (*lhs_cursor == Structural::ConcreteCloseParen) { + return false; + } + + // There's either a Concrete element or an open paren on the LHS. If it's + // the former, the Symbolic just matches with it. If it's the latter, the + // Symbolic matches with everything on the LHS up to the matching closing + // paren. + CARBON_CHECK(*lhs_cursor == Structural::Concrete || + *lhs_cursor == Structural::ConcreteOpenParen); + int depth = 0; + do { + switch (*lhs_cursor) { + case Structural::ConcreteOpenParen: + depth += 1; + break; + case Structural::ConcreteCloseParen: + depth -= 1; + break; + case Structural::Concrete: + break; + case Structural::Symbolic: + break; + } + ++lhs_cursor; + } while (depth > 0); + return true; + }; + + // We move the symbolic to the RHS to make only one case to handle in the + // lambda. + if (*lhs_cursor == Structural::Symbolic) { + if (!consume_symbolic(rhs_cursor, lhs_cursor)) { + return false; + } + } else { + if (!consume_symbolic(lhs_cursor, rhs_cursor)) { + return false; + } + } + } + + return true; +} + +// A class that builds a `TypeStructure` for an `Impl`, or an impl lookup query, +// that represents its self type and interface. +class TypeStructureBuilder { + public: + explicit TypeStructureBuilder(Context& context) : context_(context) {} + + auto Run(SemIR::InstId self_inst_id, + SemIR::SpecificInterface interface_constraint) -> TypeStructure { + CARBON_CHECK(work_list_.empty()); + + first_symbolic_distance_ = TypeStructure::InfiniteDistance; + structure_.clear(); + + // The self type comes first in the type structure, so we push it last, as + // the queue works from the back. + Push(interface_constraint); + PushInstId(self_inst_id); + BuildTypeStructure(); + + return TypeStructure(std::exchange(structure_, {}), + first_symbolic_distance_); + } + + private: + auto BuildTypeStructure() -> void { + while (!work_list_.empty()) { + auto next = work_list_.back(); + work_list_.pop_back(); + + if (std::holds_alternative(next)) { + AppendStructural(TypeStructure::Structural::ConcreteCloseParen); + continue; + } + + if (const auto* interface = + std::get_if(&next)) { + auto args = GetSpecificArgs(interface->specific_id); + if (args.empty()) { + AppendStructural(TypeStructure::Structural::Concrete); + } else { + AppendStructural(TypeStructure::Structural::ConcreteOpenParen); + Push(CloseType()); + PushArgs(args); + } + continue; + } + + if (std::holds_alternative(next)) { + AppendStructural(TypeStructure::Structural::Symbolic); + continue; + } + + if (std::holds_alternative(next)) { + // TODO: Include the value's type into the structure, with the type + // coming first and paired together with the value, like: + // `{TypeWithPossibleNestedTypes, Concrete}`. + // We might want a different bracket marker than ConcreteOpenParen for + // this so that it can look different in the type structure when dumped. + AppendStructural(TypeStructure::Structural::Concrete); + continue; + } + + SemIR::TypeId next_type_id = std::get(next); + auto inst_id = context_.types().GetInstId(next_type_id); + auto inst = context_.insts().Get(inst_id); + CARBON_KIND_SWITCH(inst) { + // ==== Symbolic types ==== + + case SemIR::BindSymbolicName::Kind: + case SemIR::SymbolicBindingPattern::Kind: + case SemIR::FacetAccessType::Kind: { + Push(SymbolicType()); + break; + } + + // ==== Concrete types ==== + + case SemIR::AssociatedEntityType::Kind: + case SemIR::BoolType::Kind: + case SemIR::FloatType::Kind: + case SemIR::GenericClassType::Kind: + case SemIR::GenericInterfaceType::Kind: + case SemIR::ImplWitnessAccess::Kind: + case SemIR::IntLiteralType::Kind: + case SemIR::LegacyFloatType::Kind: + case SemIR::StringType::Kind: + case SemIR::TypeType::Kind: { + AppendStructural(TypeStructure::Structural::Concrete); + break; + } + + case CARBON_KIND(SemIR::FacetType facet_type): { + (void)facet_type; + // A `FacetType` instruction shows up in the self type of impl lookup + // queries like `C(D)` where `C` requires its parameter to satisfy + // some `FacetType` `Z`. The `D` argument is converted to a + // `FacetValue` satisfying `Z`, and the type of `C` in the self type + // has a specific with the type of that `FacetValue`, which is the + // `FacetType` satisfying `Z` we see here. + // + // The `FacetValue` may still be symbolic in generic code but its + // type, the `FacetType` here, is concrete. + AppendStructural(TypeStructure::Structural::Concrete); + break; + } + case CARBON_KIND(SemIR::IntType int_type): { + if (context_.constant_values().Get(inst_id).is_concrete()) { + AppendStructural(TypeStructure::Structural::Concrete); + } else { + AppendStructural(TypeStructure::Structural::ConcreteOpenParen); + Push(CloseType()); + PushArgs({int_type.bit_width_id}); + } + break; + } + + // ==== Aggregate types ==== + + case CARBON_KIND(SemIR::ArrayType array_type): { + AppendStructural(TypeStructure::Structural::ConcreteOpenParen); + Push(CloseType()); + Push(array_type.element_type_id); + PushInstId(array_type.bound_id); + break; + } + case CARBON_KIND(SemIR::ClassType class_type): { + auto args = GetSpecificArgs(class_type.specific_id); + if (args.empty()) { + AppendStructural(TypeStructure::Structural::Concrete); + } else { + AppendStructural(TypeStructure::Structural::ConcreteOpenParen); + Push(CloseType()); + PushArgs(args); + } + break; + } + case CARBON_KIND(SemIR::ConstType const_type): { + // We don't put the `const` into the type structure since it is a + // modifier; just move to the inner type. + Push(const_type.inner_id); + break; + } + case CARBON_KIND(SemIR::PointerType pointer_type): { + AppendStructural(TypeStructure::Structural::ConcreteOpenParen); + Push(CloseType()); + Push(pointer_type.pointee_id); + break; + } + case CARBON_KIND(SemIR::TupleType tuple_type): { + auto inner_types = context_.type_blocks().Get(tuple_type.elements_id); + if (inner_types.empty()) { + AppendStructural(TypeStructure::Structural::Concrete); + } else { + AppendStructural(TypeStructure::Structural::ConcreteOpenParen); + Push(CloseType()); + for (auto type : + context_.type_blocks().Get(tuple_type.elements_id)) { + Push(type); + } + } + break; + } + case CARBON_KIND(SemIR::StructType struct_type): { + auto fields = + context_.struct_type_fields().Get(struct_type.fields_id); + if (fields.empty()) { + AppendStructural(TypeStructure::Structural::Concrete); + } else { + AppendStructural(TypeStructure::Structural::ConcreteOpenParen); + Push(CloseType()); + for (const auto& field : fields) { + Push(field.type_id); + } + } + break; + } + case CARBON_KIND(SemIR::TypeOfInst type_of): { + (void)type_of; + auto const_id = context_.constant_values().Get(inst_id); + // TODO: TypeOfInst should not be encountered in impl lookup with a + // template-dependent value, since impl lookup on such values should + // be deferred to type-checking the specific. So this should become a + // CARBON_FATAL code path. For now it is possible, though, to reach + // here and it results in a diagnostic. + // + // However, TypeOfInst can be determined to be a concrete value for a + // template value with a non-template dependent type. This currently + // does not happen though, the TypeOfInst is always template + // dependent. If it does in the future then we will want to use the + // concrete constant value instruction of `inst_id` in the type + // structure: + // if (const_id.is_concrete()) { + // PushInstId(context_.constant_values().GetInstId(const_id)); + // } + // + // If TypeOfInst was used for more general metaprogramming then we may + // need to handle both concrete and perhaps symbolic (non-template) + // values of TypeOfInst. + CARBON_CHECK(const_id.is_symbolic()); + auto sym = context_.constant_values().GetSymbolicConstant(const_id); + CARBON_CHECK(sym.dependence == SemIR::ConstantDependence::Template, + "TypeOfInst with non-template symbolic value?"); + context_.TODO(context_.insts().GetLocId(inst_id), + "Impl lookup on template-dependent type value"); + break; + } + default: + CARBON_FATAL("Unhandled type instruction {0}", inst_id); + } + } + } + + // A work item to mark the closing paren for an aggregate concrete type. + struct CloseType {}; + // A work item to mark a symbolic type. + struct SymbolicType {}; + // A work item to mark a non-type value. + struct NonTypeValue {}; + + using WorkItem = std::variant; + + // Get the TypeId for an instruction that is not a facet value, otherwise + // return SymbolicType to indicate the instruction is a symbolic facet value. + // + // If the instruction is not a type value, the return is TypeId::None. + // + // We reuse the `SymbolicType` work item here to give a nice return type. + auto TryGetInstIdAsTypeId(SemIR::InstId inst_id) const + -> std::variant { + if (auto facet_value = + context_.insts().TryGetAs(inst_id)) { + inst_id = facet_value->type_inst_id; + } + + auto type_id_of_inst_id = context_.insts().Get(inst_id).type_id(); + // All instructions of type FacetType are symbolic except for FacetValue: + // - In non-generic code, values of type FacetType are only created through + // conversion to a FacetType (e.g. `Class as Iface`), which produces a + // non-symbolic FacetValue. + // - In generic code, binding values of type FacetType are symbolic as they + // refer to an unknown type. Non-binding values would be FacetValues like + // in non-generic code, but would be symbolic as well. + // - In specifics of generic code, when deducing a value for a symbolic + // binding of type FacetType, we always produce a FacetValue (which may or + // may not itself be symbolic) through conversion. + // + // FacetValues are handled earlier by getting the type instruction from + // them. That type instruction is never of type FacetType. If it refers to a + // FacetType it does so through a FacetAccessType, which is of type TypeType + // and thus does not match here. + if (context_.types().Is(type_id_of_inst_id)) { + return SymbolicType(); + } + // Non-type values are concrete, only types are symbolic. + if (type_id_of_inst_id != SemIR::TypeType::SingletonTypeId) { + return SemIR::TypeId::None; + } + return context_.types().GetTypeIdForTypeInstId(inst_id); + } + + // Get the instructions in the specific's instruction block as an ArrayRef. + auto GetSpecificArgs(SemIR::SpecificId specific_id) + -> llvm::ArrayRef { + if (specific_id == SemIR::SpecificId::None) { + return {}; + } + auto specific = context_.specifics().Get(specific_id); + return context_.inst_blocks().Get(specific.args_id); + } + + // Push all arguments from the array into the work queue. + auto PushArgs(llvm::ArrayRef args) -> void { + for (auto arg_id : llvm::reverse(args)) { + PushInstId(arg_id); + } + } + + // Push an instruction's type value into the work queue, or a marker if the + // instruction has a symbolic value. + auto PushInstId(SemIR::InstId inst_id) -> void { + auto maybe_type_id = TryGetInstIdAsTypeId(inst_id); + if (std::holds_alternative(maybe_type_id)) { + Push(SymbolicType()); + } else if (auto type_id = std::get(maybe_type_id); + type_id.has_value()) { + Push(type_id); + } else { + Push(NonTypeValue()); + } + } + + // Push the next step into the work queue. + auto Push(WorkItem item) -> void { work_list_.push_back(item); } + + // Append a structural element to the TypeStructure being built. + auto AppendStructural(TypeStructure::Structural structural) -> void { + if (structural == TypeStructure::Structural::Symbolic) { + // Sets the `distance` in `first_symbolic_distance_` if it does not + // already have a non-infinite value. + if (first_symbolic_distance_ == TypeStructure::InfiniteDistance) { + first_symbolic_distance_ = structure_.size(); + } + } + structure_.push_back(structural); + } + + Context& context_; + llvm::SmallVector work_list_; + int first_symbolic_distance_; + llvm::SmallVector structure_; +}; + +auto BuildTypeStructure(Context& context, SemIR::InstId self_inst_id, + SemIR::SpecificInterface interface) -> TypeStructure { + TypeStructureBuilder builder(context); + return builder.Run(self_inst_id, interface); +} + +} // namespace Carbon::Check diff --git a/toolchain/check/type_structure.h b/toolchain/check/type_structure.h new file mode 100644 index 000000000000..8ae475278a10 --- /dev/null +++ b/toolchain/check/type_structure.h @@ -0,0 +1,107 @@ +// 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 + +#ifndef CARBON_TOOLCHAIN_CHECK_TYPE_STRUCTURE_H_ +#define CARBON_TOOLCHAIN_CHECK_TYPE_STRUCTURE_H_ + +#include + +#include "common/ostream.h" +#include "toolchain/check/context.h" +#include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/impl.h" + +namespace Carbon::Check { + +// The "type structure" for an impl declaration. +// +// See +// https://docs.carbon-lang.dev/docs/design/generics/overview.html#parameterized-impl-declarations. +// +// Type structures are ordered, and a type structure that is ordered higher is a +// better, more specified, match. +class TypeStructure : public Printable { + public: + // Returns whether the type structure is compatible with `other`. If false, + // they can not possibly match with one being an `impl` for the other as a + // lookup query. + auto IsCompatibleWith(const TypeStructure& other) const -> bool; + + // Ordering of type structures. A higher value is a better match. + friend auto operator<=>(const TypeStructure& lhs, const TypeStructure& rhs) + -> std::weak_ordering { + // Higher distance is a better match, and `InfiniteDistance` is treated + // specially as the best possible match. + if (lhs.distance_to_first_symbolic_type_ != + rhs.distance_to_first_symbolic_type_) { + if (lhs.distance_to_first_symbolic_type_ == InfiniteDistance) { + return std::weak_ordering::greater; + } else if (rhs.distance_to_first_symbolic_type_ == InfiniteDistance) { + return std::weak_ordering::less; + } else { + return lhs.distance_to_first_symbolic_type_ <=> + rhs.distance_to_first_symbolic_type_; + } + } + // TODO: If they have a symbolic in the same position, we could use further + // symbolic types to get an ordering. + return std::weak_ordering::equivalent; + } + + auto Print(llvm::raw_ostream& out) const -> void { + out << "TypeStructure = "; + for (auto s : structure_) { + switch (s) { + case Structural::Concrete: + out << 'c'; + break; + case Structural::Symbolic: + out << '?'; + break; + case Structural::ConcreteOpenParen: + out << "("; + break; + case Structural::ConcreteCloseParen: + out << ')'; + break; + } + } + } + + private: + friend class TypeStructureBuilder; + + enum class Structural : uint8_t { + Concrete, + ConcreteOpenParen, + ConcreteCloseParen, + Symbolic, + }; + + static constexpr int InfiniteDistance = -1; + + TypeStructure(llvm::SmallVector structure, + int distance_to_first_symbolic_type) + : structure_(std::move(structure)), + distance_to_first_symbolic_type_(distance_to_first_symbolic_type) {} + + // The structural position of concrete and symbolic values in the type. + llvm::SmallVector structure_; + + // Number of concrete types traversed before finding a symbolic type. + int distance_to_first_symbolic_type_; +}; + +// Constructs the TypeStructure for a self type or facet value and an interface +// constraint (e.g. `Iface(A, B(C))`), which represents the location of unknown +// symbolic values in the combined signature and which is ordered by them. +// +// Given `impl C as Z {}` the `self_const_id` would be a `C` and the interface +// constraint would be `Z`. +auto BuildTypeStructure(Context& context, SemIR::InstId self_inst_id, + SemIR::SpecificInterface interface) -> TypeStructure; + +} // namespace Carbon::Check + +#endif // CARBON_TOOLCHAIN_CHECK_TYPE_STRUCTURE_H_ diff --git a/toolchain/sem_ir/constant.h b/toolchain/sem_ir/constant.h index bbe84857d891..6ee9c93b0cd6 100644 --- a/toolchain/sem_ir/constant.h +++ b/toolchain/sem_ir/constant.h @@ -43,7 +43,7 @@ struct SymbolicConstant : Printable { // constants, or `None` if `generic_id` is `None`. GenericInstIndex index; // The kind of dependence this symbolic constant exhibits. Should never be - // `Concrete`. + // `None`. ConstantDependence dependence; auto Print(llvm::raw_ostream& out) const -> void { diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index 854398be529d..f44cfbb8d474 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -708,7 +708,9 @@ struct FacetType { // of witnesses that it satisfies the required interfaces of the facet type. struct FacetValue { static constexpr auto Kind = InstKind::FacetValue.Define( - {.ir_name = "facet_value", .constant_kind = InstConstantKind::Always}); + {.ir_name = "facet_value", + .constant_kind = InstConstantKind::Always, + .deduce_through = true}); // A `FacetType`. TypeId type_id;