Specifically, this API has some hard edges where instead of just returning an
invalid value to signal that we do not have self, we assert or return something
bogus. This commit just fixes our usage of that API to be correct.
rdar://132545626
This is just moving up the declaration in the chain of dependencies so that I
can write logic in PartitionUtils.h using it. I also added entrypoints to lookup
the ReprensetativeValue for our various emitters.
This reverts commit b63781f7ba.
We found some cases where due to malformed IR that we allow through due to
either us compiling for strict-concurrency=complete+swift-5 or swift-6 +
preconcurrency, that we can actually have actor isolation mismatch. I am going
to in a subsequent commit add a better phrasing here. But for now, just undo the
conversion from error -> warning.
rdar://131757602
This shows an actual issue with the compiler where semantically we should crash.
Rather than crashing (due to the broken invariants), we emit this error so that
the user gets a nice error message at the problem place and can work around it
instead of just getting a mysterious crash.
Previously, we were making this a warning in swift 5 mode... but given the
issues, it makes sense to emit an error diagnostic so we get the feedback and
the user cannot ship the code.
rdar://131482934
Otherwise, we will assume that an async let autoclosure infers isolation from
its DeclContext... which we do not want. An async let autoclosure should always
be nonisolated + sending.
The diagnostic change that I mentioned in the header is that we were emitting
unfortunate "sending task or actor isolated could result in races" error. I
eliminated this by adding a new diagnostic for transfer non transferrable errors
happening in autoclosures. So now we emit this:
```swift
func asyncLetInferAsNonIsolated<T : Actor>(
isolation actor: isolated T
) async throws {
async let subTask: Void = {
await useValueAsyncNoReturnWithInstance(self, actor)
// expected-warning @-1:47 {{sending 'self' risks causing data races}}
// expected-note @-2 {{sending 'actor'-isolated 'self' into async let risks causing data races between nonisolated and 'actor'-isolated uses}}
}()
await subTask
```
I also noticed that we did not have enough test cases for autoclosures in
general so I also added a bunch of tests just so we can see what the current
behavior is. I think there are a few issues therein (I believe some may have
been reported due to '??').
rdar://130151318
This is triggered by the test case in the next commit. The problem is anonymous
closures can be passed here and they do not have a ValueDecl so there isn't a
decl for us to use.
Specifically:
1. We error now if one transfers an 'inout sending' parameter and does not
reinitialize it before the end of the function.
2. We error now if one merges an 'inout sending' parameter into an actor
isolated region and do not reinitialize it with a non-actor isolated value
before the end of the function.
rdar://126303739
The reason why I am doing this is that I am adding support for failing to
reinitialize an inout sending parameter that was transferred. To make it really
easy to do I am just going to explicitly represent this on the RequireInst and
let the decision on what diagnostic to be done to be represented in the
pseudo-IR instead of trying to just infer it straight from the type of require
inst. This keeps all of the logic in the same place and attempts to keep the
diagnostic emitter not use logic and instead just emit.
This is NFC so I can make sure that things work before adding the additional code.
This asserts only option is an option to make it quicker/easier to triage
unknown pattern match errors by aborting when we emit it (allowing one to
immediately drop into the debugger at that point).
Previously, it only happened for errors in RegionAnalysis not in
TransferNonSendable itself.
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
DISCUSSION: The analysis itself is unable to emit errors. So we achieve the same
functionality by in such cases emitting a partition op that signals to our user
that when they process that partition op they should emit an "unknown pattern"
error at the partition op's instructions.
I have wanted this for a long time, but I never got around to it.
Specifically, I introduced a new composition type called
SILDynamicMergedIsolationInfo that just contains a
SILIsolationInfo. Importantly, whenever one merges a SILIsolationInfo with
another SILIsolationInfo, one gets back a SILDynamicMergedIsolationInfo.
The reason why I am doing this is that we drop nonisolated(unsafe) when merging
so I want to ensure that parts of the code that use merging (where the dropping
occurs) and normal SILIsolationInfo where we do not want to merge is
distinguished.
I made sure we match what we get without region isolation by turning off region
isolation in one of the test runs on the test for this.
There is one problem where for non-final classes with nonisolated(unsafe) var
fields, we currently do not properly squelch since I need to do more
infrastructure work. I am going to do that in the next commit.
rdar://128299305
The "send non-Sendable" pass had a copy of the code for determining
what limit to put on the diagnostic behavior for a given reference to
a nominal type declaration. Rather than update that copy for the
recent changes to the canonical version of this in the type checker,
share the computation.
Just trying to slice off a larger change where I change these tests to actually
use 'sending'. This is nice to do now since it is algebraic to do.
rdar://128216574
We still only parse transferring... but this sets us up for adding the new
'sending' syntax by first validating that this internal change does not mess up
the current transferring impl since we want both to keep working for now.
rdar://128216574
As part of this I went through how we handled inference and rather than using a
grab-bag getActorIsolation that was confusing to use, I created split APIs for
specific use cases (actor instance, global actor, just an apply expr crossing)
that makes it clearer inside the SILIsolationInfo::get* APIs what we are
actually trying to model. I found a few issues as a result and fixed most of
them if they were small. I also fixed one bigger one around computed property
initializers in the next commit. There is a larger change I didn't fix around allowing function
ref/partial_apply with isolated self parameters have a delayed flow sensitive
actor isolation... this will be fixed in a subsequent commit.
This also fixes a bunch of cases where we were printing actor-isolated instead
of 'self' isolated.
rdar://127295657
I am doing this separately from the previous fix for just normal region
isolation since without transferring args and results enabled, we do not hit
this code path. But since I am here, I want to fix it at the same time.
rdar://127588005
This translates the rules for @preconcurrency import from SE-0337 into the
region isolation world. Specifically if a module is compiled without strict
concurrency checking and imported with @preconcurrency:
1. All types from that module that are implicitly non-Sendable have diagnostics
suppressed in swift 5 and swift 6.
2. All types from that module that are explicitly non-Sendable emit warnings in
both swift 5 and swift 6.
rdar://126804052
I have been using these in TransferNonSendable and they are useful in terms of
reducing the amount of code that one has to type to use this API. I am going to
need to use it in SILIsolationInfo, so it makes sense to move it into
SILOptimizer/Utils.
NFCI.
This is backing out an approach that I thought would be superior, but ended up
causing problems.
Originally, we mapped a region number to an immutable pointer set containing
Operand * where the region was tranferred. This worked great for a time... until
I began to need to propagate other information from the transferring code in the
analysis to the actual diagnostic emitter.
To be able to do that, my thought was to make a wrapper type around Operand
called TransferringOperand that contained the operand and the other information
I needed. This seemed to provide me what I wanted but I later found that since
the immutable pointer set was tracking TransferringOperands which were always
newly wrapped with an Operand *, we actually always created new pointer
sets. This is of course wasteful from a memory perspective, but also prevents me
from tracking transferring operand sets during the dataflow since we would never
converge.
In this commit, I fix that issue by again tracking just an Operand * in the
TransferringOperandSet and instead map each operand to a state structure which
we merge dataflow state into whenever we visit it. This provides us with
everything we need to in the next commit to including a region -> transferring
operand set equality check in our dataflow equations and always converge.
I fixed a bunch of small issues around here that resulted in a bunch of radars
being fixed. Specifically:
1. I made it so that we treat function_refs that are from an actor isolated
function as actor isolated instead of sendable.
2. I made it so that autoclosures which return global actor isolated functions
are treated as producing a global actor isolated function.
3. I made it so that we properly handle SILGen code patterns produced by
Sendable GlobalActor isolated things.
rdar://125452372
rdar://121954871
rdar://121955895
rdar://122692698
Specifically, I added a named version of the diagnostic:
func testSimpleTransferLet() {
let k = Klass()
- transferArg(k) // expected-warning {{binding of non-Sendable type 'Klass' accessed after being transferred; later accesses could race}}
+ transferArg(k) // expected-warning {{transferring 'k' may cause a race}}
+ // expected-note @-1 {{'k' used after being passed as a transferring parameter}}
useValue(k) // expected-note {{use here could race}}
}
and I also cleaned up the typed version of the diagnostic that is used
if we fail to find a name:
func testSimpleTransferLet() {
let k = Klass()
- transferArg(k) // expected-warning {{binding of non-Sendable type 'Klass' accessed after being transferred; later accesses could race}}
- transferArg(k) // expected-warning {{value of non-Sendable type 'Klass' accessed after being transferred; later accesses could race}}
useValue(k) // expected-note {{use here could race}}
}
This is the 2nd to the last part of a larger effort to rework all of
the region based diagnostics to first try and use names and only go back
to the old typed diagnostics when we fail to look up a name (which should
be pretty rare, but is always possible).
At some point if I really feel confident enough with the name lookup code, I am
most likely just going to get rid of the typed diagnostic code and just emit a
compiler doesnt understand error. The user will still not be able to ship the
code but would also be told to file a bug so that we can fix the name
inference.
As an example of the change:
- // expected-note @-1 {{'x' is transferred from nonisolated caller to main actor-isolated callee. Later uses in caller could race with potential uses in callee}}
+ // expected-note @-1 {{transferring disconnected 'x' to main actor-isolated callee could cause races in between callee main actor-isolated and local nonisolated uses}}
Part of the reason I am doing this is that I am going to be ensuring that we
handle a bunch more cases and I wanted to fix this diagnostic before I added
more incaranations of it to the tests.
I need to start tracking the dynamic IsolationRegionInfo for the transferring
operand so I can ignore uses that are part of the same
IsolationRegionInfo. IsolationRegionInfo doesn't fit into a pointer, so just to
keep things the same, I am going to just allocate it.
This is an initial staging commit that tests out the bump ptr allocating without
expanding the type yet.
This is just a pseudo-why are these two things part of the same region error. I
am going to remove this for now and the proper form of this diagnostic will come
back when I land the region history functionality.
I also eliminated the very basic "why is this task isolated" part of the warning
in favor of the larger, better, region history impl that I am going to land
soon. The diagnostic wasn't that good in the first place and also was fiddly. So
I removed it for now.
rdar://124960994
Some notes:
1. If the result is non-Sendable and we didn't infer something that is
transferring, we still emit the current sema error that says that one cannot
assign a non-Sendable value to an async let.
2. When region isolation is enabled, but transferring args and results are
disabled, we leave the async let semantics alone. This means that the async let
closure is still @Sendable and one cannot pass in non-Sendable values to it.
Otherwise, we get off by one errors.
NOTE: I removed the assert that this originally hit since it is possible for us
to perhaps hit other issues and it would be better to just emit a suboptimal
error than crashing. With time, I will probably make it so if we miss we emit a
"compiler couldn't understand error".
rdar://124478890
We do not emit these very much anymore. I am just keeping it in place a bit
longer... eventually, this should just be an unknown pattern error since if a
user sees this it won't compile and we would rather then send it to us so we can
fix it.