Skip to content

Abstract the object type of optional types #4689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,14 @@ A type ``T`` is a *legal SIL type* if:
- it is a function type which satisfies the constraints (below) on
function types in SIL,

- it is a metatype type which describes its representation,

- it is a tuple type whose element types are legal SIL types,

- it is a legal Swift type that is not a function, tuple, or l-value type, or
- it is ``Optional<U>``, where ``U`` is a legal SIL type,

- it is a legal Swift type that is not a function, tuple, optional,
metatype, or l-value type, or

- it is a ``@box`` containing a legal SIL type.

Expand Down Expand Up @@ -394,6 +399,22 @@ a box containing a mutable value of type ``T``. Boxes always use Swift-native
reference counting, so they can be queried for uniqueness and cast to the
``Builtin.NativeObject`` type.

Metatype Types
``````````````

A concrete or existential metatype in SIL must describe its representation.
This can be:

- ``@thin``, meaning that it requires no storage and thus necessarily
represents an exact type (only allowed for concrete metatypes);

- ``@thick``, meaning that it stores a reference to a type or (if a
concrete class) a subclass of that type; or

- ``@objc``, meaning that it stores a reference to a class type (or a
subclass thereof) using an Objective-C class object representation
rather than the native Swift type-object representation.

Function Types
``````````````

Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2713,6 +2713,8 @@ ERROR(sil_function_multiple_error_results,PointsToFirstBadToken,
"SIL function types cannot have multiple @error results", ())
ERROR(unsupported_sil_convention,none,
"convention '%0' not supported in SIL", (StringRef))
ERROR(illegal_sil_type,none,
"type %0 is not a legal SIL value type", (Type))

