Skip to content

Commit ef293a5

Browse files
authored
Merge pull request swiftlang#25443 from xedin/rdar-50869732
[CSDiag] Always find and set correct declaration context for sub-expr…
2 parents 62b5d64 + 4fdc9ff commit ef293a5

File tree

2 files changed

+91
-52
lines changed

2 files changed

+91
-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
}
@@ -1542,10 +1540,14 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
15421540
if ((!convertType || options.contains(TCC_AllowUnresolvedTypeVariables)) &&
15431541
allowFreeTypeVariables)
15441542
TCEOptions |= TypeCheckExprFlags::AllowUnresolvedTypeVariables;
1545-
1546-
auto resultTy = CS.TC.typeCheckExpression(
1547-
subExpr, CS.DC, TypeLoc::withoutLoc(convertType), convertTypePurpose,
1548-
TCEOptions, listener, &CS);
1543+
1544+
// When we're type checking a single-expression closure, we need to reset the
1545+
// DeclContext to this closure for the recursive type checking. Otherwise,
1546+
// if there is a closure in the subexpression, we can violate invariants.
1547+
auto *DC = findDeclContext(subExpr);
1548+
auto resultTy =
1549+
CS.TC.typeCheckExpression(subExpr, DC, TypeLoc::withoutLoc(convertType),
1550+
convertTypePurpose, TCEOptions, listener, &CS);
15491551

15501552
CS.cacheExprTypes(subExpr);
15511553

@@ -1581,49 +1583,53 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
15811583
return subExpr;
15821584
}
15831585

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

1619-
// When we're type checking a single-expression closure, we need to reset the
1620-
// DeclContext to this closure for the recursive type checking. Otherwise,
1621-
// if there is a closure in the subexpression, we can violate invariants.
1622-
auto newDC = NearestClosure ? NearestClosure : CS.DC;
1623-
llvm::SaveAndRestore<DeclContext *> SavedDC(CS.DC, newDC);
1629+
} finder(CS.DC, subExpr);
16241630

1625-
// Otherwise, we're ok to type check the subexpr.
1626-
return typeCheckChildIndependently(subExpr, options);
1631+
expr->walk(finder);
1632+
return finder.DC;
16271633
}
16281634

16291635
/// For an expression being type checked with a CTP_CalleeResult contextual
@@ -6668,8 +6674,7 @@ bool FailureDiagnosis::diagnoseMemberFailures(
66686674
NameLoc = DeclNameLoc(memberRange.Start);
66696675

66706676
// Retypecheck the anchor type, which is the base of the member expression.
6671-
baseExpr =
6672-
typeCheckArbitrarySubExprIndependently(baseExpr, TCC_AllowLValue);
6677+
baseExpr = typeCheckChildIndependently(baseExpr, TCC_AllowLValue);
66736678
if (!baseExpr)
66746679
return true;
66756680

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol P {
4+
associatedtype T : P
5+
}
6+
7+
struct Generic<T> {
8+
init(_ value: T) {}
9+
}
10+
11+
@_functionBuilder
12+
struct Builder {
13+
static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1)
14+
-> Generic<(C0, C1)> where C0 : P, C1 : P {
15+
return Generic((c0, c1))
16+
}
17+
}
18+
19+
struct G<C> {
20+
init(@Builder _: () -> C) {}
21+
}
22+
23+
struct Empty {
24+
init() {}
25+
}
26+
27+
struct Test<T> where T : P {
28+
init(@Builder _: () -> T) {}
29+
}
30+
31+
let x = G {
32+
Empty()
33+
Test { <#code#> } // expected-error {{editor placeholder in source file}}
34+
}

0 commit comments

Comments
 (0)