Skip to content

Commit a2ec0f9

Browse files
committed
[AST] Create ParameterTypeFlags and put them on function params
Long term, we want to refactor the AST to reflect the current programming model in Swift. This would include refactoring FunctionType to take a list of ParameterTypeElt, or something with a better name, that can contain both the type and flags/bits that are only specific to types in parameter position, such as @autoclosure and @escaping. At the same time, noescape-by-default has severely hurt our ability to print types without significant context, as we either have to choose to too aggressively print @escaping or not print it in every situation it occurs, or both. As a gentle step towards the final solution, without uprooting our overall AST structure, and as a way towards fixing the @escaping printing ails, put these bits on the TupleTypeElt and ParenType, which will serve as a model for what ParameterTypeElt will be like in the future. Re-use these flags on CallArgParam, to leverage shared knowledge in the type system. It is a little painful to tack onto these types, but it's minor and will be overhauled soon, which will eventually result in size savings and less complexity overall. This includes all the constraint system adjustments to make these types work and influence type equality and overload resolution as desired. They are encoded in the module format. Additional tests added.
1 parent 0f11feb commit a2ec0f9

File tree

13 files changed

+228
-91
lines changed

13 files changed

+228
-91
lines changed

include/swift/AST/Types.h

Lines changed: 116 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,22 +1276,70 @@ class NameAliasType : public TypeBase {
12761276
}
12771277
};
12781278

