Refactor cast representation in AST and SIL, and implement 'is'.

Improve our representations of casts in the AST and SIL so that 'as!' and 'is' (and eventually 'as?') can share almost all of the same type-checking, SILGen, and IRGen code.

In the AST, we now represent 'as!' and 'is' as UnconditionalCheckedCastExpr and IsaExpr, respectively, with the semantic variations of cast (downcast, super-to-archetype, archetype-to-concrete, etc.) discriminated by an enum field. This keeps the user-visible syntactic and type behavior differences of the two forms cleanly separated for AST consumers.

At the SIL level, we transpose the representation so that the different cast semantics get their own instructions and the conditional/unconditional cast behavior is indicated by an enum, making it easy for IRGen to discriminate the different code paths for the different semantics. We also add an 'IsNonnull' instruction to cover the conditional-cast-result-to-boolean conversion common to all the forms of 'is'.

The upshot of all this is that 'x is T' now works for all the new archetype and existential cast forms supported by 'as!'.

Swift SVN r5737
This commit is contained in:
Joe Groff
2013-06-21 05:54:03 +00:00
parent be0f7b4c48
commit f072c48e45
28 changed files with 587 additions and 636 deletions

View File

@@ -3897,10 +3897,11 @@ llvm::Value *irgen::emitClassExistentialProjection(IRGenFunction &IGF,
}
static Address
emitUnconditionalOpaqueDowncast(IRGenFunction &IGF,
Address value,
llvm::Value *srcMetadata,
SILType destType) {
emitOpaqueDowncast(IRGenFunction &IGF,
Address value,
llvm::Value *srcMetadata,
SILType destType,
CheckedCastMode mode) {
llvm::Value *addr = IGF.Builder.CreateBitCast(value.getAddress(),
IGF.IGM.OpaquePtrTy);
@@ -3908,9 +3909,17 @@ emitUnconditionalOpaqueDowncast(IRGenFunction &IGF,
llvm::Value *destMetadata = IGF.emitTypeMetadataRef(destType);
destMetadata = IGF.Builder.CreateBitCast(destMetadata, IGF.IGM.Int8PtrTy);
auto *call
= IGF.Builder.CreateCall3(IGF.IGM.getDynamicCastIndirectUnconditionalFn(),
addr, srcMetadata, destMetadata);
llvm::Value *castFn;
switch (mode) {
case CheckedCastMode::Unconditional:
castFn = IGF.IGM.getDynamicCastIndirectUnconditionalFn();
break;
case CheckedCastMode::Conditional:
castFn = IGF.IGM.getDynamicCastIndirectFn();
break;
}
auto *call = IGF.Builder.CreateCall3(castFn, addr, srcMetadata, destMetadata);
// FIXME: Eventually, we may want to throw.
call->setDoesNotThrow();
@@ -3921,24 +3930,26 @@ emitUnconditionalOpaqueDowncast(IRGenFunction &IGF,
return destTI.getAddressForPointer(ptr);
}
/// Emit a checked unconditional cast of an opaque archetype.
Address irgen::emitUnconditionalOpaqueArchetypeDowncast(IRGenFunction &IGF,
Address value,
SILType srcType,
SILType destType) {
/// Emit a checked cast of an opaque archetype.
Address irgen::emitOpaqueArchetypeDowncast(IRGenFunction &IGF,
Address value,
SILType srcType,
SILType destType,
CheckedCastMode mode) {
assert(srcType.is<ArchetypeType>());
assert(!srcType.castTo<ArchetypeType>()->requiresClass());
llvm::Value *srcMetadata = IGF.emitTypeMetadataRef(srcType);
return emitUnconditionalOpaqueDowncast(IGF, value, srcMetadata, destType);
return emitOpaqueDowncast(IGF, value, srcMetadata, destType, mode);
}
/// Emit a checked unconditional cast of an opaque existential container's
/// contained value.
Address irgen::emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF,
Address container,
SILType srcType,
SILType destType) {
Address irgen::emitOpaqueExistentialDowncast(IRGenFunction &IGF,
Address container,
SILType srcType,
SILType destType,
CheckedCastMode mode) {
assert(srcType.isExistentialType());
assert(!srcType.isClassExistentialType());
@@ -3949,5 +3960,5 @@ Address irgen::emitUnconditionalOpaqueExistentialDowncast(IRGenFunction &IGF,
std::tie(value, srcMetadata)
= emitOpaqueExistentialProjectionWithMetadata(IGF, container, srcType);
return emitUnconditionalOpaqueDowncast(IGF, value, srcMetadata, destType);
return emitOpaqueDowncast(IGF, value, srcMetadata, destType, mode);
}