14
14
//
15
15
// ===----------------------------------------------------------------------===//
16
16
17
- #include " ConstraintSystem.h"
18
17
#include " CSDiag.h"
19
18
#include " CalleeCandidateInfo.h"
19
+ #include " ConstraintSystem.h"
20
20
#include " MiscDiagnostics.h"
21
21
#include " TypeCheckAvailability.h"
22
22
#include " TypoCorrection.h"
23
23
#include " swift/AST/ASTWalker.h"
24
+ #include " swift/AST/DiagnosticEngine.h"
24
25
#include " swift/AST/GenericEnvironment.h"
25
26
#include " swift/AST/Initializer.h"
26
27
#include " swift/AST/ParameterList.h"
27
28
#include " swift/AST/ProtocolConformance.h"
28
- #include " swift/AST/TypeWalker.h"
29
29
#include " swift/AST/TypeMatcher.h"
30
+ #include " swift/AST/TypeWalker.h"
30
31
#include " swift/Basic/Defer.h"
31
32
#include " swift/Basic/StringExtras.h"
32
33
#include " llvm/ADT/DenseSet.h"
@@ -455,9 +456,91 @@ tryDiagnoseTrailingClosureAmbiguity(TypeChecker &tc,
455
456
return true ;
456
457
}
457
458
458
- static bool diagnoseAmbiguity (ConstraintSystem &cs,
459
- ArrayRef<Solution> solutions,
460
- Expr *expr) {
459
+ bool ConstraintSystem::diagnoseAmbiguityWithFixes (
460
+ Expr *expr, ArrayRef<Solution> solutions) {
461
+ if (solutions.empty ())
462
+ return false ;
463
+
464
+ auto getOverloadDecl = [&](SelectedOverload &overload) -> ValueDecl * {
465
+ auto &choice = overload.choice ;
466
+ return choice.isDecl () ? choice.getDecl () : nullptr ;
467
+ };
468
+
469
+ // Problems related to fixes forming ambiguous solution set
470
+ // could only be diagnosed (at the moment), if all of the fixes
471
+ // are attached to the same anchor, which means they fix
472
+ // different overloads of the same declaration.
473
+ Expr *commonAnchor = nullptr ;
474
+ SmallPtrSet<ValueDecl *, 4 > distinctChoices;
475
+ SmallVector<std::pair<const Solution *, const ConstraintFix *>, 4 >
476
+ viableSolutions;
477
+
478
+ bool diagnosable = llvm::all_of (solutions, [&](const Solution &solution) {
479
+ ArrayRef<ConstraintFix *> fixes = solution.Fixes ;
480
+
481
+ // Currently only support a single fix in a solution,
482
+ // but ultimately should be able to deal with multiple.
483
+ if (fixes.size () != 1 )
484
+ return false ;
485
+
486
+ const auto *fix = fixes.front ();
487
+ if (commonAnchor && commonAnchor != fix->getAnchor ())
488
+ return false ;
489
+
490
+ commonAnchor = fix->getAnchor ();
491
+
492
+ SmallVector<SelectedOverload, 2 > overloads;
493
+ solution.getOverloadChoices (commonAnchor, overloads);
494
+ // There is unfortunately no way, at the moment, to figure out
495
+ // what declaration the fix is attached to, so we have to make
496
+ // sure that there is only one declaration associated with common
497
+ // anchor to be sure that the right problem is being diagnosed.
498
+ if (overloads.size () != 1 )
499
+ return false ;
500
+
501
+ auto *decl = getOverloadDecl (overloads.front ());
502
+ if (!decl)
503
+ return false ;
504
+
505
+ // If this declaration is distinct, let's record this solution
506
+ // as viable, otherwise we'd produce the same diagnostic multiple
507
+ // times, which means that actual problem is elsewhere.
508
+ if (distinctChoices.insert (decl).second )
509
+ viableSolutions.push_back ({&solution, fix});
510
+ return true ;
511
+ });
512
+
513
+ if (!diagnosable || viableSolutions.size () < 2 )
514
+ return false ;
515
+
516
+ auto *decl = *distinctChoices.begin ();
517
+ assert (solverState);
518
+
519
+ bool diagnosed = true ;
520
+ {
521
+ DiagnosticTransaction transaction (TC.Diags );
522
+
523
+ TC.diagnose (commonAnchor->getLoc (), diag::ambiguous_reference_to_decl,
524
+ decl->getDescriptiveKind (), decl->getFullName ());
525
+
526
+ for (const auto &viable : viableSolutions) {
527
+ // Create scope so each applied solution is rolled back.
528
+ ConstraintSystem::SolverScope scope (*this );
529
+ applySolution (*viable.first );
530
+ // All of the solutions supposed to produce a "candidate" note.
531
+ diagnosed &= viable.second ->diagnose (expr, /* asNote*/ true );
532
+ }
533
+
534
+ // If not all of the fixes produced a note, we can't diagnose this.
535
+ if (!diagnosed)
536
+ transaction.abort ();
537
+ }
538
+
539
+ return diagnosed;
540
+ }
541
+
542
+ bool ConstraintSystem::diagnoseAmbiguity (Expr *expr,
543
+ ArrayRef<Solution> solutions) {
461
544
// Produce a diff of the solutions.
462
545
SolutionDiff diff (solutions);
463
546
@@ -484,7 +567,7 @@ static bool diagnoseAmbiguity(ConstraintSystem &cs,
484
567
485
568
// If we can't resolve the locator to an anchor expression with no path,
486
569
// we can't diagnose this well.
487
- auto *anchor = simplifyLocatorToAnchor (cs , overload.locator );
570
+ auto *anchor = simplifyLocatorToAnchor (* this , overload.locator );
488
571
if (!anchor)
489
572
continue ;
490
573
auto it = indexMap.find (anchor);
@@ -524,10 +607,10 @@ static bool diagnoseAmbiguity(ConstraintSystem &cs,
524
607
if (bestOverload) {
525
608
auto &overload = diff.overloads [*bestOverload];
526
609
auto name = getOverloadChoiceName (overload.choices );
527
- auto anchor = simplifyLocatorToAnchor (cs , overload.locator );
610
+ auto anchor = simplifyLocatorToAnchor (* this , overload.locator );
528
611
529
612
// Emit the ambiguity diagnostic.
530
- auto &tc = cs. getTypeChecker ();
613
+ auto &tc = getTypeChecker ();
531
614
tc.diagnose (anchor->getLoc (),
532
615
name.isOperator () ? diag::ambiguous_operator_ref
533
616
: diag::ambiguous_decl_ref,
@@ -9021,6 +9104,11 @@ bool ConstraintSystem::salvage(SmallVectorImpl<Solution> &viable, Expr *expr) {
9021
9104
// FIXME: If we were able to actually fix things along the way,
9022
9105
// we may have to hunt for the best solution. For now, we don't care.
9023
9106
9107
+ // Before removing any "fixed" solutions, let's check
9108
+ // if ambiguity is caused by fixes and diagnose if possible.
9109
+ if (diagnoseAmbiguityWithFixes (expr, viable))
9110
+ return true ;
9111
+
9024
9112
// Remove solutions that require fixes; the fixes in those systems should
9025
9113
// be diagnosed rather than any ambiguity.
9026
9114
auto hasFixes = [](const Solution &sol) { return !sol.Fixes .empty (); };
@@ -9039,9 +9127,9 @@ bool ConstraintSystem::salvage(SmallVectorImpl<Solution> &viable, Expr *expr) {
9039
9127
solution.dump (log);
9040
9128
log << " \n " ;
9041
9129
}
9042
- }
9130
+ }
9043
9131
9044
- if (diagnoseAmbiguity (* this , viable, expr )) {
9132
+ if (diagnoseAmbiguity (expr , viable)) {
9045
9133
return true ;
9046
9134
}
9047
9135
}
0 commit comments