Skip to content

Commit f9411ca

Browse files
committed
---
yaml --- r: 348149 b: refs/heads/master c: 23da09f h: refs/heads/master i: 348147: f03eab2
1 parent 75320b8 commit f9411ca

File tree

5 files changed

+201
-83
lines changed

5 files changed

+201
-83
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: db2d388117d42e8e4797bae6527ac346bbdd17a9
2+
refs/heads/master: 23da09fc1bb10e9599defa20a5b60389c286a946
33
refs/heads/master-next: 203b3026584ecad859eb328b2e12490099409cd5
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea

trunk/lib/Sema/CSApply.cpp

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7413,44 +7413,78 @@ Expr *ConstraintSystem::coerceToRValue(Expr *expr) {
74137413
/// Emit the fixes computed as part of the solution, returning true if we were
74147414
/// able to emit an error message, or false if none of the fixits worked out.
74157415
bool ConstraintSystem::applySolutionFixes(Expr *E, const Solution &solution) {
7416-
llvm::SmallDenseMap<Expr *, SmallVector<const ConstraintFix *, 4>>
7417-
fixesPerExpr;
7418-
7416+
// First transfer all of the deduced information back
7417+
// to the constraint system.
74197418
applySolution(solution);
74207419

7421-
for (auto *fix : solution.Fixes)
7422-
fixesPerExpr[fix->getAnchor()].push_back(fix);
7420+
class DiagnosticWalker : public ASTWalker {
7421+
Expr *root;
7422+
const Solution &solution;
7423+
llvm::SmallDenseMap<Expr *, SmallVector<ConstraintFix *, 4>> fixesPerExpr;
74237424

7424-
auto diagnoseExprFailures = [&](Expr *expr) -> bool {
7425-
auto fixes = fixesPerExpr.find(expr);
7426-
if (fixes == fixesPerExpr.end())
7427-
return false;
7425+
/// Determines whether any error have been diagnosed while
7426+
/// trying to apply fixes associated with a given solution.
7427+
bool DiagnosedAnyErrors = false;
7428+
7429+
public:
7430+
DiagnosticWalker(Expr *expr, const Solution &solution)
7431+
: root(expr), solution(solution) {
7432+
for (auto *fix : solution.Fixes)
7433+
fixesPerExpr[fix->getAnchor()].push_back(fix);
7434+
}
7435+
7436+
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
7437+
// Diagnose root expression last.
7438+
if (E == root)
7439+
return {true, E};
7440+
7441+
if (auto *closure = dyn_cast<ClosureExpr>(E)) {
7442+
auto result = solution.builderTransformedClosures.find(closure);
7443+
if (result != solution.builderTransformedClosures.end()) {
7444+
auto *transformedExpr = result->second.second;
7445+
// Since this closure has been transformed into something
7446+
// else let's look inside transformed expression instead.
7447+
return {true, transformedExpr};
7448+
}
7449+
}
74287450

7429-
bool diagnosedError = false;
7430-
for (const auto *fix : fixes->second) {
7431-
auto diagnosed = fix->diagnose(E);
7451+
diagnose(E);
7452+
return {true, E};
7453+
}
74327454

7433-
if (fix->isWarning()) {
7434-
assert(diagnosed && "warnings should always be diagnosed");
7435-
(void)diagnosed;
7436-
} else {
7437-
diagnosedError |= diagnosed;
7455+
Expr *walkToExprPost(Expr *E) override {
7456+
if (E == root)
7457+
diagnose(E);
7458+
return E;
7459+
}
7460+
7461+
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
7462+
return {true, S};
7463+
}
7464+
7465+
bool hadErrors() const { return DiagnosedAnyErrors; }
7466+
7467+
private:
7468+
void diagnose(Expr *E) {
7469+
auto fixes = fixesPerExpr.find(E);
7470+
if (fixes == fixesPerExpr.end())
7471+
return;
7472+
7473+
for (const auto *fix : fixes->second) {
7474+
auto diagnosed = fix->diagnose(root);
7475+
if (fix->isWarning()) {
7476+
assert(diagnosed && "warnings should always be diagnosed");
7477+
(void)diagnosed;
7478+
} else {
7479+
DiagnosedAnyErrors |= diagnosed;
7480+
}
74387481
}
74397482
}
7440-
return diagnosedError;
74417483
};
74427484

7443-
bool diagnosedError = false;
7444-
E->forEachChildExpr([&](Expr *subExpr) -> Expr * {
7445-
// Diagnose root expression at the end to
7446-
// preserve ordering.
7447-
if (subExpr != E)
7448-
diagnosedError |= diagnoseExprFailures(subExpr);
7449-
return subExpr;
7450-
});
7451-
7452-
diagnosedError |= diagnoseExprFailures(E);
7453-
return diagnosedError;
7485+
DiagnosticWalker diagnostics(E, solution);
7486+
E->walk(diagnostics);
7487+
return diagnostics.hadErrors();
74547488
}
74557489

74567490
/// Apply a given solution to the expression, producing a fully

trunk/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

trunk/test/Constraints/function_builder_diags.swift

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-opaque-result-types
22

33
@_functionBuilder
44
struct TupleBuilder { // expected-note 2{{struct 'TupleBuilder' declared here}}
@@ -126,3 +126,48 @@ func testOverloading(name: String) {
126126
}
127127
}
128128
}
129+
130+
protocol P {
131+
associatedtype T
132+
}
133+
134+
struct AnyP : P {
135+
typealias T = Any
136+
init<T>(_: T) where T : P {}
137+
}
138+
139+
struct TupleP<U> : P {
140+
typealias T = U
141+
init(_: U) {}
142+
}
143+
144+
@_functionBuilder
145+
struct Builder {
146+
static func buildBlock<S0, S1>(_ stmt1: S0, _ stmt2: S1) // expected-note {{where 'S1' = 'Label<Any>.Type'}}
147+
-> TupleP<(S0, S1)> where S0: P, S1: P {
148+
return TupleP((stmt1, stmt2))
149+
}
150+
}
151+
152+
struct G<C> : P where C : P {
153+
typealias T = C
154+
init(@Builder _: () -> C) {}
155+
}
156+
157+
struct Text : P {
158+
typealias T = String
159+
init(_: T) {}
160+
}
161+
162+
struct Label<L> : P where L : P { // expected-note {{'L' declared as parameter to type 'Label'}}
163+
typealias T = L
164+
init(@Builder _: () -> L) {}
165+
}
166+
167+
func test_51167632() -> some P {
168+
AnyP(G { // expected-error {{static method 'buildBlock' requires that 'Label<Any>.Type' conform to 'P'}}
169+
Text("hello")
170+
Label // expected-error {{generic parameter 'L' could not be inferred}}
171+
// expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} {{10-10=<<#L: P#>>}}
172+
})
173+
}
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)