Skip to content

[6.2] Allow passing MutableSpan 'inout' without an experimental feature. #81657

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

Merged
merged 3 commits into from
May 21, 2025

Conversation

atrick
Copy link
Contributor

@atrick atrick commented May 20, 2025

This adds a new lifetime inference rule, loosening the requirement for @Lifetime
annotations even when the experimental LifetimeDependence mode is
enabled. Additionally, it enables this new inference rule even when the
experimental mode is disabled. All other inference rules continue to require the
experimental feature. The rule is:

If a function or method has a single inout non-Escapable parameter other than
'self' and has no other non-Escapable parameters including 'self', then infer a
single @Lifetime(copy) dependency on the inout parameter from its own incoming
value.

This supports the common case in which the user of a non-Escapable type,
such as MutableSpan, wants to modify the span's contents without modifying
the span value itself. It should be possible to use MutableSpan this way
without requiring any knowledge of lifetime annotations. The tradeoff is
that it makes authoring non-Escapable types less safe. For example, a
MutableSpan method could update the underlying unsafe pointer and forget to
declare a dependence on the incoming pointer.

Disallowing other non-Escapable parameters rules out the easy mistake of
programmers attempting to trivially reassign the inout parameter. There's
is no way to rule out the possibility that they derive another
non-Escapable value from an Escapable parameteter. So users can still write
the following:

func reassign(s: inout MutableSpan<Int>, a: [Int]) {
  s = a.mutableSpan
}

The 'reassign' declaration will type check, but it's implementation will
diagnose a lifetime error on 's'.

Fixes rdar://150557314 ([nonescapable] Declaration of inout MutableSpan
parameter requires LifetimeDependence experimental feature)

(cherry picked from commit dbcba01)

main PR: #81656

--- CCC ---

Explanation: Enable limited lifetime inference when the experimental LifetimeDependence feature is disabled. This is necessary for MutableSpan usability. Otherwise, it is impossible to pass the mutable span into a function and mutate its elements!

Radar/SR Issue: rdar://150557314 ([nonescapable] Declaration of inout MutableSpan
parameter requires LifetimeDependence experimental feature)

main PR: #81656

Risks: (1) this runs a small amount of type checking code now by default that was previously guarded by a feature flag. This only affects usage od ~Escapable types. (2) this triggers the declaration checker in an arbitrarily different order which can slightly change the diagnostic output for invalid declarations.

Testing: I added unit tests for both pass and fail diagnostics both with and without the exerimental feature.

Reviewer: Doug Gregor

@atrick atrick requested a review from a team as a code owner May 20, 2025 23:59
@atrick atrick added 🍒 release cherry pick Flag: Release branch cherry picks swift 6.2 labels May 20, 2025
@atrick atrick requested review from DougGregor, meg-gupta and tbkka May 21, 2025 00:02
@atrick
Copy link
Contributor Author

atrick commented May 21, 2025

@swift-ci test

atrick added 3 commits May 21, 2025 00:14
This adds a new lifetime inference rule, loosening the requirement for @Lifetime
annotations even when the experimental LifetimeDependence mode is
enabled. Additionally, it enables this new inference rule even when the
experimental mode is disabled. All other inference rules continue to require the
experimental feature. The rule is:

If a function or method has a single inout non-Escapable parameter other than
'self' and has no other non-Escapable parameters including 'self', then infer a
single @Lifetime(copy) dependency on the inout parameter from its own incoming
value.

This supports the common case in which the user of a non-Escapable type,
such as MutableSpan, wants to modify the span's contents without modifying
the span value itself. It should be possible to use MutableSpan this way
without requiring any knowledge of lifetime annotations. The tradeoff is
that it makes authoring non-Escapable types less safe. For example, a
MutableSpan method could update the underlying unsafe pointer and forget to
declare a dependence on the incoming pointer.

Disallowing other non-Escapable parameters rules out the easy mistake of
programmers attempting to trivially reassign the inout parameter. There's
is no way to rule out the possibility that they derive another
non-Escapable value from an Escapable parameteter. So users can still write
the following:

    func reassign(s: inout MutableSpan<Int>, a: [Int]) {
      s = a.mutableSpan
    }

The 'reassign' declaration will type check, but it's implementation will
diagnose a lifetime error on 's'.

Fixes rdar://150557314 ([nonescapable] Declaration of inout MutableSpan
parameter requires LifetimeDependence experimental feature)

(cherry picked from commit dbcba01)
When reporting the declarations that lead to a cycle, we end up printing an
extra "through reference here" on the function declaration:

class C2: C1, P {
   |       |- note: through reference here
   |       `- note: through reference here
15 |     // expected-note@-1 2{{through reference here}}
16 |     override func run(a: A) {}
   |                   |   |  `- note: while resolving type 'A'
   |                   |   `- note: through reference here
   |                   |- error: circular reference
   |                   |- note: through reference here
   |                   `- note: through reference here

(cherry picked from commit b71cc44)
Evaluating LifetimeDependence changes the order that the declarations are
diagnosed. Fix this test output by flipping the order of two declarations. The
new order actually makes more sense to me.

(cherry picked from commit c40fd2a)
@atrick atrick force-pushed the 62-lifedep-inout-infer branch from 6afec87 to 818b38b Compare May 21, 2025 07:15
@atrick
Copy link
Contributor Author

atrick commented May 21, 2025

@swift-ci test

@atrick
Copy link
Contributor Author

atrick commented May 21, 2025

Windows: ModuleInterface/swift_build_sdk_interfaces/find-modules.test-sh' FAILED

@atrick
Copy link
Contributor Author

atrick commented May 21, 2025

@swift-ci test windows

@atrick atrick enabled auto-merge May 21, 2025 16:16
@atrick atrick merged commit 9e02af8 into swiftlang:release/6.2 May 21, 2025
5 checks passed
@atrick atrick deleted the 62-lifedep-inout-infer branch May 21, 2025 22:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🍒 release cherry pick Flag: Release branch cherry picks swift 6.2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants