diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 24e6856ddb2d5..5ab0c1347824f 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2519,30 +2519,47 @@ SingleValueStmtExpr *SingleValueStmtExpr::createWithWrappedBranches( SingleValueStmtExpr * SingleValueStmtExpr::tryDigOutSingleValueStmtExpr(Expr *E) { - while (true) { - // Look through implicit conversions. - if (auto *ICE = dyn_cast(E)) { - E = ICE->getSubExpr(); - continue; + class SVEFinder final : public ASTWalker { + public: + SingleValueStmtExpr *FoundSVE = nullptr; + + PreWalkResult walkToExprPre(Expr *E) override { + if (auto *SVE = dyn_cast(E)) { + FoundSVE = SVE; + return Action::Stop(); + } + + // Look through implicit exprs. + if (E->isImplicit()) + return Action::Continue(E); + + // Look through coercions. + if (isa(E)) + return Action::Continue(E); + + // Look through try/await (this is invalid, but we'll error on it in + // effect checking). + if (isa(E) || isa(E)) + return Action::Continue(E); + + return Action::Stop(); } - // Look through coercions. - if (auto *CE = dyn_cast(E)) { - E = CE->getSubExpr(); - continue; + PreWalkResult walkToStmtPre(Stmt *S) override { + return Action::Stop(); } - // Look through try/await (this is invalid, but we'll error on it in - // effect checking). - if (auto *TE = dyn_cast(E)) { - E = TE->getSubExpr(); - continue; + PreWalkAction walkToDeclPre(Decl *D) override { + return Action::Stop(); } - if (auto *AE = dyn_cast(E)) { - E = AE->getSubExpr(); - continue; + PreWalkResult walkToPatternPre(Pattern *P) override { + return Action::Stop(); } - break; - } - return dyn_cast(E); + PreWalkAction walkToTypeReprPre(TypeRepr *T) override { + return Action::Stop(); + } + }; + SVEFinder finder; + E->walk(finder); + return finder.FoundSVE; } SourceRange SingleValueStmtExpr::getSourceRange() const { diff --git a/test/expr/unary/if_expr.swift b/test/expr/unary/if_expr.swift index ab88e23a0642a..7f52006e4d859 100644 --- a/test/expr/unary/if_expr.swift +++ b/test/expr/unary/if_expr.swift @@ -1016,3 +1016,16 @@ func tryAwaitIf2() async throws -> Int { // expected-error@-1 {{'try' may not be used on 'if' expression}} // expected-error@-2 {{'await' may not be used on 'if' expression}} } + +struct AnyEraserP: EraserP { + init(erasing: T) {} +} + +@_typeEraser(AnyEraserP) +protocol EraserP {} +struct SomeEraserP: EraserP {} + +// rdar://113435870 - Make sure we allow an implicit init(erasing:) call. +dynamic func testDynamicOpaqueErase() -> some EraserP { + if .random() { SomeEraserP() } else { SomeEraserP() } +} diff --git a/test/expr/unary/switch_expr.swift b/test/expr/unary/switch_expr.swift index b498598375dfb..a164624a9ad0b 100644 --- a/test/expr/unary/switch_expr.swift +++ b/test/expr/unary/switch_expr.swift @@ -1288,3 +1288,16 @@ func tryAwaitSwitch2() async throws -> Int { // expected-error@-1 {{'try' may not be used on 'switch' expression}} // expected-error@-2 {{'await' may not be used on 'switch' expression}} } + +struct AnyEraserP: EraserP { + init(erasing: T) {} +} + +@_typeEraser(AnyEraserP) +protocol EraserP {} +struct SomeEraserP: EraserP {} + +// rdar://113435870 - Make sure we allow an implicit init(erasing:) call. +dynamic func testDynamicOpaqueErase() -> some EraserP { + switch Bool.random() { default: SomeEraserP() } +}