Skip to content

[3.0] Fix @escaping printing (from #4905) #4931

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
3 changes: 3 additions & 0 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ struct PrintOptions {
/// protocol requirements.
bool SkipOverrides = false;

/// Whether to skip parameter type attributes
bool SkipParameterTypeAttributes = false;

/// Whether to print a long attribute like '\@available' on a separate line
/// from the declaration or other attributes.
bool PrintLongAttrsOnSeparateLines = false;
Expand Down
149 changes: 124 additions & 25 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1276,22 +1276,79 @@ class NameAliasType : public TypeBase {
}
};

// 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 {
enum ParameterFlags : uint8_t {
None = 0,
Variadic = 1 << 0,
AutoClosure = 1 << 1,
Escaping = 1 << 2,

NumBits = 3
};
OptionSet<ParameterFlags> value;
static_assert(NumBits < 8*sizeof(value), "overflowed");

ParameterTypeFlags(OptionSet<ParameterFlags, uint8_t> val) : value(val) {}

public:
ParameterTypeFlags() = default;

ParameterTypeFlags(bool variadic, bool autoclosure, bool escaping)
: value((variadic ? Variadic : 0) |
(autoclosure ? AutoClosure : 0) |
(escaping ? Escaping : 0)) {}

/// Create one from what's present in the parameter type
inline static ParameterTypeFlags fromParameterType(Type paramTy,
bool isVariadic);

bool isNone() const { return !value; }
bool isVariadic() const { return value.contains(Variadic); }
bool isAutoClosure() const { return value.contains(AutoClosure); }
bool isEscaping() const { return value.contains(Escaping); }

ParameterTypeFlags withEscaping(bool escaping) const {
return ParameterTypeFlags(escaping ? value | ParameterTypeFlags::Escaping
: value - ParameterTypeFlags::Escaping);
}

bool operator ==(const ParameterTypeFlags &other) const {
return value.toRaw() == other.value.toRaw();
}

uint8_t toRaw() const { return value.toRaw(); }
};

