mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
as a way to get more type information out of incorrect subexpressions. UnresolvedType
generally just propagates around the type system like a type variable:
- it magically conforms to all protocols
- it CSGens as an unconstrained type variable.
- it ASTPrints as _, just like a type variable.
The major difference is that UnresolvedType can be used outside the context of a
ConstraintSystem, which is useful for CSGen since it sets up several of them to
diagnose subexpressions w.r.t. their types.
For now, our use of this is extremely limited: when a closureexpr has no contextual
type available and its parameters are invalid, we wipe them out with UnresolvedType
(instead of the previous nulltype dance) to get ambiguities later on.
We also introduce a new FreeTypeVariableBinding::UnresolvedType approach for
constraint solving (and use this only in one place in CSDiags so far, to resolve
the callee of a CallExpr) which solves a system and rewrites any leftover type
variables as UnresolvedTypes. This allows us to get more precise information out,
for example, diagnosing:
func r22162441(lines: [String]) {
lines.map { line in line.fooBar() }
}
with: value of type 'String' has no member 'fooBar'
instead of: type of expression is ambiguous without more context
This improves a number of other diagnostics as well, but is just the infrastructural
stepping stone for greater things.
Swift SVN r31105
3986 lines
140 KiB
C++
3986 lines
140 KiB
C++
//===--- CSDiag.cpp - Constraint Diagnostics ------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements diagnostics for the type checker.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ConstraintSystem.h"
|
|
#include "llvm/Support/SaveAndRestore.h"
|
|
|
|
using namespace swift;
|
|
using namespace constraints;
|
|
|
|
void Failure::dump(SourceManager *sm) const {
|
|
dump(sm, llvm::errs());
|
|
}
|
|
|
|
void Failure::dump(SourceManager *sm, raw_ostream &out) const {
|
|
out << "(";
|
|
if (locator) {
|
|
out << "@";
|
|
locator->dump(sm, out);
|
|
out << ": ";
|
|
}
|
|
|
|
switch (getKind()) {
|
|
case DoesNotConformToProtocol:
|
|
out << getFirstType().getString() << " does not conform to "
|
|
<< getSecondType().getString();
|
|
break;
|
|
|
|
case DoesNotHaveMember:
|
|
out << getFirstType().getString() << " does not have a member named '"
|
|
<< getName() << "'";
|
|
break;
|
|
|
|
case FunctionTypesMismatch:
|
|
out << "function type " << getFirstType().getString() << " is not equal to "
|
|
<< getSecondType().getString();
|
|
break;
|
|
|
|
case FunctionAutoclosureMismatch:
|
|
out << "autoclosure mismatch " << getFirstType().getString() << " vs. "
|
|
<< getSecondType().getString();
|
|
break;
|
|
|
|
case FunctionNoReturnMismatch:
|
|
out << "noreturn attribute mismatch " << getFirstType().getString()
|
|
<< " vs. " << getSecondType().getString();
|
|
break;
|
|
|
|
case FunctionNoEscapeMismatch:
|
|
out << "noescape attribute mismatch " << getFirstType().getString()
|
|
<< " vs. " << getSecondType().getString();
|
|
break;
|
|
|
|
case FunctionThrowsMismatch:
|
|
out << "function throws mismatch " << getFirstType().getString() << " vs. "
|
|
<< getSecondType().getString();
|
|
break;
|
|
|
|
case IsNotMetatype:
|
|
out << getFirstType().getString() << " is not a metatype";
|
|
break;
|
|
|
|
case IsNotArchetype:
|
|
out << getFirstType().getString() << " is not an archetype";
|
|
break;
|
|
|
|
case IsNotClass:
|
|
out << getFirstType().getString() << " is not a class";
|
|
break;
|
|
|
|
case IsNotBridgedToObjectiveC:
|
|
out << getFirstType().getString() << "is not bridged to Objective-C";
|
|
break;
|
|
|
|
case IsNotDynamicLookup:
|
|
out << getFirstType().getString() << " is not a dynamic lookup value";
|
|
break;
|
|
|
|
case IsNotOptional:
|
|
out << getFirstType().getString() << "is not an optional type";
|
|
break;
|
|
|
|
case TupleNameMismatch:
|
|
case TupleNamePositionMismatch:
|
|
case TupleSizeMismatch:
|
|
case TupleVariadicMismatch:
|
|
case TupleUnused:
|
|
out << "mismatched tuple types " << getFirstType().getString() << " and "
|
|
<< getSecondType().getString();
|
|
break;
|
|
|
|
case TypesNotConstructible:
|
|
out << getFirstType().getString() << " is not a constructible argument for "
|
|
<< getSecondType().getString();
|
|
break;
|
|
|
|
case TypesNotConvertible:
|
|
out << getFirstType().getString() << " is not convertible to "
|
|
<< getSecondType().getString();
|
|
break;
|
|
|
|
case TypesNotSubtypes:
|
|
out << getFirstType().getString() << " is not a subtype of "
|
|
<< getSecondType().getString();
|
|
break;
|
|
|
|
case TypesNotEqual:
|
|
out << getFirstType().getString() << " is not equal to "
|
|
<< getSecondType().getString();
|
|
break;
|
|
|
|
case IsForbiddenLValue:
|
|
out << "disallowed l-value binding of " << getFirstType().getString()
|
|
<< " and " << getSecondType().getString();
|
|
break;
|
|
|
|
case OutOfOrderArgument:
|
|
out << "out-of-order argument " << getValue() << " should come before "
|
|
<< getSecondValue();
|
|
break;
|
|
|
|
case MissingArgument:
|
|
out << "missing argument for parameter " << getValue();
|
|
break;
|
|
|
|
case ExtraArgument:
|
|
out << "extra argument " << getValue();
|
|
break;
|
|
|
|
case NoPublicInitializers:
|
|
out << getFirstType().getString()
|
|
<< " does not have any public initializers";
|
|
break;
|
|
|
|
case IsNotMaterializable:
|
|
out << getFirstType().getString() << " is not materializable";
|
|
break;
|
|
}
|
|
|
|
out << ")\n";
|
|
}
|
|
|
|
/// Given a subpath of an old locator, compute its summary flags.
|
|
static unsigned recomputeSummaryFlags(ConstraintLocator *oldLocator,
|
|
ArrayRef<LocatorPathElt> path) {
|
|
if (oldLocator->getSummaryFlags() != 0)
|
|
return ConstraintLocator::getSummaryFlagsForPath(path);
|
|
return 0;
|
|
}
|
|
|
|
ConstraintLocator *
|
|
constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator,
|
|
SourceRange &range,
|
|
ConstraintLocator **targetLocator) {
|
|
// Clear out the target locator result.
|
|
if (targetLocator)
|
|
*targetLocator = nullptr;
|
|
|
|
// The path to be tacked on to the target locator to identify the specific
|
|
// target.
|
|
Expr *targetAnchor;
|
|
SmallVector<LocatorPathElt, 4> targetPath;
|
|
|
|
auto path = locator->getPath();
|
|
auto anchor = locator->getAnchor();
|
|
simplifyLocator(anchor, path, targetAnchor, targetPath, range);
|
|
|
|
|
|
// If we have a target anchor, build and simplify the target locator.
|
|
if (targetLocator && targetAnchor) {
|
|
SourceRange targetRange;
|
|
unsigned targetFlags = recomputeSummaryFlags(locator, targetPath);
|
|
auto loc = cs.getConstraintLocator(targetAnchor, targetPath, targetFlags);
|
|
*targetLocator = simplifyLocator(cs, loc, targetRange);
|
|
}
|
|
|
|
// If we didn't simplify anything, just return the input.
|
|
if (anchor == locator->getAnchor() &&
|
|
path.size() == locator->getPath().size()) {
|
|
return locator;
|
|
}
|
|
|
|
// Recompute the summary flags if we had any to begin with. This is
|
|
// necessary because we might remove e.g. tuple elements from the path.
|
|
unsigned summaryFlags = recomputeSummaryFlags(locator, path);
|
|
return cs.getConstraintLocator(anchor, path, summaryFlags);
|
|
}
|
|
|
|
void constraints::simplifyLocator(Expr *&anchor,
|
|
ArrayRef<LocatorPathElt> &path,
|
|
Expr *&targetAnchor,
|
|
SmallVectorImpl<LocatorPathElt> &targetPath,
|
|
SourceRange &range) {
|
|
range = SourceRange();
|
|
targetAnchor = nullptr;
|
|
|
|
while (!path.empty()) {
|
|
switch (path[0].getKind()) {
|
|
case ConstraintLocator::ApplyArgument:
|
|
// Extract application argument.
|
|
if (auto applyExpr = dyn_cast<ApplyExpr>(anchor)) {
|
|
// The target anchor is the function being called.
|
|
targetAnchor = applyExpr->getFn();
|
|
targetPath.push_back(path[0]);
|
|
|
|
anchor = applyExpr->getArg();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
|
|
#ifdef SWIFT_ENABLE_OBJECT_LITERALS
|
|
if (auto objectLiteralExpr = dyn_cast<ObjectLiteralExpr>(anchor)) {
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
|
|
anchor = objectLiteralExpr->getArg();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
#endif // SWIFT_ENABLE_OBJECT_LITERALS
|
|
break;
|
|
|
|
case ConstraintLocator::ApplyFunction:
|
|
// Extract application function.
|
|
if (auto applyExpr = dyn_cast<ApplyExpr>(anchor)) {
|
|
// No additional target locator information.
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
|
|
anchor = applyExpr->getFn();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
|
|
// The unresolved member itself is the function.
|
|
if (auto unresolvedMember = dyn_cast<UnresolvedMemberExpr>(anchor)) {
|
|
if (unresolvedMember->getArgument()) {
|
|
// No additional target locator information.
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
|
|
anchor = unresolvedMember;
|
|
path = path.slice(1);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
|
|
case ConstraintLocator::Load:
|
|
case ConstraintLocator::RvalueAdjustment:
|
|
case ConstraintLocator::ScalarToTuple:
|
|
// Loads, rvalue adjustment, and scalar-to-tuple conversions are implicit.
|
|
path = path.slice(1);
|
|
continue;
|
|
|
|
case ConstraintLocator::NamedTupleElement:
|
|
case ConstraintLocator::TupleElement:
|
|
// Extract tuple element.
|
|
if (auto tupleExpr = dyn_cast<TupleExpr>(anchor)) {
|
|
// Append this extraction to the target locator path.
|
|
if (targetAnchor) {
|
|
targetPath.push_back(path[0]);
|
|
}
|
|
|
|
anchor = tupleExpr->getElement(path[0].getValue());
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::ApplyArgToParam:
|
|
// Extract tuple element.
|
|
if (auto tupleExpr = dyn_cast<TupleExpr>(anchor)) {
|
|
// Append this extraction to the target locator path.
|
|
if (targetAnchor) {
|
|
targetPath.push_back(path[0]);
|
|
}
|
|
|
|
anchor = tupleExpr->getElement(path[0].getValue());
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
|
|
// Extract subexpression in parentheses.
|
|
if (auto parenExpr = dyn_cast<ParenExpr>(anchor)) {
|
|
assert(path[0].getValue() == 0);
|
|
|
|
// Append this extraction to the target locator path.
|
|
if (targetAnchor) {
|
|
targetPath.push_back(path[0]);
|
|
}
|
|
|
|
anchor = parenExpr->getSubExpr();
|
|
path = path.slice(1);
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::ConstructorMember:
|
|
if (auto typeExpr = dyn_cast<TypeExpr>(anchor)) {
|
|
// This is really an implicit 'init' MemberRef, so point at the base,
|
|
// i.e. the TypeExpr.
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
range = SourceRange();
|
|
anchor = typeExpr;
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
SWIFT_FALLTHROUGH;
|
|
|
|
case ConstraintLocator::Member:
|
|
case ConstraintLocator::MemberRefBase:
|
|
if (auto UDE = dyn_cast<UnresolvedDotExpr>(anchor)) {
|
|
// No additional target locator information.
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
|
|
range = UDE->getNameLoc();
|
|
anchor = UDE->getBase();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
if (auto USE = dyn_cast<UnresolvedSelectorExpr>(anchor)) {
|
|
// No additional target locator information.
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
|
|
range = USE->getNameRange();
|
|
anchor = USE->getBase();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::InterpolationArgument:
|
|
if (auto interp = dyn_cast<InterpolatedStringLiteralExpr>(anchor)) {
|
|
// No additional target locator information.
|
|
// FIXME: Dig out the constructor we're trying to call?
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
|
|
anchor = interp->getSegments()[path[0].getValue()];
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::AssignSource:
|
|
if (auto assign = dyn_cast<AssignExpr>(anchor)) {
|
|
targetAnchor = assign->getDest();
|
|
targetPath.clear();
|
|
|
|
anchor = assign->getSrc();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::SubscriptIndex:
|
|
if (auto subscript = dyn_cast<SubscriptExpr>(anchor)) {
|
|
targetAnchor = subscript->getBase();
|
|
targetPath.clear();
|
|
|
|
anchor = subscript->getIndex();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
break;
|
|
case ConstraintLocator::SubscriptMember:
|
|
if (auto subscript = dyn_cast<SubscriptExpr>(anchor)) {
|
|
anchor = subscript->getBase();
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::CheckedCastOperand:
|
|
if (auto castExpr = dyn_cast<ExplicitCastExpr>(anchor)) {
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
anchor = castExpr->getSubExpr();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::ClosureResult:
|
|
if (auto CE = dyn_cast<ClosureExpr>(anchor)) {
|
|
if (CE->hasSingleExpressionBody()) {
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
anchor = CE->getSingleExpressionBody();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::IfThen:
|
|
if (auto ITE = dyn_cast<IfExpr>(anchor)) {
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
anchor = ITE->getThenExpr();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
break;
|
|
case ConstraintLocator::IfElse:
|
|
if (auto ITE = dyn_cast<IfExpr>(anchor)) {
|
|
targetAnchor = nullptr;
|
|
targetPath.clear();
|
|
anchor = ITE->getElseExpr();
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// FIXME: Lots of other cases to handle.
|
|
break;
|
|
}
|
|
|
|
// If we get here, we couldn't simplify the path further.
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// Simplify the given locator down to a specific anchor expression,
|
|
/// if possible.
|
|
///
|
|
/// \returns the anchor expression if it fully describes the locator, or
|
|
/// null otherwise.
|
|
static Expr *simplifyLocatorToAnchor(ConstraintSystem &cs,
|
|
ConstraintLocator *locator) {
|
|
if (!locator || !locator->getAnchor())
|
|
return nullptr;
|
|
|
|
SourceRange range;
|
|
locator = simplifyLocator(cs, locator, range);
|
|
if (!locator->getAnchor() || !locator->getPath().empty())
|
|
return nullptr;
|
|
|
|
return locator->getAnchor();
|
|
}
|
|
|
|
/// Retrieve the argument pattern for the given declaration.
|
|
///
|
|
static Pattern *getParameterPattern(ValueDecl *decl) {
|
|
if (auto func = dyn_cast<FuncDecl>(decl))
|
|
return func->getBodyParamPatterns()[0];
|
|
if (auto constructor = dyn_cast<ConstructorDecl>(decl))
|
|
return constructor->getBodyParamPatterns()[1];
|
|
if (auto subscript = dyn_cast<SubscriptDecl>(decl))
|
|
return subscript->getIndices();
|
|
|
|
// FIXME: Variables of function type?
|
|
return nullptr;
|
|
}
|
|
|
|
ResolvedLocator constraints::resolveLocatorToDecl(
|
|
ConstraintSystem &cs,
|
|
ConstraintLocator *locator,
|
|
std::function<Optional<SelectedOverload>(ConstraintLocator *)> findOvlChoice,
|
|
std::function<ConcreteDeclRef (ValueDecl *decl,
|
|
Type openedType)> getConcreteDeclRef)
|
|
{
|
|
assert(locator && "Null locator");
|
|
if (!locator->getAnchor())
|
|
return ResolvedLocator();
|
|
|
|
ConcreteDeclRef declRef;
|
|
auto anchor = locator->getAnchor();
|
|
// Unwrap any specializations, constructor calls, implicit conversions, and
|
|
// '.'s.
|
|
// FIXME: This is brittle.
|
|
do {
|
|
if (auto specialize = dyn_cast<UnresolvedSpecializeExpr>(anchor)) {
|
|
anchor = specialize->getSubExpr();
|
|
continue;
|
|
}
|
|
|
|
if (auto implicit = dyn_cast<ImplicitConversionExpr>(anchor)) {
|
|
anchor = implicit->getSubExpr();
|
|
continue;
|
|
}
|
|
|
|
if (auto identity = dyn_cast<IdentityExpr>(anchor)) {
|
|
anchor = identity->getSubExpr();
|
|
continue;
|
|
}
|
|
|
|
if (auto tryExpr = dyn_cast<AnyTryExpr>(anchor)) {
|
|
if (isa<OptionalTryExpr>(tryExpr))
|
|
break;
|
|
|
|
anchor = tryExpr->getSubExpr();
|
|
continue;
|
|
}
|
|
|
|
if (auto constructor = dyn_cast<ConstructorRefCallExpr>(anchor)) {
|
|
anchor = constructor->getFn();
|
|
continue;
|
|
}
|
|
|
|
if (auto dotSyntax = dyn_cast<DotSyntaxBaseIgnoredExpr>(anchor)) {
|
|
anchor = dotSyntax->getRHS();
|
|
continue;
|
|
}
|
|
|
|
if (auto dotSyntax = dyn_cast<DotSyntaxCallExpr>(anchor)) {
|
|
anchor = dotSyntax->getFn();
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
} while (true);
|
|
|
|
auto getConcreteDeclRefFromOverload
|
|
= [&](const SelectedOverload &selected) -> ConcreteDeclRef {
|
|
return getConcreteDeclRef(selected.choice.getDecl(),
|
|
selected.openedType);
|
|
};
|
|
|
|
if (auto dre = dyn_cast<DeclRefExpr>(anchor)) {
|
|
// Simple case: direct reference to a declaration.
|
|
declRef = dre->getDeclRef();
|
|
} else if (auto mre = dyn_cast<MemberRefExpr>(anchor)) {
|
|
// Simple case: direct reference to a declaration.
|
|
declRef = mre->getMember();
|
|
} else if (isa<OverloadedDeclRefExpr>(anchor) ||
|
|
isa<OverloadedMemberRefExpr>(anchor) ||
|
|
isa<UnresolvedDeclRefExpr>(anchor)) {
|
|
// Overloaded and unresolved cases: find the resolved overload.
|
|
auto anchorLocator = cs.getConstraintLocator(anchor);
|
|
if (auto selected = findOvlChoice(anchorLocator)) {
|
|
if (selected->choice.isDecl())
|
|
declRef = getConcreteDeclRefFromOverload(*selected);
|
|
}
|
|
} else if (isa<UnresolvedMemberExpr>(anchor)) {
|
|
// Unresolved member: find the resolved overload.
|
|
auto anchorLocator = cs.getConstraintLocator(
|
|
anchor,
|
|
ConstraintLocator::UnresolvedMember);
|
|
if (auto selected = findOvlChoice(anchorLocator)) {
|
|
if (selected->choice.isDecl())
|
|
declRef = getConcreteDeclRefFromOverload(*selected);
|
|
}
|
|
} else if (auto ctorRef = dyn_cast<OtherConstructorDeclRefExpr>(anchor)) {
|
|
declRef = ctorRef->getDeclRef();
|
|
}
|
|
|
|
// If we didn't find the declaration, we're out of luck.
|
|
if (!declRef)
|
|
return ResolvedLocator();
|
|
|
|
// Use the declaration and the path to produce a more specific result.
|
|
// FIXME: This is an egregious hack. We'd be far better off
|
|
// FIXME: Perform deeper path resolution?
|
|
auto path = locator->getPath();
|
|
Pattern *parameterPattern = nullptr;
|
|
bool impliesFullPattern = false;
|
|
while (!path.empty()) {
|
|
switch (path[0].getKind()) {
|
|
case ConstraintLocator::ApplyArgument:
|
|
// If we're calling into something that has parameters, dig into the
|
|
// actual parameter pattern.
|
|
parameterPattern = getParameterPattern(declRef.getDecl());
|
|
if (!parameterPattern)
|
|
break;
|
|
|
|
impliesFullPattern = true;
|
|
path = path.slice(1);
|
|
continue;
|
|
|
|
case ConstraintLocator::TupleElement:
|
|
case ConstraintLocator::NamedTupleElement:
|
|
if (parameterPattern) {
|
|
unsigned index = path[0].getValue();
|
|
if (auto tuple = dyn_cast<TuplePattern>(
|
|
parameterPattern->getSemanticsProvidingPattern())) {
|
|
parameterPattern = tuple->getElement(index).getPattern();
|
|
impliesFullPattern = false;
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
parameterPattern = nullptr;
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::ApplyArgToParam:
|
|
if (parameterPattern) {
|
|
unsigned index = path[0].getValue2();
|
|
if (auto tuple = dyn_cast<TuplePattern>(
|
|
parameterPattern->getSemanticsProvidingPattern())) {
|
|
parameterPattern = tuple->getElement(index).getPattern();
|
|
impliesFullPattern = false;
|
|
path = path.slice(1);
|
|
continue;
|
|
}
|
|
parameterPattern = nullptr;
|
|
}
|
|
break;
|
|
|
|
case ConstraintLocator::ScalarToTuple:
|
|
continue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// If we have a parameter pattern that refers to a parameter, grab it.
|
|
if (parameterPattern) {
|
|
parameterPattern = parameterPattern->getSemanticsProvidingPattern();
|
|
if (impliesFullPattern) {
|
|
if (auto tuple = dyn_cast<TuplePattern>(parameterPattern)) {
|
|
if (tuple->getNumElements() == 1) {
|
|
parameterPattern = tuple->getElement(0).getPattern();
|
|
parameterPattern = parameterPattern->getSemanticsProvidingPattern();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (auto named = dyn_cast<NamedPattern>(parameterPattern)) {
|
|
return ResolvedLocator(ResolvedLocator::ForVar, named->getDecl());
|
|
}
|
|
}
|
|
|
|
// Otherwise, do the best we can with the declaration we found.
|
|
if (isa<FuncDecl>(declRef.getDecl()))
|
|
return ResolvedLocator(ResolvedLocator::ForFunction, declRef);
|
|
if (isa<ConstructorDecl>(declRef.getDecl()))
|
|
return ResolvedLocator(ResolvedLocator::ForConstructor, declRef);
|
|
|
|
// FIXME: Deal with the other interesting cases here, e.g.,
|
|
// subscript declarations.
|
|
return ResolvedLocator();
|
|
}
|
|
|
|
/// Emit a note referring to the target of a diagnostic, e.g., the function
|
|
/// or parameter being used.
|
|
static void noteTargetOfDiagnostic(ConstraintSystem &cs,
|
|
const Failure *failure,
|
|
ConstraintLocator *targetLocator) {
|
|
// If there's no anchor, there's nothing we can do.
|
|
if (!targetLocator->getAnchor())
|
|
return;
|
|
|
|
// Try to resolve the locator to a particular declaration.
|
|
auto resolved
|
|
= resolveLocatorToDecl(cs, targetLocator,
|
|
[&](ConstraintLocator *locator) -> Optional<SelectedOverload> {
|
|
if (!failure) return None;
|
|
for (auto resolved = failure->getResolvedOverloadSets();
|
|
resolved; resolved = resolved->Previous) {
|
|
if (resolved->Locator == locator)
|
|
return SelectedOverload{resolved->Choice,
|
|
resolved->OpenedFullType,
|
|
// FIXME: opened type?
|
|
Type()};
|
|
}
|
|
|
|
return None;
|
|
},
|
|
[&](ValueDecl *decl,
|
|
Type openedType) -> ConcreteDeclRef {
|
|
return decl;
|
|
});
|
|
|
|
// We couldn't resolve the locator to a declaration, so we're done.
|
|
if (!resolved)
|
|
return;
|
|
|
|
switch (resolved.getKind()) {
|
|
case ResolvedLocatorKind::Unresolved:
|
|
// Can't emit any diagnostic here.
|
|
return;
|
|
|
|
case ResolvedLocatorKind::Function: {
|
|
auto name = resolved.getDecl().getDecl()->getName();
|
|
cs.getTypeChecker().diagnose(resolved.getDecl().getDecl(),
|
|
name.isOperator()? diag::note_call_to_operator
|
|
: diag::note_call_to_func,
|
|
resolved.getDecl().getDecl()->getName());
|
|
return;
|
|
}
|
|
|
|
case ResolvedLocatorKind::Constructor:
|
|
// FIXME: Specialize for implicitly-generated constructors.
|
|
cs.getTypeChecker().diagnose(resolved.getDecl().getDecl(),
|
|
diag::note_call_to_initializer);
|
|
return;
|
|
|
|
case ResolvedLocatorKind::Parameter:
|
|
cs.getTypeChecker().diagnose(resolved.getDecl().getDecl(),
|
|
diag::note_init_parameter,
|
|
resolved.getDecl().getDecl()->getName());
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// \brief Emit a diagnostic for the given failure.
|
|
///
|
|
/// \param cs The constraint system in which the diagnostic was generated.
|
|
/// \param failure The failure to emit.
|
|
/// \param expr The expression associated with the failure.
|
|
/// \param useExprLoc If the failure lacks a location, use the one associated
|
|
/// with expr.
|
|
///
|
|
/// \returns true if the diagnostic was emitted successfully.
|
|
static bool diagnoseFailure(ConstraintSystem &cs, Failure &failure,
|
|
Expr *expr, bool useExprLoc) {
|
|
ConstraintLocator *cloc;
|
|
if (!failure.getLocator() || !failure.getLocator()->getAnchor()) {
|
|
if (useExprLoc)
|
|
cloc = cs.getConstraintLocator(expr);
|
|
else
|
|
return false;
|
|
} else {
|
|
cloc = failure.getLocator();
|
|
}
|
|
|
|
SourceRange range;
|
|
|
|
ConstraintLocator *targetLocator;
|
|
auto locator = simplifyLocator(cs, cloc, range, &targetLocator);
|
|
auto &tc = cs.getTypeChecker();
|
|
|
|
auto anchor = locator->getAnchor();
|
|
auto loc = anchor->getLoc();
|
|
switch (failure.getKind()) {
|
|
case Failure::TupleSizeMismatch: {
|
|
auto tuple1 = failure.getFirstType()->castTo<TupleType>();
|
|
auto tuple2 = failure.getSecondType()->castTo<TupleType>();
|
|
tc.diagnose(loc, diag::invalid_tuple_size, tuple1, tuple2,
|
|
tuple1->getNumElements(), tuple2->getNumElements())
|
|
.highlight(range);
|
|
return true;
|
|
}
|
|
|
|
case Failure::TupleUnused:
|
|
tc.diagnose(loc, diag::invalid_tuple_element_unused,
|
|
failure.getFirstType(), failure.getSecondType())
|
|
.highlight(range);
|
|
return true;
|
|
|
|
case Failure::TypesNotConvertible:
|
|
case Failure::TypesNotEqual:
|
|
case Failure::TypesNotSubtypes:
|
|
case Failure::TypesNotConstructible:
|
|
case Failure::FunctionTypesMismatch:
|
|
case Failure::DoesNotHaveMember:
|
|
case Failure::DoesNotConformToProtocol:
|
|
case Failure::FunctionNoEscapeMismatch:
|
|
case Failure::FunctionThrowsMismatch:
|
|
// The Expr path handling these constraints does a good job.
|
|
return false;
|
|
|
|
case Failure::IsNotBridgedToObjectiveC:
|
|
tc.diagnose(loc, diag::type_not_bridged, failure.getFirstType());
|
|
if (targetLocator)
|
|
noteTargetOfDiagnostic(cs, &failure, targetLocator);
|
|
break;
|
|
|
|
case Failure::IsForbiddenLValue:
|
|
// FIXME: Probably better handled by InOutExpr later.
|
|
if (auto iotTy = failure.getSecondType()->getAs<InOutType>()) {
|
|
tc.diagnose(loc, diag::reference_non_inout, iotTy->getObjectType())
|
|
.highlight(range);
|
|
return true;
|
|
}
|
|
// FIXME: diagnose other cases
|
|
return false;
|
|
|
|
case Failure::OutOfOrderArgument:
|
|
if (auto tuple = dyn_cast_or_null<TupleExpr>(anchor)) {
|
|
unsigned firstIdx = failure.getValue();
|
|
Identifier first = tuple->getElementName(firstIdx);
|
|
unsigned secondIdx = failure.getSecondValue();
|
|
Identifier second = tuple->getElementName(secondIdx);
|
|
if (!first.empty() && !second.empty()) {
|
|
tc.diagnose(tuple->getElementNameLoc(firstIdx),
|
|
diag::argument_out_of_order, first, second)
|
|
.highlight(tuple->getElement(firstIdx)->getSourceRange())
|
|
.highlight(SourceRange(tuple->getElementNameLoc(secondIdx),
|
|
tuple->getElement(secondIdx)->getEndLoc()));
|
|
return true;
|
|
}
|
|
}
|
|
// FIXME: Can this even happen?
|
|
return false;
|
|
|
|
case Failure::MissingArgument: {
|
|
Identifier name;
|
|
unsigned idx = failure.getValue();
|
|
if (auto tupleTy = failure.getFirstType()->getAs<TupleType>()) {
|
|
name = tupleTy->getElement(idx).getName();
|
|
} else {
|
|
// Scalar.
|
|
assert(idx == 0);
|
|
}
|
|
|
|
if (name.empty())
|
|
tc.diagnose(loc, diag::missing_argument_positional, idx+1);
|
|
else
|
|
tc.diagnose(loc, diag::missing_argument_named, name);
|
|
return true;
|
|
}
|
|
|
|
case Failure::ExtraArgument: {
|
|
if (auto tuple = dyn_cast_or_null<TupleExpr>(anchor)) {
|
|
unsigned firstIdx = failure.getValue();
|
|
auto name = tuple->getElementName(firstIdx);
|
|
if (name.empty())
|
|
tc.diagnose(loc, diag::extra_argument_positional)
|
|
.highlight(tuple->getElement(firstIdx)->getSourceRange());
|
|
else
|
|
tc.diagnose(loc, diag::extra_argument_named, name)
|
|
.highlight(tuple->getElement(firstIdx)->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
case Failure::IsNotOptional: {
|
|
if (auto force = dyn_cast_or_null<ForceValueExpr>(anchor)) {
|
|
// If there was an 'as' cast in the subexpression, note it.
|
|
if (auto *cast = findForcedDowncast(tc.Context, force->getSubExpr())) {
|
|
tc.diagnose(force->getLoc(), diag::forcing_explicit_downcast,
|
|
failure.getFirstType())
|
|
.highlight(cast->getLoc())
|
|
.fixItRemove(force->getLoc());
|
|
return true;
|
|
}
|
|
|
|
tc.diagnose(loc, diag::invalid_force_unwrap,
|
|
failure.getFirstType())
|
|
.highlight(force->getSourceRange())
|
|
.fixItRemove(force->getExclaimLoc());
|
|
|
|
return true;
|
|
}
|
|
|
|
if (auto bind = dyn_cast_or_null<BindOptionalExpr>(anchor)) {
|
|
tc.diagnose(loc, diag::invalid_optional_chain,
|
|
failure.getFirstType())
|
|
.highlight(bind->getSourceRange())
|
|
.fixItRemove(bind->getQuestionLoc());
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
case Failure::NoPublicInitializers: {
|
|
tc.diagnose(loc, diag::no_accessible_initializers, failure.getFirstType())
|
|
.highlight(range);
|
|
if (targetLocator && !useExprLoc)
|
|
noteTargetOfDiagnostic(cs, &failure, targetLocator);
|
|
break;
|
|
}
|
|
|
|
case Failure::IsNotMaterializable: {
|
|
tc.diagnose(loc, diag::cannot_bind_generic_parameter_to_type,
|
|
failure.getFirstType())
|
|
.highlight(range);
|
|
if (!useExprLoc)
|
|
noteTargetOfDiagnostic(cs, &failure, locator);
|
|
break;
|
|
}
|
|
|
|
case Failure::FunctionAutoclosureMismatch:
|
|
case Failure::FunctionNoReturnMismatch:
|
|
case Failure::IsNotArchetype:
|
|
case Failure::IsNotClass:
|
|
case Failure::IsNotDynamicLookup:
|
|
case Failure::IsNotMetatype:
|
|
case Failure::TupleNameMismatch:
|
|
case Failure::TupleNamePositionMismatch:
|
|
case Failure::TupleVariadicMismatch:
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// \brief Determine the number of distinct overload choices in the
|
|
/// provided set.
|
|
static unsigned countDistinctOverloads(ArrayRef<OverloadChoice> choices) {
|
|
llvm::SmallPtrSet<void *, 4> uniqueChoices;
|
|
unsigned result = 0;
|
|
for (auto choice : choices) {
|
|
if (uniqueChoices.insert(choice.getOpaqueChoiceSimple()).second)
|
|
++result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// \brief Determine the name of the overload in a set of overload choices.
|
|
static DeclName getOverloadChoiceName(ArrayRef<OverloadChoice> choices) {
|
|
for (auto choice : choices) {
|
|
if (choice.isDecl())
|
|
return choice.getDecl()->getFullName();
|
|
}
|
|
|
|
return DeclName();
|
|
}
|
|
|
|
static bool diagnoseAmbiguity(ConstraintSystem &cs,
|
|
ArrayRef<Solution> solutions,
|
|
Expr *expr) {
|
|
// Produce a diff of the solutions.
|
|
SolutionDiff diff(solutions);
|
|
|
|
// Find the locators which have the largest numbers of distinct overloads.
|
|
Optional<unsigned> bestOverload;
|
|
unsigned maxDistinctOverloads = 0;
|
|
unsigned maxDepth = 0;
|
|
unsigned minIndex = std::numeric_limits<unsigned>::max();
|
|
|
|
// Get a map of expressions to their depths and post-order traversal indices.
|
|
// Heuristically, all other things being equal, we should complain about the
|
|
// ambiguous expression that (1) has the most overloads, (2) is deepest, or
|
|
// (3) comes earliest in the expression.
|
|
auto depthMap = expr->getDepthMap();
|
|
auto indexMap = expr->getPreorderIndexMap();
|
|
|
|
for (unsigned i = 0, n = diff.overloads.size(); i != n; ++i) {
|
|
auto &overload = diff.overloads[i];
|
|
|
|
// If we can't resolve the locator to an anchor expression with no path,
|
|
// we can't diagnose this well.
|
|
auto *anchor = simplifyLocatorToAnchor(cs, overload.locator);
|
|
if (!anchor)
|
|
continue;
|
|
auto it = indexMap.find(anchor);
|
|
if (it == indexMap.end())
|
|
continue;
|
|
unsigned index = it->second;
|
|
it = depthMap.find(anchor);
|
|
if (it == depthMap.end())
|
|
continue;
|
|
unsigned depth = it->second;
|
|
|
|
// If we don't have a name to hang on to, it'll be hard to diagnose this
|
|
// overload.
|
|
if (!getOverloadChoiceName(overload.choices))
|
|
continue;
|
|
|
|
unsigned distinctOverloads = countDistinctOverloads(overload.choices);
|
|
|
|
// We need at least two overloads to make this interesting.
|
|
if (distinctOverloads < 2)
|
|
continue;
|
|
|
|
// If we have more distinct overload choices for this locator than for
|
|
// prior locators, just keep this locator.
|
|
|
|
bool better = false;
|
|
if (bestOverload) {
|
|
if (distinctOverloads > maxDistinctOverloads) {
|
|
better = true;
|
|
} else if (distinctOverloads == maxDistinctOverloads) {
|
|
if (depth > maxDepth) {
|
|
better = true;
|
|
} else if (depth == maxDepth) {
|
|
if (index < minIndex) {
|
|
better = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bestOverload || better) {
|
|
bestOverload = i;
|
|
maxDistinctOverloads = distinctOverloads;
|
|
maxDepth = depth;
|
|
minIndex = index;
|
|
continue;
|
|
}
|
|
|
|
// We have better results. Ignore this one.
|
|
}
|
|
|
|
// FIXME: Should be able to pick the best locator, e.g., based on some
|
|
// depth-first numbering of expressions.
|
|
if (bestOverload) {
|
|
auto &overload = diff.overloads[*bestOverload];
|
|
auto name = getOverloadChoiceName(overload.choices);
|
|
auto anchor = simplifyLocatorToAnchor(cs, overload.locator);
|
|
|
|
// Emit the ambiguity diagnostic.
|
|
auto &tc = cs.getTypeChecker();
|
|
tc.diagnose(anchor->getLoc(),
|
|
name.isOperator() ? diag::ambiguous_operator_ref
|
|
: diag::ambiguous_decl_ref,
|
|
name);
|
|
|
|
// Emit candidates. Use a SmallPtrSet to make sure only emit a particular
|
|
// candidate once. FIXME: Why is one candidate getting into the overload
|
|
// set multiple times?
|
|
SmallPtrSet<Decl*, 8> EmittedDecls;
|
|
for (auto choice : overload.choices) {
|
|
switch (choice.getKind()) {
|
|
case OverloadChoiceKind::Decl:
|
|
case OverloadChoiceKind::DeclViaDynamic:
|
|
case OverloadChoiceKind::TypeDecl:
|
|
case OverloadChoiceKind::DeclViaBridge:
|
|
case OverloadChoiceKind::DeclViaUnwrappedOptional:
|
|
// FIXME: show deduced types, etc, etc.
|
|
if (EmittedDecls.insert(choice.getDecl()).second)
|
|
tc.diagnose(choice.getDecl(), diag::found_candidate);
|
|
break;
|
|
|
|
case OverloadChoiceKind::BaseType:
|
|
case OverloadChoiceKind::TupleIndex:
|
|
// FIXME: Actually diagnose something here.
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// FIXME: If we inferred different types for literals (for example),
|
|
// could diagnose ambiguity that way as well.
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Conveniently unwrap a paren expression, if necessary.
|
|
static Expr *unwrapParenExpr(Expr *e) {
|
|
if (auto parenExpr = dyn_cast<ParenExpr>(e))
|
|
return unwrapParenExpr(parenExpr->getSubExpr());
|
|
|
|
return e;
|
|
}
|
|
|
|
static SmallVector<Type, 4> decomposeArgumentType(Type ty) {
|
|
SmallVector<Type, 4> result;
|
|
|
|
// Assemble the parameter type list.
|
|
if (auto parenType = dyn_cast<ParenType>(ty.getPointer())) {
|
|
result.push_back(parenType->getUnderlyingType());
|
|
} else if (auto tupleType = ty->getAs<TupleType>()) {
|
|
for (auto field : tupleType->getElements())
|
|
result.push_back(field.getType());
|
|
} else {
|
|
result.push_back(ty);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static std::string getTypeListString(Type type) {
|
|
// Assemble the parameter type list.
|
|
auto tupleType = type->getAs<TupleType>();
|
|
if (!tupleType) {
|
|
if (auto PT = dyn_cast<ParenType>(type.getPointer()))
|
|
type = PT->getUnderlyingType();
|
|
|
|
return "(" + type->getString() + ")";
|
|
}
|
|
|
|
std::string result = "(";
|
|
for (auto field : tupleType->getElements()) {
|
|
if (result.size() != 1)
|
|
result += ", ";
|
|
if (!field.getName().empty()) {
|
|
result += field.getName().str();
|
|
result += ": ";
|
|
}
|
|
|
|
if (!field.isVararg())
|
|
result += field.getType()->getString();
|
|
else {
|
|
result += field.getVarargBaseTy()->getString();
|
|
result += "...";
|
|
}
|
|
}
|
|
result += ")";
|
|
return result;
|
|
}
|
|
|
|
|
|
/// If an UnresolvedDotExpr, SubscriptMember, etc has been resolved by the
|
|
/// constraint system, return the decl that it references.
|
|
static ValueDecl *findResolvedMemberRef(ConstraintLocator *locator,
|
|
ConstraintSystem &CS) {
|
|
auto *resolvedOverloadSets = CS.getResolvedOverloadSets();
|
|
if (!resolvedOverloadSets) return nullptr;
|
|
|
|
// Search through the resolvedOverloadSets to see if we have a resolution for
|
|
// this member. This is an O(n) search, but only happens when producing an
|
|
// error diagnostic.
|
|
for (auto resolved = resolvedOverloadSets;
|
|
resolved; resolved = resolved->Previous) {
|
|
if (resolved->Locator != locator) continue;
|
|
|
|
// We only handle the simplest decl binding.
|
|
if (resolved->Choice.getKind() != OverloadChoiceKind::Decl)
|
|
return nullptr;
|
|
return resolved->Choice.getDecl();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
/// Given an expression that has a non-lvalue type, dig into it until we find
|
|
/// the part of the expression that prevents the entire subexpression from being
|
|
/// mutable. For example, in a sequence like "x.v.v = 42" we want to complain
|
|
/// about "x" being a let property if "v.v" are both mutable.
|
|
///
|
|
/// This returns the base subexpression that looks immutable (or that can't be
|
|
/// analyzed any further) along with a decl extracted from it if we could.
|
|
///
|
|
static std::pair<Expr*, ValueDecl*>
|
|
resolveImmutableBase(Expr *expr, ConstraintSystem &CS) {
|
|
expr = expr->getSemanticsProvidingExpr();
|
|
|
|
// Provide specific diagnostics for assignment to subscripts whose base expr
|
|
// is known to be an rvalue.
|
|
if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
|
|
// If we found a decl for the subscript, check to see if it is a set-only
|
|
// subscript decl.
|
|
SubscriptDecl *member = nullptr;
|
|
if (SE->hasDecl())
|
|
member = dyn_cast_or_null<SubscriptDecl>(SE->getDecl().getDecl());
|
|
|
|
if (!member) {
|
|
auto loc = CS.getConstraintLocator(SE,ConstraintLocator::SubscriptMember);
|
|
member = dyn_cast_or_null<SubscriptDecl>(findResolvedMemberRef(loc, CS));
|
|
}
|
|
|
|
// If it isn't settable, return it.
|
|
if (member) {
|
|
if (!member->isSettable() ||
|
|
!member->isSetterAccessibleFrom(CS.DC))
|
|
return { expr, member };
|
|
}
|
|
|
|
// If it is settable, then the base must be the problem, recurse.
|
|
return resolveImmutableBase(SE->getBase(), CS);
|
|
}
|
|
|
|
// Look through property references.
|
|
if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr)) {
|
|
// If we found a decl for the UDE, check it.
|
|
auto loc = CS.getConstraintLocator(UDE, ConstraintLocator::Member);
|
|
auto *member = dyn_cast_or_null<VarDecl>(findResolvedMemberRef(loc, CS));
|
|
|
|
// If the member isn't settable, then it is the problem: return it.
|
|
if (member) {
|
|
if (!member->isSettable(nullptr) ||
|
|
!member->isSetterAccessibleFrom(CS.DC))
|
|
return { expr, member };
|
|
}
|
|
|
|
// If we weren't able to resolve a member or if it is mutable, then the
|
|
// problem must be with the base, recurse.
|
|
return resolveImmutableBase(UDE->getBase(), CS);
|
|
}
|
|
|
|
if (auto *MRE = dyn_cast<MemberRefExpr>(expr)) {
|
|
// If the member isn't settable, then it is the problem: return it.
|
|
if (auto member = dyn_cast<AbstractStorageDecl>(MRE->getMember().getDecl()))
|
|
if (!member->isSettable(nullptr) ||
|
|
!member->isSetterAccessibleFrom(CS.DC))
|
|
return { expr, member };
|
|
|
|
// If we weren't able to resolve a member or if it is mutable, then the
|
|
// problem must be with the base, recurse.
|
|
return resolveImmutableBase(MRE->getBase(), CS);
|
|
}
|
|
|
|
if (auto *DRE = dyn_cast<DeclRefExpr>(expr))
|
|
return { expr, DRE->getDecl() };
|
|
|
|
// Look through x!
|
|
if (auto *FVE = dyn_cast<ForceValueExpr>(expr))
|
|
return resolveImmutableBase(FVE->getSubExpr(), CS);
|
|
|
|
// Look through x?
|
|
if (auto *BOE = dyn_cast<BindOptionalExpr>(expr))
|
|
return resolveImmutableBase(BOE->getSubExpr(), CS);
|
|
|
|
return { expr, nullptr };
|
|
}
|
|
|
|
static void diagnoseSubElementFailure(Expr *destExpr,
|
|
SourceLoc loc,
|
|
ConstraintSystem &CS,
|
|
Diag<StringRef> diagID,
|
|
Diag<Type> unknownDiagID) {
|
|
auto &TC = CS.getTypeChecker();
|
|
|
|
// Walk through the destination expression, resolving what the problem is. If
|
|
// we find a node in the lvalue path that is problematic, this returns it.
|
|
auto immInfo = resolveImmutableBase(destExpr, CS);
|
|
|
|
// Otherwise, we cannot resolve this because the available setter candidates
|
|
// are all mutating and the base must be mutating. If we dug out a
|
|
// problematic decl, we can produce a nice tailored diagnostic.
|
|
if (auto *VD = dyn_cast_or_null<VarDecl>(immInfo.second)) {
|
|
std::string message = "'";
|
|
message += VD->getName().str().str();
|
|
message += "'";
|
|
|
|
if (VD->isImplicit())
|
|
message += " is immutable";
|
|
else if (VD->isLet())
|
|
message += " is a 'let' constant";
|
|
else if (VD->hasAccessorFunctions() && !VD->getSetter())
|
|
message += " is a get-only property";
|
|
else if (!VD->isSetterAccessibleFrom(CS.DC))
|
|
message += " setter is inaccessible";
|
|
else {
|
|
message += " is immutable";
|
|
}
|
|
TC.diagnose(loc, diagID, message)
|
|
.highlight(immInfo.first->getSourceRange());
|
|
|
|
// If this is a simple variable marked with a 'let', emit a note to fixit
|
|
// hint it to 'var'.
|
|
VD->emitLetToVarNoteIfSimple(CS.DC);
|
|
return;
|
|
}
|
|
|
|
// If the underlying expression was a read-only subscript, diagnose that.
|
|
if (auto *SD = dyn_cast_or_null<SubscriptDecl>(immInfo.second)) {
|
|
StringRef message;
|
|
if (!SD->getSetter())
|
|
message = "subscript is get-only";
|
|
else if (!SD->isSetterAccessibleFrom(CS.DC))
|
|
message = "subscript setter is inaccessible";
|
|
else
|
|
message = "subscript is immutable";
|
|
|
|
TC.diagnose(loc, diagID, message)
|
|
.highlight(immInfo.first->getSourceRange());
|
|
return;
|
|
}
|
|
|
|
// If the expression is the result of a call, it is an rvalue, not a mutable
|
|
// lvalue.
|
|
if (auto *AE = dyn_cast<ApplyExpr>(immInfo.first)) {
|
|
std::string name = "call";
|
|
if (isa<PrefixUnaryExpr>(AE) || isa<PostfixUnaryExpr>(AE))
|
|
name = "unary operator";
|
|
else if (isa<BinaryExpr>(AE))
|
|
name = "binary operator";
|
|
else if (isa<CallExpr>(AE))
|
|
name = "function call";
|
|
else if (isa<DotSyntaxCallExpr>(AE) || isa<DotSyntaxBaseIgnoredExpr>(AE))
|
|
name = "method call";
|
|
|
|
if (auto *DRE =
|
|
dyn_cast<DeclRefExpr>(AE->getFn()->getSemanticsProvidingExpr()))
|
|
name = std::string("'") + DRE->getDecl()->getName().str().str() + "'";
|
|
|
|
TC.diagnose(loc, diagID, name + " returns immutable value")
|
|
.highlight(AE->getSourceRange());
|
|
return;
|
|
}
|
|
|
|
TC.diagnose(loc, unknownDiagID, destExpr->getType())
|
|
.highlight(immInfo.first->getSourceRange());
|
|
}
|
|
|
|
namespace {
|
|
/// Each match in an ApplyExpr is evaluated for how close of a match it is.
|
|
/// The result is captured in this enum value, where the earlier entries are
|
|
/// most specific.
|
|
enum CandidateCloseness {
|
|
CC_ExactMatch, // This is a perfect match for the arguments.
|
|
CC_NonLValueInOut, // First argument is inout but no lvalue present.
|
|
CC_OneArgumentMismatch, // All arguments except one match.
|
|
CC_SelfMismatch, // Self argument mismatches.
|
|
CC_ArgumentMismatch, // Argument list mismatch.
|
|
CC_ArgumentCountMismatch, // This candidate has wrong # arguments.
|
|
CC_GeneralMismatch // Something else is wrong.
|
|
};
|
|
|
|
/// This is a candidate for a callee, along with an uncurry level.
|
|
///
|
|
/// The uncurry level specifies how far much of a curried value has already
|
|
/// been applied. For example, in a funcdecl of:
|
|
/// func f(a:Int)(b:Double) -> Int
|
|
/// Uncurry level of 0 indicates that we're looking at the "a" argument, an
|
|
/// uncurry level of 1 indicates that we're looking at the "b" argument.
|
|
struct UncurriedCandidate {
|
|
ValueDecl *decl;
|
|
unsigned level;
|
|
|
|
AnyFunctionType *getUncurriedFunctionType() const {
|
|
#if 1 // TODO: Simplify with unresolved types? Can this be removed?
|
|
if (!decl->hasType())
|
|
return nullptr;
|
|
#endif
|
|
|
|
auto type = decl->getType();
|
|
|
|
// If this is an operator func decl in a type context, the 'self' isn't
|
|
// actually going to be applied.
|
|
if (auto *fd = dyn_cast<FuncDecl>(decl))
|
|
if (fd->isOperator() && fd->getDeclContext()->isTypeContext())
|
|
type = type->castTo<AnyFunctionType>()->getResult();
|
|
|
|
for (unsigned i = 0, e = level; i != e; ++i) {
|
|
auto funcTy = type->getAs<AnyFunctionType>();
|
|
if (!funcTy) return nullptr;
|
|
type = funcTy->getResult();
|
|
}
|
|
|
|
return type->getAs<AnyFunctionType>();
|
|
}
|
|
|
|
/// Given a function candidate with an uncurry level, return the parameter
|
|
/// type at the specified uncurry level. If there is an error getting to
|
|
/// the specified input, this returns a null Type.
|
|
Type getArgumentType() const {
|
|
if (auto *funcTy = getUncurriedFunctionType())
|
|
return funcTy->getInput();
|
|
return Type();
|
|
}
|
|
|
|
/// Given a function candidate with an uncurry level, return the parameter
|
|
/// type at the specified uncurry level. If there is an error getting to
|
|
/// the specified input, this returns a null Type.
|
|
Type getResultType() const {
|
|
if (auto *funcTy = getUncurriedFunctionType())
|
|
return funcTy->getResult();
|
|
return Type();
|
|
}
|
|
};
|
|
|
|
|
|
/// This struct represents an analyzed function pointer to determine the
|
|
/// candidates that could be called, or the one concrete decl that will be
|
|
/// called if not ambiguous.
|
|
class CalleeCandidateInfo {
|
|
ConstraintSystem *CS;
|
|
public:
|
|
std::string declName;
|
|
|
|
/// This is the list of candidates identified.
|
|
SmallVector<UncurriedCandidate, 4> candidates;
|
|
|
|
/// This tracks how close the match is.
|
|
CandidateCloseness closeness;
|
|
|
|
/// Analyze a function expr and break it into a candidate set. On failure,
|
|
/// this leaves the candidate list empty.
|
|
CalleeCandidateInfo(Expr *Fn, ConstraintSystem *CS) : CS(CS) {
|
|
collectCalleeCandidates(Fn);
|
|
}
|
|
|
|
/// Analyze a locator for a SubscriptExpr for its candidate set.
|
|
CalleeCandidateInfo(ConstraintLocator *locator, ConstraintSystem *CS);
|
|
|
|
typedef const std::function<CandidateCloseness(UncurriedCandidate)>
|
|
&ClosenessPredicate;
|
|
|
|
/// After the candidate list is formed, it can be filtered down to discard
|
|
/// obviously mismatching candidates and compute a "closeness" for the
|
|
/// resultant set.
|
|
void filterList(Type actualArgsType);
|
|
void filterList(ClosenessPredicate predicate);
|
|
|
|
bool empty() const { return candidates.empty(); }
|
|
unsigned size() const { return candidates.size(); }
|
|
UncurriedCandidate operator[](unsigned i) const {
|
|
return candidates[i];
|
|
}
|
|
|
|
/// Given a set of parameter lists from an overload group, and a list of
|
|
/// arguments, emit a diagnostic indicating any partially matching
|
|
/// overloads.
|
|
void suggestPotentialOverloads(StringRef functionName, SourceLoc loc,
|
|
bool isCallExpr = false);
|
|
|
|
private:
|
|
void collectCalleeCandidates(Expr *fnExpr);
|
|
};
|
|
}
|
|
|
|
|
|
/// Given a candidate list, this computes the narrowest closeness to the match
|
|
/// we're looking for and filters out any worse matches. The predicate
|
|
/// indicates how close a given candidate is to the desired match.
|
|
void CalleeCandidateInfo::filterList(ClosenessPredicate predicate) {
|
|
closeness = CC_GeneralMismatch;
|
|
|
|
// If we couldn't find anything, give up.
|
|
if (candidates.empty())
|
|
return;
|
|
|
|
// Now that we have the candidate list, figure out what the best matches from
|
|
// the candidate list are, and remove all the ones that aren't at that level.
|
|
SmallVector<CandidateCloseness, 4> closenessList;
|
|
closenessList.reserve(candidates.size());
|
|
for (auto decl : candidates) {
|
|
closenessList.push_back(predicate(decl));
|
|
closeness = std::min(closeness, closenessList.back());
|
|
}
|
|
|
|
// Now that we know the minimum closeness, remove all the elements that aren't
|
|
// as close.
|
|
unsigned NextElt = 0;
|
|
for (unsigned i = 0, e = candidates.size(); i != e; ++i) {
|
|
// If this decl in the result list isn't a close match, ignore it.
|
|
if (closeness != closenessList[i])
|
|
continue;
|
|
|
|
// Otherwise, preserve it.
|
|
candidates[NextElt++] = candidates[i];
|
|
}
|
|
|
|
candidates.erase(candidates.begin()+NextElt, candidates.end());
|
|
}
|
|
|
|
|
|
/// Determine how close an argument list is to an already decomposed argument
|
|
/// list.
|
|
static CandidateCloseness
|
|
evaluateCloseness(Type candArgListType, ArrayRef<Type> actualArgs) {
|
|
auto candArgs = decomposeArgumentType(candArgListType);
|
|
|
|
// FIXME: This isn't handling varargs, and isn't handling default values
|
|
// either.
|
|
if (actualArgs.size() != candArgs.size()) {
|
|
// If the candidate is varargs, and if there are more arguments specified
|
|
// than required, consider this a general mismatch.
|
|
// TODO: we could catalog the remaining entries if they *do* match up.
|
|
if (auto *TT = candArgListType->getAs<TupleType>()) {
|
|
if (!TT->getElements().empty()) {
|
|
if (TT->getElements().back().isVararg() &&
|
|
actualArgs.size() >= TT->getElements().size()-1)
|
|
return CC_GeneralMismatch;
|
|
}
|
|
}
|
|
|
|
return CC_ArgumentCountMismatch;
|
|
}
|
|
|
|
// Count the number of mismatched arguments.
|
|
unsigned mismatchingArgs = 0;
|
|
for (unsigned i = 0, e = actualArgs.size(); i != e; ++i) {
|
|
// FIXME: Right now, a "matching" overload is one with a parameter whose
|
|
// type is identical to one of the argument types. We can obviously do
|
|
// something more sophisticated with this.
|
|
if (!actualArgs[i]->getRValueType()->isEqual(candArgs[i]))
|
|
++mismatchingArgs;
|
|
}
|
|
|
|
// If the arguments match up exactly, then we have an exact match. This
|
|
// handles the no-argument cases as well.
|
|
if (mismatchingArgs == 0)
|
|
return CC_ExactMatch;
|
|
|
|
// Check to see if the first argument expects an inout argument, but is not
|
|
// an lvalue.
|
|
if (candArgs[0]->is<InOutType>() && !actualArgs[0]->isLValueType())
|
|
return CC_NonLValueInOut;
|
|
|
|
if (mismatchingArgs == 1)
|
|
return actualArgs.size() != 1 ? CC_OneArgumentMismatch :CC_ArgumentMismatch;
|
|
|
|
// TODO: Keyword argument mismatches.
|
|
|
|
return CC_GeneralMismatch;
|
|
}
|
|
|
|
|
|
void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn) {
|
|
fn = fn->getSemanticsProvidingExpr();
|
|
|
|
// Treat a call to a load of a variable as a call to that variable, it is just
|
|
// the lvalue'ness being removed.
|
|
if (auto load = dyn_cast<LoadExpr>(fn)) {
|
|
if (isa<DeclRefExpr>(load->getSubExpr()))
|
|
return collectCalleeCandidates(load->getSubExpr());
|
|
}
|
|
|
|
if (auto declRefExpr = dyn_cast<DeclRefExpr>(fn)) {
|
|
candidates.push_back({ declRefExpr->getDecl(), 0 });
|
|
declName = declRefExpr->getDecl()->getNameStr().str();
|
|
return;
|
|
}
|
|
|
|
if (auto declRefExpr = dyn_cast<OtherConstructorDeclRefExpr>(fn)) {
|
|
auto decl = declRefExpr->getDecl();
|
|
candidates.push_back({ decl, 0 });
|
|
|
|
if (auto fTy = decl->getType()->getAs<AnyFunctionType>())
|
|
declName = fTy->getInput()->getRValueInstanceType()->getString()+".init";
|
|
else
|
|
declName = "init";
|
|
return;
|
|
}
|
|
|
|
if (auto overloadedDRE = dyn_cast<OverloadedDeclRefExpr>(fn)) {
|
|
for (auto cand : overloadedDRE->getDecls()) {
|
|
candidates.push_back({ cand, 0 });
|
|
}
|
|
|
|
if (!candidates.empty())
|
|
declName = candidates[0].decl->getNameStr().str();
|
|
return;
|
|
}
|
|
|
|
if (auto TE = dyn_cast<TypeExpr>(fn)) {
|
|
// It's always a metatype type, so use the instance type name.
|
|
auto instanceType =TE->getType()->castTo<MetatypeType>()->getInstanceType();
|
|
|
|
// TODO: figure out right value for isKnownPrivate
|
|
if (!instanceType->getAs<TupleType>()) {
|
|
auto ctors = CS->TC.lookupConstructors(CS->DC, instanceType);
|
|
for (auto ctor : ctors)
|
|
if (ctor->hasType())
|
|
candidates.push_back({ ctor, 1 });
|
|
}
|
|
|
|
declName = instanceType->getString();
|
|
return;
|
|
}
|
|
|
|
if (auto *DSBI = dyn_cast<DotSyntaxBaseIgnoredExpr>(fn)) {
|
|
collectCalleeCandidates(DSBI->getRHS());
|
|
return;
|
|
}
|
|
|
|
|
|
if (auto AE = dyn_cast<ApplyExpr>(fn)) {
|
|
collectCalleeCandidates(AE->getFn());
|
|
|
|
// If we found a candidate list with a recursive walk, try adjust the curry
|
|
// level for the applied subexpression in this call.
|
|
if (!candidates.empty()) {
|
|
for (auto &C : candidates)
|
|
C.level += 1;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Otherwise, we couldn't tell structurally what is going on here, so try to
|
|
// dig something out of the constraint system.
|
|
unsigned uncurryLevel = 0;
|
|
|
|
// The candidate list of an unresolved_dot_expr is the candidate list of the
|
|
// base uncurried by one level, and we refer to the name of the member, not to
|
|
// the name of any base.
|
|
if (auto UDE = dyn_cast<UnresolvedDotExpr>(fn)) {
|
|
declName = UDE->getName().str().str();
|
|
uncurryLevel = 1;
|
|
|
|
// If we actually resolved the member to use, return it.
|
|
auto loc = CS->getConstraintLocator(UDE, ConstraintLocator::Member);
|
|
if (auto *member = findResolvedMemberRef(loc, *CS)) {
|
|
candidates.push_back({ member, uncurryLevel });
|
|
return;
|
|
}
|
|
// Otherwise, look for a disjunction constraint explaining what the set is.
|
|
}
|
|
|
|
// Calls to super.init() are automatically uncurried one level.
|
|
if (auto *UCE = dyn_cast<UnresolvedConstructorExpr>(fn)) {
|
|
uncurryLevel = 1;
|
|
|
|
auto selfTy = UCE->getSubExpr()->getType()->getLValueOrInOutObjectType();
|
|
if (selfTy->hasTypeVariable())
|
|
declName = "init";
|
|
else
|
|
declName = selfTy.getString() + ".init";
|
|
}
|
|
|
|
if (isa<MemberRefExpr>(fn))
|
|
uncurryLevel = 1;
|
|
|
|
// Scan to see if we have a disjunction constraint for this callee.
|
|
for (auto &constraint : CS->getConstraints()) {
|
|
if (constraint.getKind() != ConstraintKind::Disjunction) continue;
|
|
|
|
auto locator = constraint.getLocator();
|
|
if (!locator || locator->getAnchor() != fn) continue;
|
|
|
|
for (auto *bindOverload : constraint.getNestedConstraints()) {
|
|
if (bindOverload->getKind() != ConstraintKind::BindOverload)
|
|
continue;
|
|
auto c = bindOverload->getOverloadChoice();
|
|
if (c.isDecl())
|
|
candidates.push_back({ c.getDecl(), uncurryLevel });
|
|
}
|
|
|
|
// If we found some candidates, then we're done.
|
|
if (candidates.empty()) continue;
|
|
|
|
if (declName.empty())
|
|
declName = candidates[0].decl->getNameStr().str();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// After the candidate list is formed, it can be filtered down to discard
|
|
/// obviously mismatching candidates and compute a "closeness" for the
|
|
/// resultant set.
|
|
void CalleeCandidateInfo::filterList(Type actualArgsType) {
|
|
// Now that we have the candidate list, figure out what the best matches from
|
|
// the candidate list are, and remove all the ones that aren't at that level.
|
|
auto actualArgs = decomposeArgumentType(actualArgsType);
|
|
filterList([&](UncurriedCandidate candidate) -> CandidateCloseness {
|
|
auto inputType = candidate.getArgumentType();
|
|
// If this isn't a function or isn't valid at this uncurry level, treat it
|
|
// as a general mismatch.
|
|
if (!inputType) return CC_GeneralMismatch;
|
|
return evaluateCloseness(inputType, actualArgs);
|
|
});
|
|
}
|
|
|
|
CalleeCandidateInfo::CalleeCandidateInfo(ConstraintLocator *locator,
|
|
ConstraintSystem *CS) : CS(CS) {
|
|
if (auto decl = findResolvedMemberRef(locator, *CS)) {
|
|
// If the decl is fully resolved, add it.
|
|
candidates.push_back({ decl, 0 });
|
|
} else {
|
|
// Otherwise, look for a disjunction between different candidates.
|
|
for (auto &constraint : CS->getConstraints()) {
|
|
if (constraint.getLocator() != locator) continue;
|
|
|
|
// Okay, we found our constraint. Check to see if it is a disjunction.
|
|
if (constraint.getKind() != ConstraintKind::Disjunction) continue;
|
|
|
|
for (auto *bindOverload : constraint.getNestedConstraints()) {
|
|
auto c = bindOverload->getOverloadChoice();
|
|
if (c.isDecl())
|
|
candidates.push_back({ c.getDecl(), 0 });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// Given a set of parameter lists from an overload group, and a list of
|
|
/// arguments, emit a diagnostic indicating any partially matching overloads.
|
|
void CalleeCandidateInfo::
|
|
suggestPotentialOverloads(StringRef functionName, SourceLoc loc,
|
|
bool isCallExpr) {
|
|
|
|
// If the candidate list is has no near matches to the actual types, don't
|
|
// print out a candidate list, it will just be noise.
|
|
if (closeness == CC_GeneralMismatch) {
|
|
|
|
// FIXME: This is arbitrary, we should use the same policy for operators.
|
|
if (!isCallExpr)
|
|
return;
|
|
}
|
|
|
|
std::string suggestionText = "";
|
|
std::set<std::string> dupes;
|
|
|
|
// FIXME2: For (T,T) & (Self, Self), emit this as two candidates, one using
|
|
// the LHS and one using the RHS type for T's.
|
|
for (auto cand : candidates) {
|
|
Type paramListType;
|
|
|
|
if (auto *SD = dyn_cast<SubscriptDecl>(cand.decl)) {
|
|
paramListType = SD->getIndicesType();
|
|
} else {
|
|
paramListType = cand.getArgumentType();
|
|
}
|
|
if (paramListType.isNull())
|
|
continue;
|
|
|
|
// If we've already seen this (e.g. decls overridden on the result type),
|
|
// ignore this one.
|
|
auto name = getTypeListString(paramListType);
|
|
if (!dupes.insert(name).second)
|
|
continue;
|
|
|
|
if (!suggestionText.empty())
|
|
suggestionText += ", ";
|
|
suggestionText += name;
|
|
}
|
|
|
|
if (suggestionText.empty())
|
|
return;
|
|
|
|
if (dupes.size() == 1) {
|
|
CS->TC.diagnose(loc, diag::suggest_expected_match, suggestionText);
|
|
} else {
|
|
CS->TC.diagnose(loc, diag::suggest_partial_overloads, functionName,
|
|
suggestionText);
|
|
}
|
|
}
|
|
|
|
/// Flags that can be used to control name lookup.
|
|
enum TCCFlags {
|
|
/// Don't force the subexpression to resolve to a specific type. If the
|
|
/// subexpr is ambiguous, don't diagnose an error.
|
|
/// FIXME: this should always be on.
|
|
TCC_AllowUnresolved = 0x01,
|
|
|
|
/// Allow the result of the subexpression to be an lvalue. If this is not
|
|
/// specified, any lvalue will be forced to be loaded into an rvalue.
|
|
TCC_AllowLValue = 0x02
|
|
};
|
|
|
|
typedef OptionSet<TCCFlags> TCCOptions;
|
|
|
|
inline TCCOptions operator|(TCCFlags flag1, TCCFlags flag2) {
|
|
return TCCOptions(flag1) | flag2;
|
|
}
|
|
|
|
|
|
namespace {
|
|
/// If a constraint system fails to converge on a solution for a given
|
|
/// expression, this class can produce a reasonable diagnostic for the failure
|
|
/// by analyzing the remnants of the failed constraint system. (Specifically,
|
|
/// left-over inactive, active and failed constraints.)
|
|
/// This class does not tune its diagnostics for a specific expression kind,
|
|
/// for that, you'll want to use an instance of the FailureDiagnosis class.
|
|
class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
|
|
friend class ASTVisitor<FailureDiagnosis, /*exprresult*/bool>;
|
|
|
|
Expr *expr = nullptr;
|
|
ConstraintSystem *const CS;
|
|
public:
|
|
FailureDiagnosis(Expr *expr, ConstraintSystem *cs) : expr(expr), CS(cs) {
|
|
assert(expr && CS);
|
|
}
|
|
|
|
template<typename ...ArgTypes>
|
|
InFlightDiagnostic diagnose(ArgTypes &&...Args) {
|
|
return CS->TC.diagnose(std::forward<ArgTypes>(Args)...);
|
|
}
|
|
|
|
/// Attempt to diagnose a failure without taking into account the specific
|
|
/// kind of expression that could not be type checked.
|
|
bool diagnoseConstraintFailure();
|
|
|
|
/// Unless we've already done this, retypecheck the specified child of the
|
|
/// current expression on its own, without including any contextual
|
|
/// constraints or the parent expr nodes. This is more likely to succeed than
|
|
/// type checking the original expression.
|
|
///
|
|
/// This mention may only be used on immediate children of the current expr
|
|
/// node, because ClosureExpr parameters need to be treated specially.
|
|
///
|
|
/// This can return a new expression (for e.g. when a UnresolvedDeclRef gets
|
|
/// resolved) and returns null when the subexpression fails to typecheck.
|
|
///
|
|
Expr *typeCheckChildIndependently(Expr *subExpr, Type convertType = Type(),
|
|
ContextualTypePurpose convertTypePurpose = CTP_Unused,
|
|
TCCOptions options = TCCOptions());
|
|
Expr *typeCheckChildIndependently(Expr *subExpr, TCCOptions options) {
|
|
return typeCheckChildIndependently(subExpr, Type(), CTP_Unused, options);
|
|
}
|
|
|
|
Type getTypeOfTypeCheckedChildIndependently(Expr *subExpr,
|
|
TCCOptions options = TCCOptions()) {
|
|
auto e = typeCheckChildIndependently(subExpr, options);
|
|
return e ? e->getType() : Type();
|
|
}
|
|
|
|
/// This is the same as typeCheckChildIndependently, but works on an arbitrary
|
|
/// subexpression of the current node because it handles ClosureExpr parents
|
|
/// of the specified node.
|
|
Expr *typeCheckArbitrarySubExprIndependently(Expr *subExpr,
|
|
TCCOptions options = TCCOptions());
|
|
|
|
/// Special magic to handle inout exprs and tuples in argument lists.
|
|
Expr *typeCheckArgumentChildIndependently(Expr *argExpr, Type argType,
|
|
const CalleeCandidateInfo &candidates);
|
|
|
|
/// Attempt to diagnose a specific failure from the info we've collected from
|
|
/// the failed constraint system.
|
|
bool diagnoseExprFailure();
|
|
|
|
/// Emit an ambiguity diagnostic about the specified expression.
|
|
void diagnoseAmbiguity(Expr *E);
|
|
|
|
|
|
private:
|
|
|
|
/// Attempt to produce a diagnostic for a mismatch between an expression's
|
|
/// type and its assumed contextual type.
|
|
bool diagnoseContextualConversionError(Type exprResultType);
|
|
|
|
/// Produce a diagnostic for a general member-lookup failure (irrespective of
|
|
/// the exact expression kind).
|
|
bool diagnoseGeneralMemberFailure(Constraint *constraint);
|
|
|
|
/// Produce a diagnostic for a general overload resolution failure
|
|
/// (irrespective of the exact expression kind).
|
|
bool diagnoseGeneralOverloadFailure(Constraint *constraint);
|
|
|
|
/// Produce a diagnostic for a general conversion failure (irrespective of the
|
|
/// exact expression kind).
|
|
bool diagnoseGeneralConversionFailure(Constraint *constraint);
|
|
|
|
bool visitExpr(Expr *E);
|
|
|
|
bool visitForceValueExpr(ForceValueExpr *FVE);
|
|
bool visitBindOptionalExpr(BindOptionalExpr *BOE);
|
|
|
|
bool visitBinaryExpr(BinaryExpr *BE);
|
|
bool visitUnaryExpr(ApplyExpr *AE);
|
|
bool visitPrefixUnaryExpr(PrefixUnaryExpr *PUE) {
|
|
return visitUnaryExpr(PUE);
|
|
}
|
|
bool visitPostfixUnaryExpr(PostfixUnaryExpr *PUE) {
|
|
return visitUnaryExpr(PUE);
|
|
}
|
|
|
|
bool visitSubscriptExpr(SubscriptExpr *SE);
|
|
bool visitCallExpr(CallExpr *CE);
|
|
bool visitAssignExpr(AssignExpr *AE);
|
|
bool visitInOutExpr(InOutExpr *IOE);
|
|
bool visitCoerceExpr(CoerceExpr *CE);
|
|
bool visitForcedCheckedCastExpr(ForcedCheckedCastExpr *FCCE);
|
|
bool visitIfExpr(IfExpr *IE);
|
|
bool visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E);
|
|
bool visitClosureExpr(ClosureExpr *CE);
|
|
};
|
|
} // end anonymous namespace.
|
|
|
|
|
|
|
|
static bool isMemberConstraint(Constraint *C) {
|
|
return C->getKind() == ConstraintKind::ValueMember ||
|
|
C->getKind() == ConstraintKind::UnresolvedValueMember ||
|
|
C->getKind() == ConstraintKind::TypeMember;
|
|
}
|
|
|
|
static bool isOverloadConstraint(Constraint *C) {
|
|
if (C->getKind() == ConstraintKind::BindOverload)
|
|
return true;
|
|
|
|
if (C->getKind() != ConstraintKind::Disjunction)
|
|
return false;
|
|
|
|
return C->getNestedConstraints().front()->getKind() ==
|
|
ConstraintKind::BindOverload;
|
|
}
|
|
|
|
/// Return true if this constraint is a conversion or requirement between two
|
|
/// types.
|
|
static bool isConversionConstraint(const Constraint *C) {
|
|
switch (C->getKind()) {
|
|
case ConstraintKind::Conversion:
|
|
case ConstraintKind::ExplicitConversion:
|
|
case ConstraintKind::ArgumentConversion:
|
|
case ConstraintKind::ArgumentTupleConversion:
|
|
case ConstraintKind::ConformsTo:
|
|
case ConstraintKind::SelfObjectOfProtocol:
|
|
case ConstraintKind::Subtype:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Attempt to diagnose a failure without taking into account the specific
|
|
/// kind of expression that could not be type checked.
|
|
bool FailureDiagnosis::diagnoseConstraintFailure() {
|
|
// This is the priority order in which we handle constraints. Things earlier
|
|
// in the list are considered to have higher specificity (and thus, higher
|
|
// priority) than things lower in the list.
|
|
enum ConstraintRanking {
|
|
CR_MemberConstraint,
|
|
CR_OverloadConstraint,
|
|
CR_ConversionConstraint,
|
|
CR_OtherConstraint
|
|
};
|
|
|
|
// Start out by classifying all the constraints.
|
|
typedef std::pair<Constraint*, ConstraintRanking> RCElt;
|
|
std::vector<RCElt> rankedConstraints;
|
|
|
|
// This is a predicate that classifies constraints according to our
|
|
// priorities.
|
|
auto classifyConstraint = [&](Constraint *C) -> ConstraintRanking {
|
|
if (isMemberConstraint(C))
|
|
return CR_MemberConstraint;
|
|
|
|
if (isOverloadConstraint(C))
|
|
return CR_OverloadConstraint;
|
|
|
|
if (isConversionConstraint(C))
|
|
return CR_ConversionConstraint;
|
|
|
|
return CR_OtherConstraint;
|
|
};
|
|
|
|
// Look at the failed constraint and the general constraint list.
|
|
if (CS->failedConstraint) {
|
|
rankedConstraints.push_back({
|
|
CS->failedConstraint,
|
|
classifyConstraint(CS->failedConstraint)
|
|
});
|
|
}
|
|
for (auto &C : CS->getConstraints())
|
|
rankedConstraints.push_back({ &C, classifyConstraint(&C)} );
|
|
|
|
// Okay, now that we've classified all the constraints, sort them by their
|
|
// priority and priviledge the favored constraints.
|
|
std::stable_sort(rankedConstraints.begin(), rankedConstraints.end(),
|
|
[&] (RCElt LHS, RCElt RHS) {
|
|
// Rank things by their kind as the highest priority.
|
|
if (LHS.second < RHS.second)
|
|
return true;
|
|
if (LHS.second > RHS.second)
|
|
return false;
|
|
// Next priority is favored constraints.
|
|
if (LHS.first->isFavored())
|
|
return true;
|
|
if (RHS.first->isFavored())
|
|
return false;
|
|
// Finally, rank disjunction constraints lower than non-disjunction
|
|
// constraints.
|
|
bool LHSDisj = LHS.first->getKind() == ConstraintKind::Disjunction;
|
|
bool RHSDisj = RHS.first->getKind() == ConstraintKind::Disjunction;
|
|
return LHSDisj < RHSDisj;
|
|
});
|
|
|
|
// Now that we have a sorted precedence of constraints to diagnose, charge
|
|
// through them.
|
|
for (auto elt : rankedConstraints) {
|
|
auto C = elt.first;
|
|
switch (elt.second) {
|
|
case CR_MemberConstraint:
|
|
if (diagnoseGeneralMemberFailure(C))
|
|
return true;
|
|
continue;
|
|
case CR_OverloadConstraint:
|
|
if (diagnoseGeneralOverloadFailure(C))
|
|
return true;
|
|
continue;
|
|
case CR_ConversionConstraint:
|
|
case CR_OtherConstraint:
|
|
if (diagnoseGeneralConversionFailure(C))
|
|
return true;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Otherwise, all the constraints look ok, diagnose this as an ambiguous
|
|
// expression.
|
|
return false;
|
|
}
|
|
|
|
|
|
bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) {
|
|
assert(isMemberConstraint(constraint));
|
|
|
|
auto memberName = constraint->getMember();
|
|
|
|
// Get the referenced expression from the failed constraint.
|
|
auto anchor = expr;
|
|
SourceRange range = anchor->getSourceRange();
|
|
if (auto locator = constraint->getLocator()) {
|
|
locator = simplifyLocator(*CS, locator, range);
|
|
if (locator->getAnchor())
|
|
anchor = locator->getAnchor();
|
|
}
|
|
|
|
// Retypecheck the anchor type, which is the base of the member expression.
|
|
anchor = typeCheckArbitrarySubExprIndependently(anchor, TCC_AllowLValue);
|
|
if (!anchor) return true;
|
|
|
|
auto baseTy = anchor->getType();
|
|
auto baseObjTy = baseTy->getRValueType();
|
|
|
|
// If the base type is an IUO, look through it. Odds are, the code is not
|
|
// trying to find a member of it.
|
|
if (auto objTy = CS->lookThroughImplicitlyUnwrappedOptionalType(baseObjTy))
|
|
baseObjTy = objTy;
|
|
|
|
|
|
if (auto moduleTy = baseObjTy->getAs<ModuleType>()) {
|
|
diagnose(anchor->getLoc(), diag::no_member_of_module,
|
|
moduleTy->getModule()->getName(), memberName)
|
|
.highlight(anchor->getSourceRange()).highlight(range);
|
|
return true;
|
|
}
|
|
|
|
// If the base of this property access is a function that takes an empty
|
|
// argument list, then the most likely problem is that the user wanted to
|
|
// call the function, e.g. in "a.b.c" where they had to write "a.b().c".
|
|
// Produce a specific diagnostic + fixit for this situation.
|
|
if (auto baseFTy = baseObjTy->getAs<AnyFunctionType>()) {
|
|
if (baseFTy->getInput()->isEqual(CS->TC.Context.TheEmptyTupleType)) {
|
|
SourceLoc insertLoc = anchor->getEndLoc();
|
|
|
|
if (auto *DRE = dyn_cast<DeclRefExpr>(anchor)) {
|
|
diagnose(anchor->getLoc(), diag::did_not_call_function,
|
|
DRE->getDecl()->getName())
|
|
.fixItInsertAfter(insertLoc, "()");
|
|
return true;
|
|
}
|
|
|
|
if (auto *DSCE = dyn_cast<DotSyntaxCallExpr>(anchor))
|
|
if (auto *DRE = dyn_cast<DeclRefExpr>(DSCE->getFn())) {
|
|
diagnose(anchor->getLoc(), diag::did_not_call_method,
|
|
DRE->getDecl()->getName())
|
|
.fixItInsertAfter(insertLoc, "()");
|
|
return true;
|
|
}
|
|
|
|
diagnose(anchor->getLoc(), diag::did_not_call_function_value)
|
|
.fixItInsertAfter(insertLoc, "()");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (baseObjTy->is<TupleType>()) {
|
|
diagnose(anchor->getLoc(), diag::could_not_find_tuple_member,
|
|
baseObjTy, memberName)
|
|
.highlight(anchor->getSourceRange()).highlight(range);
|
|
return true;
|
|
}
|
|
|
|
MemberLookupResult result = CS->performMemberLookup(baseObjTy, *constraint);
|
|
|
|
switch (result.OverallResult) {
|
|
case MemberLookupResult::Unsolved:
|
|
// Diagnose 'super.init', which can only appear inside another initializer,
|
|
// specially.
|
|
if (memberName.isSimpleName(CS->TC.Context.Id_init) &&
|
|
!baseObjTy->is<MetatypeType>()) {
|
|
if (auto ctorRef = dyn_cast<UnresolvedConstructorExpr>(anchor)) {
|
|
if (isa<SuperRefExpr>(ctorRef->getSubExpr())) {
|
|
diagnose(anchor->getLoc(),
|
|
diag::super_initializer_not_in_initializer);
|
|
return true;
|
|
}
|
|
|
|
// Suggest inserting '.dynamicType' to construct another object of the
|
|
// same dynamic type.
|
|
SourceLoc fixItLoc = ctorRef->getConstructorLoc().getAdvancedLoc(-1);
|
|
|
|
// Place the '.dynamicType' right before the init.
|
|
diagnose(anchor->getLoc(), diag::init_not_instance_member)
|
|
.fixItInsert(fixItLoc, ".dynamicType");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// If we couldn't resolve a specific type for the base expression, then we
|
|
// cannot produce a specific diagnostic.
|
|
return false;
|
|
|
|
case MemberLookupResult::ErrorAlreadyDiagnosed:
|
|
// If an error was already emitted, then we're done, don't emit anything
|
|
// redundant.
|
|
return true;
|
|
|
|
case MemberLookupResult::HasResults:
|
|
break;
|
|
}
|
|
|
|
// We know that this is a failing lookup, so we should have no viable
|
|
// candidates here.
|
|
if (!result.ViableCandidates.empty())
|
|
return false;
|
|
|
|
// If we found no results at all, mention that fact.
|
|
if (result.UnviableCandidates.empty()) {
|
|
// TODO: This should handle tuple member lookups, like x.1231 as well.
|
|
if (auto MTT = baseObjTy->getAs<MetatypeType>())
|
|
diagnose(anchor->getLoc(), diag::could_not_find_type_member,
|
|
MTT->getInstanceType(), memberName)
|
|
.highlight(anchor->getSourceRange()).highlight(range);
|
|
else
|
|
diagnose(anchor->getLoc(), diag::could_not_find_value_member,
|
|
baseObjTy, memberName)
|
|
.highlight(anchor->getSourceRange()).highlight(range);
|
|
return true;
|
|
}
|
|
|
|
// Otherwise, we have at least one (and potentially many) viable candidates
|
|
// sort them out. If all of the candidates have the same problem (commonly
|
|
// because there is exactly one candidate!) diagnose this.
|
|
bool sameProblem = true;
|
|
auto firstProblem = result.UnviableCandidates[0].second;
|
|
for (auto cand : result.UnviableCandidates)
|
|
sameProblem &= cand.second == firstProblem;
|
|
|
|
auto instanceTy = baseObjTy;
|
|
if (auto *MTT = instanceTy->getAs<AnyMetatypeType>())
|
|
instanceTy = MTT->getInstanceType();
|
|
|
|
if (sameProblem) {
|
|
switch (firstProblem) {
|
|
case MemberLookupResult::UR_LabelMismatch:
|
|
break;
|
|
case MemberLookupResult::UR_UnavailableInExistential:
|
|
diagnose(anchor->getLoc(), diag::could_not_use_member_on_existential,
|
|
instanceTy, memberName)
|
|
.highlight(anchor->getSourceRange()).highlight(range);
|
|
return true;
|
|
case MemberLookupResult::UR_InstanceMemberOnType:
|
|
diagnose(anchor->getLoc(), diag::could_not_use_instance_member_on_type,
|
|
instanceTy, memberName)
|
|
.highlight(anchor->getSourceRange()).highlight(range);
|
|
return true;
|
|
case MemberLookupResult::UR_TypeMemberOnInstance:
|
|
diagnose(anchor->getLoc(), diag::could_not_use_type_member_on_instance,
|
|
baseObjTy, memberName)
|
|
.highlight(anchor->getSourceRange()).highlight(range);
|
|
return true;
|
|
|
|
case MemberLookupResult::UR_MutatingMemberOnRValue:
|
|
case MemberLookupResult::UR_MutatingGetterOnRValue:
|
|
auto diagIDsubelt = diag::cannot_pass_rvalue_mutating_subelement;
|
|
auto diagIDmember = diag::cannot_pass_rvalue_mutating;
|
|
if (firstProblem == MemberLookupResult::UR_MutatingGetterOnRValue) {
|
|
diagIDsubelt = diag::cannot_pass_rvalue_mutating_getter_subelement;
|
|
diagIDmember = diag::cannot_pass_rvalue_mutating_getter;
|
|
}
|
|
diagnoseSubElementFailure(anchor, anchor->getLoc(), *CS,
|
|
diagIDsubelt, diagIDmember);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// FIXME: Emit candidate set....
|
|
|
|
|
|
// Otherwise, we don't have a specific issue to diagnose. Just say the vague
|
|
// 'cannot use' diagnostic.
|
|
if (!baseObjTy->isEqual(instanceTy))
|
|
diagnose(anchor->getLoc(), diag::could_not_use_type_member,
|
|
instanceTy, memberName)
|
|
.highlight(anchor->getSourceRange()).highlight(range);
|
|
else
|
|
diagnose(anchor->getLoc(), diag::could_not_use_value_member,
|
|
baseObjTy, memberName)
|
|
.highlight(anchor->getSourceRange()).highlight(range);
|
|
return true;
|
|
}
|
|
|
|
// In the absense of a better conversion constraint failure, point out the
|
|
// inability to find an appropriate overload.
|
|
bool FailureDiagnosis::diagnoseGeneralOverloadFailure(Constraint *constraint) {
|
|
Constraint *bindOverload = constraint;
|
|
if (constraint->getKind() == ConstraintKind::Disjunction)
|
|
bindOverload = constraint->getNestedConstraints().front();
|
|
|
|
auto overloadChoice = bindOverload->getOverloadChoice();
|
|
std::string overloadName = overloadChoice.getDecl()->getNameStr();
|
|
|
|
if (auto *CD = dyn_cast<ConstructorDecl>(overloadChoice.getDecl()))
|
|
if (auto *SD = CD->getImplicitSelfDecl())
|
|
overloadName = SD->getType()->getInOutObjectType().getString() + ".init";
|
|
|
|
// Get the referenced expression from the failed constraint.
|
|
auto anchor = expr;
|
|
if (auto locator = bindOverload->getLocator()) {
|
|
anchor = simplifyLocatorToAnchor(*CS, locator);
|
|
if (!anchor)
|
|
anchor = locator->getAnchor();
|
|
}
|
|
|
|
// The anchor for the constraint is almost always an OverloadedDeclRefExpr or
|
|
// UnresolvedDotExpr. Look at the parent node in the AST to find the Apply to
|
|
// give a better diagnostic.
|
|
Expr *call = expr->getParentMap()[anchor];
|
|
// Ignore parens around the callee.
|
|
while (call) {
|
|
bool shouldIgnore = isa<IdentityExpr>(call);
|
|
if (!shouldIgnore)
|
|
shouldIgnore = isa<AnyTryExpr>(call) && !isa<OptionalTryExpr>(call);
|
|
if (shouldIgnore)
|
|
break;
|
|
call = expr->getParentMap()[call];
|
|
}
|
|
|
|
// Do some sanity checking based on the call: e.g. make sure we're invoking
|
|
// the overloaded decl, not using it as an argument.
|
|
Expr *argExpr = nullptr;
|
|
SourceLoc fnLoc;
|
|
if (auto *AE = dyn_cast_or_null<ApplyExpr>(call)) {
|
|
if (AE->getFn()->getSemanticsProvidingExpr() == anchor) {
|
|
// Type check the argument list independently to try to get a concrete
|
|
// type (ignoring context).
|
|
argExpr = typeCheckArbitrarySubExprIndependently(AE->getArg(),
|
|
TCC_AllowUnresolved);
|
|
if (!argExpr) return true;
|
|
}
|
|
|
|
fnLoc = AE->getFn()->getLoc();
|
|
}
|
|
|
|
// If we couldn't resolve an argument, then produce a generic "ambiguity"
|
|
// diagnostic.
|
|
if (!argExpr || argExpr->getType()->is<TypeVariableType>()) {
|
|
if (constraint->getKind() != ConstraintKind::Disjunction) {
|
|
diagnose(anchor->getLoc(), diag::cannot_find_appropriate_overload,
|
|
overloadName)
|
|
.highlight(anchor->getSourceRange());
|
|
diagnose(overloadChoice.getDecl()->getLoc(), diag::found_candidate);
|
|
return true;
|
|
}
|
|
|
|
diagnose(anchor->getLoc(), diag::ambiguous_member_overload_set,
|
|
overloadName)
|
|
.highlight(anchor->getSourceRange());
|
|
|
|
for (auto elt : constraint->getNestedConstraints()) {
|
|
if (elt->getKind() != ConstraintKind::BindOverload) continue;
|
|
auto candidate = elt->getOverloadChoice().getDecl();
|
|
diagnose(candidate->getLoc(), diag::found_candidate);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Type argType = argExpr->getType();
|
|
|
|
// Otherwise, we have a good grasp on what is going on: we have a call of an
|
|
// unresolve overload set. Try to dig out the candidates.
|
|
auto apply = cast<ApplyExpr>(call);
|
|
CalleeCandidateInfo calleeInfo(apply->getFn(), CS);
|
|
calleeInfo.filterList(argType);
|
|
|
|
// Otherwise, whatever the result type of the call happened to be must not
|
|
// have been what we were looking for - diagnose this as a conversion
|
|
// failure.
|
|
if (calleeInfo.closeness == CC_ExactMatch)
|
|
return false;
|
|
|
|
// A common error is to apply an operator that only has an inout LHS (e.g. +=)
|
|
// to non-lvalues (e.g. a local let). Produce a nice diagnostic for this
|
|
// case.
|
|
if (calleeInfo.closeness == CC_NonLValueInOut) {
|
|
Expr *firstArg = argExpr;
|
|
if (auto *tuple = dyn_cast<TupleExpr>(firstArg))
|
|
if (tuple->getNumElements())
|
|
firstArg = tuple->getElement(0);
|
|
|
|
diagnoseSubElementFailure(firstArg, call->getLoc(), *CS,
|
|
diag::cannot_apply_lvalue_binop_to_subelement,
|
|
diag::cannot_apply_lvalue_binop_to_rvalue);
|
|
return true;
|
|
}
|
|
|
|
// If we have an argument list (i.e., a scalar, or a non-zero-element tuple)
|
|
// then diagnose with some specificity about the arguments.
|
|
if (isa<TupleExpr>(argExpr) &&
|
|
cast<TupleExpr>(argExpr)->getNumElements() == 0) {
|
|
// Emit diagnostics that say "no arguments".
|
|
diagnose(fnLoc, diag::cannot_call_with_no_params,
|
|
overloadName, /*isInitializer*/false)
|
|
.highlight(call->getSourceRange());
|
|
} else {
|
|
diagnose(fnLoc, diag::cannot_call_with_params,
|
|
overloadName, getTypeListString(argType), /*isInitializer*/false)
|
|
.highlight(call->getSourceRange());
|
|
}
|
|
|
|
calleeInfo.suggestPotentialOverloads(overloadName, call->getLoc());
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
|
|
auto anchor = expr;
|
|
if (auto locator = constraint->getLocator()) {
|
|
anchor = simplifyLocatorToAnchor(*CS, locator);
|
|
if (!anchor)
|
|
anchor = locator->getAnchor();
|
|
}
|
|
|
|
Type fromType = CS->simplifyType(constraint->getFirstType());
|
|
if (fromType->is<TypeVariableType>()) {
|
|
auto sub = typeCheckArbitrarySubExprIndependently(anchor);
|
|
if (!sub) return true;
|
|
fromType = sub->getType();
|
|
}
|
|
|
|
fromType = fromType->getRValueType();
|
|
auto toType = CS->simplifyType(constraint->getSecondType());
|
|
|
|
// If this constraint doesn't simplify into an error, then
|
|
if (CS->simplifyConstraint(*constraint) !=
|
|
ConstraintSystem::SolutionKind::Error)
|
|
return false;
|
|
|
|
|
|
// If the second type is a type variable, the expression itself is
|
|
// ambiguous. Bail out so the general ambiguity diagnosing logic can handle
|
|
// it.
|
|
if (fromType->is<TypeVariableType>() ||
|
|
fromType->is<UnresolvedType>() ||
|
|
fromType->is<UnboundGenericType>() ||
|
|
toType->is<TypeVariableType>() ||
|
|
toType->is<UnresolvedType>()) {
|
|
diagnoseAmbiguity(anchor);
|
|
return true;
|
|
}
|
|
|
|
auto failureKind = Failure::FailureKind::TypesNotConvertible;
|
|
switch (constraint->getKind()) {
|
|
case ConstraintKind::ConformsTo:
|
|
case ConstraintKind::SelfObjectOfProtocol:
|
|
if (auto pt = toType->getAs<ProtocolType>())
|
|
if (pt->getDecl()->
|
|
isSpecificProtocol(KnownProtocolKind::NilLiteralConvertible)) {
|
|
diagnose(expr->getLoc(), diag::cannot_use_nil_with_this_type, toType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
diagnose(anchor->getLoc(), diag::type_does_not_conform,
|
|
fromType, toType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
|
|
case ConstraintKind::Subtype:
|
|
failureKind = Failure::FailureKind::TypesNotSubtypes;
|
|
break;
|
|
case ConstraintKind::Conversion:
|
|
case ConstraintKind::ExplicitConversion:
|
|
failureKind = Failure::FailureKind::TypesNotConvertible;
|
|
break;
|
|
case ConstraintKind::ArgumentTupleConversion:
|
|
default: break;
|
|
}
|
|
|
|
// Try to simplify irrelevant details of function types. For example, if
|
|
// someone passes a "() -> Float" function to a "() throws -> Int"
|
|
// parameter, then uttering the "throws" may confuse them into thinking that
|
|
// that is the problem, even though there is a clear subtype relation.
|
|
if (auto srcFT = fromType->getAs<FunctionType>())
|
|
if (auto destFT = toType->getAs<FunctionType>()) {
|
|
auto destExtInfo = destFT->getExtInfo();
|
|
|
|
if (!srcFT->isNoEscape()) destExtInfo = destExtInfo.withNoEscape(false);
|
|
if (!srcFT->throws()) destExtInfo = destExtInfo.withThrows(false);
|
|
if (destExtInfo != destFT->getExtInfo())
|
|
toType = FunctionType::get(destFT->getInput(),
|
|
destFT->getResult(), destExtInfo);
|
|
|
|
// If this is a function conversion that discards throwability or
|
|
// noescape, emit a specific diagnostic about that.
|
|
if (srcFT->throws() && !destFT->throws()) {
|
|
diagnose(expr->getLoc(), diag::throws_functiontype_mismatch,
|
|
fromType, toType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
if (srcFT->isNoEscape() && !destFT->isNoEscape()) {
|
|
diagnose(expr->getLoc(), diag::noescape_functiontype_mismatch,
|
|
fromType, toType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
diagnose(anchor->getLoc(), diag::invalid_relation,
|
|
failureKind - Failure::TypesNotEqual,
|
|
fromType, toType)
|
|
.highlight(anchor->getSourceRange());
|
|
|
|
return true;
|
|
}
|
|
namespace {
|
|
class ExprTypeSaver {
|
|
llvm::DenseMap<Expr*, Type> ExprTypes;
|
|
llvm::DenseMap<TypeLoc*, std::pair<Type, bool>> TypeLocTypes;
|
|
llvm::DenseMap<Pattern*, Type> PatternTypes;
|
|
public:
|
|
|
|
void save(Expr *E) {
|
|
struct TypeSaver : public ASTWalker {
|
|
ExprTypeSaver *TS;
|
|
TypeSaver(ExprTypeSaver *TS) : TS(TS) {}
|
|
|
|
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
|
|
TS->ExprTypes[expr] = expr->getType();
|
|
return { true, expr };
|
|
}
|
|
|
|
bool walkToTypeLocPre(TypeLoc &TL) override {
|
|
if (TL.getTypeRepr() && TL.getType())
|
|
TS->TypeLocTypes[&TL] = { TL.getType(), TL.wasValidated() };
|
|
return true;
|
|
}
|
|
|
|
std::pair<bool, Pattern*> walkToPatternPre(Pattern *P) override {
|
|
if (P->hasType())
|
|
TS->PatternTypes[P] = P->getType();
|
|
return { true, P };
|
|
}
|
|
|
|
// Don't walk into statements. This handles the BraceStmt in
|
|
// non-single-expr closures, so we don't walk into their body.
|
|
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
|
|
return { false, S };
|
|
}
|
|
};
|
|
|
|
E->walk(TypeSaver(this));
|
|
}
|
|
|
|
void restore(Expr *E) {
|
|
for (auto exprElt : ExprTypes)
|
|
exprElt.first->setType(exprElt.second);
|
|
|
|
for (auto typelocElt : TypeLocTypes)
|
|
typelocElt.first->setType(typelocElt.second.first,
|
|
typelocElt.second.second);
|
|
|
|
for (auto patternElt : PatternTypes)
|
|
patternElt.first->setType(patternElt.second);
|
|
|
|
// Done, don't do redundant work on destruction.
|
|
ExprTypes.clear();
|
|
TypeLocTypes.clear();
|
|
PatternTypes.clear();
|
|
}
|
|
|
|
// On destruction, if a type got wiped out, reset it from null to its
|
|
// original type. This is helpful because type checking a subexpression
|
|
// can lead to replacing the nodes in that subexpression. However, the
|
|
// failed ConstraintSystem still has locators pointing to the old nodes,
|
|
// and if expr-specific diagnostics fail to turn up anything useful to say,
|
|
// we go digging through failed constraints, and expect their locators to
|
|
// still be meaningful.
|
|
~ExprTypeSaver() {
|
|
for (auto exprElt : ExprTypes)
|
|
if (!exprElt.first->getType())
|
|
exprElt.first->setType(exprElt.second);
|
|
|
|
for (auto typelocElt : TypeLocTypes)
|
|
if (!typelocElt.first->getType())
|
|
typelocElt.first->setType(typelocElt.second.first,
|
|
typelocElt.second.second);
|
|
|
|
for (auto patternElt : PatternTypes)
|
|
if (!patternElt.first->hasType())
|
|
patternElt.first->setType(patternElt.second);
|
|
}
|
|
};
|
|
}
|
|
|
|
/// \brief "Nullify" an expression tree's type data, to make it suitable for
|
|
/// re-typecheck operations.
|
|
static void eraseTypeData(Expr *expr) {
|
|
/// Private class to "cleanse" an expression tree of types. This is done in the
|
|
/// case of a typecheck failure, where we may want to re-typecheck partially-
|
|
/// typechecked subexpressions in a context-free manner.
|
|
class TypeNullifier : public ASTWalker {
|
|
public:
|
|
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
|
|
// Preserve module expr type data to prevent further lookups.
|
|
if (auto *declRef = dyn_cast<DeclRefExpr>(expr))
|
|
if (isa<ModuleDecl>(declRef->getDecl()))
|
|
return { false, expr };
|
|
|
|
// Don't strip type info off OtherConstructorDeclRefExpr, because CSGen
|
|
// doesn't know how to reconstruct it.
|
|
if (isa<OtherConstructorDeclRefExpr>(expr))
|
|
return { false, expr };
|
|
|
|
// If a literal has a Builtin.Int or Builtin.FP type on it already,
|
|
// then sema has already expanded out a call to
|
|
// Init.init(<builtinliteral>)
|
|
// and we don't want it to make
|
|
// Init.init(Init.init(<builtinliteral>))
|
|
// preserve the type info to prevent this from happening.
|
|
if (isa<IntegerLiteralExpr>(expr) || isa<FloatLiteralExpr>(expr) ||
|
|
isa<BooleanLiteralExpr>(expr))
|
|
if (expr->getType()->is<BuiltinType>())
|
|
return { false, expr };
|
|
|
|
expr->setType(nullptr);
|
|
return { true, expr };
|
|
}
|
|
|
|
// If we find a TypeLoc (e.g. in an as? expr) with a type variable, rewrite
|
|
// it.
|
|
bool walkToTypeLocPre(TypeLoc &TL) override {
|
|
if (TL.getTypeRepr())
|
|
TL.setType(Type(), /*was validated*/false);
|
|
return true;
|
|
}
|
|
|
|
std::pair<bool, Pattern*> walkToPatternPre(Pattern *pattern) override {
|
|
pattern->setType(nullptr);
|
|
return { true, pattern };
|
|
}
|
|
|
|
// Don't walk into statements. This handles the BraceStmt in
|
|
// non-single-expr closures, so we don't walk into their body.
|
|
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
|
|
return { false, S };
|
|
}
|
|
};
|
|
|
|
expr->walk(TypeNullifier());
|
|
}
|
|
|
|
|
|
/// Erase an expression tree's open existentials after a re-typecheck operation.
|
|
///
|
|
/// This is done in the case of a typecheck failure, after we re-typecheck
|
|
/// partially-typechecked subexpressions in a context-free manner.
|
|
///
|
|
static void eraseOpenedExistentials(Expr *&expr) {
|
|
|
|
class ExistentialEraser : public ASTWalker {
|
|
llvm::SmallDenseMap<OpaqueValueExpr *, Expr *, 4> OpenExistentials;
|
|
|
|
public:
|
|
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
|
|
if (auto openExistentialExpr = dyn_cast<OpenExistentialExpr>(expr)) {
|
|
auto archetypeVal = openExistentialExpr->getOpaqueValue();
|
|
auto base = openExistentialExpr->getExistentialValue();
|
|
bool inserted = OpenExistentials.insert({archetypeVal, base}).second;
|
|
assert(inserted);
|
|
(void) inserted;
|
|
return { true, openExistentialExpr->getSubExpr() };
|
|
}
|
|
|
|
if (auto opaqueValueExpr = dyn_cast<OpaqueValueExpr>(expr)) {
|
|
auto value = OpenExistentials.find(opaqueValueExpr);
|
|
assert(value != OpenExistentials.end());
|
|
return { true, value->second };
|
|
}
|
|
|
|
return { true, expr };
|
|
}
|
|
|
|
Expr *walkToExprPost(Expr *expr) override {
|
|
Type type = expr->getType();
|
|
if (!type || !type->hasOpenedExistential())
|
|
return expr;
|
|
|
|
type = type.transform([&](Type type) -> Type {
|
|
if (auto archetype = type->getAs<ArchetypeType>())
|
|
if (auto existentialType = archetype->getOpenedExistentialType())
|
|
return existentialType;
|
|
|
|
return type;
|
|
});
|
|
expr->setType(type);
|
|
|
|
return expr;
|
|
}
|
|
|
|
// Don't walk into statements. This handles the BraceStmt in
|
|
// non-single-expr closures, so we don't walk into their body.
|
|
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
|
|
return { false, S };
|
|
}
|
|
};
|
|
|
|
expr->walk(ExistentialEraser());
|
|
}
|
|
|
|
|
|
/// Unless we've already done this, retypecheck the specified subexpression on
|
|
/// its own, without including any contextual constraints or parent expr
|
|
/// nodes. This is more likely to succeed than type checking the original
|
|
/// expression.
|
|
///
|
|
/// This can return a new expression (for e.g. when a UnresolvedDeclRef gets
|
|
/// resolved) and returns null when the subexpression fails to typecheck.
|
|
Expr *FailureDiagnosis::typeCheckChildIndependently(Expr *subExpr,
|
|
Type convertType,
|
|
ContextualTypePurpose convertTypePurpose,
|
|
TCCOptions options) {
|
|
// Track if this sub-expression is currently being diagnosed.
|
|
if (Expr *res = CS->TC.isExprBeingDiagnosed(subExpr))
|
|
return res;
|
|
|
|
// FIXME: expressions are never removed from this set.
|
|
CS->TC.addExprForDiagnosis(subExpr, subExpr);
|
|
|
|
|
|
// If we have a conversion type, but it has type variables (from the current
|
|
// ConstraintSystem), then we can't use it.
|
|
if (convertType &&
|
|
(convertType->hasTypeVariable() ||
|
|
// If the contextual type has an archetype, we need to open it, but
|
|
// don't know how yet.
|
|
// FIXME: implement opening of archetypes.
|
|
convertType->hasArchetype())) {
|
|
convertType = Type();
|
|
convertTypePurpose = CTP_Unused;
|
|
}
|
|
|
|
if (isa<ClosureExpr>(subExpr))
|
|
options |= TCC_AllowUnresolved;
|
|
|
|
// These expression types can never be checked without their enclosing
|
|
// context, so don't try - it would just make bogus diagnostics.
|
|
if (isa<NilLiteralExpr>(subExpr) ||
|
|
|
|
// A '_' is only allowed on the LHS of an assignment, so we can't descend
|
|
// past the AssignExpr. This is a problem below because we're not
|
|
// allowing ambiguous solutions for subexprs, and thus the code below is
|
|
// forced to diagnose "discard_expr_outside_of_assignment". This should
|
|
// really allow ambiguous expressions and diagnose it only in MiscDiags.
|
|
isa<DiscardAssignmentExpr>(subExpr)) {
|
|
|
|
// If we have a contextual conversion type, then we *can* type check these.
|
|
if (!convertType)
|
|
return subExpr;
|
|
}
|
|
|
|
// TupleExpr often contains things that cannot be typechecked without
|
|
// context (usually from a parameter list), but we do it if they already have
|
|
// an unspecialized type.
|
|
// FIXME: This is a total hack.
|
|
if ((isa<TupleExpr>(subExpr) ||
|
|
|
|
// InOutExpr needs contextual information otherwise we complain about it
|
|
// not being in an argument context.
|
|
isa<InOutExpr>(subExpr)) &&
|
|
!subExpr->getType()->hasTypeVariable() &&
|
|
!convertType)
|
|
return subExpr;
|
|
|
|
|
|
ExprTypeSaver SavedTypeData;
|
|
SavedTypeData.save(subExpr);
|
|
|
|
// Store off the sub-expression, in case a new one is provided via the
|
|
// type check operation.
|
|
Expr *preCheckedExpr = subExpr;
|
|
|
|
eraseTypeData(subExpr);
|
|
|
|
// Disable structural checks, because we know that the overall expression
|
|
// has type constraint problems, and we don't want to know about any
|
|
// syntactic issues in a well-typed subexpression (which might be because
|
|
// the context is missing).
|
|
TypeCheckExprOptions TCEOptions = TypeCheckExprFlags::DisableStructuralChecks;
|
|
|
|
// Claim that the result is discarded to preserve the lvalue type of
|
|
// the expression.
|
|
if (options.contains(TCC_AllowLValue))
|
|
TCEOptions |= TypeCheckExprFlags::IsDiscarded;
|
|
|
|
if (options.contains(TCC_AllowUnresolved) && !convertType)
|
|
TCEOptions |= TypeCheckExprFlags::AllowUnresolvedTypeVariables;
|
|
|
|
bool hadError = CS->TC.typeCheckExpression(subExpr, CS->DC, convertType,
|
|
convertTypePurpose, TCEOptions);
|
|
|
|
// This is a terrible hack to get around the fact that typeCheckExpression()
|
|
// might change subExpr to point to a new OpenExistentialExpr. In that case,
|
|
// since the caller passed subExpr by value here, they would be left
|
|
// holding on to an expression containing open existential types but
|
|
// no OpenExistentialExpr, which breaks invariants enforced by the
|
|
// ASTChecker.
|
|
eraseOpenedExistentials(subExpr);
|
|
|
|
// If recursive type checking failed, then an error was emitted. Return
|
|
// null to indicate this to the caller.
|
|
if (hadError)
|
|
return nullptr;
|
|
|
|
// If we type checked the result but failed to get a usable output from it,
|
|
// just pretend as though nothing happened.
|
|
if (subExpr->getType()->is<ErrorType>()) {
|
|
subExpr = preCheckedExpr;
|
|
SavedTypeData.restore(subExpr);
|
|
}
|
|
|
|
CS->TC.addExprForDiagnosis(preCheckedExpr, subExpr);
|
|
return subExpr;
|
|
}
|
|
|
|
/// This is the same as typeCheckChildIndependently, but works on an arbitrary
|
|
/// subexpression of the current node because it handles ClosureExpr parents
|
|
/// of the specified node.
|
|
Expr *FailureDiagnosis::
|
|
typeCheckArbitrarySubExprIndependently(Expr *subExpr, TCCOptions options) {
|
|
if (subExpr == expr)
|
|
return typeCheckChildIndependently(subExpr, options);
|
|
|
|
// Construct a parent map for the expr tree we're investigating.
|
|
auto parentMap = expr->getParentMap();
|
|
|
|
ClosureExpr *NearestClosure = nullptr;
|
|
|
|
// Walk the parents of the specified expression, handling any ClosureExprs.
|
|
for (Expr *node = parentMap[subExpr]; node && node != expr;
|
|
node = parentMap[node]) {
|
|
auto *CE = dyn_cast<ClosureExpr>(node);
|
|
if (!CE) continue;
|
|
|
|
// Keep track of the innermost closure we see that we're jumping into.
|
|
if (!NearestClosure)
|
|
NearestClosure = CE;
|
|
|
|
// If we have a ClosureExpr parent of the specified node, check to make sure
|
|
// none of its arguments are type variables. If so, these type variables
|
|
// would be accessible to name lookup of the subexpression and may thus leak
|
|
// in. Reset them to UnresolvedTypes for safe measures.
|
|
CE->getParams()->forEachVariable([&](VarDecl *VD) {
|
|
if (VD->getType()->hasTypeVariable() || VD->getType()->is<ErrorType>())
|
|
VD->overwriteType(CS->getASTContext().TheUnresolvedType);
|
|
});
|
|
}
|
|
|
|
// When we're type checking a single-expression closure, we need to reset the
|
|
// DeclContext to this closure for the recursive type checking. Otherwise,
|
|
// if there is a closure in the subexpression, we can violate invariants.
|
|
auto newDC = NearestClosure ? NearestClosure : CS->DC;
|
|
llvm::SaveAndRestore<DeclContext*> SavedDC(CS->DC, newDC);
|
|
|
|
// Otherwise, we're ok to type check the subexpr.
|
|
return typeCheckChildIndependently(subExpr, options);
|
|
}
|
|
|
|
|
|
bool FailureDiagnosis::diagnoseContextualConversionError(Type exprType) {
|
|
// If we don't have a type for the expression, then we cannot use it in
|
|
// diagnostic generation. A common cause of this failure is that the
|
|
// subexpression has no inherent type (e.g. nil), and we're trying to convert
|
|
// it to something it isn't compatible with (e.g. Int). Handle a few of these
|
|
// cases.
|
|
if (exprType->is<TypeVariableType>()) {
|
|
if (Type contextualType = CS->getContextualType()) {
|
|
Diag<Type> nilDiag;
|
|
|
|
switch (CS->getContextualTypePurpose()) {
|
|
case CTP_Unused:
|
|
case CTP_CannotFail:
|
|
llvm_unreachable("These contextual type purposes cannot fail with a "
|
|
"conversion type specified!");
|
|
case CTP_Initialization:
|
|
nilDiag = diag::cannot_convert_initializer_value_nil;
|
|
break;
|
|
case CTP_ReturnStmt:
|
|
nilDiag = diag::cannot_convert_to_return_type_nil;
|
|
break;
|
|
case CTP_ThrowStmt:
|
|
nilDiag = diag::cannot_convert_thrown_type;
|
|
break;
|
|
|
|
case CTP_EnumCaseRawValue:
|
|
nilDiag = diag::cannot_convert_raw_initializer_value_nil;
|
|
break;
|
|
case CTP_DefaultParameter:
|
|
nilDiag = diag::cannot_convert_default_arg_value_nil;
|
|
break;
|
|
|
|
case CTP_CallArgument:
|
|
nilDiag = diag::cannot_convert_argument_value_nil;
|
|
break;
|
|
case CTP_ClosureResult:
|
|
nilDiag = diag::cannot_convert_closure_result_nil;
|
|
break;
|
|
}
|
|
|
|
if (isa<NilLiteralExpr>(expr->getSemanticsProvidingExpr())) {
|
|
diagnose(expr->getLoc(), nilDiag, contextualType);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Otherwise, we can't do anything smart.
|
|
return false;
|
|
}
|
|
|
|
// Try to find the contextual type in a variety of ways. If the constraint
|
|
// system had a contextual type specified, we use it - it will have a purpose
|
|
// indicator which allows us to give a very "to the point" diagnostic.
|
|
if (Type contextualType = CS->getContextualType()) {
|
|
Diag<Type, Type> diagID;
|
|
Diag<Type, Type> diagIDProtocol;
|
|
|
|
// If this is conversion failure due to a return statement with an argument
|
|
// that cannot be coerced to the result type of the function, emit a
|
|
// specific error.
|
|
switch (CS->getContextualTypePurpose()) {
|
|
case CTP_Unused:
|
|
case CTP_CannotFail:
|
|
llvm_unreachable("These contextual type purposes cannot fail with a "
|
|
"conversion type specified!");
|
|
case CTP_Initialization:
|
|
diagID = diag::cannot_convert_initializer_value;
|
|
diagIDProtocol = diag::cannot_convert_initializer_value_protocol;
|
|
break;
|
|
case CTP_ReturnStmt:
|
|
// Special case the "conversion to void" case.
|
|
if (contextualType->isVoid()) {
|
|
diagnose(expr->getLoc(), diag::cannot_return_value_from_void_func)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
diagID = diag::cannot_convert_to_return_type;
|
|
diagIDProtocol = diag::cannot_convert_to_return_type_protocol;
|
|
break;
|
|
case CTP_ThrowStmt:
|
|
// The conversion destination of throw is always ErrorType (at the moment)
|
|
// if this ever expands, this should be a specific form like () is for
|
|
// return.
|
|
diagnose(expr->getLoc(), diag::cannot_convert_thrown_type, exprType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
|
|
case CTP_EnumCaseRawValue:
|
|
diagID = diag::cannot_convert_raw_initializer_value;
|
|
diagIDProtocol = diag::cannot_convert_raw_initializer_value;
|
|
break;
|
|
case CTP_DefaultParameter:
|
|
diagID = diag::cannot_convert_default_arg_value;
|
|
diagIDProtocol = diag::cannot_convert_default_arg_value_protocol;
|
|
break;
|
|
|
|
case CTP_CallArgument:
|
|
diagID = diag::cannot_convert_argument_value;
|
|
diagIDProtocol = diag::cannot_convert_argument_value_protocol;
|
|
break;
|
|
case CTP_ClosureResult:
|
|
diagID = diag::cannot_convert_closure_result;
|
|
diagIDProtocol = diag::cannot_convert_closure_result_protocol;
|
|
break;
|
|
}
|
|
|
|
// When complaining about conversion to a protocol type, complain about
|
|
// conformance instead of "conversion".
|
|
if (contextualType->is<ProtocolType>() ||
|
|
contextualType->is<ProtocolCompositionType>())
|
|
diagID = diagIDProtocol;
|
|
|
|
// Try to simplify irrelevant details of function types. For example, if
|
|
// someone passes a "() -> Float" function to a "() throws -> Int"
|
|
// parameter, then uttering the "throws" may confuse them into thinking that
|
|
// that is the problem, even though there is a clear subtype relation.
|
|
if (auto srcFT = exprType->getAs<FunctionType>())
|
|
if (auto destFT = contextualType->getAs<FunctionType>()) {
|
|
auto destExtInfo = destFT->getExtInfo();
|
|
|
|
if (!srcFT->isNoEscape()) destExtInfo = destExtInfo.withNoEscape(false);
|
|
if (!srcFT->throws()) destExtInfo = destExtInfo.withThrows(false);
|
|
if (destExtInfo != destFT->getExtInfo())
|
|
contextualType = FunctionType::get(destFT->getInput(),
|
|
destFT->getResult(), destExtInfo);
|
|
|
|
// If this is a function conversion that discards throwability or
|
|
// noescape, emit a specific diagnostic about that.
|
|
if (srcFT->throws() && !destFT->throws())
|
|
diagID = diag::throws_functiontype_mismatch;
|
|
else if (srcFT->isNoEscape() && !destFT->isNoEscape())
|
|
diagID = diag::noescape_functiontype_mismatch;
|
|
}
|
|
|
|
diagnose(expr->getLoc(), diagID, exprType, contextualType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
|
|
// If we didn't have a specified conversion constraint, try to dig the most
|
|
// likely offender out of the constraint system.
|
|
Constraint *foundConstraint = nullptr;
|
|
|
|
auto checkConstraint = [&](Constraint *C) {
|
|
// Ignore non-conversion constraints.
|
|
if (!isConversionConstraint(C)) return;
|
|
|
|
// If we already found a favored constraint, don't replace it.
|
|
if (foundConstraint && foundConstraint->isFavored())
|
|
return;
|
|
|
|
// Ignore conversion constraints that aren't on the root expression.
|
|
if (!C->getLocator() || C->getLocator()->getAnchor() != expr)
|
|
return;
|
|
|
|
// Don't take a constraint that won't tell us anything.
|
|
if (C->getSecondType()->hasTypeVariable() ||
|
|
C->getSecondType()->hasUnresolvedType())
|
|
return;
|
|
|
|
foundConstraint = C;
|
|
};
|
|
|
|
// Check the failed constraint, if present.
|
|
if (CS->failedConstraint)
|
|
checkConstraint(CS->failedConstraint);
|
|
|
|
// Scan through all of the inactive constraints as well.
|
|
for (auto &constraint : CS->getConstraints())
|
|
checkConstraint(&constraint);
|
|
|
|
// If we didn't find a conversion constraint, we have no type.
|
|
if (!foundConstraint)
|
|
return false;
|
|
|
|
Type contextualType = foundConstraint->getSecondType();
|
|
|
|
// The contextual type relates to the overall expression, but may be
|
|
// describing only part of the type. Dive into the overall type to narrow
|
|
// it down based on the locator path.
|
|
for (auto &elt : foundConstraint->getLocator()->getPath()) {
|
|
switch (elt.getKind()) {
|
|
case ConstraintLocator::FunctionArgument:
|
|
if (auto FTy = exprType->getAs<AnyFunctionType>())
|
|
exprType = FTy->getInput();
|
|
else
|
|
return false;
|
|
break;
|
|
case ConstraintLocator::FunctionResult:
|
|
if (auto FTy = exprType->getAs<AnyFunctionType>())
|
|
exprType = FTy->getResult();
|
|
else
|
|
return false;
|
|
break;
|
|
default:
|
|
// Don't know how to process this path element yet. Don't emit a
|
|
// warpo diagnostic.
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// If we have a type that is the same as what we're looking for, we'd produce
|
|
// a "Int is not convertible to Int" diagnostic and look idiotic, so don't do
|
|
// that.
|
|
if (exprType->isEqual(contextualType))
|
|
return false;
|
|
|
|
// If the destination type is a protocol, then use conformsToProtocol to
|
|
// produce a more specific diagnostic.
|
|
if (auto *PT = contextualType->getAs<ProtocolType>()) {
|
|
if (!CS->TC.conformsToProtocol(exprType, PT->getDecl(), CS->DC,
|
|
ConformanceCheckFlags::InExpression,
|
|
nullptr, expr->getLoc()))
|
|
return true;
|
|
}
|
|
|
|
Failure::FailureKind failureKind;
|
|
switch (foundConstraint->getKind()) {
|
|
default: llvm_unreachable("list out of sync with isConversionConstraint");
|
|
case ConstraintKind::ConformsTo:
|
|
case ConstraintKind::SelfObjectOfProtocol:
|
|
if (auto pt = contextualType->getAs<ProtocolType>())
|
|
if (pt->getDecl()->
|
|
isSpecificProtocol(KnownProtocolKind::NilLiteralConvertible)) {
|
|
diagnose(expr->getLoc(), diag::cannot_use_nil_with_this_type,
|
|
contextualType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
diagnose(expr->getLoc(), diag::type_does_not_conform,
|
|
exprType, contextualType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
|
|
case ConstraintKind::Subtype:
|
|
failureKind = Failure::FailureKind::TypesNotSubtypes;
|
|
break;
|
|
case ConstraintKind::Conversion:
|
|
case ConstraintKind::ExplicitConversion:
|
|
failureKind = Failure::FailureKind::TypesNotConvertible;
|
|
break;
|
|
case ConstraintKind::ArgumentTupleConversion:
|
|
failureKind = Failure::FailureKind::TypesNotConvertible;
|
|
break;
|
|
}
|
|
|
|
// Try to simplify irrelevant details of function types. For example, if
|
|
// someone passes a "() -> Float" function to a "() throws -> Int"
|
|
// parameter, then uttering the "throws" may confuse them into thinking that
|
|
// that is the problem, even though there is a clear subtype relation.
|
|
if (auto srcFT = exprType->getAs<FunctionType>())
|
|
if (auto destFT = contextualType->getAs<FunctionType>()) {
|
|
auto destExtInfo = destFT->getExtInfo();
|
|
|
|
if (!srcFT->isNoEscape()) destExtInfo = destExtInfo.withNoEscape(false);
|
|
if (!srcFT->throws()) destExtInfo = destExtInfo.withThrows(false);
|
|
if (destExtInfo != destFT->getExtInfo())
|
|
contextualType = FunctionType::get(destFT->getInput(),
|
|
destFT->getResult(), destExtInfo);
|
|
|
|
// If this is a function conversion that discards throwability or
|
|
// noescape, emit a specific diagnostic about that.
|
|
if (srcFT->throws() && !destFT->throws()) {
|
|
diagnose(expr->getLoc(), diag::throws_functiontype_mismatch,
|
|
exprType, contextualType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
if (srcFT->isNoEscape() && !destFT->isNoEscape()) {
|
|
diagnose(expr->getLoc(), diag::noescape_functiontype_mismatch,
|
|
exprType, contextualType)
|
|
.highlight(expr->getSourceRange());
|
|
return true;
|
|
}
|
|
}
|
|
|
|
diagnose(expr->getLoc(), diag::invalid_relation,
|
|
failureKind - Failure::FailureKind::TypesNotEqual,
|
|
exprType, contextualType)
|
|
.highlight(expr->getSourceRange());
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/// When an assignment to an expression is detected and the destination is
|
|
/// invalid, emit a detailed error about the condition.
|
|
void ConstraintSystem::diagnoseAssignmentFailure(Expr *dest, Type destTy,
|
|
SourceLoc equalLoc) {
|
|
auto &TC = getTypeChecker();
|
|
|
|
// Diagnose obvious assignments to literals.
|
|
if (isa<LiteralExpr>(dest->getSemanticsProvidingExpr())) {
|
|
TC.diagnose(equalLoc, diag::cannot_assign_to_literal);
|
|
return;
|
|
}
|
|
|
|
Diag<StringRef> diagID;
|
|
if (isa<DeclRefExpr>(dest))
|
|
diagID = diag::assignment_lhs_is_immutable_variable;
|
|
else if (isa<ForceValueExpr>(dest))
|
|
diagID = diag::assignment_bang_has_immutable_subcomponent;
|
|
else if (isa<UnresolvedDotExpr>(dest) || isa<MemberRefExpr>(dest))
|
|
diagID = diag::assignment_lhs_is_immutable_property;
|
|
else if (isa<SubscriptExpr>(dest))
|
|
diagID = diag::assignment_subscript_has_immutable_base;
|
|
else {
|
|
diagID = diag::assignment_lhs_is_immutable_variable;
|
|
}
|
|
|
|
diagnoseSubElementFailure(dest, equalLoc, *this, diagID,
|
|
diag::assignment_lhs_not_lvalue);
|
|
}
|
|
|
|
|
|
/// Special magic to handle inout exprs and tuples in argument lists.
|
|
Expr *FailureDiagnosis::
|
|
typeCheckArgumentChildIndependently(Expr *argExpr, Type argType,
|
|
const CalleeCandidateInfo &candidates) {
|
|
// Grab one of the candidates (if present) and get its input list to help
|
|
// identify operators that have implicit inout arguments.
|
|
Type exampleInputType;
|
|
if (!candidates.empty()) {
|
|
exampleInputType = candidates[0].getArgumentType();
|
|
|
|
// If we found a single candidate, and have no contextually known argument
|
|
// type information, use that one candidate as the type information for
|
|
// subexpr checking.
|
|
//
|
|
// TODO: If all candidates have the same type for some argument, we could pass
|
|
// down partial information.
|
|
if (candidates.size() == 1 && !argType)
|
|
argType = candidates[0].getArgumentType();
|
|
}
|
|
|
|
auto CTPurpose = argType ? CTP_CallArgument : CTP_Unused;
|
|
|
|
// FIXME: This should all just be a matter of getting type type of the
|
|
// sub-expression, but this doesn't work well when typeCheckChildIndependently
|
|
// is over-conservative w.r.t. TupleExprs.
|
|
auto *TE = dyn_cast<TupleExpr>(argExpr);
|
|
if (!TE) {
|
|
// If the argument isn't a tuple, it is some scalar value for a
|
|
// single-argument call.
|
|
TCCOptions options;
|
|
if (exampleInputType && exampleInputType->is<InOutType>())
|
|
options |= TCC_AllowLValue;
|
|
|
|
// If the argtype is a tuple type with default arguments, or a labeled tuple
|
|
// with a single element, pull the scalar element type for the subexpression
|
|
// out. If we can't do that and the tuple has default arguments, we have to
|
|
// punt on passing down the type information, since type checking the
|
|
// subexpression won't be able to find the default argument provider.
|
|
if (argType)
|
|
if (auto argTT = argType->getAs<TupleType>()) {
|
|
int scalarElt = argTT->getElementForScalarInit();
|
|
if (scalarElt != -1)
|
|
argType = argTT->getElementType(scalarElt);
|
|
else if (argTT->hasAnyDefaultValues())
|
|
argType = Type();
|
|
}
|
|
|
|
return typeCheckChildIndependently(unwrapParenExpr(argExpr), argType,
|
|
CTPurpose, options);
|
|
}
|
|
|
|
// If we know the requested argType to use, use computeTupleShuffle to produce
|
|
// the shuffle of input arguments to destination values. It requires a
|
|
// TupleType to compute the mapping from argExpr. Conveniently, it doesn't
|
|
// care about the actual types though, so we can just use 'void' for them.
|
|
if (argType && argType->is<TupleType>()) {
|
|
auto argTypeTT = argType->castTo<TupleType>();
|
|
SmallVector<TupleTypeElt, 4> ArgElts;
|
|
auto voidTy = CS->getASTContext().TheEmptyTupleType;
|
|
|
|
for (unsigned i = 0, e = TE->getNumElements(); i != e; ++i)
|
|
ArgElts.push_back({ voidTy, TE->getElementName(i) });
|
|
auto actualArgType = TupleType::get(ArgElts, CS->getASTContext());
|
|
if (auto *actualArgTypeTT = actualArgType->getAs<TupleType>()) {
|
|
SmallVector<int, 4> sources;
|
|
SmallVector<unsigned, 4> variadicArgs;
|
|
if (!computeTupleShuffle(actualArgTypeTT, argTypeTT,
|
|
sources, variadicArgs)) {
|
|
SmallVector<Expr*, 4> resultElts(TE->getNumElements(), nullptr);
|
|
SmallVector<TupleTypeElt, 4> resultEltTys(TE->getNumElements(), voidTy);
|
|
|
|
// If we got a correct shuffle, we can perform the analysis of all of
|
|
// the input elements, with their expected types.
|
|
for (unsigned i = 0, e = sources.size(); i != e; ++i) {
|
|
// If the value is taken from a default argument, ignore it.
|
|
if (sources[i] == TupleShuffleExpr::DefaultInitialize ||
|
|
sources[i] == TupleShuffleExpr::Variadic ||
|
|
sources[i] == TupleShuffleExpr::CallerDefaultInitialize)
|
|
continue;
|
|
|
|
assert(sources[i] >= 0 && "Unknown sources index");
|
|
|
|
// Otherwise, it must match the corresponding expected argument type.
|
|
unsigned inArgNo = sources[i];
|
|
auto actualType = argTypeTT->getElementType(i);
|
|
|
|
TCCOptions options;
|
|
if (actualType->is<InOutType>())
|
|
options |= TCC_AllowLValue;
|
|
|
|
auto expr =
|
|
typeCheckChildIndependently(TE->getElement(inArgNo), actualType,
|
|
CTP_CallArgument, options);
|
|
// If there was an error type checking this argument, then we're done.
|
|
if (!expr)
|
|
return nullptr;
|
|
resultElts[inArgNo] = expr;
|
|
resultEltTys[inArgNo] = {expr->getType(),TE->getElementName(inArgNo)};
|
|
}
|
|
|
|
if (!variadicArgs.empty()) {
|
|
auto varargsTy = argTypeTT->getVarArgsBaseType();
|
|
for (unsigned i = 0, e = variadicArgs.size(); i != e; ++i) {
|
|
unsigned inArgNo = variadicArgs[i];
|
|
|
|
auto expr =
|
|
typeCheckChildIndependently(TE->getElement(inArgNo), varargsTy,
|
|
CTP_CallArgument);
|
|
// If there was an error type checking this argument, then we're done.
|
|
if (!expr)
|
|
return nullptr;
|
|
resultElts[inArgNo] = expr;
|
|
resultEltTys[inArgNo] = { expr->getType() };
|
|
}
|
|
}
|
|
|
|
auto TT = TupleType::get(resultEltTys, CS->getASTContext());
|
|
return TupleExpr::create(CS->getASTContext(), TE->getLParenLoc(),
|
|
resultElts, TE->getElementNames(),
|
|
TE->getElementNameLocs(),
|
|
TE->getRParenLoc(), TE->hasTrailingClosure(),
|
|
TE->isImplicit(), TT);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the simplified type of each element and rebuild the aggregate.
|
|
SmallVector<TupleTypeElt, 4> resultEltTys;
|
|
SmallVector<Expr*, 4> resultElts;
|
|
|
|
TupleType *exampleInputTuple = nullptr;
|
|
if (exampleInputType)
|
|
exampleInputTuple = exampleInputType->getAs<TupleType>();
|
|
|
|
for (unsigned i = 0, e = TE->getNumElements(); i != e; i++) {
|
|
TCCOptions options;
|
|
if (exampleInputTuple && i < exampleInputTuple->getNumElements() &&
|
|
exampleInputTuple->getElementType(i)->is<InOutType>())
|
|
options |= TCC_AllowLValue;
|
|
|
|
auto elExpr = typeCheckChildIndependently(TE->getElement(i), options);
|
|
if (!elExpr) return nullptr; // already diagnosed.
|
|
|
|
resultElts.push_back(elExpr);
|
|
resultEltTys.push_back({elExpr->getType(), TE->getElementName(i)});
|
|
}
|
|
|
|
auto TT = TupleType::get(resultEltTys, CS->getASTContext());
|
|
return TupleExpr::create(CS->getASTContext(), TE->getLParenLoc(),
|
|
resultElts, TE->getElementNames(),
|
|
TE->getElementNameLocs(),
|
|
TE->getRParenLoc(), TE->hasTrailingClosure(),
|
|
TE->isImplicit(), TT);
|
|
}
|
|
|
|
bool FailureDiagnosis::visitBinaryExpr(BinaryExpr *binop) {
|
|
CalleeCandidateInfo calleeInfo(binop->getFn(), CS);
|
|
assert(!calleeInfo.candidates.empty() && "unrecognized binop function kind");
|
|
|
|
auto checkedArgExpr = typeCheckArgumentChildIndependently(binop->getArg(),
|
|
Type(),
|
|
calleeInfo);
|
|
if (!checkedArgExpr) return true;
|
|
|
|
// Pre-checking can turn (T,U) into a TypeExpr. That's an artifact
|
|
// of independent type-checking; just use the standard diagnostics
|
|
// paths.
|
|
auto argExpr = dyn_cast<TupleExpr>(checkedArgExpr);
|
|
if (!argExpr) return visitExpr(binop);
|
|
|
|
auto argTupleType = argExpr->getType()->castTo<TupleType>();
|
|
calleeInfo.filterList(argTupleType);
|
|
|
|
// Otherwise, whatever the result type of the call happened to be must not
|
|
// have been what we were looking for - diagnose this as a conversion
|
|
// failure.
|
|
if (calleeInfo.closeness == CC_ExactMatch)
|
|
return false;
|
|
|
|
// A common error is to apply an operator that only has an inout LHS (e.g. +=)
|
|
// to non-lvalues (e.g. a local let). Produce a nice diagnostic for this
|
|
// case.
|
|
if (calleeInfo.closeness == CC_NonLValueInOut) {
|
|
diagnoseSubElementFailure(argExpr->getElement(0), binop->getLoc(), *CS,
|
|
diag::cannot_apply_lvalue_binop_to_subelement,
|
|
diag::cannot_apply_lvalue_binop_to_rvalue);
|
|
return true;
|
|
}
|
|
|
|
auto argType1 = argTupleType->getElementType(0)->getRValueType();
|
|
auto argType2 = argTupleType->getElementType(1)->getRValueType();
|
|
std::string overloadName = calleeInfo[0].decl->getNameStr();
|
|
assert(!overloadName.empty());
|
|
if (!argType1->isEqual(argType2)) {
|
|
diagnose(binop->getLoc(), diag::cannot_apply_binop_to_args,
|
|
overloadName, argType1, argType2)
|
|
.highlight(argExpr->getElement(0)->getSourceRange())
|
|
.highlight(argExpr->getElement(1)->getSourceRange());
|
|
} else {
|
|
diagnose(binop->getLoc(), diag::cannot_apply_binop_to_same_args,
|
|
overloadName, argType1)
|
|
.highlight(argExpr->getElement(0)->getSourceRange())
|
|
.highlight(argExpr->getElement(1)->getSourceRange());
|
|
}
|
|
|
|
calleeInfo.suggestPotentialOverloads(overloadName, binop->getLoc());
|
|
return true;
|
|
}
|
|
|
|
|
|
bool FailureDiagnosis::visitUnaryExpr(ApplyExpr *applyExpr) {
|
|
assert(expr->getKind() == ExprKind::PostfixUnary ||
|
|
expr->getKind() == ExprKind::PrefixUnary);
|
|
|
|
CalleeCandidateInfo calleeInfo(applyExpr->getFn(), CS);
|
|
assert(!calleeInfo.candidates.empty() && "unrecognized unop function kind");
|
|
|
|
auto argExpr = typeCheckArgumentChildIndependently(applyExpr->getArg(),
|
|
Type(), calleeInfo);
|
|
if (!argExpr) return true;
|
|
|
|
Type argType = argExpr->getType();
|
|
calleeInfo.filterList(argType);
|
|
|
|
if (calleeInfo.closeness == CC_ExactMatch) {
|
|
// Otherwise, whatever the result type of the call happened to be must not
|
|
// have been what we were looking for. Lets diagnose it as a conversion
|
|
// or ambiguity failure.
|
|
return false;
|
|
}
|
|
|
|
// A common error is to apply an operator that only has inout forms (e.g. ++)
|
|
// to non-lvalues (e.g. a local let). Produce a nice diagnostic for this
|
|
// case.
|
|
if (calleeInfo.closeness == CC_NonLValueInOut) {
|
|
// Diagnose the case when the failure.
|
|
diagnoseSubElementFailure(argExpr, applyExpr->getFn()->getLoc(), *CS,
|
|
diag::cannot_apply_lvalue_unop_to_subelement,
|
|
diag::cannot_apply_lvalue_unop_to_rvalue);
|
|
return true;
|
|
}
|
|
|
|
std::string overloadName = calleeInfo[0].decl->getNameStr();
|
|
assert(!overloadName.empty());
|
|
diagnose(argExpr->getLoc(), diag::cannot_apply_unop_to_arg, overloadName,
|
|
argType);
|
|
|
|
calleeInfo.suggestPotentialOverloads(overloadName, argExpr->getLoc());
|
|
return true;
|
|
}
|
|
|
|
bool FailureDiagnosis::visitSubscriptExpr(SubscriptExpr *SE) {
|
|
// See if the subscript got resolved.
|
|
auto locator =
|
|
CS->getConstraintLocator(SE, ConstraintLocator::SubscriptMember);
|
|
CalleeCandidateInfo calleeInfo(locator, CS);
|
|
|
|
auto indexExpr = typeCheckArgumentChildIndependently(SE->getIndex(),
|
|
Type(), calleeInfo);
|
|
if (!indexExpr) return true;
|
|
|
|
auto baseExpr = typeCheckChildIndependently(SE->getBase());
|
|
if (!baseExpr) return true;
|
|
|
|
auto indexType = indexExpr->getType();
|
|
auto baseType = baseExpr->getType();
|
|
|
|
auto decomposedIndexType = decomposeArgumentType(indexType);
|
|
calleeInfo.filterList([&](UncurriedCandidate cand) -> CandidateCloseness
|
|
{
|
|
// Classify how close this match is. Non-subscript decls don't match.
|
|
auto *SD = dyn_cast<SubscriptDecl>(cand.decl);
|
|
if (!SD) return CC_GeneralMismatch;
|
|
|
|
// Check to make sure the base expr type is convertible to the expected base
|
|
// type.
|
|
auto selfConstraint = CC_ExactMatch;
|
|
auto instanceTy =
|
|
SD->getGetter()->getImplicitSelfDecl()->getType()->getInOutObjectType();
|
|
if (!baseType->hasTypeVariable() &&
|
|
!baseType->hasUnresolvedType() &&
|
|
!CS->TC.isConvertibleTo(baseType, instanceTy, CS->DC)) {
|
|
selfConstraint = CC_SelfMismatch;
|
|
}
|
|
|
|
// Explode out multi-index subscripts to find the best match.
|
|
return std::max(evaluateCloseness(SD->getIndicesType(),decomposedIndexType),
|
|
selfConstraint);
|
|
});
|
|
|
|
// TODO: Is there any reason to check for CC_NonLValueInOut here?
|
|
|
|
if (calleeInfo.closeness == CC_ExactMatch) {
|
|
// Otherwise, whatever the result type of the call happened to be must not
|
|
// have been what we were looking for. Lets diagnose it as a conversion
|
|
// or ambiguity failure.
|
|
return false;
|
|
}
|
|
|
|
// If the closes matches all mismatch on self, we either have something that
|
|
// cannot be subscripted, or an ambiguity.
|
|
if (calleeInfo.closeness == CC_SelfMismatch) {
|
|
diagnose(SE->getLoc(), diag::cannot_subscript_base, baseType)
|
|
.highlight(SE->getBase()->getSourceRange());
|
|
// FIXME: Should suggest overload set, but we're not ready for that until
|
|
// it points to candidates and identifies the self type in the diagnostic.
|
|
//calleeInfo.suggestPotentialOverloads("subscript", SE->getLoc());
|
|
return true;
|
|
}
|
|
|
|
diagnose(SE->getLoc(), diag::cannot_subscript_with_index,
|
|
baseType, indexType);
|
|
|
|
calleeInfo.suggestPotentialOverloads("subscript", SE->getLoc());
|
|
return true;
|
|
}
|
|
|
|
|
|
bool FailureDiagnosis::visitCallExpr(CallExpr *callExpr) {
|
|
// Type check the function subexpression to resolve a type for it if possible.
|
|
auto fnExpr = typeCheckChildIndependently(callExpr->getFn(),
|
|
TCC_AllowUnresolved);
|
|
if (!fnExpr) return true;
|
|
auto fnType = fnExpr->getType()->getRValueType();
|
|
|
|
CalleeCandidateInfo calleeInfo(fnExpr, CS);
|
|
|
|
// If we weren't able to resolve the entire callee function expression, but
|
|
// we were able to find a single candidate, use it to inform the type of the
|
|
// argument analysis stuff.
|
|
// TODO: If all candidates have the same type for some argument, we could pass
|
|
// down partial information.
|
|
if (fnType->hasTypeVariable() && calleeInfo.size() == 1 &&
|
|
calleeInfo[0].getUncurriedFunctionType())
|
|
fnType = calleeInfo[0].getUncurriedFunctionType();
|
|
|
|
// If we resolved a concrete expression for the callee, and it has
|
|
// non-function/non-metatype type, then we cannot call it!
|
|
if (!fnType->hasTypeVariable() &&
|
|
!fnType->is<AnyFunctionType>() && !fnType->is<MetatypeType>()) {
|
|
|
|
// If the argument is a trailing ClosureExpr (i.e. {....}) and it is on a
|
|
// different line than the callee, then the "real" issue is that the user
|
|
// forgot to write "do" before their brace stmt.
|
|
if (auto *PE = dyn_cast<ParenExpr>(callExpr->getArg()))
|
|
if (PE->hasTrailingClosure() && isa<ClosureExpr>(PE->getSubExpr())) {
|
|
auto &SM = CS->getASTContext().SourceMgr;
|
|
if (SM.getLineNumber(callExpr->getFn()->getEndLoc()) !=
|
|
SM.getLineNumber(PE->getStartLoc())) {
|
|
diagnose(PE->getStartLoc(), diag::expected_do_in_statement)
|
|
.fixItInsert(PE->getStartLoc(), "do ");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
diagnose(callExpr->getArg()->getStartLoc(),
|
|
diag::cannot_call_non_function_value, fnExpr->getType())
|
|
.highlight(fnExpr->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
Type argType; // Type of the argument list, if knowable.
|
|
if (auto FTy = fnType->getAs<AnyFunctionType>())
|
|
argType = FTy->getInput();
|
|
|
|
// Get the expression result of type checking the arguments to the call
|
|
// independently, so we have some idea of what we're working with.
|
|
//
|
|
auto argExpr = typeCheckArgumentChildIndependently(callExpr->getArg(),
|
|
argType, calleeInfo);
|
|
if (!argExpr)
|
|
return true; // already diagnosed.
|
|
|
|
calleeInfo.filterList(argExpr->getType());
|
|
|
|
// If we found an exact match, this must be a problem with a conversion from
|
|
// the result of the call to the expected type. Diagnose this as a conversion
|
|
// failure.
|
|
if (calleeInfo.closeness == CC_ExactMatch)
|
|
return false;
|
|
|
|
|
|
bool isInitializer = isa<TypeExpr>(fnExpr);
|
|
auto overloadName = calleeInfo.declName;
|
|
|
|
std::string argString = getTypeListString(argExpr->getType());
|
|
|
|
// If we couldn't get the name of the callee, then it must be something of a
|
|
// more complex "value of function type".
|
|
if (overloadName.empty()) {
|
|
// If we couldn't infer the result type of the closure expr, then we have
|
|
// some sort of ambiguity, let the ambiguity diagnostic stuff handle this.
|
|
if (auto ffty = fnType->getAs<AnyFunctionType>())
|
|
if (ffty->getResult()->hasTypeVariable()) {
|
|
diagnoseAmbiguity(fnExpr);
|
|
return true;
|
|
}
|
|
|
|
// The most common unnamed value of closure type is a ClosureExpr, so
|
|
// special case it.
|
|
if (isa<ClosureExpr>(fnExpr->getSemanticsProvidingExpr())) {
|
|
if (fnType->hasTypeVariable())
|
|
diagnose(argExpr->getStartLoc(), diag::cannot_invoke_closure, argString)
|
|
.highlight(fnExpr->getSourceRange());
|
|
else
|
|
diagnose(argExpr->getStartLoc(), diag::cannot_invoke_closure_type,
|
|
fnType, argString)
|
|
.highlight(fnExpr->getSourceRange());
|
|
|
|
} else if (fnType->hasTypeVariable()) {
|
|
diagnose(argExpr->getStartLoc(), diag::cannot_call_function_value,
|
|
argString)
|
|
.highlight(fnExpr->getSourceRange());
|
|
} else {
|
|
diagnose(argExpr->getStartLoc(), diag::cannot_call_value_of_function_type,
|
|
fnType, argString)
|
|
.highlight(fnExpr->getSourceRange());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// If we have an argument list (i.e., a scalar, or a non-zero-element tuple)
|
|
// then diagnose with some specificity about the arguments.
|
|
if (isa<TupleExpr>(argExpr) &&
|
|
cast<TupleExpr>(argExpr)->getNumElements() == 0) {
|
|
// Emit diagnostics that say "no arguments".
|
|
diagnose(fnExpr->getLoc(), diag::cannot_call_with_no_params,
|
|
overloadName, isInitializer);
|
|
} else {
|
|
diagnose(fnExpr->getLoc(), diag::cannot_call_with_params,
|
|
overloadName, argString, isInitializer);
|
|
}
|
|
|
|
// Did the user intend on invoking a different overload?
|
|
calleeInfo.suggestPotentialOverloads(overloadName, fnExpr->getLoc(),
|
|
/*isCallExpr*/true);
|
|
return true;
|
|
}
|
|
|
|
bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) {
|
|
// Diagnose obvious assignments to literals.
|
|
if (isa<LiteralExpr>(assignExpr->getDest()->getSemanticsProvidingExpr())) {
|
|
diagnose(assignExpr->getLoc(), diag::cannot_assign_to_literal);
|
|
return true;
|
|
}
|
|
|
|
// If the source type is already an error type, we've already posted an error.
|
|
auto srcExpr = typeCheckChildIndependently(assignExpr->getSrc());
|
|
if (!srcExpr) return true;
|
|
|
|
auto destExpr = typeCheckChildIndependently(assignExpr->getDest(),
|
|
TCC_AllowLValue);
|
|
if (!destExpr) return true;
|
|
|
|
auto destType = destExpr->getType();
|
|
auto srcType = srcExpr->getType();
|
|
|
|
// If the result type is a non-lvalue, then we are failing because it is
|
|
// immutable and that's not a great thing to assign to.
|
|
if (!destType->isLValueType()) {
|
|
CS->diagnoseAssignmentFailure(destExpr, destType, assignExpr->getLoc());
|
|
return true;
|
|
}
|
|
|
|
diagnose(srcExpr->getLoc(), diag::cannot_assign_values, srcType,
|
|
destType->getRValueType());
|
|
return true;
|
|
}
|
|
|
|
bool FailureDiagnosis::visitInOutExpr(InOutExpr *IOE) {
|
|
auto subExpr = typeCheckChildIndependently(IOE->getSubExpr(),TCC_AllowLValue);
|
|
if (!subExpr) return true;
|
|
|
|
auto subExprType = subExpr->getType();
|
|
|
|
// The common cause is that the operand is not an lvalue.
|
|
if (!subExprType->isLValueType()) {
|
|
diagnoseSubElementFailure(subExpr, IOE->getLoc(), *CS,
|
|
diag::cannot_pass_rvalue_inout_subelement,
|
|
diag::cannot_pass_rvalue_inout);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// FIXME: Change this to be visitExplicitCastExpr, which is a superclass of
|
|
// CoerceExpr & ForcedCheckedCastExpr and other stuff.
|
|
bool FailureDiagnosis::visitCoerceExpr(CoerceExpr *CE) {
|
|
Expr *subExpr = typeCheckChildIndependently(CE->getSubExpr());
|
|
if (!subExpr) return true;
|
|
Type subType = subExpr->getType();
|
|
|
|
if (!subType->is<TypeVariableType>()) {
|
|
diagnose(CE->getLoc(), diag::invalid_relation,
|
|
Failure::TypesNotConvertible - Failure::TypesNotEqual,
|
|
subType, CE->getType())
|
|
.highlight(CE->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FailureDiagnosis::
|
|
visitForcedCheckedCastExpr(ForcedCheckedCastExpr *FCE) {
|
|
Expr *subExpr = typeCheckChildIndependently(FCE->getSubExpr());
|
|
if (!subExpr) return true;
|
|
Type subType = subExpr->getType();
|
|
|
|
if (!subType->is<TypeVariableType>()) {
|
|
diagnose(FCE->getLoc(), diag::invalid_relation,
|
|
Failure::TypesNotConvertible - Failure::TypesNotEqual,
|
|
subType, FCE->getType())
|
|
.highlight(FCE->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FailureDiagnosis::visitForceValueExpr(ForceValueExpr *FVE) {
|
|
auto argExpr = typeCheckChildIndependently(FVE->getSubExpr());
|
|
if (!argExpr) return true;
|
|
auto argType = argExpr->getType();
|
|
|
|
// If the subexpression type checks as a non-optional type, then that is the
|
|
// error. Produce a specific diagnostic about this.
|
|
if (argType->getOptionalObjectType().isNull()) {
|
|
diagnose(FVE->getLoc(), diag::invalid_force_unwrap, argType)
|
|
.fixItRemove(FVE->getExclaimLoc())
|
|
.highlight(FVE->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FailureDiagnosis::visitBindOptionalExpr(BindOptionalExpr *BOE) {
|
|
auto argExpr = typeCheckChildIndependently(BOE->getSubExpr());
|
|
if (!argExpr) return true;
|
|
auto argType = argExpr->getType();
|
|
|
|
// If the subexpression type checks as a non-optional type, then that is the
|
|
// error. Produce a specific diagnostic about this.
|
|
if (argType->getOptionalObjectType().isNull()) {
|
|
diagnose(BOE->getQuestionLoc(), diag::invalid_optional_chain, argType)
|
|
.highlight(BOE->getSourceRange())
|
|
.fixItRemove(BOE->getQuestionLoc());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FailureDiagnosis::visitIfExpr(IfExpr *IE) {
|
|
// Check all of the subexpressions independently.
|
|
auto condExpr = typeCheckChildIndependently(IE->getCondExpr());
|
|
if (!condExpr) return true;
|
|
auto trueExpr = typeCheckChildIndependently(IE->getThenExpr());
|
|
if (!trueExpr) return true;
|
|
|
|
auto falseExpr = typeCheckChildIndependently(IE->getElseExpr());
|
|
if (!falseExpr) return true;
|
|
|
|
// If the condition wasn't of boolean type, diagnose the problem.
|
|
auto booleanType = CS->TC.getProtocol(IE->getQuestionLoc(),
|
|
KnownProtocolKind::BooleanType);
|
|
if (!booleanType) return true;
|
|
|
|
if (!CS->TC.conformsToProtocol(condExpr->getType(), booleanType, CS->DC,
|
|
ConformanceCheckFlags::InExpression,
|
|
nullptr, condExpr->getLoc()))
|
|
return true;
|
|
|
|
// Otherwise, the true/false result types must not be matching.
|
|
diagnose(IE->getColonLoc(), diag::if_expr_cases_mismatch,
|
|
trueExpr->getType(), falseExpr->getType())
|
|
.highlight(trueExpr->getSourceRange())
|
|
.highlight(falseExpr->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
|
|
bool FailureDiagnosis::
|
|
visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
|
|
// Don't walk the children for this node, it leads to multiple diagnostics
|
|
// because of how sema injects this node into the type checker.
|
|
return false;
|
|
}
|
|
|
|
|
|
bool FailureDiagnosis::visitClosureExpr(ClosureExpr *CE) {
|
|
// If this is a complex leaf closure, give up.
|
|
if (!CE->hasSingleExpressionBody())
|
|
return false;
|
|
|
|
Type expectedResultType;
|
|
|
|
// If we have a contextual type available for this closure, apply it to the
|
|
// ParamDecls in our parameter list. This ensures that any uses of them get
|
|
// appropriate types.
|
|
if (CS->getContextualType() &&
|
|
CS->getContextualType()->is<AnyFunctionType>()) {
|
|
auto fnType = CS->getContextualType()->castTo<AnyFunctionType>();
|
|
Pattern *params = CE->getParams();
|
|
TypeResolutionOptions TROptions;
|
|
TROptions |= TR_OverrideType;
|
|
TROptions |= TR_FromNonInferredPattern;
|
|
TROptions |= TR_InExpression;
|
|
TROptions |= TR_ImmediateFunctionInput;
|
|
if (CS->TC.coercePatternToType(params, CE, fnType->getInput(), TROptions))
|
|
return true;
|
|
CE->setParams(params);
|
|
|
|
expectedResultType = fnType->getResult();
|
|
} else {
|
|
|
|
// Defend against type variables from our constraint system leaking into
|
|
// recursive constraints systems formed when checking the body of the
|
|
// closure. These typevars come into them when the body does name
|
|
// lookups against the parameter decls.
|
|
//
|
|
// Handle this by rewriting the arguments to UnresolvedType().
|
|
CE->getParams()->forEachVariable([&](VarDecl *VD) {
|
|
if (VD->getType()->hasTypeVariable() || VD->getType()->is<ErrorType>())
|
|
VD->overwriteType(CS->getASTContext().TheUnresolvedType);
|
|
});
|
|
}
|
|
|
|
// If the closure had an expected result type, use it.
|
|
if (CE->hasExplicitResultType())
|
|
expectedResultType = CE->getExplicitResultTypeLoc().getType();
|
|
|
|
// When we're type checking a single-expression closure, we need to reset the
|
|
// DeclContext to this closure for the recursive type checking. Otherwise,
|
|
// if there is a closure in the subexpression, we can violate invariants.
|
|
{
|
|
llvm::SaveAndRestore<DeclContext*> SavedDC(CS->DC, CE);
|
|
|
|
auto CTP = expectedResultType ? CTP_ClosureResult : CTP_Unused;
|
|
|
|
if (!typeCheckChildIndependently(CE->getSingleExpressionBody(),
|
|
expectedResultType, CTP))
|
|
return true;
|
|
}
|
|
|
|
// If the body of the closure looked ok, then look for a contextual type
|
|
// error. This is necessary because FailureDiagnosis::diagnoseExprFailure
|
|
// doesn't do this for closures.
|
|
if (CS->getContextualType() &&
|
|
!CS->getContextualType()->isEqual(CE->getType())) {
|
|
|
|
auto fnType = CS->getContextualType()->getAs<AnyFunctionType>();
|
|
|
|
// If the closure had an explicitly written return type incompatible with
|
|
// the contextual type, diagnose that.
|
|
if (CE->hasExplicitResultType() &&
|
|
CE->getExplicitResultTypeLoc().getTypeRepr()) {
|
|
auto explicitResultTy = CE->getExplicitResultTypeLoc().getType();
|
|
if (!explicitResultTy->isEqual(fnType->getResult())) {
|
|
auto repr = CE->getExplicitResultTypeLoc().getTypeRepr();
|
|
diagnose(repr->getStartLoc(), diag::incorrect_explicit_closure_result,
|
|
explicitResultTy, fnType->getResult())
|
|
.fixItReplace(repr->getSourceRange(),fnType->getResult().getString());
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Otherwise, diagnose a general error talking about the type of the closure
|
|
// in-aggregate.
|
|
if (diagnoseContextualConversionError(CE->getType()))
|
|
return true;
|
|
}
|
|
|
|
|
|
// Otherwise, produce a generic error.
|
|
return false;
|
|
}
|
|
|
|
bool FailureDiagnosis::visitExpr(Expr *E) {
|
|
// Check each of our immediate children to see if any of them are
|
|
// independently invalid.
|
|
bool errorInSubExpr = false;
|
|
|
|
E->forEachChildExpr([&](Expr *Child) {
|
|
// If we already found an error, stop checking.
|
|
if (errorInSubExpr) return;
|
|
|
|
// Otherwise this subexpr is an error if type checking it produces an error.
|
|
errorInSubExpr |= !typeCheckChildIndependently(Child);
|
|
});
|
|
|
|
// If any of the children were errors, we're done.
|
|
if (errorInSubExpr)
|
|
return true;
|
|
|
|
// Otherwise, produce a more generic error.
|
|
return false;
|
|
}
|
|
|
|
|
|
bool FailureDiagnosis::diagnoseExprFailure() {
|
|
assert(CS && expr);
|
|
|
|
// Our general approach is to do a depth first traversal of the broken
|
|
// expression tree, type checking as we go. If we find a subtree that cannot
|
|
// be type checked on its own (even to an incomplete type) then that is where
|
|
// we focus our attention. If we do find a type, we use it to check for
|
|
// contextual type mismatches.
|
|
|
|
// If we're at the top-level of the expression fresh in from a client whose
|
|
// constraint system failed, check to see if we can type check the expression
|
|
// by itself. If not, then we'll get a more specific failure in the
|
|
// subexpression. If so, then we know it must be some conversion constraint
|
|
// binding the result of the expression to a type that fails.
|
|
if (!CS->TC.isExprBeingDiagnosed(expr) ||
|
|
(CS->getContextualType() && !isa<ClosureExpr>(expr))) {
|
|
// Make sure we retypecheck this expression, without context.
|
|
CS->TC.addExprForDiagnosis(expr, nullptr);
|
|
|
|
// Type check the expression independently of any contextual constraints.
|
|
auto subExprTy = getTypeOfTypeCheckedChildIndependently(expr,
|
|
TCCFlags::TCC_AllowUnresolved);
|
|
|
|
// If it failed an diagnosed something, then we're done.
|
|
if (!subExprTy) return true;
|
|
|
|
// Otherwise, it is almost certainly a contextual constraint mismatch, dig
|
|
// one out.
|
|
if (diagnoseContextualConversionError(subExprTy))
|
|
return true;
|
|
}
|
|
|
|
return visit(expr);
|
|
}
|
|
|
|
|
|
/// Given a specific expression and the remnants of the failed constraint
|
|
/// system, produce a specific diagnostic.
|
|
///
|
|
/// This is guaranteed to always emit an error message.
|
|
///
|
|
void ConstraintSystem::diagnoseFailureForExpr(Expr *expr) {
|
|
if (auto *RB = dyn_cast<RebindSelfInConstructorExpr>(expr))
|
|
expr = RB->getSubExpr();
|
|
|
|
FailureDiagnosis diagnosis(expr, this);
|
|
|
|
// Now, attempt to diagnose the failure from the info we've collected.
|
|
if (diagnosis.diagnoseExprFailure())
|
|
return;
|
|
|
|
// If we can diagnose a problem based on the constraints left laying around in
|
|
// the system, do so now.
|
|
if (diagnosis.diagnoseConstraintFailure())
|
|
return;
|
|
|
|
// If the expression-order diagnostics didn't find any diagnosable problems,
|
|
// try the unavoidable failures list again, with locator substitutions in
|
|
// place. To make sure we emit the error if we have a failure recorded.
|
|
for (auto failure : unavoidableFailures) {
|
|
if (diagnoseFailure(*this, *failure, expr, true))
|
|
return;
|
|
}
|
|
|
|
// If no one could find a problem with this expression or constraint system,
|
|
// then it must be well-formed... but is ambiguous. Handle this by diagnosic
|
|
// various cases that come up.
|
|
diagnosis.diagnoseAmbiguity(expr);
|
|
}
|
|
|
|
/// Emit an ambiguity diagnostic about the specified expression.
|
|
void FailureDiagnosis::diagnoseAmbiguity(Expr *E) {
|
|
|
|
// Check out all of the type variables lurking in the system. If any are
|
|
// unbound archetypes, then the problem is that it couldn't be resolved.
|
|
for (auto tv : CS->getTypeVariables()) {
|
|
if (tv->getImpl().hasRepresentativeOrFixed())
|
|
continue;
|
|
|
|
|
|
// If this is a conversion to a type variable used to form an archetype,
|
|
// Then diagnose this as a generic parameter that could not be resolved.
|
|
auto archetype = tv->getImpl().getArchetype();
|
|
|
|
// Only diagnose archetypes that don't have a parent, i.e., ones
|
|
// that correspond to generic parameters.
|
|
if (archetype && !archetype->getParent()) {
|
|
diagnose(expr->getLoc(), diag::unbound_generic_parameter, archetype);
|
|
|
|
// Emit a "note, archetype declared here" sort of thing.
|
|
noteTargetOfDiagnostic(*CS, nullptr, tv->getImpl().getLocator());
|
|
return;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Unresolved/Anonymous ClosureExprs are common enough that we should give
|
|
// them tailored diagnostics.
|
|
if (auto CE = dyn_cast<ClosureExpr>(E->getSemanticsProvidingExpr())) {
|
|
auto CFTy = CE->getType()->getAs<AnyFunctionType>();
|
|
|
|
// If this is a multi-statement closure with no explicit result type, emit
|
|
// a note to clue the developer in.
|
|
if (!CE->hasExplicitResultType() && CFTy &&
|
|
(CFTy->getResult()->hasTypeVariable() ||
|
|
CFTy->getResult()->is<UnresolvedType>())) {
|
|
diagnose(CE->getLoc(), diag::cannot_infer_closure_result_type);
|
|
return;
|
|
}
|
|
|
|
diagnose(E->getLoc(), diag::cannot_infer_closure_type)
|
|
.highlight(E->getSourceRange());
|
|
return;
|
|
}
|
|
|
|
// A DiscardAssignmentExpr (spelled "_") needs contextual type information to
|
|
// infer its type. If we see one at top level, diagnose that it must be part
|
|
// of an assignment so we don't get a generic "expression is ambiguous" error.
|
|
if (isa<DiscardAssignmentExpr>(E)) {
|
|
diagnose(E->getLoc(), diag::discard_expr_outside_of_assignment)
|
|
.highlight(E->getSourceRange());
|
|
return;
|
|
}
|
|
|
|
// If there are no posted constraints or failures, then there was
|
|
// not enough contextual information available to infer a type for the
|
|
// expression.
|
|
diagnose(E->getLoc(), diag::type_of_expression_is_ambiguous);
|
|
}
|
|
|
|
bool ConstraintSystem::salvage(SmallVectorImpl<Solution> &viable, Expr *expr) {
|
|
// If there were any unavoidable failures, emit the first one we can.
|
|
if (!unavoidableFailures.empty()) {
|
|
for (auto failure : unavoidableFailures) {
|
|
if (diagnoseFailure(*this, *failure, expr, false))
|
|
return true;
|
|
}
|
|
|
|
// If none of the failures wanted to print themselves, emit them in
|
|
// expression order.
|
|
diagnoseFailureForExpr(expr);
|
|
return true;
|
|
}
|
|
|
|
// There were no unavoidable failures, so attempt to solve again, capturing
|
|
// any failures that come from our attempts to select overloads or bind
|
|
// type variables.
|
|
{
|
|
viable.clear();
|
|
|
|
// Set up solver state.
|
|
SolverState state(*this);
|
|
state.recordFailures = true;
|
|
this->solverState = &state;
|
|
|
|
// Solve the system.
|
|
solveRec(viable, FreeTypeVariableBinding::Disallow);
|
|
|
|
// Check whether we have a best solution; this can happen if we found
|
|
// a series of fixes that worked.
|
|
if (auto best = findBestSolution(viable, /*minimize=*/true)) {
|
|
if (*best != 0)
|
|
viable[0] = std::move(viable[*best]);
|
|
viable.erase(viable.begin() + 1, viable.end());
|
|
return false;
|
|
}
|
|
|
|
// FIXME: If we were able to actually fix things along the way,
|
|
// we may have to hunt for the best solution. For now, we don't care.
|
|
|
|
// Remove solutions that require fixes; the fixes in those systems should
|
|
// be diagnosed rather than any ambiguity.
|
|
auto hasFixes = [](const Solution &sol) { return !sol.Fixes.empty(); };
|
|
auto newEnd = std::remove_if(viable.begin(), viable.end(), hasFixes);
|
|
viable.erase(newEnd, viable.end());
|
|
|
|
// If there are multiple solutions, try to diagnose an ambiguity.
|
|
if (viable.size() > 1) {
|
|
if (getASTContext().LangOpts.DebugConstraintSolver) {
|
|
auto &log = getASTContext().TypeCheckerDebug->getStream();
|
|
log << "---Ambiguity error: "
|
|
<< viable.size() << " solutions found---\n";
|
|
int i = 0;
|
|
for (auto &solution : viable) {
|
|
log << "---Ambiguous solution #" << i++ << "---\n";
|
|
solution.dump(log);
|
|
log << "\n";
|
|
}
|
|
}
|
|
|
|
if (diagnoseAmbiguity(*this, viable, expr)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Remove the solver state.
|
|
this->solverState = nullptr;
|
|
|
|
// Fall through to produce diagnostics.
|
|
}
|
|
|
|
if (getExpressionTooComplex()) {
|
|
TC.diagnose(expr->getLoc(), diag::expression_too_complex).
|
|
highlight(expr->getSourceRange());
|
|
return true;
|
|
}
|
|
|
|
// Continue simplifying any active constraints left in the system. We can end
|
|
// up with them because the solver bails out as soon as it sees a Failure. We
|
|
// don't want to leave them around in the system because later diagnostics
|
|
// will assume they are unsolvable and may otherwise leave the system in an
|
|
// inconsistent state.
|
|
simplify(/*ContinueAfterFailures*/true);
|
|
|
|
// If all else fails, diagnose the failure by looking through the system's
|
|
// constraints.
|
|
diagnoseFailureForExpr(expr);
|
|
return true;
|
|
}
|