From 53c98a8619cc5fc06ccf8b13a2a05efbed66e68f Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Wed, 26 Mar 2025 08:10:23 -0700 Subject: [PATCH] Support specialization in impl lookup with a symbolic query/impl. (#5169) Add a new instruction called ImplSymbolicWitness which represents a search for an impl declaration given a self type and an interface to find implemented for the self type. The self type is stored as a constant instruction id, rather than as a ConstantId, as instructions don't currently support holding ConstantId. The interface is stored as a SpecificInterface but we can't fit all of it directly into the instruction. So we add a new id to refer to the SpecificInterface as follows. Add a new SpecificInterfaceId which indexes into a canonical value store on SemIR::File. This tracks all `SpecificInterface`s stored in an instruction - specifically the ImplSymbolicWitness instruction. The SpecificInterface on Impl is still stored there as a value, not as an id, and no id is eagerly constructed for it. We wait until an id is needed to make one. Since they are canonical, a new id is only create when a new SpecificInterface value is seen. When doing impl lookup, and the query is not concrete, and the impl is not effectively final, the query needs to consider future impls that may specialize either the self type or the constaint to make a more precise match and replace the found impl declaration. Instead of returning the ImplWitness instruction from the found impl, we generate a ImplSymbolicWitness instruction, storing the query so that it can be replayed later. This instruction is added to the generic eval block and thus will be re-evaluated later with a SpecificId that may make the query more concrete. When evaluating the instruction and replaying the query, the lookup has the same conditions and if it does not decide to use the found impl concretely, then the same instruction is returned from eval, leaving it as symbolic. --- Impl lookup changes --- Impl lookup gets a little more interesting now. It continues to look in the facet value for a witness if the self type is a facet value. Then falls back to looking for an impl declaration. This step is no longer done directly. Instead, we construct a ImplSymbolicWitness instruction and evaluate it immediately for each interface that are in the query facet type. The ImplSymbolicWitness instruction, when evaluated, calls back to the impl lookup code, with a query specific interface. There we resume back into the same code path as from before, finding a witness in an impl declaration. But we may return "found a non-final impl" instead of a concrete witness. If eval receives this back, it evaluates to the current ImplSymbolicWitness instruction as the resulting constant value. To pass lookup failures back through eval, a result of InstId::None from the second step of impl lookup will result in a non-constant value, which is used as a signal back up the stack to the original impl lookup function that the lookup failed. Using a non-constant value here would break evaluation of the generic eval block if impl lookup could fail there, however we know it will not since we only leave behind an ImplSymbolicWitness instruction in the eval block if we found at least one matching impl already, and we just want to look for a better match with a more specific query. We must take care to not store a reference into any value store across computation in impl lookup, since impl lookup can recurse into itself invalidate those stores. That includes the SpecificInterface obtained from a SpecificInterfaceId, which impl lookup also inserts into the store. --- The long tail --- Adding a new instruction and a new id type requires a myriad of changes to support them: We add Dump() support for SpecificInterfaceId. And fix a crash in Dump for SpecificId::None. We also add MakeSpecificInterfaceId() for dumping arbitrary ids. The type of ImplSymbolicWitness is a new singleton builtin type instruction called WitnessSymbolicType (like WitnessType is the type for an ImplWitness). Both ImplSymbolicWitness and WitnessSymbolicType are given `Value` as their expression category as they are builtin constant values. And BuildInfo() in TypeCompleter is taught about them both, returning a `ValueRepr::Copy`. WitnessSymbolicType is added to the set of SingletonInstKinds, so that it can have a singleton instrution id as a static member. Lower's BuildTypeForInst() is taught to make an empty struct for WitnessSymbolicType, similar to WitnessType. Instruction formatter (FormatterImpl) grows support for printing a SpecificInterfaceId so that it can print both arguments of ImplSymbolicWitness on the RHS when printing the SemIR instruction. To print a SpecificInterfaceId, it prints both the interface id and the specific id (if there is one). For example, for a query on a generic interface `Z` with one parameter, the RHS includes the query, interface, and specific: ``` %Z.impl_symbolic_witness: = impl_symbolic_witness %U, @Z, @Z(%U.as_type) [symbolic] ``` IdKind is extended to include SpecificInterfaceId. InstFingerprinter is taught to look through SpecificInterfaceId and use the interface and specific ids in the fingerprint. InstNamer is taught about SpecificInterfaceId, counting the interfaces when building an index. It is also tought about ImplSymbolicWitness, using the name of the interface within and the `.impl_symbolic_witness` suffix. For example, here the LHS is named after the interface in the query: ``` %Z.impl_symbolic_witness: = impl_symbolic_witness %U, @Z, @Z(%U.as_type) [symbolic] ``` StringifyTypeExpr is taught about WitnessSymbolicType, which uses its IR name since it's a singleton. And about ImplSymbolicWitness which uses its constant value. The handling of ImplWitnessAccess also needed to be adjusted, since it assumed that ImplWitnessAccess::witness_id would always be a FacetAccessWitness, but it can now also be an ImplSymbolicWitness. (It seems that the witness_id is also assigned ImplWitness instructions, but those ImplWitnessAccess instructions don't ever seem to get stringified in a diagnostic at this time.) At the moment the ImplWitnessAccess with a symbolic witness is just stringified as "", such as in: ``` x.carbon:1:2: error: cannot implicitly convert value of type `()` to `` [ConversionFailure] let a: C(D).(Z.X) = (); ^~ ``` There is a TODO left behind to include more information there. The TypeStructure builder is made to handle WitnessSymbolicType and WitnessType. These come up now in deduce where a generic impl will have a ImplSymbolicWitness in a FacetValue for a generic self type. The query may have a concrete ImplWitness in the same position. Since deduce tries to deduce through the FacetValue, it tries to convert ImplWitness to ImplSymbolicWitness, tries to do an impl lookup for `impl ImplWitness as ImplicitAs(ImplSymbolicWitness)` and causes us to build type structures with each of these. Subst is updated to handle pushing and popping SpecificInterfaceId. Without this, when finishing a generic's eval block, we would walk into the ImplSymbolicWitness instruction, and its arguments, and fail to recurse down into the SpecificInterfaceId. Then any specifics inside would be left as "orphaned" without any generic id attached to them, and we would never update the instructions in the SpecificInterface's instructions (inside its own SpecificId) with new constant values when evaluating the generic eval block against a specific. To do this we push the specific_id inside the SpecificInterface, and when popping we pop the specific_id then construct a new canonical SpecificInterface with it and return that id. We add support for importing ImplSymbolicWitness by importing its self constant instruction and specific interface id. However we also had to add import support for SpecificImplFunction, which can now appear in the generic eval block for a generic impl declaration, and thus must be imported with the declaration. This is done very similarly to SpecificFunction, except the `type_id` is a singleton value. --------- Co-authored-by: Jon Ross-Perkins --- toolchain/check/BUILD | 1 + toolchain/check/context.h | 5 + toolchain/check/diagnostic_helpers.h | 2 + toolchain/check/dump.cpp | 6 + toolchain/check/eval.cpp | 24 ++ toolchain/check/eval.h | 4 + toolchain/check/eval_inst.cpp | 43 ++ toolchain/check/impl_lookup.cpp | 367 +++++++++++------- toolchain/check/impl_lookup.h | 62 +++ toolchain/check/import_ref.cpp | 57 +++ toolchain/check/subst.cpp | 17 + ..._facet_value_to_narrowed_facet_type.carbon | 13 +- ...t_facet_value_value_to_blanket_impl.carbon | 13 +- ..._value_to_generic_facet_value_value.carbon | 33 +- .../testdata/function/generic/deduce.carbon | 65 ++-- .../lookup/min_prelude/specialization.carbon | 69 +++- .../impl/lookup/no_prelude/impl_forall.carbon | 62 ++- .../no_prelude/import_builtin_call.carbon | 108 +++--- .../no_prelude/fail_assoc_const_alias.carbon | 47 ++- toolchain/check/type_completion.cpp | 1 + toolchain/check/type_structure.cpp | 3 +- toolchain/sem_ir/dump.cpp | 19 +- toolchain/sem_ir/dump.h | 1 + toolchain/sem_ir/file.cpp | 1 + toolchain/sem_ir/file.h | 11 + toolchain/sem_ir/formatter.cpp | 9 + toolchain/sem_ir/id_kind.h | 51 ++- toolchain/sem_ir/ids.h | 9 + toolchain/sem_ir/inst_fingerprinter.cpp | 11 + toolchain/sem_ir/inst_kind.def | 1 + toolchain/sem_ir/inst_namer.cpp | 8 + toolchain/sem_ir/inst_namer.h | 7 +- toolchain/sem_ir/stringify_type.cpp | 5 + toolchain/sem_ir/typed_insts.h | 22 +- 34 files changed, 825 insertions(+), 332 deletions(-) diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 1a69acb4eee6..19578e2fbab8 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -103,6 +103,7 @@ cc_library( "//common:vlog", "//toolchain/base:index_base", "//toolchain/base:kind_switch", + "//toolchain/base:value_store", "//toolchain/check:generic_region_stack", "//toolchain/check:scope_stack", "//toolchain/diagnostics:diagnostic_emitter", diff --git a/toolchain/check/context.h b/toolchain/check/context.h index c7a9ed27bca2..e3c7c93d46e4 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -10,6 +10,7 @@ #include "common/map.h" #include "common/ostream.h" #include "llvm/ADT/SmallVector.h" +#include "toolchain/base/value_store.h" #include "toolchain/check/decl_introducer_state.h" #include "toolchain/check/decl_name_stack.h" #include "toolchain/check/full_pattern_stack.h" @@ -232,6 +233,10 @@ class Context { return sem_ir().complete_facet_types(); } auto impls() -> SemIR::ImplStore& { return sem_ir().impls(); } + auto specific_interfaces() + -> CanonicalValueStore& { + return sem_ir().specific_interfaces(); + } auto generics() -> SemIR::GenericStore& { return sem_ir().generics(); } auto specifics() -> SemIR::SpecificStore& { return sem_ir().specifics(); } auto import_irs() -> ValueStore& { diff --git a/toolchain/check/diagnostic_helpers.h b/toolchain/check/diagnostic_helpers.h index db37acf162f5..c323cd5248b5 100644 --- a/toolchain/check/diagnostic_helpers.h +++ b/toolchain/check/diagnostic_helpers.h @@ -34,6 +34,8 @@ class SemIRLoc { private: // Only allow member access for diagnostics. friend class SemIRLocDiagnosticEmitter; + // And also for eval to unwrap a LocId for calling into the rest of Check. + friend class UnwrapSemIRLoc; union { SemIR::InstId inst_id_; diff --git a/toolchain/check/dump.cpp b/toolchain/check/dump.cpp index e896475278fd..330251b256c4 100644 --- a/toolchain/check/dump.cpp +++ b/toolchain/check/dump.cpp @@ -147,6 +147,12 @@ LLVM_DUMP_METHOD static auto Dump(const Context& context, SemIR::Dump(context.sem_ir(), specific_id); } +LLVM_DUMP_METHOD static auto Dump( + const Context& context, SemIR::SpecificInterfaceId specific_interface_id) + -> void { + SemIR::Dump(context.sem_ir(), specific_interface_id); +} + LLVM_DUMP_METHOD static auto Dump( const Context& context, SemIR::StructTypeFieldsId struct_type_fields_id) -> void { diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index f7aa514a58f7..6d8ca8c1bf4b 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -153,6 +153,10 @@ class EvalContext { auto interfaces() -> const ValueStore& { return sem_ir().interfaces(); } + auto specific_interfaces() + -> CanonicalValueStore& { + return sem_ir().specific_interfaces(); + } auto facet_types() -> CanonicalValueStore& { return sem_ir().facet_types(); } @@ -553,6 +557,20 @@ static auto GetConstantValue(EvalContext& eval_context, specific.generic_id, args_id); } +static auto GetConstantValue(EvalContext& eval_context, + SemIR::SpecificInterfaceId specific_interface_id, + Phase* phase) -> SemIR::SpecificInterfaceId { + const auto& interface = + eval_context.specific_interfaces().Get(specific_interface_id); + if (!interface.specific_id.has_value()) { + return specific_interface_id; + } + return eval_context.specific_interfaces().Add( + {.interface_id = interface.interface_id, + .specific_id = + GetConstantValue(eval_context, interface.specific_id, phase)}); +} + // Like `GetConstantValue` but does a `FacetTypeId` -> `FacetTypeInfo` // conversion. Does not perform canonicalization. static auto GetConstantFacetTypeInfo(EvalContext& eval_context, @@ -1841,6 +1859,12 @@ static auto TryEvalInstInContext(EvalContext& eval_context, inst_id, inst); } +auto TryEvalInst(Context& context, SemIR::LocId loc_id, SemIR::InstId inst_id, + SemIR::Inst inst) -> SemIR::ConstantId { + EvalContext eval_context(context, loc_id); + return TryEvalInstInContext(eval_context, inst_id, inst); +} + auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) -> SemIR::ConstantId { EvalContext eval_context(context, inst_id); diff --git a/toolchain/check/eval.h b/toolchain/check/eval.h index 5c444969eddb..bd4a8a8b3e41 100644 --- a/toolchain/check/eval.h +++ b/toolchain/check/eval.h @@ -16,6 +16,10 @@ namespace Carbon::Check { // `SemIR::ConstantId::NotConstant`. auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst) -> SemIR::ConstantId; +// Like the above but specific a LocId instead of deriving it from the +// `inst_id`. This is most useful when passing `None` as the `inst_id`. +auto TryEvalInst(Context& context, SemIR::LocId loc_id, SemIR::InstId inst_id, + SemIR::Inst inst) -> SemIR::ConstantId; // Evaluates the eval block for a region of a specific. Produces a block // containing the evaluated constant values of the instructions in the eval diff --git a/toolchain/check/eval_inst.cpp b/toolchain/check/eval_inst.cpp index 031c423bec09..fd4a5df10900 100644 --- a/toolchain/check/eval_inst.cpp +++ b/toolchain/check/eval_inst.cpp @@ -4,16 +4,41 @@ #include "toolchain/check/eval_inst.h" +#include + #include "toolchain/check/action.h" #include "toolchain/check/facet_type.h" #include "toolchain/check/generic.h" +#include "toolchain/check/impl_lookup.h" #include "toolchain/check/import_ref.h" #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" +#include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { +// When calling from eval to various Check functions, we need the actual LocId. +// This allows us to unwrap the SemIRLoc to do so. +// +// TODO: Decide whether to refactor calls everywhere to accept `SemIRLoc`, or +// fold `SemIRLoc` into `LocId`. Either way, we would like eval to call other +// code without unwrapping `SemIRLoc`. +class UnwrapSemIRLoc { + public: + auto operator()(Context& context, SemIRLoc loc) -> SemIR::LocId { + if (loc.is_inst_id_) { + if (loc.inst_id_.has_value()) { + return context.insts().GetLocId(loc.inst_id_); + } else { + return SemIR::LocId::None; + } + } else { + return loc.loc_id_; + } + } +}; + // Performs an access into an aggregate, retrieving the specified element. static auto PerformAggregateAccess(Context& context, SemIR::Inst inst) -> ConstantEvalResult { @@ -197,6 +222,24 @@ auto EvalConstantInst(Context& /*context*/, SemIRLoc /*loc*/, .type_id = inst.type_id, .elements_id = SemIR::InstBlockId::Empty}); } +auto EvalConstantInst(Context& context, SemIRLoc loc, + SemIR::ImplSymbolicWitness inst) -> ConstantEvalResult { + auto result = EvalLookupSingleImplWitness( + context, UnwrapSemIRLoc()(context, loc), inst); + if (!result.has_value()) { + // We use NotConstant to communicate back to impl lookup that the lookup + // failed. This can not happen for a deferred symbolic lookup in a generic + // eval block, since we only add the deferred lookup instruction (being + // evaluated here) to the SemIR if the lookup succeeds. + return ConstantEvalResult::NotConstant; + } + if (!result.has_concrete_value()) { + return ConstantEvalResult::NewSamePhase(inst); + } + return ConstantEvalResult::Existing( + context.constant_values().Get(result.concrete_witness())); +} + auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::ImplWitnessAccess inst) -> ConstantEvalResult { // This is PerformAggregateAccess followed by GetConstantInSpecific. diff --git a/toolchain/check/impl_lookup.cpp b/toolchain/check/impl_lookup.cpp index 927595e16c58..dd5bba5fc1c9 100644 --- a/toolchain/check/impl_lookup.cpp +++ b/toolchain/check/impl_lookup.cpp @@ -5,16 +5,19 @@ #include "toolchain/check/impl_lookup.h" #include +#include #include "toolchain/base/kind_switch.h" #include "toolchain/check/deduce.h" #include "toolchain/check/diagnostic_helpers.h" +#include "toolchain/check/eval.h" #include "toolchain/check/generic.h" #include "toolchain/check/import_ref.h" #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/facet_type_info.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/impl.h" #include "toolchain/sem_ir/inst.h" @@ -44,8 +47,10 @@ static auto FindAssociatedImportIRs(Context& context, llvm::SmallVector worklist; worklist.push_back(context.constant_values().GetInstId(query_self_const_id)); - worklist.push_back( - context.constant_values().GetInstId(query_facet_type_const_id)); + if (query_facet_type_const_id.has_value()) { + worklist.push_back( + context.constant_values().GetInstId(query_facet_type_const_id)); + } // Push the contents of an instruction block onto our worklist. auto push_block = [&](SemIR::InstBlockId block_id) { @@ -183,9 +188,10 @@ static auto GetInterfacesFromConstantId( } static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id, + bool query_is_concrete, SemIR::ConstantId query_self_const_id, const SemIR::SpecificInterface& interface, - SemIR::ImplId impl_id) -> SemIR::InstId { + SemIR::ImplId impl_id) -> EvalImplLookupResult { // The impl may have generic arguments, in which case we need to deduce them // to find what they are given the specific type and interface query. We use // that specific to map values in the impl to the deduced values. @@ -202,7 +208,7 @@ static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id, .specific_id = impl.interface.specific_id}, query_self_const_id, interface.specific_id); if (!specific_id.has_value()) { - return SemIR::InstId::None; + return EvalImplLookupResult::MakeNone(); } } } @@ -224,7 +230,7 @@ static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id, context.constant_values().Get(access->facet_value_inst_id); } if (query_self_const_id != deduced_self_const_id) { - return SemIR::InstId::None; + return EvalImplLookupResult::MakeNone(); } // The impl's constraint is a facet type which it is implementing for the self @@ -235,7 +241,7 @@ static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id, context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific( context.sem_ir(), specific_id, impl.constraint_id)); if (deduced_constraint_id == SemIR::ErrorInst::SingletonInstId) { - return SemIR::InstId::None; + return EvalImplLookupResult::MakeNone(); } auto deduced_constraint_facet_type_id = @@ -249,7 +255,7 @@ static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id, if (deduced_constraint_facet_type_info.other_requirements) { // TODO: Remove this when other requirements goes away. - return SemIR::InstId::None; + return EvalImplLookupResult::MakeNone(); } // The specifics in the queried interface must match the deduced specifics in @@ -258,7 +264,7 @@ static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id, deduced_constraint_facet_type_info.impls_constraints[0].specific_id; auto query_interface_specific_id = interface.specific_id; if (impl_interface_specific_id != query_interface_specific_id) { - return SemIR::InstId::None; + return EvalImplLookupResult::MakeNone(); } LoadImportRef(context, impl.witness_id); @@ -267,8 +273,18 @@ static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id, // witness. ResolveSpecificDefinition(context, loc_id, specific_id); } - return context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific( - context.sem_ir(), specific_id, impl.witness_id)); + + bool impl_is_effectively_final = + // TODO: impl.is_final || + (context.constant_values().Get(impl.self_id).is_concrete() && + context.constant_values().Get(impl.constraint_id).is_concrete()); + if (query_is_concrete || impl_is_effectively_final) { + return EvalImplLookupResult::MakeFinal( + context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific( + context.sem_ir(), specific_id, impl.witness_id))); + } else { + return EvalImplLookupResult::MakeNonFinal(); + } } // In the case where `facet_const_id` is a facet, see if its facet type requires @@ -291,104 +307,46 @@ static auto FindWitnessInFacet( for (auto [index, interface] : llvm::enumerate(facet_type_info.impls_constraints)) { if (interface == specific_interface) { - return GetOrAddInst( - context, loc_id, - SemIR::FacetAccessWitness{ - .type_id = GetSingletonType( - context, SemIR::WitnessType::SingletonInstId), - .facet_value_inst_id = facet_inst_id, - .index = SemIR::ElementIndex(index)}); + auto witness_id = + GetOrAddInst(context, loc_id, + SemIR::FacetAccessWitness{ + .type_id = GetSingletonType( + context, SemIR::WitnessType::SingletonInstId), + .facet_value_inst_id = facet_inst_id, + .index = SemIR::ElementIndex(index)}); + return witness_id; } } } 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(); - - 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. - if (impl.interface.interface_id != specific_interface.interface_id) { - continue; - } - - // When the impl's interface_id matches, but the interface is generic, the - // impl may or may not match based on restrictions in the generic parameters - // of the impl. - // - // As a shortcut, if the impl's constraint is not symbolic (does not depend - // on any generic parameters), then we can determine that we match if the - // specific ids match exactly. - auto impl_interface_const_id = - context.constant_values().Get(impl.constraint_id); - if (!impl_interface_const_id.is_symbolic()) { - if (impl.interface.specific_id != specific_interface.specific_id) { - continue; - } - } - - // This check comes first to avoid deduction with an invalid impl. We use an - // error value to indicate an error during creation of the impl, such as a - // recursive impl which will cause deduction to recurse infinitely. - if (impl.witness_id == SemIR::ErrorInst::SingletonInstId) { - continue; - } - CARBON_CHECK(impl.witness_id.has_value()); - - 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)}); +// Begin a search for an impl declaration matching the query. We do this by +// creating an ImplSymbolicWitness instruction and evaluating. If it's able to +// find a final concrete impl, then it will evaluate to that `ImplWitness` but +// if not, it will evaluate to itself as a symbolic witness to be further +// evaluated with a more specific query when building a specific for the generic +// context the query came from. +static auto FindWitnessInImpls(Context& context, SemIR::LocId loc_id, + SemIR::ConstantId query_self_const_id, + SemIR::SpecificInterface interface) + -> SemIR::InstId { + auto witness_const_id = TryEvalInst( + context, loc_id, SemIR::InstId::None, + SemIR::ImplSymbolicWitness{ + .type_id = + GetSingletonType(context, SemIR::WitnessType::SingletonInstId), + .query_self_inst_id = + context.constant_values().GetInstId(query_self_const_id), + .query_specific_interface_id = + context.specific_interfaces().Add(interface), + }); + // We use a NotConstant result from eval to communicate back an impl + // lookup failure. See `EvalConstantInst()` for `ImplSymbolicWitness`. + if (!witness_const_id.is_constant()) { + return SemIR::InstId::None; } - - 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 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; + return context.constant_values().GetInstId(witness_const_id); } auto LookupImplWitness(Context& context, SemIR::LocId loc_id, @@ -413,16 +371,6 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id, context.constant_values().GetInstId(query_facet_type_const_id))); } - // If the self type is a FacetAccessType, work with the facet value directly, - // which gives us the potential witnesses to avoid looking for impl - // declarations. We will do the same for the impl declarations we try to match - // so that we can compare the self constant values. - if (auto access = context.insts().TryGetAs( - context.constant_values().GetInstId(query_self_const_id))) { - query_self_const_id = - context.constant_values().Get(access->facet_value_inst_id); - } - auto import_irs = FindAssociatedImportIRs(context, query_self_const_id, query_facet_type_const_id); for (auto import_ir : import_irs) { @@ -436,6 +384,16 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id, } } + // If the self type is a FacetAccessType, work with the facet value directly, + // which gives us the potential witnesses to avoid looking for impl + // declarations. We will do the same for the impl declarations we try to match + // so that we can compare the self constant values. + if (auto access = context.insts().TryGetAs( + context.constant_values().GetInstId(query_self_const_id))) { + query_self_const_id = + context.constant_values().Get(access->facet_value_inst_id); + } + if (FindAndDiagnoseImplLookupCycle(context, context.impl_lookup_stack(), loc_id, query_self_const_id, query_facet_type_const_id)) { @@ -453,42 +411,20 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id, return SemIR::InstBlockId::Empty; } - llvm::SmallVector result_witness_ids; - auto& stack = context.impl_lookup_stack(); stack.push_back({ .query_self_const_id = query_self_const_id, .query_facet_type_const_id = query_facet_type_const_id, }); - - // We look for a witness in two different places if the query self type is a - // facet value. First we try to find a witness on the facet value itself. This - // avoids the need to do impl lookups which are more expensive. If that fails, - // then we go look for an impl declaration as we would for other self types. - auto facet_value_self_const_id = query_self_const_id; - - // When the query is a concrete FacetValue, we want to look through it at the - // underlying type to find all interfaces it implements. This supports - // conversion from a FacetValue to any other possible FacetValue, since - // conversion depends on impl lookup to verify it is a valid type change. See - // https://github.com/carbon-language/carbon-lang/issues/5137. We can't do - // this step earlier than inside impl lookup since we want the converted facet - // value in `facet_value_self_const_id` to avoid looking for impl - // declarations. - if (auto facet_value = context.insts().TryGetAs( - context.constant_values().GetInstId(query_self_const_id))) { - query_self_const_id = - context.constant_values().Get(facet_value->type_inst_id); - } - // We need to find a witness for each interface in `interfaces`. Every // consumer of a facet type needs to agree on the order of interfaces used for // its witnesses. + llvm::SmallVector result_witness_ids; for (const auto& interface : interfaces) { // TODO: Since both `interfaces` and `query_self_const_id` are sorted lists, // do an O(N+M) merge instead of O(N*M) nested loops. - auto result_witness_id = FindWitnessInFacet( - context, loc_id, facet_value_self_const_id, interface); + auto result_witness_id = + FindWitnessInFacet(context, loc_id, query_self_const_id, interface); if (!result_witness_id.has_value()) { result_witness_id = FindWitnessInImpls(context, loc_id, query_self_const_id, interface); @@ -515,4 +451,163 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id, return context.inst_blocks().AddCanonical(result_witness_ids); } +// Returns whether the query is concrete, it is false if the self type or +// interface specifics have a symbolic dependency. +static auto QueryIsConcrete(Context& context, SemIR::ConstantId self_const_id, + SemIR::SpecificInterface& specific_interface) + -> bool { + if (!self_const_id.is_concrete()) { + return false; + } + if (!specific_interface.specific_id.has_value()) { + return true; + } + auto args_id = + context.specifics().Get(specific_interface.specific_id).args_id; + for (auto inst_id : context.inst_blocks().Get(args_id)) { + if (!context.constant_values().Get(inst_id).is_concrete()) { + return false; + } + } + return true; +} + +struct CandidateImpl { + SemIR::ImplId impl_id; + SemIR::InstId loc_inst_id; + + // Used for sorting the candidates to find the most-specialized match. + TypeStructure type_structure; +}; + +// Returns the list of candidates impls for lookup to select from. +static auto CollectCandidateImplsForQuery( + Context& context, const TypeStructure& query_type_structure, + SemIR::SpecificInterface& query_specific_interface) + -> llvm::SmallVector { + llvm::SmallVector candidate_impls; + 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. + if (impl.interface.interface_id != query_specific_interface.interface_id) { + continue; + } + + // When the impl's interface_id matches, but the interface is generic, the + // impl may or may not match based on restrictions in the generic + // parameters of the impl. + // + // As a shortcut, if the impl's constraint is not symbolic (does not + // depend on any generic parameters), then we can determine whether we match + // by looking if the specific ids match exactly. + auto impl_interface_const_id = + context.constant_values().Get(impl.constraint_id); + if (!impl_interface_const_id.is_symbolic() && + impl.interface.specific_id != query_specific_interface.specific_id) { + continue; + } + + // This check comes first to avoid deduction with an invalid impl. We use + // an error value to indicate an error during creation of the impl, such + // as a recursive impl which will cause deduction to recurse infinitely. + if (impl.witness_id == SemIR::ErrorInst::SingletonInstId) { + continue; + } + CARBON_CHECK(impl.witness_id.has_value()); + + // Build the type structure used for choosing the best the candidate. + auto type_structure = + BuildTypeStructure(context, impl.self_id, impl.interface); + // TODO: We can skip the comparison here if the `impl_interface_const_id` is + // not symbolic, since when the interface and specific ids match, and they + // aren't symbolic, the structure will be identical. + if (!query_type_structure.IsCompatibleWith(type_structure)) { + continue; + } + + candidate_impls.push_back( + {id, impl.definition_id, std::move(type_structure)}); + } + + 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. + llvm::stable_sort(candidate_impls, compare); + + return candidate_impls; +} + +auto EvalLookupSingleImplWitness(Context& context, SemIR::LocId loc_id, + SemIR::ImplSymbolicWitness eval_query) + -> EvalImplLookupResult { + SemIR::ConstantId query_self_const_id = + context.constant_values().Get(eval_query.query_self_inst_id); + SemIR::SpecificInterfaceId query_specific_interface_id = + eval_query.query_specific_interface_id; + + // NOTE: Do not retain this reference to the SpecificInterface obtained from a + // value store by SpecificInterfaceId. Doing impl lookup does deduce which can + // do more impl lookups, and impl lookup can add a new SpecificInterface to + // the store which can reallocate and invalidate any references held here into + // the store. + auto query_specific_interface = + context.specific_interfaces().Get(query_specific_interface_id); + + // When the query is a concrete FacetValue, we want to look through it at the + // underlying type to find all interfaces it implements. This supports + // conversion from a FacetValue to any other possible FacetValue, since + // conversion depends on impl lookup to verify it is a valid type change. See + // https://github.com/carbon-language/carbon-lang/issues/5137. We can't do + // this step earlier than inside impl lookup since: + // - We want the converted facet value to be preserved in + // `FindWitnessInFacet()` to avoid looking for impl declarations. + // - The constant self value may be modified during constant evaluation as a + // more specific value is found. + if (auto facet_value = context.insts().TryGetAs( + context.constant_values().GetInstId(query_self_const_id))) { + query_self_const_id = + context.constant_values().Get(facet_value->type_inst_id); + } + + auto query_type_structure = BuildTypeStructure( + context, context.constant_values().GetInstId(query_self_const_id), + query_specific_interface); + bool query_is_concrete = + QueryIsConcrete(context, query_self_const_id, query_specific_interface); + + auto candidate_impls = CollectCandidateImplsForQuery( + context, query_type_structure, query_specific_interface); + + for (const auto& candidate : candidate_impls) { + // In deferred lookup for a symbolic impl witness, while building a + // specific, there may be no stack yet as this may be the first lookup. If + // further lookups are started as a result in deduce, they will build the + // stack. + // + // NOTE: Don't retain a reference into the stack, it may be invalidated if + // we do further impl lookups when GetWitnessIdForImpl() does deduction. + if (!context.impl_lookup_stack().empty()) { + context.impl_lookup_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 = GetWitnessIdForImpl( + context, loc_id, query_is_concrete, query_self_const_id, + query_specific_interface, candidate.impl_id); + if (result.has_value()) { + return result; + } + } + return EvalImplLookupResult::MakeNone(); +} + } // namespace Carbon::Check diff --git a/toolchain/check/impl_lookup.h b/toolchain/check/impl_lookup.h index 11d54f82c101..0f97b2ae855b 100644 --- a/toolchain/check/impl_lookup.h +++ b/toolchain/check/impl_lookup.h @@ -5,8 +5,12 @@ #ifndef CARBON_TOOLCHAIN_CHECK_IMPL_LOOKUP_H_ #define CARBON_TOOLCHAIN_CHECK_IMPL_LOOKUP_H_ +#include + #include "toolchain/check/context.h" #include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/inst.h" +#include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { @@ -35,6 +39,64 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id, SemIR::ConstantId query_facet_type_const_id) -> SemIR::InstBlockIdOrError; +// The result of EvalLookupSingleImplWitness(). It can be one of: +// - No value. Lookup failed to find an impl declaration. +// - A concrete value. Lookup found a concrete impl declaration that can be +// used definitively. +// - A symbolic value. Lookup found an impl but it is not returned since lookup +// will need to be done again with a more specific query to look for +// specializations. +class EvalImplLookupResult { + public: + static auto MakeNone() -> EvalImplLookupResult { + return EvalImplLookupResult(SemIR::InstId::None); + } + static auto MakeFinal(SemIR::InstId inst_id) -> EvalImplLookupResult { + return EvalImplLookupResult(inst_id); + } + static auto MakeNonFinal() -> EvalImplLookupResult { + return EvalImplLookupResult(FoundNonFinalImpl()); + } + + // True if a concrete impl witness was found or a non-final impl. In the + // latter case the InstId of the impl's witness is not returned, only the fact + // that it exists. + auto has_value() const -> bool { + return std::holds_alternative(result_) || + std::get(result_).has_value(); + } + + // True if there is a concrete witness in the result. If false, and + // `has_value()` is true, it means a non-final impl was found and a further + // more specific query will need to be done. + auto has_concrete_value() const -> bool { + return std::holds_alternative(result_); + } + + // Only valid if `has_concrete_value()` is true. Returns the witness id for + // the found impl declaration, or None if `has_value()` is false. + auto concrete_witness() const -> SemIR::InstId { + return std::get(result_); + } + + private: + struct FoundNonFinalImpl {}; + + explicit EvalImplLookupResult(SemIR::InstId inst_id) : result_(inst_id) {} + explicit EvalImplLookupResult(FoundNonFinalImpl f) : result_(f) {} + + std::variant result_; +}; + +// Looks for a witness instruction of an impl declaration for a query consisting +// of a type value or facet value, and a single interface. This is for eval to +// execute lookup via the ImplSymbolicWitness instruction. It does not consider +// the self facet value for finding a witness, since LookupImplWitness() would +// have found that and not caused us to defer lookup to here. +auto EvalLookupSingleImplWitness(Context& context, SemIR::LocId loc_id, + SemIR::ImplSymbolicWitness eval_query) + -> EvalImplLookupResult; + } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_IMPL_LOOKUP_H_ diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index ecd9e512624b..6ca8be7f3ba5 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -278,6 +278,9 @@ class ImportContext { return import_ir().name_scopes(); } auto import_specifics() -> decltype(auto) { return import_ir().specifics(); } + auto import_specific_interfaes() -> decltype(auto) { + return import_ir().specific_interfaces(); + } auto import_string_literal_values() -> decltype(auto) { return import_ir().string_literal_values(); } @@ -338,6 +341,9 @@ class ImportContext { return local_ir().name_scopes(); } auto local_specifics() -> decltype(auto) { return local_ir().specifics(); } + auto local_specific_interfaces() -> decltype(auto) { + return local_ir().specific_interfaces(); + } auto local_string_literal_values() -> decltype(auto) { return local_ir().string_literal_values(); } @@ -2504,6 +2510,33 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, resolver, inst.witnesses_block_id, witnesses)}); } +static auto TryResolveTypedInst(ImportRefResolver& resolver, + SemIR::ImplSymbolicWitness inst) + -> ResolveResult { + auto query_self_inst_id = + GetLocalConstantInstId(resolver, inst.query_self_inst_id); + + const auto& import_specific_interface = + resolver.import_specific_interfaes().Get( + inst.query_specific_interface_id); + auto data = GetLocalSpecificInstanceData(resolver, import_specific_interface); + + if (resolver.HasNewWork()) { + return ResolveResult::Retry(); + } + + auto specific_interface = GetLocalSpecificInterface( + resolver, import_specific_interface.specific_id, data); + auto query_specific_interface_id = + resolver.local_specific_interfaces().Add(specific_interface); + return ResolveAs( + resolver, + {.type_id = GetSingletonType(resolver.local_context(), + SemIR::WitnessType::SingletonInstId), + .query_self_inst_id = query_self_inst_id, + .query_specific_interface_id = query_specific_interface_id}); +} + static auto TryResolveTypedInst(ImportRefResolver& resolver, SemIR::ImplWitness inst) -> ResolveResult { auto specific_data = GetLocalSpecificData(resolver, inst.specific_id); @@ -2671,6 +2704,24 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, {.type_id = type_id, .callee_id = callee_id, .specific_id = specific_id}); } +static auto TryResolveTypedInst(ImportRefResolver& resolver, + SemIR::SpecificImplFunction inst) + -> ResolveResult { + auto callee_id = GetLocalConstantInstId(resolver, inst.callee_id); + auto specific_data = GetLocalSpecificData(resolver, inst.specific_id); + if (resolver.HasNewWork()) { + return ResolveResult::Retry(); + } + + auto type_id = GetSingletonType(resolver.local_context(), + SemIR::SpecificFunctionType::SingletonInstId); + auto specific_id = + GetOrAddLocalSpecific(resolver, inst.specific_id, specific_data); + return ResolveAs( + resolver, + {.type_id = type_id, .callee_id = callee_id, .specific_id = specific_id}); +} + static auto TryResolveTypedInst(ImportRefResolver& resolver, SemIR::StructType inst) -> ResolveResult { CARBON_CHECK(inst.type_id == SemIR::TypeType::SingletonTypeId); @@ -2884,6 +2935,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver, case CARBON_KIND(SemIR::ImplDecl inst): { return TryResolveTypedInst(resolver, inst, const_id); } + case CARBON_KIND(SemIR::ImplSymbolicWitness inst): { + return TryResolveTypedInst(resolver, inst); + } case CARBON_KIND(SemIR::ImplWitness inst): { return TryResolveTypedInst(resolver, inst); } @@ -2914,6 +2968,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver, case CARBON_KIND(SemIR::SpecificFunction inst): { return TryResolveTypedInst(resolver, inst); } + case CARBON_KIND(SemIR::SpecificImplFunction inst): { + return TryResolveTypedInst(resolver, inst); + } case CARBON_KIND(SemIR::SymbolicBindingPattern inst): { return TryResolveTypedInst(resolver, inst); } diff --git a/toolchain/check/subst.cpp b/toolchain/check/subst.cpp index 96c6ae34e5d7..aec981c58b19 100644 --- a/toolchain/check/subst.cpp +++ b/toolchain/check/subst.cpp @@ -104,6 +104,12 @@ static auto PushOperand(Context& context, Worklist& worklist, case SemIR::IdKind::For: push_specific(SemIR::SpecificId(arg)); break; + case SemIR::IdKind::For: { + auto interface = + context.specific_interfaces().Get(SemIR::SpecificInterfaceId(arg)); + push_specific(interface.specific_id); + break; + } case SemIR::IdKind::For: { const auto& facet_type_info = context.facet_types().Get(SemIR::FacetTypeId(arg)); @@ -205,6 +211,17 @@ static auto PopOperand(Context& context, Worklist& worklist, SemIR::IdKind kind, case SemIR::IdKind::For: { return pop_specific(SemIR::SpecificId(arg)).index; } + case SemIR::IdKind::For: { + auto interface = + context.specific_interfaces().Get(SemIR::SpecificInterfaceId(arg)); + auto specific_id = pop_specific(interface.specific_id); + return context.specific_interfaces() + .Add({ + .interface_id = interface.interface_id, + .specific_id = specific_id, + }) + .index; + } case SemIR::IdKind::For: { const auto& old_facet_type_info = context.facet_types().Get(SemIR::FacetTypeId(arg)); diff --git a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon index 30d76346013a..16ea1d0073b8 100644 --- a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon +++ b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_to_narrowed_facet_type.carbon @@ -743,8 +743,9 @@ fn CallsWithTypeExplicit(U:! type) { // CHECK:STDOUT: %W.as_wit.iface0: = facet_access_witness %W, element0 [symbolic] // CHECK:STDOUT: %Animal.facet: %Animal.type = facet_value %W.as_type, (%W.as_wit.iface0) [symbolic] // CHECK:STDOUT: %impl_witness.1d8: = impl_witness (), @impl.e7b(%Animal.facet) [symbolic] +// CHECK:STDOUT: %Eats.impl_symbolic_witness: = impl_symbolic_witness %W, @Eats [symbolic] // CHECK:STDOUT: %W.as_wit.iface1: = facet_access_witness %W, element1 [symbolic] -// CHECK:STDOUT: %facet_value: %facet_type.6ff = facet_value %W.as_type, (%impl_witness.1d8, %W.as_wit.iface1) [symbolic] +// CHECK:STDOUT: %facet_value: %facet_type.6ff = facet_value %W.as_type, (%Eats.impl_symbolic_witness, %W.as_wit.iface1) [symbolic] // CHECK:STDOUT: %FeedTame2.specific_fn: = specific_function %FeedTame2, @FeedTame2(%facet_value) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -941,8 +942,8 @@ fn CallsWithTypeExplicit(U:! type) { // CHECK:STDOUT: %W.as_wit.iface0.loc12_14.3: = facet_access_witness %W.loc11_22.2, element0 [symbolic = %W.as_wit.iface0.loc12_14.3 (constants.%W.as_wit.iface0)] // CHECK:STDOUT: %Animal.facet.loc12_14.3: %Animal.type = facet_value %W.as_type.loc11_44.2, (%W.as_wit.iface0.loc12_14.3) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)] // CHECK:STDOUT: %W.as_wit.iface1.loc12_14.3: = facet_access_witness %W.loc11_22.2, element1 [symbolic = %W.as_wit.iface1.loc12_14.3 (constants.%W.as_wit.iface1)] -// CHECK:STDOUT: %impl_witness: = impl_witness (), @impl.e7b(%Animal.facet.loc12_14.3) [symbolic = %impl_witness (constants.%impl_witness.1d8)] -// CHECK:STDOUT: %facet_value.loc12_14.3: %facet_type.6ff = facet_value %W.as_type.loc11_44.2, (%impl_witness, %W.as_wit.iface1.loc12_14.3) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)] +// CHECK:STDOUT: %Eats.impl_symbolic_witness: = impl_symbolic_witness %W.loc11_22.2, @Eats [symbolic = %Eats.impl_symbolic_witness (constants.%Eats.impl_symbolic_witness)] +// CHECK:STDOUT: %facet_value.loc12_14.3: %facet_type.6ff = facet_value %W.as_type.loc11_44.2, (%Eats.impl_symbolic_witness, %W.as_wit.iface1.loc12_14.3) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)] // CHECK:STDOUT: %FeedTame2.specific_fn.loc12_3.2: = specific_function constants.%FeedTame2, @FeedTame2(%facet_value.loc12_14.3) [symbolic = %FeedTame2.specific_fn.loc12_3.2 (constants.%FeedTame2.specific_fn)] // CHECK:STDOUT: // CHECK:STDOUT: fn[%W.patt.loc11_22.1: %facet_type.65c](%w.param_patt: @HandleTameAnimal2.%W.as_type.loc11_44.2 (%W.as_type)) { @@ -955,7 +956,7 @@ fn CallsWithTypeExplicit(U:! type) { // CHECK:STDOUT: %Animal.facet.loc12_14.1: %Animal.type = facet_value constants.%W.as_type, (%W.as_wit.iface0.loc12_14.1) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)] // CHECK:STDOUT: %.loc12_14.2: %Animal.type = converted %.loc12_14.1, %Animal.facet.loc12_14.1 [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)] // CHECK:STDOUT: %W.as_wit.iface1.loc12_14.1: = facet_access_witness constants.%W, element1 [symbolic = %W.as_wit.iface1.loc12_14.3 (constants.%W.as_wit.iface1)] -// CHECK:STDOUT: %facet_value.loc12_14.1: %facet_type.6ff = facet_value constants.%W.as_type, (constants.%impl_witness.1d8, %W.as_wit.iface1.loc12_14.1) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)] +// CHECK:STDOUT: %facet_value.loc12_14.1: %facet_type.6ff = facet_value constants.%W.as_type, (constants.%Eats.impl_symbolic_witness, %W.as_wit.iface1.loc12_14.1) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)] // CHECK:STDOUT: %.loc12_14.3: %facet_type.6ff = converted constants.%W.as_type, %facet_value.loc12_14.1 [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)] // CHECK:STDOUT: %W.as_type.loc12_14.2: type = facet_access_type constants.%W [symbolic = %W.as_type.loc11_44.2 (constants.%W.as_type)] // CHECK:STDOUT: %.loc12_14.4: type = converted constants.%W, %W.as_type.loc12_14.2 [symbolic = %W.as_type.loc11_44.2 (constants.%W.as_type)] @@ -963,7 +964,7 @@ fn CallsWithTypeExplicit(U:! type) { // CHECK:STDOUT: %Animal.facet.loc12_14.2: %Animal.type = facet_value constants.%W.as_type, (%W.as_wit.iface0.loc12_14.2) [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)] // CHECK:STDOUT: %.loc12_14.5: %Animal.type = converted %.loc12_14.4, %Animal.facet.loc12_14.2 [symbolic = %Animal.facet.loc12_14.3 (constants.%Animal.facet)] // CHECK:STDOUT: %W.as_wit.iface1.loc12_14.2: = facet_access_witness constants.%W, element1 [symbolic = %W.as_wit.iface1.loc12_14.3 (constants.%W.as_wit.iface1)] -// CHECK:STDOUT: %facet_value.loc12_14.2: %facet_type.6ff = facet_value constants.%W.as_type, (constants.%impl_witness.1d8, %W.as_wit.iface1.loc12_14.2) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)] +// CHECK:STDOUT: %facet_value.loc12_14.2: %facet_type.6ff = facet_value constants.%W.as_type, (constants.%Eats.impl_symbolic_witness, %W.as_wit.iface1.loc12_14.2) [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)] // CHECK:STDOUT: %.loc12_14.6: %facet_type.6ff = converted constants.%W.as_type, %facet_value.loc12_14.2 [symbolic = %facet_value.loc12_14.3 (constants.%facet_value)] // CHECK:STDOUT: %FeedTame2.specific_fn.loc12_3.1: = specific_function %FeedTame2.ref, @FeedTame2(constants.%facet_value) [symbolic = %FeedTame2.specific_fn.loc12_3.2 (constants.%FeedTame2.specific_fn)] // CHECK:STDOUT: %FeedTame2.call: init %empty_tuple.type = call %FeedTame2.specific_fn.loc12_3.1(%w.ref) @@ -1044,8 +1045,6 @@ fn CallsWithTypeExplicit(U:! type) { // CHECK:STDOUT: %require_complete => constants.%require_complete.ba9 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl.e7b(@HandleTameAnimal2.%Animal.facet.loc12_14.3) {} -// CHECK:STDOUT: // CHECK:STDOUT: specific @FeedTame2(@HandleTameAnimal2.%facet_value.loc12_14.3) {} // CHECK:STDOUT: // CHECK:STDOUT: --- equivalent.carbon diff --git a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_blanket_impl.carbon b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_blanket_impl.carbon index 292cd8b76084..6043f8cf3828 100644 --- a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_blanket_impl.carbon +++ b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_blanket_impl.carbon @@ -45,7 +45,8 @@ fn HandleAnimal[T:! Animal](a: T) { Feed(a); } // CHECK:STDOUT: %HandleAnimal: %HandleAnimal.type = struct_value () [concrete] // CHECK:STDOUT: %require_complete.234: = require_complete_type %T.as_type.2ad [symbolic] // CHECK:STDOUT: %impl_witness.11010a.2: = impl_witness (), @impl(%T.fd4) [symbolic] -// CHECK:STDOUT: %Eats.facet: %Eats.type = facet_value %T.as_type.2ad, (%impl_witness.11010a.2) [symbolic] +// CHECK:STDOUT: %Eats.impl_symbolic_witness: = impl_symbolic_witness %T.fd4, @Eats [symbolic] +// CHECK:STDOUT: %Eats.facet: %Eats.type = facet_value %T.as_type.2ad, (%Eats.impl_symbolic_witness) [symbolic] // CHECK:STDOUT: %Feed.specific_fn: = specific_function %Feed, @Feed(%Eats.facet) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -160,8 +161,8 @@ fn HandleAnimal[T:! Animal](a: T) { Feed(a); } // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: %require_complete: = require_complete_type @HandleAnimal.%T.as_type.loc21_32.2 (%T.as_type.2ad) [symbolic = %require_complete (constants.%require_complete.234)] -// CHECK:STDOUT: %impl_witness: = impl_witness (), @impl(%T.loc21_17.2) [symbolic = %impl_witness (constants.%impl_witness.11010a.2)] -// CHECK:STDOUT: %Eats.facet.loc21_43.3: %Eats.type = facet_value %T.as_type.loc21_32.2, (%impl_witness) [symbolic = %Eats.facet.loc21_43.3 (constants.%Eats.facet)] +// CHECK:STDOUT: %Eats.impl_symbolic_witness: = impl_symbolic_witness %T.loc21_17.2, @Eats [symbolic = %Eats.impl_symbolic_witness (constants.%Eats.impl_symbolic_witness)] +// CHECK:STDOUT: %Eats.facet.loc21_43.3: %Eats.type = facet_value %T.as_type.loc21_32.2, (%Eats.impl_symbolic_witness) [symbolic = %Eats.facet.loc21_43.3 (constants.%Eats.facet)] // CHECK:STDOUT: %Feed.specific_fn.loc21_37.2: = specific_function constants.%Feed, @Feed(%Eats.facet.loc21_43.3) [symbolic = %Feed.specific_fn.loc21_37.2 (constants.%Feed.specific_fn)] // CHECK:STDOUT: // CHECK:STDOUT: fn[%T.patt.loc21_17.1: %Animal.type](%a.param_patt: @HandleAnimal.%T.as_type.loc21_32.2 (%T.as_type.2ad)) { @@ -171,12 +172,12 @@ fn HandleAnimal[T:! Animal](a: T) { Feed(a); } // CHECK:STDOUT: %T.as_type.loc21_43.1: type = facet_access_type constants.%T.fd4 [symbolic = %T.as_type.loc21_32.2 (constants.%T.as_type.2ad)] // CHECK:STDOUT: %.loc21_43.1: type = converted constants.%T.fd4, %T.as_type.loc21_43.1 [symbolic = %T.as_type.loc21_32.2 (constants.%T.as_type.2ad)] // CHECK:STDOUT: %.loc21_43.2: %Animal.type = converted %.loc21_43.1, constants.%T.fd4 [symbolic = %T.loc21_17.2 (constants.%T.fd4)] -// CHECK:STDOUT: %Eats.facet.loc21_43.1: %Eats.type = facet_value constants.%T.as_type.2ad, (constants.%impl_witness.11010a.2) [symbolic = %Eats.facet.loc21_43.3 (constants.%Eats.facet)] +// CHECK:STDOUT: %Eats.facet.loc21_43.1: %Eats.type = facet_value constants.%T.as_type.2ad, (constants.%Eats.impl_symbolic_witness) [symbolic = %Eats.facet.loc21_43.3 (constants.%Eats.facet)] // CHECK:STDOUT: %.loc21_43.3: %Eats.type = converted constants.%T.as_type.2ad, %Eats.facet.loc21_43.1 [symbolic = %Eats.facet.loc21_43.3 (constants.%Eats.facet)] // CHECK:STDOUT: %T.as_type.loc21_43.2: type = facet_access_type constants.%T.fd4 [symbolic = %T.as_type.loc21_32.2 (constants.%T.as_type.2ad)] // CHECK:STDOUT: %.loc21_43.4: type = converted constants.%T.fd4, %T.as_type.loc21_43.2 [symbolic = %T.as_type.loc21_32.2 (constants.%T.as_type.2ad)] // CHECK:STDOUT: %.loc21_43.5: %Animal.type = converted %.loc21_43.4, constants.%T.fd4 [symbolic = %T.loc21_17.2 (constants.%T.fd4)] -// CHECK:STDOUT: %Eats.facet.loc21_43.2: %Eats.type = facet_value constants.%T.as_type.2ad, (constants.%impl_witness.11010a.2) [symbolic = %Eats.facet.loc21_43.3 (constants.%Eats.facet)] +// CHECK:STDOUT: %Eats.facet.loc21_43.2: %Eats.type = facet_value constants.%T.as_type.2ad, (constants.%Eats.impl_symbolic_witness) [symbolic = %Eats.facet.loc21_43.3 (constants.%Eats.facet)] // CHECK:STDOUT: %.loc21_43.6: %Eats.type = converted constants.%T.as_type.2ad, %Eats.facet.loc21_43.2 [symbolic = %Eats.facet.loc21_43.3 (constants.%Eats.facet)] // CHECK:STDOUT: %Feed.specific_fn.loc21_37.1: = specific_function %Feed.ref, @Feed(constants.%Eats.facet) [symbolic = %Feed.specific_fn.loc21_37.2 (constants.%Feed.specific_fn)] // CHECK:STDOUT: %Feed.call: init %empty_tuple.type = call %Feed.specific_fn.loc21_37.1(%a.ref) @@ -223,8 +224,6 @@ fn HandleAnimal[T:! Animal](a: T) { Feed(a); } // CHECK:STDOUT: %require_complete => constants.%require_complete.234 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl(@HandleAnimal.%T.loc21_17.2) {} -// CHECK:STDOUT: // CHECK:STDOUT: specific @Feed(@HandleAnimal.%Eats.facet.loc21_43.3) {} // CHECK:STDOUT: // CHECK:STDOUT: --- include_files/convert.carbon diff --git a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon index d8a5f2993e73..391ff270caec 100644 --- a/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon +++ b/toolchain/check/testdata/facet/min_prelude/convert_facet_value_value_to_generic_facet_value_value.carbon @@ -84,8 +84,9 @@ fn F() { // CHECK:STDOUT: %Eats.type.f54c3d.2: type = facet_type <@Eats, @Eats(%Food.as_type.fae)> [symbolic] // CHECK:STDOUT: %require_complete.42532a.2: = require_complete_type %Eats.type.f54c3d.2 [symbolic] // CHECK:STDOUT: %impl_witness.c7c36b.2: = impl_witness (), @impl.009(%T.fd4, %Food.5fe) [symbolic] -// CHECK:STDOUT: %Eats.facet.97e: %Eats.type.f54c3d.2 = facet_value %T.as_type.2ad, (%impl_witness.c7c36b.2) [symbolic] -// CHECK:STDOUT: %Feed.specific_fn.387: = specific_function %Feed, @Feed(%Food.5fe, %Eats.facet.97e) [symbolic] +// CHECK:STDOUT: %Eats.impl_symbolic_witness: = impl_symbolic_witness %T.fd4, @Eats, @Eats(%Food.as_type.fae) [symbolic] +// CHECK:STDOUT: %Eats.facet.eea: %Eats.type.f54c3d.2 = facet_value %T.as_type.2ad, (%Eats.impl_symbolic_witness) [symbolic] +// CHECK:STDOUT: %Feed.specific_fn.824: = specific_function %Feed, @Feed(%Food.5fe, %Eats.facet.eea) [symbolic] // CHECK:STDOUT: %F.type: type = fn_type @F [concrete] // CHECK:STDOUT: %F: %F.type = struct_value () [concrete] // CHECK:STDOUT: %Goat.val: %Goat = struct_value () [concrete] @@ -218,6 +219,10 @@ fn F() { // CHECK:STDOUT: %food: @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae) = bind_name food, %food.param // CHECK:STDOUT: } // CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {} +// CHECK:STDOUT: %Edible.facet: %Edible.type = facet_value constants.%Grass, (constants.%impl_witness.1bc) [concrete = constants.%Edible.facet] +// CHECK:STDOUT: %.loc31_76.1: %Edible.type = converted constants.%Grass, %Edible.facet [concrete = constants.%Edible.facet] +// CHECK:STDOUT: %Animal.facet: %Animal.type = facet_value constants.%Goat, (constants.%impl_witness.1bc) [concrete = constants.%Animal.facet] +// CHECK:STDOUT: %.loc31_76.2: %Animal.type = converted constants.%Goat, %Animal.facet [concrete = constants.%Animal.facet] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: interface @Edible { @@ -329,9 +334,9 @@ fn F() { // CHECK:STDOUT: %require_complete.loc31_45: = require_complete_type @HandleAnimal.%T.as_type.loc31_47.2 (%T.as_type.2ad) [symbolic = %require_complete.loc31_45 (constants.%require_complete.234)] // CHECK:STDOUT: %require_complete.loc31_54: = require_complete_type @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae) [symbolic = %require_complete.loc31_54 (constants.%require_complete.444)] // CHECK:STDOUT: %Eats.type: type = facet_type <@Eats, @Eats(%Food.as_type.loc31_56.2)> [symbolic = %Eats.type (constants.%Eats.type.f54c3d.2)] -// CHECK:STDOUT: %impl_witness: = impl_witness (), @impl.009(%T.loc31_17.2, %Food.loc31_29.2) [symbolic = %impl_witness (constants.%impl_witness.c7c36b.2)] -// CHECK:STDOUT: %Eats.facet.loc31_76.2: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = facet_value %T.as_type.loc31_47.2, (%impl_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.97e)] -// CHECK:STDOUT: %Feed.specific_fn.loc31_64.2: = specific_function constants.%Feed, @Feed(%Food.loc31_29.2, %Eats.facet.loc31_76.2) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.387)] +// CHECK:STDOUT: %Eats.impl_symbolic_witness: = impl_symbolic_witness %T.loc31_17.2, @Eats, @Eats(%Food.as_type.loc31_56.2) [symbolic = %Eats.impl_symbolic_witness (constants.%Eats.impl_symbolic_witness)] +// CHECK:STDOUT: %Eats.facet.loc31_76.2: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = facet_value %T.as_type.loc31_47.2, (%Eats.impl_symbolic_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.eea)] +// CHECK:STDOUT: %Feed.specific_fn.loc31_64.2: = specific_function constants.%Feed, @Feed(%Food.loc31_29.2, %Eats.facet.loc31_76.2) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.824)] // CHECK:STDOUT: // CHECK:STDOUT: fn[%T.patt.loc31_17.1: %Animal.type, %Food.patt.loc31_29.1: %Edible.type](%a.param_patt: @HandleAnimal.%T.as_type.loc31_47.2 (%T.as_type.2ad), %food.param_patt: @HandleAnimal.%Food.as_type.loc31_56.2 (%Food.as_type.fae)) { // CHECK:STDOUT: !entry: @@ -344,9 +349,9 @@ fn F() { // CHECK:STDOUT: %T.as_type.loc31_76: type = facet_access_type constants.%T.fd4 [symbolic = %T.as_type.loc31_47.2 (constants.%T.as_type.2ad)] // CHECK:STDOUT: %.loc31_76.4: type = converted constants.%T.fd4, %T.as_type.loc31_76 [symbolic = %T.as_type.loc31_47.2 (constants.%T.as_type.2ad)] // CHECK:STDOUT: %.loc31_76.5: %Animal.type = converted %.loc31_76.4, constants.%T.fd4 [symbolic = %T.loc31_17.2 (constants.%T.fd4)] -// CHECK:STDOUT: %Eats.facet.loc31_76.1: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = facet_value constants.%T.as_type.2ad, (constants.%impl_witness.c7c36b.2) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.97e)] -// CHECK:STDOUT: %.loc31_76.6: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = converted constants.%T.as_type.2ad, %Eats.facet.loc31_76.1 [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.97e)] -// CHECK:STDOUT: %Feed.specific_fn.loc31_64.1: = specific_function %Feed.ref, @Feed(constants.%Food.5fe, constants.%Eats.facet.97e) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.387)] +// CHECK:STDOUT: %Eats.facet.loc31_76.1: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = facet_value constants.%T.as_type.2ad, (constants.%Eats.impl_symbolic_witness) [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.eea)] +// CHECK:STDOUT: %.loc31_76.6: @HandleAnimal.%Eats.type (%Eats.type.f54c3d.2) = converted constants.%T.as_type.2ad, %Eats.facet.loc31_76.1 [symbolic = %Eats.facet.loc31_76.2 (constants.%Eats.facet.eea)] +// CHECK:STDOUT: %Feed.specific_fn.loc31_64.1: = specific_function %Feed.ref, @Feed(constants.%Food.5fe, constants.%Eats.facet.eea) [symbolic = %Feed.specific_fn.loc31_64.2 (constants.%Feed.specific_fn.824)] // CHECK:STDOUT: %Feed.call: init %empty_tuple.type = call %Feed.specific_fn.loc31_64.1(%a.ref, %food.ref) // CHECK:STDOUT: return // CHECK:STDOUT: } @@ -459,13 +464,13 @@ fn F() { // CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Feed(constants.%Food.5fe, constants.%Eats.facet.97e) { +// CHECK:STDOUT: specific @Feed(constants.%Food.5fe, constants.%Eats.facet.eea) { // CHECK:STDOUT: %Food.loc30_9.2 => constants.%Food.5fe // CHECK:STDOUT: %Food.patt.loc30_9.2 => constants.%Food.5fe // CHECK:STDOUT: %Food.as_type.loc30_37.2 => constants.%Food.as_type.fae // CHECK:STDOUT: %Eats.type.loc30_37.2 => constants.%Eats.type.f54c3d.2 -// CHECK:STDOUT: %T.loc30_24.2 => constants.%Eats.facet.97e -// CHECK:STDOUT: %T.patt.loc30_24.2 => constants.%Eats.facet.97e +// CHECK:STDOUT: %T.loc30_24.2 => constants.%Eats.facet.eea +// CHECK:STDOUT: %T.patt.loc30_24.2 => constants.%Eats.facet.eea // CHECK:STDOUT: %T.as_type.loc30_43.2 => constants.%T.as_type.2ad // CHECK:STDOUT: // CHECK:STDOUT: !definition: @@ -475,8 +480,6 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: specific @Eats(@HandleAnimal.%Food.as_type.loc31_56.2) {} // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl.009(@HandleAnimal.%T.loc31_17.2, @HandleAnimal.%Food.loc31_29.2) {} -// CHECK:STDOUT: // CHECK:STDOUT: specific @Feed(@HandleAnimal.%Food.loc31_29.2, @HandleAnimal.%Eats.facet.loc31_76.2) {} // CHECK:STDOUT: // CHECK:STDOUT: specific @HandleAnimal(constants.%Animal.facet, constants.%Edible.facet) { @@ -491,7 +494,7 @@ fn F() { // CHECK:STDOUT: %require_complete.loc31_45 => constants.%complete_type.357 // CHECK:STDOUT: %require_complete.loc31_54 => constants.%complete_type.357 // CHECK:STDOUT: %Eats.type => constants.%Eats.type.1ae -// CHECK:STDOUT: %impl_witness => constants.%impl_witness.4f1 +// CHECK:STDOUT: %Eats.impl_symbolic_witness => constants.%impl_witness.4f1 // CHECK:STDOUT: %Eats.facet.loc31_76.2 => constants.%Eats.facet.fa6 // CHECK:STDOUT: %Feed.specific_fn.loc31_64.2 => constants.%Feed.specific_fn.d82 // CHECK:STDOUT: } @@ -515,6 +518,8 @@ fn F() { // CHECK:STDOUT: %Eats.type.loc25_49.2 => constants.%Eats.type.1ae // CHECK:STDOUT: %require_complete => constants.%complete_type.004 // CHECK:STDOUT: %impl_witness => constants.%impl_witness.4f1 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @Feed(constants.%Edible.facet, constants.%Eats.facet.fa6) { diff --git a/toolchain/check/testdata/function/generic/deduce.carbon b/toolchain/check/testdata/function/generic/deduce.carbon index f87d9e7686b0..5d3d340893de 100644 --- a/toolchain/check/testdata/function/generic/deduce.carbon +++ b/toolchain/check/testdata/function/generic/deduce.carbon @@ -1519,17 +1519,18 @@ fn F() { // 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: %Z.impl_symbolic_witness: = impl_symbolic_witness %DD.296, @Z [symbolic] +// CHECK:STDOUT: %Z.facet.f61: %Z.type = facet_value %DD.296, (%Z.impl_symbolic_witness) [symbolic] +// CHECK:STDOUT: %CC.43f: type = class_type @CC, @CC(%Z.facet.f61) [symbolic] +// CHECK:STDOUT: %impl_witness.dd1: = impl_witness (), @impl.5bc(%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: %impl_witness.6b1: = impl_witness (), @impl.5bc(%EE) [concrete] +// CHECK:STDOUT: %Z.facet.a6a: %Z.type = facet_value %CC.4de, (%impl_witness.6b1) [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -1577,20 +1578,20 @@ fn F() { // 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: impl_decl @impl.5bc [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.facet.loc12_32.1: %Z.type = facet_value constants.%DD.296, (constants.%Z.impl_symbolic_witness) [symbolic = %Z.facet.loc12_32.2 (constants.%Z.facet.f61)] +// CHECK:STDOUT: %.loc12: %Z.type = converted %DD.loc12_31.1, %Z.facet.loc12_32.1 [symbolic = %Z.facet.loc12_32.2 (constants.%Z.facet.f61)] +// CHECK:STDOUT: %CC.loc12_32.1: type = class_type @CC, @CC(constants.%Z.facet.f61) [symbolic = %CC.loc12_32.2 (constants.%CC.43f)] // 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: %impl_witness.loc12: = impl_witness (), @impl.5bc(constants.%E) [symbolic = @impl.5bc.%impl_witness (constants.%impl_witness.dd1)] // CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: @@ -1621,14 +1622,14 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: generic impl @impl.c35(%E.loc12_14.1: type) { +// CHECK:STDOUT: generic impl @impl.5bc(%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: %Z.impl_symbolic_witness: = impl_symbolic_witness %DD.loc12_31.2, @Z [symbolic = %Z.impl_symbolic_witness (constants.%Z.impl_symbolic_witness)] +// CHECK:STDOUT: %Z.facet.loc12_32.2: %Z.type = facet_value %DD.loc12_31.2, (%Z.impl_symbolic_witness) [symbolic = %Z.facet.loc12_32.2 (constants.%Z.facet.f61)] +// CHECK:STDOUT: %CC.loc12_32.2: type = class_type @CC, @CC(%Z.facet.loc12_32.2) [symbolic = %CC.loc12_32.2 (constants.%CC.43f)] +// CHECK:STDOUT: %impl_witness: = impl_witness (), @impl.5bc(%E.loc12_14.2) [symbolic = %impl_witness (constants.%impl_witness.dd1)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: @@ -1686,8 +1687,8 @@ fn F() { // 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: %Z.facet.loc15_14: %Z.type = facet_value constants.%CC.4de, (constants.%impl_witness.6b1) [concrete = constants.%Z.facet.a6a] +// CHECK:STDOUT: %.loc15_14: %Z.type = converted %CC, %Z.facet.loc15_14 [concrete = constants.%Z.facet.a6a] // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -1714,28 +1715,26 @@ fn F() { // 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: specific @CC(constants.%Z.facet.f61) { +// CHECK:STDOUT: %D.loc11_10.2 => constants.%Z.facet.f61 +// CHECK:STDOUT: %D.patt.loc11_10.2 => constants.%Z.facet.f61 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl.c35(constants.%E) { +// CHECK:STDOUT: specific @impl.5bc(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: %Z.impl_symbolic_witness => constants.%Z.impl_symbolic_witness +// CHECK:STDOUT: %Z.facet.loc12_32.2 => constants.%Z.facet.f61 +// CHECK:STDOUT: %CC.loc12_32.2 => constants.%CC.43f +// CHECK:STDOUT: %impl_witness => constants.%impl_witness.dd1 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @DD(@impl.c35.%E.loc12_14.2) {} +// CHECK:STDOUT: specific @DD(@impl.5bc.%E.loc12_14.2) {} // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl.266(@impl.c35.%E.loc12_14.2) {} +// CHECK:STDOUT: specific @CC(@impl.5bc.%Z.facet.loc12_32.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: specific @impl.5bc(%E.loc12_14.2) {} // CHECK:STDOUT: // CHECK:STDOUT: specific @DD(constants.%EE) { // CHECK:STDOUT: %E.loc8_10.2 => constants.%EE @@ -1756,14 +1755,14 @@ fn F() { // CHECK:STDOUT: %D.patt.loc11_10.2 => constants.%Z.facet.85b // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl.c35(constants.%EE) { +// CHECK:STDOUT: specific @impl.5bc(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.impl_symbolic_witness => 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: %impl_witness => constants.%impl_witness.6b1 // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon b/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon index f119011388e6..4c78b5d30734 100644 --- a/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon +++ b/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon @@ -217,7 +217,7 @@ fn F() { let a: C(D(E), D(E)).(Z.X) = {} as C(E, E); } -// --- specialized_class_with_symbolic_facet_value_param.carbon +// --- fail_specialized_class_with_symbolic_facet_value_param.carbon interface Z { let X:! type; @@ -239,10 +239,13 @@ 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. + // CHECK:STDERR: fail_specialized_class_with_symbolic_facet_value_param.carbon:[[@LINE+7]]:23: error: cannot implicitly convert value of type `()` to `` [ConversionFailure] + // CHECK:STDERR: let a: C(D).(Z.X) = (); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_specialized_class_with_symbolic_facet_value_param.carbon:[[@LINE+4]]:23: note: type `()` does not implement interface `Core.ImplicitAs()` [MissingImplInMemberAccessNote] + // CHECK:STDERR: let a: C(D).(Z.X) = (); + // CHECK:STDERR: ^~ + // CHECK:STDERR: let a: C(D).(Z.X) = (); } @@ -379,21 +382,25 @@ fn F[U:! type](T:! Z(C)) { // TODO: Make this `final`. impl forall [T:! type] T as Z(C) where .X = C {} -// --- fail_specialization_written_after_generic_use.carbon +// --- specialization_written_after_generic_use.carbon library "[[@TEST_NAME]]"; interface Z { let V:! type; - fn F() -> V; + fn ZZ() -> V; } interface Y {} impl forall [T:! Y] T as Z where .V = () { - fn F() -> () { return (); } + fn ZZ() -> () { return (); } +} + +fn H(W:! Z, X: W.(Z.V)) -> W.(Z.V) { + return X; } fn G(U:! Y) -> U.(Z.V) { - return U.(Z.F)(); + return H(U, U.(Z.ZZ)()); } class C { @@ -401,16 +408,42 @@ class C { } impl C as Z where .V = {} { - fn F() -> {} { return {}; } + fn ZZ() -> {} { return {}; } } -fn H() { - // CHECK:STDERR: fail_specialization_written_after_generic_use.carbon:[[@LINE+7]]:15: error: cannot implicitly convert value of type `()` to `{}` [ConversionFailure] - // CHECK:STDERR: let x: {} = G(C); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: fail_specialization_written_after_generic_use.carbon:[[@LINE+4]]:15: note: type `()` does not implement interface `Core.ImplicitAs({})` [MissingImplInMemberAccessNote] - // CHECK:STDERR: let x: {} = G(C); - // CHECK:STDERR: ^~~~ - // CHECK:STDERR: +fn F() { + let x: {} = G(C); +} + +// --- specialization_written_after_generic_use_with_generic_interface.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let V:! type; + fn ZZ() -> V; +} + +interface Y {} +impl forall [T:! Y] T as Z(T) where .V = () { + fn ZZ() -> () { return (); } +} + +fn H(U:! Y, W:! Y & Z(U), X: W.(Z(U).V)) -> W.(Z(U).V) { + return X; +} + +fn G(U:! Y) -> U.(Z(U).V) { + return H(U, U, U.(Z(U).ZZ)()); +} + +class C { + impl as Y {} +} + +impl C as Z(C) where .V = {} { + fn ZZ() -> {} { return {}; } +} + +fn F() { let x: {} = G(C); } diff --git a/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon b/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon index 342e45f1b689..470d49e7f33f 100644 --- a/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon +++ b/toolchain/check/testdata/impl/lookup/no_prelude/impl_forall.carbon @@ -69,7 +69,7 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %impl_witness.ab3b51.1: = impl_witness (@impl.%F.decl), @impl(%V) [symbolic] // CHECK:STDOUT: %F.type.0fea45.1: type = fn_type @F.2, @impl(%V) [symbolic] // CHECK:STDOUT: %F.d6ae34.1: %F.type.0fea45.1 = struct_value () [symbolic] -// CHECK:STDOUT: %I.facet.1299b2.1: %I.type.325e65.2 = facet_value %A.13025a.2, (%impl_witness.ab3b51.1) [symbolic] +// CHECK:STDOUT: %I.facet.129: %I.type.325e65.2 = facet_value %A.13025a.2, (%impl_witness.ab3b51.1) [symbolic] // CHECK:STDOUT: %require_complete.4aeca8.2: = require_complete_type %V [symbolic] // CHECK:STDOUT: %A.elem.1ceb36.2: type = unbound_element_type %A.13025a.2, %V [symbolic] // CHECK:STDOUT: %struct_type.n.848971.2: type = struct_type {.n: %V} [symbolic] @@ -95,9 +95,11 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %impl_witness.ab3b51.2: = impl_witness (@impl.%F.decl), @impl(%W) [symbolic] // CHECK:STDOUT: %F.type.0fea45.2: type = fn_type @F.2, @impl(%W) [symbolic] // CHECK:STDOUT: %F.d6ae34.2: %F.type.0fea45.2 = struct_value () [symbolic] -// CHECK:STDOUT: %I.facet.1299b2.2: %I.type.325e65.3 = facet_value %A.13025a.3, (%impl_witness.ab3b51.2) [symbolic] -// CHECK:STDOUT: %.814: type = fn_type_with_self_type %F.type.2aef59.3, %I.facet.1299b2.2 [symbolic] -// CHECK:STDOUT: %F.specific_fn.e98: = specific_function %F.d6ae34.2, @F.2(%W) [symbolic] +// CHECK:STDOUT: %I.impl_symbolic_witness: = impl_symbolic_witness %A.13025a.3, @I, @I(%W) [symbolic] +// CHECK:STDOUT: %I.facet.5fd: %I.type.325e65.3 = facet_value %A.13025a.3, (%I.impl_symbolic_witness) [symbolic] +// CHECK:STDOUT: %.ea0: type = fn_type_with_self_type %F.type.2aef59.3, %I.facet.5fd [symbolic] +// CHECK:STDOUT: %impl.elem0: %.ea0 = impl_witness_access %I.impl_symbolic_witness, element0 [symbolic] +// CHECK:STDOUT: %specific_impl_fn: = specific_impl_function %impl.elem0, @F.1(%W, %I.facet.5fd) [symbolic] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %A.235: type = class_type @A, @A(%empty_struct_type) [concrete] // CHECK:STDOUT: %TestSpecific.type: type = fn_type @TestSpecific [concrete] @@ -118,7 +120,7 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %F.158: %F.type.875 = struct_value () [concrete] // CHECK:STDOUT: %I.facet.b64: %I.type.885 = facet_value %A.235, (%impl_witness.f35) [concrete] // CHECK:STDOUT: %.f80: type = fn_type_with_self_type %F.type.684, %I.facet.b64 [concrete] -// CHECK:STDOUT: %F.specific_fn.72f: = specific_function %F.158, @F.2(%empty_struct_type) [concrete] +// CHECK:STDOUT: %F.specific_fn: = specific_function %F.158, @F.2(%empty_struct_type) [concrete] // CHECK:STDOUT: %empty_struct: %empty_struct_type = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: @@ -334,13 +336,12 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %require_complete.loc18: = require_complete_type @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) [symbolic = %require_complete.loc18 (constants.%require_complete.cfebb2.2)] // CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) [symbolic = %I.assoc_type (constants.%I.assoc_type.955255.3)] // CHECK:STDOUT: %assoc0: @TestGeneric.%I.assoc_type (%I.assoc_type.955255.3) = assoc_entity element0, @I.%F.decl [symbolic = %assoc0 (constants.%assoc0.fef501.3)] -// CHECK:STDOUT: %F.type.loc18_11.1: type = fn_type @F.1, @I(%W.loc17_16.2) [symbolic = %F.type.loc18_11.1 (constants.%F.type.2aef59.3)] -// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%F.decl), @impl(%W.loc17_16.2) [symbolic = %impl_witness (constants.%impl_witness.ab3b51.2)] -// CHECK:STDOUT: %I.facet: @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) = facet_value %A.loc17_32.2, (%impl_witness) [symbolic = %I.facet (constants.%I.facet.1299b2.2)] -// CHECK:STDOUT: %.loc18_11: type = fn_type_with_self_type %F.type.loc18_11.1, %I.facet [symbolic = %.loc18_11 (constants.%.814)] -// CHECK:STDOUT: %F.type.loc18_11.2: type = fn_type @F.2, @impl(%W.loc17_16.2) [symbolic = %F.type.loc18_11.2 (constants.%F.type.0fea45.2)] -// CHECK:STDOUT: %F: @TestGeneric.%F.type.loc18_11.2 (%F.type.0fea45.2) = struct_value () [symbolic = %F (constants.%F.d6ae34.2)] -// CHECK:STDOUT: %F.specific_fn: = specific_function %F, @F.2(%W.loc17_16.2) [symbolic = %F.specific_fn (constants.%F.specific_fn.e98)] +// CHECK:STDOUT: %F.type: type = fn_type @F.1, @I(%W.loc17_16.2) [symbolic = %F.type (constants.%F.type.2aef59.3)] +// CHECK:STDOUT: %I.impl_symbolic_witness: = impl_symbolic_witness %A.loc17_32.2, @I, @I(%W.loc17_16.2) [symbolic = %I.impl_symbolic_witness (constants.%I.impl_symbolic_witness)] +// CHECK:STDOUT: %I.facet: @TestGeneric.%I.type.loc18_16.2 (%I.type.325e65.3) = facet_value %A.loc17_32.2, (%I.impl_symbolic_witness) [symbolic = %I.facet (constants.%I.facet.5fd)] +// CHECK:STDOUT: %.loc18_11: type = fn_type_with_self_type %F.type, %I.facet [symbolic = %.loc18_11 (constants.%.ea0)] +// CHECK:STDOUT: %impl.elem0.loc18_11.2: @TestGeneric.%.loc18_11 (%.ea0) = impl_witness_access %I.impl_symbolic_witness, element0 [symbolic = %impl.elem0.loc18_11.2 (constants.%impl.elem0)] +// CHECK:STDOUT: %specific_impl_fn.loc18_11.2: = specific_impl_function %impl.elem0.loc18_11.2, @F.1(%W.loc17_16.2, %I.facet) [symbolic = %specific_impl_fn.loc18_11.2 (constants.%specific_impl_fn)] // CHECK:STDOUT: // CHECK:STDOUT: fn[%W.patt.loc17_16.1: type](%a.param_patt: @TestGeneric.%A.loc17_32.2 (%A.13025a.3)) -> @TestGeneric.%W.loc17_16.2 (%W) { // CHECK:STDOUT: !entry: @@ -350,13 +351,13 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %I.type.loc18_16.1: type = facet_type <@I, @I(constants.%W)> [symbolic = %I.type.loc18_16.2 (constants.%I.type.325e65.3)] // CHECK:STDOUT: %.loc18_17: @TestGeneric.%I.assoc_type (%I.assoc_type.955255.3) = specific_constant @I.%assoc0.loc8_26.1, @I(constants.%W) [symbolic = %assoc0 (constants.%assoc0.fef501.3)] // CHECK:STDOUT: %F.ref: @TestGeneric.%I.assoc_type (%I.assoc_type.955255.3) = name_ref F, %.loc18_17 [symbolic = %assoc0 (constants.%assoc0.fef501.3)] -// CHECK:STDOUT: %impl.elem0: @TestGeneric.%.loc18_11 (%.814) = impl_witness_access constants.%impl_witness.ab3b51.2, element0 [symbolic = %F (constants.%F.d6ae34.2)] -// CHECK:STDOUT: %bound_method.loc18_11: = bound_method %a.ref, %impl.elem0 -// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @F.2(constants.%W) [symbolic = %F.specific_fn (constants.%F.specific_fn.e98)] -// CHECK:STDOUT: %bound_method.loc18_21: = bound_method %a.ref, %specific_fn -// CHECK:STDOUT: %F.call: init @TestGeneric.%W.loc17_16.2 (%W) = call %bound_method.loc18_21(%a.ref) -// CHECK:STDOUT: %.loc18_22.1: @TestGeneric.%W.loc17_16.2 (%W) = value_of_initializer %F.call -// CHECK:STDOUT: %.loc18_22.2: @TestGeneric.%W.loc17_16.2 (%W) = converted %F.call, %.loc18_22.1 +// CHECK:STDOUT: %impl.elem0.loc18_11.1: @TestGeneric.%.loc18_11 (%.ea0) = impl_witness_access constants.%I.impl_symbolic_witness, element0 [symbolic = %impl.elem0.loc18_11.2 (constants.%impl.elem0)] +// CHECK:STDOUT: %bound_method.loc18_11: = bound_method %a.ref, %impl.elem0.loc18_11.1 +// CHECK:STDOUT: %specific_impl_fn.loc18_11.1: = specific_impl_function %impl.elem0.loc18_11.1, @F.1(constants.%W, constants.%I.facet.5fd) [symbolic = %specific_impl_fn.loc18_11.2 (constants.%specific_impl_fn)] +// CHECK:STDOUT: %bound_method.loc18_21: = bound_method %a.ref, %specific_impl_fn.loc18_11.1 +// CHECK:STDOUT: %.loc18_21: init @TestGeneric.%W.loc17_16.2 (%W) = call %bound_method.loc18_21(%a.ref) +// CHECK:STDOUT: %.loc18_22.1: @TestGeneric.%W.loc17_16.2 (%W) = value_of_initializer %.loc18_21 +// CHECK:STDOUT: %.loc18_22.2: @TestGeneric.%W.loc17_16.2 (%W) = converted %.loc18_21, %.loc18_22.1 // CHECK:STDOUT: return %.loc18_22.2 // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -372,7 +373,7 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %F.ref: %I.assoc_type.67f = name_ref F, %.loc22_18 [concrete = constants.%assoc0.639] // CHECK:STDOUT: %impl.elem0: %.f80 = impl_witness_access constants.%impl_witness.f35, element0 [concrete = constants.%F.158] // CHECK:STDOUT: %bound_method.loc22_11: = bound_method %a.ref, %impl.elem0 -// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @F.2(constants.%empty_struct_type) [concrete = constants.%F.specific_fn.72f] +// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @F.2(constants.%empty_struct_type) [concrete = constants.%F.specific_fn] // CHECK:STDOUT: %bound_method.loc22_22: = bound_method %a.ref, %specific_fn // CHECK:STDOUT: %F.call: init %empty_struct_type = call %bound_method.loc22_22(%a.ref) // CHECK:STDOUT: %.loc22_22.1: ref %empty_struct_type = temporary_storage @@ -456,10 +457,10 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: // CHECK:STDOUT: specific @A(@F.2.%V) {} // CHECK:STDOUT: -// CHECK:STDOUT: specific @F.1(constants.%V, constants.%I.facet.1299b2.1) { +// CHECK:STDOUT: specific @F.1(constants.%V, constants.%I.facet.129) { // CHECK:STDOUT: %U => constants.%V // CHECK:STDOUT: %I.type => constants.%I.type.325e65.2 -// CHECK:STDOUT: %Self => constants.%I.facet.1299b2.1 +// CHECK:STDOUT: %Self => constants.%I.facet.129 // CHECK:STDOUT: %Self.as_type.loc8_14.1 => constants.%A.13025a.2 // CHECK:STDOUT: } // CHECK:STDOUT: @@ -509,21 +510,16 @@ fn TestSpecific(a: A({})) -> {} { // CHECK:STDOUT: %F => constants.%F.d6ae34.2 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @F.2(constants.%W) { -// CHECK:STDOUT: %V => constants.%W -// CHECK:STDOUT: %A => constants.%A.13025a.3 -// CHECK:STDOUT: -// CHECK:STDOUT: !definition: -// CHECK:STDOUT: %require_complete.loc12_22 => constants.%require_complete.4aeca8.3 -// CHECK:STDOUT: %require_complete.loc12_12 => constants.%require_complete.5b8aee.2 -// CHECK:STDOUT: %A.elem => constants.%A.elem.1ceb36.3 +// CHECK:STDOUT: specific @F.1(constants.%W, constants.%I.facet.5fd) { +// CHECK:STDOUT: %U => constants.%W +// CHECK:STDOUT: %I.type => constants.%I.type.325e65.3 +// CHECK:STDOUT: %Self => constants.%I.facet.5fd +// CHECK:STDOUT: %Self.as_type.loc8_14.1 => constants.%A.13025a.3 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @I(@TestGeneric.%W.loc17_16.2) {} // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl(@TestGeneric.%W.loc17_16.2) {} -// CHECK:STDOUT: -// CHECK:STDOUT: specific @F.2(@TestGeneric.%W.loc17_16.2) {} +// CHECK:STDOUT: specific @F.1(@TestGeneric.%W.loc17_16.2, @TestGeneric.%I.facet) {} // CHECK:STDOUT: // CHECK:STDOUT: specific @A(constants.%empty_struct_type) { // CHECK:STDOUT: %T.loc3_9.2 => constants.%empty_struct_type diff --git a/toolchain/check/testdata/impl/no_prelude/import_builtin_call.carbon b/toolchain/check/testdata/impl/no_prelude/import_builtin_call.carbon index 309d24804826..72515ccfad38 100644 --- a/toolchain/check/testdata/impl/no_prelude/import_builtin_call.carbon +++ b/toolchain/check/testdata/impl/no_prelude/import_builtin_call.carbon @@ -102,11 +102,14 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: %Op.type.883: type = fn_type @Op.2, @impl(%N) [symbolic] // CHECK:STDOUT: %Op.8bc: %Op.type.883 = struct_value () [symbolic] // CHECK:STDOUT: %require_complete.fc7: = require_complete_type %MyInt [symbolic] -// CHECK:STDOUT: %Add.facet: %Add.type = facet_value %MyInt, (%impl_witness) [symbolic] +// CHECK:STDOUT: %Add.facet.c2b: %Add.type = facet_value %MyInt, (%impl_witness) [symbolic] // CHECK:STDOUT: %Double.type: type = fn_type @Double [concrete] // CHECK:STDOUT: %Double: %Double.type = struct_value () [concrete] -// CHECK:STDOUT: %.9b8: type = fn_type_with_self_type %Op.type.31b, %Add.facet [symbolic] -// CHECK:STDOUT: %Op.specific_fn: = specific_function %Op.8bc, @Op.2(%N) [symbolic] +// CHECK:STDOUT: %Add.impl_symbolic_witness: = impl_symbolic_witness %MyInt, @Add [symbolic] +// CHECK:STDOUT: %Add.facet.f76: %Add.type = facet_value %MyInt, (%Add.impl_symbolic_witness) [symbolic] +// CHECK:STDOUT: %.dfa: type = fn_type_with_self_type %Op.type.31b, %Add.facet.f76 [symbolic] +// CHECK:STDOUT: %impl.elem0: %.dfa = impl_witness_access %Add.impl_symbolic_witness, element0 [symbolic] +// CHECK:STDOUT: %specific_impl_fn: = specific_impl_function %impl.elem0, @Op.1(%Add.facet.f76) [symbolic] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -326,26 +329,29 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: %require_complete: = require_complete_type @Double.%MyInt.loc19_39.2 (%MyInt) [symbolic = %require_complete (constants.%require_complete.fc7)] -// CHECK:STDOUT: %impl_witness: = impl_witness (@impl.%Op.decl), @impl(%N.loc19_11.2) [symbolic = %impl_witness (constants.%impl_witness)] -// CHECK:STDOUT: %Add.facet: %Add.type = facet_value %MyInt.loc19_39.2, (%impl_witness) [symbolic = %Add.facet (constants.%Add.facet)] -// CHECK:STDOUT: %.loc20_11: type = fn_type_with_self_type constants.%Op.type.31b, %Add.facet [symbolic = %.loc20_11 (constants.%.9b8)] -// CHECK:STDOUT: %Op.type: type = fn_type @Op.2, @impl(%N.loc19_11.2) [symbolic = %Op.type (constants.%Op.type.883)] -// CHECK:STDOUT: %Op: @Double.%Op.type (%Op.type.883) = struct_value () [symbolic = %Op (constants.%Op.8bc)] -// CHECK:STDOUT: %Op.specific_fn: = specific_function %Op, @Op.2(%N.loc19_11.2) [symbolic = %Op.specific_fn (constants.%Op.specific_fn)] +// CHECK:STDOUT: %Add.impl_symbolic_witness: = impl_symbolic_witness %MyInt.loc19_39.2, @Add [symbolic = %Add.impl_symbolic_witness (constants.%Add.impl_symbolic_witness)] +// CHECK:STDOUT: %Add.facet.loc20_11: %Add.type = facet_value %MyInt.loc19_39.2, (%Add.impl_symbolic_witness) [symbolic = %Add.facet.loc20_11 (constants.%Add.facet.f76)] +// CHECK:STDOUT: %.loc20_11: type = fn_type_with_self_type constants.%Op.type.31b, %Add.facet.loc20_11 [symbolic = %.loc20_11 (constants.%.dfa)] +// CHECK:STDOUT: %impl.elem0.loc20_11.2: @Double.%.loc20_11 (%.dfa) = impl_witness_access %Add.impl_symbolic_witness, element0 [symbolic = %impl.elem0.loc20_11.2 (constants.%impl.elem0)] +// CHECK:STDOUT: %specific_impl_fn.loc20_11.2: = specific_impl_function %impl.elem0.loc20_11.2, @Op.1(%Add.facet.loc20_11) [symbolic = %specific_impl_fn.loc20_11.2 (constants.%specific_impl_fn)] // CHECK:STDOUT: // CHECK:STDOUT: fn[%N.patt.loc19_11.1: Core.IntLiteral](%x.param_patt: @Double.%MyInt.loc19_39.2 (%MyInt)) -> @Double.%MyInt.loc19_39.2 (%MyInt) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %x.ref.loc20_10: @Double.%MyInt.loc19_39.2 (%MyInt) = name_ref x, %x // CHECK:STDOUT: %Add.ref: type = name_ref Add, file.%Add.decl [concrete = constants.%Add.type] // CHECK:STDOUT: %Op.ref: %Add.assoc_type = name_ref Op, @Add.%assoc0 [concrete = constants.%assoc0] -// CHECK:STDOUT: %impl.elem0: @Double.%.loc20_11 (%.9b8) = impl_witness_access constants.%impl_witness, element0 [symbolic = %Op (constants.%Op.8bc)] -// CHECK:STDOUT: %bound_method.loc20_11: = bound_method %x.ref.loc20_10, %impl.elem0 +// CHECK:STDOUT: %impl.elem0.loc20_11.1: @Double.%.loc20_11 (%.dfa) = impl_witness_access constants.%Add.impl_symbolic_witness, element0 [symbolic = %impl.elem0.loc20_11.2 (constants.%impl.elem0)] +// CHECK:STDOUT: %bound_method.loc20_11: = bound_method %x.ref.loc20_10, %impl.elem0.loc20_11.1 // CHECK:STDOUT: %x.ref.loc20_21: @Double.%MyInt.loc19_39.2 (%MyInt) = name_ref x, %x -// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Op.2(constants.%N) [symbolic = %Op.specific_fn (constants.%Op.specific_fn)] -// CHECK:STDOUT: %bound_method.loc20_22: = bound_method %x.ref.loc20_10, %specific_fn -// CHECK:STDOUT: %int.sadd: init @Double.%MyInt.loc19_39.2 (%MyInt) = call %bound_method.loc20_22(%x.ref.loc20_10, %x.ref.loc20_21) -// CHECK:STDOUT: %.loc20_23.1: @Double.%MyInt.loc19_39.2 (%MyInt) = value_of_initializer %int.sadd -// CHECK:STDOUT: %.loc20_23.2: @Double.%MyInt.loc19_39.2 (%MyInt) = converted %int.sadd, %.loc20_23.1 +// CHECK:STDOUT: %Add.facet.loc20_22.1: %Add.type = facet_value constants.%MyInt, (constants.%Add.impl_symbolic_witness) [symbolic = %Add.facet.loc20_11 (constants.%Add.facet.f76)] +// CHECK:STDOUT: %.loc20_22.1: %Add.type = converted constants.%MyInt, %Add.facet.loc20_22.1 [symbolic = %Add.facet.loc20_11 (constants.%Add.facet.f76)] +// CHECK:STDOUT: %Add.facet.loc20_22.2: %Add.type = facet_value constants.%MyInt, (constants.%Add.impl_symbolic_witness) [symbolic = %Add.facet.loc20_11 (constants.%Add.facet.f76)] +// CHECK:STDOUT: %.loc20_22.2: %Add.type = converted constants.%MyInt, %Add.facet.loc20_22.2 [symbolic = %Add.facet.loc20_11 (constants.%Add.facet.f76)] +// CHECK:STDOUT: %specific_impl_fn.loc20_11.1: = specific_impl_function %impl.elem0.loc20_11.1, @Op.1(constants.%Add.facet.f76) [symbolic = %specific_impl_fn.loc20_11.2 (constants.%specific_impl_fn)] +// CHECK:STDOUT: %bound_method.loc20_22: = bound_method %x.ref.loc20_10, %specific_impl_fn.loc20_11.1 +// CHECK:STDOUT: %.loc20_22.3: init @Double.%MyInt.loc19_39.2 (%MyInt) = call %bound_method.loc20_22(%x.ref.loc20_10, %x.ref.loc20_21) +// CHECK:STDOUT: %.loc20_23.1: @Double.%MyInt.loc19_39.2 (%MyInt) = value_of_initializer %.loc20_22.3 +// CHECK:STDOUT: %.loc20_23.2: @Double.%MyInt.loc19_39.2 (%MyInt) = converted %.loc20_22.3, %.loc20_23.1 // CHECK:STDOUT: return %.loc20_23.2 // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -384,14 +390,12 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: specific @Op.2(constants.%N) { // CHECK:STDOUT: %N => constants.%N // CHECK:STDOUT: %MyInt => constants.%MyInt -// CHECK:STDOUT: -// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @MyInt(@Op.2.%N) {} // CHECK:STDOUT: -// CHECK:STDOUT: specific @Op.1(constants.%Add.facet) { -// CHECK:STDOUT: %Self => constants.%Add.facet +// CHECK:STDOUT: specific @Op.1(constants.%Add.facet.c2b) { +// CHECK:STDOUT: %Self => constants.%Add.facet.c2b // CHECK:STDOUT: %Self.as_type.loc5_15.1 => constants.%MyInt // CHECK:STDOUT: } // CHECK:STDOUT: @@ -403,9 +407,12 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: // CHECK:STDOUT: specific @MyInt(@Double.%N.loc19_11.2) {} // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl(@Double.%N.loc19_11.2) {} +// CHECK:STDOUT: specific @Op.1(constants.%Add.facet.f76) { +// CHECK:STDOUT: %Self => constants.%Add.facet.f76 +// CHECK:STDOUT: %Self.as_type.loc5_15.1 => constants.%MyInt +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Op.2(@Double.%N.loc19_11.2) {} +// CHECK:STDOUT: specific @Op.1(@Double.%Add.facet.loc20_11) {} // CHECK:STDOUT: // CHECK:STDOUT: --- use_generic_impl.carbon // CHECK:STDOUT: @@ -435,24 +442,22 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: %Op.8bc: %Op.type.883 = struct_value () [symbolic] // CHECK:STDOUT: %require_complete.fc7: = require_complete_type %MyInt.09f [symbolic] // CHECK:STDOUT: %impl_witness.8d6: = impl_witness (imports.%Main.import_ref.19b), @impl(%int_64) [concrete] -// CHECK:STDOUT: %impl_witness.7e5be3.1: = impl_witness (imports.%Main.import_ref.464c51.1), @impl(%N) [symbolic] +// CHECK:STDOUT: %impl_witness.7e5: = impl_witness (imports.%Main.import_ref.464), @impl(%N) [symbolic] // CHECK:STDOUT: %Op.type.5a6: type = fn_type @Op.2, @impl(%int_64) [concrete] // CHECK:STDOUT: %Op.cf9: %Op.type.5a6 = struct_value () [concrete] // CHECK:STDOUT: %Add.facet.8db: %Add.type = facet_value %MyInt.f30, (%impl_witness.8d6) [concrete] // CHECK:STDOUT: %.1ca: type = fn_type_with_self_type %Op.type.31b, %Add.facet.8db [concrete] -// CHECK:STDOUT: %Op.specific_fn.16a: = specific_function %Op.cf9, @Op.2(%int_64) [concrete] +// CHECK:STDOUT: %Op.specific_fn: = specific_function %Op.cf9, @Op.2(%int_64) [concrete] // CHECK:STDOUT: %CallImportedDouble.type: type = fn_type @CallImportedDouble [concrete] // CHECK:STDOUT: %CallImportedDouble: %CallImportedDouble.type = struct_value () [concrete] // CHECK:STDOUT: %Double.type: type = fn_type @Double [concrete] // CHECK:STDOUT: %Double: %Double.type = struct_value () [concrete] -// CHECK:STDOUT: %impl_witness.7e5be3.2: = impl_witness (imports.%Main.import_ref.464c51.2), @impl(%N) [symbolic] -// CHECK:STDOUT: %Add.facet.afa: %Add.type = facet_value %MyInt.09f, (%impl_witness.7e5be3.2) [symbolic] -// CHECK:STDOUT: %.207: type = fn_type_with_self_type %Op.type.31b, %Add.facet.afa [symbolic] -// CHECK:STDOUT: %Op.specific_fn.6c0: = specific_function %Op.8bc, @Op.2(%N) [symbolic] +// CHECK:STDOUT: %Add.impl_symbolic_witness: = impl_symbolic_witness %MyInt.09f, @Add [symbolic] +// CHECK:STDOUT: %Add.facet.f76: %Add.type = facet_value %MyInt.09f, (%Add.impl_symbolic_witness) [symbolic] +// CHECK:STDOUT: %.dfa: type = fn_type_with_self_type %Op.type.31b, %Add.facet.f76 [symbolic] +// CHECK:STDOUT: %impl.elem0: %.dfa = impl_witness_access %Add.impl_symbolic_witness, element0 [symbolic] +// CHECK:STDOUT: %specific_impl_fn: = specific_impl_function %impl.elem0, @Op.1(%Add.facet.f76) [symbolic] // CHECK:STDOUT: %Double.specific_fn: = specific_function %Double, @Double(%int_64) [concrete] -// CHECK:STDOUT: %impl_witness.bb3: = impl_witness (imports.%Main.import_ref.464c51.2), @impl(%int_64) [concrete] -// CHECK:STDOUT: %Add.facet.287: %Add.type = facet_value %MyInt.f30, (%impl_witness.bb3) [concrete] -// CHECK:STDOUT: %.fc5: type = fn_type_with_self_type %Op.type.31b, %Add.facet.287 [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -468,14 +473,13 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: %Main.import_ref.db7: %Add.assoc_type = import_ref Main//generic_impl, loc5_41, loaded [concrete = constants.%assoc0] // CHECK:STDOUT: %Main.Op = import_ref Main//generic_impl, Op, unloaded // CHECK:STDOUT: %Main.import_ref.e5e: %Add.type = import_ref Main//generic_impl, inst16 [no loc], loaded [symbolic = constants.%Self] -// CHECK:STDOUT: %Main.import_ref.33b: = import_ref Main//generic_impl, loc15_48, loaded [symbolic = @impl.%impl_witness (constants.%impl_witness.7e5be3.1)] +// CHECK:STDOUT: %Main.import_ref.33b: = import_ref Main//generic_impl, loc15_48, loaded [symbolic = @impl.%impl_witness (constants.%impl_witness.7e5)] // CHECK:STDOUT: %Main.import_ref.f1e294.2: Core.IntLiteral = import_ref Main//generic_impl, loc15_14, loaded [symbolic = @impl.%N (constants.%N)] // CHECK:STDOUT: %Main.import_ref.719: type = import_ref Main//generic_impl, loc15_39, loaded [symbolic = @impl.%MyInt (constants.%MyInt.09f)] // CHECK:STDOUT: %Main.import_ref.bf0: type = import_ref Main//generic_impl, loc15_44, loaded [concrete = constants.%Add.type] // CHECK:STDOUT: %Main.import_ref.19b: @impl.%Op.type (%Op.type.883) = import_ref Main//generic_impl, loc16_42, loaded [symbolic = @impl.%Op (constants.%Op.8bc)] // CHECK:STDOUT: %Main.import_ref.f1e294.3: Core.IntLiteral = import_ref Main//generic_impl, loc15_14, loaded [symbolic = @impl.%N (constants.%N)] // CHECK:STDOUT: %Main.import_ref.f1e294.4: Core.IntLiteral = import_ref Main//generic_impl, loc19_11, loaded [symbolic = @Double.%N (constants.%N)] -// CHECK:STDOUT: %Main.import_ref.464c51.2 = import_ref Main//generic_impl, loc16_42, unloaded // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -578,7 +582,7 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: %impl.elem0: %.1ca = impl_witness_access constants.%impl_witness.8d6, element0 [concrete = constants.%Op.cf9] // CHECK:STDOUT: %bound_method.loc9_11: = bound_method %x.ref.loc9_10, %impl.elem0 // CHECK:STDOUT: %x.ref.loc9_21: %MyInt.f30 = name_ref x, %x -// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Op.2(constants.%int_64) [concrete = constants.%Op.specific_fn.16a] +// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Op.2(constants.%int_64) [concrete = constants.%Op.specific_fn] // CHECK:STDOUT: %bound_method.loc9_22: = bound_method %x.ref.loc9_10, %specific_fn // CHECK:STDOUT: %int.sadd: init %MyInt.f30 = call %bound_method.loc9_22(%x.ref.loc9_10, %x.ref.loc9_21) // CHECK:STDOUT: %.loc9_23.1: %MyInt.f30 = value_of_initializer %int.sadd @@ -620,12 +624,11 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: %require_complete: = require_complete_type @Double.%MyInt (%MyInt.09f) [symbolic = %require_complete (constants.%require_complete.fc7)] -// CHECK:STDOUT: %impl_witness: = impl_witness (imports.%Main.import_ref.464c51.2), @impl(%N) [symbolic = %impl_witness (constants.%impl_witness.7e5be3.2)] -// CHECK:STDOUT: %Add.facet: %Add.type = facet_value %MyInt, (%impl_witness) [symbolic = %Add.facet (constants.%Add.facet.afa)] -// CHECK:STDOUT: %.1: type = fn_type_with_self_type constants.%Op.type.31b, %Add.facet [symbolic = %.1 (constants.%.207)] -// CHECK:STDOUT: %Op.type: type = fn_type @Op.2, @impl(%N) [symbolic = %Op.type (constants.%Op.type.883)] -// CHECK:STDOUT: %Op: @Double.%Op.type (%Op.type.883) = struct_value () [symbolic = %Op (constants.%Op.8bc)] -// CHECK:STDOUT: %Op.specific_fn: = specific_function %Op, @Op.2(%N) [symbolic = %Op.specific_fn (constants.%Op.specific_fn.6c0)] +// CHECK:STDOUT: %Add.impl_symbolic_witness: = impl_symbolic_witness %MyInt, @Add [symbolic = %Add.impl_symbolic_witness (constants.%Add.impl_symbolic_witness)] +// CHECK:STDOUT: %Add.facet: %Add.type = facet_value %MyInt, (%Add.impl_symbolic_witness) [symbolic = %Add.facet (constants.%Add.facet.f76)] +// CHECK:STDOUT: %.1: type = fn_type_with_self_type constants.%Op.type.31b, %Add.facet [symbolic = %.1 (constants.%.dfa)] +// CHECK:STDOUT: %impl.elem0: @Double.%.1 (%.dfa) = impl_witness_access %Add.impl_symbolic_witness, element0 [symbolic = %impl.elem0 (constants.%impl.elem0)] +// CHECK:STDOUT: %specific_impl_fn: = specific_impl_function %impl.elem0, @Op.1(%Add.facet) [symbolic = %specific_impl_fn (constants.%specific_impl_fn)] // CHECK:STDOUT: // CHECK:STDOUT: fn[%N.patt.1: Core.IntLiteral](%x.param_patt: @Double.%MyInt (%MyInt.09f)) -> @Double.%MyInt (%MyInt.09f); // CHECK:STDOUT: } @@ -676,8 +679,6 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: specific @Op.2(constants.%N) { // CHECK:STDOUT: %N => constants.%N // CHECK:STDOUT: %MyInt => constants.%MyInt.09f -// CHECK:STDOUT: -// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @impl(constants.%int_64) { @@ -707,9 +708,12 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: %MyInt => constants.%MyInt.09f // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl(@Double.%N) {} +// CHECK:STDOUT: specific @Op.1(constants.%Add.facet.f76) { +// CHECK:STDOUT: %Self => constants.%Add.facet.f76 +// CHECK:STDOUT: %Self.as_type => constants.%MyInt.09f +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @Op.2(@Double.%N) {} +// CHECK:STDOUT: specific @Op.1(@Double.%Add.facet) {} // CHECK:STDOUT: // CHECK:STDOUT: specific @Double(constants.%int_64) { // CHECK:STDOUT: %N => constants.%int_64 @@ -718,12 +722,16 @@ var n: Int(64) = MakeFromClass(FromLiteral(64) as OtherInt); // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: %require_complete => constants.%complete_type.4a1 -// CHECK:STDOUT: %impl_witness => constants.%impl_witness.bb3 -// CHECK:STDOUT: %Add.facet => constants.%Add.facet.287 -// CHECK:STDOUT: %.1 => constants.%.fc5 -// CHECK:STDOUT: %Op.type => constants.%Op.type.5a6 -// CHECK:STDOUT: %Op => constants.%Op.cf9 -// CHECK:STDOUT: %Op.specific_fn => constants.%Op.specific_fn.16a +// CHECK:STDOUT: %Add.impl_symbolic_witness => constants.%impl_witness.8d6 +// CHECK:STDOUT: %Add.facet => constants.%Add.facet.8db +// CHECK:STDOUT: %.1 => constants.%.1ca +// CHECK:STDOUT: %impl.elem0 => constants.%Op.cf9 +// CHECK:STDOUT: %specific_impl_fn => constants.%Op.specific_fn +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @Op.1(constants.%Add.facet.8db) { +// CHECK:STDOUT: %Self => constants.%Add.facet.8db +// CHECK:STDOUT: %Self.as_type => constants.%MyInt.f30 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- convert_symbolic.carbon diff --git a/toolchain/check/testdata/interface/no_prelude/fail_assoc_const_alias.carbon b/toolchain/check/testdata/interface/no_prelude/fail_assoc_const_alias.carbon index ebc6a14d98a0..ed51aad4cf2b 100644 --- a/toolchain/check/testdata/interface/no_prelude/fail_assoc_const_alias.carbon +++ b/toolchain/check/testdata/interface/no_prelude/fail_assoc_const_alias.carbon @@ -360,13 +360,15 @@ interface C { // CHECK:STDOUT: %.Self.as_type: type = facet_access_type %.Self [symbolic_self] // CHECK:STDOUT: %.Self.as_wit.iface0: = facet_access_witness %.Self, element0 [symbolic_self] // CHECK:STDOUT: %I2.facet.b82: %I2.type = facet_value %.Self.as_type, (%.Self.as_wit.iface0) [symbolic_self] -// CHECK:STDOUT: %impl.elem0: type = impl_witness_access %.Self.as_wit.iface0, element0 [symbolic_self] -// CHECK:STDOUT: %I2_where.type: type = facet_type <@I2 where %impl.elem0 = %empty_tuple.type> [concrete] +// CHECK:STDOUT: %impl.elem0.71d: type = impl_witness_access %.Self.as_wit.iface0, element0 [symbolic_self] +// CHECK:STDOUT: %I2_where.type: type = facet_type <@I2 where %impl.elem0.71d = %empty_tuple.type> [concrete] // CHECK:STDOUT: %impl_witness.ec95d0.1: = impl_witness (%empty_tuple.type), @impl(%V) [symbolic] // CHECK:STDOUT: %Self.541: %J2.type = bind_symbolic_name Self, 0 [symbolic] // CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self.541 [symbolic] // CHECK:STDOUT: %impl_witness.ec95d0.2: = impl_witness (%empty_tuple.type), @impl(%Self.541) [symbolic] -// CHECK:STDOUT: %I2.facet.746: %I2.type = facet_value %Self.as_type, (%impl_witness.ec95d0.2) [symbolic] +// CHECK:STDOUT: %I2.impl_symbolic_witness: = impl_symbolic_witness %Self.541, @I2 [symbolic] +// CHECK:STDOUT: %I2.facet.fc4: %I2.type = facet_value %Self.as_type, (%I2.impl_symbolic_witness) [symbolic] +// CHECK:STDOUT: %impl.elem0.e6b: type = impl_witness_access %I2.impl_symbolic_witness, element0 [symbolic] // CHECK:STDOUT: %F2.type: type = fn_type @F2 [concrete] // CHECK:STDOUT: %F2: %F2.type = struct_value () [concrete] // CHECK:STDOUT: %J2.assoc_type: type = assoc_entity_type %J2.type [concrete] @@ -401,7 +403,7 @@ interface C { // CHECK:STDOUT: %.Self.as_type: type = facet_access_type %.Self.ref [symbolic_self = constants.%.Self.as_type] // CHECK:STDOUT: %.loc11_36: type = converted %.Self.ref, %.Self.as_type [symbolic_self = constants.%.Self.as_type] // CHECK:STDOUT: %.Self.as_wit.iface0: = facet_access_witness %.Self.ref, element0 [symbolic_self = constants.%.Self.as_wit.iface0] -// CHECK:STDOUT: %impl.elem0: type = impl_witness_access %.Self.as_wit.iface0, element0 [symbolic_self = constants.%impl.elem0] +// CHECK:STDOUT: %impl.elem0: type = impl_witness_access %.Self.as_wit.iface0, element0 [symbolic_self = constants.%impl.elem0.71d] // CHECK:STDOUT: %.loc11_43.1: %empty_tuple.type = tuple_literal () // CHECK:STDOUT: %.loc11_43.2: type = converted %.loc11_43.1, constants.%empty_tuple.type [concrete = constants.%empty_tuple.type] // CHECK:STDOUT: %.loc11_30: type = where_expr %.Self [concrete = constants.%I2_where.type] { @@ -432,21 +434,24 @@ interface C { // CHECK:STDOUT: %T2.ref: %I2.assoc_type = name_ref T2, @T2.%assoc0 [concrete = constants.%assoc0.166] // CHECK:STDOUT: %U2: %I2.assoc_type = bind_alias U2, @T2.%assoc0 [concrete = constants.%assoc0.166] // CHECK:STDOUT: %F2.decl: %F2.type = fn_decl @F2 [concrete = constants.%F2] { -// CHECK:STDOUT: %return.patt: %empty_tuple.type = return_slot_pattern -// CHECK:STDOUT: %return.param_patt: %empty_tuple.type = out_param_pattern %return.patt, call_param0 +// CHECK:STDOUT: %return.patt: @F2.%impl.elem0.loc15_14.1 (%impl.elem0.e6b) = return_slot_pattern +// CHECK:STDOUT: %return.param_patt: @F2.%impl.elem0.loc15_14.1 (%impl.elem0.e6b) = out_param_pattern %return.patt, call_param0 // CHECK:STDOUT: } { // CHECK:STDOUT: %Self.as_type.loc15_14.2: type = facet_access_type constants.%Self.541 [symbolic = %Self.as_type.loc15_14.1 (constants.%Self.as_type)] // CHECK:STDOUT: %.loc15_14.1: type = converted constants.%Self.541, %Self.as_type.loc15_14.2 [symbolic = %Self.as_type.loc15_14.1 (constants.%Self.as_type)] // CHECK:STDOUT: %.loc15_14.2: %J2.type = converted %.loc15_14.1, constants.%Self.541 [symbolic = %Self (constants.%Self.541)] // CHECK:STDOUT: %Self.as_type.loc15_14.3: type = facet_access_type constants.%Self.541 [symbolic = %Self.as_type.loc15_14.1 (constants.%Self.as_type)] -// CHECK:STDOUT: %I2.facet.loc15_14.2: %I2.type = facet_value %Self.as_type.loc15_14.3, (constants.%impl_witness.ec95d0.2) [symbolic = %I2.facet.loc15_14.1 (constants.%I2.facet.746)] -// CHECK:STDOUT: %.loc15_14.3: %I2.type = converted @J2.%Self, %I2.facet.loc15_14.2 [symbolic = %I2.facet.loc15_14.1 (constants.%I2.facet.746)] -// CHECK:STDOUT: %as_wit.iface0: = facet_access_witness %.loc15_14.3, element0 [symbolic = %impl_witness (constants.%impl_witness.ec95d0.2)] -// CHECK:STDOUT: %impl.elem0: type = impl_witness_access %as_wit.iface0, element0 [concrete = constants.%empty_tuple.type] -// CHECK:STDOUT: %U2.ref: type = name_ref U2, %impl.elem0 [concrete = constants.%empty_tuple.type] -// CHECK:STDOUT: %return.param: ref %empty_tuple.type = out_param call_param0 -// CHECK:STDOUT: %return: ref %empty_tuple.type = return_slot %return.param +// CHECK:STDOUT: %I2.facet.loc15_14.2: %I2.type = facet_value %Self.as_type.loc15_14.3, (constants.%I2.impl_symbolic_witness) [symbolic = %I2.facet.loc15_14.1 (constants.%I2.facet.fc4)] +// CHECK:STDOUT: %.loc15_14.3: %I2.type = converted @J2.%Self, %I2.facet.loc15_14.2 [symbolic = %I2.facet.loc15_14.1 (constants.%I2.facet.fc4)] +// CHECK:STDOUT: %as_wit.iface0: = facet_access_witness %.loc15_14.3, element0 [symbolic = %I2.impl_symbolic_witness (constants.%I2.impl_symbolic_witness)] +// CHECK:STDOUT: %impl.elem0.loc15_14.2: type = impl_witness_access %as_wit.iface0, element0 [symbolic = %impl.elem0.loc15_14.1 (constants.%impl.elem0.e6b)] +// CHECK:STDOUT: %U2.ref: type = name_ref U2, %impl.elem0.loc15_14.2 [symbolic = %impl.elem0.loc15_14.1 (constants.%impl.elem0.e6b)] +// CHECK:STDOUT: %return.param: ref @F2.%impl.elem0.loc15_14.1 (%impl.elem0.e6b) = out_param call_param0 +// CHECK:STDOUT: %return: ref @F2.%impl.elem0.loc15_14.1 (%impl.elem0.e6b) = return_slot %return.param // CHECK:STDOUT: } +// CHECK:STDOUT: %Self.as_type: type = facet_access_type constants.%Self.541 [symbolic = constants.%Self.as_type] +// CHECK:STDOUT: %.loc15_14.1: type = converted constants.%Self.541, %Self.as_type [symbolic = constants.%Self.as_type] +// CHECK:STDOUT: %.loc15_14.2: %J2.type = converted %.loc15_14.1, constants.%Self.541 [symbolic = constants.%Self.541] // CHECK:STDOUT: %assoc0: %J2.assoc_type = assoc_entity element0, %F2.decl [concrete = constants.%assoc0.5b2] // CHECK:STDOUT: // CHECK:STDOUT: !members: @@ -478,10 +483,11 @@ interface C { // CHECK:STDOUT: generic fn @F2(@J2.%Self: %J2.type) { // CHECK:STDOUT: %Self: %J2.type = bind_symbolic_name Self, 0 [symbolic = %Self (constants.%Self.541)] // CHECK:STDOUT: %Self.as_type.loc15_14.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc15_14.1 (constants.%Self.as_type)] -// CHECK:STDOUT: %impl_witness: = impl_witness (constants.%empty_tuple.type), @impl(%Self) [symbolic = %impl_witness (constants.%impl_witness.ec95d0.2)] -// CHECK:STDOUT: %I2.facet.loc15_14.1: %I2.type = facet_value %Self.as_type.loc15_14.1, (%impl_witness) [symbolic = %I2.facet.loc15_14.1 (constants.%I2.facet.746)] +// CHECK:STDOUT: %I2.impl_symbolic_witness: = impl_symbolic_witness %Self, @I2 [symbolic = %I2.impl_symbolic_witness (constants.%I2.impl_symbolic_witness)] +// CHECK:STDOUT: %I2.facet.loc15_14.1: %I2.type = facet_value %Self.as_type.loc15_14.1, (%I2.impl_symbolic_witness) [symbolic = %I2.facet.loc15_14.1 (constants.%I2.facet.fc4)] +// CHECK:STDOUT: %impl.elem0.loc15_14.1: type = impl_witness_access %I2.impl_symbolic_witness, element0 [symbolic = %impl.elem0.loc15_14.1 (constants.%impl.elem0.e6b)] // CHECK:STDOUT: -// CHECK:STDOUT: fn() -> %empty_tuple.type; +// CHECK:STDOUT: fn() -> @F2.%impl.elem0.loc15_14.1 (%impl.elem0.e6b); // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @T2(constants.%Self.c7b) {} @@ -506,17 +512,16 @@ interface C { // CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @T2(constants.%I2.facet.746) {} +// CHECK:STDOUT: specific @T2(constants.%I2.facet.fc4) {} // CHECK:STDOUT: // CHECK:STDOUT: specific @F2(constants.%Self.541) { // CHECK:STDOUT: %Self => constants.%Self.541 // CHECK:STDOUT: %Self.as_type.loc15_14.1 => constants.%Self.as_type -// CHECK:STDOUT: %impl_witness => constants.%impl_witness.ec95d0.2 -// CHECK:STDOUT: %I2.facet.loc15_14.1 => constants.%I2.facet.746 +// CHECK:STDOUT: %I2.impl_symbolic_witness => constants.%I2.impl_symbolic_witness +// CHECK:STDOUT: %I2.facet.loc15_14.1 => constants.%I2.facet.fc4 +// CHECK:STDOUT: %impl.elem0.loc15_14.1 => constants.%impl.elem0.e6b // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @impl(@F2.%Self) {} -// CHECK:STDOUT: // CHECK:STDOUT: --- fail_call_method_alias.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/check/type_completion.cpp b/toolchain/check/type_completion.cpp index 0ffce0fe1b18..6e92bf25c13d 100644 --- a/toolchain/check/type_completion.cpp +++ b/toolchain/check/type_completion.cpp @@ -11,6 +11,7 @@ #include "toolchain/check/type.h" #include "toolchain/diagnostics/format_providers.h" #include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { diff --git a/toolchain/check/type_structure.cpp b/toolchain/check/type_structure.cpp index bcb62f7b8873..59a9e47f6ac8 100644 --- a/toolchain/check/type_structure.cpp +++ b/toolchain/check/type_structure.cpp @@ -206,7 +206,8 @@ class TypeStructureBuilder { case SemIR::IntLiteralType::Kind: case SemIR::LegacyFloatType::Kind: case SemIR::StringType::Kind: - case SemIR::TypeType::Kind: { + case SemIR::TypeType::Kind: + case SemIR::WitnessType::Kind: { AppendStructural(TypeStructure::Structural::Concrete); break; } diff --git a/toolchain/sem_ir/dump.cpp b/toolchain/sem_ir/dump.cpp index 7d79559fc5f3..c80be9363c80 100644 --- a/toolchain/sem_ir/dump.cpp +++ b/toolchain/sem_ir/dump.cpp @@ -247,7 +247,20 @@ LLVM_DUMP_METHOD auto Dump(const File& file, LLVM_DUMP_METHOD auto Dump(const File& file, SpecificId specific_id) -> void { DumpNoNewline(file, specific_id); llvm::errs() << '\n'; - Dump(file, file.specifics().Get(specific_id).args_id); + if (specific_id.has_value()) { + Dump(file, file.specifics().Get(specific_id).args_id); + } +} + +LLVM_DUMP_METHOD auto Dump(const File& file, + SpecificInterfaceId specific_interface_id) -> void { + const auto& interface = file.specific_interfaces().Get(specific_interface_id); + llvm::errs() << specific_interface_id << '\n'; + llvm::errs() << " - interface: "; + DumpNoNewline(file, interface.interface_id); + llvm::errs() << '\n'; + llvm::errs() << " - specific_id: "; + Dump(file, interface.specific_id); } LLVM_DUMP_METHOD auto Dump(const File& file, @@ -336,6 +349,10 @@ LLVM_DUMP_METHOD static auto MakeCompleteFacetTypeId(int id) LLVM_DUMP_METHOD static auto MakeSpecificId(int id) -> SpecificId { return SpecificId(id); } +LLVM_DUMP_METHOD static auto MakeSpecificInterfaceId(int id) + -> SpecificInterfaceId { + return SpecificInterfaceId(id); +} LLVM_DUMP_METHOD static auto MakeStructTypeFieldsId(int id) -> StructTypeFieldsId { return StructTypeFieldsId(id); diff --git a/toolchain/sem_ir/dump.h b/toolchain/sem_ir/dump.h index c0a674ee0fa0..6080498f20b5 100644 --- a/toolchain/sem_ir/dump.h +++ b/toolchain/sem_ir/dump.h @@ -34,6 +34,7 @@ auto Dump(const File& file, NameId name_id) -> void; auto Dump(const File& file, NameScopeId name_scope_id) -> void; auto Dump(const File& file, CompleteFacetTypeId complete_facet_type_id) -> void; auto Dump(const File& file, SpecificId specific_id) -> void; +auto Dump(const File& file, SpecificInterfaceId specific_interface_id) -> void; auto Dump(const File& file, StructTypeFieldsId struct_type_fields_id) -> void; auto Dump(const File& file, TypeBlockId type_block_id) -> void; auto Dump(const File& file, TypeId type_id) -> void; diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index d4765ecc2c2c..96b335b264ec 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -270,6 +270,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { case FunctionTypeWithSelfType::Kind: case GenericClassType::Kind: case GenericInterfaceType::Kind: + case ImplSymbolicWitness::Kind: case ImplWitness::Kind: case ImplWitnessAccess::Kind: case ImportCppDecl::Kind: diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 4ab45525b6c3..a0682266e31f 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -169,6 +169,13 @@ class File : public Printable { } auto impls() -> ImplStore& { return impls_; } auto impls() const -> const ImplStore& { return impls_; } + auto specific_interfaces() -> CanonicalValueStore& { + return specific_interfaces_; + } + auto specific_interfaces() const + -> const CanonicalValueStore& { + return specific_interfaces_; + } auto generics() -> GenericStore& { return generics_; } auto generics() const -> const GenericStore& { return generics_; } auto specifics() -> SpecificStore& { return specifics_; } @@ -291,6 +298,10 @@ class File : public Printable { // Storage for impls. ImplStore impls_; + // Storage for specific interfaces, which are an individual unit of impl + // lookup for a single interface. + CanonicalValueStore specific_interfaces_; + // Storage for generics. GenericStore generics_; diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 55d8a0c653fd..555ac91544f2 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -1388,6 +1388,15 @@ class FormatterImpl { FormatArg(specific.args_id); } + auto FormatName(SpecificInterfaceId id) -> void { + const auto& interface = sem_ir_->specific_interfaces().Get(id); + FormatName(interface.interface_id); + if (interface.specific_id.has_value()) { + out_ << ", "; + FormatArg(interface.specific_id); + } + } + auto FormatLabel(InstBlockId id) -> void { out_ << inst_namer_->GetLabelFor(scope_, id); } diff --git a/toolchain/sem_ir/id_kind.h b/toolchain/sem_ir/id_kind.h index 015a96f44c35..41977706a576 100644 --- a/toolchain/sem_ir/id_kind.h +++ b/toolchain/sem_ir/id_kind.h @@ -135,17 +135,52 @@ class TypeEnum : public Printable> { // instructions (`toolchain/sem_ir/typed_insts.h`) and must implement the // `FromRaw` and `ToRaw` protocol in `SemIR::Inst`. In most cases this is done // by inheriting from `IdBase` or `IndexBase`. +// +// clang-format off: We want one per line. using IdKind = TypeEnum< // From base/value_store.h. - IntId, RealId, FloatId, StringLiteralValueId, + FloatId, + IntId, + RealId, + StringLiteralValueId, // From sem_ir/ids.h. - InstId, AbsoluteInstId, DestInstId, MetaInstId, AnyRawId, ConstantId, - EntityNameId, CompileTimeBindIndex, CallParamIndex, FacetTypeId, FunctionId, - ClassId, InterfaceId, AssociatedConstantId, ImplId, GenericId, SpecificId, - ImportIRId, ImportIRInstId, LocId, BoolValue, IntKind, NameId, NameScopeId, - InstBlockId, AbsoluteInstBlockId, DeclInstBlockId, LabelId, ExprRegionId, - StructTypeFieldsId, TypeId, TypeBlockId, ElementIndex, LibraryNameId, - FloatKind>; + AbsoluteInstBlockId, + AbsoluteInstId, + AnyRawId, + AssociatedConstantId, + BoolValue, + CallParamIndex, + ClassId, + CompileTimeBindIndex, + ConstantId, + DeclInstBlockId, + DestInstId, + ElementIndex, + EntityNameId, + ExprRegionId, + FacetTypeId, + FloatKind, + FunctionId, + GenericId, + ImplId, + ImportIRId, + ImportIRInstId, + InstBlockId, + InstId, + InterfaceId, + IntKind, + LabelId, + LibraryNameId, + LocId, + MetaInstId, + NameId, + NameScopeId, + SpecificId, + SpecificInterfaceId, + StructTypeFieldsId, + TypeBlockId, + TypeId>; +// clang-format on } // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 7c5a653c6f6d..6d9ee0f13a9f 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -27,6 +27,7 @@ struct Function; struct Generic; struct CompleteFacetType; struct Specific; +struct SpecificInterface; struct ImportCpp; struct ImportIR; struct ImportIRInst; @@ -306,6 +307,14 @@ struct SpecificId : public IdBase { using IdBase::IdBase; }; +// The ID of a SpecificInterface, which is an interface and a specific pair. +struct SpecificInterfaceId : public IdBase { + static constexpr llvm::StringLiteral Label = "specific_interface"; + using ValueType = SpecificInterface; + + using IdBase::IdBase; +}; + // The index of an instruction that depends on generic parameters within a // region of a generic. A corresponding specific version of the instruction can // be found in each specific corresponding to that generic. This is a pair of a diff --git a/toolchain/sem_ir/inst_fingerprinter.cpp b/toolchain/sem_ir/inst_fingerprinter.cpp index 0896920452de..b68c85686ec2 100644 --- a/toolchain/sem_ir/inst_fingerprinter.cpp +++ b/toolchain/sem_ir/inst_fingerprinter.cpp @@ -240,6 +240,17 @@ struct Worklist { Add(specific.args_id); } + auto Add(SpecificInterfaceId specific_interface_id) -> void { + if (!specific_interface_id.has_value()) { + AddInvalid(); + return; + } + const auto& interface = + sem_ir->specific_interfaces().Get(specific_interface_id); + Add(interface.interface_id); + Add(interface.specific_id); + } + auto Add(const llvm::APInt& value) -> void { contents.push_back(value.getBitWidth()); for (auto word : llvm::seq((value.getBitWidth() + 63) / 64)) { diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index f03e31336a5a..e4edc92444c4 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -70,6 +70,7 @@ CARBON_SEM_IR_INST_KIND(FunctionTypeWithSelfType) CARBON_SEM_IR_INST_KIND(GenericClassType) CARBON_SEM_IR_INST_KIND(GenericInterfaceType) CARBON_SEM_IR_INST_KIND(ImplDecl) +CARBON_SEM_IR_INST_KIND(ImplSymbolicWitness) CARBON_SEM_IR_INST_KIND(ImplWitness) CARBON_SEM_IR_INST_KIND(ImplWitnessAccess) CARBON_SEM_IR_INST_KIND(ImportCppDecl) diff --git a/toolchain/sem_ir/inst_namer.cpp b/toolchain/sem_ir/inst_namer.cpp index 8559eb6ee0cf..79b6e8c523eb 100644 --- a/toolchain/sem_ir/inst_namer.cpp +++ b/toolchain/sem_ir/inst_namer.cpp @@ -696,6 +696,14 @@ auto InstNamer::CollectNamesInBlock(ScopeId top_scope_id, queue_block_id(impl_scope_id, inst.decl_block_id); break; } + case CARBON_KIND(ImplSymbolicWitness inst): { + const auto& interface = sem_ir_->specific_interfaces().Get( + inst.query_specific_interface_id); + add_inst_name_id( + sem_ir_->interfaces().Get(interface.interface_id).name_id, + ".impl_symbolic_witness"); + continue; + } case ImplWitness::Kind: { // TODO: Include name of interface (is this available from the // specific?). diff --git a/toolchain/sem_ir/inst_namer.h b/toolchain/sem_ir/inst_namer.h index 0021aa306a19..4143a085d1d6 100644 --- a/toolchain/sem_ir/inst_namer.h +++ b/toolchain/sem_ir/inst_namer.h @@ -50,8 +50,11 @@ class InstNamer { index += sem_ir_->associated_constants().size(); if constexpr (!std::same_as) { index += sem_ir_->impls().size(); - static_assert(std::same_as, - "Unknown ID kind for scope"); + if constexpr (!std::same_as) { + index += sem_ir_->specific_interfaces().size(); + static_assert(std::same_as, + "Unknown ID kind for scope"); + } } } } diff --git a/toolchain/sem_ir/stringify_type.cpp b/toolchain/sem_ir/stringify_type.cpp index 2c24ad8f67d0..f8b1d6a60afe 100644 --- a/toolchain/sem_ir/stringify_type.cpp +++ b/toolchain/sem_ir/stringify_type.cpp @@ -375,6 +375,11 @@ class Stringifier { -> void { auto witness_inst_id = sem_ir_->constant_values().GetConstantInstId(inst.witness_id); + if (sem_ir_->insts().Is(witness_inst_id)) { + // TODO: Include the query in the diagnostic output? + step_stack_->PushString(""); + return; + } auto witness = sem_ir_->insts().GetAs(witness_inst_id); auto witness_type_id = sem_ir_->insts().Get(witness.facet_value_inst_id).type_id(); diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index f44cfbb8d474..3628013b3aad 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -868,6 +868,24 @@ struct ImplDecl { DeclInstBlockId decl_block_id; }; +// A symbolic witness that a type implements an interface. It represents a +// promise that an impl lookup query can be satisfied without providing which +// impl declaration satisfies it. When evaluated, it does lookup again to form a +// concrete ImplWitness from a more specific query. +struct ImplSymbolicWitness { + static constexpr auto Kind = + InstKind::ImplSymbolicWitness.Define( + {.ir_name = "impl_symbolic_witness", + .constant_kind = InstConstantKind::SymbolicOnly, + .is_lowered = false}); + + // Always the type of the builtin `WitnessType` singleton instruction. + TypeId type_id; + // The self type (or facet value) and interface of the impl lookup query. + InstId query_self_inst_id; + SpecificInterfaceId query_specific_interface_id; +}; + // A witness that a type implements an interface. struct ImplWitness { static constexpr auto Kind = InstKind::ImplWitness.Define( @@ -1780,7 +1798,9 @@ struct WhereExpr { InstBlockId requirements_id; }; -// The type of `ImplWitness` instructions. +// The type of `ImplWitness` and `ImplSymbolicType` instructions. The latter +// will evaluate at some point during specific computation into the former, and +// their types should not change in the process. struct WitnessType { static constexpr auto Kind = InstKind::WitnessType.Define( {.ir_name = "",