Skip to content

AST: Cache isNoncopyable() and isEscapable() bits inside TypeBase #82854

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
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
25 changes: 17 additions & 8 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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.
Expand Down
86 changes: 39 additions & 47 deletions lib/AST/ConformanceLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<PackExpansionType>()) {
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<SILPackType>(type))
return true;

// Must not have a type parameter!
assert(!type->hasTypeParameter() && "caller forgot to mapTypeIntoContext!");
if (isa<SILTokenType>(type))
return true;

assert(!type->hasUnboundGenericType() && "a UGT has no conformances!");
auto *proto = type->getASTContext().getProtocol(getKnownProtocolKind(ip));
ASSERT(proto);

assert(!type->is<PackExpansionType>());
return (bool) checkConformance(type, proto, /*allowMissing=*/false);
}

// FIXME: lldb misbehaves by getting here with a SILPackType.
// just pretend it it conforms.
if (type->is<SILPackType>())
return true;
void TypeBase::computeInvertibleConformances() {
Bits.TypeBase.ComputedInvertibleConformances = true;

if (type->is<SILTokenType>()) {
return true;
}

// The SIL types in the AST do not have real conformances, and should have
// been handled in SILType instead.
assert(!(type->is<SILBoxType,
SILMoveOnlyWrappedType,
SILPackType,
SILTokenType>()));
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<PackExpansionType>())
type = pet->getPatternType();

auto canType = type->getReferenceStorageReferent()
->getWithoutSpecifierType()
->getCanonicalType();

assert(!canType->hasTypeParameter());
assert(!canType->hasUnboundGenericType());
assert(!isa<SILBoxType>(canType));
assert(!isa<SILMoveOnlyWrappedType>(canType));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just double-checking: are the prior special cases for SILTokenType and SILPackType no longer needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they are, and the build fails without them. bringing them back :)


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) {
Expand Down