Skip to content

Commit a5df786

Browse files
committed
[CSDiag] Always find and set correct declaration context for sub-expression type-check
Replace dedicated method with `typeCheckChildIndependently` always setting the closest possible declaration context for type-check call. This fixes a problem where sub-expression comes from multiple levels or nested closures but CSDiag didn't re-typecheck parent closure. Resolves: rdar://problem/50869732
1 parent 77a642a commit a5df786

File tree

1 file changed

+57
-52
lines changed

1 file changed

+57
-52
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,9 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
347347
return e ? CS.getType(e) : Type();
348348
}
349349

350-
/// This is the same as typeCheckChildIndependently, but works on an arbitrary
351-
/// subexpression of the current node because it handles ClosureExpr parents
352-
/// of the specified node.
353-
Expr *typeCheckArbitrarySubExprIndependently(Expr *subExpr,
354-
TCCOptions options = TCCOptions());
350+
/// Find a nearest declaration context which could be used
351+
/// to type-check this sub-expression.
352+
DeclContext *findDeclContext(Expr *subExpr) const;
355353

356354
/// Special magic to handle inout exprs and tuples in argument lists.
357355
Expr *typeCheckArgumentChildIndependently(Expr *argExpr, Type argType,
@@ -1085,8 +1083,8 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
10851083
// constraint.
10861084
if (CS.getContextualTypePurpose() != CTP_Unused)
10871085
options |= TCC_ForceRecheck;
1088-
1089-
auto sub = typeCheckArbitrarySubExprIndependently(anchor, options);
1086+
1087+
auto sub = typeCheckChildIndependently(anchor, options);
10901088
if (!sub) return true;
10911089
fromType = CS.getType(sub);
10921090
}
@@ -1559,10 +1557,14 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
15591557
if ((!convertType || options.contains(TCC_AllowUnresolvedTypeVariables)) &&
15601558
allowFreeTypeVariables)
15611559
TCEOptions |= TypeCheckExprFlags::AllowUnresolvedTypeVariables;
1562-
1563-
auto resultTy = CS.TC.typeCheckExpression(
1564-
subExpr, CS.DC, TypeLoc::withoutLoc(convertType), convertTypePurpose,
1565-
TCEOptions, listener, &CS);
1560+
1561+
// When we're type checking a single-expression closure, we need to reset the
1562+
// DeclContext to this closure for the recursive type checking. Otherwise,
1563+
// if there is a closure in the subexpression, we can violate invariants.
1564+
auto *DC = findDeclContext(subExpr);
1565+
auto resultTy =
1566+
CS.TC.typeCheckExpression(subExpr, DC, TypeLoc::withoutLoc(convertType),
1567+
convertTypePurpose, TCEOptions, listener, &CS);
15661568

15671569
CS.cacheExprTypes(subExpr);
15681570

@@ -1598,49 +1600,53 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
15981600
return subExpr;
15991601
}
16001602

1601-
/// This is the same as typeCheckChildIndependently, but works on an arbitrary
1602-
/// subexpression of the current node because it handles ClosureExpr parents
1603-
/// of the specified node.
1604-
Expr *FailureDiagnosis::
1605-
typeCheckArbitrarySubExprIndependently(Expr *subExpr, TCCOptions options) {
1606-
if (subExpr == expr)
1607-
return typeCheckChildIndependently(subExpr, options);
1608-
1609-
// Construct a parent map for the expr tree we're investigating.
1610-
auto parentMap = expr->getParentMap();
1611-
1612-
ClosureExpr *NearestClosure = nullptr;
1613-
1614-
// Walk the parents of the specified expression, handling any ClosureExprs.
1615-
for (Expr *node = parentMap[subExpr]; node; node = parentMap[node]) {
1616-
auto *CE = dyn_cast<ClosureExpr>(node);
1617-
if (!CE) continue;
1618-
1619-
// Keep track of the innermost closure we see that we're jumping into.
1620-
if (!NearestClosure)
1621-
NearestClosure = CE;
1622-
1623-
// If we have a ClosureExpr parent of the specified node, check to make sure
1624-
// none of its arguments are type variables. If so, these type variables
1625-
// would be accessible to name lookup of the subexpression and may thus leak
1626-
// in. Reset them to UnresolvedTypes for safe measures.
1627-
for (auto *param : *CE->getParameters()) {
1628-
if (param->hasValidSignature()) {
1629-
auto type = param->getType();
1630-
assert(!type->hasTypeVariable() && !type->hasError());
1631-
(void)type;
1603+
DeclContext *FailureDiagnosis::findDeclContext(Expr *subExpr) const {
1604+
if (auto *closure =
1605+
dyn_cast<ClosureExpr>(subExpr->getSemanticsProvidingExpr()))
1606+
return closure->getParent();
1607+
1608+
struct DCFinder : public ASTWalker {
1609+
DeclContext *DC, *CurrDC;
1610+
Expr *SubExpr;
1611+
1612+
DCFinder(DeclContext *DC, Expr *expr) : DC(DC), CurrDC(DC), SubExpr(expr) {}
1613+
1614+
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
1615+
if (E == SubExpr) {
1616+
DC = CurrDC;
1617+
return {false, nullptr};
1618+
}
1619+
1620+
if (auto *closure = dyn_cast<ClosureExpr>(E)) {
1621+
CurrDC = closure;
1622+
// If we have a ClosureExpr parent of the specified node, check to make
1623+
// sure none of its arguments are type variables. If so, these type
1624+
// variables would be accessible to name lookup of the subexpression and
1625+
// may thus leak in. Reset them to UnresolvedTypes for safe measures.
1626+
assert(llvm::all_of(*closure->getParameters(), [](const ParamDecl *PD) {
1627+
if (PD->hasValidSignature()) {
1628+
auto paramTy = PD->getType();
1629+
return !(paramTy->hasTypeVariable() || paramTy->hasError());
1630+
}
1631+
return true;
1632+
}));
1633+
}
1634+
1635+
return {true, E};
1636+
}
1637+
1638+
Expr *walkToExprPost(Expr *E) override {
1639+
if (auto *closure = dyn_cast<ClosureExpr>(E)) {
1640+
assert(CurrDC == closure && "DeclContext imbalance");
1641+
CurrDC = closure->getParent();
16321642
}
1643+
return E;
16331644
}
1634-
}
16351645

1636-
// When we're type checking a single-expression closure, we need to reset the
1637-
// DeclContext to this closure for the recursive type checking. Otherwise,
1638-
// if there is a closure in the subexpression, we can violate invariants.
1639-
auto newDC = NearestClosure ? NearestClosure : CS.DC;
1640-
llvm::SaveAndRestore<DeclContext *> SavedDC(CS.DC, newDC);
1646+
} finder(CS.DC, subExpr);
16411647

1642-
// Otherwise, we're ok to type check the subexpr.
1643-
return typeCheckChildIndependently(subExpr, options);
1648+
expr->walk(finder);
1649+
return finder.DC;
16441650
}
16451651

16461652
/// For an expression being type checked with a CTP_CalleeResult contextual
@@ -6685,8 +6691,7 @@ bool FailureDiagnosis::diagnoseMemberFailures(
66856691
NameLoc = DeclNameLoc(memberRange.Start);
66866692

66876693
// Retypecheck the anchor type, which is the base of the member expression.
6688-
baseExpr =
6689-
typeCheckArbitrarySubExprIndependently(baseExpr, TCC_AllowLValue);
6694+
baseExpr = typeCheckChildIndependently(baseExpr, TCC_AllowLValue);
66906695
if (!baseExpr)
66916696
return true;
66926697

0 commit comments

Comments
 (0)