static bool canUnsafeCastScalars(SILType fromType, SILType toType, SILModule &M) { CanType fromCanTy = fromType.getSwiftRValueType(); bool isToPointer = toType.isPointerSizeAndAligned(); unsigned LeastFromWidth = 0; // Like UnsafeRefBitCast, allow class existentials to be truncated to // single-pointer references. Unlike UnsafeRefBitCast, this also supports raw // pointers and words. if (fromType.isPointerSizeAndAligned() || fromCanTy.isAnyClassReferenceType()) { // Allow casting from a value that contains an aligned pointer into another // pointer value regardless of the fixed width. if (isToPointer) return true; LeastFromWidth = BuiltinIntegerWidth::pointer().getLeastWidth(); } else if (auto fromIntTy = dyn_cast<BuiltinIntegerType>(fromCanTy)) { if (fromIntTy->isFixedWidth()) LeastFromWidth = fromIntTy->getFixedWidth(); } unsigned GreatestToWidth = UINT_MAX; if (isToPointer) { GreatestToWidth = BuiltinIntegerWidth::pointer().getGreatestWidth(); } else if (auto toIntTy = dyn_cast<BuiltinIntegerType>( toType.getSwiftRValueType())) { if (toIntTy->isFixedWidth()) GreatestToWidth = toIntTy->getFixedWidth(); } return LeastFromWidth >= GreatestToWidth; }
/// Can the given cast be performed by the scalar checked-cast /// instructions? bool swift::canUseScalarCheckedCastInstructions(SILModule &M, CanType sourceType, CanType targetType) { // Look through one level of optionality on the source. auto objectType = sourceType; if (auto type = objectType.getOptionalObjectType()) objectType = type; // Casting to NSError needs to go through the indirect-cast case, // since it may conform to Error and require Error-to-NSError // 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 = targetType->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) { if (auto nserror = M.Types.getNSErrorType()) return !super->isEqual(nserror); } // If NSError wasn't loaded, any base class constraint must not be NSError. return true; } if (M.getASTContext().LangOpts.EnableObjCInterop && targetType == M.Types.getNSErrorType()) { // If we statically know the source is an NSError subclass, then the cast // can go through the scalar path (and it's trivially true so can be // killed). return targetType->isExactSuperclassOf(objectType); } // Three supported cases: // - metatype to metatype // - metatype to object // - object to object if ((objectType.isAnyClassReferenceType() || isa<AnyMetatypeType>(objectType)) && targetType.isAnyClassReferenceType()) return true; if (isa<AnyMetatypeType>(objectType) && isa<AnyMetatypeType>(targetType)) return true; // Otherwise, we need to use the general indirect-cast functions. return false; }
/// Given that a type is not statically known to be an optional type, check whether /// it might dynamically be an optional type. static bool canDynamicallyBeOptionalType(CanType type) { assert(!type.getAnyOptionalObjectType()); return (isa<ArchetypeType>(type) || type.isExistentialType()) && !type.isAnyClassReferenceType(); }