1279+
// TODO: As part of AST modernization, replace with a proper
1280+
// 'ParameterTypeElt' or similar, and have FunctionTypes only have a list
1281+
// of 'ParameterTypeElt's. Then, this information can be removed from
1282+
// TupleTypeElt.
1283+
//
1284+
/// Provide parameter type relevant flags, i.e. variadic, autoclosure, and
1285+
/// escaping.
1286+
struct ParameterTypeFlags {
1287+
uint8_t value;
1288+
enum : uint8_t {
1289+
None = 0,
1290+
Variadic = 1 << 0,
1291+
AutoClosure = 1 << 1,
1292+
Escaping = 1 << 2,
1293+
1294+
NumBits = 3
1295+
};
1296+
static_assert(NumBits < 8*sizeof(value), "overflowed");
1297+
1298+
ParameterTypeFlags() : value(None) {}
1299+
1300+
ParameterTypeFlags(uint8_t val) : value(val) {}
1301+
1302+
ParameterTypeFlags(bool variadic, bool autoclosure, bool escaping)
1303+
: value((variadic ? Variadic : 0) |
1304+
(autoclosure ? AutoClosure : 0) |
1305+
(escaping ? Escaping : 0)) {}
1306+
1307+
/// Create one from what's present in the parameter type
1308+
inline static ParameterTypeFlags fromParameterType(Type paramTy,
1309+
bool isVariadic);
1310+
1311+
bool isVariadic() const { return 0 != (value & Variadic); }
1312+
bool isAutoClosure() const { return 0 != (value & AutoClosure); }
1313+
bool isEscaping() const { return 0 != (value & Escaping); }
1314+
1315+
bool operator==(const ParameterTypeFlags &other) {
1316+
return value == other.value;
1317+
}
1318+
};
1319+
12791320
/// ParenType - A paren type is a type that's been written in parentheses.
12801321
class ParenType : public TypeBase {
12811322
Type UnderlyingType;
1323+
ParameterTypeFlags parameterFlags;
12821324

12831325
friend class ASTContext;
1284-
ParenType(Type UnderlyingType, RecursiveTypeProperties properties)
1285-
: TypeBase(TypeKind::Paren, nullptr, properties),
1286-
UnderlyingType(UnderlyingType) {}
1326+
ParenType(Type UnderlyingType, RecursiveTypeProperties properties,
1327+
ParameterTypeFlags flags)
1328+
: TypeBase(TypeKind::Paren, nullptr, properties),
1329+
UnderlyingType(UnderlyingType), parameterFlags(flags) {}
1330+
12871331
public:
12881332
Type getUnderlyingType() const { return UnderlyingType; }
12891333

1290-
static ParenType *get(const ASTContext &C, Type underlying);
1291-
1334+
static ParenType *get(const ASTContext &C, Type underlying,
1335+
ParameterTypeFlags flags = {});
1336+
12921337
/// Remove one level of top-level sugar from this type.
12931338
TypeBase *getSinglyDesugaredType();
12941339

1340+
/// Get the parameter flags
1341+
ParameterTypeFlags getParameterFlags() const { return parameterFlags; }
1342+
12951343
// Implement isa/cast/dyncast/etc.
12961344
static bool classof(const TypeBase *T) {
12971345
return T->getKind() == TypeKind::Paren;
@@ -1300,33 +1348,45 @@ class ParenType : public TypeBase {
13001348

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

13071354
/// \brief This is the type of the field.
13081355
Type ElementType;
13091356

1357+
/// Flags that are specific to and relevant for parameter types
1358+
ParameterTypeFlags Flags;
1359+
13101360
friend class TupleType;
13111361

13121362
public:
13131363
TupleTypeElt() = default;
1314-
inline /*implicit*/ TupleTypeElt(Type ty,
1315-
Identifier name = Identifier(),
1316-
bool isVariadic = false);
1364+
inline /*implicit*/ TupleTypeElt(Type ty, Identifier name,
1365+
bool isVariadic, bool isAutoClosure,
1366+
bool isEscaping);
1367+
1368+
TupleTypeElt(Type ty, Identifier name = Identifier(),
1369+
ParameterTypeFlags PTFlags = {})
1370+
: Name(name), ElementType(ty), Flags(PTFlags) {}
13171371

13181372
/*implicit*/ TupleTypeElt(TypeBase *Ty)
1319-
: NameAndVariadic(Identifier(), false), ElementType(Ty) { }
1373+
: Name(Identifier()), ElementType(Ty), Flags() { }
13201374

1321-
bool hasName() const { return !NameAndVariadic.getPointer().empty(); }
1322-
Identifier getName() const { return NameAndVariadic.getPointer(); }
1375+
bool hasName() const { return !Name.empty(); }
1376+
Identifier getName() const { return Name; }
13231377

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

1380+
ParameterTypeFlags getParameterFlags() const { return Flags; }
1381+
13261382
/// Determine whether this field is variadic.
1327-
bool isVararg() const {
1328-
return NameAndVariadic.getInt();
1329-
}
1383+
bool isVararg() const { return Flags.isVariadic(); }
1384+
1385+
/// Determine whether this field is an autoclosure parameter closure.
1386+
bool isAutoClosure() const { return Flags.isAutoClosure(); }
1387+
1388+
/// Determine whether this field is an escaping parameter closure.
1389+
bool isEscaping() const { return Flags.isEscaping(); }
13301390

13311391
static inline Type getVarargBaseTy(Type VarArgT);
13321392

@@ -1339,12 +1399,20 @@ class TupleTypeElt {
13391399

13401400
/// Retrieve a copy of this tuple type element with the type replaced.
13411401
TupleTypeElt getWithType(Type T) const {
1342-
return TupleTypeElt(T, getName(), isVararg());
1402+
return TupleTypeElt(T, getName(), isVararg(), isAutoClosure(),
1403+
isEscaping());
13431404
}
13441405

13451406
/// Retrieve a copy of this tuple type element with the name replaced.
13461407
TupleTypeElt getWithName(Identifier name = Identifier()) const {
1347-
return TupleTypeElt(getType(), name, isVararg());
1408+
return TupleTypeElt(getType(), name, isVararg(), isAutoClosure(),
1409+
isEscaping());
1410+
}
1411+
1412+
/// Retrieve a copy of this tuple type element with the type and name
1413+
/// replaced.
1414+
TupleTypeElt getWithTypeAndName(Type T, Identifier name) const {
1415+
return TupleTypeElt(T, name, isVararg(), isAutoClosure(), isEscaping());
13481416
}
13491417
};
13501418

@@ -2362,11 +2430,20 @@ struct CallArgParam {
23622430
/// Whether the parameter has a default argument. Not valid for arguments.
23632431
bool HasDefaultArgument = false;
23642432

2365-
/// Whether the parameter is variadic. Not valid for arguments.
2366-
bool Variadic = false;
2433+
/// Parameter specific flags, not valid for arguments
2434+
ParameterTypeFlags parameterFlags = {};
23672435

23682436
/// Whether the argument or parameter has a label.
23692437
bool hasLabel() const { return !Label.empty(); }
2438+
2439+
/// Whether the parameter is varargs
2440+
bool isVariadic() const { return parameterFlags.isVariadic(); }
2441+
2442+
/// Whether the parameter is autoclosure
2443+
bool isAutoClosure() const { return parameterFlags.isAutoClosure(); }
2444+
2445+
/// Whether the parameter is escaping
2446+
bool isEscaping() const { return parameterFlags.isEscaping(); }
23702447
};
23712448

23722449
/// Break an argument type into an array of \c CallArgParams.
@@ -4450,16 +4527,19 @@ inline bool TypeBase::mayHaveSuperclass() {
44504527
return is<DynamicSelfType>();
44514528
}
44524529

4453-
inline TupleTypeElt::TupleTypeElt(Type ty,
4454-
Identifier name,
4455-
bool isVariadic)
4456-
: NameAndVariadic(name, isVariadic), ElementType(ty)
4457-
{
4530+
inline TupleTypeElt::TupleTypeElt(Type ty, Identifier name, bool isVariadic,
4531+
bool isAutoClosure, bool isEscaping)
4532+
: Name(name), ElementType(ty),
4533+
Flags(isVariadic, isAutoClosure, isEscaping) {
44584534
assert(!isVariadic ||
44594535
isa<ErrorType>(ty.getPointer()) ||
44604536
isa<ArraySliceType>(ty.getPointer()) ||
44614537
(isa<BoundGenericType>(ty.getPointer()) &&
44624538
ty->castTo<BoundGenericType>()->getGenericArgs().size() == 1));
4539+
assert(!isAutoClosure || (ty->is<AnyFunctionType>() &&
4540+
ty->castTo<AnyFunctionType>()->isAutoClosure()));
4541+
assert(!isEscaping || (ty->is<AnyFunctionType>() &&
4542+
!ty->castTo<AnyFunctionType>()->isNoEscape()));
44634543
}
44644544

44654545
inline Type TupleTypeElt::getVarargBaseTy(Type VarArgT) {
@@ -4474,6 +4554,16 @@ inline Type TupleTypeElt::getVarargBaseTy(Type VarArgT) {
44744554
return T;
44754555
}
44764556

4557+
/// Create one from what's present in the parameter decl and type
4558+
inline ParameterTypeFlags
4559+
ParameterTypeFlags::fromParameterType(Type paramTy, bool isVariadic) {
4560+
bool autoclosure = paramTy->is<AnyFunctionType>() &&
4561+
paramTy->castTo<AnyFunctionType>()->isAutoClosure();
4562+
bool escaping = paramTy->is<AnyFunctionType>() &&
4563+
!paramTy->castTo<AnyFunctionType>()->isNoEscape();
4564+
return {isVariadic, autoclosure, escaping};
4565+
}
4566+
44774567
inline Identifier SubstitutableType::getName() const {
44784568
if (auto Archetype = dyn_cast<ArchetypeType>(this))
44794569
return Archetype->getName();

include/swift/Serialization/ModuleFormat.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const uint16_t VERSION_MAJOR = 0;
5353
/// in source control, you should also update the comment to briefly
5454
/// describe what change you made. The content of this comment isn't important;
5555
/// it just ensures a conflict if two people change the module format.
56-
const uint16_t VERSION_MINOR = 260; // Last change: open
56+
const uint16_t VERSION_MINOR = 268; // Last change: parameter type flags
5757

5858
using DeclID = PointerEmbeddedInt<unsigned, 31>;
5959
using DeclIDField = BCFixed<31>;
@@ -570,7 +570,8 @@ namespace decls_block {
570570

571571
using ParenTypeLayout = BCRecordLayout<
572572
PAREN_TYPE,
573-
TypeIDField // inner type
573+
TypeIDField, // inner type
574+
BCFixed<ParameterTypeFlags::NumBits> // vararg?, autoclosure?, escaping?
574575
>;
575576

576577
using TupleTypeLayout = BCRecordLayout<
@@ -579,9 +580,9 @@ namespace decls_block {
579580

580581
using TupleTypeEltLayout = BCRecordLayout<
581582
TUPLE_TYPE_ELT,
582-
IdentifierIDField, // name
583-
TypeIDField, // type
584-
BCFixed<1> // vararg?
583+
IdentifierIDField, // name
584+
TypeIDField, // type
585+
BCFixed<ParameterTypeFlags::NumBits> // vararg?, autoclosure?, escaping?
585586
>;
586587

587588
using FunctionTypeLayout = BCRecordLayout<

lib/AST/ASTContext.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ struct ASTContext::Implementation {
299299
llvm::DenseMap<std::pair<Type, Type>, DictionaryType *> DictionaryTypes;
300300
llvm::DenseMap<Type, OptionalType*> OptionalTypes;
301301
llvm::DenseMap<Type, ImplicitlyUnwrappedOptionalType*> ImplicitlyUnwrappedOptionalTypes;
302-
llvm::DenseMap<Type, ParenType*> ParenTypes;
302+
llvm::DenseMap<std::pair<Type, unsigned>, ParenType*> ParenTypes;
303303
llvm::DenseMap<uintptr_t, ReferenceStorageType*> ReferenceStorageTypes;
304304
llvm::DenseMap<Type, LValueType*> LValueTypes;
305305
llvm::DenseMap<Type, InOutType*> InOutTypes;
@@ -2637,13 +2637,14 @@ BuiltinVectorType *BuiltinVectorType::get(const ASTContext &context,
26372637
return vecTy;
26382638
}
26392639

2640-
2641-
ParenType *ParenType::get(const ASTContext &C, Type underlying) {
2640+
ParenType *ParenType::get(const ASTContext &C, Type underlying,
2641+
ParameterTypeFlags flags) {
26422642
auto properties = underlying->getRecursiveProperties();
26432643
auto arena = getArena(properties);
2644-
ParenType *&Result = C.Impl.getArena(arena).ParenTypes[underlying];
2644+
ParenType *&Result =
2645+
C.Impl.getArena(arena).ParenTypes[{underlying, flags.value}];
26452646
if (Result == 0) {
2646-
Result = new (C, arena) ParenType(underlying, properties);
2647+
Result = new (C, arena) ParenType(underlying, properties, flags);
26472648
}
26482649
return Result;
26492650
}
@@ -2656,15 +2657,17 @@ void TupleType::Profile(llvm::FoldingSetNodeID &ID,
26562657
ArrayRef<TupleTypeElt> Fields) {
26572658
ID.AddInteger(Fields.size());
26582659
for (const TupleTypeElt &Elt : Fields) {
2659-
ID.AddPointer(Elt.NameAndVariadic.getOpaqueValue());
2660+
ID.AddPointer(Elt.Name.get());
26602661
ID.AddPointer(Elt.getType().getPointer());
2662+
ID.AddInteger(Elt.Flags.value);
26612663
}
26622664
}
26632665

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

26692672
RecursiveTypeProperties properties;
26702673
for (const TupleTypeElt &Elt : Fields) {

lib/AST/Decl.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,20 +1479,31 @@ static Type mapSignatureFunctionType(ASTContext &ctx, Type type,
14791479
SmallVector<TupleTypeElt, 4> elements;
14801480
bool anyChanged = false;
14811481
unsigned idx = 0;
1482+
// Remap our parameters, and make sure to strip off @escaping
14821483
for (const auto &elt : tupleTy->getElements()) {
1483-
Type eltTy = mapSignatureParamType(ctx, elt.getType());
1484-
if (anyChanged || eltTy.getPointer() != elt.getType().getPointer()) {
1485-
if (!anyChanged) {
1486-
elements.append(tupleTy->getElements().begin(),
1487-
tupleTy->getElements().begin() + idx);
1488-
anyChanged = true;
1489-
}
1484+
auto newEltTy = mapSignatureParamType(ctx, elt.getType());
1485+
ParameterTypeFlags newParamFlags(
1486+
elt.getParameterFlags().value & ~ParameterTypeFlags::Escaping);
1487+
1488+
bool exactlyTheSame = newParamFlags == elt.getParameterFlags() &&
1489+
newEltTy.getPointer() == elt.getType().getPointer();
14901490

1491-
elements.push_back(elt.getWithType(eltTy));
1491+
// Don't build up anything if we never see any difference
1492+
if (!anyChanged && exactlyTheSame) {
1493+
++idx;
1494+
continue;
14921495
}
1493-
++idx;
1496+
1497+
// First time we see a diff, copy over all the prior
1498+
if (!anyChanged && !exactlyTheSame) {
1499+
elements.append(tupleTy->getElements().begin(),
1500+
tupleTy->getElements().begin() + idx);
1501+
anyChanged = true;
1502+
}
1503+
1504+
// TODO: drop the name when it's finally out of the type system
1505+
elements.emplace_back(newEltTy, elt.getName(), newParamFlags);
14941506
}
1495-
14961507
if (anyChanged) {
14971508
argTy = TupleType::get(elements, ctx);
14981509
}

lib/AST/Parameter.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,12 @@ Type ParameterList::getType(const ASTContext &C) const {
121121

122122
for (auto P : *this) {
123123
if (!P->hasType()) return Type();
124-
125-
argumentInfo.push_back({
126-
P->getType(), P->getArgumentName(),
127-
P->isVariadic()
128-
});
124+
125+
argumentInfo.emplace_back(
126+
P->getType(), P->getArgumentName(),
127+
ParameterTypeFlags::fromParameterType(P->getType(), P->isVariadic()));
129128
}
130-
129+
131130
return TupleType::get(argumentInfo, C);
132131
}
133132

@@ -153,10 +152,9 @@ Type ParameterList::getInterfaceType(DeclContext *DC) const {
153152
type = P->getType();
154153
assert(!type->hasArchetype());
155154

156-
argumentInfo.push_back({
157-
type, P->getArgumentName(),
158-
P->isVariadic()
159-
});
155+
argumentInfo.emplace_back(
156+
type, P->getArgumentName(),
157+
ParameterTypeFlags::fromParameterType(type, P->isVariadic()));
160158
}
161159

162160
return TupleType::get(argumentInfo, C);

0 commit comments

Comments
 (0)