Skip to content

Commit 0974006

Browse files
authored
Merge pull request #25567 from xedin/rdar-50869732-5.1
[5.1][CSDiag] Always find and set correct declaration context for sub-expr type-check
2 parents 979cc66 + a6fec42 commit 0974006

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
@@ -408,11 +408,9 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
408408
return e ? CS.getType(e) : Type();
409409
}
410410

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

417415
/// Special magic to handle inout exprs and tuples in argument lists.
418416
Expr *typeCheckArgumentChildIndependently(Expr *argExpr, Type argType,
@@ -1150,8 +1148,8 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
11501148
// constraint.
11511149
if (CS.getContextualTypePurpose() != CTP_Unused)
11521150
options |= TCC_ForceRecheck;
1153-
1154-
auto sub = typeCheckArbitrarySubExprIndependently(anchor, options);
1151+
1152+
auto sub = typeCheckChildIndependently(anchor, options);
11551153
if (!sub) return true;
11561154
fromType = CS.getType(sub);
11571155
}
@@ -1624,10 +1622,14 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
16241622
if ((!convertType || options.contains(TCC_AllowUnresolvedTypeVariables)) &&
16251623
allowFreeTypeVariables)
16261624
TCEOptions |= TypeCheckExprFlags::AllowUnresolvedTypeVariables;
1627-
1628-
auto resultTy = CS.TC.typeCheckExpression(
1629-
subExpr, CS.DC, TypeLoc::withoutLoc(convertType), convertTypePurpose,
1630-
TCEOptions, listener, &CS);
1625+
1626+
// When we're type checking a single-expression closure, we need to reset the
1627+
// DeclContext to this closure for the recursive type checking. Otherwise,
1628+
// if there is a closure in the subexpression, we can violate invariants.
1629+
auto *DC = findDeclContext(subExpr);
1630+
auto resultTy =
1631+
CS.TC.typeCheckExpression(subExpr, DC, TypeLoc::withoutLoc(convertType),
1632+
convertTypePurpose, TCEOptions, listener, &CS);
16311633

16321634
CS.cacheExprTypes(subExpr);
16331635

@@ -1663,49 +1665,53 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
16631665
return subExpr;
16641666
}
16651667

1666-
/// This is the same as typeCheckChildIndependently, but works on an arbitrary
1667-
/// subexpression of the current node because it handles ClosureExpr parents
1668-
/// of the specified node.
1669-
Expr *FailureDiagnosis::
1670-
typeCheckArbitrarySubExprIndependently(Expr *subExpr, TCCOptions options) {
1671-
if (subExpr == expr)
1672-
return typeCheckChildIndependently(subExpr, options);
1673-
1674-
// Construct a parent map for the expr tree we're investigating.
1675-
auto parentMap = expr->getParentMap();
1676-
1677-
ClosureExpr *NearestClosure = nullptr;
1678-
1679-
// Walk the parents of the specified expression, handling any ClosureExprs.
1680-
for (Expr *node = parentMap[subExpr]; node; node = parentMap[node]) {
1681-
auto *CE = dyn_cast<ClosureExpr>(node);
1682-
if (!CE) continue;
1683-
1684-
// Keep track of the innermost closure we see that we're jumping into.
1685-
if (!NearestClosure)
1686-
NearestClosure = CE;
1687-
1688-
// If we have a ClosureExpr parent of the specified node, check to make sure
1689-
// none of its arguments are type variables. If so, these type variables
1690-
// would be accessible to name lookup of the subexpression and may thus leak
1691-
// in. Reset them to UnresolvedTypes for safe measures.
1692-
for (auto *param : *CE->getParameters()) {
1693-
if (param->hasValidSignature()) {
1694-
auto type = param->getType();
1695-
assert(!type->hasTypeVariable() && !type->hasError());
1696-
(void)type;
1668+
DeclContext *FailureDiagnosis::findDeclContext(Expr *subExpr) const {
1669+
if (auto *closure =
1670+
dyn_cast<ClosureExpr>(subExpr->getSemanticsProvidingExpr()))
1671+
return closure->getParent();
1672+
1673+
struct DCFinder : public ASTWalker {
1674+
DeclContext *DC, *CurrDC;
1675+
Expr *SubExpr;
1676+
1677+
DCFinder(DeclContext *DC, Expr *expr) : DC(DC), CurrDC(DC), SubExpr(expr) {}
1678+
1679+
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
1680+
if (E == SubExpr) {
1681+
DC = CurrDC;
1682+
return {false, nullptr};
1683+
}
1684+
1685+
if (auto *closure = dyn_cast<ClosureExpr>(E)) {
1686+
CurrDC = closure;
1687+
// If we have a ClosureExpr parent of the specified node, check to make
1688+
// sure none of its arguments are type variables. If so, these type
1689+
// variables would be accessible to name lookup of the subexpression and
1690+
// may thus leak in. Reset them to UnresolvedTypes for safe measures.
1691+
assert(llvm::all_of(*closure->getParameters(), [](const ParamDecl *PD) {
1692+
if (PD->hasValidSignature()) {
1693+
auto paramTy = PD->getType();
1694+
return !(paramTy->hasTypeVariable() || paramTy->hasError());
1695+
}
1696+
return true;
1697+
}));
1698+
}
1699+
1700+
return {true, E};
1701+
}
1702+
1703+
Expr *walkToExprPost(Expr *E) override {
1704+
if (auto *closure = dyn_cast<ClosureExpr>(E)) {
1705+
assert(CurrDC == closure && "DeclContext imbalance");
1706+
CurrDC = closure->getParent();
16971707
}
1708+
return E;
16981709
}
1699-
}
17001710

1701-
// When we're type checking a single-expression closure, we need to reset the
1702-
// DeclContext to this closure for the recursive type checking. Otherwise,
1703-
// if there is a closure in the subexpression, we can violate invariants.
1704-
auto newDC = NearestClosure ? NearestClosure : CS.DC;
1705-
llvm::SaveAndRestore<DeclContext *> SavedDC(CS.DC, newDC);
1711+
} finder(CS.DC, subExpr);
17061712

1707-
// Otherwise, we're ok to type check the subexpr.
1708-
return typeCheckChildIndependently(subExpr, options);
1713+
expr->walk(finder);
1714+
return finder.DC;
17091715
}
17101716

17111717
/// For an expression being type checked with a CTP_CalleeResult contextual
@@ -6723,8 +6729,7 @@ bool FailureDiagnosis::diagnoseMemberFailures(
67236729
NameLoc = DeclNameLoc(memberRange.Start);
67246730

67256731
// Retypecheck the anchor type, which is the base of the member expression.
6726-
baseExpr =
6727-
typeCheckArbitrarySubExprIndependently(baseExpr, TCC_AllowLValue);
6732+
baseExpr = typeCheckChildIndependently(baseExpr, TCC_AllowLValue);
67286733
if (!baseExpr)
67296734
return true;
67306735

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)