Skip to content

Commit 00ac57b

Browse files
committed
[CSClosure] Mark partially inferred external declarations as invalid
If a syntactic element references an external declaration (relative to its own context), let's check whether it has any type variables, and if so, replace them with errors to remove any possibility of bringing external constraints into element's scope. Resolves: rdar://92347054 (cherry picked from commit 67895c2)
1 parent 4fe77b0 commit 00ac57b

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

lib/Sema/CSClosure.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,32 @@ class TypeVariableRefFinder : public ASTWalker {
5050

5151
std::pair<bool, Expr *> walkToExprPre(Expr *expr) override {
5252
if (auto *DRE = dyn_cast<DeclRefExpr>(expr)) {
53-
if (auto type = CS.getTypeIfAvailable(DRE->getDecl()))
53+
auto *decl = DRE->getDecl();
54+
55+
if (auto type = CS.getTypeIfAvailable(DRE->getDecl())) {
56+
// If this is not one of the closure parameters which
57+
// is inferrable from the body, let's replace type
58+
// variables with errors to avoid bringing external
59+
// information to the element component.
60+
if (type->hasTypeVariable() && !isa<ParamDecl>(decl)) {
61+
// If there are type variables left in the simplified version,
62+
// it means that this is an invalid external declaration
63+
// relative to this element's context.
64+
if (CS.simplifyType(type)->hasTypeVariable()) {
65+
auto transformedTy = type.transform([&](Type type) {
66+
if (auto *typeVar = type->getAs<TypeVariableType>()) {
67+
return ErrorType::get(CS.getASTContext());
68+
}
69+
return type;
70+
});
71+
72+
CS.setType(decl, transformedTy);
73+
return {true, expr};
74+
}
75+
}
76+
5477
inferVariables(type);
78+
}
5579
}
5680

5781
return {true, expr};

test/expr/closure/multi_statement.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,3 +329,24 @@ func test_unknown_refs_in_tilde_operator() {
329329
}
330330
}
331331
}
332+
333+
// rdar://92347054 - crash during conjunction processing
334+
func test_no_crash_with_circular_ref_due_to_error() {
335+
struct S { // expected-note {{did you mean 'S'?}}
336+
var x: Int?
337+
}
338+
339+
func test(v: Int?, arr: [S]) -> Int { // expected-note {{did you mean 'v'?}}
340+
// There is missing `f` here which made body of the
341+
// `if` a multiple statement closure instead that uses
342+
// `next` inside.
343+
i let x = v, let next = arr.first?.x { // expected-error {{cannot find 'i' in scope}}
344+
// expected-error@-1 {{consecutive statements on a line must be separated by ';'}}
345+
// expected-error@-2 {{'let' cannot appear nested inside another 'var' or 'let' pattern}}
346+
// expected-error@-3 {{cannot call value of non-function type 'Int?'}}
347+
print(next)
348+
return x
349+
}
350+
return 0
351+
}
352+
}

0 commit comments

Comments
 (0)