Commit Graph

173 Commits

Author SHA1 Message Date
Doug Gregor
25e1a00dbe [Region analysis] Remove an assertion that doesn't always hold
It appears that we can end up breaking this assertion when inlining
SIL from modules with strict concurrency enabled into modules that
don't. That's not a assertion-worth condition.
2025-03-10 11:19:16 -07:00
Michael Gottesman
dab324080b [rbi] Make convert_escape_to_no_escape and convert_function lookthrough if their result/operand is non-Sendable.
In these cases, we want to lookthrough so we propagate through
nonisolated(unsafe) and make it easier to discover that we are processing
keypaths (the reason I am making this change).
2025-02-25 08:39:39 -08:00
Michael Gottesman
b286373631 [rbi] Make a confusing comment clearer.
From talking with @dgregor, it became clear that this comment was easily
interpreted as saying that AssignFresh always introduced a disconnected value...
which is not the case. Instead, AssignFresh just introduces a new value that
could have any form of isolation. The actual isolation of the value is assigned
via tryToTrackValue and eventually SILIsolationInfo::get().
2025-02-24 10:09:32 -08:00
Doug Gregor
a32470f14a Correct the region isolation rule for metatype extraction instructions
Now that metatypes might not be Sendable, we need the Assign rule for
operations that produce the metatype of a value or existential.
2025-02-14 15:33:57 -08:00
Doug Gregor
37d71f362e Add StrictSendableMetatypes to require Sendable requirements on metatypes
Introduce a new experimental feature StrictSendableMetatypes that stops
treating all metatypes as `Sendable`. Instead, metatypes of generic
parameters and existentials are only considered Sendable if their
corresponding instance types are guaranteed to be Sendable.

Start with enforcing this property within region isolation. Track
metatype creation instructions and put them in the task's isolation
domain, so that transferring them into another isolation domain
produces a diagnostic. As an example:

    func f<T: P>(_: T.Type) {
      let x: P.Type = T.self
      Task.detached {
        x.someStaticMethod() // oops, T.Type is not Sendable
      }
    }
2025-02-12 20:21:57 -08:00
Erik Eckstein
e0b4f71af6 SIL: remove the alloc_vector instruction
It's not needed anymore, because the "FixedArray" experimental feature is replaced by inline-arrays.
2025-02-12 10:51:14 +01:00
Michael Gottesman
7e350bb4ce Revert "[concurrency] Add Concurrent/ConcurrentUnsafe and use it instead of ActorIsolation::Nonisolated."
This reverts commit 0cb64638d0.
2025-02-06 14:05:06 -08:00
Michael Gottesman
0cb64638d0 [concurrency] Add Concurrent/ConcurrentUnsafe and use it instead of ActorIsolation::Nonisolated.
This is just the first part of a larger transition.
2025-02-03 10:56:06 -08:00
Erik Eckstein
3ec5d7de24 SIL: replace the is_escaping_closure instruction with destroy_not_escaped_closure
The problem with `is_escaping_closure` was that it didn't consume its operand and therefore reference count checks were unreliable.
For example, copy-propagation could break it.
As this instruction was always used together with an immediately following `destroy_value` of the closure, it makes sense to combine both into a `destroy_not_escaped_closure`.
It
1. checks the reference count and returns true if it is 1
2. consumes and destroys the operand
2025-01-24 19:23:27 +01:00
Michael Gottesman
7ae56aab2e [sil] Add a new instruction ignored_use.
This is used for synthetic uses like _ = x that do not act as a true use but
instead only suppress unused variable warnings. This patch just adds the
instruction.

Eventually, we can use it to move the unused variable warning from Sema to SIL
slimmming the type checker down a little bit... but for now I am using it so
that other diagnostic passes can have a SIL instruction (with SIL location) so
that we can emit diagnostics on code like _ = x. Today we just do not emit
anything at all for that case so a diagnostic SIL pass would not see any
instruction that it could emit a diagnostic upon. In the next patch of this
series, I am going to add SILGen support to do that.
2025-01-22 21:12:36 -08:00
Michael Gottesman
cff835e061 [region-isolation] Perform checking of non-Sendable results using rbi rather than Sema.
In terms of the test suite the only difference is that we allow for non-Sendable
types to be returned from nonisolated functions. This is safe due to the rules
of rbi. We do still error when we return non-Sendable functions across isolation
boundaries though.

