Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Concurrency] Introduce "ConcurrentValue" protocol and checking. #35264

Merged
merged 10 commits into from
Feb 5, 2021

Conversation

DougGregor
Copy link
Member

@DougGregor DougGregor commented Jan 5, 2021

This pull request introduces the ConcurrentValue protocol, which
describes types for which it is safe to use different copies of a value
concurrently. Value-semantic types, immutable types, and types that
have internal synchronization can all conform to ConcurrentValue.

A value of a non-ConcurrentValue type cannot be transferred
into a separate isolation domain. For example, they cannot be used
in a call to an actor-isolated function on a different actor. Similarly,
a local variable of non-ConcurrentValue type cannot be captured
in a closure that executes concurrently with the function in which
the local variable was declared. The actor-isolation and capture
checking rules have been adjusted accordingly.

Structural types are treated as conforming to ConcurrentValue in
certain cases, although we don't form proper conformances just yet:

  • Metatypes always conform to ConcurrentValue.
  • @concurrent function types conform to ConcurrentValue;
    their parameter and result types must also conform to ConcurrentValue
  • Tuples conform to ConcurrentValue if all element types conform to
    ConcurrentValue.

Nominal types can declare conformance to ConcurrentValue explicitly.
That conformance is checked to ensure that none of the state of the
type lacks a conformance to ConcurrentValue:

  • For structs, check that each stored property conforms to ConcurrentValue
  • For enums, check that each associated value conforms to ConcurrentValue
  • For classes, check that each stored property is immutable and conforms
    to ConcurrentValue

Because all of the stored properties / associated values need to be
visible for this check to work, limit ConcurrentValue conformances to
be in the same source file as the type definition.

This checking can be disabled by conforming to a new marker protocol,
UnsafeConcurrentValue, that inherits ConcurrentValue.
UnsafeConcurrentValue otherwise his no specific meaning. This allows
both "I know what I'm doing" for types that manage concurrent access
themselves as well as enabling retroactive conformance, both of which
are fundamentally unsafe but also quite necessary.

Roll out ConcurrentValue conformances throughout the standard library,
which both makes a lot of code "just work" and also provides out the
effectiveness of the checking and the model.

The checking for ConcurrentValue conformances is always enabled, since
there is no code using this protocol. However, all of the other diagnostics
related to ConcurrentValue checking are staged in as warnings behind a
flag -Xfrontend -enable-experimental-concurrent-value-checking.

The ConcurrentValue protocol indicates when a particular type is safe
to share in a concurrent context, e.g., that a copy of a given value
can be safely used concurrently with the value.
By making ConcurrentValue a marker protocol, it no longer has any ABI
impact whatsoever. Sink it down into the Standard Library so it's
easier to use, even from code that isn't building with concurrency
enabled.
When referring to an actor-isolated declaration from outside of the
actor, ensure that the types involved conform to the `ConcurrentValue`
protocol. Otherwise, produce a diagnostic stating that it is unsafe to
pass such types across actors.

Apply the same rule to local captures within concurrent code.
Introduce checking of ConcurrentValue conformances:
- For structs, check that each stored property conforms to ConcurrentValue
- For enums, check that each associated value conforms to ConcurrentValue
- For classes, check that each stored property is immutable and conforms
  to ConcurrentValue

Because all of the stored properties / associated values need to be
visible for this check to work, limit ConcurrentValue conformances to
be in the same source file as the type definition.

This checking can be disabled by conforming to a new marker protocol,
UnsafeConcurrentValue, that refines ConcurrentValue.
UnsafeConcurrentValue otherwise his no specific meaning. This allows
both "I know what I'm doing" for types that manage concurrent access
themselves as well as enabling retroactive conformance, both of which
are fundamentally unsafe but also quite necessary.

The bulk of this change ended up being to the standard library, because
all conformances of standard library types to the ConcurrentValue
protocol needed to be sunk down into the standard library so they
would benefit from the checking above. There were numerous little
mistakes in the initial pass through the stsandard library types that
have now been corrected.
@DougGregor
Copy link
Member Author

@swift-ci please test

@DougGregor
Copy link
Member Author

@swift-ci build toolchain

@swift-ci
Copy link
Contributor

swift-ci commented Feb 4, 2021

Build failed
Swift Test Linux Platform
Git Sha - 1a1f79c

@swift-ci
Copy link
Contributor

swift-ci commented Feb 4, 2021

Build failed
Swift Test OS X Platform
Git Sha - 1a1f79c

@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please build toolchain

@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please build toolchain

@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please build toolchain

1 similar comment
@DougGregor
Copy link
Member Author

@swift-ci please build toolchain

@DougGregor DougGregor changed the title [Experiment] [Concurrency] Introduce "ConcurrentValue" protocol and checking. [Concurrency] Introduce "ConcurrentValue" protocol and checking. Feb 5, 2021
@DougGregor
Copy link
Member Author

Merging to start staging this in, since everything is behind a flag anyway.

@DougGregor DougGregor merged commit 06dc593 into swiftlang:main Feb 5, 2021
@DougGregor DougGregor deleted the concurrent-value-protocol branch February 5, 2021 18:28
@swift-ci
Copy link
Contributor

swift-ci commented Feb 5, 2021

Linux Toolchain (Ubuntu 16.04)
Download Toolchain
Git Sha - 6fa673d

Install command
tar zxf swift-PR-35264-544-ubuntu16.04.tar.gz
More info

@swift-ci
Copy link
Contributor

swift-ci commented Feb 5, 2021

macOS Toolchain
Download Toolchain
Git Sha - 6fa673d

Install command
tar -zxf swift-PR-35264-860-osx.tar.gz --directory ~/

lorentey added a commit to lorentey/swift that referenced this pull request Mar 31, 2021
This extension (introduced in swiftlang#35264) was placed in a file location where it wasn’t correctly guarded against mentioning Float16 on macOS/x86_64, so the generated .swiftinterface file included a reference to an unavailable declaration. (The dummy stand-in Float16 type that we currently use on Intel macOS.)

Moving the declaration out of the “AnyHashable” section and into a file region that’s more suitable for it (i.e., enclosed in `#if !((os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64))`) resolves the issue.

rdar://76025365
@kirilltitov
Copy link

kirilltitov commented Apr 30, 2021

Any progress on @unchecked attribute?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants