-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Support ref tags on arguments to ref params
#6312
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
Changes from 7 commits
5a4cc85
70283da
4683a9a
24e0545
84b206b
f6a0c7d
07e7ced
6950f9d
6edeb3b
d956e90
ea93e03
b429e36
e07d557
f9ede4f
25b6926
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -189,6 +189,13 @@ class Context { | |
| return var_storage_map_; | ||
| } | ||
|
|
||
| enum class RefTag { Present, NotRequired }; | ||
|
|
||
| auto ref_tags() -> Map<SemIR::InstId, RefTag>& { return ref_tags_; } | ||
| auto ref_tags() const -> const Map<SemIR::InstId, RefTag>& { | ||
| return ref_tags_; | ||
| } | ||
|
|
||
| // During Choice typechecking, each alternative turns into a name binding on | ||
| // the Choice type, but this can't be done until the full Choice type is | ||
| // known. This represents each binding to be done at the end of checking the | ||
|
|
@@ -430,6 +437,13 @@ class Context { | |
| // processing the enclosing full-pattern. | ||
| Map<SemIR::InstId, SemIR::InstId> var_storage_map_; | ||
|
|
||
| // Insts in this map are syntactically permitted to be bound to a reference | ||
| // parameter, either because they've been explicitly tagged with `ref` in the | ||
| // source code, or because they appear in a position where that tag is not | ||
| // required, such as an operator operand (the RefTag value indicates which | ||
| // of those is the case). | ||
| Map<SemIR::InstId, RefTag> ref_tags_; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (@zygoloid I'm replying to your top-level comment here, for threading purposes)
We'd have to plumb it through a lot of layers, but yes, that's an option. The main problem I see is that an operator usage and an explicit call to the corresponding interface method will emit identical SemIR, but the former cannot use a So if I think this just brings us back to the question of whether we're modeling a syntactic property ("the user wrote a |
||
|
|
||
| // Each alternative in a Choice gets an entry here, they are stored in | ||
| // declaration order. The vector is consumed and emptied at the end of the | ||
| // Choice definition. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -730,6 +730,7 @@ static auto IsValidExprCategoryForConversionTarget( | |
| case ConversionTarget::Value: | ||
| return category == SemIR::ExprCategory::Value; | ||
| case ConversionTarget::ValueOrRef: | ||
| case ConversionTarget::RefParam: | ||
|
||
| case ConversionTarget::Discarded: | ||
| return category == SemIR::ExprCategory::Value || | ||
| category == SemIR::ExprCategory::DurableRef || | ||
|
|
@@ -1390,6 +1391,25 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id, | |
| return SemIR::ErrorInst::InstId; | ||
| } | ||
|
|
||
| bool has_ref_tag = false; | ||
| { | ||
geoffromer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (auto lookup_result = context.ref_tags().Lookup(expr_id)) { | ||
| has_ref_tag = true; | ||
| if (lookup_result.value() == Context::RefTag::Present && | ||
| target.kind != ConversionTarget::RefParam) { | ||
| CARBON_DIAGNOSTIC(RefTagNoRefParam, Error, | ||
| "`ref` tag is not an argument to a `ref` parameter"); | ||
| context.emitter().Emit(expr_id, RefTagNoRefParam); | ||
| } | ||
| } else { | ||
| if (target.kind == ConversionTarget::RefParam) { | ||
| CARBON_DIAGNOSTIC(RefParamNoRefTag, Error, | ||
| "argument to `ref` parameter not marked with `ref`"); | ||
| context.emitter().Emit(expr_id, RefParamNoRefTag); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // We can only perform initialization for complete, non-abstract types. Note | ||
| // that `RequireConcreteType` returns true for facet types, since their | ||
| // representation is fixed. This allows us to support using the `Self` of an | ||
|
|
@@ -1520,6 +1540,9 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id, | |
| {.type_id = target.type_id, | ||
| .original_id = orig_expr_id, | ||
| .result_id = expr_id}); | ||
| if (has_ref_tag) { | ||
| context.ref_tags().Insert(expr_id, Context::RefTag::NotRequired); | ||
| } | ||
| } | ||
|
|
||
| // For `as`, don't perform any value category conversions. In particular, an | ||
|
|
@@ -1574,7 +1597,8 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id, | |
| // If a reference expression is an acceptable result, we're done. | ||
| if (target.kind == ConversionTarget::ValueOrRef || | ||
| target.kind == ConversionTarget::Discarded || | ||
| target.kind == ConversionTarget::CppThunkRef) { | ||
| target.kind == ConversionTarget::CppThunkRef || | ||
| target.kind == ConversionTarget::RefParam) { | ||
zygoloid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| break; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.