Skip to content

Commit b5500b8

Browse files
committed
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.
1 parent 42591f7 commit b5500b8

File tree

8 files changed

+76
-43
lines changed

8 files changed

+76
-43
lines changed

lib/Sema/CSApply.cpp

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,9 +2284,16 @@ namespace {
22842284
}
22852285

22862286
Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *expr) {
2287-
// Dig out the type of the base, which will be the result
2288-
// type of this expression.
2287+
// Dig out the type of the base, which will be the result type of this
2288+
// expression. If constraint solving resolved this to an UnresolvedType,
2289+
// then we're in an ambiguity tolerant mode used for diagnostic
2290+
// generation. Just leave this as an unresolved member reference.
22892291
Type resultTy = simplifyType(expr->getType());
2292+
if (resultTy->is<UnresolvedType>()) {
2293+
expr->setType(resultTy);
2294+
return expr;
2295+
}
2296+
22902297
Type baseTy = resultTy->getRValueType();
22912298
auto &tc = cs.getTypeChecker();
22922299

@@ -2346,16 +2353,25 @@ namespace {
23462353
llvm::SmallPtrSet<InjectIntoOptionalExpr *, 4> DiagnosedOptionalInjections;
23472354
private:
23482355

2349-
Expr *applyMemberRefExpr(Expr *expr,
2350-
Expr *base,
2351-
SourceLoc dotLoc,
2352-
SourceLoc nameLoc,
2353-
bool implicit) {
2356+
Expr *applyMemberRefExpr(Expr *expr, Expr *base, SourceLoc dotLoc,
2357+
SourceLoc nameLoc, bool implicit) {
23542358
// Determine the declaration selected for this overloaded reference.
23552359
auto memberLocator = cs.getConstraintLocator(expr,
23562360
ConstraintLocator::Member);
2357-
auto selected = getOverloadChoice(memberLocator);
2361+
auto selectedElt = getOverloadChoiceIfAvailable(memberLocator);
2362+
2363+
if (!selectedElt) {
2364+
// If constraint solving resolved this to an UnresolvedType, then we're
2365+
// in an ambiguity tolerant mode used for diagnostic generation. Just
2366+
// leave this as whatever type of member reference it already is.
2367+
Type resultTy = simplifyType(expr->getType());
2368+
assert(resultTy->hasUnresolvedType() &&
2369+
"Should have a selected member if we got a type");
2370+
expr->setType(resultTy);
2371+
return expr;
2372+
}
23582373

2374+
auto selected = *selectedElt;
23592375
switch (selected.choice.getKind()) {
23602376
case OverloadChoiceKind::DeclViaBridge: {
23612377
// Look through an implicitly unwrapped optional.
@@ -2406,14 +2422,12 @@ namespace {
24062422

24072423
case OverloadChoiceKind::TupleIndex: {
24082424
auto baseTy = base->getType()->getRValueType();
2409-
if (auto objTy = cs.lookThroughImplicitlyUnwrappedOptionalType(baseTy)) {
2425+
if (auto objTy = cs.lookThroughImplicitlyUnwrappedOptionalType(baseTy)){
24102426
base = coerceImplicitlyUnwrappedOptionalToValue(base, objTy,
24112427
cs.getConstraintLocator(base));
24122428
}
24132429

2414-
return new (cs.getASTContext()) TupleElementExpr(
2415-
base,
2416-
dotLoc,
2430+
return new (cs.getASTContext()) TupleElementExpr(base, dotLoc,
24172431
selected.choice.getTupleIndex(),
24182432
nameLoc,
24192433
simplifyType(expr->getType()));

lib/Sema/CSDiag.cpp

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,9 +2778,9 @@ static Type replaceArchetypesAndTypeVarsWithUnresolved(Type ty) {
27782778
auto &ctx = ty->getASTContext();
27792779

27802780
return ty.transform([&](Type type) -> Type {
2781-
if (type->is<TypeVariableType>())
2782-
return ctx.TheUnresolvedType;
2783-
if (type->is<ArchetypeType>())
2781+
if (type->is<TypeVariableType>() ||
2782+
type->is<ArchetypeType>() ||
2783+
type->isTypeParameter())
27842784
return ctx.TheUnresolvedType;
27852785
return type;
27862786
});
@@ -2818,7 +2818,8 @@ typeCheckChildIndependently(Expr *subExpr, Type convertType,
28182818
if (FT->isAutoClosure())
28192819
convertType = FT->getResult();
28202820

2821-
if (convertType->hasTypeVariable() || convertType->hasArchetype())
2821+
if (convertType->hasTypeVariable() || convertType->hasArchetype() ||
2822+
convertType->isTypeParameter())
28222823
convertType = replaceArchetypesAndTypeVarsWithUnresolved(convertType);
28232824

28242825
// If the conversion type contains no info, drop it.
@@ -3958,6 +3959,15 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) {
39583959
destType->getRValueType(),
39593960
CTP_AssignSource);
39603961
if (!srcExpr) return true;
3962+
3963+
// If we are assigning to _ and have unresolvedtypes on the RHS, then we have
3964+
// an ambiguity problem.
3965+
if (isa<DiscardAssignmentExpr>(destExpr->getSemanticsProvidingExpr()) &&
3966+
srcExpr->getType()->hasUnresolvedType()) {
3967+
diagnoseAmbiguity(srcExpr);
3968+
return true;
3969+
}
3970+
39613971
return false;
39623972
}
39633973

@@ -4947,21 +4957,24 @@ void FailureDiagnosis::diagnoseAmbiguity(Expr *E) {
49474957
}
49484958

49494959

4950-
// Attempt to re-type-check the entire expression, while allowing ambiguity.
4951-
auto exprType = getTypeOfTypeCheckedChildIndependently(expr);
4952-
// If it failed and diagnosed something, then we're done.
4953-
if (!exprType) return;
4960+
// Attempt to re-type-check the entire expression, allowing ambiguity, but
4961+
// ignoring a contextual type.
4962+
if (expr == E) {
4963+
auto exprType = getTypeOfTypeCheckedChildIndependently(expr);
4964+
// If it failed and diagnosed something, then we're done.
4965+
if (!exprType) return;
49544966

4955-
// If we were able to find something more specific than "unknown" (perhaps
4956-
// something like "[_:_]" for a dictionary literal), include it in the
4957-
// diagnostic.
4958-
if (!isUnresolvedOrTypeVarType(exprType)) {
4959-
diagnose(E->getLoc(), diag::specific_type_of_expression_is_ambiguous,
4960-
exprType)
4961-
.highlight(E->getSourceRange());
4962-
return;
4967+
// If we were able to find something more specific than "unknown" (perhaps
4968+
// something like "[_:_]" for a dictionary literal), include it in the
4969+
// diagnostic.
4970+
if (!isUnresolvedOrTypeVarType(exprType)) {
4971+
diagnose(E->getLoc(), diag::specific_type_of_expression_is_ambiguous,
4972+
exprType)
4973+
.highlight(E->getSourceRange());
4974+
return;
4975+
}
49634976
}
4964-
4977+
49654978
// If there are no posted constraints or failures, then there was
49664979
// not enough contextual information available to infer a type for the
49674980
// expression.

lib/Sema/CSSolver.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,22 +1562,26 @@ bool ConstraintSystem::solveSimplified(
15621562
// constraints that could show up here?
15631563
if (allowFreeTypeVariables != FreeTypeVariableBinding::Disallow &&
15641564
hasFreeTypeVariables()) {
1565+
1566+
// If this solution is worse than the best solution we've seen so far,
1567+
// skip it.
1568+
if (worseThanBestSolution())
1569+
return true;
1570+
15651571
bool anyNonConformanceConstraints = false;
15661572
for (auto &constraint : InactiveConstraints) {
1567-
if (constraint.getKind() == ConstraintKind::ConformsTo ||
1568-
constraint.getKind() == ConstraintKind::SelfObjectOfProtocol ||
1569-
constraint.getKind() == ConstraintKind::TypeMember)
1573+
switch (constraint.getClassification()) {
1574+
case ConstraintClassification::Relational:
1575+
case ConstraintClassification::Member:
15701576
continue;
1577+
default:
1578+
break;
1579+
}
15711580

15721581
anyNonConformanceConstraints = true;
15731582
break;
15741583
}
15751584

1576-
// If this solution is worse than the best solution we've seen so far,
1577-
// skip it.
1578-
if (worseThanBestSolution())
1579-
return true;
1580-
15811585
if (!anyNonConformanceConstraints) {
15821586
auto solution = finalize(allowFreeTypeVariables);
15831587
if (TC.getLangOpts().DebugConstraintSolver) {

test/Constraints/construction.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ acceptString("\(hello), \(world) #\(i)!")
5757
Optional<Int>(1) // expected-warning{{unused}}
5858
Optional(1) // expected-warning{{unused}}
5959
_ = .none as Optional<Int>
60-
Optional(.none) // expected-error{{type of expression is ambiguous without more context}}
60+
Optional(.none) // expected-error{{generic parameter 'T' could not be inferred}}
6161

6262
// Interpolation
6363
"\(hello), \(world) #\(i)!"

test/Constraints/diagnostics.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ func r18800223(i : Int) {
242242

243243

244244
var buttonTextColor: String?
245-
_ = (buttonTextColor != nil) ? 42 : {$0}; // expected-error {{unable to infer closure return type in current context}}
245+
_ = (buttonTextColor != nil) ? 42 : {$0}; // expected-error {{result values in '? :' expression have mismatching types 'Int' and '(_) -> _'}}
246246
}
247247

248248
// <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 {
609609
}
610610

611611
func h() -> String {
612-
return "foo".unavail([0]) // expected-error {{value of type 'String' has no member 'Element'}}
612+
return "foo".unavail([0]) // expected-error {{cannot invoke 'unavail' with an argument list of type '([Int])'}}
613+
// expected-note @-1 {{expected an argument list of type '(T)'}}
613614
}
614615
}
615616

test/Constraints/invalid_constraint_lookup.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ protocol P {
77
func f<U: P>(rhs: U) -> X<U.A> { // expected-error {{use of undeclared type 'X'}}
88
// FIXME: This diagnostic isn't great, it happens because the generic constraint
99
// 'U' from the invalid type signature never gets resolved.
10-
let g = rhs.generate() // expected-error {{type of expression is ambiguous without more context}}
10+
let g = rhs.generate() // expected-error {{cannot invoke 'generate' with no arguments}}
1111
}
1212

1313
struct Zzz<T> {

test/Sema/enum_equatable_hashable.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ enum Complex {
8585
case B
8686
}
8787

88-
if Complex.A(1) == .B { } // expected-error{{type of expression is ambiguous without more context}}
88+
if Complex.A(1) == .B { } // expected-error{{binary operator '==' cannot be applied to operands of type 'Complex' and '_'}}
89+
// expected-note @-1 {{overloads for '==' exist with these partially matching parameter lists: }}
8990

9091

9192
// rdar://19773050

test/expr/delayed-ident/enum.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ var e2a: E2<Int> = .First
2121
e2a = .Second(5)
2222
var e2b: E2 = .Second(5)
2323
e2b = .First
24-
var e2c: E2 = .First // expected-error{{type of expression is ambiguous without more context}}
24+
var e2c: E2 = .First // expected-error{{generic parameter 'T' could not be inferred}}

0 commit comments

Comments
 (0)