17
17
#include " GenCast.h"
18
18
19
19
#include " Explosion.h"
20
+ #include " GenEnum.h"
20
21
#include " GenExistential.h"
21
22
#include " GenMeta.h"
22
23
#include " GenProto.h"
@@ -391,15 +392,15 @@ static llvm::Function *emitExistentialScalarCastFn(IRGenModule &IGM,
391
392
return fn;
392
393
}
393
394
394
- void irgen::emitMetatypeToObjectDowncast (IRGenFunction &IGF,
395
- llvm::Value *metatypeValue,
396
- CanAnyMetatypeType type,
397
- CheckedCastMode mode,
398
- Explosion &ex) {
395
+ llvm::Value *irgen::emitMetatypeToAnyObjectDowncast (IRGenFunction &IGF,
396
+ llvm::Value *metatypeValue,
397
+ CanAnyMetatypeType type,
398
+ CheckedCastMode mode) {
399
399
// If ObjC interop is enabled, casting a metatype to AnyObject succeeds
400
400
// if the metatype is for a class.
401
- auto triviallyFail = [&] {
402
- ex.add (llvm::ConstantPointerNull::get (IGF.IGM .ObjCPtrTy ));
401
+
402
+ auto triviallyFail = [&]() -> llvm::Value* {
403
+ return llvm::ConstantPointerNull::get (IGF.IGM .ObjCPtrTy );
403
404
};
404
405
405
406
if (!IGF.IGM .ObjCInterop )
@@ -408,8 +409,7 @@ void irgen::emitMetatypeToObjectDowncast(IRGenFunction &IGF,
408
409
switch (type->getRepresentation ()) {
409
410
case MetatypeRepresentation::ObjC:
410
411
// Metatypes that can be represented as ObjC trivially cast to AnyObject.
411
- ex.add (IGF.Builder .CreateBitCast (metatypeValue, IGF.IGM .ObjCPtrTy ));
412
- return ;
412
+ return IGF.Builder .CreateBitCast (metatypeValue, IGF.IGM .ObjCPtrTy );
413
413
414
414
case MetatypeRepresentation::Thin:
415
415
// Metatypes that can be thin would never be classes.
@@ -425,8 +425,7 @@ void irgen::emitMetatypeToObjectDowncast(IRGenFunction &IGF,
425
425
// Get the ObjC metadata for the class.
426
426
auto heapMetadata = emitClassHeapMetadataRefForMetatype (IGF,metatypeValue,
427
427
instanceTy);
428
- ex.add (IGF.Builder .CreateBitCast (heapMetadata, IGF.IGM .ObjCPtrTy ));
429
- return ;
428
+ return IGF.Builder .CreateBitCast (heapMetadata, IGF.IGM .ObjCPtrTy );
430
429
}
431
430
432
431
// Is the type obviously not a class?
@@ -451,11 +450,10 @@ void irgen::emitMetatypeToObjectDowncast(IRGenFunction &IGF,
451
450
452
451
auto call = IGF.Builder .CreateCall (castFn, metatypeValue);
453
452
call->setCallingConv (cc);
454
- ex.add (call);
455
- return ;
453
+ return call;
456
454
}
457
455
}
458
-
456
+ llvm_unreachable ( " invalid metatype representation " );
459
457
}
460
458
461
459
@@ -706,22 +704,58 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
706
704
}
707
705
}
708
706
709
- // / Emit a checked cast sequence.
710
- void irgen::emitValueCheckedCast (IRGenFunction &IGF,
711
- Explosion &value,
712
- SILType valueType,
713
- SILType loweredTargetType,
714
- CheckedCastMode mode,
715
- Explosion &out) {
716
- assert (valueType.isObject ());
717
- assert (loweredTargetType.isObject ());
718
- CanType sourceType = valueType.getSwiftRValueType ();
719
- CanType targetType = loweredTargetType.getSwiftRValueType ();
707
+ // / Emit a checked cast of a scalar value.
708
+ // /
709
+ // / This is not just an implementation of emitCheckedCast for scalar types;
710
+ // / it imposes strict restrictions on the source and target types that ensure
711
+ // / that the actual value isn't changed in any way, thus preserving its
712
+ // / reference identity.
713
+ // /
714
+ // / These restrictions are set by canUseScalarCheckedCastInstructions.
715
+ // / Essentially, both the source and target types must be one of:
716
+ // / - a (possibly generic) concrete class type,
717
+ // / - a class-bounded archetype,
718
+ // / - a class-bounded existential,
719
+ // / - a concrete metatype, or
720
+ // / - an existential metatype.
721
+ // /
722
+ // / Furthermore, if the target type is a metatype, the source type must be
723
+ // / a metatype. This restriction isn't obviously necessary; it's just that
724
+ // / the runtime support for checking that an object instance is a metatype
725
+ // / isn't exposed.
726
+ void irgen::emitScalarCheckedCast (IRGenFunction &IGF,
727
+ Explosion &value,
728
+ SILType sourceType,
729
+ SILType targetType,
730
+ CheckedCastMode mode,
731
+ Explosion &out) {
732
+ assert (sourceType.isObject ());
733
+ assert (targetType.isObject ());
734
+
735
+ OptionalTypeKind optKind;
736
+ if (auto sourceOptObjectType =
737
+ sourceType.getAnyOptionalObjectType (*IGF.IGM .SILMod , optKind)) {
738
+
739
+ // Translate the value from an enum represention to a possibly-null
740
+ // representation. Note that we assume that this projection is safe
741
+ // for the particular case of an optional class-reference or metatype
742
+ // value.
743
+ Explosion optValue;
744
+ auto someDecl = IGF.IGM .Context .getOptionalSomeDecl (optKind);
745
+ emitProjectLoadableEnum (IGF, sourceType, value, someDecl, optValue);
746
+
747
+ assert (value.empty ());
748
+ value = std::move (optValue);
749
+ sourceType = sourceOptObjectType;
750
+ }
720
751
721
- if (auto sourceMetaType = dyn_cast<AnyMetatypeType>(sourceType)) {
752
+ // If the source value is a metatype, either do a metatype-to-metatype
753
+ // cast or cast it to an object instance and continue.
754
+ if (auto sourceMetatype = sourceType.getAs <AnyMetatypeType>()) {
722
755
llvm::Value *metatypeVal = nullptr ;
723
- if (sourceMetaType ->getRepresentation () != MetatypeRepresentation::Thin)
756
+ if (sourceMetatype ->getRepresentation () != MetatypeRepresentation::Thin)
724
757
metatypeVal = value.claimNext ();
758
+
725
759
// If the metatype is existential, there may be witness tables in the
726
760
// value, which we don't need.
727
761
// TODO: In existential-to-existential casts, we should carry over common
@@ -730,64 +764,60 @@ void irgen::emitValueCheckedCast(IRGenFunction &IGF,
730
764
731
765
SmallVector<ProtocolDecl*, 1 > protocols;
732
766
733
- if (auto existential = dyn_cast<ExistentialMetatypeType>(targetType))
734
- emitScalarExistentialDowncast (IGF, metatypeVal,
735
- valueType, loweredTargetType,
736
- mode,
737
- existential->getRepresentation (),
767
+ // Casts to existential metatypes.
768
+ if (auto existential = targetType.getAs <ExistentialMetatypeType>()) {
769
+ emitScalarExistentialDowncast (IGF, metatypeVal, sourceType, targetType,
770
+ mode, existential->getRepresentation (),
738
771
out);
739
- else if (auto destMetaType = dyn_cast<MetatypeType>(targetType))
772
+ return ;
773
+
774
+ // Casts to concrete metatypes.
775
+ } else if (auto destMetaType = targetType.getAs <MetatypeType>()) {
740
776
emitMetatypeDowncast (IGF, metatypeVal, destMetaType, mode, out);
741
- else if (targetType->isExistentialType (protocols)) {
742
- assert (IGF.IGM .ObjCInterop
743
- && protocols.size () == 1
744
- && *protocols[0 ]->getKnownProtocolKind ()
745
- == KnownProtocolKind::AnyObject
746
- && " metatypes can only be cast to AnyObject, with ObjC interop" );
747
- emitMetatypeToObjectDowncast (IGF, metatypeVal, sourceMetaType, mode, out);
777
+ return ;
748
778
}
749
- return ;
750
- }
751
779
752
- if ((isa<ArchetypeType>(sourceType) && !targetType.isExistentialType ()) ||
753
- (isa<ArchetypeType>(targetType) && !sourceType.isExistentialType ())) {
754
- llvm::Value *fromValue = value.claimNext ();
755
- llvm::Value *toValue =
756
- emitClassDowncast (IGF, fromValue, loweredTargetType, mode);
757
- out.add (toValue);
758
- return ;
780
+ // Otherwise, this is a metatype-to-object cast.
781
+ assert (targetType.isAnyClassReferenceType ());
782
+
783
+ // Convert the metatype value to AnyObject.
784
+ llvm::Value *object =
785
+ emitMetatypeToAnyObjectDowncast (IGF, metatypeVal, sourceMetatype, mode);
786
+
787
+ auto anyObjectProtocol =
788
+ IGF.IGM .Context .getProtocol (KnownProtocolKind::AnyObject);
789
+ SILType anyObjectType =
790
+ SILType::getPrimitiveObjectType (
791
+ CanType (anyObjectProtocol->getDeclaredType ()));
792
+
793
+ // Continue, pretending that the source value was an (optional) value.
794
+ Explosion newValue;
795
+ newValue.add (object);
796
+ value = std::move (newValue);
797
+ sourceType = anyObjectType;
759
798
}
760
799
761
- if (sourceType.isExistentialType ()) {
762
- llvm::Value *instance
763
- = emitClassExistentialProjection (IGF, value, valueType,
764
- CanArchetypeType ());
765
-
766
- llvm::Value *toValue;
767
- if (loweredTargetType.isExistentialType ()) {
768
- emitScalarExistentialDowncast (IGF, instance, valueType,
769
- loweredTargetType, mode,
770
- /* not a metatype*/ None,
771
- out);
772
- } else {
773
- toValue = emitClassDowncast (IGF, instance, loweredTargetType, mode);
774
- out.add (toValue);
775
- }
800
+ assert (!targetType.is <AnyMetatypeType>() &&
801
+ " scalar cast of class reference to metatype is unimplemented" );
776
802
777
- return ;
803
+ // If the source type is existential, project out the class pointer.
804
+ //
805
+ // TODO: if we're casting to an existential type, don't throw away the
806
+ // protocol conformance information we already have.
807
+ llvm::Value *instance;
808
+ if (sourceType.isExistentialType ()) {
809
+ instance = emitClassExistentialProjection (IGF, value, sourceType,
810
+ CanArchetypeType ());
811
+ } else {
812
+ instance = value.claimNext ();
778
813
}
779
814
780
815
if (targetType.isExistentialType ()) {
781
- llvm::Value *fromValue = value.claimNext ();
782
- emitScalarExistentialDowncast (IGF, fromValue, valueType,
783
- loweredTargetType, mode,
784
- /* not a metatype*/ None,
785
- out);
816
+ emitScalarExistentialDowncast (IGF, instance, sourceType, targetType,
817
+ mode, /* not a metatype*/ None, out);
786
818
return ;
787
819
}
788
820
789
- llvm::Value *fromValue = value.claimNext ();
790
- llvm::Value *cast
791
- = emitClassDowncast (IGF, fromValue, loweredTargetType, mode);
792
- out.add (cast);
821
+ llvm::Value *result = emitClassDowncast (IGF, instance, targetType, mode);
822
+ out.add (result);
793
823
}
0 commit comments