/// ParenType - A paren type is a type that's been written in parentheses.
class ParenType : public TypeBase {
Type UnderlyingType;
ParameterTypeFlags parameterFlags;

friend class ASTContext;
ParenType(Type UnderlyingType, RecursiveTypeProperties properties)
: TypeBase(TypeKind::Paren, nullptr, properties),
UnderlyingType(UnderlyingType) {}
ParenType(Type UnderlyingType, RecursiveTypeProperties properties,
ParameterTypeFlags flags)
: TypeBase(TypeKind::Paren, nullptr, properties),
UnderlyingType(UnderlyingType), parameterFlags(flags) {}

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

static ParenType *get(const ASTContext &C, Type underlying);

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

/// Remove one level of top-level sugar from this type.
TypeBase *getSinglyDesugaredType();

/// Get the parameter flags
ParameterTypeFlags getParameterFlags() const { return parameterFlags; }

// Implement isa/cast/dyncast/etc.
static bool classof(const TypeBase *T) {
return T->getKind() == TypeKind::Paren;
Expand All @@ -1300,33 +1357,45 @@ class ParenType : public TypeBase {

/// TupleTypeElt - This represents a single element of a tuple.
class TupleTypeElt {
/// An optional name for the field, along with a bit indicating whether it
/// is variadic.
llvm::PointerIntPair<Identifier, 1, bool> NameAndVariadic;
/// An optional name for the field.
Identifier Name;

/// \brief 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;
inline /*implicit*/ TupleTypeElt(Type ty,
Identifier name = Identifier(),
bool isVariadic = false);
inline /*implicit*/ TupleTypeElt(Type ty, Identifier name,
bool isVariadic, bool isAutoClosure,
bool isEscaping);

TupleTypeElt(Type ty, Identifier name = Identifier(),
ParameterTypeFlags PTFlags = {})
: Name(name), ElementType(ty), Flags(PTFlags) {}

/*implicit*/ TupleTypeElt(TypeBase *Ty)
: NameAndVariadic(Identifier(), false), ElementType(Ty) { }
: Name(Identifier()), ElementType(Ty), Flags() { }

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

Type getType() const { return ElementType.getPointer(); }

ParameterTypeFlags getParameterFlags() const { return Flags; }

/// Determine whether this field is variadic.
bool isVararg() const {
return NameAndVariadic.getInt();
}
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 an escaping parameter closure.
bool isEscaping() const { return Flags.isEscaping(); }

static inline Type getVarargBaseTy(Type VarArgT);

Expand All @@ -1339,8 +1408,16 @@ class TupleTypeElt {

/// Retrieve a copy of this tuple type element with the type replaced.
TupleTypeElt getWithType(Type T) const {
return TupleTypeElt(T, getName(), isVararg());
return TupleTypeElt(T, getName(), getParameterFlags());
}

/// Retrieve a copy of this tuple type element with the name replaced.
TupleTypeElt getWithName(Identifier name) const {
return TupleTypeElt(getType(), name, getParameterFlags());
}

/// Retrieve a copy of this tuple type element with no name
TupleTypeElt getWithoutName() const { return getWithName(Identifier()); }
};

inline Type getTupleEltType(const TupleTypeElt &elt) {
Expand Down Expand Up @@ -2357,11 +2434,20 @@ struct CallArgParam {
/// Whether the parameter has a default argument. Not valid for arguments.
bool HasDefaultArgument = false;

/// Whether the parameter is variadic. Not valid for arguments.
bool Variadic = false;
/// Parameter specific flags, not valid for arguments
ParameterTypeFlags parameterFlags = {};

/// Whether the argument or parameter has a label.
bool hasLabel() const { return !Label.empty(); }

/// Whether the parameter is varargs
bool isVariadic() const { return parameterFlags.isVariadic(); }

/// Whether the parameter is autoclosure
bool isAutoClosure() const { return parameterFlags.isAutoClosure(); }

/// Whether the parameter is escaping
bool isEscaping() const { return parameterFlags.isEscaping(); }
};

/// Break an argument type into an array of \c CallArgParams.
Expand Down Expand Up @@ -4445,16 +4531,19 @@ inline bool TypeBase::mayHaveSuperclass() {
return is<DynamicSelfType>();
}

inline TupleTypeElt::TupleTypeElt(Type ty,
Identifier name,
bool isVariadic)
: NameAndVariadic(name, isVariadic), ElementType(ty)
{
inline TupleTypeElt::TupleTypeElt(Type ty, Identifier name, bool isVariadic,
bool isAutoClosure, bool isEscaping)
: Name(name), ElementType(ty),
Flags(isVariadic, isAutoClosure, isEscaping) {
assert(!isVariadic ||
isa<ErrorType>(ty.getPointer()) ||
isa<ArraySliceType>(ty.getPointer()) ||
(isa<BoundGenericType>(ty.getPointer()) &&
ty->castTo<BoundGenericType>()->getGenericArgs().size() == 1));
assert(!isAutoClosure || (ty->is<AnyFunctionType>() &&
ty->castTo<AnyFunctionType>()->isAutoClosure()));
assert(!isEscaping || (ty->is<AnyFunctionType>() &&
!ty->castTo<AnyFunctionType>()->isNoEscape()));
}

inline Type TupleTypeElt::getVarargBaseTy(Type VarArgT) {
Expand All @@ -4469,6 +4558,16 @@ inline Type TupleTypeElt::getVarargBaseTy(Type VarArgT) {
return T;
}

/// Create one from what's present in the parameter decl and type
inline ParameterTypeFlags
ParameterTypeFlags::fromParameterType(Type paramTy, bool isVariadic) {
bool autoclosure = paramTy->is<AnyFunctionType>() &&
paramTy->castTo<AnyFunctionType>()->isAutoClosure();
bool escaping = paramTy->is<AnyFunctionType>() &&
!paramTy->castTo<AnyFunctionType>()->isNoEscape();
return {isVariadic, autoclosure, escaping};
}

inline Identifier SubstitutableType::getName() const {
if (auto Archetype = dyn_cast<ArchetypeType>(this))
return Archetype->getName();
Expand Down
15 changes: 10 additions & 5 deletions include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const uint16_t VERSION_MAJOR = 0;
/// in source control, you should also update the comment to briefly
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
const uint16_t VERSION_MINOR = 260; // Last change: open
const uint16_t VERSION_MINOR = 269; // Last change: parameter type flags

using DeclID = PointerEmbeddedInt<unsigned, 31>;
using DeclIDField = BCFixed<31>;
Expand Down Expand Up @@ -570,7 +570,10 @@ namespace decls_block {

using ParenTypeLayout = BCRecordLayout<
PAREN_TYPE,
TypeIDField // inner type
TypeIDField, // inner type
BCFixed<1>, // vararg?
BCFixed<1>, // autoclosure?
BCFixed<1> // escaping?
>;

using TupleTypeLayout = BCRecordLayout<
Expand All @@ -579,9 +582,11 @@ namespace decls_block {

using TupleTypeEltLayout = BCRecordLayout<
TUPLE_TYPE_ELT,
IdentifierIDField, // name
TypeIDField, // type
BCFixed<1> // vararg?
IdentifierIDField, // name
TypeIDField, // type
BCFixed<1>, // vararg?
BCFixed<1>, // autoclosure?
BCFixed<1> // escaping?
>;

using FunctionTypeLayout = BCRecordLayout<
Expand Down
17 changes: 10 additions & 7 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ struct ASTContext::Implementation {
llvm::DenseMap<std::pair<Type, Type>, DictionaryType *> DictionaryTypes;
llvm::DenseMap<Type, OptionalType*> OptionalTypes;
llvm::DenseMap<Type, ImplicitlyUnwrappedOptionalType*> ImplicitlyUnwrappedOptionalTypes;
llvm::DenseMap<Type, ParenType*> ParenTypes;
llvm::DenseMap<std::pair<Type, unsigned>, ParenType*> ParenTypes;
llvm::DenseMap<uintptr_t, ReferenceStorageType*> ReferenceStorageTypes;
llvm::DenseMap<Type, LValueType*> LValueTypes;
llvm::DenseMap<Type, InOutType*> InOutTypes;
Expand Down Expand Up @@ -2637,13 +2637,14 @@ BuiltinVectorType *BuiltinVectorType::get(const ASTContext &context,
return vecTy;
}


ParenType *ParenType::get(const ASTContext &C, Type underlying) {
ParenType *ParenType::get(const ASTContext &C, Type underlying,
ParameterTypeFlags flags) {
auto properties = underlying->getRecursiveProperties();
auto arena = getArena(properties);
ParenType *&Result = C.Impl.getArena(arena).ParenTypes[underlying];
ParenType *&Result =
C.Impl.getArena(arena).ParenTypes[{underlying, flags.toRaw()}];
if (Result == 0) {
Result = new (C, arena) ParenType(underlying, properties);
Result = new (C, arena) ParenType(underlying, properties, flags);
}
return Result;
}
Expand All @@ -2656,15 +2657,17 @@ void TupleType::Profile(llvm::FoldingSetNodeID &ID,
ArrayRef<TupleTypeElt> Fields) {
ID.AddInteger(Fields.size());
for (const TupleTypeElt &Elt : Fields) {
ID.AddPointer(Elt.NameAndVariadic.getOpaqueValue());
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].getType());
return ParenType::get(C, Fields[0].getType(),
Fields[0].getParameterFlags());

RecursiveTypeProperties properties;
for (const TupleTypeElt &Elt : Fields) {
Expand Down
19 changes: 12 additions & 7 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2621,6 +2621,15 @@ namespace {
return OS;
}

void dumpParameterFlags(ParameterTypeFlags paramFlags) {
if (paramFlags.isVariadic())
printFlag("vararg");
if (paramFlags.isAutoClosure())
printFlag("autoclosure");
if (paramFlags.isEscaping())
printFlag("escaping");
}

public:
PrintType(raw_ostream &os, unsigned indent) : OS(os), Indent(indent) { }

Expand Down Expand Up @@ -2684,6 +2693,7 @@ namespace {

void visitParenType(ParenType *T, StringRef label) {
printCommon(T, label, "paren_type");
dumpParameterFlags(T->getParameterFlags());
printRec(T->getUnderlyingType());
OS << ")";
}
Expand All @@ -2698,9 +2708,7 @@ namespace {
PrintWithColorRAII(OS, TypeFieldColor) << "tuple_type_elt";
if (elt.hasName())
printField("name", elt.getName().str());
if (elt.isVararg())
printFlag("vararg");

dumpParameterFlags(elt.getParameterFlags());
printRec(elt.getType());
OS << ")";
}
Expand Down Expand Up @@ -2911,10 +2919,7 @@ namespace {
}

printFlag(T->isAutoClosure(), "autoclosure");

// Dump out either @noescape or @escaping
printFlag(!T->isNoEscape(), "@escaping");

printFlag(!T->isNoEscape(), "escaping");
printFlag(T->throws(), "throws");

printRec("input", T->getInput());
Expand Down
Loading