From 91881e1ffa7e25b9b5a1d0c6655ff84d42b92196 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Mon, 10 Nov 2025 10:40:35 +0000 Subject: [PATCH 1/2] [CS] Invalidate unresolved variables in ExprPatterns early Make sure we invalidate when we initially visit the ExprPattern to ensure that we don't run into issues when generating constraints for a `where` clause before the constraints for the ExprPattern. We ought to change the constraint generation there to use a conjunction to ensure that the pattern is solved before the `where` clause, but I want to keep this as a quick low risk fix that we can cherry-pick. I'll switch it to a conjunction in a follow-up. --- lib/Sema/CSGen.cpp | 10 ++++++++++ ...ConstraintSystem-getTypeOfReferencePre-60045c.swift | 9 +++++++++ .../ConstraintWalker-walkToExprPost-c956e0.swift | 2 +- .../TypeVarRefCollector-walkToStmtPre-e56ccf.swift | 10 ++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 validation-test/compiler_crashers_fixed/ConstraintSystem-getTypeOfReferencePre-60045c.swift rename validation-test/{compiler_crashers => compiler_crashers_fixed}/ConstraintWalker-walkToExprPost-c956e0.swift (79%) create mode 100644 validation-test/compiler_crashers_fixed/TypeVarRefCollector-walkToStmtPre-e56ccf.swift diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 4653856e441ed..14e285592b615 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3153,6 +3153,16 @@ namespace { } case PatternKind::Expr: { + // Make sure we invalidate any nested VarDecls early since generating + // constraints for a `where` clause may happen before we've generated + // constraints for the ExprPattern. We'll record a fix when visiting + // the UnresolvedPatternExpr. + // FIXME: We ought to use a conjunction for switch cases, then we + // wouldn't need this logic. + auto *EP = cast(pattern); + EP->getSubExpr()->forEachUnresolvedVariable([&](VarDecl *VD) { + CS.setType(VD, ErrorType::get(CS.getASTContext())); + }); // We generate constraints for ExprPatterns in a separate pass. For // now, just create a type variable. return setType(CS.createTypeVariable(CS.getConstraintLocator(locator), diff --git a/validation-test/compiler_crashers_fixed/ConstraintSystem-getTypeOfReferencePre-60045c.swift b/validation-test/compiler_crashers_fixed/ConstraintSystem-getTypeOfReferencePre-60045c.swift new file mode 100644 index 0000000000000..aece4ac77ecd1 --- /dev/null +++ b/validation-test/compiler_crashers_fixed/ConstraintSystem-getTypeOfReferencePre-60045c.swift @@ -0,0 +1,9 @@ +// {"kind":"typecheck","signature":"swift::constraints::ConstraintSystem::getTypeOfReferencePre(swift::constraints::OverloadChoice, swift::DeclContext*, swift::constraints::ConstraintLocatorBuilder, swift::constraints::PreparedOverloadBuilder*)","signatureAssert":"Assertion failed: (func->isOperator() && \"Lookup should only find operators\"), function getTypeOfReferencePre"} +// RUN: not %target-swift-frontend -typecheck %s +{ + switch if .random() else { + } + { + case let !a where a: + } +} diff --git a/validation-test/compiler_crashers/ConstraintWalker-walkToExprPost-c956e0.swift b/validation-test/compiler_crashers_fixed/ConstraintWalker-walkToExprPost-c956e0.swift similarity index 79% rename from validation-test/compiler_crashers/ConstraintWalker-walkToExprPost-c956e0.swift rename to validation-test/compiler_crashers_fixed/ConstraintWalker-walkToExprPost-c956e0.swift index 3c65a22d943f8..853ee5d6fab7f 100644 --- a/validation-test/compiler_crashers/ConstraintWalker-walkToExprPost-c956e0.swift +++ b/validation-test/compiler_crashers_fixed/ConstraintWalker-walkToExprPost-c956e0.swift @@ -1,5 +1,5 @@ // {"kind":"typecheck","original":"1562769e","signature":"(anonymous namespace)::ConstraintWalker::walkToExprPost(swift::Expr*)"} -// RUN: not --crash %target-swift-frontend -typecheck %s +// RUN: not %target-swift-frontend -typecheck %s enum c func d() e { if let diff --git a/validation-test/compiler_crashers_fixed/TypeVarRefCollector-walkToStmtPre-e56ccf.swift b/validation-test/compiler_crashers_fixed/TypeVarRefCollector-walkToStmtPre-e56ccf.swift new file mode 100644 index 0000000000000..2f88c27677f69 --- /dev/null +++ b/validation-test/compiler_crashers_fixed/TypeVarRefCollector-walkToStmtPre-e56ccf.swift @@ -0,0 +1,10 @@ +// {"kind":"typecheck","signature":"swift::constraints::TypeVarRefCollector::walkToStmtPre(swift::Stmt*)","signatureAssert":"Assertion failed: (result), function getClosureType"} +// RUN: not %target-swift-frontend -typecheck %s +{ + switch if <#expression#> { + return + } + { + case let !a where a: + } +} From 3f3098582c68a9fc049f520030f290caef5455fe Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Wed, 5 Nov 2025 19:33:19 +0000 Subject: [PATCH 2/2] [ASTScopes] Remove ErrorExpr check from condition scope expansion This appears unnecessary and incorrectly meant the ErrorExpr would be placed outside the condition, meaning we could find the binding in its own initializer. --- lib/AST/ASTScopeCreation.cpp | 7 ++----- .../TypeVarRefCollector-walkToStmtPre-5c070f.swift | 7 +++++++ 2 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 validation-test/compiler_crashers_fixed/TypeVarRefCollector-walkToStmtPre-5c070f.swift diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index d95675b40b24b..b947c44dcc8d8 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -959,11 +959,8 @@ AnnotatedInsertionPoint ConditionalClausePatternUseScope::expandAScopeThatCreatesANewInsertionPoint( ScopeCreator &scopeCreator) { auto *initializer = sec.getInitializer(); - if (!isa(initializer)) { - scopeCreator - .constructExpandAndInsert( - this, initializer); - } + scopeCreator.constructExpandAndInsert( + this, initializer); return {this, "Succeeding code must be in scope of conditional clause pattern bindings"}; diff --git a/validation-test/compiler_crashers_fixed/TypeVarRefCollector-walkToStmtPre-5c070f.swift b/validation-test/compiler_crashers_fixed/TypeVarRefCollector-walkToStmtPre-5c070f.swift new file mode 100644 index 0000000000000..a714f8547e0b9 --- /dev/null +++ b/validation-test/compiler_crashers_fixed/TypeVarRefCollector-walkToStmtPre-5c070f.swift @@ -0,0 +1,7 @@ +// {"kind":"typecheck","signature":"swift::constraints::TypeVarRefCollector::walkToStmtPre(swift::Stmt*)","signatureAssert":"Assertion failed: (result), function getClosureType"} +// RUN: not %target-swift-frontend -typecheck %s +{ + guard let a = (a if{ + return + } +) "