Skip to content
Open
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
3 changes: 2 additions & 1 deletion lib/IRGen/GenCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from,

// If the destination type is known to have a Swift-compatible
// implementation, use the most specific entrypoint.
if (destClass && destClass->hasKnownSwiftImplementation()) {
if ((destClass && destClass->hasKnownSwiftImplementation()) ||
IGF.IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
metadataRef = IGF.emitTypeMetadataRef(toType);

switch (mode) {
Expand Down
21 changes: 12 additions & 9 deletions lib/SIL/Utils/DynamicCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1378,23 +1378,26 @@ bool swift::canIRGenUseScalarCheckedCastInstructions(SILModule &M,
// bridging, unless we can statically see that the source type inherits
// NSError.

// A class-constrained archetype may be bound to NSError, unless it has a
// non-NSError superclass constraint. Casts to archetypes thus must always be
// indirect.
if (auto archetype = targetFormalType->getAs<ArchetypeType>()) {
// Only ever permit this if the source type is a reference type.
if (!objectType.isAnyClassReferenceType())
return false;

auto super = archetype->getSuperclass();
if (super.isNull())
return false;

// A base class constraint that isn't NSError rules out the archetype being
// bound to NSError.
if (M.getASTContext().LangOpts.EnableObjCInterop) {
// A class-constrained archetype may be bound to NSError, unless it has a
// non-NSError superclass constraint. Casts to archetypes thus must always be
// indirect.
auto super = archetype->getSuperclass();
if (super.isNull())
return false;

// A base class constraint that isn't NSError rules out the archetype being
// bound to NSError.
if (auto nserror = M.Types.getNSErrorType())
return !super->isEqual(nserror);
} else {
if (!archetype->requiresClass())
return false;
}

// If NSError wasn't loaded, any base class constraint must not be NSError.
Expand Down
4 changes: 2 additions & 2 deletions test/IRGen/dynamic_self_cast.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class SelfCasts {
}

// CHECK-LABEL: define {{(dllexport )?}}{{(protected )?}}swiftcc ptr @"$s17dynamic_self_cast9SelfCastsC016classGenericFromD0xyRlzClFZ"(ptr %T, ptr swiftself %0)
// CHECK: call zeroext i1 @swift_dynamicCast(ptr {{%.*}}, ptr {{%.*}}, ptr %0, ptr %T, {{.*}})
// CHECK: call ptr @swift_dynamicCastUnknownClassUnconditional(ptr {{%.*}}, ptr %T, ptr null, i32 0, i32 0) #4
// CHECK: ret
public static func classGenericFromSelf<T : AnyObject>() -> T {
let s = Self()
Expand Down Expand Up @@ -72,7 +72,7 @@ public class SelfCasts {
}

// CHECK-LABEL: define {{(dllexport )?}}{{(protected )?}}swiftcc {{i32|i64}} @"$s17dynamic_self_cast9SelfCastsC016classGenericFromD11ConditionalxSgyRlzClFZ"(ptr %T, ptr swiftself %0)
// CHECK: call zeroext i1 @swift_dynamicCast(ptr {{%.*}}, ptr {{%.*}}, ptr %0, ptr %T, {{.*}})
// CHECK: call ptr @swift_dynamicCastUnknownClass(ptr {{%.*}}, ptr %T)
// CHECK: ret
public static func classGenericFromSelfConditional<T : AnyObject>() -> T? {
let s = Self()
Expand Down
6 changes: 3 additions & 3 deletions test/SILGen/dynamic_self_cast.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -Xllvm -sil-print-types -emit-silgen %s | %FileCheck %s
// RUN: %target-swift-frontend -Xllvm -sil-print-types -disable-objc-interop -emit-silgen %s | %FileCheck %s

public class SelfCasts {
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC02toD0yACXDACFZ : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned SelfCasts {
Expand Down Expand Up @@ -31,7 +31,7 @@ public class SelfCasts {
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC016classGenericFromD0xyRlzClFZ : $@convention(method) <T where T : AnyObject> (@thick SelfCasts.Type) -> @owned T
// CHECK: unconditional_checked_cast_addr @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
// CHECK: unconditional_checked_cast {{.*}} : $SelfCasts to T
// CHECK: }
public static func classGenericFromSelf<T : AnyObject>() -> T {
let s = Self()
Expand Down Expand Up @@ -68,7 +68,7 @@ public class SelfCasts {
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC016classGenericFromD11ConditionalxSgyRlzClFZ : $@convention(method) <T where T : AnyObject> (@thick SelfCasts.Type) -> @owned Optional<T> {
// CHECK: checked_cast_addr_br take_always @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
// CHECK: checked_cast_br @dynamic_self SelfCasts in {{.*}} : $SelfCasts to T
// CHECK: }
public static func classGenericFromSelfConditional<T : AnyObject>() -> T? {
let s = Self()
Expand Down
82 changes: 82 additions & 0 deletions test/SILGen/dynamic_self_cast_objc.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// RUN: %target-swift-frontend -Xllvm -sil-print-types -module-name=dynamic_self_cast -emit-silgen %s | %FileCheck %s

// REQUIRES: objc_interop

public class SelfCasts {
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC02toD0yACXDACFZ : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned SelfCasts {
// CHECK: unconditional_checked_cast {{.*}} : $SelfCasts to @dynamic_self SelfCasts
// CHECK: }
public static func toSelf(_ s: SelfCasts) -> Self {
return s as! Self
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC09genericToD0yACXDxlFZ : $@convention(method) <T> (@in_guaranteed T, @thick SelfCasts.Type) -> @owned SelfCasts {
// CHECK: unconditional_checked_cast_addr T in {{.*}} : $*T to @dynamic_self SelfCasts in {{.*}} : $*SelfCasts
// CHECK: }
public static func genericToSelf<T>(_ s: T) -> Self {
return s as! Self
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC014classGenericToD0yACXDxRlzClFZ : $@convention(method) <T where T : AnyObject> (@guaranteed T, @thick SelfCasts.Type) -> @owned SelfCasts {
// CHECK: unconditional_checked_cast {{.*}} : $T to @dynamic_self SelfCasts
// CHECK: }
public static func classGenericToSelf<T : AnyObject>(_ s: T) -> Self {
return s as! Self
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC011genericFromD0xylFZ : $@convention(method) <T> (@thick SelfCasts.Type) -> @out T {
// CHECK: unconditional_checked_cast_addr @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
// CHECK: }
public static func genericFromSelf<T>() -> T {
let s = Self()
return s as! T
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC016classGenericFromD0xyRlzClFZ : $@convention(method) <T where T : AnyObject> (@thick SelfCasts.Type) -> @owned T
// CHECK: unconditional_checked_cast_addr @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
// CHECK: }
public static func classGenericFromSelf<T : AnyObject>() -> T {
let s = Self()
return s as! T
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC02toD11ConditionalyACXDSgACFZ : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned Optional<SelfCasts> {
// CHECK: checked_cast_br SelfCasts in {{.*}} : $SelfCasts to @dynamic_self SelfCasts
// CHECK: }
public static func toSelfConditional(_ s: SelfCasts) -> Self? {
return s as? Self
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC09genericToD11ConditionalyACXDSgxlFZ : $@convention(method) <T> (@in_guaranteed T, @thick SelfCasts.Type) -> @owned Optional<SelfCasts> {
// CHECK: checked_cast_addr_br take_always T in {{.*}} : $*T to @dynamic_self SelfCasts in {{.*}} : $*SelfCasts
// CHECK: }
public static func genericToSelfConditional<T>(_ s: T) -> Self? {
return s as? Self
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC014classGenericToD11ConditionalyACXDSgxRlzClFZ : $@convention(method) <T where T : AnyObject> (@guaranteed T, @thick SelfCasts.Type) -> @owned Optional<SelfCasts> {
// CHECK: checked_cast_br T in {{.*}} : $T to @dynamic_self SelfCasts
// CHECK: }
public static func classGenericToSelfConditional<T : AnyObject>(_ s: T) -> Self? {
return s as? Self
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC011genericFromD11ConditionalxSgylFZ : $@convention(method) <T> (@thick SelfCasts.Type) -> @out Optional<T> {
// CHECK: checked_cast_addr_br take_always @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
// CHECK: }
public static func genericFromSelfConditional<T>() -> T? {
let s = Self()
return s as? T
}

// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC016classGenericFromD11ConditionalxSgyRlzClFZ : $@convention(method) <T where T : AnyObject> (@thick SelfCasts.Type) -> @owned Optional<T> {
// CHECK: checked_cast_addr_br take_always @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
// CHECK: }
public static func classGenericFromSelfConditional<T : AnyObject>() -> T? {
let s = Self()
return s as? T
}

public required init() {}
}

12 changes: 5 additions & 7 deletions test/SILGen/generic_casts.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 5 -module-name generic_casts -Xllvm -sil-full-demangle %s | %FileCheck %s
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -disable-objc-interop -swift-version 5 -module-name generic_casts -Xllvm -sil-full-demangle %s | %FileCheck %s

protocol ClassBound : class {}
protocol NotClassBound {}
Expand Down Expand Up @@ -59,8 +59,7 @@ func class_archetype_to_class_archetype
<T:ClassBound, U:ClassBound>(_ t:T) -> U {
return t as! U
// Error bridging can change the identity of class-constrained archetypes.
// CHECK: unconditional_checked_cast_addr T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
// CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK: [[DOWNCAST:%.*]] = unconditional_checked_cast {{%.*}} : $T to U
// CHECK: return [[DOWNCAST]] : $U
}

Expand All @@ -69,7 +68,7 @@ func class_archetype_is_class_archetype
<T:ClassBound, U:ClassBound>(_ t:T, u:U.Type) -> Bool {
return t is U
// Error bridging can change the identity of class-constrained archetypes.
// CHECK: checked_cast_addr_br {{.*}} T in {{%.*}} : $*T to U in {{%.*}} : $*U
// CHECK: checked_cast_br T in {{%.*}} : $T to U
}

// CHECK-LABEL: sil hidden [ossa] @$s13generic_casts38opaque_archetype_to_addr_only_concrete{{[_0-9a-zA-Z]*}}F
Expand Down Expand Up @@ -158,16 +157,15 @@ func opaque_existential_is_class_archetype
func class_existential_to_class_archetype
<T:ClassBound>(_ p:ClassBound) -> T {
return p as! T
// CHECK: unconditional_checked_cast_addr any ClassBound in {{%.*}} : $*any ClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
// CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK: [[DOWNCAST:%.*]] = unconditional_checked_cast {{%.*}} : $any ClassBound to T
// CHECK: return [[DOWNCAST]] : $T
}

// CHECK-LABEL: sil hidden [ossa] @$s13generic_casts021class_existential_is_C10_archetype{{[_0-9a-zA-Z]*}}F
func class_existential_is_class_archetype
<T:ClassBound>(_ p:ClassBound, _: T) -> Bool {
return p is T
// CHECK: checked_cast_addr_br {{.*}} any ClassBound in {{%.*}} : $*any ClassBound to T in {{%.*}} : $*T
// CHECK: checked_cast_br any ClassBound in {{%.*}} : $any ClassBound to T
}

// CHECK-LABEL: sil hidden [ossa] @$s13generic_casts40opaque_existential_to_addr_only_concrete{{[_0-9a-zA-Z]*}}F
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

// REQUIRES: optimized_stdlib
// REQUIRES: swift_stdlib_no_asserts
// REQUIRES: OS=macosx

///////////////////
// Generic Casts //
Expand Down
4 changes: 2 additions & 2 deletions test/SILOptimizer/rcidentity_opaque.sil
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-sil-opt -rc-id-dumper -enable-sil-opaque-values -module-name Swift %s -o /dev/null | %FileCheck %s
// RUN: %target-sil-opt -rc-id-dumper -enable-sil-opaque-values -disable-objc-interop -module-name Swift %s -o /dev/null | %FileCheck %s

import Builtin

Expand Down Expand Up @@ -295,7 +295,7 @@ bb0(%0 : @owned $T):
//
// CHECK-LABEL: @testClassToClassArchetypeIsBridged
// CHECK: RESULT #0: 0 = 0
// CHECK: RESULT #1: 1 = 1
// CHECK: RESULT #1: 1 = 0
sil [ossa] @testClassToClassArchetypeIsBridged : $@convention(thin) <U : AnyObject>(@owned Base) -> @owned U {
bb0(%0 : @owned $Base):
%1 = unconditional_checked_cast %0 : $Base to U
Expand Down
22 changes: 22 additions & 0 deletions test/embedded/existential-class-bound1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
protocol ClassBound: AnyObject {
func foo()
func bar()
func predicate() -> Bool
}

class MyClass {}
Expand Down Expand Up @@ -230,6 +231,22 @@ func testP4() -> any P4 {
return C4(t: K4(x: 437))
}

var gg: any ClassBound = MyClass()

extension ClassBound {
public func isSame(_ rhs: some ClassBound) -> Bool {
if let rhs = rhs as? Self {
return rhs.predicate()
}
return false
}
public func predicate() -> Bool { true }
}

@inline(never)
func testIsSame(_ p: any ClassBound) -> Bool {
return p.isSame(gg)
}


@main
Expand Down Expand Up @@ -261,6 +278,11 @@ struct Main {
// CHECK: 102
testP4().foo()
// CHECK: 437

print(testIsSame(MyClass()))
// CHECK: true
print(testIsSame(MyOtherClass()))
// CHECK: false
}
}