mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-11-10 12:08:29 +00:00
Move IdentifiedFacetType to check (#8004)
`IdentifiedFacetType` is a concept that is only used by check. It does not appear in the semir output, unlike `DeclaredFacetType`s. `IdentifiedFacetType` is used in check to collapse named constraints together, building a single structure of requirements from a `DeclaredFacetType` and any referenced named constraints. This is used for operations like impl lookup, and building `FacetValue`s. The outputs of `IdentifiedFacetType` are now in an intermediate state, where they contain `IdentifiedWitness`es, and need to be processed before they are used. We'd like to build that into the API of `IdentifiedFacetType` so that their use is more robust. But the `IdentifiedWitnesses` need to be replaced by subst, which is a part of check, so we need to move `IdentifiedFacetType` to check in order to build the type on top of subst.
This commit is contained in:
1 parent
0546b48a7d
commit
fb7eff130d
28 files changed
+618
-607
No files matched your search
+1
-1
@@ -97,7 +97,7 @@ Example usage:
|
||||
"function": "SemIR::MakeFunctionId",
|
||||
"generated_function": "SemIR::MakeGeneratedFunctionId",
|
||||
"generic": "SemIR::MakeGenericId",
|
||||
"identified_facet_type": "SemIR::MakeIdentifiedFacetTypeId",
|
||||
"identified_facet_type": "Check::MakeIdentifiedFacetTypeId",
|
||||
"impl": "SemIR::MakeImplId",
|
||||
"inst": "SemIR::MakeInstId",
|
||||
"inst_block": "SemIR::MakeInstBlockId",
|
||||
|
||||
@@ -48,6 +48,7 @@ cc_library(
|
||||
"function.cpp",
|
||||
"generic.cpp",
|
||||
"global_init.cpp",
|
||||
"identified_facet_type.cpp",
|
||||
"impl.cpp",
|
||||
"impl_lookup.cpp",
|
||||
"impl_validation.cpp",
|
||||
@@ -116,6 +117,7 @@ cc_library(
|
||||
"function.h",
|
||||
"generic.h",
|
||||
"global_init.h",
|
||||
"identified_facet_type.h",
|
||||
"impl.h",
|
||||
"impl_lookup.h",
|
||||
"impl_validation.h",
|
||||
|
||||
@@ -40,7 +40,8 @@ Context::Context(DiagnosticEmitterBase* emitter,
|
||||
TODO(loc_id, label);
|
||||
}),
|
||||
core_identifiers_(&identifiers()),
|
||||
mangle_string_fingerprint_(mangle_string_fingerprint) {
|
||||
mangle_string_fingerprint_(mangle_string_fingerprint),
|
||||
identified_facet_types_(sem_ir->check_ir_id()) {
|
||||
// Prepare fields which relate to the number of IRs available for import.
|
||||
import_irs().Reserve(imported_ir_count);
|
||||
import_ir_constant_values_.reserve(imported_ir_count);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "toolchain/check/full_pattern_stack.h"
|
||||
#include "toolchain/check/generic_region_stack.h"
|
||||
#include "toolchain/check/global_init.h"
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
#include "toolchain/check/inst_block_stack.h"
|
||||
#include "toolchain/check/node_stack.h"
|
||||
#include "toolchain/check/param_and_arg_refs_stack.h"
|
||||
@@ -33,7 +34,6 @@
|
||||
#include "toolchain/parse/tree_and_subtrees.h"
|
||||
#include "toolchain/sem_ir/declared_facet_type.h"
|
||||
#include "toolchain/sem_ir/file.h"
|
||||
#include "toolchain/sem_ir/identified_facet_type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/import_ir.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
@@ -367,6 +367,13 @@ class Context {
|
||||
|
||||
auto access_context() -> SemIR::NameScopeId& { return access_context_; }
|
||||
|
||||
auto identified_facet_types() -> IdentifiedFacetTypeStore& {
|
||||
return identified_facet_types_;
|
||||
}
|
||||
auto identified_facet_types() const -> const IdentifiedFacetTypeStore& {
|
||||
return identified_facet_types_;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Directly expose SemIR::File data accessors for brevity in calls.
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -414,9 +421,6 @@ class Context {
|
||||
auto declared_facet_types() -> SemIR::DeclaredFacetTypeStore& {
|
||||
return sem_ir().declared_facet_types();
|
||||
}
|
||||
auto identified_facet_types() -> SemIR::IdentifiedFacetTypeStore& {
|
||||
return sem_ir().identified_facet_types();
|
||||
}
|
||||
auto impls() -> SemIR::ImplStore& { return sem_ir().impls(); }
|
||||
auto specific_interfaces() -> SemIR::SpecificInterfaceStore& {
|
||||
return sem_ir().specific_interfaces();
|
||||
@@ -671,6 +675,9 @@ class Context {
|
||||
// This is updated by `DeclNameStack`. During monomorphization, it is updated
|
||||
// by `TryEvalBlockForSpecific`.
|
||||
SemIR::NameScopeId access_context_ = SemIR::NameScopeId::None;
|
||||
|
||||
// Storage for identified facet types.
|
||||
IdentifiedFacetTypeStore identified_facet_types_;
|
||||
};
|
||||
|
||||
inline constexpr Context::FormExpr Context::FormExpr::Error = {
|
||||
|
||||
@@ -100,9 +100,35 @@ LLVM_DUMP_METHOD static auto Dump(const Context& context,
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD static auto Dump(
|
||||
const Context& context,
|
||||
SemIR::IdentifiedFacetTypeId identified_facet_type_id) -> std::string {
|
||||
return SemIR::Dump(context.sem_ir(), identified_facet_type_id);
|
||||
const Context& context, IdentifiedFacetTypeId identified_facet_type_id)
|
||||
-> std::string {
|
||||
RawStringOstream out;
|
||||
out << identified_facet_type_id;
|
||||
if (!identified_facet_type_id.has_value()) {
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
const auto& identified_facet_type =
|
||||
context.identified_facet_types().Get(identified_facet_type_id);
|
||||
for (auto [i, req_impl] :
|
||||
llvm::enumerate(identified_facet_type.required_impls())) {
|
||||
auto [self, req_interface] = req_impl;
|
||||
out << "\n - self: " << DumpConstantSummary(context.sem_ir(), self);
|
||||
out << "\n impls: "
|
||||
<< DumpInterfaceSummary(context.sem_ir(), req_interface.interface_id);
|
||||
if (req_interface.specific_id.has_value()) {
|
||||
out << "; "
|
||||
<< DumpSpecificSummary(context.sem_ir(), req_interface.specific_id);
|
||||
}
|
||||
if (req_interface == identified_facet_type.impl_as_target_interface()) {
|
||||
out << "\n - `impl as` target";
|
||||
}
|
||||
}
|
||||
if (!identified_facet_type.is_valid_impl_as_target()) {
|
||||
out << "\n - " << identified_facet_type.num_interfaces_to_impl()
|
||||
<< " possible `impl as` targets";
|
||||
}
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD static auto Dump(const Context& context, SemIR::ImplId impl_id)
|
||||
@@ -207,6 +233,11 @@ LLVM_DUMP_METHOD static auto Dump(const Context& context, SemIR::TypeId type_id)
|
||||
return SemIR::Dump(context.sem_ir(), type_id);
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD static auto MakeIdentifiedFacetTypeId(int id)
|
||||
-> IdentifiedFacetTypeId {
|
||||
return IdentifiedFacetTypeId(id);
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
#endif // NDEBUG
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "toolchain/check/diagnostic_helpers.h"
|
||||
#include "toolchain/check/facet_type.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
#include "toolchain/check/impl_lookup.h"
|
||||
#include "toolchain/check/import_ref.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
|
||||
#include "toolchain/check/facet_type.h"
|
||||
|
||||
#include "toolchain/base/kind_switch.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/import_ref.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/interface.h"
|
||||
@@ -541,231 +539,4 @@ auto FindWhere(Context& context, SemIR::ConstantId const_id) -> bool {
|
||||
return found;
|
||||
}
|
||||
|
||||
class EvaluateSubstCallbacks : public SubstInstCallbacks {
|
||||
public:
|
||||
explicit EvaluateSubstCallbacks(
|
||||
Context* context, SemIR::LocId loc_id,
|
||||
SubstIdentifiedWitnessesCallbacks* subst_callbacks = nullptr)
|
||||
: SubstInstCallbacks(context),
|
||||
loc_id_(loc_id),
|
||||
subst_callbacks_(subst_callbacks) {}
|
||||
|
||||
auto Subst(SemIR::InstId& inst_id) -> SubstResult override {
|
||||
// SubstPeriodSelf recurses into facet types, so we need to do the same to
|
||||
// find those witnesses first. So we can't early out if the inst has a
|
||||
// concrete constant value.
|
||||
if (inst_id == SemIR::TypeType::TypeInstId ||
|
||||
inst_id == SemIR::ErrorInst::InstId) {
|
||||
return FullySubstituted;
|
||||
}
|
||||
return SubstOperands;
|
||||
}
|
||||
|
||||
auto ReuseUnchanged(SemIR::InstId orig_inst_id) -> SemIR::InstId override {
|
||||
if (auto witness = context().insts().TryGetAs<SemIR::IdentifiedWitness>(
|
||||
orig_inst_id)) {
|
||||
return SubstIdentifiedWitness(*witness);
|
||||
}
|
||||
if (auto witness =
|
||||
context().insts().TryGetAs<SemIR::ImplSelfWitness>(orig_inst_id)) {
|
||||
return SubstImplSelfWitness(*witness);
|
||||
}
|
||||
return orig_inst_id;
|
||||
}
|
||||
|
||||
auto Rebuild(SemIR::InstId /*orig_inst_id*/, SemIR::Inst new_inst)
|
||||
-> SemIR::InstId override {
|
||||
if (auto witness = new_inst.TryAs<SemIR::IdentifiedWitness>()) {
|
||||
return SubstIdentifiedWitness(*witness);
|
||||
}
|
||||
if (auto witness = new_inst.TryAs<SemIR::ImplSelfWitness>()) {
|
||||
return SubstImplSelfWitness(*witness);
|
||||
}
|
||||
return RebuildNewInst(loc_id_, new_inst);
|
||||
}
|
||||
|
||||
auto RebuildSpecific(SemIR::SpecificId orig_specific_id,
|
||||
SemIR::InstBlockId args_id)
|
||||
-> SemIR::SpecificId override {
|
||||
auto generic_id = context().specifics().Get(orig_specific_id).generic_id;
|
||||
// Drop the `identified` flag from any specifics we create here, as we have
|
||||
// substituted the IdentifiedWitness instructions away.
|
||||
return context().specifics().GetOrAdd(generic_id, args_id,
|
||||
/*identified=*/false);
|
||||
}
|
||||
|
||||
private:
|
||||
auto SubstIdentifiedWitness(SemIR::IdentifiedWitness witness)
|
||||
-> SemIR::InstId {
|
||||
if (subst_callbacks_) {
|
||||
auto replaced_id = subst_callbacks_->ReplaceIdentified(witness);
|
||||
if (replaced_id.has_value()) {
|
||||
CARBON_CHECK(
|
||||
!context().insts().Is<SemIR::IdentifiedWitness>(replaced_id));
|
||||
return replaced_id;
|
||||
}
|
||||
}
|
||||
|
||||
auto const_id = EvalOrAddInst<SemIR::LookupImplWitness>(
|
||||
context(), loc_id_,
|
||||
{.type_id = witness.type_id,
|
||||
.query_self_inst_id = witness.query_self_inst_id,
|
||||
.query_specific_interface_id = witness.query_specific_interface_id});
|
||||
auto inst_id = context().constant_values().GetInstId(const_id);
|
||||
CARBON_CHECK(!context().insts().Is<SemIR::IdentifiedWitness>(inst_id));
|
||||
return inst_id;
|
||||
}
|
||||
|
||||
auto SubstImplSelfWitness(SemIR::ImplSelfWitness witness) -> SemIR::InstId {
|
||||
if (subst_callbacks_) {
|
||||
auto replaced_id = subst_callbacks_->ReplaceImplSelfWitness(witness);
|
||||
if (replaced_id.has_value()) {
|
||||
return replaced_id;
|
||||
}
|
||||
}
|
||||
return RebuildNewInst(loc_id_, witness);
|
||||
}
|
||||
|
||||
SemIR::LocId loc_id_;
|
||||
SubstIdentifiedWitnessesCallbacks* subst_callbacks_;
|
||||
};
|
||||
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::IdentifiedFacetType::RequiredImpl req)
|
||||
-> SemIR::IdentifiedFacetType::RequiredImpl {
|
||||
if (context.eval_impl_lookup_to_identified_witness()) {
|
||||
return req;
|
||||
}
|
||||
EvaluateSubstCallbacks callbacks(&context, loc_id);
|
||||
auto self_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(req.self_facet_value),
|
||||
callbacks);
|
||||
auto interface =
|
||||
EvaluateIdentifiedWitnesses(context, loc_id, req.specific_interface);
|
||||
return {.self_facet_value = context.constant_values().Get(self_id),
|
||||
.specific_interface = interface};
|
||||
}
|
||||
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::IdentifiedFacetType::Rewrite rewrite)
|
||||
-> SemIR::IdentifiedFacetType::Rewrite {
|
||||
if (context.eval_impl_lookup_to_identified_witness()) {
|
||||
return rewrite;
|
||||
}
|
||||
EvaluateSubstCallbacks callbacks(&context, loc_id);
|
||||
auto lhs_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(rewrite.lhs), callbacks);
|
||||
auto rhs_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(rewrite.rhs), callbacks);
|
||||
return {.lhs = context.constant_values().Get(lhs_id),
|
||||
.rhs = context.constant_values().Get(rhs_id)};
|
||||
}
|
||||
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::SpecificInterface interface)
|
||||
-> SemIR::SpecificInterface {
|
||||
if (context.eval_impl_lookup_to_identified_witness()) {
|
||||
return interface;
|
||||
}
|
||||
EvaluateSubstCallbacks callbacks(&context, loc_id);
|
||||
auto specific_id = interface.specific_id;
|
||||
if (specific_id.has_value()) {
|
||||
const auto& specific = context.specifics().Get(specific_id);
|
||||
llvm::SmallVector<SemIR::InstId> args(
|
||||
context.inst_blocks().Get(specific.args_id));
|
||||
for (auto& arg_id : args) {
|
||||
arg_id = SubstInst(context, arg_id, callbacks);
|
||||
}
|
||||
specific_id = MakeSpecific(context, loc_id, specific.generic_id, args);
|
||||
}
|
||||
return {.interface_id = interface.interface_id, .specific_id = specific_id};
|
||||
}
|
||||
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId const_id)
|
||||
-> SemIR::ConstantId {
|
||||
if (context.eval_impl_lookup_to_identified_witness()) {
|
||||
return const_id;
|
||||
}
|
||||
EvaluateSubstCallbacks callbacks(&context, loc_id);
|
||||
auto inst_id = context.constant_values().GetInstId(const_id);
|
||||
inst_id = SubstInst(context, inst_id, callbacks);
|
||||
return context.constant_values().Get(inst_id);
|
||||
}
|
||||
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::IdentifiedFacetType::RequiredImpl req,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> SemIR::IdentifiedFacetType::RequiredImpl {
|
||||
// SubstIdentifiedWitnesses allows the caller to cleverly replace witnesses
|
||||
// coming from identify with their own. If we do this in the middle of
|
||||
// identify, it means there is another caller waiting for identify and they
|
||||
// may also want to do their own replacements. This would be problematic! But
|
||||
// since during identify we only create specifics, and resolving them through
|
||||
// eval should not end up here, we make note of that.
|
||||
CARBON_CHECK(!context.eval_impl_lookup_to_identified_witness(),
|
||||
"SubstIdentifiedWitnesses called during identify");
|
||||
|
||||
EvaluateSubstCallbacks subst_callbacks(&context, loc_id, &callbacks);
|
||||
auto self_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(req.self_facet_value),
|
||||
subst_callbacks);
|
||||
|
||||
auto interface_id = req.specific_interface.interface_id;
|
||||
auto specific_id = req.specific_interface.specific_id;
|
||||
if (specific_id.has_value()) {
|
||||
const auto& specific = context.specifics().Get(specific_id);
|
||||
llvm::SmallVector<SemIR::InstId> args(
|
||||
context.inst_blocks().Get(specific.args_id));
|
||||
for (auto& arg_id : args) {
|
||||
arg_id = SubstInst(context, arg_id, subst_callbacks);
|
||||
}
|
||||
specific_id = MakeSpecific(context, loc_id, specific.generic_id, args);
|
||||
}
|
||||
return {.self_facet_value = context.constant_values().Get(self_id),
|
||||
.specific_interface = {.interface_id = interface_id,
|
||||
.specific_id = specific_id}};
|
||||
}
|
||||
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::IdentifiedFacetType::Equivalent equiv,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> SemIR::IdentifiedFacetType::Equivalent {
|
||||
// SubstIdentifiedWitnesses allows the caller to cleverly replace witnesses
|
||||
// coming from identify with their own. If we do this in the middle of
|
||||
// identify, it means there is another caller waiting for identify and they
|
||||
// may also want to do their own replacements. This would be problematic! But
|
||||
// since during identify we only create specifics, and resolving them through
|
||||
// eval should not end up here, we make note of that.
|
||||
CARBON_CHECK(!context.eval_impl_lookup_to_identified_witness(),
|
||||
"SubstIdentifiedWitnesses called during identify");
|
||||
|
||||
EvaluateSubstCallbacks subst_callbacks(&context, loc_id, &callbacks);
|
||||
auto lhs_inst_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(equiv.lhs), subst_callbacks);
|
||||
auto rhs_inst_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(equiv.rhs), subst_callbacks);
|
||||
return {context.constant_values().Get(lhs_inst_id),
|
||||
context.constant_values().Get(rhs_inst_id)};
|
||||
}
|
||||
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId const_id,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> SemIR::ConstantId {
|
||||
// SubstIdentifiedWitnesses allows the caller to cleverly replace witnesses
|
||||
// coming from identify with their own. If we do this in the middle of
|
||||
// identify, it means there is another caller waiting for identify and they
|
||||
// may also want to do their own replacements. This would be problematic! But
|
||||
// since during identify we only create specifics, and resolving them through
|
||||
// eval should not end up here, we make note of that.
|
||||
CARBON_CHECK(!context.eval_impl_lookup_to_identified_witness(),
|
||||
"SubstIdentifiedWitnesses called during identify");
|
||||
|
||||
EvaluateSubstCallbacks subst_callbacks(&context, loc_id, &callbacks);
|
||||
auto inst_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(const_id), subst_callbacks);
|
||||
return context.constant_values().Get(inst_id);
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
@@ -6,7 +6,6 @@
|
||||
#define CARBON_TOOLCHAIN_CHECK_FACET_TYPE_H_
|
||||
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/sem_ir/identified_facet_type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
@@ -75,61 +74,6 @@ auto GetConstantFacetValueForTypeAndInterface(
|
||||
// type with an arbitrary facet type (including a `where` expression).
|
||||
auto FindWhere(Context& context, SemIR::ConstantId const_id) -> bool;
|
||||
|
||||
// Replace all IdentifiedWitnesses with LookupImplWitnesses, which will evaluate
|
||||
// and perform an impl lookup. If part of an ImplWitnessAccess, the result may
|
||||
// replace the access and witness with the value of an associated constant from
|
||||
// an impl.
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::IdentifiedFacetType::RequiredImpl req)
|
||||
-> SemIR::IdentifiedFacetType::RequiredImpl;
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::IdentifiedFacetType::Rewrite rewrite)
|
||||
-> SemIR::IdentifiedFacetType::Rewrite;
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::SpecificInterface interface)
|
||||
-> SemIR::SpecificInterface;
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId const_id)
|
||||
-> SemIR::ConstantId;
|
||||
|
||||
class SubstIdentifiedWitnessesCallbacks {
|
||||
public:
|
||||
explicit SubstIdentifiedWitnessesCallbacks(Context* context)
|
||||
: context_(context) {}
|
||||
|
||||
auto context() const -> Context& { return *context_; }
|
||||
|
||||
// Callback to return an InstId to use in place of the IdentifiedWitness. If
|
||||
// it returns None, the substitution will replace it with a LookupImplWitness
|
||||
// which will be evaluated to perform an impl lookup.
|
||||
virtual auto ReplaceIdentified(SemIR::IdentifiedWitness witness)
|
||||
-> SemIR::InstId = 0;
|
||||
|
||||
// Callback to return an InstId to use in place of the ImplSelfWitness. If it
|
||||
// returns None, the ImplSelfWitness will be left in place.
|
||||
virtual auto ReplaceImplSelfWitness(SemIR::ImplSelfWitness witness)
|
||||
-> SemIR::InstId = 0;
|
||||
|
||||
private:
|
||||
Context* context_;
|
||||
};
|
||||
|
||||
// Replace all IdentifiedWitnesses based on the behaviour of a callback that is
|
||||
// run as each witness is visited. Also gives the opportunity to replace
|
||||
// ImplSelfWitness in the same substitution pass.
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::IdentifiedFacetType::RequiredImpl req,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> SemIR::IdentifiedFacetType::RequiredImpl;
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::IdentifiedFacetType::Equivalent equiv,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> SemIR::IdentifiedFacetType::Equivalent;
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId const_id,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> SemIR::ConstantId;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_CHECK_FACET_TYPE_H_
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "toolchain/check/facet_type.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
#include "toolchain/check/impl.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
@@ -209,7 +210,7 @@ struct BuildImplDeclResult {
|
||||
SemIR::ImplId impl_id;
|
||||
SemIR::InstId impl_decl_id;
|
||||
SemIR::TypeInstId full_constraint_type_inst_id;
|
||||
SemIR::IdentifiedFacetTypeId identified_id;
|
||||
IdentifiedFacetTypeId identified_id;
|
||||
};
|
||||
|
||||
// Build an ImplDecl describing the signature of an impl. This handles the
|
||||
|
||||
@@ -106,7 +106,7 @@ auto HandleParseNode(Context& context, Parse::RequireTypeImplsId node_id)
|
||||
|
||||
static auto TypeStructureReferencesSelf(
|
||||
Context& context, SemIR::LocId loc_id, SemIR::ConstantId const_id,
|
||||
const SemIR::IdentifiedFacetType& identified_facet_type) -> bool {
|
||||
const IdentifiedFacetType& identified_facet_type) -> bool {
|
||||
auto find_self = [&](SemIR::TypeIterator& type_iter) -> bool {
|
||||
while (true) {
|
||||
auto step = type_iter.Next();
|
||||
@@ -173,7 +173,7 @@ static auto TypeStructureReferencesSelf(
|
||||
}
|
||||
|
||||
struct ValidateRequireResult {
|
||||
const SemIR::IdentifiedFacetType* identified_facet_type;
|
||||
const IdentifiedFacetType* identified_facet_type;
|
||||
};
|
||||
|
||||
// Returns nullopt if a diagnostic has been emitted and the `require` decl is
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "toolchain/check/facet_type.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/handle.h"
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/period_self.h"
|
||||
#include "toolchain/check/subst.h"
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
|
||||
#include "toolchain/base/canonical_value_store_impl.h"
|
||||
#include "toolchain/base/kind_switch.h"
|
||||
#include "toolchain/base/value_store_impl.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/subst.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
template <typename T>
|
||||
using LessThanFn = llvm::function_ref<auto(const T&, const T&)->bool>;
|
||||
|
||||
template <typename VecT>
|
||||
static auto SortAndDeduplicate(VecT& vec,
|
||||
LessThanFn<typename VecT::value_type> compare)
|
||||
-> void {
|
||||
llvm::sort(vec, compare);
|
||||
vec.erase(llvm::unique(vec), vec.end());
|
||||
}
|
||||
|
||||
// Canonically ordered by the numerical ids. Matches the order of RequiredLess
|
||||
// when the `self_facet_value` is the same for all interfaces.
|
||||
static auto InterfaceLess(const SemIR::SpecificInterface& lhs,
|
||||
const SemIR::SpecificInterface& rhs) -> bool {
|
||||
return std::tie(lhs.interface_id.index, lhs.specific_id.index) <
|
||||
std::tie(rhs.interface_id.index, rhs.specific_id.index);
|
||||
}
|
||||
|
||||
// Canonically ordered by the numerical ids.
|
||||
static auto RequiredLess(const IdentifiedFacetType::RequiredImpl& lhs,
|
||||
const IdentifiedFacetType::RequiredImpl& rhs) -> bool {
|
||||
return std::tie(lhs.self_facet_value.index,
|
||||
lhs.specific_interface.interface_id.index,
|
||||
lhs.specific_interface.specific_id.index) <
|
||||
std::tie(rhs.self_facet_value.index,
|
||||
rhs.specific_interface.interface_id.index,
|
||||
rhs.specific_interface.specific_id.index);
|
||||
}
|
||||
|
||||
// Canonically ordered by the numerical ids.
|
||||
static auto RewriteLess(const IdentifiedFacetType::Rewrite& lhs,
|
||||
const IdentifiedFacetType::Rewrite& rhs) -> bool {
|
||||
return std::tie(lhs.lhs.index, lhs.rhs.index) <
|
||||
std::tie(rhs.lhs.index, rhs.rhs.index);
|
||||
}
|
||||
|
||||
// Canonically ordered by the numerical ids.
|
||||
static auto EquivalentLess(const IdentifiedFacetType::Equivalent& lhs,
|
||||
const IdentifiedFacetType::Equivalent& rhs) -> bool {
|
||||
return std::tie(lhs.lhs.index, lhs.rhs.index) <
|
||||
std::tie(rhs.lhs.index, rhs.rhs.index);
|
||||
}
|
||||
|
||||
IdentifiedFacetType::IdentifiedFacetType(
|
||||
IdentifiedFacetTypeKey key, bool partially_identified,
|
||||
llvm::ArrayRef<RequiredImpl> extends,
|
||||
llvm::ArrayRef<RequiredImpl> self_impls, llvm::ArrayRef<Rewrite> rewrites,
|
||||
llvm::ArrayRef<Equivalent> equivalents)
|
||||
: key_(key) {
|
||||
required_impls_.reserve(extends.size() + self_impls.size());
|
||||
llvm::append_range(required_impls_, extends);
|
||||
SortAndDeduplicate(required_impls_, RequiredLess);
|
||||
|
||||
// If there's a single extended interface then we present as that interface.
|
||||
// Otherwise, we record the number extended interfaces.
|
||||
if (required_impls_.size() == 1) {
|
||||
interface_id_ = required_impls_.front().specific_interface.interface_id;
|
||||
specific_id_ = required_impls_.front().specific_interface.specific_id;
|
||||
} else {
|
||||
interface_id_ = SemIR::InterfaceId::None;
|
||||
num_interface_to_impl_ = required_impls_.size();
|
||||
}
|
||||
|
||||
llvm::append_range(required_impls_, self_impls);
|
||||
SortAndDeduplicate(required_impls_, RequiredLess);
|
||||
SortAndDeduplicate(required_impls_, RequiredLess);
|
||||
|
||||
if (partially_identified) {
|
||||
// This marks the IdentifiedFacetType as being partially identified, and
|
||||
// prevents the key from colliding with a fully identified facet type, or
|
||||
// with other partially (but differently) identified facet types, with the
|
||||
// same constituents but a more complete set of required interfaces.
|
||||
key_.num_require_impls = required_impls_.size();
|
||||
}
|
||||
|
||||
rewrites_.assign(rewrites);
|
||||
SortAndDeduplicate(rewrites_, RewriteLess);
|
||||
equivalents_.assign(equivalents);
|
||||
SortAndDeduplicate(equivalents_, EquivalentLess);
|
||||
}
|
||||
|
||||
auto AddCanonicalWitnessesBlock(Context& context,
|
||||
llvm::SmallVector<SemIR::InstId>& witnesses)
|
||||
-> SemIR::InstBlockId {
|
||||
// Small blocks don't need to be sorted.
|
||||
if (witnesses.size() <= 1) {
|
||||
return context.inst_blocks().AddCanonical(witnesses);
|
||||
}
|
||||
|
||||
llvm::SmallVector<std::pair<SemIR::SpecificInterface, SemIR::InstId>>
|
||||
sortable;
|
||||
sortable.reserve(witnesses.size());
|
||||
|
||||
// Produce the sorted order based on the witness's SpecificInterface.
|
||||
for (auto witness_id : witnesses) {
|
||||
auto inst = context.insts().Get(witness_id);
|
||||
CARBON_KIND_SWITCH(inst) {
|
||||
case CARBON_KIND(SemIR::CustomWitness witness): {
|
||||
sortable.push_back({context.specific_interfaces().Get(
|
||||
witness.query_specific_interface_id),
|
||||
witness_id});
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::ImplWitness witness): {
|
||||
auto table = context.insts().GetAs<SemIR::ImplWitnessTable>(
|
||||
witness.witness_table_id);
|
||||
sortable.push_back(
|
||||
{context.impls().Get(table.impl_id).interface, witness_id});
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::LookupImplWitness witness): {
|
||||
sortable.push_back({context.specific_interfaces().Get(
|
||||
witness.query_specific_interface_id),
|
||||
witness_id});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CARBON_FATAL("Unhandled inst: {0}", inst);
|
||||
}
|
||||
}
|
||||
// This matches the sort order of IdentifiedFacetType::required_interfaces,
|
||||
// which is the order of the witnesses returned from impl lookup, and is
|
||||
// canonical order in which the witnesses must appear for a given facet type
|
||||
// so that ImplWitnessAccess can find the appropriate witness.
|
||||
llvm::sort(sortable, [](auto& lhs, auto& rhs) {
|
||||
return InterfaceLess(lhs.first, rhs.first);
|
||||
});
|
||||
|
||||
// Update the original list with the new order (reusing to avoid an
|
||||
// allocation).
|
||||
for (auto [witness_id, sortable_entry] :
|
||||
llvm::zip_equal(witnesses, sortable)) {
|
||||
witness_id = sortable_entry.second;
|
||||
}
|
||||
|
||||
return context.inst_blocks().AddCanonical(witnesses);
|
||||
}
|
||||
|
||||
class EvaluateSubstCallbacks : public SubstInstCallbacks {
|
||||
public:
|
||||
explicit EvaluateSubstCallbacks(
|
||||
Context* context, SemIR::LocId loc_id,
|
||||
SubstIdentifiedWitnessesCallbacks* subst_callbacks = nullptr)
|
||||
: SubstInstCallbacks(context),
|
||||
loc_id_(loc_id),
|
||||
subst_callbacks_(subst_callbacks) {}
|
||||
|
||||
auto Subst(SemIR::InstId& inst_id) -> SubstResult override {
|
||||
// SubstPeriodSelf recurses into facet types, so we need to do the same to
|
||||
// find those witnesses first. So we can't early out if the inst has a
|
||||
// concrete constant value.
|
||||
if (inst_id == SemIR::TypeType::TypeInstId ||
|
||||
inst_id == SemIR::ErrorInst::InstId) {
|
||||
return FullySubstituted;
|
||||
}
|
||||
return SubstOperands;
|
||||
}
|
||||
|
||||
auto ReuseUnchanged(SemIR::InstId orig_inst_id) -> SemIR::InstId override {
|
||||
if (auto witness = context().insts().TryGetAs<SemIR::IdentifiedWitness>(
|
||||
orig_inst_id)) {
|
||||
return SubstIdentifiedWitness(*witness);
|
||||
}
|
||||
if (auto witness =
|
||||
context().insts().TryGetAs<SemIR::ImplSelfWitness>(orig_inst_id)) {
|
||||
return SubstImplSelfWitness(*witness);
|
||||
}
|
||||
return orig_inst_id;
|
||||
}
|
||||
|
||||
auto Rebuild(SemIR::InstId /*orig_inst_id*/, SemIR::Inst new_inst)
|
||||
-> SemIR::InstId override {
|
||||
if (auto witness = new_inst.TryAs<SemIR::IdentifiedWitness>()) {
|
||||
return SubstIdentifiedWitness(*witness);
|
||||
}
|
||||
if (auto witness = new_inst.TryAs<SemIR::ImplSelfWitness>()) {
|
||||
return SubstImplSelfWitness(*witness);
|
||||
}
|
||||
return RebuildNewInst(loc_id_, new_inst);
|
||||
}
|
||||
|
||||
auto RebuildSpecific(SemIR::SpecificId orig_specific_id,
|
||||
SemIR::InstBlockId args_id)
|
||||
-> SemIR::SpecificId override {
|
||||
auto generic_id = context().specifics().Get(orig_specific_id).generic_id;
|
||||
// Drop the `identified` flag from any specifics we create here, as we have
|
||||
// substituted the IdentifiedWitness instructions away.
|
||||
return context().specifics().GetOrAdd(generic_id, args_id,
|
||||
/*identified=*/false);
|
||||
}
|
||||
|
||||
private:
|
||||
auto SubstIdentifiedWitness(SemIR::IdentifiedWitness witness)
|
||||
-> SemIR::InstId {
|
||||
if (subst_callbacks_) {
|
||||
auto replaced_id = subst_callbacks_->ReplaceIdentified(witness);
|
||||
if (replaced_id.has_value()) {
|
||||
CARBON_CHECK(
|
||||
!context().insts().Is<SemIR::IdentifiedWitness>(replaced_id));
|
||||
return replaced_id;
|
||||
}
|
||||
}
|
||||
|
||||
auto const_id = EvalOrAddInst<SemIR::LookupImplWitness>(
|
||||
context(), loc_id_,
|
||||
{.type_id = witness.type_id,
|
||||
.query_self_inst_id = witness.query_self_inst_id,
|
||||
.query_specific_interface_id = witness.query_specific_interface_id});
|
||||
auto inst_id = context().constant_values().GetInstId(const_id);
|
||||
CARBON_CHECK(!context().insts().Is<SemIR::IdentifiedWitness>(inst_id));
|
||||
return inst_id;
|
||||
}
|
||||
|
||||
auto SubstImplSelfWitness(SemIR::ImplSelfWitness witness) -> SemIR::InstId {
|
||||
if (subst_callbacks_) {
|
||||
auto replaced_id = subst_callbacks_->ReplaceImplSelfWitness(witness);
|
||||
if (replaced_id.has_value()) {
|
||||
return replaced_id;
|
||||
}
|
||||
}
|
||||
return RebuildNewInst(loc_id_, witness);
|
||||
}
|
||||
|
||||
SemIR::LocId loc_id_;
|
||||
SubstIdentifiedWitnessesCallbacks* subst_callbacks_;
|
||||
};
|
||||
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
IdentifiedFacetType::RequiredImpl req)
|
||||
-> IdentifiedFacetType::RequiredImpl {
|
||||
if (context.eval_impl_lookup_to_identified_witness()) {
|
||||
return req;
|
||||
}
|
||||
EvaluateSubstCallbacks callbacks(&context, loc_id);
|
||||
auto self_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(req.self_facet_value),
|
||||
callbacks);
|
||||
auto interface =
|
||||
EvaluateIdentifiedWitnesses(context, loc_id, req.specific_interface);
|
||||
return {.self_facet_value = context.constant_values().Get(self_id),
|
||||
.specific_interface = interface};
|
||||
}
|
||||
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
IdentifiedFacetType::Rewrite rewrite)
|
||||
-> IdentifiedFacetType::Rewrite {
|
||||
if (context.eval_impl_lookup_to_identified_witness()) {
|
||||
return rewrite;
|
||||
}
|
||||
EvaluateSubstCallbacks callbacks(&context, loc_id);
|
||||
auto lhs_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(rewrite.lhs), callbacks);
|
||||
auto rhs_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(rewrite.rhs), callbacks);
|
||||
return {.lhs = context.constant_values().Get(lhs_id),
|
||||
.rhs = context.constant_values().Get(rhs_id)};
|
||||
}
|
||||
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::SpecificInterface interface)
|
||||
-> SemIR::SpecificInterface {
|
||||
if (context.eval_impl_lookup_to_identified_witness()) {
|
||||
return interface;
|
||||
}
|
||||
EvaluateSubstCallbacks callbacks(&context, loc_id);
|
||||
auto specific_id = interface.specific_id;
|
||||
if (specific_id.has_value()) {
|
||||
const auto& specific = context.specifics().Get(specific_id);
|
||||
llvm::SmallVector<SemIR::InstId> args(
|
||||
context.inst_blocks().Get(specific.args_id));
|
||||
for (auto& arg_id : args) {
|
||||
arg_id = SubstInst(context, arg_id, callbacks);
|
||||
}
|
||||
specific_id = MakeSpecific(context, loc_id, specific.generic_id, args);
|
||||
}
|
||||
return {.interface_id = interface.interface_id, .specific_id = specific_id};
|
||||
}
|
||||
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId const_id)
|
||||
-> SemIR::ConstantId {
|
||||
if (context.eval_impl_lookup_to_identified_witness()) {
|
||||
return const_id;
|
||||
}
|
||||
EvaluateSubstCallbacks callbacks(&context, loc_id);
|
||||
auto inst_id = context.constant_values().GetInstId(const_id);
|
||||
inst_id = SubstInst(context, inst_id, callbacks);
|
||||
return context.constant_values().Get(inst_id);
|
||||
}
|
||||
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
IdentifiedFacetType::RequiredImpl req,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> IdentifiedFacetType::RequiredImpl {
|
||||
// SubstIdentifiedWitnesses allows the caller to cleverly replace witnesses
|
||||
// coming from identify with their own. If we do this in the middle of
|
||||
// identify, it means there is another caller waiting for identify and they
|
||||
// may also want to do their own replacements. This would be problematic! But
|
||||
// since during identify we only create specifics, and resolving them through
|
||||
// eval should not end up here, we make note of that.
|
||||
CARBON_CHECK(!context.eval_impl_lookup_to_identified_witness(),
|
||||
"SubstIdentifiedWitnesses called during identify");
|
||||
|
||||
EvaluateSubstCallbacks subst_callbacks(&context, loc_id, &callbacks);
|
||||
auto self_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(req.self_facet_value),
|
||||
subst_callbacks);
|
||||
|
||||
auto interface_id = req.specific_interface.interface_id;
|
||||
auto specific_id = req.specific_interface.specific_id;
|
||||
if (specific_id.has_value()) {
|
||||
const auto& specific = context.specifics().Get(specific_id);
|
||||
llvm::SmallVector<SemIR::InstId> args(
|
||||
context.inst_blocks().Get(specific.args_id));
|
||||
for (auto& arg_id : args) {
|
||||
arg_id = SubstInst(context, arg_id, subst_callbacks);
|
||||
}
|
||||
specific_id = MakeSpecific(context, loc_id, specific.generic_id, args);
|
||||
}
|
||||
return {.self_facet_value = context.constant_values().Get(self_id),
|
||||
.specific_interface = {.interface_id = interface_id,
|
||||
.specific_id = specific_id}};
|
||||
}
|
||||
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
IdentifiedFacetType::Equivalent equiv,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> IdentifiedFacetType::Equivalent {
|
||||
// SubstIdentifiedWitnesses allows the caller to cleverly replace witnesses
|
||||
// coming from identify with their own. If we do this in the middle of
|
||||
// identify, it means there is another caller waiting for identify and they
|
||||
// may also want to do their own replacements. This would be problematic! But
|
||||
// since during identify we only create specifics, and resolving them through
|
||||
// eval should not end up here, we make note of that.
|
||||
CARBON_CHECK(!context.eval_impl_lookup_to_identified_witness(),
|
||||
"SubstIdentifiedWitnesses called during identify");
|
||||
|
||||
EvaluateSubstCallbacks subst_callbacks(&context, loc_id, &callbacks);
|
||||
auto lhs_inst_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(equiv.lhs), subst_callbacks);
|
||||
auto rhs_inst_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(equiv.rhs), subst_callbacks);
|
||||
return {context.constant_values().Get(lhs_inst_id),
|
||||
context.constant_values().Get(rhs_inst_id)};
|
||||
}
|
||||
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId const_id,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> SemIR::ConstantId {
|
||||
// SubstIdentifiedWitnesses allows the caller to cleverly replace witnesses
|
||||
// coming from identify with their own. If we do this in the middle of
|
||||
// identify, it means there is another caller waiting for identify and they
|
||||
// may also want to do their own replacements. This would be problematic! But
|
||||
// since during identify we only create specifics, and resolving them through
|
||||
// eval should not end up here, we make note of that.
|
||||
CARBON_CHECK(!context.eval_impl_lookup_to_identified_witness(),
|
||||
"SubstIdentifiedWitnesses called during identify");
|
||||
|
||||
EvaluateSubstCallbacks subst_callbacks(&context, loc_id, &callbacks);
|
||||
auto inst_id = SubstInst(
|
||||
context, context.constant_values().GetInstId(const_id), subst_callbacks);
|
||||
return context.constant_values().Get(inst_id);
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
namespace Carbon {
|
||||
template class CanonicalValueStore<
|
||||
Check::IdentifiedFacetTypeId, Check::IdentifiedFacetTypeKey,
|
||||
Tag<SemIR::CheckIRId>, Check::IdentifiedFacetType>;
|
||||
template class ValueStore<Check::IdentifiedFacetTypeId,
|
||||
Check::IdentifiedFacetType, Tag<SemIR::CheckIRId>>;
|
||||
} // namespace Carbon
|
||||
+91
-26
@@ -2,22 +2,32 @@
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#ifndef CARBON_TOOLCHAIN_SEM_IR_IDENTIFIED_FACET_TYPE_H_
|
||||
#define CARBON_TOOLCHAIN_SEM_IR_IDENTIFIED_FACET_TYPE_H_
|
||||
#ifndef CARBON_TOOLCHAIN_CHECK_IDENTIFIED_FACET_TYPE_H_
|
||||
#define CARBON_TOOLCHAIN_CHECK_IDENTIFIED_FACET_TYPE_H_
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "toolchain/base/canonical_value_store.h"
|
||||
#include "toolchain/sem_ir/declared_facet_type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/specific_interface.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
namespace Carbon::Check {
|
||||
|
||||
class File;
|
||||
// The ID of an identified facet type, which flattens referenced named
|
||||
// constraints together into a single structure, and replaces any `.Self`
|
||||
// references with a self facet.
|
||||
struct IdentifiedFacetTypeId : public IdBase<IdentifiedFacetTypeId> {
|
||||
static constexpr llvm::StringLiteral Label = "identified_facet_type";
|
||||
|
||||
using IdBase::IdBase;
|
||||
};
|
||||
|
||||
class Context;
|
||||
|
||||
struct IdentifiedFacetTypeKey {
|
||||
DeclaredFacetTypeId declared_facet_type_id;
|
||||
ConstantId self_const_id;
|
||||
SemIR::DeclaredFacetTypeId declared_facet_type_id;
|
||||
SemIR::ConstantId self_const_id;
|
||||
// Inside a named constraint, each identification of the `Self` facet type can
|
||||
// be unique, as it can be modified by each require declaration seen so far.
|
||||
// Uses -1 for identifying a facet type with a self-type from outside the
|
||||
@@ -36,22 +46,22 @@ struct IdentifiedFacetTypeKey {
|
||||
struct IdentifiedFacetType {
|
||||
// A requirement that `self_facet_value` implements the `specific_interface`.
|
||||
struct RequiredImpl {
|
||||
ConstantId self_facet_value;
|
||||
SpecificInterface specific_interface;
|
||||
SemIR::ConstantId self_facet_value;
|
||||
SemIR::SpecificInterface specific_interface;
|
||||
|
||||
friend auto operator==(const RequiredImpl& lhs, const RequiredImpl& rhs)
|
||||
-> bool = default;
|
||||
};
|
||||
struct Rewrite {
|
||||
ConstantId lhs;
|
||||
ConstantId rhs;
|
||||
SemIR::ConstantId lhs;
|
||||
SemIR::ConstantId rhs;
|
||||
|
||||
friend auto operator==(const Rewrite& lhs, const Rewrite& rhs)
|
||||
-> bool = default;
|
||||
};
|
||||
struct Equivalent {
|
||||
ConstantId lhs;
|
||||
ConstantId rhs;
|
||||
SemIR::ConstantId lhs;
|
||||
SemIR::ConstantId rhs;
|
||||
|
||||
friend auto operator==(const Equivalent& lhs, const Equivalent& rhs)
|
||||
-> bool = default;
|
||||
@@ -80,11 +90,11 @@ struct IdentifiedFacetType {
|
||||
|
||||
// The interface to implement when this facet type is used in an `impl`
|
||||
// declaration.
|
||||
auto impl_as_target_interface() const -> SpecificInterface {
|
||||
auto impl_as_target_interface() const -> SemIR::SpecificInterface {
|
||||
if (is_valid_impl_as_target()) {
|
||||
return {.interface_id = interface_id_, .specific_id = specific_id_};
|
||||
} else {
|
||||
return SpecificInterface::None;
|
||||
return SemIR::SpecificInterface::None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,38 +135,93 @@ struct IdentifiedFacetType {
|
||||
// The single interface from `required_impls` to implement if this is
|
||||
// the facet type to the right of an `impl`...`as`, or `None` if no such
|
||||
// single interface.
|
||||
InterfaceId interface_id_ = InterfaceId::None;
|
||||
SemIR::InterfaceId interface_id_ = SemIR::InterfaceId::None;
|
||||
union {
|
||||
// If `interface_id` is `None`, the number of interfaces to report in a
|
||||
// diagnostic about why this facet type can't be implemented.
|
||||
int num_interface_to_impl_ = 0;
|
||||
// If `interface_id` is not `None`, the specific for that interface.
|
||||
SpecificId specific_id_;
|
||||
SemIR::SpecificId specific_id_;
|
||||
};
|
||||
};
|
||||
|
||||
using IdentifiedFacetTypeStore =
|
||||
CanonicalValueStore<IdentifiedFacetTypeId, IdentifiedFacetTypeKey,
|
||||
Tag<CheckIRId>, IdentifiedFacetType>;
|
||||
Tag<SemIR::CheckIRId>, IdentifiedFacetType>;
|
||||
|
||||
// Given an array of witnesses, sorts them to match the ordering of the specific
|
||||
// interfaces in the IdentifiedFacetType that produced the witness set, which is
|
||||
// the canonical witness order, and returns the resulting block ID. This assumes
|
||||
// witnesses have already been deduplicated, and do not contain errors, because
|
||||
// it's mainly for imports.
|
||||
auto AddCanonicalWitnessesBlock(File& sem_ir,
|
||||
llvm::SmallVector<InstId>& witnesses)
|
||||
-> InstBlockId;
|
||||
auto AddCanonicalWitnessesBlock(Context& context,
|
||||
llvm::SmallVector<SemIR::InstId>& witnesses)
|
||||
-> SemIR::InstBlockId;
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
// Replace all IdentifiedWitnesses with LookupImplWitnesses, which will evaluate
|
||||
// and perform an impl lookup. If part of an ImplWitnessAccess, the result may
|
||||
// replace the access and witness with the value of an associated constant from
|
||||
// an impl.
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
IdentifiedFacetType::RequiredImpl req)
|
||||
-> IdentifiedFacetType::RequiredImpl;
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
IdentifiedFacetType::Rewrite rewrite)
|
||||
-> IdentifiedFacetType::Rewrite;
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::SpecificInterface interface)
|
||||
-> SemIR::SpecificInterface;
|
||||
auto EvaluateIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId const_id)
|
||||
-> SemIR::ConstantId;
|
||||
|
||||
class SubstIdentifiedWitnessesCallbacks {
|
||||
public:
|
||||
explicit SubstIdentifiedWitnessesCallbacks(Context* context)
|
||||
: context_(context) {}
|
||||
|
||||
auto context() const -> Context& { return *context_; }
|
||||
|
||||
// Callback to return an InstId to use in place of the IdentifiedWitness. If
|
||||
// it returns None, the substitution will replace it with a LookupImplWitness
|
||||
// which will be evaluated to perform an impl lookup.
|
||||
virtual auto ReplaceIdentified(SemIR::IdentifiedWitness witness)
|
||||
-> SemIR::InstId = 0;
|
||||
|
||||
// Callback to return an InstId to use in place of the ImplSelfWitness. If it
|
||||
// returns None, the ImplSelfWitness will be left in place.
|
||||
virtual auto ReplaceImplSelfWitness(SemIR::ImplSelfWitness witness)
|
||||
-> SemIR::InstId = 0;
|
||||
|
||||
private:
|
||||
Context* context_;
|
||||
};
|
||||
|
||||
// Replace all IdentifiedWitnesses based on the behaviour of a callback that is
|
||||
// run as each witness is visited. Also gives the opportunity to replace
|
||||
// ImplSelfWitness in the same substitution pass.
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
IdentifiedFacetType::RequiredImpl req,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> IdentifiedFacetType::RequiredImpl;
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
IdentifiedFacetType::Equivalent equiv,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> IdentifiedFacetType::Equivalent;
|
||||
auto SubstIdentifiedWitnesses(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId const_id,
|
||||
SubstIdentifiedWitnessesCallbacks& callbacks)
|
||||
-> SemIR::ConstantId;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
namespace Carbon {
|
||||
extern template class CanonicalValueStore<
|
||||
SemIR::IdentifiedFacetTypeId, SemIR::IdentifiedFacetTypeKey,
|
||||
Tag<SemIR::CheckIRId>, SemIR::IdentifiedFacetType>;
|
||||
extern template class ValueStore<SemIR::IdentifiedFacetTypeId,
|
||||
SemIR::IdentifiedFacetType,
|
||||
Check::IdentifiedFacetTypeId, Check::IdentifiedFacetTypeKey,
|
||||
Tag<SemIR::CheckIRId>, Check::IdentifiedFacetType>;
|
||||
extern template class ValueStore<Check::IdentifiedFacetTypeId,
|
||||
Check::IdentifiedFacetType,
|
||||
Tag<SemIR::CheckIRId>>;
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_SEM_IR_IDENTIFIED_FACET_TYPE_H_
|
||||
#endif // CARBON_TOOLCHAIN_CHECK_IDENTIFIED_FACET_TYPE_H_
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "toolchain/check/facet_type.h"
|
||||
#include "toolchain/check/function.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
#include "toolchain/check/impl_lookup.h"
|
||||
#include "toolchain/check/import_ref.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
@@ -27,7 +28,6 @@
|
||||
#include "toolchain/check/type_structure.h"
|
||||
#include "toolchain/diagnostics/emitter.h"
|
||||
#include "toolchain/sem_ir/generic.h"
|
||||
#include "toolchain/sem_ir/identified_facet_type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/impl.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
@@ -442,7 +442,7 @@ class SubstWithImplWitness : public SubstIdentifiedWitnessesCallbacks {
|
||||
auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::LocId constraint_loc_id,
|
||||
const SemIR::Impl& impl,
|
||||
SemIR::IdentifiedFacetTypeId identified_id,
|
||||
IdentifiedFacetTypeId identified_id,
|
||||
SemIR::SpecificId self_specific_id)
|
||||
-> SemIR::InstId {
|
||||
const auto& identified = context.identified_facet_types().Get(identified_id);
|
||||
@@ -841,8 +841,7 @@ auto FinishImplWitness(Context& context, const SemIR::Impl& impl) -> void {
|
||||
auto CheckRequireDeclsSatisfied(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::Impl& impl,
|
||||
SemIR::TypeInstId full_constraint_id,
|
||||
SemIR::IdentifiedFacetTypeId identified_id)
|
||||
-> void {
|
||||
IdentifiedFacetTypeId identified_id) -> void {
|
||||
if (impl.witness_id == SemIR::ErrorInst::InstId) {
|
||||
return;
|
||||
}
|
||||
@@ -1011,7 +1010,7 @@ auto CheckConstraintIsFacetType(Context& context, SemIR::LocId loc_id,
|
||||
auto CheckConstraintIsInterface(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::InstId self_id,
|
||||
SemIR::TypeInstId full_constraint_id)
|
||||
-> SemIR::IdentifiedFacetTypeId {
|
||||
-> IdentifiedFacetTypeId {
|
||||
auto identified_id = RequireIdentifiedFacetType(
|
||||
context, SemIR::LocId(full_constraint_id),
|
||||
context.constant_values().Get(self_id),
|
||||
@@ -1023,7 +1022,7 @@ auto CheckConstraintIsInterface(Context& context, SemIR::LocId loc_id,
|
||||
builder.Attach(loc_id, ImplOfUnidentifiedFacetType, full_constraint_id);
|
||||
});
|
||||
if (!identified_id.has_value()) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
const auto& identified = context.identified_facet_types().Get(identified_id);
|
||||
if (!identified.is_valid_impl_as_target()) {
|
||||
@@ -1031,7 +1030,7 @@ auto CheckConstraintIsInterface(Context& context, SemIR::LocId loc_id,
|
||||
"impl as {0} interfaces, expected 1", int);
|
||||
context.emitter().Emit(loc_id, ImplOfNotOneInterface,
|
||||
identified.num_interfaces_to_impl());
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
return identified_id;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ auto AddImpl(Context& context, const SemIR::Impl& impl,
|
||||
auto AddImplWitnessForDeclaration(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::LocId constraint_loc_id,
|
||||
const SemIR::Impl& impl,
|
||||
SemIR::IdentifiedFacetTypeId identified_id,
|
||||
IdentifiedFacetTypeId identified_id,
|
||||
SemIR::SpecificId self_specific_id)
|
||||
-> SemIR::InstId;
|
||||
|
||||
@@ -70,8 +70,7 @@ auto FinishImplWitness(Context& context, const SemIR::Impl& impl_id) -> void;
|
||||
auto CheckRequireDeclsSatisfied(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::Impl& impl,
|
||||
SemIR::TypeInstId full_constraint_id,
|
||||
SemIR::IdentifiedFacetTypeId identified_id)
|
||||
-> void;
|
||||
IdentifiedFacetTypeId identified_id) -> void;
|
||||
|
||||
// Sets all unset members of the witness for `impl` to the error instruction and
|
||||
// sets the witness id in the `Impl` to an error.
|
||||
@@ -102,7 +101,7 @@ auto CheckConstraintIsFacetType(Context& context, SemIR::LocId loc_id,
|
||||
auto CheckConstraintIsInterface(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::InstId self_id,
|
||||
SemIR::TypeInstId full_constraint_id)
|
||||
-> SemIR::IdentifiedFacetTypeId;
|
||||
-> IdentifiedFacetTypeId;
|
||||
|
||||
// Given a specific for the impl, returns the specific interface that the impl
|
||||
// declaration is implementing. Returns None in the case of an error being
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#include "toolchain/check/deduce.h"
|
||||
#include "toolchain/check/diagnostic_helpers.h"
|
||||
#include "toolchain/check/eval.h"
|
||||
#include "toolchain/check/facet_type.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
#include "toolchain/check/impl.h"
|
||||
#include "toolchain/check/import_ref.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "toolchain/check/type_completion.h"
|
||||
#include "toolchain/check/type_structure.h"
|
||||
#include "toolchain/sem_ir/declared_facet_type.h"
|
||||
#include "toolchain/sem_ir/identified_facet_type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/impl.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
@@ -307,10 +306,9 @@ static auto TryGetSpecificWitnessIdForImpl(
|
||||
impl.witness_id);
|
||||
}
|
||||
|
||||
static auto ThawPeriodSelfInRequiredImpl(
|
||||
Context& context, SemIR::LocId loc_id,
|
||||
SemIR::IdentifiedFacetType::RequiredImpl req)
|
||||
-> SemIR::IdentifiedFacetType::RequiredImpl {
|
||||
static auto ThawPeriodSelfInRequiredImpl(Context& context, SemIR::LocId loc_id,
|
||||
IdentifiedFacetType::RequiredImpl req)
|
||||
-> IdentifiedFacetType::RequiredImpl {
|
||||
auto self_inst_id = context.constant_values().GetInstId(req.self_facet_value);
|
||||
self_inst_id = ThawPeriodSelf(context, self_inst_id);
|
||||
req.self_facet_value = context.constant_values().Get(self_inst_id);
|
||||
@@ -528,7 +526,7 @@ class SubstMatchingWitnessesFromImplLookup
|
||||
public:
|
||||
explicit SubstMatchingWitnessesFromImplLookup(
|
||||
Context* context,
|
||||
llvm::ArrayRef<SemIR::IdentifiedFacetType::RequiredImpl> req_impls,
|
||||
llvm::ArrayRef<IdentifiedFacetType::RequiredImpl> req_impls,
|
||||
llvm::ArrayRef<SemIR::InstId> found_witness_inst_ids)
|
||||
: SubstIdentifiedWitnessesCallbacks(context),
|
||||
req_impls_(req_impls),
|
||||
@@ -556,7 +554,7 @@ class SubstMatchingWitnessesFromImplLookup
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::ArrayRef<SemIR::IdentifiedFacetType::RequiredImpl> req_impls_;
|
||||
llvm::ArrayRef<IdentifiedFacetType::RequiredImpl> req_impls_;
|
||||
llvm::ArrayRef<SemIR::InstId> found_witness_inst_ids_;
|
||||
};
|
||||
|
||||
@@ -943,7 +941,7 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id,
|
||||
}
|
||||
// These RequiredImpls have IdentifiedWitnesses in them initially. We will
|
||||
// replace those with real witnesses as we process them.
|
||||
llvm::SmallVector<SemIR::IdentifiedFacetType::RequiredImpl> req_impls(
|
||||
llvm::SmallVector<IdentifiedFacetType::RequiredImpl> req_impls(
|
||||
required_identified.required_impls());
|
||||
|
||||
// Find all the facets in the query and their witnesses.
|
||||
@@ -1062,8 +1060,8 @@ auto LookupImplWitness(Context& context, SemIR::LocId loc_id,
|
||||
}
|
||||
for (auto rewrite : required_identified.rewrites()) {
|
||||
// Rewrites are treated as equivalent requirements in impl lookup.
|
||||
SemIR::IdentifiedFacetType::Equivalent equiv = {.lhs = rewrite.lhs,
|
||||
.rhs = rewrite.rhs};
|
||||
IdentifiedFacetType::Equivalent equiv = {.lhs = rewrite.lhs,
|
||||
.rhs = rewrite.rhs};
|
||||
equiv = SubstIdentifiedWitnesses(context, loc_id, equiv,
|
||||
subst_witnesses_callbacks);
|
||||
if (equiv.lhs != equiv.rhs) {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <variant>
|
||||
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/sem_ir/identified_facet_type.h"
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "toolchain/check/eval.h"
|
||||
#include "toolchain/check/facet_type.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
#include "toolchain/check/import.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
@@ -29,7 +30,6 @@
|
||||
#include "toolchain/sem_ir/constant.h"
|
||||
#include "toolchain/sem_ir/file.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/identified_facet_type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/impl.h"
|
||||
#include "toolchain/sem_ir/import_ir.h"
|
||||
@@ -4038,7 +4038,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
|
||||
auto witnesses_block_id = SemIR::InstBlockId::None;
|
||||
if (inst.witnesses_block_id.has_value()) {
|
||||
witnesses_block_id =
|
||||
AddCanonicalWitnessesBlock(resolver.local_ir(), witnesses);
|
||||
AddCanonicalWitnessesBlock(resolver.local_context(), witnesses);
|
||||
}
|
||||
|
||||
return ResolveResult::Deduplicated<SemIR::FacetValue>(
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "toolchain/check/cpp/import.h"
|
||||
#include "toolchain/check/facet_type.h"
|
||||
#include "toolchain/check/generic.h"
|
||||
#include "toolchain/check/identified_facet_type.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/literal.h"
|
||||
#include "toolchain/check/period_self.h"
|
||||
@@ -21,7 +22,6 @@
|
||||
#include "toolchain/sem_ir/constant.h"
|
||||
#include "toolchain/sem_ir/declared_facet_type.h"
|
||||
#include "toolchain/sem_ir/generic.h"
|
||||
#include "toolchain/sem_ir/identified_facet_type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/named_constraint.h"
|
||||
#include "toolchain/sem_ir/specific_interface.h"
|
||||
@@ -958,9 +958,9 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId initial_self_const_id,
|
||||
SemIR::ConstantId facet_type_const_id,
|
||||
bool allow_partially_identified, bool diagnose)
|
||||
-> SemIR::IdentifiedFacetTypeId {
|
||||
-> IdentifiedFacetTypeId {
|
||||
if (facet_type_const_id == SemIR::ErrorInst::ConstantId) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
auto declared_facet_type_id =
|
||||
@@ -975,9 +975,9 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
// set of required impls that it contains, which requires us to do most of the
|
||||
// work of identifying the facet type (though we could skip the mapping of
|
||||
// constant values into specifics).
|
||||
auto key = SemIR::IdentifiedFacetTypeKey{
|
||||
.declared_facet_type_id = declared_facet_type_id,
|
||||
.self_const_id = initial_self_const_id};
|
||||
auto key =
|
||||
IdentifiedFacetTypeKey{.declared_facet_type_id = declared_facet_type_id,
|
||||
.self_const_id = initial_self_const_id};
|
||||
if (auto identified_id = context.identified_facet_types().Lookup(key);
|
||||
identified_id.has_value()) {
|
||||
return identified_id;
|
||||
@@ -999,7 +999,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
auto subst_id = SubstPeriodSelf(context, loc_id, facet_type_const_id,
|
||||
initial_self_const_id);
|
||||
if (subst_id == SemIR::ErrorInst::ConstantId) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
declared_facet_type_id = context.constant_values()
|
||||
.GetInstAs<SemIR::FacetType>(subst_id)
|
||||
@@ -1020,10 +1020,10 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
|
||||
// Outputs for the IdentifiedFacetType.
|
||||
bool partially_identified = false;
|
||||
llvm::SmallVector<SemIR::IdentifiedFacetType::RequiredImpl> extends;
|
||||
llvm::SmallVector<SemIR::IdentifiedFacetType::RequiredImpl> impls;
|
||||
llvm::SmallVector<SemIR::IdentifiedFacetType::Rewrite> rewrites;
|
||||
llvm::SmallVector<SemIR::IdentifiedFacetType::Equivalent> equivalents;
|
||||
llvm::SmallVector<IdentifiedFacetType::RequiredImpl> extends;
|
||||
llvm::SmallVector<IdentifiedFacetType::RequiredImpl> impls;
|
||||
llvm::SmallVector<IdentifiedFacetType::Rewrite> rewrites;
|
||||
llvm::SmallVector<IdentifiedFacetType::Equivalent> equivalents;
|
||||
|
||||
while (!work.empty()) {
|
||||
SelfImplsFacetType next_impls = work.pop_back_val();
|
||||
@@ -1033,12 +1033,12 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
context.declared_facet_types().Get(next_impls.declared_facet_type);
|
||||
|
||||
auto self_and_interface = [&](SemIR::SpecificInterface impls_interface)
|
||||
-> SemIR::IdentifiedFacetType::RequiredImpl {
|
||||
-> IdentifiedFacetType::RequiredImpl {
|
||||
return {self_const_id, impls_interface};
|
||||
};
|
||||
auto type_and_interface =
|
||||
[&](SemIR::DeclaredFacetType::TypeImplsInterface impls)
|
||||
-> SemIR::IdentifiedFacetType::RequiredImpl {
|
||||
-> IdentifiedFacetType::RequiredImpl {
|
||||
return {context.constant_values().Get(impls.self_type),
|
||||
impls.specific_interface};
|
||||
};
|
||||
@@ -1060,7 +1060,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
type_and_interface));
|
||||
if (facet_type_extends) {
|
||||
auto rewrite_as_constants =
|
||||
[&](auto rewrite) -> SemIR::IdentifiedFacetType::Rewrite {
|
||||
[&](auto rewrite) -> IdentifiedFacetType::Rewrite {
|
||||
return {context.constant_values().Get(
|
||||
GetImplWitnessAccessWithoutSubstitution(context,
|
||||
rewrite.lhs_id)),
|
||||
@@ -1071,7 +1071,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
rewrite_as_constants));
|
||||
} else {
|
||||
auto rewrite_as_constants =
|
||||
[&](auto rewrite) -> SemIR::IdentifiedFacetType::Equivalent {
|
||||
[&](auto rewrite) -> IdentifiedFacetType::Equivalent {
|
||||
return {context.constant_values().Get(
|
||||
GetImplWitnessAccessWithoutSubstitution(context,
|
||||
rewrite.lhs_id)),
|
||||
@@ -1111,14 +1111,14 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
DiagnoseIncompleteNamedConstraint(context,
|
||||
extends.named_constraint_id);
|
||||
}
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
auto constraint_with_self_specific_id = MakeSpecificWithInnerSelf(
|
||||
context, loc_id, constraint.generic_id,
|
||||
constraint.generic_with_self_id, extends.specific_id, self_const_id);
|
||||
if (context.specifics().HasError(constraint_with_self_specific_id)) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
for (auto require_impls_id : llvm::reverse(require_impls_ids)) {
|
||||
@@ -1136,7 +1136,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
context.sem_ir(), require_specific_id, require.facet_type_inst_id);
|
||||
if (require_self == SemIR::ErrorInst::ConstantId ||
|
||||
require_facet_type == SemIR::ErrorInst::ConstantId) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
auto declared_facet_type_id =
|
||||
@@ -1168,14 +1168,14 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
if (diagnose) {
|
||||
DiagnoseIncompleteNamedConstraint(context, impls.named_constraint_id);
|
||||
}
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
auto constraint_with_self_specific_id = MakeSpecificWithInnerSelf(
|
||||
context, loc_id, constraint.generic_id,
|
||||
constraint.generic_with_self_id, impls.specific_id, self_const_id);
|
||||
if (context.specifics().HasError(constraint_with_self_specific_id)) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
for (auto require_impls_id : llvm::reverse(require_impls_ids)) {
|
||||
@@ -1193,7 +1193,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
context.sem_ir(), require_specific_id, require.facet_type_inst_id);
|
||||
if (require_self == SemIR::ErrorInst::ConstantId ||
|
||||
require_facet_type == SemIR::ErrorInst::ConstantId) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
auto declared_facet_type_id =
|
||||
@@ -1226,7 +1226,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
if (diagnose) {
|
||||
DiagnoseIncompleteNamedConstraint(context, impls.named_constraint_id);
|
||||
}
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
auto constraint_with_self_specific_id = MakeSpecificWithInnerSelf(
|
||||
@@ -1234,7 +1234,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
constraint.generic_with_self_id, impls.specific_id,
|
||||
context.constant_values().Get(self_type_inst_id));
|
||||
if (context.specifics().HasError(constraint_with_self_specific_id)) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
for (auto require_impls_id : llvm::reverse(require_impls_ids)) {
|
||||
@@ -1252,7 +1252,7 @@ static auto IdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
context.sem_ir(), require_specific_id, require.facet_type_inst_id);
|
||||
if (require_self == SemIR::ErrorInst::ConstantId ||
|
||||
require_facet_type == SemIR::ErrorInst::ConstantId) {
|
||||
return SemIR::IdentifiedFacetTypeId::None;
|
||||
return IdentifiedFacetTypeId::None;
|
||||
}
|
||||
|
||||
auto declared_facet_type_id =
|
||||
@@ -1272,7 +1272,7 @@ auto TryToIdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId self_const_id,
|
||||
SemIR::TypeId facet_type_type_id,
|
||||
bool allow_partially_identified)
|
||||
-> SemIR::IdentifiedFacetTypeId {
|
||||
-> IdentifiedFacetTypeId {
|
||||
return IdentifyFacetType(context, loc_id, self_const_id,
|
||||
facet_type_type_id.AsConstantId(),
|
||||
allow_partially_identified,
|
||||
@@ -1283,7 +1283,7 @@ auto RequireIdentifiedFacetType(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId self_const_id,
|
||||
SemIR::TypeId facet_type_type_id,
|
||||
DiagnosticContextFn diagnostic_context,
|
||||
bool diagnose) -> SemIR::IdentifiedFacetTypeId {
|
||||
bool diagnose) -> IdentifiedFacetTypeId {
|
||||
CARBON_CHECK(diagnostic_context);
|
||||
Diagnostics::ContextScope scope(&context.emitter(), diagnostic_context);
|
||||
return IdentifyFacetType(context, loc_id, self_const_id,
|
||||
|
||||
@@ -79,7 +79,7 @@ auto TryToIdentifyFacetType(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId self_const_id,
|
||||
SemIR::TypeId facet_type_type_id,
|
||||
bool allow_partially_identified)
|
||||
-> SemIR::IdentifiedFacetTypeId;
|
||||
-> IdentifiedFacetTypeId;
|
||||
|
||||
// Requires the named constraints in the facet type to be complete, so that the
|
||||
// set of interfaces the facet type requires is known. The `self_const_id` is a
|
||||
@@ -107,8 +107,7 @@ auto RequireIdentifiedFacetType(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId self_const_id,
|
||||
SemIR::TypeId facet_type_type_id,
|
||||
DiagnosticContextFn diagnostic_context,
|
||||
bool diagnose = true)
|
||||
-> SemIR::IdentifiedFacetTypeId;
|
||||
bool diagnose = true) -> IdentifiedFacetTypeId;
|
||||
|
||||
// Emits an error diagnostic explaining that a class is incomplete.
|
||||
//
|
||||
|
||||
@@ -106,7 +106,6 @@ cc_library(
|
||||
"file.cpp",
|
||||
"function.cpp",
|
||||
"generic.cpp",
|
||||
"identified_facet_type.cpp",
|
||||
"impl.cpp",
|
||||
"import_ir.cpp",
|
||||
"inst.cpp",
|
||||
@@ -143,7 +142,6 @@ cc_library(
|
||||
"file.h",
|
||||
"function.h",
|
||||
"generic.h",
|
||||
"identified_facet_type.h",
|
||||
"impl.h",
|
||||
"import_cpp.h",
|
||||
"import_ir.h",
|
||||
|
||||
@@ -303,11 +303,6 @@ namespace Carbon {
|
||||
template class CanonicalValueStore<SemIR::DeclaredFacetTypeId,
|
||||
SemIR::DeclaredFacetType,
|
||||
Tag<SemIR::CheckIRId>>;
|
||||
template class CanonicalValueStore<
|
||||
SemIR::IdentifiedFacetTypeId, SemIR::IdentifiedFacetTypeKey,
|
||||
Tag<SemIR::CheckIRId>, SemIR::IdentifiedFacetType>;
|
||||
template class ValueStore<SemIR::DeclaredFacetTypeId, SemIR::DeclaredFacetType,
|
||||
Tag<SemIR::CheckIRId>>;
|
||||
template class ValueStore<SemIR::IdentifiedFacetTypeId,
|
||||
SemIR::IdentifiedFacetType, Tag<SemIR::CheckIRId>>;
|
||||
} // namespace Carbon
|
||||
+13
-51
@@ -22,7 +22,7 @@ LLVM_DUMP_METHOD auto Dump(const File& file) -> std::string {
|
||||
return PrintToString(file);
|
||||
}
|
||||
|
||||
static auto DumpNameIfValid(const File& file, NameId name_id) -> std::string {
|
||||
auto DumpNameIfValid(const File& file, NameId name_id) -> std::string {
|
||||
RawStringOstream out;
|
||||
if (name_id.has_value()) {
|
||||
out << " `" << file.names().GetFormatted(name_id) << "`";
|
||||
@@ -30,8 +30,8 @@ static auto DumpNameIfValid(const File& file, NameId name_id) -> std::string {
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpNameOfEntityName(const File& file,
|
||||
const EntityName& entity_name) -> std::string {
|
||||
auto DumpNameOfEntityName(const File& file, const EntityName& entity_name)
|
||||
-> std::string {
|
||||
RawStringOstream out;
|
||||
out << " `";
|
||||
out << file.names().GetFormatted(entity_name.name_id);
|
||||
@@ -42,7 +42,7 @@ static auto DumpNameOfEntityName(const File& file,
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpLocSummary(const File& file, LocId loc_id) -> std::string {
|
||||
auto DumpLocSummary(const File& file, LocId loc_id) -> std::string {
|
||||
RawStringOstream out;
|
||||
// TODO: If the canonical location is None but the original is an InstId,
|
||||
// should we dump the InstId anyway even though it has no location? Is that
|
||||
@@ -84,8 +84,7 @@ static auto DumpLocSummary(const File& file, LocId loc_id) -> std::string {
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpConstantSummary(const File& file, ConstantId const_id)
|
||||
-> std::string {
|
||||
auto DumpConstantSummary(const File& file, ConstantId const_id) -> std::string {
|
||||
RawStringOstream out;
|
||||
out << const_id;
|
||||
if (!const_id.has_value()) {
|
||||
@@ -101,7 +100,7 @@ static auto DumpConstantSummary(const File& file, ConstantId const_id)
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpTypeSummary(const File& file, TypeId type_id) -> std::string {
|
||||
auto DumpTypeSummary(const File& file, TypeId type_id) -> std::string {
|
||||
RawStringOstream out;
|
||||
out << type_id;
|
||||
if (!type_id.has_value()) {
|
||||
@@ -124,7 +123,7 @@ static auto DumpTypeSummary(const File& file, TypeId type_id) -> std::string {
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpInstSummary(const File& file, InstId inst_id) -> std::string {
|
||||
auto DumpInstSummary(const File& file, InstId inst_id) -> std::string {
|
||||
RawStringOstream out;
|
||||
out << inst_id;
|
||||
if (inst_id.has_value() && inst_id != InstId::InitTombstone &&
|
||||
@@ -134,8 +133,7 @@ static auto DumpInstSummary(const File& file, InstId inst_id) -> std::string {
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpGenericSummary(const File& file, GenericId generic_id)
|
||||
-> std::string {
|
||||
auto DumpGenericSummary(const File& file, GenericId generic_id) -> std::string {
|
||||
RawStringOstream out;
|
||||
out << generic_id;
|
||||
if (!generic_id.has_value()) {
|
||||
@@ -147,7 +145,7 @@ static auto DumpGenericSummary(const File& file, GenericId generic_id)
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpInterfaceSummary(const File& file, InterfaceId interface_id)
|
||||
auto DumpInterfaceSummary(const File& file, InterfaceId interface_id)
|
||||
-> std::string {
|
||||
RawStringOstream out;
|
||||
out << interface_id;
|
||||
@@ -158,8 +156,8 @@ static auto DumpInterfaceSummary(const File& file, InterfaceId interface_id)
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpNamedConstraintSummary(const File& file,
|
||||
NamedConstraintId named_constraint_id)
|
||||
auto DumpNamedConstraintSummary(const File& file,
|
||||
NamedConstraintId named_constraint_id)
|
||||
-> std::string {
|
||||
RawStringOstream out;
|
||||
out << named_constraint_id;
|
||||
@@ -170,7 +168,7 @@ static auto DumpNamedConstraintSummary(const File& file,
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpSpecificSummary(const File& file, SpecificId specific_id)
|
||||
auto DumpSpecificSummary(const File& file, SpecificId specific_id)
|
||||
-> std::string {
|
||||
RawStringOstream out;
|
||||
out << specific_id;
|
||||
@@ -180,8 +178,7 @@ static auto DumpSpecificSummary(const File& file, SpecificId specific_id)
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
static auto DumpRequireImplsSummary(const File& file,
|
||||
RequireImplsId require_impls_id)
|
||||
auto DumpRequireImplsSummary(const File& file, RequireImplsId require_impls_id)
|
||||
-> std::string {
|
||||
RawStringOstream out;
|
||||
out << require_impls_id;
|
||||
@@ -380,37 +377,6 @@ LLVM_DUMP_METHOD auto Dump(const File& file, GenericId generic_id)
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD auto Dump(const File& file,
|
||||
IdentifiedFacetTypeId identified_facet_type_id)
|
||||
-> std::string {
|
||||
RawStringOstream out;
|
||||
out << identified_facet_type_id;
|
||||
if (!identified_facet_type_id.has_value()) {
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
const auto& identified_facet_type =
|
||||
file.identified_facet_types().Get(identified_facet_type_id);
|
||||
for (auto [i, req_impl] :
|
||||
llvm::enumerate(identified_facet_type.required_impls())) {
|
||||
auto [self, req_interface] = req_impl;
|
||||
out << "\n - self: " << DumpConstantSummary(file, self);
|
||||
out << "\n impls: "
|
||||
<< DumpInterfaceSummary(file, req_interface.interface_id);
|
||||
if (req_interface.specific_id.has_value()) {
|
||||
out << "; " << DumpSpecificSummary(file, req_interface.specific_id);
|
||||
}
|
||||
if (req_interface == identified_facet_type.impl_as_target_interface()) {
|
||||
out << "\n - `impl as` target";
|
||||
}
|
||||
}
|
||||
if (!identified_facet_type.is_valid_impl_as_target()) {
|
||||
out << "\n - " << identified_facet_type.num_interfaces_to_impl()
|
||||
<< " possible `impl as` targets";
|
||||
}
|
||||
return out.TakeStr();
|
||||
}
|
||||
|
||||
LLVM_DUMP_METHOD auto Dump(const File& file, ImplId impl_id) -> std::string {
|
||||
RawStringOstream out;
|
||||
out << impl_id;
|
||||
@@ -725,10 +691,6 @@ LLVM_DUMP_METHOD static auto MakeNameId(int id) -> NameId { return NameId(id); }
|
||||
LLVM_DUMP_METHOD static auto MakeNameScopeId(int id) -> NameScopeId {
|
||||
return NameScopeId(id);
|
||||
}
|
||||
LLVM_DUMP_METHOD static auto MakeIdentifiedFacetTypeId(int id)
|
||||
-> IdentifiedFacetTypeId {
|
||||
return IdentifiedFacetTypeId(id);
|
||||
}
|
||||
LLVM_DUMP_METHOD static auto MakeImportIRInstId(int id) -> ImportIRInstId {
|
||||
return ImportIRInstId(id);
|
||||
}
|
||||
|
||||
+18
-2
@@ -29,6 +29,24 @@
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
auto DumpNameIfValid(const File& file, NameId name_id) -> std::string;
|
||||
auto DumpNameOfEntityName(const File& file, const EntityName& entity_name)
|
||||
-> std::string;
|
||||
auto DumpLocSummary(const File& file, LocId loc_id) -> std::string;
|
||||
auto DumpConstantSummary(const File& file, ConstantId const_id) -> std::string;
|
||||
auto DumpTypeSummary(const File& file, TypeId type_id) -> std::string;
|
||||
auto DumpInstSummary(const File& file, InstId inst_id) -> std::string;
|
||||
auto DumpGenericSummary(const File& file, GenericId generic_id) -> std::string;
|
||||
auto DumpInterfaceSummary(const File& file, InterfaceId interface_id)
|
||||
-> std::string;
|
||||
auto DumpNamedConstraintSummary(const File& file,
|
||||
NamedConstraintId named_constraint_id)
|
||||
-> std::string;
|
||||
auto DumpSpecificSummary(const File& file, SpecificId specific_id)
|
||||
-> std::string;
|
||||
auto DumpRequireImplsSummary(const File& file, RequireImplsId require_impls_id)
|
||||
-> std::string;
|
||||
|
||||
auto Dump(const File& file) -> std::string;
|
||||
auto Dump(const File& file, RawBundleId bundle_id) -> std::string;
|
||||
auto Dump(const File& file, GeneratedFunctionId generated_function_id)
|
||||
@@ -45,8 +63,6 @@ auto Dump(const File& file, EntityNameId entity_name_id) -> std::string;
|
||||
auto Dump(const File& file, FieldId field_id) -> std::string;
|
||||
auto Dump(const File& file, FunctionId function_id) -> std::string;
|
||||
auto Dump(const File& file, GenericId generic_id) -> std::string;
|
||||
auto Dump(const File& file, IdentifiedFacetTypeId identified_facet_type_id)
|
||||
-> std::string;
|
||||
auto Dump(const File& file, ImplId impl_id) -> std::string;
|
||||
auto Dump(const File& file, ImportIRInstId import_inst_id) -> std::string;
|
||||
auto Dump(const File& file, const Inst& inst) -> std::string;
|
||||
|
||||
@@ -59,7 +59,6 @@ File::File(const Parse::Tree* parse_tree, CheckIRId check_ir_id,
|
||||
associated_constants_(check_ir_id),
|
||||
// 1 reserved id for `DeclaredFacetTypeId::Empty`.
|
||||
declared_facet_types_(check_ir_id, 1),
|
||||
identified_facet_types_(check_ir_id),
|
||||
impls_(*this),
|
||||
specific_interfaces_(check_ir_id),
|
||||
generics_(check_ir_id),
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "toolchain/sem_ir/field.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/generic.h"
|
||||
#include "toolchain/sem_ir/identified_facet_type.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/impl.h"
|
||||
#include "toolchain/sem_ir/import_cpp.h"
|
||||
@@ -241,12 +240,6 @@ class File : public Printable<File> {
|
||||
auto AppendCppMangledTypeName(ClassId class_id, llvm::raw_ostream& out) const
|
||||
-> bool;
|
||||
|
||||
auto identified_facet_types() -> IdentifiedFacetTypeStore& {
|
||||
return identified_facet_types_;
|
||||
}
|
||||
auto identified_facet_types() const -> const IdentifiedFacetTypeStore& {
|
||||
return identified_facet_types_;
|
||||
}
|
||||
auto impls() -> ImplStore& { return impls_; }
|
||||
auto impls() const -> const ImplStore& { return impls_; }
|
||||
auto specific_interfaces() -> SpecificInterfaceStore& {
|
||||
@@ -429,9 +422,6 @@ class File : public Printable<File> {
|
||||
// Storage for declared facet types.
|
||||
DeclaredFacetTypeStore declared_facet_types_;
|
||||
|
||||
// Storage for identified facet types.
|
||||
IdentifiedFacetTypeStore identified_facet_types_;
|
||||
|
||||
// Storage for impls.
|
||||
ImplStore impls_;
|
||||
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include "toolchain/sem_ir/identified_facet_type.h"
|
||||
|
||||
#include "toolchain/base/canonical_value_store_impl.h"
|
||||
#include "toolchain/base/kind_switch.h"
|
||||
#include "toolchain/base/value_store_impl.h"
|
||||
#include "toolchain/sem_ir/file.h"
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
template <typename T>
|
||||
using LessThanFn = llvm::function_ref<auto(const T&, const T&)->bool>;
|
||||
|
||||
template <typename VecT>
|
||||
static auto SortAndDeduplicate(VecT& vec,
|
||||
LessThanFn<typename VecT::value_type> compare)
|
||||
-> void {
|
||||
llvm::sort(vec, compare);
|
||||
vec.erase(llvm::unique(vec), vec.end());
|
||||
}
|
||||
|
||||
// Canonically ordered by the numerical ids. Matches the order of RequiredLess
|
||||
// when the `self_facet_value` is the same for all interfaces.
|
||||
static auto InterfaceLess(const SpecificInterface& lhs,
|
||||
const SpecificInterface& rhs) -> bool {
|
||||
return std::tie(lhs.interface_id.index, lhs.specific_id.index) <
|
||||
std::tie(rhs.interface_id.index, rhs.specific_id.index);
|
||||
}
|
||||
|
||||
// Canonically ordered by the numerical ids.
|
||||
static auto RequiredLess(const IdentifiedFacetType::RequiredImpl& lhs,
|
||||
const IdentifiedFacetType::RequiredImpl& rhs) -> bool {
|
||||
return std::tie(lhs.self_facet_value.index,
|
||||
lhs.specific_interface.interface_id.index,
|
||||
lhs.specific_interface.specific_id.index) <
|
||||
std::tie(rhs.self_facet_value.index,
|
||||
rhs.specific_interface.interface_id.index,
|
||||
rhs.specific_interface.specific_id.index);
|
||||
}
|
||||
|
||||
// Canonically ordered by the numerical ids.
|
||||
static auto RewriteLess(const IdentifiedFacetType::Rewrite& lhs,
|
||||
const IdentifiedFacetType::Rewrite& rhs) -> bool {
|
||||
return std::tie(lhs.lhs.index, lhs.rhs.index) <
|
||||
std::tie(rhs.lhs.index, rhs.rhs.index);
|
||||
}
|
||||
|
||||
// Canonically ordered by the numerical ids.
|
||||
static auto EquivalentLess(const IdentifiedFacetType::Equivalent& lhs,
|
||||
const IdentifiedFacetType::Equivalent& rhs) -> bool {
|
||||
return std::tie(lhs.lhs.index, lhs.rhs.index) <
|
||||
std::tie(rhs.lhs.index, rhs.rhs.index);
|
||||
}
|
||||
|
||||
IdentifiedFacetType::IdentifiedFacetType(
|
||||
IdentifiedFacetTypeKey key, bool partially_identified,
|
||||
llvm::ArrayRef<RequiredImpl> extends,
|
||||
llvm::ArrayRef<RequiredImpl> self_impls, llvm::ArrayRef<Rewrite> rewrites,
|
||||
llvm::ArrayRef<Equivalent> equivalents)
|
||||
: key_(key) {
|
||||
required_impls_.reserve(extends.size() + self_impls.size());
|
||||
llvm::append_range(required_impls_, extends);
|
||||
SortAndDeduplicate(required_impls_, RequiredLess);
|
||||
|
||||
// If there's a single extended interface then we present as that interface.
|
||||
// Otherwise, we record the number extended interfaces.
|
||||
if (required_impls_.size() == 1) {
|
||||
interface_id_ = required_impls_.front().specific_interface.interface_id;
|
||||
specific_id_ = required_impls_.front().specific_interface.specific_id;
|
||||
} else {
|
||||
interface_id_ = InterfaceId::None;
|
||||
num_interface_to_impl_ = required_impls_.size();
|
||||
}
|
||||
|
||||
llvm::append_range(required_impls_, self_impls);
|
||||
SortAndDeduplicate(required_impls_, RequiredLess);
|
||||
SortAndDeduplicate(required_impls_, RequiredLess);
|
||||
|
||||
if (partially_identified) {
|
||||
// This marks the IdentifiedFacetType as being partially identified, and
|
||||
// prevents the key from colliding with a fully identified facet type, or
|
||||
// with other partially (but differently) identified facet types, with the
|
||||
// same constituents but a more complete set of required interfaces.
|
||||
key_.num_require_impls = required_impls_.size();
|
||||
}
|
||||
|
||||
rewrites_.assign(rewrites);
|
||||
SortAndDeduplicate(rewrites_, RewriteLess);
|
||||
equivalents_.assign(equivalents);
|
||||
SortAndDeduplicate(equivalents_, EquivalentLess);
|
||||
}
|
||||
|
||||
auto AddCanonicalWitnessesBlock(File& sem_ir,
|
||||
llvm::SmallVector<InstId>& witnesses)
|
||||
-> InstBlockId {
|
||||
// Small blocks don't need to be sorted.
|
||||
if (witnesses.size() <= 1) {
|
||||
return sem_ir.inst_blocks().AddCanonical(witnesses);
|
||||
}
|
||||
|
||||
llvm::SmallVector<std::pair<SpecificInterface, InstId>> sortable;
|
||||
sortable.reserve(witnesses.size());
|
||||
|
||||
// Produce the sorted order based on the witness's SpecificInterface.
|
||||
for (auto witness_id : witnesses) {
|
||||
auto inst = sem_ir.insts().Get(witness_id);
|
||||
CARBON_KIND_SWITCH(inst) {
|
||||
case CARBON_KIND(CustomWitness witness): {
|
||||
sortable.push_back({sem_ir.specific_interfaces().Get(
|
||||
witness.query_specific_interface_id),
|
||||
witness_id});
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(ImplWitness witness): {
|
||||
auto table =
|
||||
sem_ir.insts().GetAs<ImplWitnessTable>(witness.witness_table_id);
|
||||
sortable.push_back(
|
||||
{sem_ir.impls().Get(table.impl_id).interface, witness_id});
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(LookupImplWitness witness): {
|
||||
sortable.push_back({sem_ir.specific_interfaces().Get(
|
||||
witness.query_specific_interface_id),
|
||||
witness_id});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CARBON_FATAL("Unhandled inst: {0}", inst);
|
||||
}
|
||||
}
|
||||
// This matches the sort order of IdentifiedFacetType::required_interfaces,
|
||||
// which is the order of the witnesses returned from impl lookup, and is
|
||||
// canonical order in which the witnesses must appear for a given facet type
|
||||
// so that ImplWitnessAccess can find the appropriate witness.
|
||||
llvm::sort(sortable, [](auto& lhs, auto& rhs) {
|
||||
return InterfaceLess(lhs.first, rhs.first);
|
||||
});
|
||||
|
||||
// Update the original list with the new order (reusing to avoid an
|
||||
// allocation).
|
||||
for (auto [witness_id, sortable_entry] :
|
||||
llvm::zip_equal(witnesses, sortable)) {
|
||||
witness_id = sortable_entry.second;
|
||||
}
|
||||
|
||||
return sem_ir.inst_blocks().AddCanonical(witnesses);
|
||||
}
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
@@ -378,13 +378,6 @@ struct DeclaredFacetTypeId : public IdBase<DeclaredFacetTypeId> {
|
||||
inline constexpr DeclaredFacetTypeId DeclaredFacetTypeId::Empty =
|
||||
DeclaredFacetTypeId(0);
|
||||
|
||||
// The ID of an resolved facet type value.
|
||||
struct IdentifiedFacetTypeId : public IdBase<IdentifiedFacetTypeId> {
|
||||
static constexpr llvm::StringLiteral Label = "identified_facet_type";
|
||||
|
||||
using IdBase::IdBase;
|
||||
};
|
||||
|
||||
// The ID of an `Impl`.
|
||||
struct ImplId : public IdBase<ImplId> {
|
||||
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
|
||||
|
||||
Reference in new issue
Block a user