From da86703e2acc741298c4be799f495c1280cfb718 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Fri, 2 Jun 2023 17:59:04 +0100 Subject: [PATCH] [CS] Fix `coercePatternToType` enum cast handling Previously if the cast was unresolved, we would emit a warning and bail with `nullptr`. This is wrong, because the caller expects a `nullptr` return to mean we emitted an error. Change the diagnostic to an error to fix this. This may appear source breaking, but in reality previously we were failing to add the cast at all in this case, which lead to a crash in SILGen. We really do want to reject these cases as errors, as this will give us a better opportunity to fall back to type-checking as ExprPatterns, and better matches the constraint solver type-checking. Also while we're here, change the diagnostic for the case where we don't have an existential context type from the confusing "enum doesn't have member" diagnostic to the pattern mismatch diagnostic. rdar://107420031 --- lib/Sema/TypeCheckPattern.cpp | 11 +++++------ test/Constraints/patterns.swift | 2 +- test/Constraints/rdar107420031.swift | 18 ++++++++++++++++++ test/Parse/matching_patterns.swift | 2 +- .../matching_patterns_reference_bindings.swift | 2 +- 5 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 test/Constraints/rdar107420031.swift diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 9b42c5c8896..69260e9a097 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -1570,9 +1570,8 @@ Pattern *TypeChecker::coercePatternToType( type, parentTy, CheckedCastContextKind::EnumElementPattern, dc); // If the cast failed, we can't resolve the pattern. if (foundCastKind < CheckedCastKind::First_Resolved) { - diags - .diagnose(EEP->getLoc(), diag::downcast_to_unrelated, type, - parentTy) + diags.diagnose(EEP->getLoc(), diag::cannot_match_value_with_pattern, + type, parentTy) .highlight(EEP->getSourceRange()); return nullptr; } @@ -1582,9 +1581,9 @@ Pattern *TypeChecker::coercePatternToType( castKind = foundCastKind; enumTy = parentTy; } else { - diags.diagnose(EEP->getLoc(), - diag::enum_element_pattern_not_member_of_enum, - EEP->getName(), type); + diags.diagnose(EEP->getLoc(), diag::cannot_match_value_with_pattern, + type, parentTy) + .highlight(EEP->getSourceRange()); return nullptr; } } diff --git a/test/Constraints/patterns.swift b/test/Constraints/patterns.swift index 2ef07d49700..e4022ab5d09 100644 --- a/test/Constraints/patterns.swift +++ b/test/Constraints/patterns.swift @@ -120,7 +120,7 @@ case iPadHair.HairForceOne: () case iPadHair.HairForceOne: // expected-error{{generic enum type 'iPadHair' is ambiguous without explicit generic parameters when matching value of type 'any HairType'}} () -case Watch.Edition: // expected-warning {{cast from 'any HairType' to unrelated type 'Watch' always fails}} +case Watch.Edition: // expected-error {{pattern of type 'Watch' cannot match 'any HairType'}} () case .HairForceOne: // expected-error{{type 'any HairType' has no member 'HairForceOne'}} () diff --git a/test/Constraints/rdar107420031.swift b/test/Constraints/rdar107420031.swift new file mode 100644 index 00000000000..2f5687eb6fe --- /dev/null +++ b/test/Constraints/rdar107420031.swift @@ -0,0 +1,18 @@ +// RUN: %target-typecheck-verify-swift + +enum E { + case e +} + +func ~= (lhs: any Error, rhs: E) -> Bool { true } + +// rdar://107420031 – Make sure we don't crash. +// TODO: This ought to compile. +func foo(_ error: any Error) { + switch error { + case E.e: // expected-error {{pattern of type 'E' cannot match 'any Error'}} + break + default: + break + } +} diff --git a/test/Parse/matching_patterns.swift b/test/Parse/matching_patterns.swift index 1fbec74a906..050916fac05 100644 --- a/test/Parse/matching_patterns.swift +++ b/test/Parse/matching_patterns.swift @@ -122,7 +122,7 @@ if case let .Naught(value1, value2, value3) = n {} // expected-error{{pattern wi switch n { -case Foo.A: // expected-error{{enum case 'A' is not a member of type 'Voluntary'}} +case Foo.A: // expected-error{{pattern of type 'Foo' cannot match 'Voluntary'}} () case Voluntary.Naught, Voluntary.Naught(), // expected-error {{pattern with associated values does not match enum case 'Naught'}} diff --git a/test/Parse/matching_patterns_reference_bindings.swift b/test/Parse/matching_patterns_reference_bindings.swift index fadfd53ac98..fbf6b9840b1 100644 --- a/test/Parse/matching_patterns_reference_bindings.swift +++ b/test/Parse/matching_patterns_reference_bindings.swift @@ -140,7 +140,7 @@ if case inout .Naught(value1, value2, value3) = n {} // expected-error{{pattern switch n { -case Foo.A: // expected-error{{enum case 'A' is not a member of type 'Voluntary'}} +case Foo.A: // expected-error{{pattern of type 'Foo' cannot match 'Voluntary'}} () case Voluntary.Naught, Voluntary.Naught(), // expected-error {{pattern with associated values does not match enum case 'Naught'}}