Skip to content

[AST] Remove ParameterTypeFlags from ParenType and TupleType #60263

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 4 commits into from
Aug 2, 2022
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
4 changes: 2 additions & 2 deletions include/swift/AST/TypeMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ class TypeMatcher {
const auto &firstElt = firstTuple->getElements()[i];
const auto &secondElt = secondTuple->getElements()[i];

if (firstElt.getName() != secondElt.getName() ||
firstElt.isVararg() != secondElt.isVararg())
if (firstElt.getName() != secondElt.getName()) {
return mismatch(firstTuple.getPointer(), secondTuple,
sugaredFirstType);
}

// Recurse on the tuple elements.
if (!this->visit(firstTuple.getElementType(i), secondElt.getType(),
Expand Down
136 changes: 43 additions & 93 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,11 +363,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
HasCachedType : 1
);

enum { NumFlagBits = 8 };
SWIFT_INLINE_BITFIELD(ParenType, SugarType, NumFlagBits,
/// Whether there is an original type.
Flags : NumFlagBits
);
SWIFT_INLINE_BITFIELD_EMPTY(ParenType, SugarType);

SWIFT_INLINE_BITFIELD_FULL(AnyFunctionType, TypeBase, NumAFTExtInfoBits+1+1+1+16,
/// Extra information which affects how the function is called, like
Expand Down Expand Up @@ -429,11 +425,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
ArgCount : 32
);

SWIFT_INLINE_BITFIELD_FULL(TupleType, TypeBase, 1+32,
/// Whether an element of the tuple is inout, __shared or __owned.
/// Values cannot have such tuple types in the language.
HasElementWithOwnership : 1,

SWIFT_INLINE_BITFIELD_FULL(TupleType, TypeBase, 32,
: NumPadBits,

/// The number of elements of the tuple.
Expand Down Expand Up @@ -724,8 +716,8 @@ class alignas(1 << TypeAlignInBits) TypeBase
return getRecursiveProperties().isLValue();
}

/// Is this a first-class value type, meaning it is not an InOutType or a
/// tuple type containing an InOutType?
/// Is this a first-class value type, meaning it is not an LValueType or an
/// InOutType.
bool isMaterializable();

/// Is this a non-escaping type, that is, a non-escaping function type or a
Expand Down Expand Up @@ -1995,11 +1987,6 @@ class TypeAliasType final
}
};

// TODO: As part of AST modernization, replace with a proper
// 'ParameterTypeElt' or similar, and have FunctionTypes only have a list
// of 'ParameterTypeElt's. Then, this information can be removed from
// TupleTypeElt.
//
/// Provide parameter type relevant flags, i.e. variadic, autoclosure, and
/// escaping.
class ParameterTypeFlags {
Expand Down Expand Up @@ -2123,6 +2110,28 @@ class ParameterTypeFlags {
uint16_t toRaw() const { return value.toRaw(); }
};

/// A type that indicates how parameter flags should be handled in an operation
/// that requires the conversion into a type that doesn't support them, such as
/// tuples.
enum class ParameterFlagHandling {
/// Ignores any parameter flags that may be present, dropping them from the
/// result. This should only be used in specific cases, including e.g:
///
/// - The flags have already been handled, and unsuitable flags have been
/// rejected or asserted to not be present.
/// - The flags aren't relevant for the particular conversion (e.g for type
/// printing or compatibility logic).
/// - The conversion is only interested in the 'internal argument' of a
/// parameter, in which case only the type and label are relevant.
///
/// In all other cases, you ought to verify that unsuitable flags are not
/// present, or add assertions to that effect.
IgnoreNonEmpty,

/// Asserts that no parameter flags are present.
AssertEmpty
};

class YieldTypeFlags {
enum YieldFlags : uint8_t {
None = 0,
Expand Down Expand Up @@ -2196,21 +2205,12 @@ class YieldTypeFlags {

/// ParenType - A paren type is a type that's been written in parentheses.
class ParenType : public SugarType {
friend class ASTContext;

ParenType(Type UnderlyingType, RecursiveTypeProperties properties,
ParameterTypeFlags flags);
ParenType(Type UnderlyingType, RecursiveTypeProperties properties);

public:
Type getUnderlyingType() const { return getSinglyDesugaredType(); }

static ParenType *get(const ASTContext &C, Type underlying,
ParameterTypeFlags flags = {});
static ParenType *get(const ASTContext &C, Type underlying);

/// Get the parameter flags
ParameterTypeFlags getParameterFlags() const {
return ParameterTypeFlags::fromRaw(Bits.ParenType.Flags);
}
Type getUnderlyingType() const { return getSinglyDesugaredType(); }

// Implement isa/cast/dyncast/etc.
static bool classof(const TypeBase *T) {
Expand All @@ -2226,37 +2226,17 @@ class TupleTypeElt {
/// This is the type of the field.
Type ElementType;

/// Flags that are specific to and relevant for parameter types
ParameterTypeFlags Flags;

friend class TupleType;

public:
TupleTypeElt() = default;
TupleTypeElt(Type ty, Identifier name = Identifier(),
ParameterTypeFlags fl = {});

TupleTypeElt(Type ty, Identifier name = Identifier());

bool hasName() const { return !Name.empty(); }
Identifier getName() const { return Name; }

Type getRawType() const { return ElementType; }
Type getType() const;

ParameterTypeFlags getParameterFlags() const { return Flags; }
Type getType() const { return ElementType; }

/// Determine whether this field is variadic.
bool isVararg() const { return Flags.isVariadic(); }

/// Determine whether this field is an autoclosure parameter closure.
bool isAutoClosure() const { return Flags.isAutoClosure(); }

/// Determine whether this field is marked 'inout'.
bool isInOut() const { return Flags.isInOut(); }

/// Remove the type of this varargs element designator, without the array
/// type wrapping it.
Type getVarargBaseTy() const;

/// Retrieve a copy of this tuple type element with the type replaced.
TupleTypeElt getWithType(Type T) const;

Expand Down Expand Up @@ -2318,11 +2298,6 @@ class TupleType final : public TypeBase, public llvm::FoldingSetNode,
/// getNamedElementId - If this tuple has an element with the specified name,
/// return the element index, otherwise return -1.
int getNamedElementId(Identifier I) const;

/// Returns true if this tuple has inout, __shared or __owned elements.
bool hasElementWithOwnership() const {
return static_cast<bool>(Bits.TupleType.HasElementWithOwnership);
}

// Implement isa/cast/dyncast/etc.
static bool classof(const TypeBase *T) {
Expand All @@ -2337,13 +2312,11 @@ class TupleType final : public TypeBase, public llvm::FoldingSetNode,

private:
TupleType(ArrayRef<TupleTypeElt> elements, const ASTContext *CanCtx,
RecursiveTypeProperties properties,
bool hasElementWithOwnership)
: TypeBase(TypeKind::Tuple, CanCtx, properties) {
Bits.TupleType.HasElementWithOwnership = hasElementWithOwnership;
Bits.TupleType.Count = elements.size();
std::uninitialized_copy(elements.begin(), elements.end(),
getTrailingObjects<TupleTypeElt>());
RecursiveTypeProperties properties)
: TypeBase(TypeKind::Tuple, CanCtx, properties) {
Bits.TupleType.Count = elements.size();
std::uninitialized_copy(elements.begin(), elements.end(),
getTrailingObjects<TupleTypeElt>());
}
};
BEGIN_CAN_TYPE_WRAPPER(TupleType, Type)
Expand Down Expand Up @@ -3127,10 +3100,9 @@ class AnyFunctionType : public TypeBase {
public:
/// Take an array of parameters and turn it into a tuple or paren type.
///
/// \param wantParamFlags Whether to preserve the parameter flags from the
/// given set of parameters.
/// \param paramFlagHandling How to handle the parameter flags.
static Type composeTuple(ASTContext &ctx, ArrayRef<Param> params,
bool wantParamFlags = true);
ParameterFlagHandling paramFlagHandling);

/// Given two arrays of parameters determine if they are equal in their
/// canonicalized form. Internal labels and type sugar is *not* taken into
Expand Down Expand Up @@ -6533,17 +6505,9 @@ inline bool TypeBase::isTypeSequenceParameter() {
t->castTo<GenericTypeParamType>()->isTypeSequence();
}

// TODO: This will become redundant once InOutType is removed.
inline bool TypeBase::isMaterializable() {
if (hasLValueType())
return false;

if (is<InOutType>())
return false;

if (auto *TTy = getAs<TupleType>())
return !TTy->hasElementWithOwnership();

return true;
return !(hasLValueType() || is<InOutType>());
}

inline GenericTypeParamType *TypeBase::getRootGenericParam() {
Expand Down Expand Up @@ -6755,26 +6719,12 @@ inline bool CanType::isActuallyCanonicalOrNull() const {
getPointer()->isCanonical();
}

inline Type TupleTypeElt::getVarargBaseTy() const {
TypeBase *T = getType().getPointer();
if (auto *AT = dyn_cast<VariadicSequenceType>(T))
return AT->getBaseType();
if (auto *BGT = dyn_cast<BoundGenericType>(T)) {
// It's the stdlib Array<T>.
return BGT->getGenericArgs()[0];
}
assert(T->hasError());
return T;
}

inline TupleTypeElt TupleTypeElt::getWithName(Identifier name) const {
assert(getParameterFlags().isInOut() == getType()->is<InOutType>());
return TupleTypeElt(getRawType(), name, getParameterFlags());
return TupleTypeElt(getType(), name);
}

inline TupleTypeElt TupleTypeElt::getWithType(Type T) const {
auto flags = getParameterFlags().withInOut(T->is<InOutType>());
return TupleTypeElt(T->getInOutObjectType(), getName(), flags);
return TupleTypeElt(T, getName());
}

/// Create one from what's present in the parameter decl and type
Expand Down
5 changes: 3 additions & 2 deletions lib/APIDigester/ModuleAnalyzerNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1601,8 +1601,9 @@ SwiftDeclCollector::constructTypeNode(Type T, TypeInitInfo Info) {
// Still, return type first
Root->addChild(constructTypeNode(Fun->getResult()));

auto Input = AnyFunctionType::composeTuple(Fun->getASTContext(),
Fun->getParams());
auto Input =
AnyFunctionType::composeTuple(Fun->getASTContext(), Fun->getParams(),
ParameterFlagHandling::IgnoreNonEmpty);
Root->addChild(constructTypeNode(Input));
return Root;
}
Expand Down
74 changes: 22 additions & 52 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,7 @@ struct ASTContext::Implementation {
llvm::DenseMap<Type, VariadicSequenceType*> VariadicSequenceTypes;
llvm::DenseMap<std::pair<Type, Type>, DictionaryType *> DictionaryTypes;
llvm::DenseMap<Type, OptionalType*> OptionalTypes;
llvm::DenseMap<Type, ParenType*> SimpleParenTypes; // Most are simple
llvm::DenseMap<std::pair<Type, unsigned>, ParenType*> ParenTypes;
llvm::DenseMap<Type, ParenType*> ParenTypes;
llvm::DenseMap<uintptr_t, ReferenceStorageType*> ReferenceStorageTypes;
llvm::DenseMap<Type, LValueType*> LValueTypes;
llvm::DenseMap<Type, InOutType*> InOutTypes;
Expand Down Expand Up @@ -2626,7 +2625,6 @@ size_t ASTContext::Implementation::Arena::getTotalMemory() const {
llvm::capacity_in_bytes(DictionaryTypes) +
llvm::capacity_in_bytes(OptionalTypes) +
llvm::capacity_in_bytes(VariadicSequenceTypes) +
llvm::capacity_in_bytes(SimpleParenTypes) +
llvm::capacity_in_bytes(ParenTypes) +
llvm::capacity_in_bytes(ReferenceStorageTypes) +
llvm::capacity_in_bytes(LValueTypes) +
Expand Down Expand Up @@ -2836,22 +2834,14 @@ BuiltinVectorType *BuiltinVectorType::get(const ASTContext &context,
return vecTy;
}

ParenType *ParenType::get(const ASTContext &C, Type underlying,
ParameterTypeFlags fl) {
if (fl.isInOut())
assert(!underlying->is<InOutType>() && "caller did not pass a base type");
if (underlying->is<InOutType>())
assert(fl.isInOut() && "caller did not set flags correctly");

ParenType *ParenType::get(const ASTContext &C, Type underlying) {
auto properties = underlying->getRecursiveProperties();
auto arena = getArena(properties);
auto flags = fl.toRaw();
ParenType *&Result = flags == 0
? C.getImpl().getArena(arena).SimpleParenTypes[underlying]
: C.getImpl().getArena(arena).ParenTypes[{underlying, flags}];
ParenType *&Result = C.getImpl().getArena(arena).ParenTypes[underlying];
if (Result == nullptr) {
Result = new (C, arena) ParenType(underlying,
properties, fl);
Result = new (C, arena) ParenType(underlying, properties);
assert((C.hadError() || !underlying->is<InOutType>()) &&
"Cannot wrap InOutType");
}
return Result;
}
Expand All @@ -2866,35 +2856,19 @@ void TupleType::Profile(llvm::FoldingSetNodeID &ID,
for (const TupleTypeElt &Elt : Fields) {
ID.AddPointer(Elt.Name.get());
ID.AddPointer(Elt.getType().getPointer());
ID.AddInteger(Elt.Flags.toRaw());
}
}

/// getTupleType - Return the uniqued tuple type with the specified elements.
Type TupleType::get(ArrayRef<TupleTypeElt> Fields, const ASTContext &C) {
if (Fields.size() == 1 && !Fields[0].isVararg() && !Fields[0].hasName())
return ParenType::get(C, Fields[0].getRawType(),
Fields[0].getParameterFlags());
if (Fields.size() == 1 && !Fields[0].hasName())
return ParenType::get(C, Fields[0].getType());

RecursiveTypeProperties properties;
bool hasElementWithOwnership = false;
for (const TupleTypeElt &Elt : Fields) {
auto eltTy = Elt.getType();
if (!eltTy) continue;

properties |= eltTy->getRecursiveProperties();
// Recur into paren types and canonicalized paren types. 'inout' in nested
// non-paren tuples are malformed and will be diagnosed later.
if (auto *TTy = Elt.getType()->getAs<TupleType>()) {
if (TTy->getNumElements() == 1)
hasElementWithOwnership |= TTy->hasElementWithOwnership();
} else if (auto *Pty = dyn_cast<ParenType>(Elt.getType().getPointer())) {
hasElementWithOwnership |= (Pty->getParameterFlags().getValueOwnership() !=
ValueOwnership::Default);
} else {
hasElementWithOwnership |= (Elt.getParameterFlags().getValueOwnership() !=
ValueOwnership::Default);
}
}

auto arena = getArena(properties);
Expand All @@ -2919,24 +2893,15 @@ Type TupleType::get(ArrayRef<TupleTypeElt> Fields, const ASTContext &C) {
size_t bytes = totalSizeToAlloc<TupleTypeElt>(Fields.size());
// TupleType will copy the fields list into ASTContext owned memory.
void *mem = C.Allocate(bytes, alignof(TupleType), arena);
auto New = new (mem) TupleType(Fields, IsCanonical ? &C : nullptr, properties,
hasElementWithOwnership);
auto New = new (mem) TupleType(Fields, IsCanonical ? &C : nullptr,
properties);
C.getImpl().getArena(arena).TupleTypes.InsertNode(New, InsertPos);
return New;
}

TupleTypeElt::TupleTypeElt(Type ty, Identifier name,
ParameterTypeFlags fl)
: Name(name), ElementType(ty), Flags(fl) {
if (fl.isInOut())
assert(!ty->is<InOutType>() && "caller did not pass a base type");
if (ty->is<InOutType>())
assert(fl.isInOut() && "caller did not set flags correctly");
}

Type TupleTypeElt::getType() const {
if (Flags.isInOut()) return InOutType::get(ElementType);
return ElementType;
TupleTypeElt::TupleTypeElt(Type ty, Identifier name)
: Name(name), ElementType(ty) {
assert(!ty->is<InOutType>() && "Cannot have InOutType in a tuple");
}

PackExpansionType *PackExpansionType::get(Type patternTy) {
Expand Down Expand Up @@ -3623,12 +3588,17 @@ Type AnyFunctionType::Param::getParameterType(bool forCanonical,
}

Type AnyFunctionType::composeTuple(ASTContext &ctx, ArrayRef<Param> params,
bool wantParamFlags) {
ParameterFlagHandling paramFlagHandling) {
SmallVector<TupleTypeElt, 4> elements;
for (const auto &param : params) {
auto flags = wantParamFlags ? param.getParameterFlags()
: ParameterTypeFlags();
elements.emplace_back(param.getParameterType(), param.getLabel(), flags);
switch (paramFlagHandling) {
case ParameterFlagHandling::IgnoreNonEmpty:
break;
case ParameterFlagHandling::AssertEmpty:
assert(param.getParameterFlags().isNone());
break;
}
elements.emplace_back(param.getParameterType(), param.getLabel());
}
return TupleType::get(elements, ctx);
}
Expand Down
Loading