static bool verifySILSelfParameterType(SILDeclRef DeclRef, SILFunction *F, CanSILFunctionType FTy) { SILModule &M = F->getModule(); SILParameterInfo PInfo = FTy->getSelfParameter(); CanType CTy = PInfo.getType(); SILType Ty = SILType::getPrimitiveObjectType(CTy); // We do not care about trivial parameters (for now). There seem to be // cases where we lower them as unowned. // // *NOTE* We do not run this check when we have a generic type since // *generic types do not have type lowering and are always treated as // *non-trivial since we do not know the type. if (CTy->hasArchetype() || CTy->hasTypeParameter() || M.getTypeLowering(Ty).isTrivial()) return true; // If this function is a constructor or destructor, bail. These have @owned // parameters. if (DeclRef.isConstructor() || DeclRef.isDestructor()) return true; // Otherwise, if this function type has a guaranteed self parameter type, // make sure that we have a +0 self param. return !FTy->getExtInfo().hasGuaranteedSelfParam() || PInfo.isGuaranteed() || PInfo.isIndirectMutating(); }
static bool mustBridgeToSwiftValueBox(Module *M, CanType T) { // If the target type is either an unknown dynamic type, or statically // known to bridge, the cast may succeed. if (T->hasArchetype()) return false; if (T->isAnyExistentialType()) return false; // getBridgedToObjC() might return a null-type for bridged foundation types // during compiling the standard library. Exclude this case here. if (auto N = T->getAnyNominal()) if (M->getASTContext().isStandardLibraryTypeBridgedInFoundation(N)) return false; auto bridgeTy = M->getASTContext().getBridgedToObjC(M, T, nullptr); if (!bridgeTy.hasValue()) return false; if (bridgeTy->isNull()) return true; return false; }
void OutliningMetadataCollector::collectFormalTypeMetadata(CanType type) { // If the type has no archetypes, we can emit it from scratch in the callee. assert(type->hasArchetype()); auto key = LocalTypeDataKey(type, LocalTypeDataKind::forFormalTypeMetadata()); if (Values.count(key)) return; auto metadata = IGF.emitTypeMetadataRef(type); Values.insert({key, metadata}); }
/// Add a 32-bit relative offset to a mangled typeref string /// in the typeref reflection section. void addTypeRef(Module *ModuleContext, CanType type) { assert(type); // Generic parameters should be written in terms of interface types // for the purposes of reflection metadata assert(!type->hasArchetype() && "Forgot to map typeref out of context"); Mangle::Mangler mangler(/*DWARFMangling*/false, /*usePunyCode*/ true, /*OptimizeProtocolNames*/ false); mangler.setModuleContext(ModuleContext); mangler.mangleType(type, 0); auto mangledName = IGM.getAddrOfStringForTypeRef(mangler.finalize()); addRelativeAddress(mangledName); }
static bool mayBridgeToObjectiveC(Module *M, CanType T) { // If the target type is either an unknown dynamic type, or statically // known to bridge, the cast may succeed. // TODO: We could be more precise with the bridged-to type. if (T->hasArchetype()) return true; if (T->isAnyExistentialType()) return true; if (M->getASTContext().getBridgedToObjC(M, T, nullptr)) return true; return false; }
static bool mustBridgeToSwiftValueBox(ModuleDecl *M, CanType T) { // If the target type is either an unknown dynamic type, or statically // known to bridge, the cast may succeed. if (T->hasArchetype()) return false; if (T->isAnyExistentialType()) return false; // getBridgedToObjC() might return a null-type for some types // whose bridging implementation is allowed to live elsewhere. Exclude this // case here. if (auto N = T->getAnyNominal()) if (M->getASTContext().isTypeBridgedInExternalModule(N)) return false; return !M->getASTContext().getBridgedToObjC(M, T); }
/// Add a 32-bit relative offset to a mangled typeref string /// in the typeref reflection section. void addTypeRef(ModuleDecl *ModuleContext, CanType type, CanGenericSignature Context = {}) { assert(type); // Generic parameters should be written in terms of interface types // for the purposes of reflection metadata assert(!type->hasArchetype() && "Forgot to map typeref out of context"); // TODO: As a compatibility hack, mangle single-field boxes with the legacy // mangling in reflection metadata. bool isSingleFieldOfBox = false; auto boxTy = dyn_cast<SILBoxType>(type); if (boxTy && boxTy->getLayout()->getFields().size() == 1) { GenericContextScope scope(IGM, Context); type = boxTy->getFieldLoweredType(IGM.getSILModule(), 0); isSingleFieldOfBox = true; } IRGenMangler mangler; std::string MangledStr = mangler.mangleTypeForReflection(type, ModuleContext, isSingleFieldOfBox); auto mangledName = IGM.getAddrOfStringForTypeRef(MangledStr); addRelativeAddress(mangledName); }
void LocalTypeDataCache:: addAbstractForFulfillments(IRGenFunction &IGF, FulfillmentMap &&fulfillments, llvm::function_ref<AbstractSource()> createSource) { // Add the source lazily. Optional<unsigned> sourceIndex; auto getSourceIndex = [&]() -> unsigned { if (!sourceIndex) { AbstractSources.emplace_back(createSource()); sourceIndex = AbstractSources.size() - 1; } return *sourceIndex; }; for (auto &fulfillment : fulfillments) { CanType type = CanType(fulfillment.first.first); LocalTypeDataKind localDataKind; // For now, ignore witness-table fulfillments when they're not for // archetypes. if (ProtocolDecl *protocol = fulfillment.first.second) { if (auto archetype = dyn_cast<ArchetypeType>(type)) { auto conformsTo = archetype->getConformsTo(); auto it = std::find(conformsTo.begin(), conformsTo.end(), protocol); if (it == conformsTo.end()) continue; localDataKind = LocalTypeDataKind::forAbstractProtocolWitnessTable(*it); } else { continue; } } else { // Ignore type metadata fulfillments for non-dependent types that // we can produce very cheaply. We don't want to end up emitting // the type metadata for Int by chasing through N layers of metadata // just because that path happens to be in the cache. if (!type->hasArchetype() && isTypeMetadataAccessTrivial(IGF.IGM, type)) { continue; } localDataKind = LocalTypeDataKind::forTypeMetadata(); } // Find the chain for the key. auto key = getKey(type, localDataKind); auto &chain = Map[key]; // Check whether there's already an entry that's at least as good as the // fulfillment. Optional<unsigned> fulfillmentCost; auto getFulfillmentCost = [&]() -> unsigned { if (!fulfillmentCost) fulfillmentCost = fulfillment.second.Path.cost(); return *fulfillmentCost; }; bool isConditional = IGF.isConditionalDominancePoint(); bool foundBetter = false; for (CacheEntry *cur = chain.Root, *last = nullptr; cur; last = cur, cur = cur->getNext()) { // Ensure the entry is acceptable. if (!IGF.isActiveDominancePointDominatedBy(cur->DefinitionPoint)) continue; // Ensure that the entry isn't better than the fulfillment. auto curCost = cur->cost(); if (curCost == 0 || curCost <= getFulfillmentCost()) { foundBetter = true; break; } // If the entry is defined at the current point, (1) we know there // won't be a better entry and (2) we should remove it. if (cur->DefinitionPoint == IGF.getActiveDominancePoint() && !isConditional) { // Splice it out of the chain. assert(!cur->isConditional()); chain.eraseEntry(last, cur); break; } } if (foundBetter) continue; // Okay, make a new entry. // Register with the conditional dominance scope if necessary. if (isConditional) { IGF.registerConditionalLocalTypeDataKey(key); } // Allocate the new entry. auto newEntry = new AbstractCacheEntry(IGF.getActiveDominancePoint(), isConditional, getSourceIndex(), std::move(fulfillment.second.Path)); // Add it to the front of the chain. chain.push_front(newEntry); } }
/// Try to classify the dynamic-cast relationship between two types. DynamicCastFeasibility swift::classifyDynamicCast(ModuleDecl *M, CanType source, CanType target, bool isSourceTypeExact, bool isWholeModuleOpts) { if (source == target) return DynamicCastFeasibility::WillSucceed; auto sourceObject = source.getOptionalObjectType(); auto targetObject = target.getOptionalObjectType(); // A common level of optionality doesn't affect the feasibility, // except that we can't fold things to failure because nil inhabits // both types. if (sourceObject && targetObject) { return atWorst(classifyDynamicCast(M, sourceObject, targetObject), DynamicCastFeasibility::MaySucceed); // Casting to a more optional type follows the same rule unless we // know that the source cannot dynamically be an optional value, // in which case we'll always just cast and inject into an optional. } else if (targetObject) { auto result = classifyDynamicCast(M, source, targetObject, /* isSourceTypeExact */ false, isWholeModuleOpts); if (canDynamicallyStoreOptional(source)) result = atWorst(result, DynamicCastFeasibility::MaySucceed); return result; // Casting to a less-optional type can always fail. } else if (sourceObject) { return atBest(classifyDynamicCast(M, sourceObject, target, /* isSourceTypeExact */ false, isWholeModuleOpts), DynamicCastFeasibility::MaySucceed); } assert(!sourceObject && !targetObject); // Assume that casts to or from existential types or involving // dependent types can always succeed. This is over-conservative. if (source->hasArchetype() || source.isExistentialType() || target->hasArchetype() || target.isExistentialType()) { // Check conversions from non-protocol types into protocol types. if (!source.isExistentialType() && target.isExistentialType()) return classifyDynamicCastToProtocol(M, source, target, isWholeModuleOpts); // Check conversions from protocol types to non-protocol types. if (source.isExistentialType() && !target.isExistentialType()) return classifyDynamicCastFromProtocol(M, source, target, isWholeModuleOpts); return DynamicCastFeasibility::MaySucceed; } // Casts from AnyHashable. if (auto sourceStruct = dyn_cast<StructType>(source)) { if (sourceStruct->getDecl() == M->getASTContext().getAnyHashableDecl()) { if (auto hashable = getHashableExistentialType(M)) { // Succeeds if Hashable can be cast to the target type. return classifyDynamicCastFromProtocol(M, hashable, target, isWholeModuleOpts); } } } // Casts to AnyHashable. if (auto targetStruct = dyn_cast<StructType>(target)) { if (targetStruct->getDecl() == M->getASTContext().getAnyHashableDecl()) { // Succeeds if the source type can be dynamically cast to Hashable. // Hashable is not actually a legal existential type right now, but // the check doesn't care about that. if (auto hashable = getHashableExistentialType(M)) { return classifyDynamicCastToProtocol(M, source, hashable, isWholeModuleOpts); } } } // Metatype casts. if (auto sourceMetatype = dyn_cast<AnyMetatypeType>(source)) { auto targetMetatype = dyn_cast<AnyMetatypeType>(target); if (!targetMetatype) return DynamicCastFeasibility::WillFail; source = sourceMetatype.getInstanceType(); target = targetMetatype.getInstanceType(); if (source == target && targetMetatype.isAnyExistentialType() == sourceMetatype.isAnyExistentialType()) return DynamicCastFeasibility::WillSucceed; // If the source and target are the same existential type, but the source is // P.Protocol and the dest is P.Type, then we need to consider whether the // protocol is self-conforming. // The only cases where a protocol self-conforms are objc protocols, but // we're going to expect P.Type to hold a class object. And this case // doesn't matter since for a self-conforming protocol type there can't be // any type-level methods. // Thus we consider this kind of cast to always fail. The only exception // from this rule is when the target is Any.Type, because *.Protocol // can always be casted to Any.Type. if (source->isAnyExistentialType() && isa<MetatypeType>(sourceMetatype) && isa<ExistentialMetatypeType>(targetMetatype)) { return target->isAny() ? DynamicCastFeasibility::WillSucceed : DynamicCastFeasibility::WillFail; } if (targetMetatype.isAnyExistentialType() && (isa<ProtocolType>(target) || isa<ProtocolCompositionType>(target))) { auto Feasibility = classifyDynamicCastToProtocol(M, source, target, isWholeModuleOpts); // Cast from existential metatype to existential metatype may still // succeed, even if we cannot prove anything statically. if (Feasibility != DynamicCastFeasibility::WillFail || !sourceMetatype.isAnyExistentialType()) return Feasibility; } // If isSourceTypeExact is true, we know we are casting the result of a // MetatypeInst instruction. if (isSourceTypeExact) { // If source or target are existentials, then it can be cast // successfully only into itself. if ((target.isAnyExistentialType() || source.isAnyExistentialType()) && target != source) return DynamicCastFeasibility::WillFail; } // Casts from class existential metatype into a concrete non-class metatype // can never succeed. if (source->isClassExistentialType() && !target.isAnyExistentialType() && !target.getClassOrBoundGenericClass()) return DynamicCastFeasibility::WillFail; // TODO: prove that some conversions to existential metatype will // obviously succeed/fail. // TODO: prove that some conversions from class existential metatype // to a concrete non-class metatype will obviously fail. // TODO: class metatype to/from AnyObject // TODO: protocol concrete metatype to/from ObjCProtocol if (isa<ExistentialMetatypeType>(sourceMetatype) || isa<ExistentialMetatypeType>(targetMetatype)) return (getAnyMetatypeDepth(source) == getAnyMetatypeDepth(target) ? DynamicCastFeasibility::MaySucceed : DynamicCastFeasibility::WillFail); // If both metatypes are class metatypes, check if classes can be // cast. if (source.getClassOrBoundGenericClass() && target.getClassOrBoundGenericClass()) return classifyClassHierarchyCast(source, target); // Different structs cannot be cast to each other. if (source.getStructOrBoundGenericStruct() && target.getStructOrBoundGenericStruct() && source != target) return DynamicCastFeasibility::WillFail; // Different enums cannot be cast to each other. if (source.getEnumOrBoundGenericEnum() && target.getEnumOrBoundGenericEnum() && source != target) return DynamicCastFeasibility::WillFail; // If we don't know any better, assume that the cast may succeed. return DynamicCastFeasibility::MaySucceed; } // Function casts. if (auto sourceFunction = dyn_cast<FunctionType>(source)) { if (auto targetFunction = dyn_cast<FunctionType>(target)) { // A function cast can succeed if the function types can be identical, // or if the target type is throwier than the original. // A non-throwing source function can be cast to a throwing target type, // but not vice versa. if (sourceFunction->throws() && !targetFunction->throws()) return DynamicCastFeasibility::WillFail; // The cast can't change the representation at runtime. if (targetFunction->getRepresentation() != sourceFunction->getRepresentation()) return DynamicCastFeasibility::WillFail; if (sourceFunction.getInput() == targetFunction.getInput() && sourceFunction.getResult() == targetFunction.getResult()) return DynamicCastFeasibility::WillSucceed; auto isSubstitutable = [](CanType a, CanType b) -> bool { // FIXME: Unnecessarily conservative; should structurally check for // substitutability. return a == b || a->hasArchetype() || b->hasArchetype(); }; if (isSubstitutable(sourceFunction.getInput(), targetFunction.getInput()) && isSubstitutable(targetFunction.getInput(), targetFunction.getResult())) return DynamicCastFeasibility::MaySucceed; return DynamicCastFeasibility::WillFail; } } // Tuple casts. if (auto sourceTuple = dyn_cast<TupleType>(source)) { if (auto targetTuple = dyn_cast<TupleType>(target)) { // # of elements must coincide. if (sourceTuple->getNumElements() != targetTuple->getNumElements()) return DynamicCastFeasibility::WillFail; DynamicCastFeasibility result = DynamicCastFeasibility::WillSucceed; for (unsigned i : range(sourceTuple->getNumElements())) { const auto &sourceElt = sourceTuple->getElement(i); const auto &targetElt = targetTuple->getElement(i); // If both have names and the names mismatch, the cast will fail. if (sourceElt.hasName() && targetElt.hasName() && sourceElt.getName() != targetElt.getName()) return DynamicCastFeasibility::WillFail; // Combine the result of prior elements with this element type. result = std::max(result, classifyDynamicCast(M, sourceElt.getType()->getCanonicalType(), targetElt.getType()->getCanonicalType(), isSourceTypeExact, isWholeModuleOpts)); // If this element failed, we're done. if (result == DynamicCastFeasibility::WillFail) break; } return result; } } // Class casts. auto sourceClass = source.getClassOrBoundGenericClass(); auto targetClass = target.getClassOrBoundGenericClass(); if (sourceClass) { if (targetClass) { // Imported Objective-C generics don't check the generic parameters, which // are lost at runtime. if (sourceClass->usesObjCGenericsModel()) { if (sourceClass == targetClass) return DynamicCastFeasibility::WillSucceed; if (targetClass->usesObjCGenericsModel()) { // If both classes are ObjC generics, the cast may succeed if the // classes are related, irrespective of their generic parameters. auto isDeclSuperclass = [&](ClassDecl *proposedSuper, ClassDecl *proposedSub) -> bool { do { if (proposedSuper == proposedSub) return true; } while ((proposedSub = proposedSub->getSuperclassDecl())); return false; }; if (isDeclSuperclass(sourceClass, targetClass)) return DynamicCastFeasibility::MaySucceed; if (isDeclSuperclass(targetClass, sourceClass)) { return DynamicCastFeasibility::WillSucceed; } return DynamicCastFeasibility::WillFail; } } // Try a hierarchy cast. If that isn't failure, we can report it. auto hierarchyResult = classifyClassHierarchyCast(source, target); if (hierarchyResult != DynamicCastFeasibility::WillFail) return hierarchyResult; // As a backup, consider whether either type is a CF class type // with an NS bridged equivalent. CanType bridgedSource = getNSBridgedClassOfCFClass(M, source); CanType bridgedTarget = getNSBridgedClassOfCFClass(M, target); // If neither type qualifies, we're done. if (!bridgedSource && !bridgedTarget) return DynamicCastFeasibility::WillFail; // Otherwise, map over to the bridged types and try to answer the // question there. if (bridgedSource) source = bridgedSource; if (bridgedTarget) target = bridgedTarget; return classifyDynamicCast(M, source, target, false, isWholeModuleOpts); } // Casts from a class into a non-class can never succeed if the target must // be bridged to a SwiftValueBox. You would need an AnyObject source for // that. if (!target.isAnyExistentialType() && !target.getClassOrBoundGenericClass() && !isa<ArchetypeType>(target) && mustBridgeToSwiftValueBox(M, target)) { assert((target.getEnumOrBoundGenericEnum() || target.getStructOrBoundGenericStruct() || isa<TupleType>(target) || isa<SILFunctionType>(target) || isa<FunctionType>(target) || isa<MetatypeType>(target)) && "Target should be an enum, struct, tuple, metatype or function type"); return DynamicCastFeasibility::WillFail; } // In the Objective-C runtime, class metatypes are also class instances. // The cast may succeed if the target type can be inhabited by a class // metatype. // TODO: Narrow this to the sourceClass being exactly NSObject. if (M->getASTContext().LangOpts.EnableObjCInterop) { if (auto targetMeta = dyn_cast<MetatypeType>(target)) { if (isa<ArchetypeType>(targetMeta.getInstanceType()) || targetMeta.getInstanceType()->mayHaveSuperclass()) return DynamicCastFeasibility::MaySucceed; } else if (isa<ExistentialMetatypeType>(target)) { return DynamicCastFeasibility::MaySucceed; } } } // If the source is not existential, an archetype, or (under the ObjC runtime) // a class, and the destination is a metatype, there is no way the cast can // succeed. if (target->is<AnyMetatypeType>()) return DynamicCastFeasibility::WillFail; // FIXME: Be more careful with bridging conversions from // NSArray, NSDictionary and NSSet as they may fail? // We know that a cast from Int -> class foobar will fail. if (targetClass && !source.isAnyExistentialType() && !source.getClassOrBoundGenericClass() && !isa<ArchetypeType>(source) && mustBridgeToSwiftValueBox(M, source)) { assert((source.getEnumOrBoundGenericEnum() || source.getStructOrBoundGenericStruct() || isa<TupleType>(source) || isa<SILFunctionType>(source) || isa<FunctionType>(source) || isa<MetatypeType>(source)) && "Source should be an enum, struct, tuple, metatype or function type"); return DynamicCastFeasibility::WillFail; } // Check if there might be a bridging conversion. if (source->isBridgeableObjectType() && mayBridgeToObjectiveC(M, target)) { // Try to get the ObjC type which is bridged to target type. assert(!target.isAnyExistentialType()); // ObjC-to-Swift casts may fail. And in most cases it is impossible to // statically predict the outcome. So, let's be conservative here. return DynamicCastFeasibility::MaySucceed; } if (target->isBridgeableObjectType() && mayBridgeToObjectiveC(M, source)) { // Try to get the ObjC type which is bridged to source type. assert(!source.isAnyExistentialType()); if (Type ObjCTy = M->getASTContext().getBridgedToObjC(M, source)) { // If the bridged ObjC type is known, check if // this type can be cast into target type. return classifyDynamicCast(M, ObjCTy->getCanonicalType(), target, /* isSourceTypeExact */ false, isWholeModuleOpts); } return DynamicCastFeasibility::MaySucceed; } // Check if it is a cast between bridged error types. if (isError(M, source) && isError(M, target)) { // TODO: Cast to NSError succeeds always. return DynamicCastFeasibility::MaySucceed; } // Check for a viable collection cast. if (auto sourceStruct = dyn_cast<BoundGenericStructType>(source)) { if (auto targetStruct = dyn_cast<BoundGenericStructType>(target)) { // Both types have to be the same kind of collection. auto typeDecl = sourceStruct->getDecl(); if (typeDecl == targetStruct->getDecl()) { auto sourceArgs = sourceStruct.getGenericArgs(); auto targetArgs = targetStruct.getGenericArgs(); // Note that we can never say that a collection cast is impossible: // a cast can always succeed on an empty collection. // Arrays and sets. if (typeDecl == M->getASTContext().getArrayDecl() || typeDecl == M->getASTContext().getSetDecl()) { auto valueFeasibility = classifyDynamicCast(M, sourceArgs[0], targetArgs[0]); return atWorst(valueFeasibility, DynamicCastFeasibility::MaySucceed); // Dictionaries. } else if (typeDecl == M->getASTContext().getDictionaryDecl()) { auto keyFeasibility = classifyDynamicCast(M, sourceArgs[0], targetArgs[0]); auto valueFeasibility = classifyDynamicCast(M, sourceArgs[1], targetArgs[1]); return atWorst(atBest(keyFeasibility, valueFeasibility), DynamicCastFeasibility::MaySucceed); } } } } return DynamicCastFeasibility::WillFail; }
/// Try to classify the dynamic-cast relationship between two types. DynamicCastFeasibility swift::classifyDynamicCast(Module *M, CanType source, CanType target, bool isSourceTypeExact, bool isWholeModuleOpts) { if (source == target) return DynamicCastFeasibility::WillSucceed; auto sourceObject = source.getAnyOptionalObjectType(); auto targetObject = target.getAnyOptionalObjectType(); // A common level of optionality doesn't affect the feasibility. if (sourceObject && targetObject) { return classifyDynamicCast(M, sourceObject, targetObject); // Nor does casting to a more optional type. } else if (targetObject) { return classifyDynamicCast(M, source, targetObject, /* isSourceTypeExact */ false, isWholeModuleOpts); // Casting to a less-optional type can always fail. } else if (sourceObject) { return weakenSuccess(classifyDynamicCast(M, sourceObject, target, /* isSourceTypeExact */ false, isWholeModuleOpts)); } assert(!sourceObject && !targetObject); // Assume that casts to or from existential types or involving // dependent types can always succeed. This is over-conservative. if (source->hasArchetype() || source.isExistentialType() || target->hasArchetype() || target.isExistentialType()) { auto *SourceNominalTy = source.getAnyNominal(); // Check conversions from non-protocol types into protocol types. if (!source.isExistentialType() && SourceNominalTy && target.isExistentialType()) return classifyDynamicCastToProtocol(source, target, isWholeModuleOpts); // Casts from class existential into a non-class can never succeed. if (source->isClassExistentialType() && !target.isAnyExistentialType() && !target.getClassOrBoundGenericClass() && !isa<ArchetypeType>(target) && !mayBridgeToObjectiveC(M, target)) { assert((target.getEnumOrBoundGenericEnum() || target.getStructOrBoundGenericStruct() || isa<TupleType>(target) || isa<SILFunctionType>(target) || isa<FunctionType>(target) || isa<MetatypeType>(target)) && "Target should be an enum, struct, tuple, metatype or function type"); return DynamicCastFeasibility::WillFail; } return DynamicCastFeasibility::MaySucceed; } // Metatype casts. if (auto sourceMetatype = dyn_cast<AnyMetatypeType>(source)) { auto targetMetatype = dyn_cast<AnyMetatypeType>(target); if (!targetMetatype) return DynamicCastFeasibility::WillFail; source = sourceMetatype.getInstanceType(); target = targetMetatype.getInstanceType(); if (source == target && targetMetatype.isAnyExistentialType() == sourceMetatype.isAnyExistentialType()) return DynamicCastFeasibility::WillSucceed; if (targetMetatype.isAnyExistentialType() && (isa<ProtocolType>(target) || isa<ProtocolCompositionType>(target))) { auto Feasibility = classifyDynamicCastToProtocol(source, target, isWholeModuleOpts); // Cast from existential metatype to existential metatype may still // succeed, even if we cannot prove anything statically. if (Feasibility != DynamicCastFeasibility::WillFail || !sourceMetatype.isAnyExistentialType()) return Feasibility; } // If isSourceTypeExact is true, we know we are casting the result of a // MetatypeInst instruction. if (isSourceTypeExact) { // If source or target are existentials, then it can be cast // successfully only into itself. if ((target.isAnyExistentialType() || source.isAnyExistentialType()) && target != source) return DynamicCastFeasibility::WillFail; } // Casts from class existential metatype into a concrete non-class metatype // can never succeed. if (source->isClassExistentialType() && !target.isAnyExistentialType() && !target.getClassOrBoundGenericClass()) return DynamicCastFeasibility::WillFail; // TODO: prove that some conversions to existential metatype will // obviously succeed/fail. // TODO: prove that some conversions from class existential metatype // to a concrete non-class metatype will obviously fail. // TODO: class metatype to/from AnyObject // TODO: protocol concrete metatype to/from ObjCProtocol if (isa<ExistentialMetatypeType>(sourceMetatype) || isa<ExistentialMetatypeType>(targetMetatype)) return (getAnyMetatypeDepth(source) == getAnyMetatypeDepth(target) ? DynamicCastFeasibility::MaySucceed : DynamicCastFeasibility::WillFail); // If both metatypes are class metatypes, check if classes can be // cast. if (source.getClassOrBoundGenericClass() && target.getClassOrBoundGenericClass()) return classifyDynamicCast(M, source, target, false, isWholeModuleOpts); // Different structs cannot be cast to each other. if (source.getStructOrBoundGenericStruct() && target.getStructOrBoundGenericStruct() && source != target) return DynamicCastFeasibility::WillFail; // Different enums cannot be cast to each other. if (source.getEnumOrBoundGenericEnum() && target.getEnumOrBoundGenericEnum() && source != target) return DynamicCastFeasibility::WillFail; // If we don't know any better, assume that the cast may succeed. return DynamicCastFeasibility::MaySucceed; } // Function casts. if (auto sourceFunction = dyn_cast<FunctionType>(source)) { if (auto targetFunction = dyn_cast<FunctionType>(target)) { // A function cast can succeed if the function types can be identical, // or if the target type is throwier than the original. // A non-throwing source function can be cast to a throwing target type, // but not vice versa. if (sourceFunction->throws() && !targetFunction->throws()) return DynamicCastFeasibility::WillFail; // A noreturn source function can be cast to a returning target type, // but not vice versa. // (noreturn isn't really reified at runtime though.) if (targetFunction->isNoReturn() && !sourceFunction->isNoReturn()) return DynamicCastFeasibility::WillFail; // The cast can't change the representation at runtime. if (targetFunction->getRepresentation() != sourceFunction->getRepresentation()) return DynamicCastFeasibility::WillFail; if (sourceFunction.getInput() == targetFunction.getInput() && sourceFunction.getResult() == targetFunction.getResult()) return DynamicCastFeasibility::WillSucceed; auto isSubstitutable = [](CanType a, CanType b) -> bool { // FIXME: Unnecessarily conservative; should structurally check for // substitutability. return a == b || a->hasArchetype() || b->hasArchetype(); }; if (isSubstitutable(sourceFunction.getInput(), targetFunction.getInput()) && isSubstitutable(targetFunction.getInput(), targetFunction.getResult())) return DynamicCastFeasibility::MaySucceed; return DynamicCastFeasibility::WillFail; } } // Class casts. auto sourceClass = source.getClassOrBoundGenericClass(); auto targetClass = target.getClassOrBoundGenericClass(); if (sourceClass) { if (targetClass) { // Imported Objective-C generics don't check the generic parameters, which // are lost at runtime. if (sourceClass->usesObjCGenericsModel()) { if (sourceClass == targetClass) return DynamicCastFeasibility::WillSucceed; if (targetClass->usesObjCGenericsModel()) { // If both classes are ObjC generics, the cast may succeed if the // classes are related, irrespective of their generic parameters. auto isDeclSuperclass = [&](ClassDecl *proposedSuper, ClassDecl *proposedSub) -> bool { do { if (proposedSuper == proposedSub) return true; } while ((proposedSub = proposedSub->getSuperclassDecl())); return false; }; if (isDeclSuperclass(sourceClass, targetClass)) return DynamicCastFeasibility::MaySucceed; if (isDeclSuperclass(targetClass, sourceClass)) { return DynamicCastFeasibility::WillSucceed; } return DynamicCastFeasibility::WillFail; } } if (target->isExactSuperclassOf(source, nullptr)) return DynamicCastFeasibility::WillSucceed; if (target->isBindableToSuperclassOf(source, nullptr)) return DynamicCastFeasibility::MaySucceed; if (source->isBindableToSuperclassOf(target, nullptr)) return DynamicCastFeasibility::MaySucceed; // FIXME: bridged types, e.g. CF <-> NS (but not for metatypes). return DynamicCastFeasibility::WillFail; } // In the Objective-C runtime, class metatypes are also class instances. // The cast may succeed if the target type can be inhabited by a class // metatype. // TODO: Narrow this to the sourceClass being exactly NSObject. if (M->getASTContext().LangOpts.EnableObjCInterop) { if (auto targetMeta = dyn_cast<MetatypeType>(target)) { if (isa<ArchetypeType>(targetMeta.getInstanceType()) || targetMeta.getInstanceType()->mayHaveSuperclass()) return DynamicCastFeasibility::MaySucceed; } else if (isa<ExistentialMetatypeType>(target)) { return DynamicCastFeasibility::MaySucceed; } } } // If the source is not existential, an archetype, or (under the ObjC runtime) // a class, and the destination is a metatype, there is no way the cast can // succeed. if (target->is<AnyMetatypeType>()) return DynamicCastFeasibility::WillFail; // FIXME: tuple conversions? // FIXME: Be more careful with bridging conversions from // NSArray, NSDictionary and NSSet as they may fail? // Check if there might be a bridging conversion. if (source->isBridgeableObjectType() && mayBridgeToObjectiveC(M, target)) { // Try to get the ObjC type which is bridged to target type. assert(!target.isAnyExistentialType()); Optional<Type> ObjCTy = M->getASTContext().getBridgedToObjC( M, target, nullptr); if (ObjCTy && ObjCTy.getValue()) { // If the bridged ObjC type is known, check if // source type can be cast into it. return classifyDynamicCast(M, source, ObjCTy.getValue().getCanonicalTypeOrNull(), /* isSourceTypeExact */ false, isWholeModuleOpts); } return DynamicCastFeasibility::MaySucceed; } if (target->isBridgeableObjectType() && mayBridgeToObjectiveC(M, source)) { // Try to get the ObjC type which is bridged to source type. assert(!source.isAnyExistentialType()); Optional<Type> ObjCTy = M->getASTContext().getBridgedToObjC( M, source, nullptr); if (ObjCTy && ObjCTy.getValue()) { // If the bridged ObjC type is known, check if // this type can be cast into target type. return classifyDynamicCast(M, ObjCTy.getValue().getCanonicalTypeOrNull(), target, /* isSourceTypeExact */ false, isWholeModuleOpts); } return DynamicCastFeasibility::MaySucceed; } // Check if it is a cast between bridged error types. if (isError(M, source) && isError(M, target)) { // TODO: Cast to NSError succeeds always. return DynamicCastFeasibility::MaySucceed; } return DynamicCastFeasibility::WillFail; }