The reason that I am doing this now is that I am implementing a prototype that
allows for nonisolated functions to inherit isolation from their caller. This
would have required me to implement support both in Sema for results and
arguments in SIL. Rather than implement results in Sema, I just finished the
work of transitioning the result checking out of Sema and into SIL. The actual
prototype will land in a subsequent change.

rdar://127477211
2024-12-02 16:54:12 -05:00
Michael Gottesman
b5ce28fc57 [region-isolation] Cache getUnderlyingTrackedValue.
TLDR: Was looking at some performance traces and saw that we need to cache the
result of this value.

----

Specifically, I noticed that we were spending a lot of time computing this
operation. When I looked at the code I saw that we already had a cache along the
relevant code paths... but the cache was from equivalence class representative
-> state. Before we hit that cache, we were performing the work to map the value
to the equivalence class representative... so the work to perform the relevant
lookup from value -> state (which goes through the equivalence class
representative) was not just a hash table lookup. This operation makes it
cheaper by making it two cache lookups.

It may be possible to make this cheaper by redoing the actual mapping of
information so that we can go straight from value to state. I think it would be
slightly different since we would probably need to represent the state in a
separate array and map with indices... which is really just a more efficient
hash table. We could also use malloc/etc but lets not even talk about that.

rdar://139520959
2024-11-11 11:43:07 -08:00
Michael Gottesman
edd6bf5704 [region-isolation] A little code re-organization.
I am going to be adding more functionality to this that moves a bit of the
utilities code into it. So it really makes sense to move it to the top of the
file closer to that code. I am doing this separately to make the other
refactoring easier to see in the diff.
2024-11-11 11:43:07 -08:00
Michael Gottesman
32b4de60a9 Rename transfer -> send.
Accomplished using clangd's rename functionality.
2024-11-04 15:17:51 -08:00
Michael Gottesman
3c38c79f7a [region-isolation] Implement MergeIsolationRegionInst.
I am adding this instruction to express artificially that two non-Sendable
values should be part of the same region. It is meant to be used in cases where
due to unsafe code using Sendable, we stop propagating a non-Sendable dependency
that needs to be made in the same region of a use of said Sendable value. I
included an example in ./docs/SIL.rst of where this comes up with @out results
of continuations.
2024-11-01 11:25:53 -07:00
Michael Gottesman
e49ef778f1 [region-isolation] Rename RequireInOutSendingAtFunctionExit -> InOutSendingAtFunctionExit.
I am going to be doing more types of checks for such inout sending types, so it
makes sense to rename it to have a more general name.
2024-10-25 16:57:54 -07:00
Michael Gottesman
9a6090fc43 When printing logging, dump out the whole function.
Just to make it a little quicker to debug/get this information when debugging
the pass. I have been wanting this and just hadn't gotten around to adding it.
It just centralizes the last piece of information that one wants to reach for
when debugging.
2024-10-11 13:19:05 -07:00
Michael Gottesman
561662d6cc [sil] Add a new instruction called ThunkInst.
For now this will only be used for HopToMainActorIfNeeded thunks. I am creating
this now since in the past there has only been one option for creating
thunks... to create the thunk in SILGen using SILGenThunk. This code is hard to
test and there is a lot of it. By using an instruction here we get a few benefits:

1. We decouple SILGen from needing to generate new kinds of thunks. This means
that SILGenThunk does not need to expand to handle more thunks.

2. All thunks implemented via ThunkInst will be easy to test in a decoupled way
with SIL tests.

3. Even though this stabilizes the patient, we still have many thunks in SILGen
and various parts of the compiler. Over time, we can swap to this model,
allowing us to hopefully eventually delete SILGenThunk.
2024-10-02 14:15:49 -07:00
Alejandro Alonso
75c2cbf593 Implement value generics
Some requirement machine work

Rename requirement to Value

Rename more things to Value

Fix integer checking for requirement

some docs and parser changes

