Skip to content

Commit 0bdc8b2

Browse files
authored
Merge pull request #4689 from rjmccall/optional-abstraction
Abstract the object type of optional types
2 parents a335ebc + 34fb15e commit 0bdc8b2

File tree

76 files changed

+1054
-1141
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+1054
-1141
lines changed

docs/SIL.rst

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,9 +347,14 @@ A type ``T`` is a *legal SIL type* if:
347347
- it is a function type which satisfies the constraints (below) on
348348
function types in SIL,
349349

350+
- it is a metatype type which describes its representation,
351+
350352
- it is a tuple type whose element types are legal SIL types,
351353

352-
- it is a legal Swift type that is not a function, tuple, or l-value type, or
354+
- it is ``Optional<U>``, where ``U`` is a legal SIL type,
355+
356+
- it is a legal Swift type that is not a function, tuple, optional,
357+
metatype, or l-value type, or
353358

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

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

402+
Metatype Types
403+
``````````````
404+
405+
A concrete or existential metatype in SIL must describe its representation.
406+
This can be:
407+
408+
- ``@thin``, meaning that it requires no storage and thus necessarily
409+
represents an exact type (only allowed for concrete metatypes);
410+
411+
- ``@thick``, meaning that it stores a reference to a type or (if a
412+
concrete class) a subclass of that type; or
413+
414+
- ``@objc``, meaning that it stores a reference to a class type (or a
415+
subclass thereof) using an Objective-C class object representation
416+
rather than the native Swift type-object representation.
417+
397418
Function Types
398419
``````````````
399420

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,6 +2713,8 @@ ERROR(sil_function_multiple_error_results,PointsToFirstBadToken,
27132713
"SIL function types cannot have multiple @error results", ())
27142714
ERROR(unsupported_sil_convention,none,
27152715
"convention '%0' not supported in SIL", (StringRef))
2716+
ERROR(illegal_sil_type,none,
2717+
"type %0 is not a legal SIL value type", (Type))
27162718

