Skip to content

Commit f2d1f6d

Browse files
authored
Merge pull request #26971 from theblixguy/fix/SR-11402
[Typechecker] Relax existential to concrete type cast check for non-final classes
2 parents 0d84e76 + eb1810c commit f2d1f6d

File tree

3 files changed

+32
-8
lines changed

3 files changed

+32
-8
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4299,9 +4299,13 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
42994299
// print("Caught bar error")
43004300
// }
43014301
// }
4302-
if (fromExistential) {
4302+
//
4303+
// Note: we relax the restriction if the type we're casting to is a
4304+
// non-final class because it's possible that we might have a subclass
4305+
// that conforms to the protocol.
4306+
if (fromExistential && !toExistential) {
43034307
if (auto NTD = toType->getAnyNominal()) {
4304-
if (!isa<ProtocolDecl>(NTD)) {
4308+
if (!toType->is<ClassType>() || NTD->isFinal()) {
43054309
auto protocolDecl =
43064310
dyn_cast_or_null<ProtocolDecl>(fromType->getAnyNominal());
43074311
if (protocolDecl &&

test/Constraints/patterns.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ case is B,
5555
is D,
5656
is S:
5757
()
58-
case is E: // expected-warning {{cast from 'P' to unrelated type 'E' always fails}}
58+
case is E:
5959
()
6060
default:
6161
()
@@ -69,7 +69,7 @@ case let d as D:
6969
d.d()
7070
case let s as S:
7171
s.s()
72-
case let e as E: // expected-warning {{cast from 'P' to unrelated type 'E' always fails}}
72+
case let e as E:
7373
e.e()
7474
default:
7575
()

test/stmt/errors.swift

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,17 +209,37 @@ class SR_6400_B: SR_6400_FakeApplicationDelegate & Error {}
209209
func sr_6400_4() {
210210
do {
211211
throw SR_6400_E.castError
212-
} 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}}
213-
print("Foo")
212+
} catch let error as SR_6400_A { // Okay
213+
print(error)
214214
} catch {
215215
print("Bar")
216216
}
217217

218218
do {
219219
throw SR_6400_E.castError
220-
} catch let error as SR_6400_B { // expected-warning {{immutable value 'error' was never used; consider replacing with '_' or removing it}}
221-
print("Foo")
220+
} catch let error as SR_6400_B { // Okay
221+
print(error)
222222
} catch {
223223
print("Bar")
224224
}
225225
}
226+
227+
// SR-11402
228+
229+
protocol SR_11402_P {}
230+
class SR_11402_Superclass {}
231+
class SR_11402_Subclass: SR_11402_Superclass, SR_11402_P {}
232+
233+
func sr_11402_func1(_ x: SR_11402_P) {
234+
if let y = x as? SR_11402_Superclass { // Okay
235+
print(y)
236+
}
237+
}
238+
239+
final class SR_11402_Final {}
240+
241+
func sr_11402_func2(_ x: SR_11402_P) {
242+
if let y = x as? SR_11402_Final { // expected-warning {{cast from 'SR_11402_P' to unrelated type 'SR_11402_Final' always fails}}
243+
print(y)
244+
}
245+
}

0 commit comments

Comments
 (0)