Previously, the `__consuming` decl modifier failed to get propagated to the value ownership of the
method's `self` parameter, causing it to effectively be a no-op. Fix this, and address some of the
downstream issues this exposes:
- `coerceCallArguments` in the type checker failing to handle the single `__owned` parameter case
- Various places in SILGen and optimizer passes that made inappropriate assertions that `self`
was always passed guaranteed
Before we changed convenience inits into allocating entry points, we allowed type(of: self) to be invoked on the uninitialized object, which was fine. This no longer Just Works when self doesn't even exist before `self.init` is called, but to maintain the old semantics and source compatibility, we can still just use the metatype value we were passed in.
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.
The only real bug here is that we were looking specifically for `apply`
instructions, so we failed to diagnose `try_apply` calls to mutating
throwing functions on immutable existentials. Fixing this is a
source-compatibility break, but it's clearly in the "obvious bug" category
rather than something we need to emulate. (I found this bug because DI
stopped diagnosing a modification of a property of a `let` existential
when it started being done with `modify`, which of course is called with
`begin_apply`.)
It's totally fine to have a conditional destroy of 'self' because
we now uniformly treat assignment to self and self.init delegation,
both of which can appear multiple times in a value type
initializer.
This change removes the assertion and adds some tFileCheck tests to
ensure that DI was already capable of inserting the correct memory
management operations in this scenario.
Fixes <rdar://problem/40417944>, <https://bugs.swift.org/browse/SR-7727>.
This ensures that DI creates dealloc_box in cases where the box is uninitialized
conditionally.
In the process, I also discovered that we were missing a test case for DI being
used by LLDB. Long term we shouldn't support that code pattern in the general
case, but for now we at least need a test case for it.
rdar://40332620
I am doing this so I can start writing DI tests without this lowering occuring.
There never was a real reason for this code to be in DI beyond convenience. Now
it just makes writing tests more difficult. To prevent any test delta, I changed
all current DI tests to run this pass after DI.
closure lifetimes.
SILGen will now unconditionally emit
%cvt = convert_escape_to_noescape [guaranteed] %op
instructions. The mandatory ClosureLifetimeFixup pass ensures that %op's
lifetime spans %cvt's uses.
The code in DefiniteInitialization that handled a subset of cases is
removed.
To mark when a user of it is known to escape the value. This happens
with materializeForSet arguments which are captured and used in the
write-back. This means we need to keep the context alive until after
the write-back.
Follow-up patches to fully replace the PostponedCleanup hack in SILGen
by a mandatory SIL transformation pass to guarantee the proper lifetime
will use this flag to be more conservative when extending the lifetime.
The problem:
%pa = partial_apply %f(%some_context)
%cvt = convert_escape_to_noescape [not_guaranteed] [escaped] %pa
%ptr = %materialize_for_set(..., %cvt)
... write_back
... // <-- %pa needs to be alive until after write_back
SILGen does this now to maintain ownership balance when a class initializer delegation gets interrupted, such as by an error propagation through one of the arguments to the delegatee. Fixes rdar://problem/37007554 .
This has three principal advantages:
- It gives some additional type-safety when working
with known accessors.
- It makes it significantly easier to test whether a declaration
is an accessor and encourages the use of a common idiom.
- It saves a small amount of memory in both FuncDecl and its
serialized form.
The goal is to make it more composable to add trailing-objects fields in
a subclass.
While I was doing this, I noticed that the apply instructions provided
redundant getNumArguments() and getNumCallArguments() accessors, so I
went ahead and unified them.
...being careful to only do it once per initializer. Additionally,
/don't/ offer the suggestion if there was already a conditional
assignment to 'self', because that would wipe it out and the user
should think harder.
...unless the struct contains a field that cannot be zero-initialized,
such as a non-nullable pointer.
This suggestion is only made for C structs because 'init()' may not be
the right choice for other structs.
...as detected by initializing an individual field without having
initialized the whole object (via `self = value`).
This only applies in pre-Swift-5 mode because the next commit will
treat all cross-module struct initializers as delegating in Swift 5.
This changes code generation a bit, because now the conditional
state bitmap uses a bit to track if the 'self' box was stored,
not if the 'self' value was consumed. In some cases, this
eliminates an extra bit, in other places it introduces an
extra bit, but it really doesn't matter because LLVM will
optimize this bit manipulation easily.