From d368700a6eb3bc7719206963d70ab19c92ca9671 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 18 May 2015 23:59:43 +0000 Subject: [PATCH] SILGen: Object to metatype casts have to take the slow path It looks like we don't know how to open-code the "is-a metatype" check for scalar casts, so just tighten up canUseScalarCheckedCastInstructions() so that if the target type is a metatype, the source also has to be a metatype. This fixes a regression from "SIL: Use scalar casts more". Fixes . Swift SVN r28729 --- include/swift/AST/Type.h | 4 ++-- lib/SIL/DynamicCasts.cpp | 21 ++++++++++++--------- test/SILGen/metatype_casts.swift | 17 ++++++++++++++++- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/include/swift/AST/Type.h b/include/swift/AST/Type.h index 6d7b44686ac..24ceb16fdd9 100644 --- a/include/swift/AST/Type.h +++ b/include/swift/AST/Type.h @@ -251,12 +251,12 @@ public: return isExistentialTypeImpl(*this, protocols); } - /// Is this type any kind of existential? + /// Is this type an existential or an existential metatype? bool isAnyExistentialType() const { return isAnyExistentialTypeImpl(*this); } - /// Is this type any kind of existential? + /// Is this type an existential or an existential metatype? bool isAnyExistentialType(SmallVectorImpl &protocols) { return isAnyExistentialTypeImpl(*this, protocols); } diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp index 6b628ac4b58..06d06cae825 100644 --- a/lib/SIL/DynamicCasts.cpp +++ b/lib/SIL/DynamicCasts.cpp @@ -806,16 +806,19 @@ bool swift::emitSuccessfulIndirectUnconditionalCast(SILBuilder &B, Module *M, bool swift::canUseScalarCheckedCastInstructions(CanType sourceType, CanType targetType) { // Look through one level of optionality on the source. - auto sourceObjectType = sourceType; - if (auto type = sourceObjectType.getAnyOptionalObjectType()) - sourceObjectType = type; + auto objectType = sourceType; + if (auto type = objectType.getAnyOptionalObjectType()) + objectType = type; - // The source and destination can be metatypes or anything that - // embeds a class reference. - if ((sourceObjectType.isAnyClassReferenceType() || - isa(sourceObjectType)) && - (targetType->isAnyClassReferenceType() || - isa(targetType))) + // Three supported cases: + // - metatype to metatype + // - metatype to object + // - object to object + if ((objectType.isAnyClassReferenceType() || isa(objectType)) + && targetType->isAnyClassReferenceType()) + return true; + + if (isa(objectType) && isa(targetType)) return true; // Otherwise, we need to use the general indirect-cast functions. diff --git a/test/SILGen/metatype_casts.swift b/test/SILGen/metatype_casts.swift index 9f0736c70a0..300bc56cf8d 100644 --- a/test/SILGen/metatype_casts.swift +++ b/test/SILGen/metatype_casts.swift @@ -14,7 +14,7 @@ func int_is_t() -> (Bool, T.Type?, T.Type) { return (Int.self is T.Type, Int.self as? T.Type, Int.self as! T.Type) } -// CHECK-LABEL: sil hidden @_TF14metatype_casts8t_is_inturFq_TSbGSqMSi_MSi_ : $@convention(thin) (@in T) +// CHECK-LABEL: sil hidden @_TF14metatype_casts8t_is_inturFq_TSbGSqMSi_MSi_ : $@convention(thin) (@in T) func t_is_int(_: T) -> (Bool, Int.Type?, Int.Type) { // CHECK: checked_cast_br {{%.*}} : $@thick T.Type to $@thick Int.Type // CHECK: checked_cast_br {{%.*}} : $@thick T.Type to $@thick Int.Type @@ -22,4 +22,19 @@ func t_is_int(_: T) -> (Bool, Int.Type?, Int.Type) { return (T.self is Int.Type, T.self as? Int.Type, T.self as! Int.Type) } +// Mixed metatype casts take the slow path via *_cast_addr +protocol Emergency {} +class Ambulance : Emergency {} +class FashionPolice {} +// CHECK-LABEL: sil hidden @_TF14metatype_casts30anyObjectToExistentialMetatypeFPSs9AnyObject_GSqPMPS_9Emergency__ : $@convention(thin) (@owned AnyObject) -> Optional +func anyObjectToExistentialMetatype(o: AnyObject) -> Emergency.Type? { + // CHECK: checked_cast_addr_br take_always AnyObject in {{%.*}} : $*AnyObject to Emergency.Type in {{%.*}} + return o as? Emergency.Type +} + +// CHECK-LABEL: sil hidden @_TF14metatype_casts19anyObjectToMetatypeFPSs9AnyObject_GSqMCS_13FashionPolice_ : $@convention(thin) (@owned AnyObject) -> Optional +func anyObjectToMetatype(o: AnyObject) -> FashionPolice.Type? { + // CHECK: checked_cast_addr_br take_always AnyObject in {{%.*}} : $*AnyObject to FashionPolice.Type in {{%.*}} + return o as? FashionPolice.Type +}