Skip to content

[Typechecker] Relax existential to concrete type cast check for non-final classes #26971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4298,9 +4298,13 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
// print("Caught bar error")
// }
// }
if (fromExistential) {
//
// Note: we relax the restriction if the type we're casting to is a
// non-final class because it's possible that we might have a subclass
// that conforms to the protocol.
if (fromExistential && !toExistential) {
if (auto NTD = toType->getAnyNominal()) {
if (!isa<ProtocolDecl>(NTD)) {
if (!toType->is<ClassType>() || NTD->isFinal()) {
auto protocolDecl =
dyn_cast_or_null<ProtocolDecl>(fromType->getAnyNominal());
if (protocolDecl &&
Expand Down
4 changes: 2 additions & 2 deletions test/Constraints/patterns.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ case is B,
is D,
is S:
()
case is E: // expected-warning {{cast from 'P' to unrelated type 'E' always fails}}
case is E:
()
default:
()
Expand All @@ -69,7 +69,7 @@ case let d as D:
d.d()
case let s as S:
s.s()
case let e as E: // expected-warning {{cast from 'P' to unrelated type 'E' always fails}}
case let e as E:
e.e()
default:
()
Expand Down
28 changes: 24 additions & 4 deletions test/stmt/errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,37 @@ class SR_6400_B: SR_6400_FakeApplicationDelegate & Error {}
func sr_6400_4() {
do {
throw SR_6400_E.castError
} catch let error as SR_6400_A { // expected-warning {{cast from 'Error' to unrelated type 'SR_6400_A' always fails}} // expected-warning {{immutable value 'error' was never used; consider replacing with '_' or removing it}}
print("Foo")
} catch let error as SR_6400_A { // Okay
print(error)
} catch {
print("Bar")
}

do {
throw SR_6400_E.castError
} catch let error as SR_6400_B { // expected-warning {{immutable value 'error' was never used; consider replacing with '_' or removing it}}
print("Foo")
} catch let error as SR_6400_B { // Okay
print(error)
} catch {
print("Bar")
}
}

// SR-11402

protocol SR_11402_P {}
class SR_11402_Superclass {}
class SR_11402_Subclass: SR_11402_Superclass, SR_11402_P {}

func sr_11402_func1(_ x: SR_11402_P) {
if let y = x as? SR_11402_Superclass { // Okay
print(y)
}
}

final class SR_11402_Final {}

func sr_11402_func2(_ x: SR_11402_P) {
if let y = x as? SR_11402_Final { // expected-warning {{cast from 'SR_11402_P' to unrelated type 'SR_11402_Final' always fails}}
print(y)
}
}