Skip to content

Commit 684621d

Browse files
authored
Merge pull request #76193 from hamishknight/miscing-diag
[Sema] Walk patterns for syntactic diagnostics
2 parents 273f5fd + 9bd0d9b commit 684621d

File tree

7 files changed

+76
-148
lines changed

7 files changed

+76
-148
lines changed

include/swift/AST/ASTWalker.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -634,16 +634,6 @@ class ASTWalker {
634634
}
635635
}
636636

637-
/// This method configures whether the walker should visit the body of a
638-
/// closure that was checked separately from its enclosing expression.
639-
///
640-
/// For work that is performed for every top-level expression, this should
641-
/// be overridden to return false, to avoid duplicating work or visiting
642-
/// bodies of closures that have not yet been type checked.
643-
virtual bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *) {
644-
return true;
645-
}
646-
647637
/// This method configures whether the walker should visit the body of a
648638
/// TapExpr.
649639
virtual bool shouldWalkIntoTapExpression() { return true; }

lib/AST/ASTWalker.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,12 +1012,6 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
10121012
return nullptr;
10131013
}
10141014

1015-
// If the closure was separately type checked and we don't want to
1016-
// visit separately-checked closure bodies, bail out now.
1017-
if (expr->isSeparatelyTypeChecked() &&
1018-
!Walker.shouldWalkIntoSeparatelyCheckedClosure(expr))
1019-
return expr;
1020-
10211015
// Handle other closures.
10221016
if (BraceStmt *body = cast_or_null<BraceStmt>(doIt(expr->getBody()))) {
10231017
expr->setBody(body);

lib/Sema/MiscDiagnostics.cpp

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -59,32 +59,6 @@ static Expr *isImplicitPromotionToOptional(Expr *E) {
5959
return nullptr;
6060
}
6161

62-
ASTWalker::PreWalkAction BaseDiagnosticWalker::walkToDeclPre(Decl *D) {
63-
return Action::VisitNodeIf(isa<ClosureExpr>(D->getDeclContext()) &&
64-
shouldWalkIntoDeclInClosureContext(D));
65-
}
66-
67-
bool BaseDiagnosticWalker::shouldWalkIntoDeclInClosureContext(Decl *D) {
68-
auto *closure = dyn_cast<ClosureExpr>(D->getDeclContext());
69-
assert(closure);
70-
71-
if (closure->isSeparatelyTypeChecked())
72-
return false;
73-
74-
// Let's not walk into declarations contained in a multi-statement
75-
// closure because they'd be handled via `typeCheckDecl` that runs
76-
// syntactic diagnostics.
77-
if (!closure->hasSingleExpressionBody()) {
78-
// Since pattern bindings get their types through solution application,
79-
// `typeCheckDecl` doesn't touch initializers (because they are already
80-
// fully type-checked), so pattern bindings have to be allowed to be
81-
// walked to diagnose syntactic issues.
82-
return isa<PatternBindingDecl>(D);
83-
}
84-
85-
return true;
86-
}
87-
8862
/// Diagnose syntactic restrictions of expressions.
8963
///
9064
/// - Module values may only occur as part of qualification.
@@ -127,10 +101,6 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
127101
return MacroWalking::Expansion;
128102
}
129103

130-
PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) override {
131-
return Action::SkipNode(P);
132-
}
133-
134104
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
135105
return Action::Continue();
136106
}
@@ -1609,10 +1579,6 @@ static void diagRecursivePropertyAccess(const Expr *E, const DeclContext *DC) {
16091579
cast<VarDecl>(DRE->getDecl())->isSelfParameter();
16101580
}
16111581

1612-
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
1613-
return false;
1614-
}
1615-
16161582
bool shouldWalkCaptureInitializerExpressions() override { return true; }
16171583

16181584
MacroWalking getMacroWalkingBehavior() const override {
@@ -4594,10 +4560,6 @@ static void checkStmtConditionTrailingClosure(ASTContext &ctx, const Expr *E) {
45944560
public:
45954561
DiagnoseWalker(ASTContext &ctx) : Ctx(ctx) { }
45964562

4597-
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
4598-
return false;
4599-
}
4600-
46014563
bool shouldWalkCaptureInitializerExpressions() override { return true; }
46024564

46034565
MacroWalking getMacroWalkingBehavior() const override {
@@ -4723,10 +4685,6 @@ class ObjCSelectorWalker : public ASTWalker {
47234685
ObjCSelectorWalker(const DeclContext *dc, Type selectorTy)
47244686
: Ctx(dc->getASTContext()), DC(dc), SelectorTy(selectorTy) { }
47254687

4726-
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
4727-
return false;
4728-
}
4729-
47304688
bool shouldWalkCaptureInitializerExpressions() override { return true; }
47314689

47324690
MacroWalking getMacroWalkingBehavior() const override {
@@ -5589,10 +5547,6 @@ static void diagnoseUnintendedOptionalBehavior(const Expr *E,
55895547
}
55905548
}
55915549

5592-
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
5593-
return false;
5594-
}
5595-
55965550
bool shouldWalkCaptureInitializerExpressions() override { return true; }
55975551

55985552
MacroWalking getMacroWalkingBehavior() const override {
@@ -5668,10 +5622,6 @@ static void diagnoseDeprecatedWritableKeyPath(const Expr *E,
56685622
}
56695623
}
56705624

5671-
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
5672-
return false;
5673-
}
5674-
56755625
bool shouldWalkCaptureInitializerExpressions() override { return true; }
56765626

