-
Notifications
You must be signed in to change notification settings - Fork 10.6k
[Property Wrappers] Support local property wrappers #34109
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
Conversation
has a custom attribute.
|
@swift-ci please test source compatibility |
…pper and projected value references
…nside an initializer, and for wrapped local variables.
00820e2 to
0842b42
Compare
|
@swift-ci please test source compatibility |
| body.push_back(returnStmt); | ||
| } | ||
|
|
||
| // Don't mark local accessors as type-checked - captures still need to be computed. |
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 seems a bit fragile because you're assuming that type checking is idempotent on already-checked AST. Would it be better to insert an explicit call to computeCaptures() inside TypeCheckDeclPrimary.cpp?
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.
(And yeah, computeCaptures() should be a request, since there are a few places we have to trigger it manually for synthesized code...)
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 tried to change this, but I discovered that "re" type checking the accessor is doing more necessary things than just computing captures.
For example, if the wrappedValue getter of a local property wrapper is mutating, buildStorageReference will generate something like for the local getter:
(member_ref_expr implicit type='String' decl=test.(file).Lazy.wrappedValue@test.swift:10:7 [with (substitution_map generic_signature=<Value> (substitution Value -> String))]
(declref_expr implicit type='Lazy<String>' decl=test.(file).testLocalLazy()._value@test.swift:28:13 direct_to_storage function_ref=unapplied))
But it really needs to look like this:
(load_expr implicit type='String'
(member_ref_expr implicit type='@lvalue String' decl=test.(file).Lazy.wrappedValue@test.swift:10:7 [with (substitution_map generic_signature=<Value> (substitution Value -> String))]
(inout_expr implicit type='inout Lazy<String>'
(declref_expr implicit type='@lvalue Lazy<String>' decl=test.(file).testLocalLazy()._value@test.swift:28:13 direct_to_storage function_ref=unapplied))))
CSApply knows how to do this, but buildStorageReference doesn't. Is there a reason why buildStorageReference is attempting to build a type-checked expression rather than relying on the constraint system to fill in types?
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.
Addressing this in a follow-up PR is fine. I suggest investigating why the mutating getter case works for property wrappers on members of types but not with local variables. It might be an easy fix.
checks to check for type context instead of local context. This generalization will help us implement property wrappers on global variables, which should use the same approach of not adding synthesized accessors to the AST and instead lazily visit them in SILGen.
slavapestov
left a comment
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 looks good to go! I know you haven't written SILGen tests yet but I don't expect to have anything to say about those.
One more thing you might want to do in a follow-up PR is visit auxiliary decls in a couple more places, in case you weren't already planning on it:
- LookupVisibleDecls, for code completion and typo correction. Eventually LookupVisibleDecls will use ASTScope, but for now it has a duplicate implementation of unqualified lookup
- SourceEntityWalker for indexing
unqualified lookup of auxiliary decl names.
captured local variables for the assign_by_wrapper setter. Since assign_by_wrapper will always be re-written to initialization if the captured local variable is uninitialized, it's unnecessary to mark the capture as an escape. This lets us support out-of-line initialization for local property wrappers.
1d69a1e to
4bb98ba
Compare
|
|
||
| if (auto *projectionVar = getPropertyWrapperProjectionVar()) | ||
| visit(projectionVar); | ||
| } |
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.
Should this visit the lazy backing storage as well?
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.
Yes! I was going to try to implement local lazy in a followup PR
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.
(unless somebody else gets to it first 🙂 )
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.
Awesome! There’s an old WIP PR for it: #27600 which you may find helpful.
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.
Ah, that one got dropped on the floor because I ended up focusing entirely on figuring out a proper way to insert synthesized decls into a BraceStmt post-factum. They simply get visited here instead, right? I am sort of ashamed of myself for having missed the point, but that's awesome; thanks, Holly!
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.
Yes, that's right - with this approach, I've added calls to visitAuxiliaryDecls in name lookup, the decl checker, and SILGen, so the synthesized VarDecls don't need to be added to the BraceStmt, but they're still visited in the appropriate places.
|
@slavapestov could you also take a look at 4bb98ba ? I want to make sure it's not a terrible idea |
|
@swift-ci please smoke test |
|
@swift-ci please test source compatibility |
|
Doesn't look like there were actually any failures in the source compat suite |
just like we do for regular non-member properties.
there is an initial wrapped value.
|
@swift-ci please smoke test |
Support property wrappers on local variables, e.g.