/// Specialized emitter for Builtin.castReference. static ManagedValue emitBuiltinCastReference(SILGenFunction &gen, SILLocation loc, ArrayRef<Substitution> substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { assert(args.size() == 1 && "castReference should be given one argument"); assert(substitutions.size() == 2 && "castReference should have two subs"); auto fromTy = substitutions[0].getReplacement(); auto toTy = substitutions[1].getReplacement(); auto &fromTL = gen.getTypeLowering(fromTy); auto &toTL = gen.getTypeLowering(toTy); assert(!fromTL.isTrivial() && !toTL.isTrivial() && "expected ref type"); if (fromTL.isLoadable() || toTL.isLoadable()) { if (auto refCast = gen.B.tryCreateUncheckedRefCast(loc, args[0].getValue(), toTL.getLoweredType())) { // Create a reference cast, forwarding the cleanup. // The cast takes the source reference. return ManagedValue(refCast, args[0].getCleanup()); } } // We are either casting between address-only types, or cannot promote to a // cast of reference values. // // If the from/to types are invalid, then use a cast that will fail at // runtime. We cannot catch these errors with SIL verification because they // may legitimately occur during code specialization on dynamically // unreachable paths. // // TODO: For now, we leave invalid casts in address form so that the runtime // will trap. We could emit a noreturn call here instead which would provide // more information to the optimizer. SILValue srcVal = args[0].forward(gen); SILValue fromAddr; if (fromTL.isLoadable()) { // Move the loadable value into a "source temp". Since the source and // dest are RC identical, store the reference into the source temp without // a retain. The cast will load the reference from the source temp and // store it into a dest temp effectively forwarding the cleanup. fromAddr = gen.emitTemporaryAllocation(loc, srcVal->getType()); gen.B.createStore(loc, srcVal, fromAddr); } else { // The cast loads directly from the source address. fromAddr = srcVal; } // Create a "dest temp" to hold the reference after casting it. SILValue toAddr = gen.emitTemporaryAllocation(loc, toTL.getLoweredType()); gen.B.createUncheckedRefCastAddr(loc, fromAddr, fromTy->getCanonicalType(), toAddr, toTy->getCanonicalType()); // Forward it along and register a cleanup. if (toTL.isAddressOnly()) return gen.emitManagedBufferWithCleanup(toAddr); // Load the destination value. auto result = gen.B.createLoad(loc, toAddr); return gen.emitManagedRValueWithCleanup(result); }