Skip to content

Commit ea62075

Browse files
committed
[ConstraintSystem] NFC: Move diagnoseAmbiguity methods from CSDiag to ConstraintSystem`
1 parent 4692e30 commit ea62075

File tree

3 files changed

+313
-314
lines changed

3 files changed

+313
-314
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 0 additions & 314 deletions
Original file line numberDiff line numberDiff line change
@@ -342,320 +342,6 @@ void constraints::simplifyLocator(Expr *&anchor,
342342
}
343343
}
344344

345-
/// Simplify the given locator down to a specific anchor expression,
346-
/// if possible.
347-
///
348-
/// \returns the anchor expression if it fully describes the locator, or
349-
/// null otherwise.
350-
static Expr *simplifyLocatorToAnchor(ConstraintSystem &cs,
351-
ConstraintLocator *locator) {
352-
if (!locator || !locator->getAnchor())
353-
return nullptr;
354-
355-
SourceRange range;
356-
locator = simplifyLocator(cs, locator, range);
357-
if (!locator->getAnchor() || !locator->getPath().empty())
358-
return nullptr;
359-
360-
return locator->getAnchor();
361-
}
362-
363-
364-
365-
366-
/// \brief Determine the number of distinct overload choices in the
367-
/// provided set.
368-
static unsigned countDistinctOverloads(ArrayRef<OverloadChoice> choices) {
369-
llvm::SmallPtrSet<void *, 4> uniqueChoices;
370-
unsigned result = 0;
371-
for (auto choice : choices) {
372-
if (uniqueChoices.insert(choice.getOpaqueChoiceSimple()).second)
373-
++result;
374-
}
375-
return result;
376-
}
377-
378-
/// \brief Determine the name of the overload in a set of overload choices.
379-
static DeclName getOverloadChoiceName(ArrayRef<OverloadChoice> choices) {
380-
DeclName name;
381-
for (auto choice : choices) {
382-
if (!choice.isDecl())
383-
continue;
384-
385-
DeclName nextName = choice.getDecl()->getFullName();
386-
if (!name) {
387-
name = nextName;
388-
continue;
389-
}
390-
391-
if (name != nextName) {
392-
// Assume all choices have the same base name and only differ in
393-
// argument labels. This may not be a great assumption, but we don't
394-
// really have a way to recover for diagnostics otherwise.
395-
return name.getBaseName();
396-
}
397-
}
398-
399-
return name;
400-
}
401-
402-
/// Returns true if any diagnostics were emitted.
403-
static bool
404-
tryDiagnoseTrailingClosureAmbiguity(TypeChecker &tc,
405-
const Expr *expr,
406-
const Expr *anchor,
407-
ArrayRef<OverloadChoice> choices) {
408-
auto *callExpr = dyn_cast<CallExpr>(expr);
409-
if (!callExpr)
410-
return false;
411-
if (!callExpr->hasTrailingClosure())
412-
return false;
413-
if (callExpr->getFn() != anchor)
414-
return false;
415-
416-
llvm::SmallMapVector<Identifier, const ValueDecl *, 8> choicesByLabel;
417-
for (const OverloadChoice &choice : choices) {
418-
auto *callee = dyn_cast<AbstractFunctionDecl>(choice.getDecl());
419-
if (!callee)
420-
return false;
421-
422-
const ParameterList *paramList = callee->getParameters();
423-
const ParamDecl *param = paramList->getArray().back();
424-
425-
// Sanity-check that the trailing closure corresponds to this parameter.
426-
if (!param->hasValidSignature() ||
427-
!param->getInterfaceType()->is<AnyFunctionType>())
428-
return false;
429-
430-
Identifier trailingClosureLabel = param->getArgumentName();
431-
auto &choiceForLabel = choicesByLabel[trailingClosureLabel];
432-
433-
// FIXME: Cargo-culted from diagnoseAmbiguity: apparently the same decl can
434-
// appear more than once?
435-
if (choiceForLabel == callee)
436-
continue;
437-
438-
// If just providing the trailing closure label won't solve the ambiguity,
439-
// don't bother offering the fix-it.
440-
if (choiceForLabel != nullptr)
441-
return false;
442-
443-
choiceForLabel = callee;
444-
}
445-
446-
// If we got here, then all of the choices have unique labels. Offer them in
447-
// order.
448-
for (const auto &choicePair : choicesByLabel) {
449-
auto diag = tc.diagnose(expr->getLoc(),
450-
diag::ambiguous_because_of_trailing_closure,
451-
choicePair.first.empty(),
452-
choicePair.second->getFullName());
453-
swift::fixItEncloseTrailingClosure(tc, diag, callExpr, choicePair.first);
454-
}
455-
456-
return true;
457-
}
458-
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) {
544-
// Produce a diff of the solutions.
545-
SolutionDiff diff(solutions);
546-
547-
// Find the locators which have the largest numbers of distinct overloads.
548-
Optional<unsigned> bestOverload;
549-
// Overloads are scored by lexicographical comparison of (# of distinct
550-
// overloads, depth, *reverse* of the index). N.B. - cannot be used for the
551-
// reversing: the score version of index == 0 should be > than that of 1, but
552-
// -0 == 0 < UINT_MAX == -1, whereas ~0 == UINT_MAX > UINT_MAX - 1 == ~1.
553-
auto score = [](unsigned distinctOverloads, unsigned depth, unsigned index) {
554-
return std::make_tuple(distinctOverloads, depth, ~index);
555-
};
556-
auto bestScore = score(0, 0, std::numeric_limits<unsigned>::max());
557-
558-
// Get a map of expressions to their depths and post-order traversal indices.
559-
// Heuristically, all other things being equal, we should complain about the
560-
// ambiguous expression that (1) has the most overloads, (2) is deepest, or
561-
// (3) comes earliest in the expression.
562-
auto depthMap = expr->getDepthMap();
563-
auto indexMap = expr->getPreorderIndexMap();
564-
565-
for (unsigned i = 0, n = diff.overloads.size(); i != n; ++i) {
566-
auto &overload = diff.overloads[i];
567-
568-
// If we can't resolve the locator to an anchor expression with no path,
569-
// we can't diagnose this well.
570-
auto *anchor = simplifyLocatorToAnchor(*this, overload.locator);
571-
if (!anchor)
572-
continue;
573-
auto it = indexMap.find(anchor);
574-
if (it == indexMap.end())
575-
continue;
576-
unsigned index = it->second;
577-
it = depthMap.find(anchor);
578-
if (it == depthMap.end())
579-
continue;
580-
unsigned depth = it->second;
581-
582-
// If we don't have a name to hang on to, it'll be hard to diagnose this
583-
// overload.
584-
if (!getOverloadChoiceName(overload.choices))
585-
continue;
586-
587-
unsigned distinctOverloads = countDistinctOverloads(overload.choices);
588-
589-
// We need at least two overloads to make this interesting.
590-
if (distinctOverloads < 2)
591-
continue;
592-
593-
// If we have more distinct overload choices for this locator than for
594-
// prior locators, just keep this locator.
595-
auto thisScore = score(distinctOverloads, depth, index);
596-
if (thisScore > bestScore) {
597-
bestScore = thisScore;
598-
bestOverload = i;
599-
continue;
600-
}
601-
602-
// We have better results. Ignore this one.
603-
}
604-
605-
// FIXME: Should be able to pick the best locator, e.g., based on some
606-
// depth-first numbering of expressions.
607-
if (bestOverload) {
608-
auto &overload = diff.overloads[*bestOverload];
609-
auto name = getOverloadChoiceName(overload.choices);
610-
auto anchor = simplifyLocatorToAnchor(*this, overload.locator);
611-
612-
// Emit the ambiguity diagnostic.
613-
auto &tc = getTypeChecker();
614-
tc.diagnose(anchor->getLoc(),
615-
name.isOperator() ? diag::ambiguous_operator_ref
616-
: diag::ambiguous_decl_ref,
617-
name);
618-
619-
if (tryDiagnoseTrailingClosureAmbiguity(tc, expr, anchor, overload.choices))
620-
return true;
621-
622-
// Emit candidates. Use a SmallPtrSet to make sure only emit a particular
623-
// candidate once. FIXME: Why is one candidate getting into the overload
624-
// set multiple times? (See also tryDiagnoseTrailingClosureAmbiguity.)
625-
SmallPtrSet<Decl*, 8> EmittedDecls;
626-
for (auto choice : overload.choices) {
627-
switch (choice.getKind()) {
628-
case OverloadChoiceKind::Decl:
629-
case OverloadChoiceKind::DeclViaDynamic:
630-
case OverloadChoiceKind::DeclViaBridge:
631-
case OverloadChoiceKind::DeclViaUnwrappedOptional:
632-
// FIXME: show deduced types, etc, etc.
633-
if (EmittedDecls.insert(choice.getDecl()).second)
634-
tc.diagnose(choice.getDecl(), diag::found_candidate);
635-
break;
636-
637-
case OverloadChoiceKind::KeyPathApplication:
638-
case OverloadChoiceKind::DynamicMemberLookup:
639-
// Skip key path applications and dynamic member lookups, since we don't
640-
// want them to noise up unrelated subscript diagnostics.
641-
break;
642-
643-
case OverloadChoiceKind::BaseType:
644-
case OverloadChoiceKind::TupleIndex:
645-
// FIXME: Actually diagnose something here.
646-
break;
647-
}
648-
}
649-
650-
return true;
651-
}
652-
653-
// FIXME: If we inferred different types for literals (for example),
654-
// could diagnose ambiguity that way as well.
655-
656-
return false;
657-
}
658-
659345
/// Given an expression that has a non-lvalue type, dig into it until we find
660346
/// the part of the expression that prevents the entire subexpression from being
661347
/// mutable. For example, in a sequence like "x.v.v = 42" we want to complain

0 commit comments

Comments
 (0)