mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Generalize the conditions in which we'll accept an ambiguous solution to
a constraint system in "allowFreeTypeVariables" mode. Previously, we only allowed a few specific constraints, now we allow any relational and member constraints. The later one is a big deal because it means that we can allow ".Foo" expressions as ambiguous solutions, which CSDiags can handle well. This unblocks solving 23942743 and enables some minor improvements across the board, including diagnosing things like this better: Optional(.none) // now: generic parameter 'T' could not be inferred That said, it also just permutes some non-awesome diagnostics.
This commit is contained in:
@@ -2284,9 +2284,16 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) {
|
Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) {
|
||||||
// Dig out the type of the base, which will be the result
|
// Dig out the type of the base, which will be the result type of this
|
||||||
// type of this expression.
|
// expression. If constraint solving resolved this to an UnresolvedType,
|
||||||
|
// then we're in an ambiguity tolerant mode used for diagnostic
|
||||||
|
// generation. Just leave this as an unresolved member reference.
|
||||||
Type resultTy = simplifyType(expr->getType());
|
Type resultTy = simplifyType(expr->getType());
|
||||||
|
if (resultTy->is<UnresolvedType>()) {
|
||||||
|
expr->setType(resultTy);
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
Type baseTy = resultTy->getRValueType();
|
Type baseTy = resultTy->getRValueType();
|
||||||
auto &tc = cs.getTypeChecker();
|
auto &tc = cs.getTypeChecker();
|
||||||
|
|
||||||
@@ -2346,16 +2353,25 @@ namespace {
|
|||||||
llvm::SmallPtrSet<InjectIntoOptionalExpr *, 4> DiagnosedOptionalInjections;
|
llvm::SmallPtrSet<InjectIntoOptionalExpr *, 4> DiagnosedOptionalInjections;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Expr *applyMemberRefExpr(Expr *expr,
|
Expr *applyMemberRefExpr(Expr *expr, Expr *base, SourceLoc dotLoc,
|
||||||
Expr *base,
|
SourceLoc nameLoc, bool implicit) {
|
||||||
SourceLoc dotLoc,
|
|
||||||
SourceLoc nameLoc,
|
|
||||||
bool implicit) {
|
|
||||||
// Determine the declaration selected for this overloaded reference.
|
// Determine the declaration selected for this overloaded reference.
|
||||||
auto memberLocator = cs.getConstraintLocator(expr,
|
auto memberLocator = cs.getConstraintLocator(expr,
|
||||||
ConstraintLocator::Member);
|
ConstraintLocator::Member);
|
||||||
auto selected = getOverloadChoice(memberLocator);
|
auto selectedElt = getOverloadChoiceIfAvailable(memberLocator);
|
||||||
|
|
||||||
|
if (!selectedElt) {
|
||||||
|
// If constraint solving resolved this to an UnresolvedType, then we're
|
||||||
|
// in an ambiguity tolerant mode used for diagnostic generation. Just
|
||||||
|
// leave this as whatever type of member reference it already is.
|
||||||
|
Type resultTy = simplifyType(expr->getType());
|
||||||
|
assert(resultTy->hasUnresolvedType() &&
|
||||||
|
"Should have a selected member if we got a type");
|
||||||
|
expr->setType(resultTy);
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto selected = *selectedElt;
|
||||||
switch (selected.choice.getKind()) {
|
switch (selected.choice.getKind()) {
|
||||||
case OverloadChoiceKind::DeclViaBridge: {
|
case OverloadChoiceKind::DeclViaBridge: {
|
||||||
// Look through an implicitly unwrapped optional.
|
// Look through an implicitly unwrapped optional.
|
||||||
@@ -2406,14 +2422,12 @@ namespace {
|
|||||||
|
|
||||||
case OverloadChoiceKind::TupleIndex: {
|
case OverloadChoiceKind::TupleIndex: {
|
||||||
auto baseTy = base->getType()->getRValueType();
|
auto baseTy = base->getType()->getRValueType();
|
||||||
if (auto objTy = cs.lookThroughImplicitlyUnwrappedOptionalType(baseTy)) {
|
if (auto objTy = cs.lookThroughImplicitlyUnwrappedOptionalType(baseTy)){
|
||||||
base = coerceImplicitlyUnwrappedOptionalToValue(base, objTy,
|
base = coerceImplicitlyUnwrappedOptionalToValue(base, objTy,
|
||||||
cs.getConstraintLocator(base));
|
cs.getConstraintLocator(base));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new (cs.getASTContext()) TupleElementExpr(
|
return new (cs.getASTContext()) TupleElementExpr(base, dotLoc,
|
||||||
base,
|
|
||||||
dotLoc,
|
|
||||||
selected.choice.getTupleIndex(),
|
selected.choice.getTupleIndex(),
|
||||||
nameLoc,
|
nameLoc,
|
||||||
simplifyType(expr->getType()));
|
simplifyType(expr->getType()));
|
||||||
|
|||||||
@@ -2778,9 +2778,9 @@ static Type replaceArchetypesAndTypeVarsWithUnresolved(Type ty) {
|
|||||||
auto &ctx = ty->getASTContext();
|
auto &ctx = ty->getASTContext();
|
||||||
|
|
||||||
return ty.transform([&](Type type) -> Type {
|
return ty.transform([&](Type type) -> Type {
|
||||||
if (type->is<TypeVariableType>())
|
if (type->is<TypeVariableType>() ||
|
||||||
return ctx.TheUnresolvedType;
|
type->is<ArchetypeType>() ||
|
||||||
if (type->is<ArchetypeType>())
|
type->isTypeParameter())
|
||||||
return ctx.TheUnresolvedType;
|
return ctx.TheUnresolvedType;
|
||||||
return type;
|
return type;
|
||||||
});
|
});
|
||||||
@@ -2818,7 +2818,8 @@ typeCheckChildIndependently(Expr *subExpr, Type convertType,
|
|||||||
if (FT->isAutoClosure())
|
if (FT->isAutoClosure())
|
||||||
convertType = FT->getResult();
|
convertType = FT->getResult();
|
||||||
|
|
||||||
if (convertType->hasTypeVariable() || convertType->hasArchetype())
|
if (convertType->hasTypeVariable() || convertType->hasArchetype() ||
|
||||||
|
convertType->isTypeParameter())
|
||||||
convertType = replaceArchetypesAndTypeVarsWithUnresolved(convertType);
|
convertType = replaceArchetypesAndTypeVarsWithUnresolved(convertType);
|
||||||
|
|
||||||
// If the conversion type contains no info, drop it.
|
// If the conversion type contains no info, drop it.
|
||||||
@@ -3958,6 +3959,15 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) {
|
|||||||
destType->getRValueType(),
|
destType->getRValueType(),
|
||||||
CTP_AssignSource);
|
CTP_AssignSource);
|
||||||
if (!srcExpr) return true;
|
if (!srcExpr) return true;
|
||||||
|
|
||||||
|
// If we are assigning to _ and have unresolvedtypes on the RHS, then we have
|
||||||
|
// an ambiguity problem.
|
||||||
|
if (isa<DiscardAssignmentExpr>(destExpr->getSemanticsProvidingExpr()) &&
|
||||||
|
srcExpr->getType()->hasUnresolvedType()) {
|
||||||
|
diagnoseAmbiguity(srcExpr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4947,21 +4957,24 @@ void FailureDiagnosis::diagnoseAmbiguity(Expr *E) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Attempt to re-type-check the entire expression, while allowing ambiguity.
|
// Attempt to re-type-check the entire expression, allowing ambiguity, but
|
||||||
auto exprType = getTypeOfTypeCheckedChildIndependently(expr);
|
// ignoring a contextual type.
|
||||||
// If it failed and diagnosed something, then we're done.
|
if (expr == E) {
|
||||||
if (!exprType) return;
|
auto exprType = getTypeOfTypeCheckedChildIndependently(expr);
|
||||||
|
// If it failed and diagnosed something, then we're done.
|
||||||
|
if (!exprType) return;
|
||||||
|
|
||||||
// If we were able to find something more specific than "unknown" (perhaps
|
// If we were able to find something more specific than "unknown" (perhaps
|
||||||
// something like "[_:_]" for a dictionary literal), include it in the
|
// something like "[_:_]" for a dictionary literal), include it in the
|
||||||
// diagnostic.
|
// diagnostic.
|
||||||
if (!isUnresolvedOrTypeVarType(exprType)) {
|
if (!isUnresolvedOrTypeVarType(exprType)) {
|
||||||
diagnose(E->getLoc(), diag::specific_type_of_expression_is_ambiguous,
|
diagnose(E->getLoc(), diag::specific_type_of_expression_is_ambiguous,
|
||||||
exprType)
|
exprType)
|
||||||
.highlight(E->getSourceRange());
|
.highlight(E->getSourceRange());
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no posted constraints or failures, then there was
|
// If there are no posted constraints or failures, then there was
|
||||||
// not enough contextual information available to infer a type for the
|
// not enough contextual information available to infer a type for the
|
||||||
// expression.
|
// expression.
|
||||||
|
|||||||
@@ -1562,22 +1562,26 @@ bool ConstraintSystem::solveSimplified(
|
|||||||
// constraints that could show up here?
|
// constraints that could show up here?
|
||||||
if (allowFreeTypeVariables != FreeTypeVariableBinding::Disallow &&
|
if (allowFreeTypeVariables != FreeTypeVariableBinding::Disallow &&
|
||||||
hasFreeTypeVariables()) {
|
hasFreeTypeVariables()) {
|
||||||
bool anyNonConformanceConstraints = false;
|
|
||||||
for (auto &constraint : InactiveConstraints) {
|
|
||||||
if (constraint.getKind() == ConstraintKind::ConformsTo ||
|
|
||||||
constraint.getKind() == ConstraintKind::SelfObjectOfProtocol ||
|
|
||||||
constraint.getKind() == ConstraintKind::TypeMember)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
anyNonConformanceConstraints = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this solution is worse than the best solution we've seen so far,
|
// If this solution is worse than the best solution we've seen so far,
|
||||||
// skip it.
|
// skip it.
|
||||||
if (worseThanBestSolution())
|
if (worseThanBestSolution())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
bool anyNonConformanceConstraints = false;
|
||||||
|
for (auto &constraint : InactiveConstraints) {
|
||||||
|
switch (constraint.getClassification()) {
|
||||||
|
case ConstraintClassification::Relational:
|
||||||
|
case ConstraintClassification::Member:
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
anyNonConformanceConstraints = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!anyNonConformanceConstraints) {
|
if (!anyNonConformanceConstraints) {
|
||||||
auto solution = finalize(allowFreeTypeVariables);
|
auto solution = finalize(allowFreeTypeVariables);
|
||||||
if (TC.getLangOpts().DebugConstraintSolver) {
|
if (TC.getLangOpts().DebugConstraintSolver) {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ acceptString("\(hello), \(world) #\(i)!")
|
|||||||
Optional<Int>(1) // expected-warning{{unused}}
|
Optional<Int>(1) // expected-warning{{unused}}
|
||||||
Optional(1) // expected-warning{{unused}}
|
Optional(1) // expected-warning{{unused}}
|
||||||
_ = .none as Optional<Int>
|
_ = .none as Optional<Int>
|
||||||
Optional(.none) // expected-error{{type of expression is ambiguous without more context}}
|
Optional(.none) // expected-error{{generic parameter 'T' could not be inferred}}
|
||||||
|
|
||||||
// Interpolation
|
// Interpolation
|
||||||
"\(hello), \(world) #\(i)!"
|
"\(hello), \(world) #\(i)!"
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ func r18800223(i : Int) {
|
|||||||
|
|
||||||
|
|
||||||
var buttonTextColor: String?
|
var buttonTextColor: String?
|
||||||
_ = (buttonTextColor != nil) ? 42 : {$0}; // expected-error {{unable to infer closure return type in current context}}
|
_ = (buttonTextColor != nil) ? 42 : {$0}; // expected-error {{result values in '? :' expression have mismatching types 'Int' and '(_) -> _'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// <rdar://problem/21883806> Bogus "'_' can only appear in a pattern or on the left side of an assignment" is back
|
// <rdar://problem/21883806> Bogus "'_' can only appear in a pattern or on the left side of an assignment" is back
|
||||||
@@ -609,7 +609,8 @@ extension Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func h() -> String {
|
func h() -> String {
|
||||||
return "foo".unavail([0]) // expected-error {{value of type 'String' has no member 'Element'}}
|
return "foo".unavail([0]) // expected-error {{cannot invoke 'unavail' with an argument list of type '([Int])'}}
|
||||||
|
// expected-note @-1 {{expected an argument list of type '(T)'}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ protocol P {
|
|||||||
func f<U: P>(rhs: U) -> X<U.A> { // expected-error {{use of undeclared type 'X'}}
|
func f<U: P>(rhs: U) -> X<U.A> { // expected-error {{use of undeclared type 'X'}}
|
||||||
// FIXME: This diagnostic isn't great, it happens because the generic constraint
|
// FIXME: This diagnostic isn't great, it happens because the generic constraint
|
||||||
// 'U' from the invalid type signature never gets resolved.
|
// 'U' from the invalid type signature never gets resolved.
|
||||||
let g = rhs.generate() // expected-error {{type of expression is ambiguous without more context}}
|
let g = rhs.generate() // expected-error {{cannot invoke 'generate' with no arguments}}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Zzz<T> {
|
struct Zzz<T> {
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ enum Complex {
|
|||||||
case B
|
case B
|
||||||
}
|
}
|
||||||
|
|
||||||
if Complex.A(1) == .B { } // expected-error{{type of expression is ambiguous without more context}}
|
if Complex.A(1) == .B { } // expected-error{{binary operator '==' cannot be applied to operands of type 'Complex' and '_'}}
|
||||||
|
// expected-note @-1 {{overloads for '==' exist with these partially matching parameter lists: }}
|
||||||
|
|
||||||
|
|
||||||
// rdar://19773050
|
// rdar://19773050
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ var e2a: E2<Int> = .First
|
|||||||
e2a = .Second(5)
|
e2a = .Second(5)
|
||||||
var e2b: E2 = .Second(5)
|
var e2b: E2 = .Second(5)
|
||||||
e2b = .First
|
e2b = .First
|
||||||
var e2c: E2 = .First // expected-error{{type of expression is ambiguous without more context}}
|
var e2c: E2 = .First // expected-error{{generic parameter 'T' could not be inferred}}
|
||||||
|
|||||||
Reference in New Issue
Block a user