diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 1dbedc7d13600..c50defaf6b48e 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -413,15 +413,19 @@ class alignas(1 << TypeAlignInBits) TypeBase // clang-format off union { uint64_t OpaqueBits; - SWIFT_INLINE_BITFIELD_BASE(TypeBase, bitmax(NumTypeKindBits,8) + - RecursiveTypeProperties::BitWidth + 1, + SWIFT_INLINE_BITFIELD_BASE(TypeBase, NumTypeKindBits + + RecursiveTypeProperties::BitWidth + 1 + 3, /// Kind - The discriminator that indicates what subclass of type this is. - Kind : bitmax(NumTypeKindBits,8), + Kind : NumTypeKindBits, Properties : RecursiveTypeProperties::BitWidth, /// Whether this type is canonical or not. - IsCanonical : 1 + IsCanonical : 1, + + ComputedInvertibleConformances : 1, + IsCopyable : 1, + IsEscapable : 1 ); SWIFT_INLINE_BITFIELD(ErrorType, TypeBase, 1, @@ -441,8 +445,7 @@ class alignas(1 << TypeAlignInBits) TypeBase HasClangTypeInfo : 1, HasThrownError : 1, HasLifetimeDependencies : 1, - : NumPadBits, - NumParams : 16 + NumParams : 15 ); SWIFT_INLINE_BITFIELD_FULL(ArchetypeType, TypeBase, 1+1+16, @@ -455,9 +458,8 @@ class alignas(1 << TypeAlignInBits) TypeBase SWIFT_INLINE_BITFIELD_FULL(TypeVariableType, TypeBase, 7+28, /// Type variable options. Options : 7, - : NumPadBits, /// The unique number assigned to this type variable. - ID : 28 + ID : 27 ); SWIFT_INLINE_BITFIELD_FULL(ErrorUnionType, TypeBase, 32, @@ -560,6 +562,11 @@ class alignas(1 << TypeAlignInBits) TypeBase Bits.TypeBase.IsCanonical = true; Context = CanTypeCtx; } + + Bits.TypeBase.ComputedInvertibleConformances = false; + Bits.TypeBase.IsCopyable = false; + Bits.TypeBase.IsEscapable = false; + setRecursiveProperties(properties); } @@ -591,6 +598,8 @@ class alignas(1 << TypeAlignInBits) TypeBase private: CanType computeCanonicalType(); + void computeInvertibleConformances(); + public: /// getCanonicalType - Return the canonical version of this type, which has /// sugar from all levels stripped off. diff --git a/lib/AST/ConformanceLookup.cpp b/lib/AST/ConformanceLookup.cpp index 29089041a968a..1eb1c371053c1 100644 --- a/lib/AST/ConformanceLookup.cpp +++ b/lib/AST/ConformanceLookup.cpp @@ -897,68 +897,60 @@ bool TypeBase::isSendableType() { /// Copyable and Escapable checking utilities /// -/// Preprocesses a type before querying whether it conforms to an invertible. -static CanType preprocessTypeForInvertibleQuery(Type orig) { - Type type = orig; - - // Strip off any StorageType wrapper. - type = type->getReferenceStorageReferent(); - - // Pack expansions such as `repeat T` themselves do not have conformances, - // so check its pattern type for conformance. - if (auto *pet = type->getAs()) { - type = pet->getPatternType()->getCanonicalType(); - } - - // Strip @lvalue and canonicalize. - auto canType = type->getRValueType()->getCanonicalType(); - return canType; -} - static bool conformsToInvertible(CanType type, InvertibleProtocolKind ip) { - auto &ctx = type->getASTContext(); - - auto *proto = ctx.getProtocol(getKnownProtocolKind(ip)); - assert(proto && "missing Copyable/Escapable from stdlib!"); + // FIXME: Remove these. + if (isa(type)) + return true; - // Must not have a type parameter! - assert(!type->hasTypeParameter() && "caller forgot to mapTypeIntoContext!"); + if (isa(type)) + return true; - assert(!type->hasUnboundGenericType() && "a UGT has no conformances!"); + auto *proto = type->getASTContext().getProtocol(getKnownProtocolKind(ip)); + ASSERT(proto); - assert(!type->is()); + return (bool) checkConformance(type, proto, /*allowMissing=*/false); +} - // FIXME: lldb misbehaves by getting here with a SILPackType. - // just pretend it it conforms. - if (type->is()) - return true; +void TypeBase::computeInvertibleConformances() { + Bits.TypeBase.ComputedInvertibleConformances = true; - if (type->is()) { - return true; - } - - // The SIL types in the AST do not have real conformances, and should have - // been handled in SILType instead. - assert(!(type->is())); + Type type(this); - const bool conforms = - (bool) checkConformance(type, proto, /*allowMissing=*/false); + // FIXME: Remove all of the below. Callers should be changed to perform any + // necessary unwrapping themselves. - return conforms; + // Pack expansions such as `repeat T` themselves do not have conformances, + // so check its pattern type for conformance. + if (auto *pet = type->getAs()) + type = pet->getPatternType(); + + auto canType = type->getReferenceStorageReferent() + ->getWithoutSpecifierType() + ->getCanonicalType(); + + assert(!canType->hasTypeParameter()); + assert(!canType->hasUnboundGenericType()); + assert(!isa(canType)); + assert(!isa(canType)); + + Bits.TypeBase.IsCopyable = conformsToInvertible( + canType, InvertibleProtocolKind::Copyable); + Bits.TypeBase.IsEscapable = conformsToInvertible( + canType, InvertibleProtocolKind::Escapable); } /// \returns true iff this type lacks conformance to Copyable. bool TypeBase::isNoncopyable() { - auto canType = preprocessTypeForInvertibleQuery(this); - return !conformsToInvertible(canType, InvertibleProtocolKind::Copyable); + if (!Bits.TypeBase.ComputedInvertibleConformances) + computeInvertibleConformances(); + return !Bits.TypeBase.IsCopyable; } +/// \returns true iff this type conforms to Escaping. bool TypeBase::isEscapable() { - auto canType = preprocessTypeForInvertibleQuery(this); - return conformsToInvertible(canType, InvertibleProtocolKind::Escapable); + if (!Bits.TypeBase.ComputedInvertibleConformances) + computeInvertibleConformances(); + return Bits.TypeBase.IsEscapable; } bool TypeBase::isEscapable(GenericSignature sig) {