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".
ManagedValue::{forward,assign}Into both have the signature SILGenFunction &,
SILLocation, SILValue. For some reason copyInto has SILLocation and SILValue
swapped. This commit standardizes copyInto to match the others.
OpaqueValueState used to store a SILValue, so back then the IsConsumable flag
was meaningful. But now we can just check if the ManagedValue has a cleanup
or not.
Also, we were passing around an opened ArchetypeType for no good reason.
Instead of passing in a DeclContext, which we don't have when emitting a keypath
accessor, pass in a ModuleDecl and ResilienceExpansion.
Keypaths now work well enough in inlinable contexts that we can check in an
end-to-end resilience test.
Previously, the stdlib provided:
- getters for AnyKeyPath and PartialKeyPath, which have remained;
- a getter for KeyPath, which still exists alongside a new read
coroutine; and
- a pair of owned mutable addressors that provided modify-like behavior
for WritableKeyPath and ReferenceWritableKeyPath, which have been
replaced with modify coroutines and augmented with dedicated setters.
SILGen then uses the most efficient accessor available for the access
it's been asked to do: for example, if it's been asked to produce a
borrowed r-value, it uses the read accessor.
Providing a broad spectrum of accessor functions here seems acceptable
because the code-size hit is fixed-size: we don't need to generate
extra code per storage declaration to support more alternatives for
key paths.
Note that this is just the compiler ABI; the implementation is still
basically what it was. That means the implementation of the setters
and the read accessor is pretty far from optimal. But we can improve
the implementation later; we can't improve the ABI.
The coroutine accessors have to be implemented in C++ and used via
hand-rolled declarations in SILGen because it's not currently possible
to declare independent coroutine accessors in Swift.
Not NFC because it also fixes an evaluation order bug (and reorders
some less-important stuff): the key-path expression needs to be
evaluated immediately during formal evaluation and cannot be delayed
until start-of-access.
Dynamic replacements are currently written in extensions as
extension ExtendedType {
@_dynamicReplacement(for: replacedFun())
func replacement() { }
}
The runtime implementation allows an implementation in the future where
dynamic replacements are gather in a scope and can be dynamically
enabled and disabled.
For example:
dynamic_extension_scope CollectionOfReplacements {
extension ExtentedType {
func replacedFun() {}
}
extension ExtentedType2 {
func replacedFun() {}
}
}
CollectionOfReplacements.enable()
CollectionOfReplacements.disable()
Beyond just being better code, this also fixes problems where
the duplicate code didn't handle e.g. _read accessors.
I believe this finishes unblocking _read in the stdlib (rdar://45230566).
To make that work, enter appropriate scopes (ArgumentScopes and
FormalEvaluationScopes) at a bunch of places. But note that l-value
emission generally can't enter such a scope, so in generic routines
like emitOpenExistentialExpr we have to just assert that we're
already in a scope.
The `Stmt` and `Expr` classes had both `dump` and `print` methods that behaved similarly, making it unclear what each method was for. Following a conversation in https://forums.swift.org/t/unifying-printing-logic-in-astdumper/15995/6 the `dump` methods will be used to print the S-Expression-like ASTs, and the `print` methods will be used to print the more textual ASTPrinter-based representations. The `Stmt` and `Expr` classes seem to be where this distinction was more ambiguous. These changes should fix that ambiguity.
A few other classes also have `print` methods used to print straightforward representations that are neither the S-Expressions nor ASTPrinters. These were left as they are, as they don't cause the same ambiguity.
It should be noted that the ASTPrinter implementations themselves haven't yet been finished and aren't a part of these changes.
The same base value is necessary to invoke other accessors as part of the same access, but we would end up consuming it as part of materializing the base value for calls into nonmutating setters.
Fixes SR-8990 | rdar://problem/45274900.
This silences the instances of the warning from Visual Studio about not all
codepaths returning a value. This makes the output more readable and less
likely to lose useful warnings. NFC.
This is NFC for now, but I plan to build on this to (1) immediately
remove some unnecessary materialization and loads of the base value
and (2) to allow clients to load a borrowed value.
Most of this patch is just removing special cases for materializeForSet
or other fairly mechanical replacements. Unfortunately, the rest is
still a fairly big change, and not one that can be easily split apart
because of the quite reasonable reliance on metaprogramming throughout
the compiler. And, of course, there are a bunch of test updates that
have to be sync'ed with the actual change to code-generation.
This is SR-7134.
In SILGenFunction::emitAssignToLValue, use an ArgumentScope instead of
a FormalEvaluationScope. This ensures that the lifetime of objects
needed to materialize each LValue component do not overlap.
For example in this tuple assignment:
public func testTupleAssign(x: inout [Int]) {
(x[0], x[1]) = (0, 1)
}
Array.subscript.nativeOwningMutableAddressor keeps a reference to the
array across the assignment, unnecessarily forcing a copy of the
array.
Fixes SR-8621: SILGen creates destroys for tuple assignment at the
wrong places.