This required quite a bit of infrastructure for emitting this kind of
tuple expression, although I'm not going to claim they really work yet;
in particular, I know the RValue constructor is going to try to explode
them, which it really shouldn't.
It also doesn't include the caller side of returns, for which I'll need
to teach ResultPlan to do the new abstraction-pattern walk. But that's
next.
This is the first slice of bringing up escaping closure support. The support is
based around introducing a new type of SILGen VarLoc: a VarLoc with a box and
without a value. Because the VarLoc only has a box, we have to in SILGen always
eagerly reproject out the address from the box. The reason why I am doing this
is that it makes it easy for the move checker to distinguish in between
different accesses to the box that we want to check separately. As such every
time that we open the box, we insert a mark_must_check
[assignable_but_not_consumable] on that project. If allocbox_to_stack manages to
determine that the box can be stack allocated, we eliminate all of the
mark_must_check and place a new mark_must_check [consumable_and_assignable] on
the alloc_stack. The end result is that we get the old model that we had before
and also can support escaping closures.
As part of this I also had to change how we emit global_addr in
SILGenLValue. Specifically, only for noncopyable types, we no longer emit a
single global_addr at the beginning of the function (in a sense auto-CSEing) and
instead always emit a new global_addr for each access. The reason why we do this
is that otherwise, access base visitor will consider all accesses to the global
to be for the same single access. In contrast, by always emitting the
global_addr each time, we provide a new base for each access allowing us to emit
the diagnostics that we want to.
rdar://102794400
Consider the following example:
```
class Klass {}
@_moveOnly struct Butt {
var k = Klass()
}
func mixedUse(_: inout Butt, _: __owned Butt) {}
func foo() {
var y = Butt()
mixedUse(&y, y)
}
```
In this case, we want to have an exclusivity violation. Before this patch, we
did a by-value load [copy] of y and then performed the inout access. Since the
access scopes did not overlap, we would not get an exclusivity violation.
Additionally, since the checker assumes that exclusivity violations will be
caught in such a situation, we convert the load [copy] to a load [take] causing
a later memory lifetime violation as seen in the following SIL:
```
sil hidden [ossa] @$s4test3fooyyF : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack [lexical] $Butt, var, name "y" // users: %4, %5, %8, %12, %13
%1 = metatype $@thin Butt.Type // user: %3
// function_ref Butt.init()
%2 = function_ref @$s4test4ButtVACycfC : $@convention(method) (@thin Butt.Type) -> @owned Butt // user: %3
%3 = apply %2(%1) : $@convention(method) (@thin Butt.Type) -> @owned Butt // user: %4
store %3 to [init] %0 : $*Butt // id: %4
%5 = begin_access [modify] [static] %0 : $*Butt // users: %7, %6
%6 = load [take] %5 : $*Butt // user: %10 // <————————— This was a load [copy].
end_access %5 : $*Butt // id: %7
%8 = begin_access [modify] [static] %0 : $*Butt // users: %11, %10
// function_ref mixedUse2(_:_:)
%9 = function_ref @$s4test9mixedUse2yyAA4ButtVz_ADntF : $@convention(thin) (@inout Butt, @owned Butt) -> () // user: %10
%10 = apply %9(%8, %6) : $@convention(thin) (@inout Butt, @owned Butt) -> ()
end_access %8 : $*Butt // id: %11
destroy_addr %0 : $*Butt // id: %12
dealloc_stack %0 : $*Butt // id: %13
%14 = tuple () // user: %15
return %14 : $() // id: %15
} // end sil function '$s4test3fooyyF'
```
Now, instead we create a [consume] access and get the nice exclusivity error we
are looking for.
NOTE: As part of this I needed to tweak the verifier so that [deinit] accesses
are now allowed to have any form of access enforcement before we are in
LoweredSIL. I left in the original verifier error in LoweredSIL and additionally
left in the original error in IRGen. The reason why I am doing this is that I
need the deinit access to represent semantically what consuming from a
ref_element_addr, global, or escaping mutable var look like at the SIL level so
that the move checker can error upon it. Since we will error upon such
consumptions in Canonical SIL, such code patterns will never actually hit
Lowered/IRGen SIL, so it is safe to do so (and the verifier/errors will help us
if we make any mistakes). In the case of a non-escaping var though, we will be
able to use deinit statically and the move checker will make sure that it is not
reused before it is reinitialized.
rdar://101767439
The reason to do the first is to ensure that when I enable -sil-verify-all, we
do not have errors due to a copy_value of a move only type.
The reason to do the second thing is that:
1. If we have a move only type that is no implicit copy, I am in a subsequent
commit going to emit a type checker error saying that one cannot do this. When
we implement consuming/borrowing bindings/etc, we can make this looser if it
gets into the way.
2. If we have a copyable no implicit copy type, then any structural accesses
that we may want to do that would require a destructure must be to a copyable
type which is ok to copy as long as we do the unwrap from the first thing.
rdar://104929957
If a function body references a declaration with the `@_backDeploy(before:)` attribute and that function body will only execute on deployment targets for which the ABI version of the decl is available then it is unnecessary to thunk the reference to the decl. Function bodies that may be emitted into other modules (e.g. `@inlinable`) must always use the thunk.
Resolves rdar://90729799
`getValue` -> `value`
`getValueOr` -> `value_or`
`hasValue` -> `has_value`
`map` -> `transform`
The old API will be deprecated in the rebranch.
To avoid merge conflicts, use the new API already in the main branch.
rdar://102362022
The reason why we are doing this is that we want move only addresses to be
checked by the move only address checker and not the move operator address
checker.
rdar://102056097
When property has attached property wrappers and is managed
by a type wrapper at the same time it has to be initialized in
a special way - instead of using backing property directly
(which is not actually a stored property in this scheme)
`assign_by_wrapper` instruction has to use a field of a
local `_storage` variable which represents underlying storage
before `$storage` property could be initialized.
Properties that are managed by a type wrapper have to be initialized
through a temporary `_storage` variable and only DI can tell us
when `_storage` is fully initialized, so we need to emit a
`assign_by_wrapper` instruction (with originator - type wrapper)
for every assignment to keep that and inject `$_storage.init`
as soon as all the managed properties are initialized.
Also renaming it to be UncheckedConversionComponent since it's a better name.
As a physical component, we'd run into problems in assignment statements.
The problem was that if we had something like:
```
SomeOtherComponent // first component
GetterSetterComponent
ABISafeConversionComponent // last component
```
When emitting the assignment, we always drill down through all but
the last component by calling `project()` on each one. Then on the last
component, we'd do the actual setting operation. But GetterSetterComponent
cannot be projected when the access is for writing.
So, to work around this I decided to model it as a TranslationComponent, because
those are specifically designed to be handled during an assignment by popping those
off the end of the component sequence, untranslating the value we're about to assign
as we go, until we hit the GetterSetterComponent.
By "untranslating" we're effectively putting Sendable back onto the set's argument
prior to calling set, because the underlying property's type still has `@Sendable`
on it (e.g., it's accessors still have that on its argument type). When
"translating" we're effectively taking Sendable off after reading it.
I think actually works really well and makes much more sense now.
resolves rdar://99619834
We needed a way to describe an ABI-safe cast of an address
representing an LValue to implement `@preconcurrency` and
its injection of casts during accesses of members.
This new AST node, `ABISafeConversionExpr` models what is
essentially an `unchecked_addr_cast` in SIL when accessing
the LVAlue.
As of now I simply implemented it and the verification of
the node for the concurrency needs to ensure that it's not
misused by accident. If it finds use outside of that,
feel free to update the verifier.
The generalized ActorIsolation is enough to represent everything that
ImplicitActorHopTarget can do, and we were mapping between the two way
too often, so collapse them.
I also updated the move function tests to show that this is working. As a nice
bonus, I was able to enable all of the tests also in a non-optimized stdlib.
When emitting a call to the getter for storage, emit the actor hop (and
hop back) as part of the call itself, rather than around the whole
initialization. This address a bug involving initialization with an
optional binding in an `if let`, where the hop-back would only be
performed on the non-nil branch.
Fixes rdar://96487805 / FB10562197
It used to be an accessor but that is not required because
SILDeclRef controls mangling which is the most imprortant
and could be used to emit the right reference.
This strategy is used to dispatch accesses to 'distributed' computed
property to distributed thunk accessor instead of a regular getter
when access happen outside actor isolation context.
This involved doing the following:
1. Update the move only checker to look for new patterns.
2. Teach emitSemanticStore to use a moveonlywrapper_to_copyable to store moveonly
values into memory. The various checkers will validate that this code is
correct.
3. When emitting an apply, always unwrap move only variables. In the
future, I am going to avoid this if a parameter is explicitly marked as also
being moveonly (e.x.: @moveOnly parameter or @noEscape argument).
4. Convert from moveOnly -> copyable on return inst automatically in SILGen.
5. Fix SILGenLValue emission so we emit an error diagnostic later rather than
crash. This is needed to keep SILGen emitting move only addresses (that is no
implicit copy address only lets) in a form that the move only checker then
will error upon. Without this change, SILGen crashes instead of emitting an
error diagnostic in the following test:
.//test/SILOptimizer/move_only_checker_addressonly_fail.swift
The resignID call within the initializer moved into DI, because an assignment to
the actorSystem, and thus initialization of the id, is no longer guaranteed to happen.
Thus, while we previously could model the resignation as a clean-up emitted on all
unwind paths in an initializer, now it's conditional, based on whether the id was
initialized. This is exactly what DI is designed to do, so we inject the resignation
call just before we call the identity's deinit.
The `@exclusivity(unchecked)` attribute can be used on variables to selectively disable exclusivity checking.
For completeness, also the `@exclusivity(checked)` variant is supported: it turns on exclusivity checking for specific variables if exclusivity enforcement is disabled by the command line option.
This new attribute is a missing implementation part of SE-0176 (https://github.com/apple/swift-evolution/blob/main/proposals/0176-enforce-exclusive-access-to-memory.md).
rdar://31121356