27172719
// SIL Metatypes
27182720
ERROR(sil_metatype_without_repr,none,

include/swift/SIL/SILBuilder.h

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -757,27 +757,13 @@ class SILBuilder {
757757

758758
/// Inject a loadable value into the corresponding optional type.
759759
EnumInst *createOptionalSome(SILLocation Loc, SILValue operand, SILType ty) {
760-
return createOptionalSome(Loc, operand, ty.getOptionalTypeKind(), ty);
761-
}
762-
763-
/// Inject a loadable value into the corresponding optional type.
764-
EnumInst *createOptionalSome(SILLocation Loc, SILValue operand,
765-
OptionalTypeKind optKind, SILType ty) {
766-
assert(ty.getOptionalTypeKind() == optKind);
767-
auto someDecl = F.getModule().getASTContext().getOptionalSomeDecl(optKind);
760+
auto someDecl = F.getModule().getASTContext().getOptionalSomeDecl();
768761
return createEnum(Loc, operand, someDecl, ty);
769762
}
770763

771764
/// Create the nil value of a loadable optional type.
772765
EnumInst *createOptionalNone(SILLocation Loc, SILType ty) {
773-
return createOptionalNone(Loc, ty.getOptionalTypeKind(), ty);
774-
}
775-
776-
/// Create the nil value of a loadable optional type.
777-
EnumInst *createOptionalNone(SILLocation Loc, OptionalTypeKind optKind,
778-
SILType ty) {
779-
assert(ty.getOptionalTypeKind() == optKind);
780-
auto noneDecl = F.getModule().getASTContext().getOptionalNoneDecl(optKind);
766+
auto noneDecl = F.getModule().getASTContext().getOptionalNoneDecl();
781767
return createEnum(Loc, nullptr, noneDecl, ty);
782768
}
783769

include/swift/SIL/SILType.h

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -385,18 +385,15 @@ class SILType {
385385
static bool canRefCast(SILType operTy, SILType resultTy, SILModule &M);
386386

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

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

477-
/// Returns the lowered type for T if this type is Optional<T> or
478-
/// ImplicitlyUnwrappedOptional<T>; otherwise, return the null type.
479-
SILType getAnyOptionalObjectType(SILModule &SILMod,
480-
OptionalTypeKind &OTK) const;
474+
/// Returns the lowered type for T if this type is Optional<T>;
475+
/// otherwise, return the null type.
476+
SILType getAnyOptionalObjectType() const;
481477

482478
/// Unwraps one level of optional type.
483-
/// Returns the lowered T if the given type is Optional<T> or IUO<T>.
479+
/// Returns the lowered T if the given type is Optional<T>.
484480
/// Otherwise directly returns the given type.
485-
static SILType unwrapAnyOptionalType(SILType Ty, SILModule &SILMod,
486-
OptionalTypeKind &OTK) {
487-
if (auto unwrappedTy = Ty.getAnyOptionalObjectType(SILMod, OTK))
488-
return unwrappedTy;
489-
490-
return Ty;
491-
};
492-
493-
/// Classify this type as an optional type.
494-
OptionalTypeKind getOptionalTypeKind() const;
481+
SILType unwrapAnyOptionalType() const;
495482

496483
/// Returns true if this is the AnyObject SILType;
497484
bool isAnyObject() const { return getSwiftRValueType()->isAnyObject(); }

include/swift/SIL/TypeLowering.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,6 @@ class TypeConverter {
522522

523523
const TypeLowering &getTypeLoweringForLoweredType(TypeKey key);
524524
const TypeLowering &getTypeLoweringForUncachedLoweredType(TypeKey key);
525-
const TypeLowering &getTypeLoweringForLoweredFunctionType(TypeKey key);
526-
const TypeLowering &getTypeLoweringForUncachedLoweredFunctionType(TypeKey key);
527525

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

791789
/// \brief Same as above but for SIL function types.
792790
ABIDifference checkFunctionForABIDifferences(SILFunctionType *fnTy1,
@@ -800,6 +798,9 @@ class TypeConverter {
800798
getUncachedSILFunctionTypeForConstant(SILDeclRef constant,
801799
CanAnyFunctionType origInterfaceType);
802800
private:
801+
CanType getLoweredRValueType(AbstractionPattern origType, CanType substType,
802+
unsigned uncurryLevel);
803+
803804
Type getLoweredCBridgedType(AbstractionPattern pattern, Type t,
804805
bool canBridgeBool,
805806
bool bridgedCollectionsAreOptional);

lib/AST/ASTContext.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2901,6 +2901,8 @@ ReferenceStorageType *ReferenceStorageType::get(Type T, Ownership ownership,
29012901
new (C, arena) UnownedStorageType(T, T->isCanonical() ? &C : 0,
29022902
properties);
29032903
case Ownership::Weak:
2904+
assert(T->getAnyOptionalObjectType() &&
2905+
"object of weak storage type is not optional");
29042906
return entry =
29052907
new (C, arena) WeakStorageType(T, T->isCanonical() ? &C : 0,
29062908
properties);

lib/AST/Type.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,16 +500,34 @@ TypeBase::getTypeVariables(SmallVectorImpl<TypeVariableType *> &typeVariables) {
500500
}
501501

502502
static bool isLegalSILType(CanType type) {
503+
// L-values and inouts are not legal.
503504
if (!type->isMaterializable()) return false;
505+
506+
// Function types must be lowered.
504507
if (isa<AnyFunctionType>(type)) return false;
508+
509+
// Metatypes must have a representation.
505510
if (auto meta = dyn_cast<AnyMetatypeType>(type))
506511
return meta->hasRepresentation();
512+
513+
// Tuples are legal if all their elements are legal.
507514
if (auto tupleType = dyn_cast<TupleType>(type)) {
508515
for (auto eltType : tupleType.getElementTypes()) {
509516
if (!isLegalSILType(eltType)) return false;
510517
}
511518
return true;
512519
}
520+
521+
// Optionals are legal if their object type is legal and they're Optional.
522+
OptionalTypeKind optKind;
523+
if (auto objectType = type.getAnyOptionalObjectType(optKind)) {
524+
return (optKind == OTK_Optional && isLegalSILType(objectType));
525+
}
526+
527+
// Reference storage types are legal if their object type is legal.
528+
if (auto refType = dyn_cast<ReferenceStorageType>(type))
529+
return isLegalSILType(refType.getReferentType());
530+
513531
return true;
514532
}
515533

lib/IRGen/GenCast.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -733,16 +733,14 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
733733
assert(sourceType.isObject());
734734
assert(targetType.isObject());
735735

736-
OptionalTypeKind optKind;
737-
if (auto sourceOptObjectType =
738-
sourceType.getAnyOptionalObjectType(IGF.getSILModule(), optKind)) {
736+
if (auto sourceOptObjectType = sourceType.getAnyOptionalObjectType()) {
739737

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

748746
assert(value.empty());

lib/IRGen/GenClangType.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,9 +421,8 @@ clang::CanQualType
421421
GenClangType::visitBoundGenericType(CanBoundGenericType type) {
422422
// We only expect *Pointer<T>, ImplicitlyUnwrappedOptional<T>, and Optional<T>.
423423
// The first two are structs; the last is an enum.
424-
OptionalTypeKind OTK;
425-
if (auto underlyingTy = SILType::getPrimitiveObjectType(type)
426-
.getAnyOptionalObjectType(IGM.getSILModule(), OTK)) {
424+
if (auto underlyingTy =
425+
SILType::getPrimitiveObjectType(type).getAnyOptionalObjectType()) {
427426
// The underlying type could be a bridged type, which makes any
428427
// sort of casual assertion here difficult.
429428
return Converter.convert(IGM, underlyingTy.getSwiftRValueType());

lib/IRGen/GenEnum.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5041,8 +5041,7 @@ irgen::getEnumImplStrategy(IRGenModule &IGM, SILType ty) {
50415041

50425042
const EnumImplStrategy &
50435043
irgen::getEnumImplStrategy(IRGenModule &IGM, CanType ty) {
5044-
// Nominal types are always preserved through SIL lowering.
5045-
return getEnumImplStrategy(IGM, SILType::getPrimitiveAddressType(ty));
5044+
return getEnumImplStrategy(IGM, IGM.getLoweredType(ty));
50465045
}
50475046

50485047
TypeInfo *

lib/IRGen/GenMeta.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) {
474474
return false;
475475

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

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

17201720
/// Set the metatype in local data.
17211721
llvm::Value *setLocal(CanType type, llvm::Instruction *metatype) {
1722-
IGF.setScopedLocalTypeDataForLayout(SILType::getPrimitiveObjectType(type),
1722+
IGF.setScopedLocalTypeDataForLayout(IGF.IGM.getLoweredType(type),
17231723
LocalTypeDataKind::forTypeMetadata(),
17241724
metatype);
17251725
return metatype;
@@ -1770,7 +1770,7 @@ namespace {
17701770
/// Emit the type layout by projecting it from dynamic type metadata.
17711771
llvm::Value *emitFromTypeMetadata(CanType t) {
17721772
auto *vwtable = IGF.emitValueWitnessTableRefForLayout(
1773-
SILType::getPrimitiveObjectType(t));
1773+
IGF.IGM.getLoweredType(t));
17741774
return emitFromValueWitnessTablePointer(vwtable);
17751775
}
17761776

@@ -1811,7 +1811,7 @@ namespace {
18111811

18121812
/// Fallback default implementation.
18131813
llvm::Value *visitType(CanType t) {
1814-
auto silTy = SILType::getPrimitiveObjectType(t);
1814+
auto silTy = IGF.IGM.getLoweredType(t);
18151815
auto &ti = IGF.getTypeInfo(silTy);
18161816

18171817
// If the type is in the same source file, or has a common value
@@ -2428,6 +2428,19 @@ namespace {
24282428
NominalTypeDecl *type,
24292429
ArrayRef<EnumImplStrategy::Element> enumElements) {
24302430
SmallVector<FieldTypeInfo, 4> types;
2431+
2432+
// This is a terrible special case, but otherwise the archetypes
2433+
// aren't mapped correctly because the EnumImplStrategy ends up
2434+
// using the lowered cases, i.e. the cases for Optional<>.
2435+
if (type->classifyAsOptionalType() == OTK_ImplicitlyUnwrappedOptional) {
2436+
assert(enumElements.size() == 1);
2437+
auto caseType =
2438+
IGM.Context.getImplicitlyUnwrappedOptionalSomeDecl()
2439+
->getArgumentType()->getCanonicalType();
2440+
types.push_back(FieldTypeInfo(caseType, false, false));
2441+
return getFieldTypeAccessorFn(IGM, type, types);
2442+
}
2443+
24312444
for (auto &elt : enumElements) {
24322445
assert(elt.decl->hasArgumentType() && "enum case doesn't have arg?!");
24332446
auto caseType = elt.decl->getArgumentType()->getCanonicalType();
@@ -4813,8 +4826,7 @@ namespace {
48134826
assert(var->hasStorage() &&
48144827
"storing field offset for computed property?!");
48154828
SILType structType =
4816-
SILType::getPrimitiveAddressType(
4817-
Target->getDeclaredTypeInContext()->getCanonicalType());
4829+
IGM.getLoweredType(Target->getDeclaredTypeInContext());
48184830

48194831
llvm::Constant *offset =
48204832
emitPhysicalStructMemberFixedOffset(IGM, structType, var);
@@ -4943,9 +4955,9 @@ namespace {
49434955
llvm::Value *vwtable) {
49444956
// Nominal types are always preserved through SIL lowering.
49454957
auto structTy = Target->getDeclaredTypeInContext()->getCanonicalType();
4946-
IGM.getTypeInfoForLowered(structTy)
4958+
IGM.getTypeInfoForUnlowered(structTy)
49474959
.initializeMetadata(IGF, metadata, vwtable,
4948-
SILType::getPrimitiveAddressType(structTy));
4960+
IGF.IGM.getLoweredType(structTy));
49494961
}
49504962
};
49514963
}
@@ -5050,7 +5062,7 @@ class EnumMetadataBuilder
50505062

50515063
void addPayloadSize() {
50525064
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5053-
auto &enumTI = IGM.getTypeInfoForLowered(enumTy);
5065+
auto &enumTI = IGM.getTypeInfoForUnlowered(enumTy);
50545066
if (!enumTI.isFixedSize(ResilienceExpansion::Maximal)) {
50555067
addConstantWord(0);
50565068
HasUnfilledPayloadSize = true;
@@ -5120,7 +5132,7 @@ class GenericEnumMetadataBuilder
51205132
// In all cases where a payload size is demanded in the metadata, it's
51215133
// runtime-dependent, so fill in a zero here.
51225134
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5123-
auto &enumTI = IGM.getTypeInfoForLowered(enumTy);
5135+
auto &enumTI = IGM.getTypeInfoForUnlowered(enumTy);
51245136
(void) enumTI;
51255137
assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) &&
51265138
"non-generic, non-resilient enums don't need payload size in metadata");
@@ -5132,9 +5144,9 @@ class GenericEnumMetadataBuilder
51325144
llvm::Value *vwtable) {
51335145
// Nominal types are always preserved through SIL lowering.
51345146
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
5135-
IGM.getTypeInfoForLowered(enumTy)
5147+
IGM.getTypeInfoForUnlowered(enumTy)
51365148
.initializeMetadata(IGF, metadata, vwtable,
5137-
SILType::getPrimitiveAddressType(enumTy));
5149+
IGF.IGM.getLoweredType(enumTy));
51385150
}
51395151
};
51405152

0 commit comments

Comments
 (0)