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;
|
return MacroWalking::Expansion;
|
||||||
}
|
}
|
||||||
|
|
||||||
PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) override {
|
|
||||||
return Action::SkipNode(P);
|
|
||||||
}
|
|
||||||
|
|
||||||
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
|
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
|
||||||
return Action::Continue();
|
return Action::Continue();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,20 +327,31 @@ void ParentConditionalConformance::diagnoseConformanceStack(
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/// Produce any additional syntactic diagnostics for the body of a function
|
/// Produce any additional syntactic diagnostics for a SyntacticElementTarget.
|
||||||
/// that had a result builder applied.
|
class SyntacticDiagnosticWalker final : public ASTWalker {
|
||||||
class FunctionSyntacticDiagnosticWalker : public ASTWalker {
|
|
||||||
SmallVector<DeclContext *, 4> dcStack;
|
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:
|
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 {
|
MacroWalking getMacroWalkingBehavior() const override {
|
||||||
return MacroWalking::Expansion;
|
return MacroWalking::Expansion;
|
||||||
}
|
}
|
||||||
|
|
||||||
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
|
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 (auto closure = dyn_cast<ClosureExpr>(expr)) {
|
||||||
if (closure->isSeparatelyTypeChecked()) {
|
if (closure->isSeparatelyTypeChecked()) {
|
||||||
@@ -368,9 +379,10 @@ public:
|
|||||||
return Action::Continue(stmt);
|
return Action::Continue(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreWalkResult<Pattern *> walkToPatternPre(Pattern *pattern) override {
|
PreWalkAction walkToDeclPre(Decl *D) override {
|
||||||
return Action::SkipNode(pattern);
|
return Action::VisitNodeIf(isa<PatternBindingDecl>(D));
|
||||||
}
|
}
|
||||||
|
|
||||||
PreWalkAction walkToTypeReprPre(TypeRepr *typeRepr) override {
|
PreWalkAction walkToTypeReprPre(TypeRepr *typeRepr) override {
|
||||||
return Action::SkipNode();
|
return Action::SkipNode();
|
||||||
}
|
}
|
||||||
@@ -382,41 +394,7 @@ public:
|
|||||||
|
|
||||||
void constraints::performSyntacticDiagnosticsForTarget(
|
void constraints::performSyntacticDiagnosticsForTarget(
|
||||||
const SyntacticElementTarget &target, bool isExprStmt) {
|
const SyntacticElementTarget &target, bool isExprStmt) {
|
||||||
auto *dc = target.getDeclContext();
|
SyntacticDiagnosticWalker::check(target, isExprStmt);
|
||||||
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!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark High-level entry points
|
#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