@@ -5537,6 +5537,96 @@ static unsigned functionParameterArity(AnyFunctionType::Param param) {
5537
5537
return paramType->castTo <AnyFunctionType>()->getNumParams ();
5538
5538
}
5539
5539
5540
+ // / Attach a Fix-It to the given diagnostic to give the trailing closure
5541
+ // / argument a label.
5542
+ static void labelTrailingClosureArgument (
5543
+ ASTContext &ctx, Expr *fn, Expr *arg, Identifier paramName,
5544
+ Expr *trailingClosure, InFlightDiagnostic &diag) {
5545
+ // Dig out source locations.
5546
+ SourceLoc existingRParenLoc;
5547
+ SourceLoc leadingCommaLoc;
5548
+ if (auto tupleExpr = dyn_cast<TupleExpr>(arg)) {
5549
+ existingRParenLoc = tupleExpr->getRParenLoc ();
5550
+ assert (tupleExpr->getNumElements () >= 2 && " Should be a ParenExpr?" );
5551
+ leadingCommaLoc = Lexer::getLocForEndOfToken (
5552
+ ctx.SourceMgr ,
5553
+ tupleExpr->getElements ()[tupleExpr->getNumElements ()-2 ]->getEndLoc ());
5554
+ } else {
5555
+ auto parenExpr = cast<ParenExpr>(arg);
5556
+ existingRParenLoc = parenExpr->getRParenLoc ();
5557
+ }
5558
+
5559
+ // Figure out the text to be inserted before the trailing closure.
5560
+ SmallString<16 > insertionText;
5561
+ SourceLoc insertionLoc;
5562
+ if (leadingCommaLoc.isValid ()) {
5563
+ insertionText += " , " ;
5564
+ assert (existingRParenLoc.isValid ());
5565
+ insertionLoc = leadingCommaLoc;
5566
+ } else if (existingRParenLoc.isInvalid ()) {
5567
+ insertionText += " (" ;
5568
+ insertionLoc = Lexer::getLocForEndOfToken (
5569
+ ctx.SourceMgr , fn->getEndLoc ());
5570
+ } else {
5571
+ insertionLoc = existingRParenLoc;
5572
+ }
5573
+
5574
+ // Add the label, if there is one.
5575
+ if (!paramName.empty ()) {
5576
+ insertionText += paramName.str ();
5577
+ insertionText += " : " ;
5578
+ }
5579
+
5580
+ // If there is an existing right parentheses, remove it while we
5581
+ // insert the new text.
5582
+ if (existingRParenLoc.isValid ()) {
5583
+ SourceLoc afterExistingRParenLoc = Lexer::getLocForEndOfToken (
5584
+ ctx.SourceMgr , existingRParenLoc);
5585
+ diag.fixItReplaceChars (
5586
+ insertionLoc, afterExistingRParenLoc, insertionText);
5587
+ } else {
5588
+ // Insert the appropriate prefix.
5589
+ diag.fixItInsert (insertionLoc, insertionText);
5590
+ }
5591
+
5592
+ // Insert a right parenthesis after the closing '}' of the trailing closure;
5593
+ SourceLoc newRParenLoc = Lexer::getLocForEndOfToken (
5594
+ ctx.SourceMgr , trailingClosure->getEndLoc ());
5595
+ diag.fixItInsert (newRParenLoc, " )" );
5596
+ }
5597
+
5598
+ // / Find the trailing closure argument of a tuple or parenthesized expression.
5599
+ // /
5600
+ // / Due to a quirk of the backward scan that could allow reordering of
5601
+ // / arguments in the presence of a trailing closure, it might not be the last
5602
+ // / argument in the tuple.
5603
+ static Expr *findTrailingClosureArgument (Expr *arg) {
5604
+ if (auto parenExpr = dyn_cast<ParenExpr>(arg)) {
5605
+ return parenExpr->getSubExpr ();
5606
+ }
5607
+
5608
+ auto tupleExpr = cast<TupleExpr>(arg);
5609
+ SourceLoc endLoc = tupleExpr->getEndLoc ();
5610
+ for (Expr *elt : llvm::reverse (tupleExpr->getElements ())) {
5611
+ if (elt->getEndLoc () == endLoc)
5612
+ return elt;
5613
+ }
5614
+
5615
+ return tupleExpr->getElements ().back ();
5616
+ }
5617
+
5618
+ // / Find the index of the parameter that binds the given argument.
5619
+ static unsigned findParamBindingArgument (
5620
+ ArrayRef<ParamBinding> parameterBindings, unsigned argIndex) {
5621
+ for (unsigned paramIdx : indices (parameterBindings)) {
5622
+ if (llvm::find (parameterBindings[paramIdx], argIndex)
5623
+ != parameterBindings[paramIdx].end ())
5624
+ return paramIdx;
5625
+ }
5626
+
5627
+ llvm_unreachable (" No parameter binds the argument?" );
5628
+ }
5629
+
5540
5630
// / SE-0286 changed the direction in which the unlabeled trailing closure
5541
5631
// / argument is matched to a parameter, from backward (the pre-Swift 5.3
5542
5632
// / semantics) to forward (after SE-0286). Identify cases where this may
@@ -5558,13 +5648,8 @@ static void maybeWarnAboutTrailingClosureBindingChange(
5558
5648
return ;
5559
5649
5560
5650
// Find the parameter that bound the unlabeled trailing closure argument.
5561
- unsigned paramIdx;
5562
- for (paramIdx = 0 ; paramIdx != parameterBindings.size (); ++paramIdx) {
5563
- if (llvm::find (parameterBindings[paramIdx], *unlabeledTrailingClosureIndex)
5564
- != parameterBindings[paramIdx].end ())
5565
- break ;
5566
- }
5567
- assert (paramIdx != parameterBindings.size () && " Unbound trailing closure!" );
5651
+ unsigned paramIdx = findParamBindingArgument (
5652
+ parameterBindings, *unlabeledTrailingClosureIndex);
5568
5653
5569
5654
// If this parameter requires an argument, it would have been unfilled
5570
5655
// prior to SE-2086; there is nothing to diagnose.
@@ -5594,30 +5679,16 @@ static void maybeWarnAboutTrailingClosureBindingChange(
5594
5679
functionParameterArity (params[*matchingBackwardParamIdx]))
5595
5680
return ;
5596
5681
5597
- // Compute the various source locations where diagnostics will occur.
5598
- ASTContext &ctx = params[paramIdx].getPlainType ()->getASTContext ();
5599
- Expr *trailingClosure;
5600
- SourceLoc existingRParenLoc;
5601
- SourceLoc leadingCommaLoc;
5602
- if (auto tupleExpr = dyn_cast<TupleExpr>(arg)) {
5603
- trailingClosure = tupleExpr->getElements ().back ();
5604
- existingRParenLoc = tupleExpr->getRParenLoc ();
5605
- assert (tupleExpr->getNumElements () >= 2 && " Should be a ParenExpr?" );
5606
- leadingCommaLoc = Lexer::getLocForEndOfToken (
5607
- ctx.SourceMgr ,
5608
- tupleExpr->getElements ()[tupleExpr->getNumElements ()-2 ]->getEndLoc ());
5609
- } else {
5610
- auto parenExpr = cast<ParenExpr>(arg);
5611
- trailingClosure = parenExpr->getSubExpr ();
5612
- existingRParenLoc = parenExpr->getRParenLoc ();
5613
- }
5682
+ // Dig out the trailing closure.
5683
+ Expr *trailingClosure = findTrailingClosureArgument (arg);
5614
5684
5615
5685
// Determine the names of the parameters that would be matched by the
5616
5686
// forward and backward scans.
5617
5687
Identifier paramName = params[paramIdx].getLabel ();
5618
5688
Identifier backwardParamName = params[*matchingBackwardParamIdx].getLabel ();
5619
5689
5620
5690
// Produce a diagnostic referencing the callee.
5691
+ ASTContext &ctx = params[paramIdx].getPlainType ()->getASTContext ();
5621
5692
auto noteCallee = [&] {
5622
5693
auto decl = callee.getDecl ();
5623
5694
if (!decl)
@@ -5653,45 +5724,8 @@ static void maybeWarnAboutTrailingClosureBindingChange(
5653
5724
auto diag = ctx.Diags .diagnose (
5654
5725
trailingClosure->getStartLoc (), diag::trailing_closure_select_parameter,
5655
5726
paramName, which);
5656
-
5657
- // Figure out the text to be inserted before the trailing closure.
5658
- SmallString<16 > insertionText;
5659
- SourceLoc insertionLoc;
5660
- if (leadingCommaLoc.isValid ()) {
5661
- insertionText += " , " ;
5662
- assert (existingRParenLoc.isValid ());
5663
- insertionLoc = leadingCommaLoc;
5664
- } else if (existingRParenLoc.isInvalid ()) {
5665
- insertionText += " (" ;
5666
- insertionLoc = Lexer::getLocForEndOfToken (
5667
- ctx.SourceMgr , fn->getEndLoc ());
5668
- } else {
5669
- insertionLoc = existingRParenLoc;
5670
- }
5671
-
5672
- // Add the label, if there is one.
5673
- if (!paramName.empty ()) {
5674
- insertionText += paramName.str ();
5675
- insertionText += " : " ;
5676
- }
5677
-
5678
- // If there is an existing right parentheses, remove it while we
5679
- // insert the new text.
5680
- if (existingRParenLoc.isValid ()) {
5681
- SourceLoc afterExistingRParenLoc = Lexer::getLocForEndOfToken (
5682
- ctx.SourceMgr , existingRParenLoc);
5683
- diag.fixItReplaceChars (
5684
- insertionLoc, afterExistingRParenLoc, insertionText);
5685
- } else {
5686
- // Insert the appropriate prefix.
5687
- diag.fixItInsert (insertionLoc, insertionText);
5688
- }
5689
-
5690
-
5691
- // Insert a right parenthesis after the closing '}' of the trailing closure;
5692
- SourceLoc newRParenLoc = Lexer::getLocForEndOfToken (
5693
- ctx.SourceMgr , trailingClosure->getEndLoc ());
5694
- diag.fixItInsert (newRParenLoc, " )" );
5727
+ labelTrailingClosureArgument (
5728
+ ctx, fn, arg, paramName, trailingClosure, diag);
5695
5729
};
5696
5730
5697
5731
diagResolution (backwardParamName, 0 );
@@ -5700,6 +5734,34 @@ static void maybeWarnAboutTrailingClosureBindingChange(
5700
5734
noteCallee ();
5701
5735
}
5702
5736
5737
+ // / Warn about the use of the deprecated "backward" scan for matching the
5738
+ // / unlabeled trailing closure. It was needed to properly type check, but
5739
+ // / this code will break with a future version of Swift.
5740
+ static void warnAboutTrailingClosureBackwardScan (
5741
+ ConcreteDeclRef callee, Expr *fn, Expr *arg,
5742
+ ArrayRef<AnyFunctionType::Param> params,
5743
+ Optional<unsigned > unlabeledTrailingClosureIndex,
5744
+ ArrayRef<ParamBinding> parameterBindings) {
5745
+
5746
+ Expr *trailingClosure = findTrailingClosureArgument (arg);
5747
+ unsigned paramIdx = findParamBindingArgument (
5748
+ parameterBindings, *unlabeledTrailingClosureIndex);
5749
+ ASTContext &ctx = params[paramIdx].getPlainType ()->getASTContext ();
5750
+ Identifier paramName = params[paramIdx].getLabel ();
5751
+
5752
+ {
5753
+ auto diag = ctx.Diags .diagnose (
5754
+ trailingClosure->getStartLoc (),
5755
+ diag::unlabeled_trailing_closure_deprecated, paramName);
5756
+ labelTrailingClosureArgument (
5757
+ ctx, fn, arg, paramName, trailingClosure, diag);
5758
+ }
5759
+
5760
+ if (auto decl = callee.getDecl ()) {
5761
+ ctx.Diags .diagnose (decl, diag::decl_declared_here, decl->getName ());
5762
+ }
5763
+ }
5764
+
5703
5765
Expr *ExprRewriter::coerceCallArguments (
5704
5766
Expr *arg, AnyFunctionType *funcType,
5705
5767
ConcreteDeclRef callee,
@@ -5790,9 +5852,15 @@ Expr *ExprRewriter::coerceCallArguments(
5790
5852
5791
5853
// Warn if there was a recent change in trailing closure binding semantics
5792
5854
// that might have lead to a silent change in behavior.
5793
- maybeWarnAboutTrailingClosureBindingChange (
5794
- callee, apply ? apply->getFn () : nullptr , arg, args, params, paramInfo,
5795
- unlabeledTrailingClosureIndex, parameterBindings);
5855
+ if (trailingClosureMatching == TrailingClosureMatching::Forward) {
5856
+ maybeWarnAboutTrailingClosureBindingChange (
5857
+ callee, apply ? apply->getFn () : nullptr , arg, args, params, paramInfo,
5858
+ unlabeledTrailingClosureIndex, parameterBindings);
5859
+ } else {
5860
+ warnAboutTrailingClosureBackwardScan (
5861
+ callee, apply ? apply->getFn () : nullptr , arg, params,
5862
+ unlabeledTrailingClosureIndex, parameterBindings);
5863
+ }
5796
5864
5797
5865
SourceLoc lParenLoc, rParenLoc;
5798
5866
if (argTuple) {
0 commit comments