Commit Graph

17 Commits

Author SHA1 Message Date
Michael Gottesman
f43911b30f [region-isolation] Given a .none #isolation parameter, infer the isolation from the callee rather than the isolated parameter.
Otherwise, we will have differing isolation from other parameters since
the isolations will look different since one will have the .none value
as an instance and the other will not have one and instead will rely on
the AST isolation info. That is the correct behavior here since we do
not actually have an actor here.

I also removed some undefined behavior in the merging code. The way the
code should work is that we should check if the merge fails and in such
a case emit an unknown pattern error... instead of not checking
appropriately on the next iteration and hitting undefined behavior.

rdar://130396399
2024-06-25 14:12:15 -07:00
Michael Gottesman
c01f551ebe [transfer-non-sendable] Teach SILIsolationInfo how to handle "look through instructions" when finding actor instances.
From the perspective of the IR, we are changing SILIsolationInfo such that
inferring an actor instance means looking at equivalence classes of values where
we consider operands to look through instructions to be equivalent to their dest
value. The result is that cases where the IR maybe puts in a copy_value or the
like, we consider the copy_value to have the same isolation info as using the
actor directly. This prevents a class of crashes due to merge failings. Example:

```swift
actor MyActor {
  init() async {

  init(ns: NonSendableKlass) async {
    self.k = NonSendableKlass()
    self.helper(ns)
  }

  func helper(_ newK: NonSendableKlass) {}
}
```

Incidently, we already had a failing test case from this behavior rather than
the one that was the original genesis. Specifically:

1. If a function's SILIsolationInfo is the same as the isolation info of a
SILValue, we assume that no transfer actually occurs.

2. Since we were taking too static of a view of actor instances when comparing,
we would think that a SILIsolationInfo of a #isolation parameter to as an
argument would be different than the ambient's function isolation which is also
that same one. So we would emit a transfer non transferrable error if we pass in
any parameters of the ambient function into another isolated function. Example:

```swift
actor Test {

  @TaskLocal static var local: Int?

  func withTaskLocal(isolation: isolated (any Actor)? = #isolation,
                     _ body: (consuming NonSendableValue, isolated (any Actor)?) -> Void) async {
    Self.$local.withValue(12) {

      // We used to get these errors here since we thought that body's isolation
      // was different than the body's isolation.
      //
      //  warning: sending 'body' risks causing data races
      //  note: actor-isolated 'body' is captured by a actor-isolated closure...
      body(NonSendableValue(), isolation)
    }
  }
}
```

rdar://129400019
2024-06-24 18:16:11 -07:00
Tim Kientzle
1098054291 Merge branch 'main' into tbkka-assertions2 2024-06-18 17:52:00 -07:00
Michael Gottesman
d032bc033a [region-isolation] Check if we have a self param before attempting to get the self type.
Otherwise in asserts builds we get an assert and in no-asserts we get a crash.

rdar://129975097
2024-06-18 13:39:20 -07:00
Michael Gottesman
f035590784 [region-isolation] Dont crash when processing global actor isolated init accessors.
This just means that I stopped treating it like an actor instance isolated
thing. This was fun to track down since ActorIsolation has a union in it that
was being misinterpreted, leading to memory corruption... my favorite! = ).

rdar://129256560
2024-06-11 22:15:37 -07:00
Tim Kientzle
1d961ba22d Add #include "swift/Basic/Assertions.h" to a lot of source files
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)
2024-06-05 19:37:30 -07:00
Michael Gottesman
c7124e431a [sending] Fix recent alloc_stack as indirect result isolation inference to infer disconnected if the alloc stack is used as a sending indirect result.
I also fixed an issue that I found where we were not substituting SILResultInfo
flags which was causing us to drop when substituting sil_sending. I added a
SILVerifier check to make sure that we do not break this again.
2024-06-01 23:25:16 -07:00
Michael Gottesman
0cd0868f52 [region-isolation] Recognize sil_isolated parameters that are global actors as global actors rather than actor instance.
The specific example I ran into was in sendable_continuation.swift where we were
passing in the @MainActor instance as a sil_isolated parameter. We were thinking
it was an actor instance so we emitted the wrong message.
2024-06-01 23:25:16 -07:00
Michael Gottesman
1d8ea84fa3 [region-isolation] When determining isolation of a full apply site... use the isolated parameter, not self.
This was ok in the small since most of the time we were processing a self
parameter as isolated... but that isn't always true...
2024-06-01 23:25:16 -07:00
Michael Gottesman
06c32d74ff [region-isolation] Teach SIL isolation inference how to infer applies isolation from their callee's isolation.
This fixes a few issues I missed in the past bit of commits.

