mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Fix two bugs related to the casts optimizations.
The protocol_lookup the testcase from Interpreter test-cases exposed two bugs, once I tried to compiler with with -O: - SILCloner was generating an open_existential_ref from an open_existential_metatype instruction during cloning even if the existential in question was not a class existential. - DynamicCasts was not considering the fact that subclasses of a given class may implement a protocol, even if the class does not implement it. Swift SVN r27260
This commit is contained in:
@@ -1223,6 +1223,15 @@ visitOpenExistentialMetatypeInst(OpenExistentialMetatypeInst *inst) {
|
||||
OpenedExistentialSubs[archetypeTy]
|
||||
= ArchetypeType::getOpened(archetypeTy->getOpenedExistentialType());
|
||||
|
||||
if (!inst->getOperand().getType().canUseExistentialRepresentation(
|
||||
inst->getModule(), ExistentialRepresentation::Class)) {
|
||||
doPostProcess(inst, getBuilder().createOpenExistentialMetatype(
|
||||
getOpLocation(inst->getLoc()),
|
||||
getOpValue(inst->getOperand()),
|
||||
getOpType(inst->getType())));
|
||||
return;
|
||||
}
|
||||
|
||||
doPostProcess(inst,
|
||||
getBuilder().createOpenExistentialRef(getOpLocation(inst->getLoc()),
|
||||
getOpValue(inst->getOperand()),
|
||||
|
||||
@@ -130,6 +130,13 @@ classifyDynamicCastToProtocol(CanType source,
|
||||
if (auto *CD = source.getClassOrBoundGenericClass()) {
|
||||
if (canClassOrSuperclassesHaveExtensions(CD, isWholeModuleOpts))
|
||||
return DynamicCastFeasibility::MaySucceed;
|
||||
// Derived types may conform to the protocol.
|
||||
if (!CD->isFinal()) {
|
||||
// TODO: If it is a private type or internal type and we
|
||||
// can prove that there are no derived types conforming to a
|
||||
// protocol, then we can still return WillFail.
|
||||
return DynamicCastFeasibility::MaySucceed;
|
||||
}
|
||||
}
|
||||
|
||||
// If the source type is private or target protocol is private,
|
||||
|
||||
@@ -62,6 +62,8 @@ public protocol CP2: class {}
|
||||
// and it cannot be extended elsewhere as it is private
|
||||
private class D: CP1 {}
|
||||
|
||||
private final class F: CP1 {}
|
||||
|
||||
// Class E implements both class protocols at once
|
||||
class E: CP1, CP2 {}
|
||||
|
||||
@@ -668,10 +670,8 @@ func test27() -> Bool {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden [noinline] @_TF12cast_folding8test28_1FT_Sb
|
||||
// CHECK: bb0
|
||||
// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, 0
|
||||
// CHECK-NEXT: %1 = struct $Bool
|
||||
// CHECK-NEXT: return %1
|
||||
// CHECK: checked_cast
|
||||
// CHECK: return
|
||||
@inline(never)
|
||||
func test28_1() -> Bool {
|
||||
return cast28(D.self)
|
||||
@@ -687,6 +687,16 @@ func test28_2() -> Bool {
|
||||
return cast28(E.self)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden [noinline] @_TF12cast_folding8test28_3FT_Sb
|
||||
// CHECK: bb0
|
||||
// CHECK-NEXT: %0 = integer_literal $Builtin.Int1, 0
|
||||
// CHECK-NEXT: %1 = struct $Bool
|
||||
// CHECK-NEXT: return %1
|
||||
@inline(never)
|
||||
func test28_3() -> Bool {
|
||||
return cast28(F.self)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil hidden [noinline] @_TF12cast_folding6test29FT_Sb
|
||||
// CHECK: bb0
|
||||
// Check that cast is not elmiminated even though cast29 is a conversion
|
||||
|
||||
32
test/SILPasses/protocol_lookup.swift
Normal file
32
test/SILPasses/protocol_lookup.swift
Normal file
@@ -0,0 +1,32 @@
|
||||
// RUN: %target-swift-frontend -O -emit-sil -primary-file %s | FileCheck %s
|
||||
|
||||
// Check that this file can be compiled using -O at all (it used to crash due to a bug in the SILCloner)
|
||||
// Check that it can be compiled correctly.
|
||||
|
||||
// Protocol lookup for metatypes.
|
||||
protocol StaticFoo {
|
||||
static func foo() -> String
|
||||
}
|
||||
|
||||
class StaticBar {
|
||||
// Check that the cast is not folded as a failing cast.
|
||||
// CHECK-LABEL: sil hidden [noinline] @_TZFC15protocol_lookup9StaticBar12mightHaveFoofMS0_FT_SS
|
||||
// Check that the cast was not eliminated.
|
||||
// CHECK: checked_cast_addr_br
|
||||
@inline(never)
|
||||
class func mightHaveFoo() -> String {
|
||||
if let selfAsFoo? = self as? StaticFoo.Type {
|
||||
return selfAsFoo.foo()
|
||||
} else {
|
||||
return "no Foo for you"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StaticWibble : StaticBar, StaticFoo {
|
||||
static func foo() -> String { return "StaticWibble.foo" }
|
||||
}
|
||||
|
||||
// CHECK: StaticWibble.foo
|
||||
println(StaticWibble.mightHaveFoo())
|
||||
|
||||
Reference in New Issue
Block a user