-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Make FacetAccessType evaluate to SymbolicBindingType for type-of a BindSymbolicName #6115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Conversation
Based on #6113, first commit is |
c629cab
to
d1f58ab
Compare
d1f58ab
to
0d4947f
Compare
0d4947f
to
80f3f92
Compare
toolchain/check/type.cpp
Outdated
auto GetCanonicalizedFacetTypeOrType(Context& context, SemIR::InstId inst_id) | ||
-> SemIR::TypeInstId { | ||
inst_id = GetCanonicalizedFacetOrTypeValue(context, inst_id); | ||
auto type_id = context.insts().Get(inst_id).type_id(); | ||
if (context.types().Is<SemIR::TypeType>(type_id)) { | ||
return context.types().GetAsTypeInstId(inst_id); | ||
} else { | ||
CARBON_CHECK(context.types().Is<SemIR::FacetType>(type_id)); | ||
return context.types().GetInstId(type_id); | ||
} | ||
} | ||
|
||
auto MoveToFacetValue(Context& context, SemIR::InstId inst_id) | ||
-> SemIR::InstId { | ||
auto type_id = context.insts().Get(inst_id).type_id(); | ||
if (context.types().Is<SemIR::SymbolicBindingType>(type_id)) { | ||
return GetCanonicalizedFacetOrTypeValue(context, | ||
context.types().GetInstId(type_id)); | ||
} | ||
return inst_id; | ||
} | ||
|
||
auto MoveToFacetType(Context& context, SemIR::InstId inst_id) -> SemIR::InstId { | ||
auto facet_value_id = GetCanonicalizedFacetOrTypeValue(context, inst_id); | ||
auto type_id = context.insts().Get(facet_value_id).type_id(); | ||
if (context.types().Is<SemIR::FacetType>(type_id)) { | ||
return context.types().GetInstId(type_id); | ||
} | ||
return facet_value_id; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are these three operations which all want to move to the type of a facet value but in slightly different ways or with slightly different inputs. I want to figure out a way to consolidate them though...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have merged two of them, need to think more about how to shape things with the third still, but it's not fundamental to the PR.
if (auto value = | ||
eval_context.GetCompileTimeBindValue(bind_name.bind_index()); | ||
value.has_value()) { | ||
auto value_inst_id = eval_context.constant_values().GetInstId(value); | ||
if (auto facet = | ||
eval_context.insts().TryGetAs<SemIR::FacetValue>(value_inst_id)) { | ||
// If the symbolic binding is replaced by a FacetValue (type + witness), | ||
// evaluate to its type component. | ||
return eval_context.constant_values().Get(facet->type_inst_id); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be worth at least noting in a comment that this is effectively forming and evaluating a FacetAccessType
? Given the small amount of duplicated code here I guess it's probably not worth attempting to share the implementation.
// TODO: This is to be removed, at which point replace NewSamePhase with | ||
// NewAnyPhase. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NewAnyPhase
would deduce the phase from the operands, which would give Concrete
, whereas we want this to always be symbolic. I think we'd need a little more machinery here, or maybe we can just keep using NewSamePhase
?
} | ||
|
||
CARBON_CHECK(!context.insts().Is<SemIR::FacetAccessType>(inst_id)); | ||
CARBON_CHECK(!context.insts().Is<SemIR::FacetValue>(inst_id)); | ||
CARBON_CHECK(!context.insts().Is<SemIR::SymbolicBindingType>(inst_id)); | ||
|
||
return context.constant_values().GetConstantInstId(inst_id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder: can this function be rephrased as first mapping to the constant inst id, and then doing some postprocessing steps if needed? (Eg, mapping from a facet value -> its type component, or mapping from a symbolic binding type -> its facet value, depending on whether we want a facet-flavored result or a type-flavored result.) I guess it's not entirely clear to me what the contract is here, but I'd have expected that two instructions with the same constant value ought to produce the same canonicalized facet or type value, and going to the constant value first would guarantee that is the case.
auto GetTypeForFacetOrTypeValue(Context& context, SemIR::InstId inst_id) | ||
-> SemIR::TypeInstId { | ||
if (inst_id == SemIR::ErrorInst::InstId) { | ||
return SemIR::ErrorInst::TypeInstId; | ||
} | ||
|
||
inst_id = GetCanonicalizedFacetOrTypeValue(context, inst_id); | ||
auto type_id = context.insts().Get(inst_id).type_id(); | ||
if (context.types().Is<SemIR::TypeType>(type_id)) { | ||
return context.types().GetAsTypeInstId(inst_id); | ||
} else { | ||
CARBON_CHECK(context.types().Is<SemIR::FacetType>(type_id)); | ||
return context.types().GetInstId(type_id); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having trouble understanding what this function is doing. It looks like:
Given inst_id
which is a facet value, perform some canonicalization step. Then:
If the type of inst_id
is the type type
, then return inst_id
.
If the type of inst_id
is a facet type other than type
, then return the type of inst_id
.
I find that behavior surprising -- that it sometimes returns the value of inst_id
, and sometimes returns the type of inst_id
. Is that the intent here?
// If `preserve_facet_value` is false, the `FacetValue` instruction is unwrapped | ||
// to get to an underlying canonical type instruction. Otherwise, the output is | ||
// either the original instruction or a facet value instruction. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm misunderstanding something, but it looks to me like this comment doesn't match the implementation. Specifically, I think if we're given a SymbolicBindingType
, we'll always produce a facet value regardless of preserve_facet_value
, and won't produce a canoncial type instruction (which would be the SymbolicBindingType
).
Feed(Goat as (Animal & Climbs)); | ||
|
||
// CHECK:STDERR: fail_convert_multi_interface_facet_value_to_facet_value.carbon:[[@LINE+7]]:3: error: cannot convert type `Animal & Climbs` into type implementing `Eats` [ConversionFailureTypeToFacet] | ||
// CHECK:STDERR: fail_convert_multi_interface_facet_value_to_facet_value.carbon:[[@LINE+7]]:3: error: cannot convert type `Animal & Climbs` that implements `Animal & Climbs` into type implementing `Eats` [ConversionFailureFacetToFacet] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This diagnostic doesn't look right to me.
impl Goat as Animal {} | ||
|
||
fn Feed[Food:! Edible, T:! Eats(Food)](e: T, food: Food) {} | ||
// CHECK:STDERR: convert_facet_value_value_to_generic_facet_value_value.carbon:[[@LINE+7]]:64: error: cannot convert type `T` that implements `Animal` into type implementing `Eats(Food)` [ConversionFailureFacetToFacet] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this diagnostic expected? (If so I guess we need to rename this to fail_todo_
)
Co-authored-by: Richard Smith <[email protected]>
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
inI(T)
resolve to a.Self
reference in the type so that we get type equality with the binding's type:T:! I(.Self)
.