mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Sema] Walk patterns for syntactic diagnostics
Use `SyntacticElementTarget::walk`, ensuring we walk to any ExprPatterns.
This commit is contained in:
@@ -127,10 +127,6 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
|
||||
return MacroWalking::Expansion;
|
||||
}
|
||||
|
||||
PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) override {
|
||||
return Action::SkipNode(P);
|
||||
}
|
||||
|
||||
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
|
||||
return Action::Continue();
|
||||
}
|
||||
|
||||
@@ -327,20 +327,31 @@ void ParentConditionalConformance::diagnoseConformanceStack(
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Produce any additional syntactic diagnostics for the body of a function
|
||||
/// that had a result builder applied.
|
||||
class FunctionSyntacticDiagnosticWalker : public ASTWalker {
|
||||
/// Produce any additional syntactic diagnostics for a SyntacticElementTarget.
|
||||
class SyntacticDiagnosticWalker final : public ASTWalker {
|
||||
SmallVector<DeclContext *, 4> dcStack;
|
||||
const SyntacticElementTarget &Target;
|
||||
bool IsTopLevelExprStmt;
|
||||
|
||||
SyntacticDiagnosticWalker(const SyntacticElementTarget &target,
|
||||
bool isExprStmt)
|
||||
: Target(target), IsTopLevelExprStmt(isExprStmt) {
|
||||
dcStack.push_back(target.getDeclContext());
|
||||
}
|
||||
|
||||
public:
|
||||
FunctionSyntacticDiagnosticWalker(DeclContext *dc) { dcStack.push_back(dc); }
|
||||
static void check(const SyntacticElementTarget &target, bool isExprStmt) {
|
||||
auto walker = SyntacticDiagnosticWalker(target, isExprStmt);
|
||||
target.walk(walker);
|
||||
}
|
||||
|
||||
MacroWalking getMacroWalkingBehavior() const override {
|
||||
return MacroWalking::Expansion;
|
||||
}
|
||||
|
||||
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
|
||||
performSyntacticExprDiagnostics(expr, dcStack.back(), /*isExprStmt=*/false);
|
||||
auto isExprStmt = (expr == Target.getAsExpr()) ? IsTopLevelExprStmt : false;
|
||||
performSyntacticExprDiagnostics(expr, dcStack.back(), isExprStmt);
|
||||
|
||||
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
|
||||
if (closure->isSeparatelyTypeChecked()) {
|
||||
@@ -368,9 +379,10 @@ public:
|
||||
return Action::Continue(stmt);
|
||||
}
|
||||
|
||||
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pattern) override {
|
||||
return Action::SkipNode(pattern);
|
||||
PreWalkAction walkToDeclPre(Decl *D) override {
|
||||
return Action::VisitNodeIf(isa<PatternBindingDecl>(D));
|
||||
}
|
||||
|
||||
PreWalkAction walkToTypeReprPre(TypeRepr *typeRepr) override {
|
||||
return Action::SkipNode();
|
||||
}
|
||||
@@ -382,41 +394,7 @@ public:
|
||||
|
||||
void constraints::performSyntacticDiagnosticsForTarget(
|
||||
const SyntacticElementTarget &target, bool isExprStmt) {
|
||||
auto *dc = target.getDeclContext();
|
||||
switch (target.kind) {
|
||||
case SyntacticElementTarget::Kind::expression: {
|
||||
// First emit diagnostics for the main expression.
|
||||
performSyntacticExprDiagnostics(target.getAsExpr(), dc, isExprStmt);
|
||||
return;
|
||||
}
|
||||
|
||||
case SyntacticElementTarget::Kind::forEachPreamble: {
|
||||
auto *stmt = target.getAsForEachStmt();
|
||||
|
||||
// First emit diagnostics for the main expression.
|
||||
performSyntacticExprDiagnostics(stmt->getTypeCheckedSequence(), dc,
|
||||
isExprStmt);
|
||||
|
||||
if (auto *whereExpr = stmt->getWhere())
|
||||
performSyntacticExprDiagnostics(whereExpr, dc, /*isExprStmt*/ false);
|
||||
return;
|
||||
}
|
||||
|
||||
case SyntacticElementTarget::Kind::function: {
|
||||
auto *body = target.getFunctionBody();
|
||||
FunctionSyntacticDiagnosticWalker walker(dc);
|
||||
body->walk(walker);
|
||||
return;
|
||||
}
|
||||
case SyntacticElementTarget::Kind::closure:
|
||||
case SyntacticElementTarget::Kind::stmtCondition:
|
||||
case SyntacticElementTarget::Kind::caseLabelItem:
|
||||
case SyntacticElementTarget::Kind::patternBinding:
|
||||
case SyntacticElementTarget::Kind::uninitializedVar:
|
||||
// Nothing to do for these.
|
||||
return;
|
||||
}
|
||||
llvm_unreachable("Unhandled case in switch!");
|
||||
SyntacticDiagnosticWalker::check(target, isExprStmt);
|
||||
}
|
||||
|
||||
#pragma mark High-level entry points
|
||||
|
||||
55
test/Sema/issue-75389.swift
Normal file
55
test/Sema/issue-75389.swift
Normal file
@@ -0,0 +1,55 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
// https://github.com/swiftlang/swift/issues/75389
|
||||
|
||||
@available(*, unavailable)
|
||||
func unavailableFn() -> Int { 0 }
|
||||
// expected-note@-1 5{{'unavailableFn()' has been explicitly marked unavailable here}}
|
||||
|
||||
if case unavailableFn() = 0 {}
|
||||
// expected-error@-1 {{'unavailableFn()' is unavailable}}
|
||||
|
||||
switch Bool.random() {
|
||||
case true where unavailableFn() == 1:
|
||||
// expected-error@-1 {{'unavailableFn()' is unavailable}}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
switch 0 {
|
||||
case unavailableFn():
|
||||
// expected-error@-1 {{'unavailableFn()' is unavailable}}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
let _ = {
|
||||
switch Bool.random() {
|
||||
case true where unavailableFn() == 1:
|
||||
// expected-error@-1 {{'unavailableFn()' is unavailable}}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
switch 0 {
|
||||
case unavailableFn():
|
||||
// expected-error@-1 {{'unavailableFn()' is unavailable}}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
struct S {}
|
||||
|
||||
func ~= (lhs: S.Type, rhs: S.Type) -> Bool { true }
|
||||
|
||||
if case (S) = S.self {}
|
||||
// expected-error@-1 {{expected member name or initializer call after type name}}
|
||||
// expected-note@-2 {{add arguments after the type to construct a value of the type}}
|
||||
// expected-note@-3 {{use '.self' to reference the type object}}
|
||||
|
||||
if case ({ if case (S) = S.self { true } else { false } }()) = true {}
|
||||
// expected-error@-1 {{expected member name or initializer call after type name}}
|
||||
// expected-note@-2 {{add arguments after the type to construct a value of the type}}
|
||||
// expected-note@-3 {{use '.self' to reference the type object}}
|
||||
Reference in New Issue
Block a user