Skip to content

Commit d1f58ab

Browse files
committed
symbolic-binding-type
1 parent 2d594e3 commit d1f58ab

File tree

165 files changed

+6452
-6336
lines changed

Some content is hidden

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

165 files changed

+6452
-6336
lines changed

toolchain/check/convert.cpp

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -828,29 +828,20 @@ static auto CanRemoveQualifiers(SemIR::TypeQualifiers quals,
828828
static auto DiagnoseConversionFailureToConstraintValue(
829829
Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
830830
SemIR::TypeId target_type_id) -> void {
831-
CARBON_DCHECK(target_type_id == SemIR::TypeType::TypeId ||
832-
context.types().Is<SemIR::FacetType>(target_type_id));
831+
CARBON_CHECK(context.types().IsFacetType(target_type_id));
833832

834-
auto type_of_expr_id = context.insts().Get(expr_id).type_id();
835-
CARBON_CHECK(context.types().IsFacetType(type_of_expr_id));
836833
// If the source type is/has a facet value, then we can include its
837834
// FacetType in the diagnostic to help explain what interfaces the
838835
// source type implements.
839-
auto facet_value_inst_id = SemIR::InstId::None;
840-
if (auto facet_access_type =
841-
context.insts().TryGetAs<SemIR::FacetAccessType>(expr_id)) {
842-
facet_value_inst_id = facet_access_type->facet_value_inst_id;
843-
} else if (context.types().Is<SemIR::FacetType>(type_of_expr_id)) {
844-
facet_value_inst_id = expr_id;
845-
}
836+
auto facet_type_inst_id = GetCanonicalizedFacetTypeOrType(context, expr_id);
846837

847-
if (facet_value_inst_id.has_value()) {
838+
if (context.insts().Is<SemIR::FacetType>(facet_type_inst_id)) {
848839
CARBON_DIAGNOSTIC(ConversionFailureFacetToFacet, Error,
849840
"cannot convert type {0} that implements {1} into type "
850841
"implementing {2}",
851-
InstIdAsType, TypeOfInstId, SemIR::TypeId);
842+
InstIdAsType, InstIdAsType, SemIR::TypeId);
852843
context.emitter().Emit(loc_id, ConversionFailureFacetToFacet, expr_id,
853-
facet_value_inst_id, target_type_id);
844+
facet_type_inst_id, target_type_id);
854845
} else {
855846
CARBON_DIAGNOSTIC(ConversionFailureTypeToFacet, Error,
856847
"cannot convert type {0} into type implementing {1}",
@@ -1219,8 +1210,9 @@ static auto PerformBuiltinConversion(
12191210
const_type_inst_id = sem_ir.constant_values().GetConstantTypeInstId(
12201211
context.types().GetAsTypeInstId(value_id));
12211212

1222-
// Lossless round trips through a FacetAccessType when converting back to
1223-
// the type of its original facet value.
1213+
// Lossless round trips through a FacetAccessType (which evaluates to
1214+
// SymbolicBindingType) when converting back to the type of its original
1215+
// facet value.
12241216
//
12251217
// Given a symbolic facet value X, if a FacetAccessType(X) is converted to
12261218
// the type of X, we make the past introduction of the FacetAccessType
@@ -1239,12 +1231,11 @@ static auto PerformBuiltinConversion(
12391231
//
12401232
// See also test:
12411233
// facet_access_type_converts_back_to_original_facet_value.carbon
1242-
//
1243-
// TODO: This instruction is going to become a `SymbolicBindingType`, so
1244-
// we'll need to handle that instead.
12451234
if (auto facet_access_type_inst =
1246-
sem_ir.insts().TryGetAs<SemIR::FacetAccessType>(
1235+
sem_ir.insts().TryGetAs<SemIR::SymbolicBindingType>(
12471236
const_type_inst_id)) {
1237+
// TODO: Look in ScopeStack with the the entity_name_id to find the
1238+
// facet value.
12481239
auto facet_value_inst_id = facet_access_type_inst->facet_value_inst_id;
12491240
if (sem_ir.insts().Get(facet_value_inst_id).type_id() ==
12501241
target.type_id) {

toolchain/check/deduce.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ auto DeductionContext::Deduce() -> bool {
411411
// TODO: Match field name order between param and arg.
412412
break;
413413

414-
case CARBON_KIND(SemIR::FacetAccessType access): {
414+
case CARBON_KIND(SemIR::SymbolicBindingType binding): {
415415
// Given `fn F[G:! Interface](g: G)`, the type of `g` is `G as type`.
416416
// `G` is a symbolic binding, whose type is a facet type, but `G as
417417
// type` converts into a `FacetAccessType`.
@@ -421,7 +421,10 @@ auto DeductionContext::Deduce() -> bool {
421421
// argument would be a facet value, whose type is the same facet type of
422422
// `G`. So here we "undo" the `as type` operation that's built into the
423423
// `g` parameter's type.
424-
Add(access.facet_value_inst_id, arg_id);
424+
//
425+
// TODO: Look in ScopeStack with the the entity_name_id to find the
426+
// facet value.
427+
Add(binding.facet_value_inst_id, arg_id);
425428
continue;
426429
}
427430

toolchain/check/eval.cpp

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,15 +2174,70 @@ auto TryEvalTypedInst<SemIR::BindSymbolicName>(EvalContext& eval_context,
21742174
return MakeConstantResult(eval_context.context(), bind, phase);
21752175
}
21762176

2177+
template <>
2178+
auto TryEvalTypedInst<SemIR::SymbolicBindingType>(EvalContext& eval_context,
2179+
SemIR::InstId inst_id,
2180+
SemIR::Inst inst)
2181+
-> SemIR::ConstantId {
2182+
auto bind = inst.As<SemIR::SymbolicBindingType>();
2183+
2184+
Phase phase = Phase::Concrete;
2185+
2186+
// If we know which specific we're evaluating within and this is the type of
2187+
// an argument of that specific, its constant value refers to the type of the
2188+
// corresponding argument value.
2189+
const auto& bind_name = eval_context.entity_names().Get(bind.entity_name_id);
2190+
if (bind_name.bind_index().has_value()) {
2191+
if (auto value =
2192+
eval_context.GetCompileTimeBindValue(bind_name.bind_index());
2193+
value.has_value()) {
2194+
auto value_inst_id = eval_context.constant_values().GetInstId(value);
2195+
if (auto facet =
2196+
eval_context.insts().TryGetAs<SemIR::FacetValue>(value_inst_id)) {
2197+
// If the symbolic binding is replaced by a FacetValue (type + witness),
2198+
// evaluate to its type component.
2199+
return eval_context.constant_values().Get(facet->type_inst_id);
2200+
}
2201+
2202+
// Use the EntityNameId from the specific.
2203+
auto value_bind =
2204+
eval_context.insts().GetAs<SemIR::BindSymbolicName>(value_inst_id);
2205+
bind.entity_name_id =
2206+
GetConstantValue(eval_context, value_bind.entity_name_id, &phase);
2207+
inst = bind;
2208+
}
2209+
}
2210+
2211+
// Find the constant values of the fields other than the EntityNameId.
2212+
if (!ReplaceTypeWithConstantValue(eval_context, inst_id, &inst, &phase) ||
2213+
!ReplaceAllFieldsWithConstantValues(eval_context, &inst, &phase)) {
2214+
return SemIR::ConstantId::NotConstant;
2215+
}
2216+
// Propagate error phase after getting the constant value for all fields.
2217+
if (phase == Phase::UnknownDueToError) {
2218+
return SemIR::ErrorInst::ConstantId;
2219+
}
2220+
2221+
// Get the updated constant field values.
2222+
bind = inst.As<SemIR::SymbolicBindingType>();
2223+
2224+
// TODO: Look in ScopeStack with the the entity_name_id to find the facet
2225+
// value and get its constant value in the current specific context. The
2226+
// facet_value_inst_id will go away.
2227+
if (auto facet_value = eval_context.insts().TryGetAs<SemIR::FacetValue>(
2228+
bind.facet_value_inst_id)) {
2229+
return eval_context.constant_values().Get(facet_value->type_inst_id);
2230+
}
2231+
2232+
return MakeConstantResult(eval_context.context(), bind, phase);
2233+
}
2234+
21772235
// Returns whether `const_id` is the same constant facet value as
21782236
// `facet_value_inst_id`.
21792237
static auto IsSameFacetValue(Context& context, SemIR::ConstantId const_id,
21802238
SemIR::InstId facet_value_inst_id) -> bool {
2181-
if (auto facet_access_type = context.insts().TryGetAs<SemIR::FacetAccessType>(
2182-
context.constant_values().GetInstId(const_id))) {
2183-
const_id =
2184-
context.constant_values().Get(facet_access_type->facet_value_inst_id);
2185-
}
2239+
const_id = GetCanonicalizedFacetOrTypeValue(context, const_id,
2240+
/*preserve_facet_value=*/true);
21862241
return const_id == context.constant_values().Get(facet_value_inst_id);
21872242
}
21882243

toolchain/check/eval_inst.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,20 @@ 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 replace NewSamePhase with
210+
// NewAnyPhase.
211+
.facet_value_inst_id = inst.facet_value_inst_id});
212+
}
213+
214+
// Other instructions (e.g. ImplWitnessAccess) of type FacetType can appear
215+
// here, in which case the constant inst is a FacetAccessType until those
216+
// instructions resolve to one of the above.
203217
return ConstantEvalResult::NewSamePhase(inst);
204218
}
205219

toolchain/check/impl_lookup.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -299,20 +299,6 @@ static auto GetWitnessIdForImpl(Context& context, SemIR::LocId loc_id,
299299
}
300300
}
301301

302-
// Unwraps a FacetAccessType to move from a value of type `TypeType` to a facet
303-
// value of type `FacetType` if possible.
304-
//
305-
// Generally `GetCanonicalizedFacetOrTypeValue()` is what you want to call
306-
// instead, as this only does part of that operation, potentially returning a
307-
// non-canonical facet value.
308-
static auto UnwrapFacetAccessType(Context& context, SemIR::InstId inst_id)
309-
-> SemIR::InstId {
310-
if (auto access = context.insts().TryGetAs<SemIR::FacetAccessType>(inst_id)) {
311-
return access->facet_value_inst_id;
312-
}
313-
return inst_id;
314-
}
315-
316302
// Finds a lookup result from `query_self_inst_id` if it is a facet value that
317303
// names the query interface in its facet type. Note that `query_self_inst_id`
318304
// is allowed to be a non-canonical facet value in order to find a concrete
@@ -323,7 +309,8 @@ static auto LookupImplWitnessInSelfFacetValue(
323309
// Unwrap FacetAccessType without getting the canonical facet value from the
324310
// self value, as we want to preserve the non-canonical `FacetValue`
325311
// instruction which can contain the concrete witness.
326-
query_self_inst_id = UnwrapFacetAccessType(context, query_self_inst_id);
312+
query_self_inst_id = GetCanonicalizedFacetOrTypeValue(
313+
context, query_self_inst_id, /*preserve_facet_value=*/true);
327314

328315
auto facet_type = context.types().TryGetAs<SemIR::FacetType>(
329316
context.insts().Get(query_self_inst_id).type_id());

toolchain/check/import_ref.cpp

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,8 @@ static auto GetLocalConstantId(ImportRefResolver& resolver,
748748
}
749749

750750
// Translates a NameId from the import IR to a local NameId.
751+
//
752+
// No new work is generated by calling this function.
751753
static auto GetLocalNameId(ImportContext& context, SemIR::NameId import_name_id)
752754
-> SemIR::NameId {
753755
if (auto ident_id = import_name_id.AsIdentifierId(); ident_id.has_value()) {
@@ -757,6 +759,23 @@ static auto GetLocalNameId(ImportContext& context, SemIR::NameId import_name_id)
757759
return import_name_id;
758760
}
759761

762+
// Returns the id for a local EntityName from an imported one, preserving only
763+
// the `NameId`, the `CompileTimeBindIndex`, and whether it is a template. Other
764+
// parts of the EntityName are not kept and are not considered part of the
765+
// canonical EntityName (even if they are present there).
766+
//
767+
// No new work is generated by calling this function.
768+
static auto GetLocalEntityNameId(ImportRefResolver& resolver,
769+
SemIR::EntityNameId import_entity_name_id)
770+
-> SemIR::EntityNameId {
771+
const auto& import_entity_name =
772+
resolver.import_entity_names().Get(import_entity_name_id);
773+
auto name_id = GetLocalNameId(resolver, import_entity_name.name_id);
774+
return resolver.local_entity_names().AddSymbolicBindingName(
775+
name_id, SemIR::NameScopeId::None, import_entity_name.bind_index(),
776+
import_entity_name.is_template);
777+
}
778+
760779
// Gets the local constant values corresponding to an imported inst block.
761780
static auto GetLocalInstBlockContents(ImportRefResolver& resolver,
762781
SemIR::InstBlockId import_block_id)
@@ -1497,12 +1516,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
14971516
return ResolveResult::Retry();
14981517
}
14991518

1500-
const auto& import_entity_name =
1501-
resolver.import_entity_names().Get(inst.entity_name_id);
1502-
auto name_id = GetLocalNameId(resolver, import_entity_name.name_id);
1503-
auto entity_name_id = resolver.local_entity_names().AddSymbolicBindingName(
1504-
name_id, SemIR::NameScopeId::None, import_entity_name.bind_index(),
1505-
import_entity_name.is_template);
1519+
auto entity_name_id = GetLocalEntityNameId(resolver, inst.entity_name_id);
15061520
return ResolveAsDeduplicated<SemIR::BindSymbolicName>(
15071521
resolver,
15081522
{.type_id =
@@ -2942,6 +2956,22 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver,
29422956
GetLocalCanonicalInstBlockId(resolver, inst.elements_id, elems)});
29432957
}
29442958

2959+
static auto TryResolveTypedInst(ImportRefResolver& resolver,
2960+
SemIR::SymbolicBindingType inst)
2961+
-> ResolveResult {
2962+
auto facet_value_inst_id =
2963+
GetLocalConstantInstId(resolver, inst.facet_value_inst_id);
2964+
if (resolver.HasNewWork()) {
2965+
return ResolveResult::Retry();
2966+
}
2967+
2968+
auto entity_name_id = GetLocalEntityNameId(resolver, inst.entity_name_id);
2969+
return ResolveAsDeduplicated<SemIR::SymbolicBindingType>(
2970+
resolver, {.type_id = SemIR::TypeType::TypeId,
2971+
.entity_name_id = entity_name_id,
2972+
.facet_value_inst_id = facet_value_inst_id});
2973+
}
2974+
29452975
static auto TryResolveTypedInst(ImportRefResolver& resolver,
29462976
SemIR::TupleAccess inst) -> ResolveResult {
29472977
auto type_id = GetLocalConstantId(resolver, inst.type_id);
@@ -3290,6 +3320,9 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver,
32903320
case CARBON_KIND(SemIR::SymbolicBindingPattern inst): {
32913321
return TryResolveTypedInst(resolver, inst, constant_inst_id);
32923322
}
3323+
case CARBON_KIND(SemIR::SymbolicBindingType inst): {
3324+
return TryResolveTypedInst(resolver, inst);
3325+
}
32933326
case CARBON_KIND(SemIR::TupleAccess inst): {
32943327
return TryResolveTypedInst(resolver, inst);
32953328
}

toolchain/check/member_access.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,15 @@ static auto LookupMemberNameInScope(Context& context, SemIR::LocId loc_id,
321321
context.types().TryGetAs<SemIR::AssociatedEntityType>(type_id)) {
322322
if (lookup_in_type_of_base) {
323323
SemIR::TypeId base_type_id = context.insts().Get(base_id).type_id();
324-
if (auto facet_access_type =
325-
context.types().TryGetAs<SemIR::FacetAccessType>(base_type_id)) {
324+
if (auto binding_type =
325+
context.types().TryGetAs<SemIR::SymbolicBindingType>(
326+
base_type_id)) {
326327
// Move from the type of a symbolic facet value up in typish-ness to its
327328
// FacetType to find the type to work with.
328-
base_id = facet_access_type->facet_value_inst_id;
329+
//
330+
// TODO: Look in ScopeStack with the the entity_name_id to find the
331+
// facet value.
332+
base_id = binding_type->facet_value_inst_id;
329333
base_type_id = context.insts().Get(base_id).type_id();
330334
}
331335

@@ -612,9 +616,9 @@ static auto GetAssociatedValueImpl(Context& context, SemIR::LocId loc_id,
612616
}
613617
// That facet value has both the self type we need below and the witness
614618
// we are going to use to look up the value of the associated member.
615-
auto self_type_const_id = TryEvalInst(
616-
context, SemIR::FacetAccessType{.type_id = SemIR::TypeType::TypeId,
617-
.facet_value_inst_id = facet_inst_id});
619+
auto self_type_const_id = TryEvalInst<SemIR::FacetAccessType>(
620+
context, {.type_id = SemIR::TypeType::TypeId,
621+
.facet_value_inst_id = facet_inst_id});
618622
// TODO: We should be able to lookup constant associated values from runtime
619623
// facet values by using their FacetType only, but we assume constant values
620624
// for impl lookup at the moment.
@@ -625,6 +629,11 @@ static auto GetAssociatedValueImpl(Context& context, SemIR::LocId loc_id,
625629
auto self_type_id =
626630
context.types().GetTypeIdForTypeConstantId(self_type_const_id);
627631

632+
// TODO: If `ConvertToValueOfType` returned a `FacetValue`, we already got a
633+
// witness for this interface there. We don't need to do both a
634+
// ConvertToValueOfType and LookupImplWitness, that is redundant. Since we
635+
// want to do LookupImplWitness unconditionally (eg. if `base_id` has exactly
636+
// the right FacetType already), can we drop the ConvertToValueOfType step?
628637
auto lookup_result = LookupImplWitness(
629638
context, loc_id, context.constant_values().Get(facet_inst_id),
630639
EvalOrAddInst(context, loc_id,

toolchain/check/name_lookup.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "toolchain/diagnostics/format_providers.h"
1616
#include "toolchain/sem_ir/generic.h"
1717
#include "toolchain/sem_ir/name_scope.h"
18+
#include "toolchain/sem_ir/typed_insts.h"
1819

1920
namespace Carbon::Check {
2021

@@ -273,12 +274,15 @@ auto AppendLookupScopesForConstant(Context& context, SemIR::LocId loc_id,
273274
auto base_id = context.constant_values().GetInstId(base_const_id);
274275
auto base = context.insts().Get(base_id);
275276

276-
if (auto base_as_facet_access_type = base.TryAs<SemIR::FacetAccessType>()) {
277+
if (auto base_as_binding_type = base.TryAs<SemIR::SymbolicBindingType>()) {
277278
// Move from the symbolic facet value up in typish-ness to its FacetType to
278279
// find a lookup scope.
280+
//
281+
// TODO: Look in ScopeStack with the the entity_name_id to find the
282+
// facet value.
279283
auto facet_type_type_id =
280284
context.insts()
281-
.Get(base_as_facet_access_type->facet_value_inst_id)
285+
.Get(base_as_binding_type->facet_value_inst_id)
282286
.type_id();
283287
base_const_id = context.types().GetConstantId(facet_type_type_id);
284288
base_id = context.constant_values().GetInstId(base_const_id);

0 commit comments

Comments
 (0)