Commit Graph

720 Commits

Author SHA1 Message Date
Michael Gottesman
72eb5e2eec [move-operator] Specify if LexicalLifetimes is enabled using an enum instead of a bool.
The reason why I am doing this is that we are going to be enabling lexical
lifetimes early in the pipeline so that I can use it for the move operator's
diagnostics.

To make it easy for passes to know whether or not they should support lexical
lifetimes, I included a query on SILOptions called
supportsLexicalLifetimes. This will return true if the pass (given the passed in
option) should insert the lexical lifetime flag. This ensures that passes that
run in both pipelines (e.x.: AllocBoxToStack) know whether or not to set the
lexical lifetime flag without having to locally reason about it.

This is just chopping off layers of a larger patch I am upstreaming.

NOTE: This is technically NFC since it leaves the default alone of not inserting
lexical lifetimes at all.
2021-11-15 13:47:22 -08:00
Michael Gottesman
e5d0f386e4 [moveOnly] Add a new experimental move only checker that checks noImplicitCopy variables.
NOTE: This is only available when the flag -enable-experimental-move-only. There
are no effects when the flag is disabled.

The way that this works is that it takes advantage of the following changes to
SILGen emission:

* When SILGen initializes a let with NoImplicitCopyAttribute, SILGen now emits
a begin_borrow [lexical] + copy + move_only. This is a pattern that we can check
and know that we are processing a move only value. When performing move
checking, we check move_only as a move only value and that it isn't consumed
multiple times.

* The first point works well for emitting all diagnostics except for
initializing an additional let var. To work around that I changed let
initialization to always bind to an owned value to a move of that owned
value. There is no semantic difference since that value is going to be consumed
by the binding operation anyways so we effectively just move the cleanup from
the original value we wanted to bind to the move. We still then actually borrow
the new let value with a begin_borrow [lexical] for the new let value. This
ensures that an initialization of a let value appears to be a consuming use to
the move only value checker while ensuring that the value has a proper
begin_borrow [lexical].

Some notes on functionality:

1. This attribute can only be applied to local 'let'.

2. "print" due to how we call it today with a vararg array is treated as a
   consuming use (unfortunately).

3. I have not added the builtin copy operator yet, but I recently added a _move
   skeleton attribute so one can end the lifetimes of these values early.

4. This supports all types that are not address only types (similar to
   _move). To support full on address only types we need opaque values.

rdar://83957088
2021-10-28 11:32:22 -07:00
Nate Chandler
23a9a1d4c9 Moved lexical lifetime flag to SILOptions.
Previously, the flag was a LangOptioins.  That didn't make much sense because
this isn't really a user-facing behavior.  More importantly, as a member
of that type type it couldn't be accessed when setting up pass
pipelines.  Here, the flag is moved to SILOptions.
2021-10-13 13:47:44 -07:00
Michael Gottesman
f64180870a [silgen] When initializing tuples in SILGen, first evaluate all tuple elts and then perform sub-initialization.
Previsouly we were evaluating a tuple elt and then performing the relevant
sub-initialization. The problem is that a sub-initialization can invoke code
that could perform an early exit cleanup. So any later tuple-elements that may
need to be cleaned up along such path will not have had their cleanups
initialized, resulting in a leak along such paths.

With this commit, we instead evaluate all of the tuple elements and only them
perform the sub-initialization ensuring that any early exits clean up all of the
tuple elements.

rdar://83770295
2021-10-05 14:03:49 -05:00
Michael Gottesman
49bc96dc8d Revert "[silgen] Ensure that the outer cleanup is emitted along failure paths when initializing sub-tuple patterns"
This reverts commit be922b9990.

By adding some extra scopes here we are triggering some broken behavior in a
bunch of projects. I am going to see if I can do another fix for this. That
being said in the short term, we are reverting to unblock those projects.

rdar://83770295
2021-10-01 11:51:12 -05:00
Nate Chandler
f833b68d3b [SIL] Changed spelling of lifetime flags.
Changed the frontend flag to -enable-experimental-lexical-lifetimes from
-enable-experimental-defined-lifetimes.