56775627
MacroWalking getMacroWalkingBehavior() const override {
@@ -5974,10 +5924,6 @@ static void diagUnqualifiedAccessToMethodNamedSelf(const Expr *E,
59745924
public:
59755925
DiagnoseWalker(const DeclContext *DC) : Ctx(DC->getASTContext()), DC(DC) {}
59765926

5977-
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
5978-
return false;
5979-
}
5980-
59815927
MacroWalking getMacroWalkingBehavior() const override {
59825928
return MacroWalking::Expansion;
59835929
}
@@ -6133,10 +6079,6 @@ diagnoseDictionaryLiteralDuplicateKeyEntries(const Expr *E,
61336079
public:
61346080
DiagnoseWalker(const DeclContext *DC) : Ctx(DC->getASTContext()) {}
61356081

6136-
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
6137-
return false;
6138-
}
6139-
61406082
MacroWalking getMacroWalkingBehavior() const override {
61416083
return MacroWalking::Expansion;
61426084
}

lib/Sema/MiscDiagnostics.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,19 +133,14 @@ namespace swift {
133133
ForEachStmt *forEach);
134134

135135
class BaseDiagnosticWalker : public ASTWalker {
136-
PreWalkAction walkToDeclPre(Decl *D) override;
137-
138-
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
139-
return false;
136+
PreWalkAction walkToDeclPre(Decl *D) override {
137+
return Action::VisitNodeIf(isa<PatternBindingDecl>(D));
140138
}
141139

142140
// Only emit diagnostics in the expansion of macros.
143141
MacroWalking getMacroWalkingBehavior() const override {
144142
return MacroWalking::Expansion;
145143
}
146-
147-
private:
148-
static bool shouldWalkIntoDeclInClosureContext(Decl *D);
149144
};
150145

151146
// A simple, deferred diagnostic container.

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3472,10 +3472,6 @@ class ExprAvailabilityWalker : public ASTWalker {
34723472
explicit ExprAvailabilityWalker(const ExportContext &Where)
34733473
: Context(Where.getDeclContext()->getASTContext()), Where(Where) {}
34743474

3475-
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
3476-
return false;
3477-
}
3478-
34793475
MacroWalking getMacroWalkingBehavior() const override {
34803476
// Expanded source should be type checked and diagnosed separately.
34813477
return MacroWalking::Arguments;

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 19 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -327,50 +327,40 @@ void ParentConditionalConformance::diagnoseConformanceStack(
327327
}
328328

329329
namespace {
330-
/// Produce any additional syntactic diagnostics for the body of a function
331-
/// that had a result builder applied.
332-
class FunctionSyntacticDiagnosticWalker : public ASTWalker {
333-
SmallVector<DeclContext *, 4> dcStack;
330+
/// Produce any additional syntactic diagnostics for a SyntacticElementTarget.
331+
class SyntacticDiagnosticWalker final : public ASTWalker {
332+
const SyntacticElementTarget &Target;
333+
bool IsTopLevelExprStmt;
334+
335+
SyntacticDiagnosticWalker(const SyntacticElementTarget &target,
336+
bool isExprStmt)
337+
: Target(target), IsTopLevelExprStmt(isExprStmt) {}
334338

335339
public:
336-
FunctionSyntacticDiagnosticWalker(DeclContext *dc) { dcStack.push_back(dc); }
340+
static void check(const SyntacticElementTarget &target, bool isExprStmt) {
341+
auto walker = SyntacticDiagnosticWalker(target, isExprStmt);
342+
target.walk(walker);
343+
}
337344

338345
MacroWalking getMacroWalkingBehavior() const override {
339346
return MacroWalking::Expansion;
340347
}
341348

342349
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
343-
performSyntacticExprDiagnostics(expr, dcStack.back(), /*isExprStmt=*/false);
344-
345-
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
346-
if (closure->isSeparatelyTypeChecked()) {
347-
dcStack.push_back(closure);
348-
return Action::Continue(expr);
349-
}
350-
}
351-
350+
auto isExprStmt = (expr == Target.getAsExpr()) ? IsTopLevelExprStmt : false;
351+
performSyntacticExprDiagnostics(expr, Target.getDeclContext(), isExprStmt);
352352
return Action::SkipNode(expr);
353353
}
354354

355-
PostWalkResult<Expr *> walkToExprPost(Expr *expr) override {
356-
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
357-
if (closure->isSeparatelyTypeChecked()) {
358-
assert(dcStack.back() == closure);
359-
dcStack.pop_back();
360-
}
361-
}
362-
363-
return Action::Continue(expr);
364-
}
365-
366355
PreWalkResult<Stmt *> walkToStmtPre(Stmt *stmt) override {
367-
performStmtDiagnostics(stmt, dcStack.back());
356+
performStmtDiagnostics(stmt, Target.getDeclContext());
368357
return Action::Continue(stmt);
369358
}
370359

371-
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pattern) override {
372-
return Action::SkipNode(pattern);
360+
PreWalkAction walkToDeclPre(Decl *D) override {
361+
return Action::VisitNodeIf(isa<PatternBindingDecl>(D));
373362
}
363+
374364
PreWalkAction walkToTypeReprPre(TypeRepr *typeRepr) override {
375365
return Action::SkipNode();
376366
}
@@ -382,41 +372,7 @@ class FunctionSyntacticDiagnosticWalker : public ASTWalker {
382372

383373
void constraints::performSyntacticDiagnosticsForTarget(
384374
const SyntacticElementTarget &target, bool isExprStmt) {
385-
auto *dc = target.getDeclContext();
386-
switch (target.kind) {
387-
case SyntacticElementTarget::Kind::expression: {
388-
// First emit diagnostics for the main expression.
389-
performSyntacticExprDiagnostics(target.getAsExpr(), dc, isExprStmt);
390-
return;
391-
}
392-
393-
case SyntacticElementTarget::Kind::forEachPreamble: {
394-
auto *stmt = target.getAsForEachStmt();
395-
396-
// First emit diagnostics for the main expression.
397-
performSyntacticExprDiagnostics(stmt->getTypeCheckedSequence(), dc,
398-
isExprStmt);
399-
400-
if (auto *whereExpr = stmt->getWhere())
401-
performSyntacticExprDiagnostics(whereExpr, dc, /*isExprStmt*/ false);
402-
return;
403-
}
404-
405-
case SyntacticElementTarget::Kind::function: {
406-
auto *body = target.getFunctionBody();
407-
FunctionSyntacticDiagnosticWalker walker(dc);
408-
body->walk(walker);
409-
return;
410-
}
411-
case SyntacticElementTarget::Kind::closure:
412-
case SyntacticElementTarget::Kind::stmtCondition:
413-
case SyntacticElementTarget::Kind::caseLabelItem:
414-
case SyntacticElementTarget::Kind::patternBinding:
415-
case SyntacticElementTarget::Kind::uninitializedVar:
416-
// Nothing to do for these.
417-
return;
418-
}
419-
llvm_unreachable("Unhandled case in switch!");
375+
SyntacticDiagnosticWalker::check(target, isExprStmt);
420376
}
421377

422378
#pragma mark High-level entry points

test/Sema/issue-75389.swift

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// https://github.com/swiftlang/swift/issues/75389
4+
5+
@available(*, unavailable)
6+
func unavailableFn() -> Int { 0 }
7+
// expected-note@-1 5{{'unavailableFn()' has been explicitly marked unavailable here}}
8+
9+
if case unavailableFn() = 0 {}
10+
// expected-error@-1 {{'unavailableFn()' is unavailable}}
11+
12+
switch Bool.random() {
13+
case true where unavailableFn() == 1:
14+
// expected-error@-1 {{'unavailableFn()' is unavailable}}
15+
break
16+
default:
17+
break
18+
}
19+
switch 0 {
20+
case unavailableFn():
21+
// expected-error@-1 {{'unavailableFn()' is unavailable}}
22+
break
23+
default:
24+
break
25+
}
26+
let _ = {
27+
switch Bool.random() {
28+
case true where unavailableFn() == 1:
29+
// expected-error@-1 {{'unavailableFn()' is unavailable}}
30+
break
31+
default:
32+
break
33+
}
34+
switch 0 {
35+
case unavailableFn():
36+
// expected-error@-1 {{'unavailableFn()' is unavailable}}
37+
break
38+
default:
39+
break
40+
}
41+
}
42+
43+
struct S {}
44+
45+
func ~= (lhs: S.Type, rhs: S.Type) -> Bool { true }
46+
47+
if case (S) = S.self {}
48+
// expected-error@-1 {{expected member name or initializer call after type name}}
49+
// expected-note@-2 {{add arguments after the type to construct a value of the type}}
50+
// expected-note@-3 {{use '.self' to reference the type object}}
51+
52+
if case ({ if case (S) = S.self { true } else { false } }()) = true {}
53+
// expected-error@-1 {{expected member name or initializer call after type name}}
54+
// expected-note@-2 {{add arguments after the type to construct a value of the type}}
55+
// expected-note@-3 {{use '.self' to reference the type object}}

0 commit comments

Comments
 (0)