// SIL Metatypes
ERROR(sil_metatype_without_repr,none,
Expand Down
18 changes: 2 additions & 16 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -757,27 +757,13 @@ class SILBuilder {

/// Inject a loadable value into the corresponding optional type.
EnumInst *createOptionalSome(SILLocation Loc, SILValue operand, SILType ty) {
return createOptionalSome(Loc, operand, ty.getOptionalTypeKind(), ty);
}

/// Inject a loadable value into the corresponding optional type.
EnumInst *createOptionalSome(SILLocation Loc, SILValue operand,
OptionalTypeKind optKind, SILType ty) {
assert(ty.getOptionalTypeKind() == optKind);
auto someDecl = F.getModule().getASTContext().getOptionalSomeDecl(optKind);
auto someDecl = F.getModule().getASTContext().getOptionalSomeDecl();
return createEnum(Loc, operand, someDecl, ty);
}

/// Create the nil value of a loadable optional type.
EnumInst *createOptionalNone(SILLocation Loc, SILType ty) {
return createOptionalNone(Loc, ty.getOptionalTypeKind(), ty);
}

/// Create the nil value of a loadable optional type.
EnumInst *createOptionalNone(SILLocation Loc, OptionalTypeKind optKind,
SILType ty) {
assert(ty.getOptionalTypeKind() == optKind);
auto noneDecl = F.getModule().getASTContext().getOptionalNoneDecl(optKind);
auto noneDecl = F.getModule().getASTContext().getOptionalNoneDecl();
return createEnum(Loc, nullptr, noneDecl, ty);
}

Expand Down
35 changes: 11 additions & 24 deletions include/swift/SIL/SILType.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,18 +385,15 @@ class SILType {
static bool canRefCast(SILType operTy, SILType resultTy, SILModule &M);

/// True if the type is block-pointer-compatible, meaning it either is a block
/// or is an Optional or ImplicitlyUnwrappedOptional with a block payload.
/// or is an Optional with a block payload.
bool isBlockPointerCompatible() const {
CanType ty = getSwiftRValueType();
if (auto optPayload = ty->getAnyOptionalObjectType()) {
// The object type of Optional<T> is an unlowered AST type.
auto fTy = optPayload->getAs<FunctionType>();
if (!fTy)
return false;
return fTy->getRepresentation() == FunctionType::Representation::Block;
// Look through one level of optionality.
SILType ty = *this;
if (auto optPayload = ty.getAnyOptionalObjectType()) {
ty = optPayload;
}

auto fTy = dyn_cast<SILFunctionType>(ty);
auto fTy = ty.getAs<SILFunctionType>();
if (!fTy)
return false;
return fTy->getRepresentation() == SILFunctionType::Representation::Block;
Expand Down Expand Up @@ -474,24 +471,14 @@ class SILType {
/// meaning it cannot be fully destructured in SIL.
bool aggregateHasUnreferenceableStorage() const;

/// Returns the lowered type for T if this type is Optional<T> or
/// ImplicitlyUnwrappedOptional<T>; otherwise, return the null type.
SILType getAnyOptionalObjectType(SILModule &SILMod,
OptionalTypeKind &OTK) const;
/// Returns the lowered type for T if this type is Optional<T>;
/// otherwise, return the null type.
SILType getAnyOptionalObjectType() const;

/// Unwraps one level of optional type.
/// Returns the lowered T if the given type is Optional<T> or IUO<T>.
/// Returns the lowered T if the given type is Optional<T>.
/// Otherwise directly returns the given type.
static SILType unwrapAnyOptionalType(SILType Ty, SILModule &SILMod,
OptionalTypeKind &OTK) {
if (auto unwrappedTy = Ty.getAnyOptionalObjectType(SILMod, OTK))
return unwrappedTy;

return Ty;
};

/// Classify this type as an optional type.
OptionalTypeKind getOptionalTypeKind() const;
SILType unwrapAnyOptionalType() const;

/// Returns true if this is the AnyObject SILType;
bool isAnyObject() const { return getSwiftRValueType()->isAnyObject(); }
Expand Down
7 changes: 4 additions & 3 deletions include/swift/SIL/TypeLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,8 +522,6 @@ class TypeConverter {

const TypeLowering &getTypeLoweringForLoweredType(TypeKey key);
const TypeLowering &getTypeLoweringForUncachedLoweredType(TypeKey key);
const TypeLowering &getTypeLoweringForLoweredFunctionType(TypeKey key);
const TypeLowering &getTypeLoweringForUncachedLoweredFunctionType(TypeKey key);

public:
SILModule &M;
Expand Down Expand Up @@ -786,7 +784,7 @@ class TypeConverter {
/// The ABI compatible relation is not symmetric on function types -- while
/// T and T! are both subtypes of each other, a calling convention conversion
/// of T! to T always requires a thunk.
ABIDifference checkForABIDifferences(CanType type1, CanType type2);
ABIDifference checkForABIDifferences(SILType type1, SILType type2);

/// \brief Same as above but for SIL function types.
ABIDifference checkFunctionForABIDifferences(SILFunctionType *fnTy1,
Expand All @@ -800,6 +798,9 @@ class TypeConverter {
getUncachedSILFunctionTypeForConstant(SILDeclRef constant,
CanAnyFunctionType origInterfaceType);
private:
CanType getLoweredRValueType(AbstractionPattern origType, CanType substType,
unsigned uncurryLevel);

Type getLoweredCBridgedType(AbstractionPattern pattern, Type t,
bool canBridgeBool,
bool bridgedCollectionsAreOptional);
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2901,6 +2901,8 @@ ReferenceStorageType *ReferenceStorageType::get(Type T, Ownership ownership,
new (C, arena) UnownedStorageType(T, T->isCanonical() ? &C : 0,
properties);
case Ownership::Weak:
assert(T->getAnyOptionalObjectType() &&
"object of weak storage type is not optional");
return entry =
new (C, arena) WeakStorageType(T, T->isCanonical() ? &C : 0,
properties);
Expand Down
18 changes: 18 additions & 0 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,16 +500,34 @@ TypeBase::getTypeVariables(SmallVectorImpl<TypeVariableType *> &typeVariables) {
}

static bool isLegalSILType(CanType type) {
// L-values and inouts are not legal.
if (!type->isMaterializable()) return false;

// Function types must be lowered.
if (isa<AnyFunctionType>(type)) return false;

// Metatypes must have a representation.
if (auto meta = dyn_cast<AnyMetatypeType>(type))
return meta->hasRepresentation();

// Tuples are legal if all their elements are legal.
if (auto tupleType = dyn_cast<TupleType>(type)) {
for (auto eltType : tupleType.getElementTypes()) {
if (!isLegalSILType(eltType)) return false;
}
return true;
}

// Optionals are legal if their object type is legal and they're Optional.
OptionalTypeKind optKind;
if (auto objectType = type.getAnyOptionalObjectType(optKind)) {
return (optKind == OTK_Optional && isLegalSILType(objectType));
}

// Reference storage types are legal if their object type is legal.
if (auto refType = dyn_cast<ReferenceStorageType>(type))
return isLegalSILType(refType.getReferentType());

return true;
}

Expand Down
6 changes: 2 additions & 4 deletions lib/IRGen/GenCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,16 +733,14 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
assert(sourceType.isObject());
assert(targetType.isObject());

OptionalTypeKind optKind;
if (auto sourceOptObjectType =
sourceType.getAnyOptionalObjectType(IGF.getSILModule(), optKind)) {
if (auto sourceOptObjectType = sourceType.getAnyOptionalObjectType()) {

// Translate the value from an enum representation to a possibly-null
// representation. Note that we assume that this projection is safe
// for the particular case of an optional class-reference or metatype
// value.
Explosion optValue;
auto someDecl = IGF.IGM.Context.getOptionalSomeDecl(optKind);
auto someDecl = IGF.IGM.Context.getOptionalSomeDecl();
emitProjectLoadableEnum(IGF, sourceType, value, someDecl, optValue);

assert(value.empty());
Expand Down
5 changes: 2 additions & 3 deletions lib/IRGen/GenClangType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,9 +421,8 @@ clang::CanQualType
GenClangType::visitBoundGenericType(CanBoundGenericType type) {
// We only expect *Pointer<T>, ImplicitlyUnwrappedOptional<T>, and Optional<T>.
// The first two are structs; the last is an enum.
OptionalTypeKind OTK;
if (auto underlyingTy = SILType::getPrimitiveObjectType(type)
.getAnyOptionalObjectType(IGM.getSILModule(), OTK)) {
if (auto underlyingTy =
SILType::getPrimitiveObjectType(type).getAnyOptionalObjectType()) {
// The underlying type could be a bridged type, which makes any
// sort of casual assertion here difficult.
return Converter.convert(IGM, underlyingTy.getSwiftRValueType());
Expand Down
3 changes: 1 addition & 2 deletions lib/IRGen/GenEnum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5041,8 +5041,7 @@ irgen::getEnumImplStrategy(IRGenModule &IGM, SILType ty) {

const EnumImplStrategy &
irgen::getEnumImplStrategy(IRGenModule &IGM, CanType ty) {
// Nominal types are always preserved through SIL lowering.
return getEnumImplStrategy(IGM, SILType::getPrimitiveAddressType(ty));
return getEnumImplStrategy(IGM, IGM.getLoweredType(ty));
}

TypeInfo *
Expand Down
38 changes: 25 additions & 13 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) {
return false;

// Resiliently-sized metadata access always requires an accessor.
return (IGM.getTypeInfoForLowered(type).isFixedSize());
return (IGM.getTypeInfoForUnlowered(type).isFixedSize());
}

// The empty tuple type has a singleton metadata.
Expand Down Expand Up @@ -1713,13 +1713,13 @@ namespace {
/// Try to find the metatype in local data.
llvm::Value *tryGetLocal(CanType type) {
return IGF.tryGetLocalTypeDataForLayout(
SILType::getPrimitiveObjectType(type),
IGF.IGM.getLoweredType(type),
LocalTypeDataKind::forTypeMetadata());
}

/// Set the metatype in local data.
llvm::Value *setLocal(CanType type, llvm::Instruction *metatype) {
IGF.setScopedLocalTypeDataForLayout(SILType::getPrimitiveObjectType(type),
IGF.setScopedLocalTypeDataForLayout(IGF.IGM.getLoweredType(type),
LocalTypeDataKind::forTypeMetadata(),
metatype);
return metatype;
Expand Down Expand Up @@ -1770,7 +1770,7 @@ namespace {
/// Emit the type layout by projecting it from dynamic type metadata.
llvm::Value *emitFromTypeMetadata(CanType t) {
auto *vwtable = IGF.emitValueWitnessTableRefForLayout(
SILType::getPrimitiveObjectType(t));
IGF.IGM.getLoweredType(t));
return emitFromValueWitnessTablePointer(vwtable);
}

Expand Down Expand Up @@ -1811,7 +1811,7 @@ namespace {

/// Fallback default implementation.
llvm::Value *visitType(CanType t) {
auto silTy = SILType::getPrimitiveObjectType(t);
auto silTy = IGF.IGM.getLoweredType(t);
auto &ti = IGF.getTypeInfo(silTy);

// If the type is in the same source file, or has a common value
Expand Down Expand Up @@ -2428,6 +2428,19 @@ namespace {
NominalTypeDecl *type,
ArrayRef<EnumImplStrategy::Element> enumElements) {
SmallVector<FieldTypeInfo, 4> types;

// This is a terrible special case, but otherwise the archetypes
// aren't mapped correctly because the EnumImplStrategy ends up
// using the lowered cases, i.e. the cases for Optional<>.
if (type->classifyAsOptionalType() == OTK_ImplicitlyUnwrappedOptional) {
assert(enumElements.size() == 1);
auto caseType =
IGM.Context.getImplicitlyUnwrappedOptionalSomeDecl()
->getArgumentType()->getCanonicalType();
types.push_back(FieldTypeInfo(caseType, false, false));
return getFieldTypeAccessorFn(IGM, type, types);
}

for (auto &elt : enumElements) {
assert(elt.decl->hasArgumentType() && "enum case doesn't have arg?!");
auto caseType = elt.decl->getArgumentType()->getCanonicalType();
Expand Down Expand Up @@ -4813,8 +4826,7 @@ namespace {
assert(var->hasStorage() &&
"storing field offset for computed property?!");
SILType structType =
SILType::getPrimitiveAddressType(
Target->getDeclaredTypeInContext()->getCanonicalType());
IGM.getLoweredType(Target->getDeclaredTypeInContext());

llvm::Constant *offset =
emitPhysicalStructMemberFixedOffset(IGM, structType, var);
Expand Down Expand Up @@ -4943,9 +4955,9 @@ namespace {
llvm::Value *vwtable) {
// Nominal types are always preserved through SIL lowering.
auto structTy = Target->getDeclaredTypeInContext()->getCanonicalType();
IGM.getTypeInfoForLowered(structTy)
IGM.getTypeInfoForUnlowered(structTy)
.initializeMetadata(IGF, metadata, vwtable,
SILType::getPrimitiveAddressType(structTy));
IGF.IGM.getLoweredType(structTy));
}
};
}
Expand Down Expand Up @@ -5050,7 +5062,7 @@ class EnumMetadataBuilder

void addPayloadSize() {
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
auto &enumTI = IGM.getTypeInfoForLowered(enumTy);
auto &enumTI = IGM.getTypeInfoForUnlowered(enumTy);
if (!enumTI.isFixedSize(ResilienceExpansion::Maximal)) {
addConstantWord(0);
HasUnfilledPayloadSize = true;
Expand Down Expand Up @@ -5120,7 +5132,7 @@ class GenericEnumMetadataBuilder
// In all cases where a payload size is demanded in the metadata, it's
// runtime-dependent, so fill in a zero here.
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
auto &enumTI = IGM.getTypeInfoForLowered(enumTy);
auto &enumTI = IGM.getTypeInfoForUnlowered(enumTy);
(void) enumTI;
assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) &&
"non-generic, non-resilient enums don't need payload size in metadata");
Expand All @@ -5132,9 +5144,9 @@ class GenericEnumMetadataBuilder
llvm::Value *vwtable) {
// Nominal types are always preserved through SIL lowering.
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
IGM.getTypeInfoForLowered(enumTy)
IGM.getTypeInfoForUnlowered(enumTy)
.initializeMetadata(IGF, metadata, vwtable,
SILType::getPrimitiveAddressType(enumTy));
IGF.IGM.getLoweredType(enumTy));
}
};

Expand Down
Loading