Changed the attribute on begin_borrow from [defined] to [lexical].
2021-09-14 08:49:30 -07:00
nate-chandler
e68b6a7f83 Merge pull request #39283 from nate-chandler/lexical_lifetimes/let/initial
[SILGen] Added [defined] lifetimes for lets behind flag.
2021-09-14 08:47:35 -07:00
Nate Chandler
a0c47cb32e [SILGen] Emitted [defined] borrow scopes for lets.
When -enable-experimental-defined-lifetimes is passed, SILGen emits
lexical scopes for lets.
2021-09-13 11:06:26 -07:00
Michael Gottesman
be922b9990 [silgen] Ensure that the outer cleanup is emitted along failure paths when initializing sub-tuple patterns
Previously, we would leak in this case along the inner failure path since we had
already forwarded the outer cleanup. Instead in this patch, I change the outer
cleanup to be persistently active (ensuring that failure paths along the
sub-pattern are cleaned up appropriately) and forward it manually afterwards
ensuring that we do not /actually/ emit the cleanup along the success path.

rdar://81817725
2021-08-24 20:56:07 -07:00
Joe Groff
fc67ba57f2 Merge pull request #37938 from jckarter/async-let-multi-suspend
Handle multiple awaits and suspend-on-exit for async let tasks.
2021-07-23 07:36:54 -07:00
Joe Groff
439edbce1f Handle multiple awaits and suspend-on-exit for async let tasks.
Change the code generation patterns for `async let` bindings to use an ABI based on the following
functions:

- `swift_asyncLet_begin`, which starts an `async let` child task, but which additionally
  now associates the `async let` with a caller-owned buffer to receive the result of the task.
  This is intended to allow the task to emplace its result in caller-owned memory, allowing the
  child task to be deallocated after completion without invalidating the result buffer.
- `swift_asyncLet_get[_throwing]`, which replaces `swift_asyncLet_wait[_throwing]`. Instead of
  returning a copy of the value, this entry point concerns itself with populating the local buffer.
  If the buffer hasn't been populated, then it awaits completion of the task and emplaces the
  result in the buffer; otherwise, it simply returns. The caller can then read the result out of
  its owned memory. These entry points are intended to be used before every read from the
  `async let` binding, after which point the local buffer is guaranteed to contain an initialized
  value.
- `swift_asyncLet_finish`, which replaces `swift_asyncLet_end`. Unlike `_end`, this variant
  is async and will suspend the parent task after cancelling the child to ensure it finishes
  before cleaning up. The local buffer will also be deinitialized if necessary. This is intended
  to be used on exit from an `async let` scope, to handle cleaning up the local buffer if necessary
  as well as cancelling, awaiting, and deallocating the child task.
- `swift_asyncLet_consume[_throwing]`, which combines `get` and `finish`. This will await completion
  of the task, leaving the result value in the result buffer (or propagating the error, if it
  throws), while destroying and deallocating the child task. This is intended as an optimization
  for reading `async let` variables that are read exactly once by their parent task.

To avoid an epoch break with existing swiftinterfaces and ABI clients, the old builtins and entry
points are kept intact for now, but SILGen now only generates code using the new interface.

This new interface fixes several issues with the old async let codegen, including use-after-free
crashes if the `async let` was never awaited, and the inability to read from an `async let` variable
more than once.

rdar://77855176
2021-07-22 10:19:31 -07:00
Bruno Rocha
1fe3857735 [SE-0290] Add #unavailable 2021-07-02 13:35:11 +02:00
Slava Pestov
62caff637a Merge pull request #37935 from slavapestov/ban-reference-to-uninitialized-box
SILGen: Don't allow referencing the 'var' box before it's fully initialized
2021-06-24 10:38:45 -04:00
Konrad `ktoso` Malawski
8536100354 [Concurrency] introduce task options, and change ABI to accept them
introduce new options parameter to all task spawning

[Concurrency] ABI for asynclet start to accept options

[Concurrency] fix unittest usages of changed task creation ABI

[Concurrency] introduce constants for parameter indexes in ownership

[Concurrency] fix test/SILOptimizer/closure_lifetime_fixup_concurrency.swift
2021-06-21 13:03:50 +09:00
Slava Pestov
2a52e4a424 SILGen: Don't allow referencing the 'var' box before it's fully initialized
In the following code, SILGen emits a mark_uninitialized instruction
on the projected box value, diagnosing the reference to 'x' before
it has been fully initialized:

    var x: Int
    x = { _ = x; 123 }()

