mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Only propagate .Self dependence in facet types from extended constraints (#7253)
When forming the constant value of a `where` expression, don't consider it to be `.Self`-dependent if the dependence only comes from the RHS of the `where`. More generally, ignore `.Self` dependence when evaluating a facet type unless it comes from an extended interface or named constraint. While we can get other kinds of constraint from the left-hand side of a `where`, such constraints must either come from the right-hand side of other `where` expressions or be extend constraints. This fixes a crash in lowering caused by a concrete function containing a `.Self`-symbolic `where` constant. Assisted-by: Gemini via Antigravity
This commit is contained in:
+22
-40
@@ -475,33 +475,6 @@ static auto RequireConstantValue(EvalContext& eval_context,
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
// If the given instruction is constant, returns its constant value. Otherwise,
|
||||
// produces an error diagnostic. When determining the phase of the result,
|
||||
// ignore any dependence on `.Self`.
|
||||
//
|
||||
// This is used when evaluating facet types, for which `where` expressions using
|
||||
// `.Self` should not be considered symbolic
|
||||
// - `Interface where .Self impls I and .A = bool` -> concrete
|
||||
// - `T:! type` ... `Interface where .A = T` -> symbolic, since uses `T` which
|
||||
// is symbolic and not due to `.Self`.
|
||||
static auto RequireConstantValueIgnoringPeriodSelf(EvalContext& eval_context,
|
||||
SemIR::InstId inst_id,
|
||||
Phase* phase)
|
||||
-> SemIR::InstId {
|
||||
if (!inst_id.has_value()) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
Phase constant_phase = *phase;
|
||||
auto const_inst_id =
|
||||
RequireConstantValue(eval_context, inst_id, &constant_phase);
|
||||
// Since LatestPhase(x, Phase::Concrete) == x, this is equivalent to replacing
|
||||
// Phase::PeriodSelfSymbolic with Phase::Concrete.
|
||||
if (constant_phase != Phase::PeriodSelfSymbolic) {
|
||||
*phase = LatestPhase(*phase, constant_phase);
|
||||
}
|
||||
return const_inst_id;
|
||||
}
|
||||
|
||||
// Gets a constant value for an `inst_id`, diagnosing when the input is not
|
||||
// constant, and CHECKing that it is concrete. Should only be used in contexts
|
||||
// where non-concrete constants cannot appear.
|
||||
@@ -723,6 +696,10 @@ static auto GetConstantFacetTypeInfo(EvalContext& eval_context,
|
||||
Phase* phase) -> SemIR::FacetTypeInfo {
|
||||
SemIR::FacetTypeInfo info = {};
|
||||
|
||||
// Phase of constraints whose `.Self` refers to the type constrained by this
|
||||
// facet type.
|
||||
Phase self_phase = Phase::Concrete;
|
||||
|
||||
info.extend_constraints.reserve(orig.extend_constraints.size());
|
||||
for (const auto& extend : orig.extend_constraints) {
|
||||
// TODO: Add GetConstantValue for SpecificInterface.
|
||||
@@ -737,8 +714,8 @@ static auto GetConstantFacetTypeInfo(EvalContext& eval_context,
|
||||
// TODO: Add GetConstantValue for SpecificInterface.
|
||||
info.self_impls_constraints.push_back(
|
||||
{.interface_id = self_impls.interface_id,
|
||||
.specific_id =
|
||||
GetConstantValue(eval_context, self_impls.specific_id, phase)});
|
||||
.specific_id = GetConstantValue(eval_context, self_impls.specific_id,
|
||||
&self_phase)});
|
||||
}
|
||||
|
||||
info.extend_named_constraints.reserve(orig.extend_named_constraints.size());
|
||||
@@ -756,21 +733,21 @@ static auto GetConstantFacetTypeInfo(EvalContext& eval_context,
|
||||
// TODO: Add GetConstantValue for SpecificNamedConstraint.
|
||||
info.self_impls_named_constraints.push_back(
|
||||
{.named_constraint_id = self_impls.named_constraint_id,
|
||||
.specific_id =
|
||||
GetConstantValue(eval_context, self_impls.specific_id, phase)});
|
||||
.specific_id = GetConstantValue(eval_context, self_impls.specific_id,
|
||||
&self_phase)});
|
||||
}
|
||||
|
||||
info.type_impls_interfaces.reserve(orig.type_impls_interfaces.size());
|
||||
for (const auto& type_impls : orig.type_impls_interfaces) {
|
||||
info.type_impls_interfaces.push_back(
|
||||
{.self_type =
|
||||
GetConstantValue(eval_context, type_impls.self_type, phase),
|
||||
GetConstantValue(eval_context, type_impls.self_type, &self_phase),
|
||||
// TODO: Add GetConstantValue for SpecificInterface.
|
||||
.specific_interface = {
|
||||
.interface_id = type_impls.specific_interface.interface_id,
|
||||
.specific_id = GetConstantValue(
|
||||
eval_context, type_impls.specific_interface.specific_id,
|
||||
phase)}});
|
||||
&self_phase)}});
|
||||
}
|
||||
|
||||
info.type_impls_named_constraints.reserve(
|
||||
@@ -778,14 +755,14 @@ static auto GetConstantFacetTypeInfo(EvalContext& eval_context,
|
||||
for (const auto& type_impls : orig.type_impls_named_constraints) {
|
||||
info.type_impls_named_constraints.push_back(
|
||||
{.self_type =
|
||||
GetConstantValue(eval_context, type_impls.self_type, phase),
|
||||
GetConstantValue(eval_context, type_impls.self_type, &self_phase),
|
||||
// TODO: Add GetConstantValue for SpecificNamedConstraint.
|
||||
.specific_named_constraint = {
|
||||
.named_constraint_id =
|
||||
type_impls.specific_named_constraint.named_constraint_id,
|
||||
.specific_id = GetConstantValue(
|
||||
eval_context, type_impls.specific_named_constraint.specific_id,
|
||||
phase)}});
|
||||
&self_phase)}});
|
||||
}
|
||||
|
||||
// Rewrite constraints are resolved first before replacing them with their
|
||||
@@ -806,14 +783,19 @@ static auto GetConstantFacetTypeInfo(EvalContext& eval_context,
|
||||
}
|
||||
|
||||
for (auto& rewrite : info.rewrite_constraints) {
|
||||
// `where` requirements using `.Self` should not be considered symbolic.
|
||||
auto lhs_id = RequireConstantValueIgnoringPeriodSelf(eval_context,
|
||||
rewrite.lhs_id, phase);
|
||||
auto rhs_id = RequireConstantValueIgnoringPeriodSelf(eval_context,
|
||||
rewrite.rhs_id, phase);
|
||||
auto lhs_id =
|
||||
RequireConstantValue(eval_context, rewrite.lhs_id, &self_phase);
|
||||
auto rhs_id =
|
||||
RequireConstantValue(eval_context, rewrite.rhs_id, &self_phase);
|
||||
rewrite = {.lhs_id = lhs_id, .rhs_id = rhs_id};
|
||||
}
|
||||
|
||||
// Update phase, ignoring `.Self` dependence from constraints whose `.Self` is
|
||||
// scoped to this facet type.
|
||||
if (self_phase > Phase::PeriodSelfSymbolic) {
|
||||
*phase = LatestPhase(*phase, self_phase);
|
||||
}
|
||||
|
||||
// TODO: Process other requirements.
|
||||
info.other_requirements = orig.other_requirements;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user