@@ -225,14 +225,103 @@ static CanType getHashableExistentialType(ModuleDecl *M) {
225225 return hashable->getDeclaredInterfaceType ()->getCanonicalType ();
226226}
227227
228- static bool canBeExistential (CanType ty) {
229- // If ty is an archetype, conservatively assume it's an existential.
230- return ty.isAnyExistentialType () || ty->is <ArchetypeType>();
231- }
228+ // Returns true if casting \p sourceFormalType to \p targetFormalType preserves
229+ // ownership.
230+ //
231+ // Casting preserves ownership when all references from the source value are
232+ // forwarded into the result value (without unbalanced retains or releases).
233+ //
234+ // When both the source and target types of checked-cast preserve ownership,
235+ // then the cast is compatible with guaranteed ownership. A guaranteed
236+ // compatible cast cannot release any references within its operand's value
237+ // and cannot retain any references owned by its result.
238+ //
239+ // A type's ownership might not be preserved by a dynamic cast if it is either
240+ // (A) a potentially bridged value
241+ // or
242+ // (B) potentially wrapped in a transparent type, which is equivalent to
243+ // isPotentiallyAnyObject()
244+ //
245+ // Given:
246+ // let source: sourceType
247+ // let dest = source as! targetType
248+ //
249+ // Ownership conversion happens when
250+ //
251+ // (A) one type is a bridged value and the other is an object:
252+ //
253+ // (A1) Boxing: <trivial> as! Object instantiates references in Object
254+ // Presumably, Object's type must be class-bound, but this is not
255+ // currently checked.
256+ //
257+ // (A2) Unboxing: Object as! <trivial> destroys references in Object
258+ // Object may be any type that can hold an object, including
259+ // non-class-bound archetypes and existentials.
260+ //
261+ // (B) one type is transparently wrapped in __SwiftValue, while the other is
262+ // unwrapped. Given:
263+ //
264+ // class C : Hashable {}
265+ // let a = AnyHashable(C())
266+ //
267+ // (B1) When the substituted source type is AnyHashable and the
268+ // substituted destination type is AnyObject, the cast
269+ // instantiates an owned __SwiftValue:
270+ //
271+ // // instantiates __SwiftValue
272+ // let b = a as! AnyObject
273+ // or
274+ // let b = a as! T where T.self == AnyObject.self
275+ //
276+ // (B2) When the substituted source type is Any or AnyObject, and the
277+ // substituted destination type is not Any or AnyObject, the cast
278+ // releases the owned __SwiftValue:
279+ //
280+ // let c = b as! C // releases __SwiftValue
281+ //
282+ // After unwrapping Optional, the type may fall into one one of
283+ // the following categories that are relevant for cast ownership:
284+ //
285+ // Class-bound types (hasReferenceSemantics() && !isPotentiallyAnyObject())
286+ // - includes classes, class-bound existentials other than AnyObject,
287+ // class-bound archetypes with a superclass or protocol constraint,
288+ // objc types, blocks, Builtin.NativeObject, etc.
289+ // - excludes any type that are potentially AnyObject after substitution
290+ // - the value is a single reference
291+ // - the single reference is "known unwrapped". It never transparently wraps the
292+ // underlying dynamically typed value in another type, such as __SwiftValue
293+ // - casting directly forwards the reference
294+ //
295+ // Potentially bridged values:
296+ // - includes struct, enum, non-class archetype, non-class existential,
297+ // and non-objc-metatype
298+ // - these types are potentially trivial after subsitution. If so, then they
299+ // convert to a reference when casting to AnyObject or certain classes
300+ //
301+ // Any and AnyObject existentials:
302+ // - although called existentials, their type is a protocol composition
303+ // - these do not include existentials with constraints
304+ // - these are very special types, unlike normal existentials...
305+ // - the immediately erased value may itself be an existential
306+ // (an AnyObject existential can be wrapped within an Any existential!)
307+ // - the underlying dynamically typed value may be transparently wrapped in
308+ // __SwiftValue
309+ //
310+ // These type categories are disjoint, except that a non-class archetype is both
311+ // potentially bridged and potentially Any or AnyObject after substitution.
312+ //
313+ // TODO: In the future, when the runtime stops wrapping nontrivial types inside
314+ // __SwiftValue, cases (B1) and (B2) above will no longer apply. At that time,
315+ // expand ownership preserving cast types to AnyObject. Then remove the
316+ // isPotentiallyAnyObject() check.
317+ bool swift::doesCastPreserveOwnershipForTypes (SILModule &module ,
318+ CanType sourceType,
319+ CanType targetType) {
320+ if (!canIRGenUseScalarCheckedCastInstructions (module , sourceType, targetType))
321+ return false ;
232322
233- static bool canBeClass (CanType ty) {
234- // If ty is an archetype, conservatively assume it's an existential.
235- return ty.getClassOrBoundGenericClass () || ty->is <ArchetypeType>();
323+ return !sourceType->isPotentiallyAnyObject ()
324+ && !targetType->isPotentiallyAnyObject ();
236325}
237326
238327bool SILDynamicCastInst::isRCIdentityPreserving () const {
@@ -247,26 +336,12 @@ bool SILDynamicCastInst::isRCIdentityPreserving() const {
247336 // would get confused and might eliminate a retain of such an object
248337 // completely.
249338 SILFunction &f = *getFunction ();
250- if (getSourceLoweredType ().isTrivial (f) != getTargetLoweredType ().isTrivial (f))
251- return false ;
252-
253- CanType source = getSourceFormalType ();
254- CanType target = getTargetFormalType ();
255-
256- // An existential may be holding a reference to a bridgeable struct.
257- // In this case, ARC on the existential affects the refcount of the container
258- // holding the struct, not the class to which the struct is bridged.
259- // Therefore, don't assume RC identity when casting between existentials and
260- // classes (and also between two existentials).
261- if (canBeExistential (source) &&
262- (canBeClass (target) || canBeExistential (target)))
263- return false ;
264-
265- // And vice versa.
266- if (canBeClass (source) && canBeExistential (target))
267- return false ;
268-
269- return true ;
339+ if (getSourceLoweredType ().isTrivial (f)
340+ && getTargetLoweredType ().isTrivial (f)) {
341+ return true ;
342+ }
343+ return doesCastPreserveOwnershipForTypes (f.getModule (), getSourceFormalType (),
344+ getTargetFormalType ());
270345}
271346
272347// / Check if a given type conforms to _BridgedToObjectiveC protocol.
@@ -1204,15 +1279,29 @@ bool swift::emitSuccessfulIndirectUnconditionalCast(
12041279}
12051280
12061281// / Can the given cast be performed by the scalar checked-cast
1207- // / instructions?
1282+ // / instructions at the current SIL stage ?
12081283// /
1209- // / TODO: in OSSA-with-opaque-values SIL, all casts could be modeled using
1210- // / scalar casts by setting 'OwnershipForwardingMixin::directlyForwards =
1211- // / false'. This would simplify SIL analysis. Temporaries would be emitted
1212- // / during address lowering.
1213- bool swift::canUseScalarCheckedCastInstructions (SILModule &M,
1214- CanType sourceFormalType,
1215- CanType targetFormalType) {
1284+ // / FIXME: Always return true for !useLoweredAddresses: Scalar casts are always
1285+ // / valid for owned values. If the operand is +1, the case will always destroy
1286+ // / or forward it. The result is always either +1 or trivial. The cast never
1287+ // / hides a copy. doesCastPreserveOwnershipForTypes determines whether the
1288+ // / scalar cast is also compatible with guaranteed values.
1289+ bool swift::canSILUseScalarCheckedCastInstructions (SILModule &M,
1290+ CanType sourceFormalType,
1291+ CanType targetFormalType) {
1292+ if (M.useLoweredAddresses ())
1293+ return canIRGenUseScalarCheckedCastInstructions (M, sourceFormalType,
1294+ targetFormalType);
1295+
1296+ return
1297+ doesCastPreserveOwnershipForTypes (M, sourceFormalType, targetFormalType);
1298+ }
1299+
1300+ // / Can the given cast be performed by the scalar checked-cast
1301+ // / instructions?
1302+ bool swift::canIRGenUseScalarCheckedCastInstructions (SILModule &M,
1303+ CanType sourceFormalType,
1304+ CanType targetFormalType) {
12161305 // Look through one level of optionality on the source.
12171306 auto objectType = sourceFormalType;
12181307 if (auto type = objectType.getOptionalObjectType ())
@@ -1278,8 +1367,9 @@ void swift::emitIndirectConditionalCastWithScalar(
12781367 SILValue destAddr, CanType targetFormalType,
12791368 SILBasicBlock *indirectSuccBB, SILBasicBlock *indirectFailBB,
12801369 ProfileCounter TrueCount, ProfileCounter FalseCount) {
1281- assert (canUseScalarCheckedCastInstructions (B.getModule (),
1282- sourceFormalType, targetFormalType));
1370+ assert (canSILUseScalarCheckedCastInstructions (B.getModule (),
1371+ sourceFormalType,
1372+ targetFormalType));
12831373
12841374 // Create our successor and fail blocks.
12851375 SILBasicBlock *scalarFailBB = B.splitBlockForFallthrough ();
0 commit comments