Skip to content

Commit 1576ab7

Browse files
authored
Merge pull request swiftlang#29393 from DougGregor/decontextualize-contextuals
[Constraint solver] Request contextual type information per expression.
2 parents 8c13747 + 83cb351 commit 1576ab7

File tree

11 files changed

+117
-78
lines changed

11 files changed

+117
-78
lines changed

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7321,7 +7321,8 @@ llvm::PointerUnion<Expr *, Stmt *> ConstraintSystem::applySolutionImpl(
73217321
auto shouldCoerceToContextualType = [&]() {
73227322
return convertType &&
73237323
!(getType(resultExpr)->isUninhabited() &&
7324-
getContextualTypePurpose() == CTP_ReturnSingleExpr);
7324+
getContextualTypePurpose(target.getAsExpr())
7325+
== CTP_ReturnSingleExpr);
73257326
};
73267327

73277328
// If we're supposed to convert the expression to some particular type,

lib/Sema/CSDiag.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,7 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
14231423
if (calleeInfo.closeness == CC_ExactMatch)
14241424
return true;
14251425

1426-
if (!CS.getContextualType() ||
1426+
if (!CS.getContextualType(callExpr) ||
14271427
(calleeInfo.closeness != CC_ArgumentMismatch &&
14281428
calleeInfo.closeness != CC_OneGenericArgumentMismatch))
14291429
return false;
@@ -1585,14 +1585,14 @@ visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
15851585
/// An IdentityExpr doesn't change its argument, but it *can* propagate its
15861586
/// contextual type information down.
15871587
bool FailureDiagnosis::visitIdentityExpr(IdentityExpr *E) {
1588-
auto contextualType = CS.getContextualType();
1588+
auto contextualType = CS.getContextualType(E);
15891589

15901590
// If we have a paren expr and our contextual type is a ParenType, remove the
15911591
// paren expr sugar.
15921592
if (contextualType)
15931593
contextualType = contextualType->getWithoutParens();
15941594
if (!typeCheckChildIndependently(E->getSubExpr(), contextualType,
1595-
CS.getContextualTypePurpose()))
1595+
CS.getContextualTypePurpose(E)))
15961596
return true;
15971597
return false;
15981598
}
@@ -1666,8 +1666,10 @@ void ConstraintSystem::diagnoseFailureFor(SolutionApplicationTarget target) {
16661666
return;
16671667

16681668
// If this is a contextual conversion problem, dig out some information.
1669-
if (diagnosis.diagnoseContextualConversionError(expr, getContextualType(),
1670-
getContextualTypePurpose()))
1669+
if (diagnosis.diagnoseContextualConversionError(
1670+
expr,
1671+
getContextualType(expr),
1672+
getContextualTypePurpose(expr)))
16711673
return;
16721674

16731675
// If no one could find a problem with this expression or constraint system,
@@ -1795,7 +1797,7 @@ void FailureDiagnosis::diagnoseAmbiguity(Expr *E) {
17951797
// Diagnose ".foo" expressions that lack context specifically.
17961798
if (auto UME =
17971799
dyn_cast<UnresolvedMemberExpr>(E->getSemanticsProvidingExpr())) {
1798-
if (!CS.getContextualType()) {
1800+
if (!CS.getContextualType(E)) {
17991801
diagnose(E->getLoc(), diag::unresolved_member_no_inference,UME->getName())
18001802
.highlight(SourceRange(UME->getDotLoc(),
18011803
UME->getNameLoc().getSourceRange().End));

lib/Sema/CSDiagnostics.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ ValueDecl *RequirementFailure::getDeclRef() const {
232232
};
233233

234234
if (isFromContextualType())
235-
return getAffectedDeclFromType(cs.getContextualType());
235+
return getAffectedDeclFromType(
236+
cs.getContextualType(getLocator()->getAnchor()));
236237

237238
if (auto overload = getChoiceFor(getLocator())) {
238239
// If there is a declaration associated with this
@@ -1207,7 +1208,7 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() {
12071208
// Assignment is not allowed inside of a condition,
12081209
// so let's not diagnose immutability, because
12091210
// most likely the problem is related to use of `=` itself.
1210-
if (cs.getContextualTypePurpose() == CTP_Condition)
1211+
if (cs.getContextualTypePurpose(diagExpr) == CTP_Condition)
12111212
return false;
12121213

12131214
if (auto assignExpr = dyn_cast<AssignExpr>(diagExpr)) {
@@ -2200,7 +2201,8 @@ bool ContextualFailure::diagnoseConversionToNil() const {
22002201
emitDiagnostic(anchor->getLoc(), *diagnostic, getToType());
22012202

22022203
if (CTP == CTP_Initialization) {
2203-
auto *patternTR = cs.getContextualTypeLoc().getTypeRepr();
2204+
auto *patternTR =
2205+
cs.getContextualTypeLoc(locator->getAnchor()).getTypeRepr();
22042206
if (!patternTR)
22052207
return true;
22062208

@@ -2902,7 +2904,8 @@ bool TupleContextualFailure::diagnoseAsError() {
29022904
auto &cs = getConstraintSystem();
29032905
if (isNumElementsMismatch())
29042906
diagnostic = diag::tuple_types_not_convertible_nelts;
2905-
else if ((purpose == CTP_Initialization) && !cs.getContextualType())
2907+
else if ((purpose == CTP_Initialization) &&
2908+
!cs.getContextualType(getAnchor()))
29062909
diagnostic = diag::tuple_types_not_convertible;
29072910
else if (auto diag = getDiagnosticFor(purpose, /*forProtocol=*/false))
29082911
diagnostic = *diag;
@@ -3387,6 +3390,12 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
33873390
return true;
33883391
}
33893392

3393+
auto getRootExpr = [&cs](Expr *expr) {
3394+
while (auto parent = cs.getParentExpr(expr))
3395+
expr = parent;
3396+
return expr;
3397+
};
3398+
33903399
Expr *expr = findParentExpr(getAnchor());
33913400
SourceRange baseRange = expr ? expr->getSourceRange() : SourceRange();
33923401

@@ -3442,7 +3451,7 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
34423451
OverloadChoice choice = selection->choice;
34433452
if (choice.isDecl() && isMutable(choice.getDecl()) &&
34443453
!isCallArgument(initCall) &&
3445-
cs.getContextualTypePurpose() == CTP_Unused) {
3454+
cs.getContextualTypePurpose(getRootExpr(ctorRef)) == CTP_Unused) {
34463455
auto fixItLoc = ctorRef->getBase()->getSourceRange().End;
34473456
emitDiagnostic(loc, diag::init_not_instance_member_use_assignment)
34483457
.fixItInsertAfter(fixItLoc, " = ");
@@ -3628,7 +3637,7 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
36283637
Type contextualType;
36293638
for (auto iterateCS = &cs; contextualType.isNull() && iterateCS;
36303639
iterateCS = iterateCS->baseCS) {
3631-
contextualType = iterateCS->getContextualType();
3640+
contextualType = iterateCS->getContextualType(getRawAnchor());
36323641
}
36333642

36343643
// Try to provide a fix-it that only contains a '.'
@@ -3639,11 +3648,10 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
36393648

36403649
// Check if the expression is the matching operator ~=, most often used in
36413650
// case statements. If so, try to provide a single dot fix-it
3642-
const Expr *contextualTypeNode = nullptr;
3651+
const Expr *contextualTypeNode = getRootExpr(getAnchor());
36433652
ConstraintSystem *lastCS = nullptr;
36443653
for (auto iterateCS = &cs; iterateCS; iterateCS = iterateCS->baseCS) {
36453654
lastCS = iterateCS;
3646-
contextualTypeNode = iterateCS->getContextualTypeNode();
36473655
}
36483656

36493657
// The '~=' operator is an overloaded decl ref inside a binaryExpr
@@ -3791,7 +3799,8 @@ bool MissingArgumentsFailure::diagnoseAsError() {
37913799
if (locator->isLastElement<LocatorPathElt::ContextualType>()) {
37923800
auto &cs = getConstraintSystem();
37933801
emitDiagnostic(anchor->getLoc(), diag::cannot_convert_initializer_value,
3794-
getType(anchor), resolveType(cs.getContextualType()));
3802+
getType(anchor),
3803+
resolveType(cs.getContextualType(getAnchor())));
37953804
// TODO: It would be great so somehow point out which arguments are missing.
37963805
return true;
37973806
}
@@ -4003,7 +4012,7 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) {
40034012

40044013
auto *locator = getLocator();
40054014
if (locator->isForContextualType()) {
4006-
funcType = cs.getContextualType()->getAs<FunctionType>();
4015+
funcType = cs.getContextualType(locator->getAnchor())->getAs<FunctionType>();
40074016
} else if (auto info = cs.getFunctionArgApplyInfo(locator)) {
40084017
funcType = info->getParamType()->getAs<FunctionType>();
40094018
} else if (locator->isLastElement<LocatorPathElt::ClosureResult>()) {
@@ -5251,7 +5260,7 @@ bool InOutConversionFailure::diagnoseAsError() {
52515260
argApplyInfo->getArgType(), argApplyInfo->getParamType());
52525261
} else {
52535262
assert(locator->findLast<LocatorPathElt::ContextualType>());
5254-
auto contextualType = cs.getContextualType();
5263+
auto contextualType = cs.getContextualType(anchor);
52555264
auto purpose = getContextualTypePurpose();
52565265
auto diagnostic = getDiagnosticFor(purpose, /*forProtocol=*/false);
52575266

lib/Sema/CSDiagnostics.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,9 @@ class ContextualFailure : public FailureDiagnostic {
532532
public:
533533
ContextualFailure(ConstraintSystem &cs, Type lhs, Type rhs,
534534
ConstraintLocator *locator)
535-
: ContextualFailure(cs, cs.getContextualTypePurpose(), lhs, rhs,
536-
locator) {}
535+
: ContextualFailure(cs,
536+
cs.getContextualTypePurpose(locator->getAnchor()),
537+
lhs, rhs, locator) {}
537538

538539
ContextualFailure(ConstraintSystem &cs, ContextualTypePurpose purpose,
539540
Type lhs, Type rhs, ConstraintLocator *locator)

lib/Sema/CSFix.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ bool MissingConformance::diagnose(bool asNote) const {
191191
auto *locator = getLocator();
192192

193193
if (IsContextual) {
194-
auto context = cs.getContextualTypePurpose();
194+
auto context = cs.getContextualTypePurpose(locator->getAnchor());
195195
MissingContextualConformanceFailure failure(
196196
cs, context, NonConformingType, ProtocolType, locator);
197197
return failure.diagnose(asNote);
@@ -262,9 +262,9 @@ ContextualMismatch *ContextualMismatch::create(ConstraintSystem &cs, Type lhs,
262262
/// and the contextual type.
263263
static Optional<std::tuple<ContextualTypePurpose, Type, Type>>
264264
getStructuralTypeContext(ConstraintSystem &cs, ConstraintLocator *locator) {
265-
if (auto contextualType = cs.getContextualType()) {
265+
if (auto contextualType = cs.getContextualType(locator->getAnchor())) {
266266
if (auto *anchor = simplifyLocatorToAnchor(locator))
267-
return std::make_tuple(cs.getContextualTypePurpose(),
267+
return std::make_tuple(cs.getContextualTypePurpose(locator->getAnchor()),
268268
cs.getType(anchor),
269269
contextualType);
270270
} else if (auto argApplyInfo = cs.getFunctionArgApplyInfo(locator)) {
@@ -304,7 +304,7 @@ bool AllowTupleTypeMismatch::coalesceAndDiagnose(
304304
Type toType;
305305

306306
if (getFromType()->is<TupleType>() && getToType()->is<TupleType>()) {
307-
purpose = cs.getContextualTypePurpose();
307+
purpose = cs.getContextualTypePurpose(locator->getAnchor());
308308
fromType = getFromType();
309309
toType = getToType();
310310
} else if (auto contextualTypeInfo = getStructuralTypeContext(cs, locator)) {

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2995,7 +2995,7 @@ bool ConstraintSystem::repairFailures(
29952995
auto elt = path.back();
29962996
switch (elt.getKind()) {
29972997
case ConstraintLocator::LValueConversion: {
2998-
auto CTP = getContextualTypePurpose();
2998+
auto CTP = getContextualTypePurpose(anchor);
29992999
// Special case for `CTP_CallArgument` set by CSDiag
30003000
// while type-checking each argument because we yet
30013001
// to cover argument-to-parameter conversions in the
@@ -3368,7 +3368,7 @@ bool ConstraintSystem::repairFailures(
33683368
if (lhs->isHole() || rhs->isHole())
33693369
return true;
33703370

3371-
auto purpose = getContextualTypePurpose();
3371+
auto purpose = getContextualTypePurpose(anchor);
33723372
if (rhs->isVoid() &&
33733373
(purpose == CTP_ReturnStmt || purpose == CTP_ReturnSingleExpr)) {
33743374
conversionsOrFixes.push_back(

lib/Sema/CSSolver.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ ConstraintSystem::SolverScope::SolverScope(ConstraintSystem &cs)
441441
numFunctionBuilderTransformed = cs.functionBuilderTransformed.size();
442442
numResolvedOverloads = cs.ResolvedOverloads.size();
443443
numInferredClosureTypes = cs.ClosureTypes.size();
444+
numContextualTypes = cs.contextualTypes.size();
444445

445446
PreviousScore = cs.CurrentScore;
446447

@@ -510,6 +511,9 @@ ConstraintSystem::SolverScope::~SolverScope() {
510511
// Remove any inferred closure types (e.g. used in function builder body).
511512
truncate(cs.ClosureTypes, numInferredClosureTypes);
512513

514+
// Remove any contextual types.
515+
truncate(cs.contextualTypes, numContextualTypes);
516+
513517
// Reset the previous score.
514518
cs.CurrentScore = PreviousScore;
515519

@@ -747,7 +751,7 @@ void ConstraintSystem::shrink(Expr *expr) {
747751
// that have overload sets.
748752
if (auto collectionExpr = dyn_cast<CollectionExpr>(expr)) {
749753
visitCollectionExpr(collectionExpr, CS.getContextualType(expr),
750-
CS.getContextualTypePurpose());
754+
CS.getContextualTypePurpose(expr));
751755
// Don't try to walk into the dictionary.
752756
return {false, expr};
753757
}
@@ -813,11 +817,11 @@ void ConstraintSystem::shrink(Expr *expr) {
813817
if (Candidates.empty())
814818
return expr;
815819

816-
auto contextualType = CS.getContextualType();
820+
auto contextualType = CS.getContextualType(expr);
817821
// If there is a contextual type set for this expression.
818822
if (!contextualType.isNull()) {
819823
Candidates.push_back(Candidate(CS, PrimaryExpr, contextualType,
820-
CS.getContextualTypePurpose()));
824+
CS.getContextualTypePurpose(expr)));
821825
return expr;
822826
}
823827

@@ -1191,6 +1195,8 @@ ConstraintSystem::solveImpl(Expr *&expr,
11911195
// Set up the expression type checker timer.
11921196
Timer.emplace(expr, *this);
11931197

1198+
Expr *origExpr = expr;
1199+
11941200
// Try to shrink the system by reducing disjunction domains. This
11951201
// goes through every sub-expression and generate its own sub-system, to
11961202
// try to reduce the domains of those subexpressions.
@@ -1209,23 +1215,23 @@ ConstraintSystem::solveImpl(Expr *&expr,
12091215
// constraint.
12101216
if (convertType) {
12111217
auto constraintKind = ConstraintKind::Conversion;
1212-
1213-
if ((getContextualTypePurpose() == CTP_ReturnStmt ||
1214-
getContextualTypePurpose() == CTP_ReturnSingleExpr ||
1215-
getContextualTypePurpose() == CTP_Initialization)
1218+
1219+
auto ctp = getContextualTypePurpose(origExpr);
1220+
if ((ctp == CTP_ReturnStmt ||
1221+
ctp == CTP_ReturnSingleExpr ||
1222+
ctp == CTP_Initialization)
12161223
&& Options.contains(ConstraintSystemFlags::UnderlyingTypeForOpaqueReturnType))
12171224
constraintKind = ConstraintKind::OpaqueUnderlyingType;
12181225

1219-
if (getContextualTypePurpose() == CTP_CallArgument)
1226+
if (ctp == CTP_CallArgument)
12201227
constraintKind = ConstraintKind::ArgumentConversion;
12211228

12221229
// In a by-reference yield, we expect the contextual type to be an
12231230
// l-value type, so the result must be bound to that.
1224-
if (getContextualTypePurpose() == CTP_YieldByReference)
1231+
if (ctp == CTP_YieldByReference)
12251232
constraintKind = ConstraintKind::Bind;
12261233

1227-
bool isForSingleExprFunction =
1228-
getContextualTypePurpose() == CTP_ReturnSingleExpr;
1234+
bool isForSingleExprFunction = ctp == CTP_ReturnSingleExpr;
12291235
auto *convertTypeLocator = getConstraintLocator(
12301236
expr, LocatorPathElt::ContextualType(isForSingleExprFunction));
12311237

lib/Sema/ConstraintSystem.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2918,9 +2918,11 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
29182918
return locator
29192919
->isLastElement<LocatorPathElt::ContextualType>();
29202920
})) {
2921+
auto anchor =
2922+
viableSolutions.front()->Fixes.front()->getLocator()->getAnchor();
29212923
auto baseName = name.getBaseName();
29222924
DE.diagnose(commonAnchor->getLoc(), diag::no_candidates_match_result_type,
2923-
baseName.userFacingName(), getContextualType());
2925+
baseName.userFacingName(), getContextualType(anchor));
29242926
} else {
29252927
emitGeneralAmbiguityFailure();
29262928
}

0 commit comments

Comments
 (0)