Skip to content

Commit 3feeeac

Browse files
committed
[Sema] Fold SequenceExpr in pre-checking pre-walk
Doing it in the post-walk meant we ended up walking the children twice, which lead to duplicate diagnostics and incorrect inference of the level of application for function references. Move it to the pre-walk, ensuring that we resolve any operator references before folding.
1 parent a2b4ce8 commit 3feeeac

File tree

5 files changed

+36
-31
lines changed

5 files changed

+36
-31
lines changed

lib/Sema/PreCheckExpr.cpp

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,9 +1056,6 @@ namespace {
10561056
/// Keep track of acceptable DiscardAssignmentExpr's.
10571057
llvm::SmallPtrSet<DiscardAssignmentExpr*, 2> CorrectDiscardAssignmentExprs;
10581058

1059-
/// The current number of nested \c SequenceExprs that we're within.
1060-
unsigned SequenceExprDepth = 0;
1061-
10621059
/// The current number of nested \c SingleValueStmtExprs that we're within.
10631060
unsigned SingleValueStmtExprDepth = 0;
10641061

@@ -1127,6 +1124,16 @@ namespace {
11271124
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
11281125
auto &diags = Ctx.Diags;
11291126

1127+
// Fold sequence expressions.
1128+
if (auto *seqExpr = dyn_cast<SequenceExpr>(expr)) {
1129+
auto result = TypeChecker::foldSequence(seqExpr, DC);
1130+
result = result->walk(*this);
1131+
if (!result)
1132+
return Action::Stop();
1133+
// Already walked.
1134+
return Action::SkipNode(result);
1135+
}
1136+
11301137
// FIXME(diagnostics): `InOutType` could appear here as a result
11311138
// of successful re-typecheck of the one of the sub-expressions e.g.
11321139
// `let _: Int = { (s: inout S) in s.bar() }`. On the first
@@ -1158,11 +1165,9 @@ namespace {
11581165
return Action::Stop();
11591166

11601167
// If we're going to recurse, record this expression on the stack.
1161-
if (recursive) {
1162-
if (isa<SequenceExpr>(expr))
1163-
SequenceExprDepth++;
1168+
if (recursive)
11641169
ExprStack.push_back(expr);
1165-
}
1170+
11661171
return Action::VisitNodeIf(recursive, expr);
11671172
};
11681173

@@ -1237,10 +1242,6 @@ namespace {
12371242
auto result = parents.find(expr);
12381243
if (result != parents.end()) {
12391244
auto *parent = result->getSecond();
1240-
1241-
if (isa<SequenceExpr>(parent))
1242-
return finish(true, expr);
1243-
12441245
SourceLoc lastInnerParenLoc;
12451246
// Unwrap to the outermost paren in the sequence.
12461247
// e.g. `foo(((&bar))`
@@ -1292,17 +1293,6 @@ namespace {
12921293
assert(ExprStack.back() == expr);
12931294
ExprStack.pop_back();
12941295

1295-
// Fold sequence expressions.
1296-
if (auto *seqExpr = dyn_cast<SequenceExpr>(expr)) {
1297-
auto result = TypeChecker::foldSequence(seqExpr, DC);
1298-
SequenceExprDepth--;
1299-
result = result->walk(*this);
1300-
if (!result)
1301-
return Action::Stop();
1302-
1303-
return Action::Continue(result);
1304-
}
1305-
13061296
// Type check the type parameters in an UnresolvedSpecializeExpr.
13071297
if (auto *us = dyn_cast<UnresolvedSpecializeExpr>(expr)) {
13081298
if (auto *typeExpr = simplifyUnresolvedSpecializeExpr(us))
@@ -1426,12 +1416,9 @@ namespace {
14261416
return Action::Continue(simplified);
14271417

14281418
// Diagnose a '_' that isn't on the immediate LHS of an assignment. We
1429-
// skip diagnostics if we've explicitly marked the expression as valid,
1430-
// or if we're inside a SequenceExpr (since the whole tree will be
1431-
// re-checked when we finish folding anyway).
1419+
// skip diagnostics if we've explicitly marked the expression as valid.
14321420
if (auto *DAE = dyn_cast<DiscardAssignmentExpr>(expr)) {
1433-
if (!CorrectDiscardAssignmentExprs.count(DAE) &&
1434-
SequenceExprDepth == 0) {
1421+
if (!CorrectDiscardAssignmentExprs.count(DAE)) {
14351422
ctx.Diags.diagnose(expr->getLoc(),
14361423
diag::discard_expr_outside_of_assignment);
14371424
return Action::Stop();
@@ -1688,7 +1675,7 @@ bool PreCheckExpression::possiblyInTypeContext(Expr *E) {
16881675
/// been explicitly marked as correct, and the current AST state allows it.
16891676
bool PreCheckExpression::canSimplifyDiscardAssignmentExpr(
16901677
DiscardAssignmentExpr *DAE) {
1691-
return !CorrectDiscardAssignmentExprs.count(DAE) && SequenceExprDepth == 0 &&
1678+
return !CorrectDiscardAssignmentExprs.count(DAE) &&
16921679
possiblyInTypeContext(DAE);
16931680
}
16941681

lib/Sema/TypeCheckExpr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,15 @@ swift::DefaultTypeRequest::evaluate(Evaluator &evaluator,
631631
}
632632

633633
Expr *TypeChecker::foldSequence(SequenceExpr *expr, DeclContext *dc) {
634+
// First resolve any unresolved decl references in operator positions.
635+
for (auto i : indices(expr->getElements())) {
636+
if (i % 2 == 0)
637+
continue;
638+
auto *elt = expr->getElement(i);
639+
if (auto *UDRE = dyn_cast<UnresolvedDeclRefExpr>(elt))
640+
elt = TypeChecker::resolveDeclRefExpr(UDRE, dc);
641+
expr->setElement(i, elt);
642+
}
634643
ArrayRef<Expr*> Elts = expr->getElements();
635644
assert(Elts.size() > 1 && "inadequate number of elements in sequence");
636645
assert((Elts.size() & 1) == 1 && "even number of elements in sequence");

test/Constraints/argument_matching.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,3 +1810,14 @@ func test_extraneous_argument_with_inout() {
18101810
var x: Int = 0
18111811
test(42, &x) // expected-error {{extra argument in call}}
18121812
}
1813+
1814+
// https://github.com/swiftlang/swift/issues/75527
1815+
struct Issue75527 {
1816+
func foo(x: Int) {}
1817+
1818+
func bar() {
1819+
typealias Magic<T> = T
1820+
let fn = Issue75527.foo(self) as Magic
1821+
fn(0) // Make sure the argument label does not escape here.
1822+
}
1823+
}

test/StringProcessing/Parse/forward-slash-regex.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ do {
5252
_=/0/
5353
// expected-error@-1 {{'_' can only appear in a pattern or on the left side of an assignment}}
5454
// expected-error@-2 {{cannot find operator '=/' in scope}}
55-
// expected-error@-3 {{'/' is not a postfix unary operator}}
5655
}
5756

5857
// No closing '/' so a prefix operator.

test/expr/primary/super/unsupported.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ class Derived: Base {
4242
// expected-error@+1 {{'super' may be used only to access a superclass member, subscript, or initializer}}
4343
let _ = self[super]
4444

45-
// FIXME: Duplicate diagnostic because expression is re-pre-checked after folding initial sequence expression.
46-
// expected-error@+1 2 {{'super' may be used only to access a superclass member, subscript, or initializer}}
45+
// expected-error@+1 {{'super' may be used only to access a superclass member, subscript, or initializer}}
4746
_ = (0, super)
4847

4948
func nested() {

0 commit comments

Comments
 (0)