Minor fixes
2024-09-04 15:13:25 -07:00
Michael Gottesman
3e27bfc03b [region-isolation] Treat sending indirect_results as disconnected even if it is a return value of an actor isolated function.
rdar://134623227
2024-08-24 14:02:41 -04:00
Michael Gottesman
b993d7d094 [region-isolation] Improve the logging so that we also dump a function's demangled name when processing it in RegionAnalysis.
Just trying to improve logging to speed up triaging further. This is useful so
that I can quickly find specific closures we process by using the closure
numbering (e.x.: closure #1 in XXXX).
2024-08-24 13:46:22 -04:00
Michael Gottesman
226e97a5a6 [region-isolation] Clean up some code now that SILBasicBlock::{dump,print}ID are in front of NDEBUG. 2024-08-09 11:10:37 -07:00
Michael Gottesman
1fbc930cdd [region-isolation] Make logging and debug tooling appear in non-asserts builds.
This will just help me to more quickly triage without needing to compile an
asserts compiler.
2024-08-07 13:35:18 -07:00
Michael Gottesman
541863dbc6 [region-isolation] Fix handling of coroutine apply results.
In this part of the code, we are attempting to merge all of the operands into
the same region and then assigning all non-Sendable results of the function to
that same region. The problem that was occuring here was a thinko due to the
control flow of the code here not separating nicely the case of whether or not
we had operands or not. Previously this did not matter, since we just used the
first result in such a case... but since we changed to assign to the first
operand element in some cases, it matters now. To fix this, I split the confused
logic into two different easy to follow control paths... one if we have operands
and one where we do not have an operand. In the case where we have a first
operand, we merge our elements into its region. If we do not have any operands,
then we just perform one large region assign fresh.

This was not exposed by code that used non-coroutines since in SIL only
coroutines today have multiple results.

rdar://132767643
2024-07-31 09:37:42 -07:00
Michael Gottesman
8604480d12 [region-isolation] Do not ignore non-trivial results that are Sendable to be more permissive in the face of lazy typechecker issues.
We have found certain cases due to the requestified typechecker, a type is
initially Sendable and then is later non-Sendable. This can be seen by the
attached test case where the first time one calls isNonSendableType on the test
value, one would get that it is Sendable and then the second time one would get
it was non-Sendable. The result of this is that the pass gets into an
inconsistent state.

This patch is a small patch that makes the pass more permissive in the face of
such an error by making it so that we do not ignore Sendable results of
instructions (that is we make sure to track a value for them), so we do not
break invariants.

The longer term better fix is to make it so that we have a cache in the pass for
this query that way we just always use the first answer returned from the
typechecker and cache that. If the typechecker has such a bug, we may get bogus
results, but we at least do not break invariants.

As an example of this type of behavior, in the test case in this patch, we first
find the Sendable conformance of MySubClass and then the typechecker after doing
some more type checking while performing that query, the second time finds the
inherited non-Sendable conformance of MyParentClass causing MySubClass to be
considered to be non-Sendable.

rdar://132347404
2024-07-29 09:44:57 -07:00
Michael Gottesman
ae797d43e9 [region-isolation] Propagate through the whole source operand instead of just the representative of the source value when constructing assign and merge.
This will let me know the exact source operand used instead of the source value
representative. This will ensure that the name associated with the diagnostic is
not of the representative value, but the actual value that was the source of the
assign.

This is an NFCI commit that is an algebraic refactor.
2024-07-18 21:28:22 -07:00
Michael Gottesman
ace94b00ba [region-isolation] Move RepresentativeValue from RegionAnalysis.h -> PartitionUtils.h and add APIs for mapping an ElementID -> Representative.
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.
2024-07-18 21:28:22 -07:00
Michael Gottesman
c986af7695 [region-isolation] Be more aggressive about not looking through Sendable values when getting underlying objects.
Otherwise, in cases like the following, we look through the load to x.boolean
and think that the closure is actually capturing x instead of y:

```swift
func testBooleanCapture(_ x: inout NonSendableKlass) {
  let y = x.boolean
  Task.detached { @MainActor [z = y] in
    print(z)
  }
}
```

rdar://131369987
2024-07-09 14:38:47 -07:00
Michael Gottesman
0c254807bf [region-isolation] Allow for unapplied isolated parameter ownership.
Given a function or a partial_apply with an isolated parameter, we do not know
immediately what the actual isolation is of the function or partial_apply since
we do not know which instance will be applied to the function or partial_apply.

In this commit, I introduce a new bit into SILIsolationInfo that tracks this
information upon construction and allows for it to merge with ownership that has
the appropriate type and a specific instance. Since the values that created the
two isolations, will be in the same region this should ensure that the value is
only ever in a flow sensitive manner in a region with only one actor instance
(since regions with isolations with differing actor instances are illegal).
2024-07-06 23:02:11 -07:00
Michael Gottesman
c20abe570d Merge pull request #74919 from gottesmm/pr-d8b24a45ff257893c8172491f11a617fc00d5589
[region-isolation] Implement support for 'inout sending' diagnostics.
2024-07-02 20:16:25 -07:00
Michael Gottesman
6fe749626f [region-isolation] Add 'inout sending' diagnostics.
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
2024-07-02 16:21:44 -07:00
Michael Gottesman
e9e5c4eb4c [region-isolation] Ensure that some NDEBUG code is properly guarded. 2024-07-02 13:55:33 -07:00
Michael Gottesman
a13c1dc2dc Merge pull request #74869 from gottesmm/rdar130915737
[region-isolation] Improve async let errors to always use a new style error.
2024-07-01 16:24:32 -07:00
Michael Gottesman
78d74cf716 [region-isolation] Make sil-region-isolation-assert-on-unknown-pattern also work with TransferNonSendable versions of the error.
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.
2024-07-01 13:12:36 -07:00
Michael Gottesman
f0fff2e5a0 [region-isolation] Treat sendable return values as Sendable when the returning function has a known actor isolation.
rdar://130544081
2024-06-26 16:31:45 -07:00
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
43e1c5499f [sending] Make the operation of Builtin.createAsyncTask/friends a sending non-Sendable function instead of an @Sendable function.
This matches the interface of the public stdlib APIs that wrap these builtin calls.
2024-06-21 02:24:03 -07:00
Tim Kientzle
1098054291 Merge branch 'main' into tbkka-assertions2 2024-06-18 17:52:00 -07:00
Michael Gottesman
6d15e41a2f Merge pull request #74123 from gottesmm/pr-9e8378fdeee3204a34f48ea8d2ff8f0be40a4674
[region-isolation] Make store_borrow a store operation that does not require
2024-06-12 19:43:17 -07:00
Michael Gottesman
bd472b12be [region-isolation] Make store_borrow a store operation that does not require.
TLDR:

The reason why I am doing this is it ensures that temporary store_borrow that we
create when materializing a value before were treated as uses. So we would error
on this:

```swift
@MainActor func transferToMain<T>(_ t: T) async {}

func test() async {
  let x = NonSendableKlass()
  await transferToMain(x)
  await transferToMain(x)
}
```

----

store_borrow is an instruction intended to be used to initialize temporary
alloc_stack with borrows. Since it is a temporary, we do not want to error on
the temporaries initialization... instead, we want to error on the use of the
temporary parameter.

This is achieved by making it so that store_borrow still performs an
assign/merge, but does not require that src/dest be alive. So the regions still
merge (yielding diagnostics for later uses).

It also required me to make it so that PartitionOp::{Assign,Merge} do not
require by default. Instead, we want the individual operations to always emit a
PartitionOp::Require explicitly (which they already did).

One thing to be aware of is that when it comes to diagnostics, we already know
how to find a temporaries original value and how to handle that. So this is the
last part of making store_borrow behave nicely.

rdar://129237675
2024-06-12 15:01:38 -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
Nate Chandler
2a5d07522d [SIL] Add extend_lifetime instruction.
It indicates that the value's lifetime continues to at least this point.
The boundary formed by all consuming uses together with these
instructions will encompass all uses of the value.
2024-06-05 16:28:26 -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
b7249e7e2f [region-isolation] Rather than considering the callee as part of an applies merged region as a value, just propagate its isolation.
The reason that I am doing this is it ensures that if we have a region isolation
merge failure due to a mismatch in between the actual args in the region and the
propagated callee isolation, we see it immediately when we translate the apply
into the pseudo-IR instead of later when we perform the actual diagnostic
emission. This makes it far easier to diagnose these issues since we get an
unknown pattern very early which can be asserted on via the option
-sil-region-isolation-assert-on-unknown-pattern.
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
1bef011e48 [region-isolation] Add the ability for the analysis to emit "unknown error" partition ops in case we detect a case we cannot pattern match.
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.
2024-05-27 21:42:04 -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