@@ -5471,6 +5471,96 @@ static unsigned functionParameterArity(AnyFunctionType::Param param) {
5471
5471
return paramType->castTo <AnyFunctionType>()->getNumParams ();
5472
5472
}
5473
5473
5474
+ // / Attach a Fix-It to the given diagnostic to give the trailing closure
5475
+ // / argument a label.
5476
+ static void labelTrailingClosureArgument (
5477
+ ASTContext &ctx, Expr *fn, Expr *arg, Identifier paramName,
5478
+ Expr *trailingClosure, InFlightDiagnostic &diag) {
5479
+ // Dig out source locations.
5480
+ SourceLoc existingRParenLoc;
5481
+ SourceLoc leadingCommaLoc;
5482
+ if (auto tupleExpr = dyn_cast<TupleExpr>(arg)) {
5483
+ existingRParenLoc = tupleExpr->getRParenLoc ();
5484
+ assert (tupleExpr->getNumElements () >= 2 && " Should be a ParenExpr?" );
5485
+ leadingCommaLoc = Lexer::getLocForEndOfToken (
5486
+ ctx.SourceMgr ,
5487
+ tupleExpr->getElements ()[tupleExpr->getNumElements ()-2 ]->getEndLoc ());
5488
+ } else {
5489
+ auto parenExpr = cast<ParenExpr>(arg);
5490
+ existingRParenLoc = parenExpr->getRParenLoc ();
5491
+ }
5492
+
5493
+ // Figure out the text to be inserted before the trailing closure.
5494
+ SmallString<16 > insertionText;
5495
+ SourceLoc insertionLoc;
5496
+ if (leadingCommaLoc.isValid ()) {
5497
+ insertionText += " , " ;
5498
+ assert (existingRParenLoc.isValid ());
5499
+ insertionLoc = leadingCommaLoc;
5500
+ } else if (existingRParenLoc.isInvalid ()) {
5501
+ insertionText += " (" ;
5502
+ insertionLoc = Lexer::getLocForEndOfToken (
5503
+ ctx.SourceMgr , fn->getEndLoc ());
5504
+ } else {
5505
+ insertionLoc = existingRParenLoc;
5506
+ }
5507
+
5508
+ // Add the label, if there is one.
5509
+ if (!paramName.empty ()) {
5510
+ insertionText += paramName.str ();
5511
+ insertionText += " : " ;
5512
+ }
5513
+
5514
+ // If there is an existing right parentheses, remove it while we
5515
+ // insert the new text.
5516
+ if (existingRParenLoc.isValid ()) {
5517
+ SourceLoc afterExistingRParenLoc = Lexer::getLocForEndOfToken (
5518
+ ctx.SourceMgr , existingRParenLoc);
5519
+ diag.fixItReplaceChars (
5520
+ insertionLoc, afterExistingRParenLoc, insertionText);
5521
+ } else {
5522
+ // Insert the appropriate prefix.
5523
+ diag.fixItInsert (insertionLoc, insertionText);
5524
+ }
5525
+
5526
+ // Insert a right parenthesis after the closing '}' of the trailing closure;
5527
+ SourceLoc newRParenLoc = Lexer::getLocForEndOfToken (
5528
+ ctx.SourceMgr , trailingClosure->getEndLoc ());
5529
+ diag.fixItInsert (newRParenLoc, " )" );
5530
+ }
5531
+
5532
+ // / Find the trailing closure argument of a tuple or parenthesized expression.
5533
+ // /
5534
+ // / Due to a quirk of the backward scan that could allow reordering of
5535
+ // / arguments in the presence of a trailing closure, it might not be the last
5536
+ // / argument in the tuple.
5537
+ static Expr *findTrailingClosureArgument (Expr *arg) {
5538
+ if (auto parenExpr = dyn_cast<ParenExpr>(arg)) {
5539
+ return parenExpr->getSubExpr ();
5540
+ }
5541
+
5542
+ auto tupleExpr = cast<TupleExpr>(arg);
5543
+ SourceLoc endLoc = tupleExpr->getEndLoc ();
5544
+ for (Expr *elt : llvm::reverse (tupleExpr->getElements ())) {
5545
+ if (elt->getEndLoc () == endLoc)
5546
+ return elt;
5547
+ }
5548
+
5549
+ return tupleExpr->getElements ().back ();
5550
+ }
5551
+
5552
+ // / Find the index of the parameter that binds the given argument.
5553
+ static unsigned findParamBindingArgument (
5554
+ ArrayRef<ParamBinding> parameterBindings, unsigned argIndex) {
5555
+ for (unsigned paramIdx : indices (parameterBindings)) {
5556
+ if (llvm::find (parameterBindings[paramIdx], argIndex)
5557
+ != parameterBindings[paramIdx].end ())
5558
+ return paramIdx;
5559
+ }
5560
+
5561
+ llvm_unreachable (" No parameter binds the argument?" );
5562
+ }
5563
+
5474
5564
// / SE-0286 changed the direction in which the unlabeled trailing closure
5475
5565
// / argument is matched to a parameter, from backward (the pre-Swift 5.3
5476
5566
// / semantics) to forward (after SE-0286). Identify cases where this may
@@ -5492,13 +5582,8 @@ static void maybeWarnAboutTrailingClosureBindingChange(
5492
5582
return ;
5493
5583
5494
5584
// Find the parameter that bound the unlabeled trailing closure argument.
5495
- unsigned paramIdx;
5496
- for (paramIdx = 0 ; paramIdx != parameterBindings.size (); ++paramIdx) {
5497
- if (llvm::find (parameterBindings[paramIdx], *unlabeledTrailingClosureIndex)
5498
- != parameterBindings[paramIdx].end ())
5499
- break ;
5500
- }
5501
- assert (paramIdx != parameterBindings.size () && " Unbound trailing closure!" );
5585
+ unsigned paramIdx = findParamBindingArgument (
5586
+ parameterBindings, *unlabeledTrailingClosureIndex);
5502
5587
5503
5588
// If this parameter requires an argument, it would have been unfilled
5504
5589
// prior to SE-2086; there is nothing to diagnose.
@@ -5528,30 +5613,16 @@ static void maybeWarnAboutTrailingClosureBindingChange(
5528
5613
functionParameterArity (params[*matchingBackwardParamIdx]))
5529
5614
return ;
5530
5615
5531
- // Compute the various source locations where diagnostics will occur.
5532
- ASTContext &ctx = params[paramIdx].getPlainType ()->getASTContext ();
5533
- Expr *trailingClosure;
5534
- SourceLoc existingRParenLoc;
5535
- SourceLoc leadingCommaLoc;
5536
- if (auto tupleExpr = dyn_cast<TupleExpr>(arg)) {
5537
- trailingClosure = tupleExpr->getElements ().back ();
5538
- existingRParenLoc = tupleExpr->getRParenLoc ();
5539
- assert (tupleExpr->getNumElements () >= 2 && " Should be a ParenExpr?" );
5540
- leadingCommaLoc = Lexer::getLocForEndOfToken (
5541
- ctx.SourceMgr ,
5542
- tupleExpr->getElements ()[tupleExpr->getNumElements ()-2 ]->getEndLoc ());
5543
- } else {
5544
- auto parenExpr = cast<ParenExpr>(arg);
5545
- trailingClosure = parenExpr->getSubExpr ();
5546
- existingRParenLoc = parenExpr->getRParenLoc ();
5547
- }
5616
+ // Dig out the trailing closure.
5617
+ Expr *trailingClosure = findTrailingClosureArgument (arg);
5548
5618
5549
5619
// Determine the names of the parameters that would be matched by the
5550
5620
// forward and backward scans.
5551
5621
Identifier paramName = params[paramIdx].getLabel ();
5552
5622
Identifier backwardParamName = params[*matchingBackwardParamIdx].getLabel ();
5553
5623
5554
5624
// Produce a diagnostic referencing the callee.
5625
+ ASTContext &ctx = params[paramIdx].getPlainType ()->getASTContext ();
5555
5626
auto noteCallee = [&] {
5556
5627
auto decl = callee.getDecl ();
5557
5628
if (!decl)
@@ -5587,45 +5658,8 @@ static void maybeWarnAboutTrailingClosureBindingChange(
5587
5658
auto diag = ctx.Diags .diagnose (
5588
5659
trailingClosure->getStartLoc (), diag::trailing_closure_select_parameter,
5589
5660
paramName, which);
5590
-
5591
- // Figure out the text to be inserted before the trailing closure.
5592
- SmallString<16 > insertionText;
5593
- SourceLoc insertionLoc;
5594
- if (leadingCommaLoc.isValid ()) {
5595
- insertionText += " , " ;
5596
- assert (existingRParenLoc.isValid ());
5597
- insertionLoc = leadingCommaLoc;
5598
- } else if (existingRParenLoc.isInvalid ()) {
5599
- insertionText += " (" ;
5600
- insertionLoc = Lexer::getLocForEndOfToken (
5601
- ctx.SourceMgr , fn->getEndLoc ());
5602
- } else {
5603
- insertionLoc = existingRParenLoc;
5604
- }
5605
-
5606
- // Add the label, if there is one.
5607
- if (!paramName.empty ()) {
5608
- insertionText += paramName.str ();
5609
- insertionText += " : " ;
5610
- }
5611
-
5612
- // If there is an existing right parentheses, remove it while we
5613
- // insert the new text.
5614
- if (existingRParenLoc.isValid ()) {
5615
- SourceLoc afterExistingRParenLoc = Lexer::getLocForEndOfToken (
5616
- ctx.SourceMgr , existingRParenLoc);
5617
- diag.fixItReplaceChars (
5618
- insertionLoc, afterExistingRParenLoc, insertionText);
5619
- } else {
5620
- // Insert the appropriate prefix.
5621
- diag.fixItInsert (insertionLoc, insertionText);
5622
- }
5623
-
5624
-
5625
- // Insert a right parenthesis after the closing '}' of the trailing closure;
5626
- SourceLoc newRParenLoc = Lexer::getLocForEndOfToken (
5627
- ctx.SourceMgr , trailingClosure->getEndLoc ());
5628
- diag.fixItInsert (newRParenLoc, " )" );
5661
+ labelTrailingClosureArgument (
5662
+ ctx, fn, arg, paramName, trailingClosure, diag);
5629
5663
};
5630
5664
5631
5665
diagResolution (backwardParamName, 0 );
@@ -5634,6 +5668,34 @@ static void maybeWarnAboutTrailingClosureBindingChange(
5634
5668
noteCallee ();
5635
5669
}
5636
5670
5671
+ // / Warn about the use of the deprecated "backward" scan for matching the
5672
+ // / unlabeled trailing closure. It was needed to properly type check, but
5673
+ // / this code will break with a future version of Swift.
5674
+ static void warnAboutTrailingClosureBackwardScan (
5675
+ ConcreteDeclRef callee, Expr *fn, Expr *arg,
5676
+ ArrayRef<AnyFunctionType::Param> params,
5677
+ Optional<unsigned > unlabeledTrailingClosureIndex,
5678
+ ArrayRef<ParamBinding> parameterBindings) {
5679
+
5680
+ Expr *trailingClosure = findTrailingClosureArgument (arg);
5681
+ unsigned paramIdx = findParamBindingArgument (
5682
+ parameterBindings, *unlabeledTrailingClosureIndex);
5683
+ ASTContext &ctx = params[paramIdx].getPlainType ()->getASTContext ();
5684
+ Identifier paramName = params[paramIdx].getLabel ();
5685
+
5686
+ {
5687
+ auto diag = ctx.Diags .diagnose (
5688
+ trailingClosure->getStartLoc (),
5689
+ diag::unlabeled_trailing_closure_deprecated, paramName);
5690
+ labelTrailingClosureArgument (
5691
+ ctx, fn, arg, paramName, trailingClosure, diag);
5692
+ }
5693
+
5694
+ if (auto decl = callee.getDecl ()) {
5695
+ ctx.Diags .diagnose (decl, diag::decl_declared_here, decl->getName ());
5696
+ }
5697
+ }
5698
+
5637
5699
Expr *ExprRewriter::coerceCallArguments (
5638
5700
Expr *arg, AnyFunctionType *funcType,
5639
5701
ConcreteDeclRef callee,
@@ -5727,9 +5789,15 @@ Expr *ExprRewriter::coerceCallArguments(
5727
5789
5728
5790
// Warn if there was a recent change in trailing closure binding semantics
5729
5791
// that might have lead to a silent change in behavior.
5730
- maybeWarnAboutTrailingClosureBindingChange (
5731
- callee, apply ? apply->getFn () : nullptr , arg, args, params, paramInfo,
5732
- unlabeledTrailingClosureIndex, parameterBindings);
5792
+ if (trailingClosureMatching == TrailingClosureMatching::Forward) {
5793
+ maybeWarnAboutTrailingClosureBindingChange (
5794
+ callee, apply ? apply->getFn () : nullptr , arg, args, params, paramInfo,
5795
+ unlabeledTrailingClosureIndex, parameterBindings);
5796
+ } else {
5797
+ warnAboutTrailingClosureBackwardScan (
5798
+ callee, apply ? apply->getFn () : nullptr , arg, params,
5799
+ unlabeledTrailingClosureIndex, parameterBindings);
5800
+ }
5733
5801
5734
5802
SourceLoc lParenLoc, rParenLoc;
5735
5803
if (argTuple) {
0 commit comments