@@ -24,9 +24,11 @@ namespace Carbon::Check {
24
24
25
25
auto FacetTypeFromInterface (Context& context, SemIR::InterfaceId interface_id,
26
26
SemIR::SpecificId specific_id) -> SemIR::FacetType {
27
- SemIR::FacetTypeId facet_type_id = context. facet_types (). Add (
27
+ auto info =
28
28
SemIR::FacetTypeInfo{.extend_constraints = {{interface_id, specific_id}},
29
- .other_requirements = false });
29
+ .other_requirements = false };
30
+ info.Canonicalize ();
31
+ SemIR::FacetTypeId facet_type_id = context.facet_types ().Add (info);
30
32
return {.type_id = SemIR::TypeType::TypeId, .facet_type_id = facet_type_id};
31
33
}
32
34
@@ -58,6 +60,16 @@ static auto IncompleteFacetTypeDiagnosticBuilder(
58
60
}
59
61
}
60
62
63
+ auto GetImplWitnessAccessWithoutSubstitution (Context& context,
64
+ SemIR::InstId inst_id)
65
+ -> SemIR::InstId {
66
+ if (auto inst = context.insts ().TryGetAs <SemIR::ImplWitnessAccessSubstituted>(
67
+ inst_id)) {
68
+ return inst->impl_witness_access_id ;
69
+ }
70
+ return inst_id;
71
+ }
72
+
61
73
auto InitialFacetTypeImplWitness (
62
74
Context& context, SemIR::LocId witness_loc_id,
63
75
SemIR::TypeInstId facet_type_inst_id, SemIR::TypeInstId self_type_inst_id,
@@ -123,8 +135,8 @@ auto InitialFacetTypeImplWitness(
123
135
}
124
136
125
137
for (auto rewrite : facet_type_info.rewrite_constraints ) {
126
- auto access =
127
- context. insts (). GetAs <SemIR::ImplWitnessAccess>( rewrite.lhs_id );
138
+ auto access = context. insts (). GetAs <SemIR::ImplWitnessAccess>(
139
+ GetImplWitnessAccessWithoutSubstitution (context, rewrite.lhs_id ) );
128
140
if (!WitnessQueryMatchesInterface (context, access.witness_id ,
129
141
interface_to_witness)) {
130
142
continue ;
@@ -252,6 +264,9 @@ auto AllocateFacetTypeImplWitness(Context& context,
252
264
}
253
265
254
266
namespace {
267
+ // TODO: This class should go away, and we should just use the constant value of
268
+ // the ImplWitnessAccess as a key in AccessRewriteValues, but that requires
269
+ // changing its API to work with InstId instead of ImplWitnessAccess.
255
270
struct FacetTypeConstraintValue {
256
271
SemIR::EntityNameId entity_name_id;
257
272
SemIR::ElementIndex access_index;
@@ -280,32 +295,6 @@ static auto GetFacetTypeConstraintValue(Context& context,
280
295
return std::nullopt;
281
296
}
282
297
283
- // Returns true if two values in a rewrite constraint are equivalent. Two
284
- // `ImplWitnessAccess` instructions that refer to the same associated constant
285
- // through the same facet value are treated as equivalent.
286
- static auto CompareFacetTypeConstraintValues (Context& context,
287
- SemIR::InstId lhs_id,
288
- SemIR::InstId rhs_id) -> bool {
289
- if (lhs_id == rhs_id) {
290
- return true ;
291
- }
292
-
293
- auto lhs_access = context.insts ().TryGetAs <SemIR::ImplWitnessAccess>(lhs_id);
294
- auto rhs_access = context.insts ().TryGetAs <SemIR::ImplWitnessAccess>(rhs_id);
295
- if (lhs_access && rhs_access) {
296
- auto lhs_access_value = GetFacetTypeConstraintValue (context, *lhs_access);
297
- auto rhs_access_value = GetFacetTypeConstraintValue (context, *rhs_access);
298
- // We do *not* want to get the evaluated result of `ImplWitnessAccess` here,
299
- // we want to keep them as a reference to an associated constant for the
300
- // resolution phase.
301
- return lhs_access_value && rhs_access_value &&
302
- *lhs_access_value == *rhs_access_value;
303
- }
304
-
305
- return context.constant_values ().GetConstantInstId (lhs_id) ==
306
- context.constant_values ().GetConstantInstId (rhs_id);
307
- }
308
-
309
298
// A mapping of each associated constant (represented as `ImplWitnessAccess`) to
310
299
// its value (represented as an `InstId`). Used to track rewrite constraints,
311
300
// with the LHS mapping to the resolved value of the RHS.
@@ -349,9 +338,10 @@ class AccessRewriteValues {
349
338
350
339
auto SetFullyRewritten (Context& context, Value& value, SemIR::InstId inst_id)
351
340
-> void {
352
- CARBON_CHECK (
353
- value.state == BeingRewritten ||
354
- CompareFacetTypeConstraintValues (context, value.inst_id , inst_id));
341
+ if (value.state == FullyRewritten) {
342
+ CARBON_CHECK (context.constant_values ().Get (value.inst_id ) ==
343
+ context.constant_values ().Get (inst_id));
344
+ }
355
345
value = {FullyRewritten, inst_id};
356
346
}
357
347
@@ -459,13 +449,22 @@ class SubstImplWitnessAccessCallbacks : public SubstInstCallbacks {
459
449
// There's no ImplWitnessAccess that we care about inside this
460
450
// instruction.
461
451
return SubstResult::FullySubstituted;
462
- } else {
463
- // SubstOperands will result in a Rebuild or ReuseUnchanged callback, so
464
- // push the non-ImplWitnessAccess to get proper bracketing, allowing us
465
- // to pop it in the paired callback.
452
+ }
453
+ if (auto subst =
454
+ context ().insts ().TryGetAs <SemIR::ImplWitnessAccessSubstituted>(
455
+ rhs_inst_id)) {
456
+ // The reference to an associated constant was eagerly replaced with the
457
+ // value of an earlier rewrite constraint, but may need further
458
+ // substitution if it contains an `ImplWitnessAccess`.
459
+ rhs_inst_id = subst->value_id ;
466
460
substs_in_progress_.push_back (rhs_inst_id);
467
- return SubstResult::SubstOperands ;
461
+ return SubstResult::SubstAgain ;
468
462
}
463
+ // SubstOperands will result in a Rebuild or ReuseUnchanged callback, so
464
+ // push the non-ImplWitnessAccess to get proper bracketing, allowing us
465
+ // to pop it in the paired callback.
466
+ substs_in_progress_.push_back (rhs_inst_id);
467
+ return SubstResult::SubstOperands;
469
468
}
470
469
471
470
// If the access is going through a nested `ImplWitnessAccess`, that
@@ -581,8 +580,8 @@ auto ResolveFacetTypeRewriteConstraints(
581
580
AccessRewriteValues rewrite_values;
582
581
583
582
for (auto & constraint : rewrites) {
584
- auto lhs_access =
585
- context. insts (). TryGetAs <SemIR::ImplWitnessAccess>( constraint.lhs_id );
583
+ auto lhs_access = context. insts (). TryGetAs <SemIR::ImplWitnessAccess>(
584
+ GetImplWitnessAccessWithoutSubstitution (context, constraint.lhs_id ) );
586
585
if (!lhs_access) {
587
586
continue ;
588
587
}
@@ -591,8 +590,8 @@ auto ResolveFacetTypeRewriteConstraints(
591
590
}
592
591
593
592
for (auto & constraint : rewrites) {
594
- auto lhs_access =
595
- context. insts (). TryGetAs <SemIR::ImplWitnessAccess>( constraint.lhs_id );
593
+ auto lhs_access = context. insts (). TryGetAs <SemIR::ImplWitnessAccess>(
594
+ GetImplWitnessAccessWithoutSubstitution (context, constraint.lhs_id ) );
596
595
if (!lhs_access) {
597
596
continue ;
598
597
}
@@ -610,33 +609,40 @@ auto ResolveFacetTypeRewriteConstraints(
610
609
return false ;
611
610
}
612
611
613
- if (lhs_rewrite_value->state == AccessRewriteValues::FullyRewritten &&
614
- !CompareFacetTypeConstraintValues (context, lhs_rewrite_value->inst_id ,
615
- rhs_subst_inst_id)) {
616
- if (lhs_rewrite_value->inst_id != SemIR::ErrorInst::InstId) {
617
- CARBON_DIAGNOSTIC (AssociatedConstantWithDifferentValues, Error,
618
- " associated constant {0} given two different "
619
- " values {1} and {2}" ,
620
- InstIdAsConstant, InstIdAsConstant, InstIdAsConstant);
621
- // Use inst id ordering as a simple proxy for source ordering, to
622
- // try to name the values in the same order they appear in the facet
623
- // type.
624
- auto source_order1 =
625
- lhs_rewrite_value->inst_id .index < rhs_subst_inst_id.index
626
- ? lhs_rewrite_value->inst_id
627
- : rhs_subst_inst_id;
628
- auto source_order2 =
629
- lhs_rewrite_value->inst_id .index >= rhs_subst_inst_id.index
630
- ? lhs_rewrite_value->inst_id
631
- : rhs_subst_inst_id;
632
- // TODO: It would be nice to note the places where the values are
633
- // assigned but rewrite constraint instructions are from canonical
634
- // constant values, and have no locations. We'd need to store a
635
- // location along with them in the rewrite constraints.
636
- context.emitter ().Emit (loc_id, AssociatedConstantWithDifferentValues,
637
- constraint.lhs_id , source_order1, source_order2);
612
+ if (lhs_rewrite_value->state == AccessRewriteValues::FullyRewritten) {
613
+ auto rhs_existing_const_id =
614
+ context.constant_values ().Get (lhs_rewrite_value->inst_id );
615
+ auto rhs_subst_const_id =
616
+ context.constant_values ().Get (rhs_subst_inst_id);
617
+ if (rhs_subst_const_id != rhs_existing_const_id) {
618
+ if (rhs_existing_const_id != SemIR::ErrorInst::ConstantId) {
619
+ CARBON_DIAGNOSTIC (AssociatedConstantWithDifferentValues, Error,
620
+ " associated constant {0} given two different "
621
+ " values {1} and {2}" ,
622
+ InstIdAsConstant, InstIdAsConstant,
623
+ InstIdAsConstant);
624
+ // Use inst id ordering as a simple proxy for source ordering, to
625
+ // try to name the values in the same order they appear in the facet
626
+ // type.
627
+ auto source_order1 =
628
+ lhs_rewrite_value->inst_id .index < rhs_subst_inst_id.index
629
+ ? lhs_rewrite_value->inst_id
630
+ : rhs_subst_inst_id;
631
+ auto source_order2 =
632
+ lhs_rewrite_value->inst_id .index >= rhs_subst_inst_id.index
633
+ ? lhs_rewrite_value->inst_id
634
+ : rhs_subst_inst_id;
635
+ // TODO: It would be nice to note the places where the values are
636
+ // assigned but rewrite constraint instructions are from canonical
637
+ // constant values, and have no locations. We'd need to store a
638
+ // location along with them in the rewrite constraints.
639
+ context.emitter ().Emit (loc_id, AssociatedConstantWithDifferentValues,
640
+ GetImplWitnessAccessWithoutSubstitution (
641
+ context, constraint.lhs_id ),
642
+ source_order1, source_order2);
643
+ }
644
+ return false ;
638
645
}
639
- return false ;
640
646
}
641
647
642
648
rewrite_values.SetFullyRewritten (context, *lhs_rewrite_value,
@@ -652,8 +658,8 @@ auto ResolveFacetTypeRewriteConstraints(
652
658
for (size_t i = 0 ; i < keep_size;) {
653
659
auto & constraint = rewrites[i];
654
660
655
- auto lhs_access =
656
- context. insts (). TryGetAs <SemIR::ImplWitnessAccess>( constraint.lhs_id );
661
+ auto lhs_access = context. insts (). TryGetAs <SemIR::ImplWitnessAccess>(
662
+ GetImplWitnessAccessWithoutSubstitution (context, constraint.lhs_id ) );
657
663
if (!lhs_access) {
658
664
++i;
659
665
continue ;
0 commit comments