If a stored property has a didSet/willSet, we currently synthesize
the getter and the setter inside the parser. I want to get rid of
the parser's code path for doing that and consolidate all accessor
synthesis here in Sema.
Note that the parser did not synthesize a modify. This is now more
explicit in the code.
Also, we have to relax an assertion since addMemberToContextIfNeeded()
now gets called on declarations in local contexts.
Allow both explicit initialization and initial values to work together, e.g.,
```
@Clamping(min: 0, max: 255) var red: Int = 127
```
gets initialized as
```
Clamping(initialValue: 127, min: 0, max: 255)
```
When multiple property wrapper attributes are provided on a declaration,
compose them outside-in to form a composite property wrapper type. For
example,
@A @B @C var foo = 17
will produce
var $foo = A(initialValue: B(initialValue: C(initialValue: 17)))
and foo's getter/setter will access "foo.value.value.value".
By calling isFinal() first in makeFinal(), we were triggering
computation of IsFinalRequest and caching a value of 'false'.
With lazy properties, we did direct storage access, and no
accessors were synthesized anyway, but add a test for that.
With property wrappers this now means the backing storage
property is final, as intended (?).
When the backing storage of a wrapped property is default-initialized via the
property wrapper type's init(), don't count that as a direct initialization
of the backing storage for the purposes of constructing the memberwise
initializer. Instead, treat this case the same as if there were no initializer,
keying the form of the memberwise initializer off the presence of
init(initialValue:).
Various optimizations / shortcuts in type checking property wrappers meant
that we weren't consistently verifying that a wrapped property type is
identical to the type of the 'value' property of the wrapper. Do so.
Fixes SR-10899 / rdar://problem/51588022.
Previously, we'd clone the superclass's initializer and update its
interface type, but we didn't reset the TypeLoc. This meant the
synthesized overridden initializer's parameter typeLocs would still be in
the parent decl context, which caused the ASTPrinter to print the
unsubstituted type.
rdar://50914733
Similarly to trivial accessors, the body of a synthesized
designated initializer override is simple enough that we can
build it directly without involving the constraint solver.
This includes all synthesized accessors except for lazy getters
and observer setters.
Building checked AST has certain advantages:
- It is faster, avoiding the need to create and solve ConstraintSystems
or performing various diagnostic and semantic walks over the AST.
- It allows us to postpone delayed body synthesis until needed in SILGen,
instead of having to walk a list of "external declarations" in Sema.
It also unblocks lazier conformance checking. Now that SILGen can
trigger conformance checking on its own, we need to be able to
synthesize bodies of accessors that witness protocol requirements.
This will allow us to eventually remove Sema's "used conformances"
list.
Note that for now, various utility functions in CodeSynthesis.cpp are
used for both checked and unchecked function bodies, so they take a
'typeChecked' boolean parameter that complicates some logic more than
necessary. Once the remaining body synthesizers are refactored to
build type-checked AST, the 'typeChecked' flag will go away.
When a property delegate type has a default initializer, use that to
implicitly initialize properties that use that delegate and do not have
their own initializers. For example, this would allow (e.g.), delegate
types like the DelayedImmutable and DelayedMutable examples to drop
the explicit initialization, e.g.,
```
@DelayedMutable var foo: Int
```
would be implicitly initialized via
```
$foo = DelayedMutable()
```
This is a simplistic implementation that does not yet propertly handle
definite initialization.
Fixes rdar://problem/50266039.
When a property with an attached delegate has less-than-internal visibility
and is initialized, don’t put it into the memberwise initializer because
doing so lowers the access level of the memberwise initializer, making it
fairly useless.
Longer term, it probably makes sense to have several memberwise initializers
at different access levels, so adding an initialized `private var` make
the memberwise initializer useless throughout the rest of the module.
Addresses rdar://problem/50266245.
The determination of whether a property is memberwise-initialized is
somewhat confused for properties that have synthesized backing properties.
Some clients (Sema/Index) want to see the declared properties, while others
(SILGen) want to see the backing stored properties. Add a flag to
`VarDecl::isMemberwiseInitialized()` to capture this variation.
This utility was defined in Sema, used in Sema and Index, declared in
two headers, and semi- copy-pasted into SILGen. Pull it into
VarDecl::isMemberwiseInitialized() and use it consistently.
When the property delegate type overrides the delegate value by providing
a delegateValue property, name the backing storage $$foo and make it private.
The initialization of an instance property that has an attached
property delegate involves the initial value written on the property
declaration, the implicit memberwise initializer, and the default
arguments to the implicit memberwise initializer. Implement SILGen
support for each of these cases.
There is a small semantic change to the creation of the implicit
memberwise initializer due to SE-0242 (default arguments for the
memberwise initializer). Specifically, the memberwise initializer will
use the original property type for the parameter to memberwise
initializer when either of the following is true:
- The corresponding property has an initial value specified with the
`=` syntax, e.g., `@Lazy var i = 17`, or
- The corresponding property has no initial value, but the property
delegate type has an `init(initialValue:)`.
The specific case that changed is when a property has an initial value
specified as a direct initialization of the delegate *and* the
property delegate type has an `init(initialValue:)`, e.g.,
```swift
struct X {
@Lazy(closure: { ... })
var i: Int
}
```
Previously, this would have synthesized an initializer:
```swift
init(i: Int = ???) { ... }
```
However, there is no way for the initialization specified within the
declaration of i to be expressed via the default argument. Now, it
synthesizes an initializer:
```swift
init(i: Lazy<Int> = Lazy(closure: { ... }))
```
When a property has an attached property delegate, a backing storage
property of the corresponding delegate type will be
synthesized. Perform this synthesis, and also synthesize the
getter/setter for the original property to reference the backing
storage property.