I need to fix one issue around async let, but I am going to fix it when I do a
sweep across async let.
2024-05-28 17:31:09 -07:00
Michael Gottesman
74ac12c9d2 [region-isolation] Make temporary alloc_stack that we form for returning values from a non-final class field take on the class method's isolation.
The reason why we are doing this is that otherwise, we have that the alloc_stack
formed for the result is disconnected and despite the fact that we merge it into
the actor region of the class method, we do not have that the alloc_stack
specifically is marked when we attempt to squelch Please.

This patch fixes that problem by detecting when an alloc_stack is being used as
a temporary for an out parameter and makes the alloc_stack initially isolated as
appropriate. It only does this in the specific cases where we can pattern match
it which in my limited testing has handled everything.
2024-05-28 17:31:08 -07:00
Michael Gottesman
2de13df909 [region-isolation] Use SILIsolationInfo::initializeTrackableValue instead of SILIsolationInfo::mergeIsolationRegionInfo to fix last issue
When merging SILIsolationInfo for regions, we want to drop
nonisolated(unsafe). This is important since nonisolated(unsafe) should only
apply to the specific "value" that it belongs to, not the entire region.

This creates a problem since in a few places in the code base we initialize a
value (producing a disconnected value) and then initialize it by merging in an
actor isolation. This no longer work since we will then always have
nonisolated(unsafe) stripped, so no values would ever be considered to be
nonisolated(unsafe). After analyzing the use case, I realized that these were
just initialization patterns and in this commit, I added a specific
initialization operation called SILIsolationInfo::initializeTrackableValue and
eliminated those calls to SILIsolationInfo::mergeIsolationRegionInfo.

Since SILIsolationInfo no longer has any merge operation on it, I then
eliminated that code in this commit. This completes the behavior split that I
put into the type system in the last commit. Specifically, I defined a
composition type called SILDynamicMergedIsolationInfo. It represents a
SILIsolationInfo that has been merged... that is why I called it the
DynamicMergedIsolationInfo. It could probably use a better name = (.

This fixes one of the last weird test case that I wrote where we were not letting through valid
nonisolated(unsafe) code.

At the same time, I discovered an additional issue (which can be seen in the
TODOs in this commit), where we are being too conservative around a non-Sendable
class var field. I am going to fix that in the next commit.

rdar://128299305
2024-05-27 21:42:15 -07:00
Michael Gottesman
741244e16b [region-isolation] Split in the type system SILIsolationInfo that has been merged and those that haven't.
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.
2024-05-27 21:41:54 -07:00
Michael Gottesman
3a1f58a72a [region-isolation] Make sure that nonisolated(unsafe) works in all cases.
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
2024-05-27 21:41:32 -07:00
Michael Gottesman
89a2cfce0b [region-isolation] Initialize TrackableValueState's regionInfo with a .none instead of a disconnected region.
The design change here is that instead of just initializing the regionInfo with
disconnected, we set it as .none and if we see .none, just return a newly
construct disconnected isolation region info when getIsolationRegionInfo() is
called.

This enables us to provide a setIsolationRegionInfo() helper for
RegionAnalysisValueMap::getTrackableValue that does not perform a merge. This is
important since for nonisolated(unsafe), we want to not have nonisolated(unsafe)
propagate through merging. So if we use merging to initialize the internal
regionInfo state of a SILIsolationInfo, we will never have a SILIsolationInfo
with that bit set since it will be lost in the merge. So we need some sort of
other assignment operator. Noting that we should only compute a value's
SILIsolationInfo once in RegionAnalysisValueMap before we cache it in the map,
it made sense to just represent it as an optional that way we can guarantee that
the regionInfo is only ever set exactly once by that routine.
2024-05-27 21:28:34 -07:00
Michael Gottesman
3f26d08ee4 [region-isolation] Add the ability in SILIsolationInfo to represent a disconnected value that is nonisolated(unsafe). 2024-05-27 21:25:44 -07:00
Michael Gottesman
3597006200 [region-isolation] Move SILIsolationInfo out of PartitionUtils into its own header/cpp file.
SILIsolationInfo is conceptually a layer that composes with PartitionUtils so it
makes sense for it to be in a different file.
2024-05-27 20:37:08 -07:00