However, when the binding has an initial value, we don't emit the
mark_uninitialized instruction, and the closure ends up capturing the
uninitialized box:

    var x: Int = { _ = x; 123 }() // undefined behavior

Unfortunately, we can't unconditionally emit a mark_uninitialized here,
because DI does not recognize all the code patterns that SILGen can emit
when initializing an address-only value in-place.

Instead, what we want to do is only enter the box into SILGenFunction::VarLocs
after the initial value expression has been emitted. This ensures that the
forward-referenced-capture diagnostics catch this.

Note that this only addresses the case of a local binding; we still
generate invalid code here if you forward-reference a global 'var' in
this manner. Fixing that requires some additional changes.

Fixes https://bugs.swift.org/browse/SR-14747, rdar://problem/77933460.
2021-06-15 19:38:37 -04:00
Doug Gregor
220e29d674 Reinstate "async let", with "spawn let" as an alias. 2021-05-07 00:13:56 -07:00
Doug Gregor
5d8174da57 [Concurrency] Introduce spawn let 2021-04-29 22:42:40 -07:00
Konrad `ktoso` Malawski
ba615029c7 [Concurrency] Store child record when async let child task spawned 2021-04-19 10:06:23 +09:00
Joe Groff
18bd2f7526 SILGen: Don't crash when compiling if #available with -disable-availability-checking.
This isn't an officially supported configuration, but is useful for testing and runtime development,
and we shouldn't crash.
2021-04-09 14:41:09 -07:00
Konrad `ktoso` Malawski
a5ac6f06fa [Concurrency] detach, spawnUnlessCancelled, priority param cleanup 2021-04-03 09:54:42 +09:00
Holly Borla
21a86b5d2f [NFC][Property Wrappers] Split PropertyWrapperBackingPropertyInfoRequest into
two separate requests - one to synthesize the auxiliary declarations, and
another to compute how the backing storage is initialized.
2021-03-19 13:03:13 -07:00
Holly Borla
0a700b7c41 [SILGen] Don't emit property wrapper generator functions for local property
wrappers with initializers. Instead, call the property wrapper initializer
directly.
2021-03-09 10:29:07 -08:00
Holly Borla
13692fefde [Property Wrappers] Store property wrapper "init from projection" expressions
in PropertyWrapperBackingPropertyInfo.
2021-02-25 18:35:14 -08:00
Slava Pestov
ed247a1fa1 Sema: Allow 'lazy' local variables 2021-02-06 08:56:38 -05:00
Slava Pestov
c2b26671db AST: Fast path to skip evaluating requests on local variables without property wrappers 2020-12-15 23:43:04 -05:00
Doug Gregor
dab6fb7098 [Concurrency] Implement SIL generation for "async let".
Implement SIL generation for "async let" constructs, which involves:

1. Creating a child task future at the point of declaration of the "async let",
which runs the initializer in an async closure.
2. Entering a cleanup to destroy the child task.
3. Entering a cleanup to cancel the child task.
4. Waiting for the child task when any of the variables is reference.
5. Decomposing the result of the child task to write the results into the
appropriate variables.

Implements rdar://71123479.
2020-11-27 22:50:39 -08:00
Doug Gregor
81f5528199 [Concurrency] More cleanups for getCurrentAsyncTask builtin.
Michael has ghostwritten all of this to address his own comments.
Thank you!
2020-11-05 12:58:03 -08:00
Doug Gregor
ed9a548c9f [Concurrency] Return getCurrentAsyncTask() as owned.
Rather than produce an "unowned" result from `getCurrentAsyncTask()`,
take advantage of the fact that the task is effectively guaranteed in
the scope. Do so be returning it as "unowned", and push an
end_lifetime cleanup to end the lifetime. This eliminates unnecessary
ref-count traffic as well as introducing another use of unowned.

Approach is thanks to Michael Gottesman, bugs are mine.
2020-11-05 12:18:49 -08:00
Michael Gottesman
f0a59a25ea [silgen] Ensure that cleanup cloner clones formal access cleanups to formal access cleanups.
This has been a long standing issue that we have been hacking around in various
points in SILGen. Now CleanupCloner just does the right thing.

I was unable to cause any issues to pop up in tree (since I believe we hacked
around this and converged on correctness). But it does come up in combination
with new code in https://github.com/apple/swift/pull/31779.

