[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
This commit is contained in:
Hamish Knight
2023-06-02 17:59:04 +01:00
parent b43d351197
commit da86703e2a
5 changed files with 26 additions and 9 deletions

View File

@@ -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;
}
}

View File

@@ -120,7 +120,7 @@ case iPadHair<E>.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'}}
()

View File

@@ -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
}
}

View File

@@ -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<Int>'}}
case Foo.A: // expected-error{{pattern of type 'Foo' cannot match 'Voluntary<Int>'}}
()
case Voluntary<Int>.Naught,
Voluntary<Int>.Naught(), // expected-error {{pattern with associated values does not match enum case 'Naught'}}

View File

@@ -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<Int>'}}
case Foo.A: // expected-error{{pattern of type 'Foo' cannot match 'Voluntary<Int>'}}
()
case Voluntary<Int>.Naught,
Voluntary<Int>.Naught(), // expected-error {{pattern with associated values does not match enum case 'Naught'}}