Skip to content

Commit d2b298b

Browse files
committed
[CS] Avoid doing performStmtDiagnostics in CSApply
Instead, ensure we walk into expressions in SyntacticDiagnosticWalker, allowing `performStmtDiagnostics` to be called there for all statements present in the target. This avoids a case where we'd double diagnose. While here, inherit the walker from BaseDiagnosticWalker.
1 parent ed1589d commit d2b298b

File tree

4 files changed

+54
-36
lines changed

4 files changed

+54
-36
lines changed

lib/Sema/CSSyntacticElement.cpp

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,20 +1733,6 @@ class SyntacticElementSolutionApplication
17331733
return Type();
17341734
}
17351735

1736-
ASTNode visit(Stmt *S, bool performSyntacticDiagnostics = true) {
1737-
auto rewritten = ASTVisitor::visit(S);
1738-
if (!rewritten)
1739-
return {};
1740-
1741-
if (performSyntacticDiagnostics) {
1742-
if (auto *stmt = getAsStmt(rewritten)) {
1743-
performStmtDiagnostics(stmt, context.getAsDeclContext());
1744-
}
1745-
}
1746-
1747-
return rewritten;
1748-
}
1749-
17501736
bool visitPatternBindingDecl(PatternBindingDecl *PBD) {
17511737
// If this is a placeholder variable with an initializer, we just need to
17521738
// set the inferred type.
@@ -2274,7 +2260,7 @@ class ResultBuilderRewriter : public SyntacticElementSolutionApplication {
22742260
private:
22752261
ASTNode visitDoStmt(DoStmt *doStmt) override {
22762262
if (auto transformed = transformDo(doStmt)) {
2277-
return visit(transformed.get(), /*performSyntacticDiagnostics=*/false);
2263+
return visit(transformed.get());
22782264
}
22792265

22802266
auto newBody = visit(doStmt->getBody());

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -327,9 +327,10 @@ void ParentConditionalConformance::diagnoseConformanceStack(
327327

328328
namespace {
329329
/// Produce any additional syntactic diagnostics for a SyntacticElementTarget.
330-
class SyntacticDiagnosticWalker final : public ASTWalker {
330+
class SyntacticDiagnosticWalker final : public BaseDiagnosticWalker {
331331
const SyntacticElementTarget &Target;
332332
bool IsTopLevelExprStmt;
333+
unsigned ExprDepth = 0;
333334

334335
SyntacticDiagnosticWalker(const SyntacticElementTarget &target,
335336
bool isExprStmt)
@@ -341,27 +342,30 @@ class SyntacticDiagnosticWalker final : public ASTWalker {
341342
target.walk(walker);
342343
}
343344

344-
MacroWalking getMacroWalkingBehavior() const override {
345-
// We only want to walk macro arguments. Expansions will be walked when
346-
// they're type-checked, not as part of the surrounding code.
347-
return MacroWalking::Arguments;
345+
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
346+
// We only want to call the diagnostic logic for the top-level expression,
347+
// since the underlying logic will visit each sub-expression. We want to
348+
// continue walking however to diagnose any child statements in e.g
349+
// closures.
350+
if (ExprDepth == 0) {
351+
auto isExprStmt = (E == Target.getAsExpr()) ? IsTopLevelExprStmt : false;
352+
performSyntacticExprDiagnostics(E, Target.getDeclContext(), isExprStmt);
353+
}
354+
ExprDepth += 1;
355+
return Action::Continue(E);
348356
}
349357

350-
PreWalkResult<Expr *> walkToExprPre(Expr *expr) override {
351-
auto isExprStmt = (expr == Target.getAsExpr()) ? IsTopLevelExprStmt : false;
352-
performSyntacticExprDiagnostics(expr, Target.getDeclContext(), isExprStmt);
353-
return Action::SkipNode(expr);
358+
PostWalkResult<Expr *> walkToExprPost(Expr *E) override {
359+
assert(ExprDepth > 0);
360+
ExprDepth -= 1;
361+
return Action::Continue(E);
354362
}
355363

356364
PreWalkResult<Stmt *> walkToStmtPre(Stmt *stmt) override {
357365
performStmtDiagnostics(stmt, Target.getDeclContext());
358366
return Action::Continue(stmt);
359367
}
360368

361-
PreWalkAction walkToDeclPre(Decl *D) override {
362-
return Action::VisitNodeIf(isa<PatternBindingDecl>(D));
363-
}
364-
365369
PreWalkAction walkToTypeReprPre(TypeRepr *typeRepr) override {
366370
return Action::SkipNode();
367371
}

test/Constraints/result_builder_diags.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,3 +1029,31 @@ func testMissingElementInEmptyBuilder() {
10291029
func test2() -> Int {}
10301030
// expected-error@-1 {{expected expression of type 'Int' in result builder 'SingleElementBuilder'}} {{24-24=<#T##Int#>}}
10311031
}
1032+
1033+
// https://github.com/swiftlang/swift/issues/77453
1034+
func testNoDuplicateStmtDiags() {
1035+
@resultBuilder
1036+
struct Builder {
1037+
static func buildBlock<T>(_ components: T...) -> T {
1038+
components.first!
1039+
}
1040+
static func buildEither<T>(first component: T) -> T {
1041+
component
1042+
}
1043+
static func buildEither<T>(second component: T) -> T {
1044+
component
1045+
}
1046+
}
1047+
1048+
func takesClosure(_ fn: () -> Void) -> Int? { nil }
1049+
1050+
@Builder
1051+
func foo() -> Int {
1052+
if let x = takesClosure {} {
1053+
// expected-warning@-1 {{trailing closure in this context is confusable with the body of the statement}}
1054+
x
1055+
} else {
1056+
1
1057+
}
1058+
}
1059+
}

test/Macros/macro_misc_diags.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,12 @@ _ = #identity(deprecatedFunc())
8080
#makeBinding((deprecatedFunc(), Int, {
8181
if let _ = takesClosure {} {}
8282
}()))
83-
// CHECK-DIAG: Client.swift:[[@LINE-2]]:27: warning: trailing closure in this context is confusable with the body of the statement
84-
// CHECK-DIAG: Client.swift:[[@LINE-4]]:33: error: expected member name or initializer call after type name
85-
// CHECK-DIAG: Client.swift:[[@LINE-5]]:15: warning: 'deprecatedFunc()' is deprecated
86-
// CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-7]]{{.*}}makeBindingfMf_.swift:2:27: warning: trailing closure in this context is confusable with the body of the statement; pass as a parenthesized argument to silence this warning
87-
// CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-8]]{{.*}}makeBindingfMf_.swift:1:28: error: expected member name or initializer call after type name
88-
// CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-9]]{{.*}}makeBindingfMf_.swift:1:10: warning: 'deprecatedFunc()' is deprecated
83+
// CHECK-DIAG: Client.swift:[[@LINE-3]]:33: error: expected member name or initializer call after type name
84+
// CHECK-DIAG: Client.swift:[[@LINE-4]]:15: warning: 'deprecatedFunc()' is deprecated
85+
// CHECK-DIAG: Client.swift:[[@LINE-4]]:27: warning: trailing closure in this context is confusable with the body of the statement
86+
// CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-7]]{{.*}}makeBindingfMf_.swift:1:28: error: expected member name or initializer call after type name
87+
// CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-8]]{{.*}}makeBindingfMf_.swift:1:10: warning: 'deprecatedFunc()' is deprecated
88+
// CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-9]]{{.*}}makeBindingfMf_.swift:2:27: warning: trailing closure in this context is confusable with the body of the statement
8989
// CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-10]]{{.*}}makeBindingfMf_.swift:1:5: warning: initialization of immutable value
9090

9191
struct S1 {
@@ -104,8 +104,8 @@ func takesClosure(_ fn: () -> Void) -> Int? { nil }
104104

105105
_ = #trailingClosure {
106106
if let _ = takesClosure {} {}
107-
// CHECK-DIAG: Client.swift:[[@LINE-1]]:27: warning: trailing closure in this context is confusable with the body of the statement; pass as a parenthesized argument to silence this warning
108-
// CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-4]]{{.*}}trailingClosurefMf_.swift:2:27: warning: trailing closure in this context is confusable with the body of the statement
107+
// CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-3]]{{.*}}trailingClosurefMf_.swift:2:27: warning: trailing closure in this context is confusable with the body of the statement
108+
// CHECK-DIAG: Client.swift:[[@LINE-2]]:27: warning: trailing closure in this context is confusable with the body of the statement
109109
}
110110

111111
func testOptionalToAny(_ y: Int?) {

0 commit comments

Comments
 (0)