rdar://63514765
2020-10-19 14:15:48 -07:00
Slava Pestov
47e32d1e0f SILGen: Peephole Conversion::OrigToSubst / Conversion::SubstToOrig 2020-10-11 12:48:30 -04:00
Slava Pestov
5d9e704854 SILGen: Move BlackHoleInitialization to Initialization.h 2020-10-11 12:48:30 -04:00
Holly Borla
21cbdfa337 [Property Wrappers] Add a VarDecl helper method for visiting synthesized
property wrapper vars.
2020-09-28 19:31:50 -07:00
Holly Borla
b33dbedd9b [SILGen] Teach SIlGen to emit local property wrappers 2020-09-28 16:57:35 -07:00
Slava Pestov
d4cc35a938 AST: Remove VarDecl::hasNonPatternBindingInit() 2020-09-18 16:11:06 -04:00
Michael Gottesman
092edd6621 [ast] Rename VarPattern -> BindingPattern.
VarPattern is today used to implement both 'let' and 'var' pattern bindings, so
today is already misleading. The reason why the name Var was chosen was done b/c
it is meant to represent a pattern that performs 'variable binding'. Given that
I am going to add a new 'inout' pattern binding to this, it makes sense to
give it now a better fitting name before I make things more confusing.
2020-07-16 18:56:01 -07:00
Robert Widmann
426d930d10 Merge pull request #32301 from CodaFi/location-location-location
Strip TypeLoc out of Patterns
2020-06-10 19:25:56 -07:00
Vedant Kumar
60ec3f1b90 Fix debug description for cases with multiple items (#32282)
* [SILGenFunction] Don't create redundant nested debug scopes

Instead of emitting:

```
sil_scope 4 { loc "main.swift":6:19 parent 3 }
sil_scope 5 { loc "main.swift":7:3 parent 4 }
sil_scope 6 { loc "main.swift":7:3 parent 5 }
sil_scope 7 { loc "main.swift":7:3 parent 5 }
sil_scope 8 { loc "main.swift":9:5 parent 4 }
```

Emit:

```
sil_scope 4 { loc "main.swift":6:19 parent 3 }
sil_scope 5 { loc "main.swift":7:3 parent 4 }
sil_scope 6 { loc "main.swift":9:5 parent 5 }
```

* [IRGenSIL] Diagnose conflicting shadow copies

If we attempt to store a value with the wrong type into a slot reserved
for a shadow copy, diagnose what went wrong.

* [SILGenPattern] Defer debug description of case variables

Create unique nested debug scopes for a switch, each of its case labels,
and each of its case bodies. This looks like:

```
  switch ... { // Enter scope 1.
    case ... : // Enter scope 2, nested within scope 1.
      <body-1> // Enter scope 3, nested within scope 2.

    case ... : // Enter scope 4, nested within scope 1.
      <body-2> // Enter scope 5, nested within scope 4.
  }
```

Use the new scope structure to defer emitting debug descriptions of case
bindings. Specifically, defer the work until we can nest the scope for a
case body under the scope for a pattern match.

This fixes SR-7973, a problem where it was impossible to inspect a case
binding in lldb when stopped at a case with multiple items.

Previously, we would emit the debug descriptions too early (in the
pattern match), leading to duplicate/conflicting descriptions. The only
reason that the ambiguous description was allowed to compile was because
the debug scopes were nested incorrectly.

rdar://41048339

* Update tests
2020-06-10 13:31:10 -07:00
Robert Widmann
fc9070c072 Strip TypeLoc from IsPattern 2020-06-10 13:29:39 -07:00
Arnold Schwaighofer
33f4f57cc4 SILGen: Add TypeExpansionContext to SILGen 2019-11-11 14:21:52 -08:00
Robert Widmann
3b829943af Uniformly iterate over the pattern binding entry indices
Clarify a bunch of C-style for loops and remove a ton of references to getPatternList().
2019-10-17 13:39:07 -07:00
Robert Widmann
56b6e53dae Remove raw references to PatternBindingEntry APIs
Switch most callers to explicit indices.  The exceptions lie in things that needs to manipulate the parsed output directly including the Parser and components of the ASTScope.  These are included as friend class exceptions.
2019-10-17 13:31:14 -07:00
Slava Pestov
6c5ecb5fc9 AST: Introduce AbstractStorageDecl::visit{Parsed,Emitted}Accessors() 2019-08-06 16:30:13 -04:00
Slava Pestov
b18d1680b3 SILGen: Emit accessors as part of their storage
This removes an intricate set of invariants that must be kept consistent
between Parse and SILGen. It will also make it easier to implement local
variables with 'lazy' and property wrappers in the future.
2019-06-18 18:34:04 -04:00
Slava Pestov
83a3bd2f4b SILGen: Simplify delayed function emission
Just as with conformances, we can detect that a delayed function
needs to be added to the queue from 'first principles' rather than
walking the ExternalDefinitions list.

This completely eliminates the ExternalDefinitions walk from SILGen,
which has several advantages:

- It fixes a source of quadratic behavior. In batch mode, type checking
  produces a list of external definitions shared across all primary
  files. Then, SILGen runs once per primary file, building a delayed
  emission map every time.

- It allows SILGen to emit external definitions which only come into
  existence as a result of lazy conformance checking. Previously,
  anything that was added after SILGen performed its walk over the
  external definitions list would not be emitted.
2019-05-18 11:35:05 -04:00
Slava Pestov
04db869d80 SILGen: Simplify delayed conformance emission
Instead of visiting all types in the ExternalDefinitions list and
queuing up their conformances, just emit conformances as needed
when they are first referenced.
2019-05-18 11:35:05 -04:00
Michael Gottesman
dccd6eb0d6 [silgen] Change ManagedValue::copyInto to have same paramter order as ManagedValue::{forward,assign}Into.
ManagedValue::{forward,assign}Into both have the signature SILGenFunction &,
SILLocation, SILValue. For some reason copyInto has SILLocation and SILValue
swapped. This commit standardizes copyInto to match the others.
2019-05-15 13:47:39 -07:00
Jordan Rose
c506747a9c [Serialization] Drop inherited conformances on classes (#23347)
These can be recreated if needed in a client library. To do this, I've
added a new ConformanceLookupKind::NonInherited, which can also be
used elsewhere in the project where we're already filtering out
inherited conformances some other way.

Note that this doesn't drop inherited conformances from the entire
serialized interface, just from the list that a class explicitly
declares. They still get referenced sometimes.

rdar://problem/50541451 and possibly others
2019-05-13 13:41:10 -07:00
Slava Pestov
16d5716e71 SIL: Use the best resilience expansion when lowering types
This is a large patch; I couldn't split it up further while still
keeping things working. There are four things being changed at
once here:

- Places that call SILType::isAddressOnly()/isLoadable() now call
  the SILFunction overload and not the SILModule one.

- SILFunction's overloads of getTypeLowering() and getLoweredType()
  now pass the function's resilience expansion down, instead of
  hardcoding ResilienceExpansion::Minimal.

- Various other places with '// FIXME: Expansion' now use a better
  resilience expansion.

- A few tests were updated to reflect SILGen's improved code
  generation, and some new tests are added to cover more code paths
  that previously were uncovered and only manifested themselves as
  standard library build failures while I was working on this change.
2019-04-26 22:47:59 -04:00
Slava Pestov
6c04a7acb1 SILGen: Lazily emit ClangImporter-synthesized conformances even when they're incomplete
Currently Sema completes all _ObjectiveCBridgeable conformances it thinks
are needed in SILGen and runtime dynamic casts, but that's about to change.

When emitting conformances for an imported type we would skip incomplete
conformances. Now that we have a long-lived type checker instance, there
is no longer any reason to do that. Looking up witnesses from an
incomplete conformance will trigger conformance checking as needed.

Furthermore, conformances emitted in this path are emitted lazily, so if
a conformance is not used, no conformance checking will take place.

A change in behavior only occurs after subsequent changes to remove Sema's
eager checking of ClangImporter-synthesized _ObjectiveCBridgeable
conformances; at that point, we must be prepared to lazily emit these
incomplete conformances.
2019-04-25 22:29:37 -04:00
Slava Pestov
472787bab7 SIL: isNonThrowing parameter of SILBuilder::create{Begin,}Apply() defaults to false
Also remove the overload of createApply() that does not take a SubstitutionMap.
It accomplishes nothing except creating ambiguity.
2019-04-25 22:27:38 -04:00