Skip to content

Commit fe020ee

Browse files
authored
Make FacetAccessType evaluate to SymbolicBindingType for type-of a BindSymbolicName (#6115)
The SymbolicBindingType refers to the type value that will be substituted in for the BindSymbolicName, but holds onto the EntityNameId from the BindSymbolicName instead of (or in addition to, for now) the instruction. The EntityNameId will be used to look in the ScopeStack to find the witnesses either from the BindSymbolicName instruction, or other instructions that specify `impls` constraints against the EntityName. This will allow us to have the `T` in `I(T)` resolve to a `.Self` reference in the type so that we get type equality with the binding's type: `T:! I(.Self)`.
1 parent bd4d580 commit fe020ee

File tree

237 files changed

+7825
-7584
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

237 files changed

+7825
-7584
lines changed

toolchain/check/convert.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,8 +1208,10 @@ static auto PerformBuiltinConversion(
12081208
} else {
12091209
type_inst_id = context.types().GetAsTypeInstId(value_id);
12101210

1211-
// Shortcut for lossless round trips through a FacetAccessType when
1212-
// converting back to the type of its original facet value.
1211+
// Shortcut for lossless round trips through a FacetAccessType (which
1212+
// evaluates to SymbolicBindingType when wrapping a symbolic binding) when
1213+
// converting back to the type of the original symbolic binding facet
1214+
// value.
12131215
//
12141216
// In the case where the FacetAccessType wraps a BindSymbolicName with the
12151217
// exact facet type that we are converting to, the resulting FacetValue
@@ -1219,16 +1221,10 @@ static auto PerformBuiltinConversion(
12191221
//
12201222
// TODO: This instruction is going to become a `SymbolicBindingType`, so
12211223
// we'll need to handle that instead.
1222-
auto const_type_inst_id =
1223-
sem_ir.constant_values().GetConstantTypeInstId(type_inst_id);
1224-
if (auto facet_access_type_inst =
1225-
sem_ir.insts().TryGetAs<SemIR::FacetAccessType>(
1226-
const_type_inst_id)) {
1227-
auto facet_value_inst_id = facet_access_type_inst->facet_value_inst_id;
1228-
if (sem_ir.insts().Get(facet_value_inst_id).type_id() ==
1229-
target.type_id) {
1230-
return facet_value_inst_id;
1231-
}
1224+
auto facet_value_inst_id =
1225+
GetCanonicalFacetOrTypeValue(context, type_inst_id);
1226+
if (sem_ir.insts().Get(facet_value_inst_id).type_id() == target.type_id) {
1227+
return facet_value_inst_id;
12321228
}
12331229
}
12341230

toolchain/check/eval.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,6 +2171,82 @@ auto TryEvalTypedInst<SemIR::BindSymbolicName>(EvalContext& eval_context,
21712171
return MakeConstantResult(eval_context.context(), bind, phase);
21722172
}
21732173

2174+
template <>
2175+
auto TryEvalTypedInst<SemIR::SymbolicBindingType>(EvalContext& eval_context,
2176+
SemIR::InstId inst_id,
2177+
SemIR::Inst inst)
2178+
-> SemIR::ConstantId {
2179+
auto bind = inst.As<SemIR::SymbolicBindingType>();
2180+
2181+
Phase phase = Phase::Concrete;
2182+
bool updated_constants = false;
2183+
2184+
// If we know which specific we're evaluating within and this is the type
2185+
// component of a facet parameter of the generic, its constant value refers to
2186+
// the type component of the corresponding argument value of the specific.
2187+
const auto& bind_name = eval_context.entity_names().Get(bind.entity_name_id);
2188+
if (bind_name.bind_index().has_value()) {
2189+
// SymbolicBindingType comes from the evaluation of FacetAccessType when the
2190+
// facet value is symbolic. This block is effectively the deferred
2191+
// evaluation of that FacetAccessType now that a new value for the symbolic
2192+
// facet value has become known. The result is equivalent to creating a new
2193+
// FacetAccessType here with the `value_inst_id` and evaluating it.
2194+
if (auto value =
2195+
eval_context.GetCompileTimeBindValue(bind_name.bind_index());
2196+
value.has_value()) {
2197+
auto value_inst_id = eval_context.constant_values().GetInstId(value);
2198+
if (auto facet =
2199+
eval_context.insts().TryGetAs<SemIR::FacetValue>(value_inst_id)) {
2200+
return eval_context.constant_values().Get(facet->type_inst_id);
2201+
}
2202+
2203+
// Replace the fields with constant values as usual, except we get the
2204+
// EntityNameId from the BindSymbolicName in the specific, which
2205+
// ReplaceFieldWithConstantValue doesn't know how to do.
2206+
if (!ReplaceTypeWithConstantValue(eval_context, inst_id, &bind, &phase) ||
2207+
!ReplaceFieldWithConstantValue(
2208+
eval_context, &bind,
2209+
&SemIR::SymbolicBindingType::facet_value_inst_id, &phase)) {
2210+
return SemIR::ConstantId::NotConstant;
2211+
}
2212+
2213+
if (value_inst_id == SemIR::ErrorInst::InstId) {
2214+
phase = Phase::UnknownDueToError;
2215+
} else {
2216+
auto value_bind =
2217+
eval_context.insts().GetAs<SemIR::BindSymbolicName>(value_inst_id);
2218+
bind.entity_name_id =
2219+
GetConstantValue(eval_context, value_bind.entity_name_id, &phase);
2220+
}
2221+
2222+
updated_constants = true;
2223+
}
2224+
}
2225+
2226+
if (!updated_constants) {
2227+
if (!ReplaceTypeWithConstantValue(eval_context, inst_id, &inst, &phase) ||
2228+
!ReplaceAllFieldsWithConstantValues(eval_context, &inst, &phase)) {
2229+
return SemIR::ConstantId::NotConstant;
2230+
}
2231+
// Copy the updated constant field values into `bind`.
2232+
bind = inst.As<SemIR::SymbolicBindingType>();
2233+
}
2234+
// Propagate error phase after getting the constant value for all fields.
2235+
if (phase == Phase::UnknownDueToError) {
2236+
return SemIR::ErrorInst::ConstantId;
2237+
}
2238+
2239+
// TODO: Look in ScopeStack with the entity_name_id to find the facet value
2240+
// and get its constant value in the current specific context. The
2241+
// facet_value_inst_id will go away.
2242+
if (auto facet_value = eval_context.insts().TryGetAs<SemIR::FacetValue>(
2243+
bind.facet_value_inst_id)) {
2244+
return eval_context.constant_values().Get(facet_value->type_inst_id);
2245+
}
2246+
2247+
return MakeConstantResult(eval_context.context(), bind, phase);
2248+
}
2249+
21742250
// Returns whether `const_id` is the same constant facet value as
21752251
// `facet_value_inst_id`.
21762252
//

toolchain/check/eval_inst.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,46 @@ auto EvalConstantInst(Context& context, SemIR::FacetAccessType inst)
200200
return ConstantEvalResult::Existing(
201201
context.constant_values().Get(facet_value->type_inst_id));
202202
}
203+
204+
if (auto bind_name = context.insts().TryGetAs<SemIR::BindSymbolicName>(
205+
inst.facet_value_inst_id)) {
206+
return ConstantEvalResult::NewSamePhase(SemIR::SymbolicBindingType{
207+
.type_id = SemIR::TypeType::TypeId,
208+
.entity_name_id = bind_name->entity_name_id,
209+
// TODO: This is to be removed, at which point explore if we should
210+
// replace NewSamePhase with NewAnyPhase (to make the constant value
211+
// concrete). This is still a symbolic type though even if the inst
212+
// doesn't contain a symbolic constant. Previously we crashed in CHECKs
213+
// when we had a symbolic instruction with only an EntityNameId, due to
214+
// it not changing in a generic eval block. Maybe that has improved in
215+
// the latest version of this instruction. If it's not symbolic, then
216+
// SubstConstantCallbacks and other Subst callers may need to handle
217+
// looking through concrete instructions which would be unfortunate.
218+
.facet_value_inst_id = inst.facet_value_inst_id});
219+
}
220+
221+
// The `facet_value_inst_id` is always a facet value (has type facet type).
222+
CARBON_CHECK(context.types().Is<SemIR::FacetType>(
223+
context.insts().Get(inst.facet_value_inst_id).type_id()));
224+
225+
// Other instructions (e.g. ImplWitnessAccess) of type FacetType can appear
226+
// here, in which case the constant inst is a FacetAccessType until those
227+
// instructions resolve to one of the above.
203228
return ConstantEvalResult::NewSamePhase(inst);
204229
}
205230

206231
auto EvalConstantInst(Context& context, SemIR::FacetValue inst)
207232
-> ConstantEvalResult {
208233
// A FacetValue that just wraps a BindSymbolicName without adding/removing any
209234
// witnesses is evaluated back to the BindSymbolicName itself.
210-
if (auto access =
211-
context.insts().TryGetAs<SemIR::FacetAccessType>(inst.type_inst_id)) {
212-
auto bind_id = access->facet_value_inst_id;
213-
auto bind = context.insts().TryGetAs<SemIR::BindSymbolicName>(bind_id);
235+
if (auto bind_as_type = context.insts().TryGetAs<SemIR::SymbolicBindingType>(
236+
inst.type_inst_id)) {
237+
// TODO: Look in ScopeStack with the entity_name_id to find the facet value.
238+
auto bind_id = bind_as_type->facet_value_inst_id;
239+
auto bind = context.insts().GetAs<SemIR::BindSymbolicName>(bind_id);
214240
// If the FacetTypes are the same, then the FacetValue didn't add/remove
215241
// any witnesses.
216-
if (bind.has_value() && bind->type_id == inst.type_id) {
242+
if (bind.type_id == inst.type_id) {
217243
return ConstantEvalResult::Existing(
218244
context.constant_values().Get(bind_id));
219245
}

toolchain/check/import_ref.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,8 @@ static auto GetLocalConstantId(ImportRefResolver& resolver,
752752
}
753753

754754
// Translates a NameId from the import IR to a local NameId.
755+
//
756+
// No new work is generated by calling this function.
755757
static auto GetLocalNameId(ImportContext& context, SemIR::NameId import_name_id)
756758
-> SemIR::NameId {
757759
if (auto ident_id = import_name_id.AsIdentifierId(); ident_id.has_value()) {
@@ -761,6 +763,23 @@ static auto GetLocalNameId(ImportContext& context, SemIR::NameId import_name_id)
761763
return import_name_id;
762764
}
763765

766+
// Returns the id for a local symbolic EntityName from an imported one,
767+
// preserving only the `NameId`, the `CompileTimeBindIndex`, and whether it is a
768+
// template. Other parts of the EntityName are not kept and are not considered
769+
// part of the canonical EntityName (even if they are present there).
770+
//
771+
// No new work is generated by calling this function.
772+
static auto GetLocalSymbolicEntityNameId(
773+
ImportContext& context, SemIR::EntityNameId import_entity_name_id)
774+
-> SemIR::EntityNameId {
775+
const auto& import_entity_name =
776+
context.import_entity_names().Get(import_entity_name_id);
777+
auto name_id = GetLocalNameId(context, import_entity_name.name_id);
778+
return context.local_entity_names().AddSymbolicBindingName(
779+
name_id, SemIR::NameScopeId::None, import_entity_name.bind_index(),
780+
import_entity_name.is_template);
781+
}
782+
764783
// Gets the local constant values corresponding to an imported inst block.
765784
static auto GetLocalInstBlockContents(ImportRefResolver& resolver,
766785
SemIR::InstBlockId import_block_id)
@@ -1501,12 +1520,8 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
15011520
return ResolveResult::Retry();
15021521
}
15031522

1504-
const auto& import_entity_name =
1505-
resolver.import_entity_names().Get(inst.entity_name_id);
1506-
auto name_id = GetLocalNameId(resolver, import_entity_name.name_id);
1507-
auto entity_name_id = resolver.local_entity_names().AddSymbolicBindingName(
1508-
name_id, SemIR::NameScopeId::None, import_entity_name.bind_index(),
1509-
import_entity_name.is_template);
1523+
auto entity_name_id =
1524+
GetLocalSymbolicEntityNameId(resolver, inst.entity_name_id);
15101525
return ResolveAsDeduplicated<SemIR::BindSymbolicName>(
15111526
resolver,
15121527
{.type_id =
@@ -2960,6 +2975,23 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
29602975
GetLocalCanonicalInstBlockId(resolver, inst.elements_id, elems)});
29612976
}
29622977

2978+
static auto TryResolveTypedInst(ImportRefResolver& resolver,
2979+
SemIR::SymbolicBindingType inst)
2980+
-> ResolveResult {
2981+
auto facet_value_inst_id =
2982+
GetLocalConstantInstId(resolver, inst.facet_value_inst_id);
2983+
if (resolver.HasNewWork()) {
2984+
return ResolveResult::Retry();
2985+
}
2986+
2987+
auto entity_name_id =
2988+
GetLocalSymbolicEntityNameId(resolver, inst.entity_name_id);
2989+
return ResolveAsDeduplicated<SemIR::SymbolicBindingType>(
2990+
resolver, {.type_id = SemIR::TypeType::TypeId,
2991+
.entity_name_id = entity_name_id,
2992+
.facet_value_inst_id = facet_value_inst_id});
2993+
}
2994+
29632995
static auto TryResolveTypedInst(ImportRefResolver& resolver,
29642996
SemIR::TupleAccess inst) -> ResolveResult {
29652997
auto type_id = GetLocalConstantId(resolver, inst.type_id);
@@ -3311,6 +3343,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver,
33113343
case CARBON_KIND(SemIR::SymbolicBindingPattern inst): {
33123344
return TryResolveTypedInst(resolver, inst, constant_inst_id);
33133345
}
3346+
case CARBON_KIND(SemIR::SymbolicBindingType inst): {
3347+
return TryResolveTypedInst(resolver, inst);
3348+
}
33143349
case CARBON_KIND(SemIR::TupleAccess inst): {
33153350
return TryResolveTypedInst(resolver, inst);
33163351
}

0 commit comments

Comments
 (0)