Commit Graph

6 Commits

Author SHA1 Message Date
Holly Borla
f1cd9cb422 [Test] Remove REQUIRES: asserts from tests that use -swift-version 6. 2024-02-13 07:13:35 -08:00
Doug Gregor
725624fc1b [SE-0286] Disable backward scanning for trailing closures in Swift 6 mode. 2021-08-18 05:54:54 -07:00
Doug Gregor
25d40125e9 [Trailing closures] Bias toward the backward scan for ambiguities.
This approach, suggested by Xiaodi Wu, provides better source
compatibility for existing Swift code, by breaking ties in favor of the
existing Swift semantics. Each time the backward-scan rule is needed
(and differs from the forward-scan result), we will produce a warning
+ Fix-It to prepare for Swift 6 where the backward rule can be
removed.
2020-07-24 08:47:51 -07:00
Doug Gregor
4acb094677 Fix a NULL pointer dereference and update test cases. 2020-07-24 08:11:25 -07:00
Doug Gregor
563ce3cd1d [Trailing closures] Allow the unlabeled closure for variadic closure parameters.
Once the first argument for a variadic function-typed parameter has been
matched, allow an unlabeled trailing closure to match, rather than
banning all uses of the unlabeled trailing closure with variadic
parameters.
2020-07-24 08:10:00 -07:00
Doug Gregor
ed541f32e3 Forward matching of trailing closure arguments.
Introsuce a new "forward" algorithm for trailing closures where
the unlabeled trailing closure argument matches the next parameter in
the parameter list that can accept an unlabeled trailing closure.

The "can accept an unlabeled trailing closure" criteria looks at the
parameter itself. The parameter accepts an unlabeled trailing closure
if all of the following are true:

* The parameter is not 'inout'
* The adjusted type of the parameter (defined below) is a function type

The adjusted type of the parameter is the parameter's type as
declared, after performing two adjustments:

* If the parameter is an @autoclosure, use the result type of the
parameter's declared (function) type, before performing the second
adjustment.
* Remove all outer "optional" types.

For example, the following function illustrates both adjustments to
determine that the parameter "body" accepts an unlabeled trailing
closure:

    func doSomething(body: @autoclosure () -> (((Int) -> String)?))

This is a source-breaking change. However, there is a "fuzzy" matching
rule that that addresses the source break we've observed in practice,
where a defaulted closure parameter precedes a non-defaulted closure
parameter:

    func doSomethingElse(
       onError: ((Error) -> Void)? = nil,
       onCompletion: (Int) -> Void
    ) { }

    doSomethingElse { x in
      print(x)
    }

With the existing "backward" scan rule, the trailing closure matches
onCompletion, and onError is given the default of "nil". With the
forward scanning rule, the trailing closure matches onError, and there
is no "onCompletion" argument, so the call fails.

The fuzzy matching rule proceeds as follows:
* if the call has a single, unlabeled trailing closure argument, and
* the parameter that would match the unlabeled trailing closure
argument has a default, and
* there are parameters *after* that parameter that require an argument
(i.e., they are not variadic and do not have a default argument)

then the forward scan skips this parameter and considers the next
parameter that could accept the unlabeled trailing closure.

Note that APIs like doSomethingElse(onError:onCompletion:) above
should probably be reworked to put the defaulted parameters at the
end, which works better with the forward scan and with multiple
trailing closures:

    func doSomethingElseBetter(
       onCompletion: (Int) -> Void,
       onError: ((Error) -> Void)? = nil
    ) { }

    doSomethingElseBetter { x in
      print(x)
    }

    doSomethingElseBetter { x in
      print(x)
    } onError: { error in
      throw error
    }
2020-07-24 08:10:00 -07:00