Skip to content

Commit cbeb4bf

Browse files
committed
[Sema] Walk patterns for syntactic diagnostics
Use `SyntacticElementTarget::walk`, ensuring we walk to any ExprPatterns.
1 parent 614e8aa commit cbeb4bf

File tree

3 files changed

+75
-46
lines changed

3 files changed

+75
-46
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,6 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
127127
return MacroWalking::Expansion;
128128
}
129129

130-
PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) override {
131-
return Action::SkipNode(P);
132-
}
133-
134130
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
135131
return Action::Continue();
136132
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -327,20 +327,31 @@ 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 {
330+
/// Produce any additional syntactic diagnostics for a SyntacticElementTarget.
331+
class SyntacticDiagnosticWalker final : public ASTWalker {
333332
SmallVector<DeclContext *, 4> dcStack;
333+
const SyntacticElementTarget &Target;
334+
bool IsTopLevelExprStmt;
335+
336+
SyntacticDiagnosticWalker(const SyntacticElementTarget &target,
337+
bool isExprStmt)
338+
: Target(target), IsTopLevelExprStmt(isExprStmt) {
339+
dcStack.push_back(target.getDeclContext());
340+
}
334341

335342
public:
336-
FunctionSyntacticDiagnosticWalker(DeclContext *dc) { dcStack.push_back(dc); }
343+
static void check(const SyntacticElementTarget &target, bool isExprStmt) {
344+
auto walker = SyntacticDiagnosticWalker(target, isExprStmt);
345+
target.walk(walker);
346+
}
337347

338348
MacroWalking getMacroWalkingBehavior() const override {
339349
return MacroWalking::Expansion;
340350
}
341351

342352
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
343-
performSyntacticExprDiagnostics(expr, dcStack.back(), /*isExprStmt=*/false);
353+
auto isExprStmt = (expr == Target.getAsExpr()) ? IsTopLevelExprStmt : false;
354+
performSyntacticExprDiagnostics(expr, dcStack.back(), isExprStmt);
344355

345356
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
346357
if (closure->isSeparatelyTypeChecked()) {
@@ -368,9 +379,10 @@ class FunctionSyntacticDiagnosticWalker : public ASTWalker {
368379
return Action::Continue(stmt);
369380
}
370381

371-
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pattern) override {
372-
return Action::SkipNode(pattern);
382+
PreWalkAction walkToDeclPre(Decl *D) override {
383+
return Action::VisitNodeIf(isa<PatternBindingDecl>(D));
373384
}
385+
374386
PreWalkAction walkToTypeReprPre(TypeRepr *typeRepr) override {
375387
return Action::SkipNode();
376388
}
@@ -382,41 +394,7 @@ class FunctionSyntacticDiagnosticWalker : public ASTWalker {
382394

383395
void constraints::performSyntacticDiagnosticsForTarget(
384396
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!");
397+
SyntacticDiagnosticWalker::check(target, isExprStmt);
420398
}
421399

422400
#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)