diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 2dc883d2b1a..f55616749d2 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -15,11 +15,13 @@ //===----------------------------------------------------------------------===// #include "CSDiagnostics.h" -#include "ConstraintSystem.h" #include "CSDiag.h" +#include "ConstraintSystem.h" #include "MiscDiagnostics.h" +#include "swift/AST/Decl.h" #include "swift/AST/Expr.h" #include "swift/AST/GenericSignature.h" +#include "swift/AST/ParameterList.h" #include "swift/AST/Types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" @@ -611,3 +613,56 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() { subElementDiagID, rvalueDiagID); return true; } + +bool TrailingClosureAmbiguityFailure::diagnoseAsNote() { + const auto *expr = getParentExpr(); + auto *callExpr = dyn_cast(expr); + if (!callExpr) + return false; + if (!callExpr->hasTrailingClosure()) + return false; + if (callExpr->getFn() != getAnchor()) + return false; + + llvm::SmallMapVector choicesByLabel; + for (const auto &choice : Choices) { + auto *callee = dyn_cast(choice.getDecl()); + if (!callee) + return false; + + const ParameterList *paramList = callee->getParameters(); + const ParamDecl *param = paramList->getArray().back(); + + // Sanity-check that the trailing closure corresponds to this parameter. + if (!param->hasValidSignature() || + !param->getInterfaceType()->is()) + return false; + + Identifier trailingClosureLabel = param->getArgumentName(); + auto &choiceForLabel = choicesByLabel[trailingClosureLabel]; + + // FIXME: Cargo-culted from diagnoseAmbiguity: apparently the same decl can + // appear more than once? + if (choiceForLabel == callee) + continue; + + // If just providing the trailing closure label won't solve the ambiguity, + // don't bother offering the fix-it. + if (choiceForLabel != nullptr) + return false; + + choiceForLabel = callee; + } + + // If we got here, then all of the choices have unique labels. Offer them in + // order. + for (const auto &choicePair : choicesByLabel) { + auto diag = emitDiagnostic( + expr->getLoc(), diag::ambiguous_because_of_trailing_closure, + choicePair.first.empty(), choicePair.second->getFullName()); + swift::fixItEncloseTrailingClosure(getTypeChecker(), diag, callExpr, + choicePair.first); + } + + return true; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index fadc55a5919..2dbd74c8b0a 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -467,6 +467,21 @@ public: bool diagnoseAsError() override; }; +class TrailingClosureAmbiguityFailure final : public FailureDiagnostic { + ArrayRef Choices; + +public: + TrailingClosureAmbiguityFailure(Expr *root, ConstraintSystem &cs, + Expr *anchor, + ArrayRef choices) + : FailureDiagnostic(root, cs, cs.getConstraintLocator(anchor)), + Choices(choices) {} + + bool diagnoseAsError() override { return false; } + + bool diagnoseAsNote() override; +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 90a92c57a6a..be96f4994d2 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -17,7 +17,7 @@ //===----------------------------------------------------------------------===// #include "ConstraintSystem.h" #include "ConstraintGraph.h" -#include "MiscDiagnostics.h" +#include "CSDiagnostics.h" #include "TypeCheckType.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/ParameterList.h" @@ -2283,61 +2283,6 @@ static DeclName getOverloadChoiceName(ArrayRef choices) { return name; } -/// Returns true if any diagnostics were emitted. -static bool -tryDiagnoseTrailingClosureAmbiguity(TypeChecker &tc, const Expr *expr, - const Expr *anchor, - ArrayRef choices) { - auto *callExpr = dyn_cast(expr); - if (!callExpr) - return false; - if (!callExpr->hasTrailingClosure()) - return false; - if (callExpr->getFn() != anchor) - return false; - - llvm::SmallMapVector choicesByLabel; - for (const OverloadChoice &choice : choices) { - auto *callee = dyn_cast(choice.getDecl()); - if (!callee) - return false; - - const ParameterList *paramList = callee->getParameters(); - const ParamDecl *param = paramList->getArray().back(); - - // Sanity-check that the trailing closure corresponds to this parameter. - if (!param->hasValidSignature() || - !param->getInterfaceType()->is()) - return false; - - Identifier trailingClosureLabel = param->getArgumentName(); - auto &choiceForLabel = choicesByLabel[trailingClosureLabel]; - - // FIXME: Cargo-culted from diagnoseAmbiguity: apparently the same decl can - // appear more than once? - if (choiceForLabel == callee) - continue; - - // If just providing the trailing closure label won't solve the ambiguity, - // don't bother offering the fix-it. - if (choiceForLabel != nullptr) - return false; - - choiceForLabel = callee; - } - - // If we got here, then all of the choices have unique labels. Offer them in - // order. - for (const auto &choicePair : choicesByLabel) { - auto diag = - tc.diagnose(expr->getLoc(), diag::ambiguous_because_of_trailing_closure, - choicePair.first.empty(), choicePair.second->getFullName()); - swift::fixItEncloseTrailingClosure(tc, diag, callExpr, choicePair.first); - } - - return true; -} - bool ConstraintSystem::diagnoseAmbiguity(Expr *expr, ArrayRef solutions) { // Produce a diff of the solutions. @@ -2415,7 +2360,9 @@ bool ConstraintSystem::diagnoseAmbiguity(Expr *expr, : diag::ambiguous_decl_ref, name); - if (tryDiagnoseTrailingClosureAmbiguity(tc, expr, anchor, overload.choices)) + TrailingClosureAmbiguityFailure failure(expr, *this, anchor, + overload.choices); + if (failure.diagnoseAsNote()) return true; // Emit candidates. Use a SmallPtrSet to make sure only emit a particular