Skip to content

Commit 80eae20

Browse files
committed
[AST] Preserve type sugar for generic typealiases
Introduce a new Type node, BoundNameAliasType, which describes a reference to a typealias that requires substitutions to produce the underlying type. This new type node is used both for references to generic typealiases and for references to (non-generic) typealiases that occur within generic contexts, e.g., Array<Int>.Element. At present, the new type node is mainly useful in preserving type sugar for diagnostics purposes, as well as being reflected in other tools (indexing, code completion, etc.). The intent is to completely replace NameAliasType in the future.
1 parent 334c024 commit 80eae20

22 files changed

+434
-19
lines changed

include/swift/AST/SubstitutionMap.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
#include "llvm/ADT/SmallPtrSet.h"
3737
#include "llvm/ADT/SmallVector.h"
3838

39+
namespace llvm {
40+
class FoldingSetNodeID;
41+
}
42+
3943
namespace swift {
4044

4145
class GenericSignature;
@@ -174,6 +178,9 @@ class SubstitutionMap {
174178

175179
LLVM_ATTRIBUTE_DEPRECATED(void dump() const, "only for use in the debugger");
176180

181+
/// Profile the substitution map, for use with LLVM's FoldingSet.
182+
void profile(llvm::FoldingSetNodeID &id) const;
183+
177184
private:
178185
friend class GenericSignature;
179186
friend class GenericEnvironment;

include/swift/AST/TypeNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ UNCHECKED_TYPE(TypeVariable, Type)
146146
ABSTRACT_SUGARED_TYPE(Sugar, Type)
147147
SUGARED_TYPE(Paren, SugarType)
148148
SUGARED_TYPE(NameAlias, SugarType)
149+
SUGARED_TYPE(BoundNameAlias, SugarType)
149150
ABSTRACT_SUGARED_TYPE(SyntaxSugar, SugarType)
150151
ABSTRACT_SUGARED_TYPE(UnarySyntaxSugar, SyntaxSugarType)
151152
SUGARED_TYPE(ArraySlice, UnarySyntaxSugarType)

include/swift/AST/Types.h

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,16 @@ class alignas(1 << TypeAlignInBits) TypeBase {
373373
GenericArgCount : 32
374374
);
375375

376+
SWIFT_INLINE_BITFIELD_FULL(BoundNameAliasType, SugarType, 1+16,
377+
: NumPadBits,
378+
379+
/// Whether we have a parent type.
380+
HasParent : 1,
381+
382+
/// The number of substitutions.
383+
NumSubstitutions : 16
384+
);
385+
376386
} Bits;
377387

378388
protected:
@@ -1560,6 +1570,81 @@ class NameAliasType : public SugarType {
15601570
}
15611571
};
15621572

1573+
/// A reference to a type alias that is somehow generic, along with the
1574+
/// set of substitutions to apply to make the type concrete.
1575+
class BoundNameAliasType final
1576+
: public SugarType, public llvm::FoldingSetNode,
1577+
llvm::TrailingObjects<BoundNameAliasType, Type, Substitution>
1578+
{
1579+
TypeAliasDecl *typealias;
1580+
1581+
friend class ASTContext;
1582+
friend TrailingObjects;
1583+
1584+
BoundNameAliasType(TypeAliasDecl *typealias, Type parent,
1585+
const SubstitutionMap &substitutions, Type underlying,
1586+
RecursiveTypeProperties properties);
1587+
1588+
unsigned getNumSubstitutions() const {
1589+
return Bits.BoundNameAliasType.NumSubstitutions;
1590+
}
1591+
1592+
size_t numTrailingObjects(OverloadToken<Type>) const {
1593+
return Bits.BoundNameAliasType.HasParent ? 1 : 0;
1594+
}
1595+
1596+
size_t numTrailingObjects(OverloadToken<Substitution>) const {
1597+
return getNumSubstitutions();
1598+
}
1599+
1600+
/// Retrieve the set of substitutions to be applied to the declaration to
1601+
/// produce the underlying type.
1602+
SubstitutionList getSubstitutionList() const {
1603+
return {getTrailingObjects<Substitution>(), getNumSubstitutions()};
1604+
}
1605+
1606+
public:
1607+
static BoundNameAliasType *get(TypeAliasDecl *typealias, Type parent,
1608+
const SubstitutionMap &substitutions,
1609+
Type underlying);
1610+
1611+
/// \brief Returns the declaration that declares this type.
1612+
TypeAliasDecl *getDecl() const {
1613+
// Avoid requiring the definition of TypeAliasDecl.
1614+
return typealias;
1615+
}
1616+
1617+
/// Retrieve the parent of this type as written, e.g., the part that was
1618+
/// written before ".", if provided.
1619+
Type getParent() const {
1620+
return Bits.BoundNameAliasType.HasParent ? *getTrailingObjects<Type>()
1621+
: Type();
1622+
}
1623+
1624+
/// Retrieve the substitution map applied to the declaration's underlying
1625+
/// to produce the described type.
1626+
SubstitutionMap getSubstitutionMap() const;
1627+
1628+
/// Get the innermost generic arguments, which correspond to the generic
1629+
/// arguments that are directly applied to the typealias declaration in
1630+
/// produced by \c getDecl().
1631+
///
1632+
/// The result can be empty, if the declaration itself is non-generic but
1633+
/// the parent is generic.
1634+
SmallVector<Type, 2> getInnermostGenericArgs() const;
1635+
1636+
// Support for FoldingSet.
1637+
void Profile(llvm::FoldingSetNodeID &id) const;
1638+
1639+
static void Profile(llvm::FoldingSetNodeID &id, TypeAliasDecl *typealias,
1640+
Type parent, const SubstitutionMap &substitutions);
1641+
1642+
// Implement isa/cast/dyncast/etc.
1643+
static bool classof(const TypeBase *T) {
1644+
return T->getKind() == TypeKind::BoundNameAlias;
1645+
}
1646+
};
1647+
15631648
// TODO: As part of AST modernization, replace with a proper
15641649
// 'ParameterTypeElt' or similar, and have FunctionTypes only have a list
15651650
// of 'ParameterTypeElt's. Then, this information can be removed from

include/swift/Serialization/DeclTypeRecordNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ TYPE(OPENED_EXISTENTIAL)
106106
TYPE(EXISTENTIAL_METATYPE)
107107
TYPE(SIL_BLOCK_STORAGE)
108108
TYPE(SIL_BOX)
109+
TYPE(BOUND_NAME_ALIAS)
109110

110111
FIRST_DECL(TYPE_ALIAS, 60)
111112
DECL(GENERIC_TYPE_PARAM)

include/swift/Serialization/ModuleFormat.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,14 @@ namespace decls_block {
647647
TypeIDField // canonical type (a fallback)
648648
>;
649649

650+
using BoundNameAliasTypeLayout = BCRecordLayout<
651+
BOUND_NAME_ALIAS_TYPE,
652+
DeclIDField, // typealias decl
653+
TypeIDField, // parent type
654+
TypeIDField // underlying type
655+
// trailing substitutions
656+
>;
657+
650658
using GenericTypeParamTypeLayout = BCRecordLayout<
651659
GENERIC_TYPE_PARAM_TYPE,
652660
DeclIDField, // generic type parameter decl or depth

lib/AST/ASTContext.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
278278
/// arenas.
279279
struct Arena {
280280
llvm::DenseMap<Type, ErrorType *> ErrorTypesWithOriginal;
281+
llvm::FoldingSet<BoundNameAliasType> BoundNameAliasTypes;
281282
llvm::FoldingSet<TupleType> TupleTypes;
282283
llvm::DenseMap<std::pair<Type,char>, MetatypeType*> MetatypeTypes;
283284
llvm::DenseMap<std::pair<Type,char>,
@@ -2886,6 +2887,88 @@ StringRef ASTContext::getSwiftName(KnownFoundationEntity kind) {
28862887
// Type manipulation routines.
28872888
//===----------------------------------------------------------------------===//
28882889

2890+
BoundNameAliasType::BoundNameAliasType(TypeAliasDecl *typealias, Type parent,
2891+
const SubstitutionMap &substitutions,
2892+
Type underlying,
2893+
RecursiveTypeProperties properties)
2894+
: SugarType(TypeKind::BoundNameAlias, underlying, properties),
2895+
typealias(typealias) {
2896+
// Record the parent (or absence of a parent).
2897+
if (parent) {
2898+
Bits.BoundNameAliasType.HasParent = true;
2899+
*getTrailingObjects<Type>() = parent;
2900+
} else {
2901+
Bits.BoundNameAliasType.HasParent = false;
2902+
}
2903+
2904+
// Record the substitutions.
2905+
if (auto genericSig = typealias->getGenericSignature()) {
2906+
SmallVector<Substitution, 4> flatSubs;
2907+
genericSig->getSubstitutions(substitutions, flatSubs);
2908+
Bits.BoundNameAliasType.NumSubstitutions = flatSubs.size();
2909+
std::copy(flatSubs.begin(), flatSubs.end(),
2910+
getTrailingObjects<Substitution>());
2911+
} else {
2912+
Bits.BoundNameAliasType.NumSubstitutions = 0;
2913+
}
2914+
}
2915+
2916+
BoundNameAliasType *BoundNameAliasType::get(
2917+
TypeAliasDecl *typealias,
2918+
Type parent,
2919+
const SubstitutionMap &substitutions,
2920+
Type underlying) {
2921+
// Compute the recursive properties.
2922+
auto properties = underlying->getRecursiveProperties();
2923+
if (parent)
2924+
properties |= parent->getRecursiveProperties();
2925+
auto genericSig = typealias->getGenericSignature();
2926+
if (genericSig) {
2927+
for (Type gp : genericSig->getGenericParams()) {
2928+
properties |= gp.subst(substitutions, SubstFlags::UseErrorType)
2929+
->getRecursiveProperties();
2930+
}
2931+
}
2932+
2933+
// Figure out which arena this type will go into.
2934+
auto &ctx = underlying->getASTContext();
2935+
auto arena = getArena(properties);
2936+
2937+
// Profile the type.
2938+
llvm::FoldingSetNodeID id;
2939+
BoundNameAliasType::Profile(id, typealias, parent, substitutions);
2940+
2941+
// Did we already record this type?
2942+
void *insertPos;
2943+
auto &types = ctx.Impl.getArena(arena).BoundNameAliasTypes;
2944+
if (auto result = types.FindNodeOrInsertPos(id, insertPos))
2945+
return result;
2946+
2947+
// Build a new type.
2948+
unsigned numSubstitutions =
2949+
genericSig ? genericSig->getSubstitutionListSize() : 0;
2950+
auto size =
2951+
totalSizeToAlloc<Type, Substitution>(parent ? 1 : 0, numSubstitutions);
2952+
auto mem = ctx.Allocate(size, alignof(BoundNameAliasType), arena);
2953+
auto result = new (mem) BoundNameAliasType(typealias, parent, substitutions,
2954+
underlying, properties);
2955+
types.InsertNode(result, insertPos);
2956+
return result;
2957+
}
2958+
2959+
void BoundNameAliasType::Profile(llvm::FoldingSetNodeID &id) const {
2960+
Profile(id, getDecl(), getParent(), getSubstitutionMap());
2961+
}
2962+
2963+
void BoundNameAliasType::Profile(
2964+
llvm::FoldingSetNodeID &id,
2965+
TypeAliasDecl *typealias,
2966+
Type parent, const SubstitutionMap &substitutions) {
2967+
id.AddPointer(typealias);
2968+
id.AddPointer(parent.getPointer());
2969+
substitutions.profile(id);
2970+
}
2971+
28892972
// Simple accessors.
28902973
Type ErrorType::get(const ASTContext &C) { return C.TheErrorType; }
28912974

lib/AST/ASTDumper.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3035,6 +3035,17 @@ namespace {
30353035
OS << ")";
30363036
}
30373037

3038+
void visitBoundNameAliasType(BoundNameAliasType *T, StringRef label) {
3039+
printCommon(label, "bound_name_alias_type");
3040+
printField("decl", T->getDecl()->printRef());
3041+
if (T->getParent())
3042+
printRec("parent", T->getParent());
3043+
3044+
for (auto arg : T->getInnermostGenericArgs())
3045+
printRec(arg);
3046+
OS << ")";
3047+
}
3048+
30383049
void visitParenType(ParenType *T, StringRef label) {
30393050
printCommon(label, "paren_type");
30403051
dumpParameterFlags(T->getParameterFlags());

lib/AST/ASTMangler.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,13 @@ void ASTMangler::appendType(Type type) {
746746
// unless the type alias references a builtin type.
747747
return appendAnyGenericType(decl);
748748
}
749+
case TypeKind::BoundNameAlias: {
750+
assert(DWARFMangling && "sugared types are only legal for the debugger");
751+
auto boundAliasTy = cast<BoundNameAliasType>(tybase);
752+
753+
// FIXME: Mangle as a generic type.
754+
return appendType(boundAliasTy->getSinglyDesugaredType());
755+
}
749756

750757
case TypeKind::Paren:
751758
return appendSugaredType<ParenType>(type);

lib/AST/ASTPrinter.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3283,6 +3283,21 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
32833283
printTypeDeclName(T);
32843284
}
32853285

3286+
void visitBoundNameAliasType(BoundNameAliasType *T) {
3287+
if (Options.PrintForSIL || Options.PrintNameAliasUnderlyingType) {
3288+
visit(T->getSinglyDesugaredType());
3289+
return;
3290+
}
3291+
3292+
if (auto parent = T->getParent()) {
3293+
visit(parent);
3294+
Printer << ".";
3295+
}
3296+
3297+
printTypeDeclName(T);
3298+
printGenericArgs(T->getInnermostGenericArgs());
3299+
}
3300+
32863301
void visitParenType(ParenType *T) {
32873302
Printer << "(";
32883303
printParameterFlags(Printer, Options, T->getParameterFlags());

lib/AST/DiagnosticEngine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ static void formatSelectionArgument(StringRef ModifierArguments,
327327
}
328328

329329
static bool isInterestingTypealias(Type type) {
330+
// Bound name alias types are always interesting.
331+
if (isa<BoundNameAliasType>(type.getPointer())) return true;
332+
330333
auto aliasTy = dyn_cast<NameAliasType>(type.getPointer());
331334
if (!aliasTy)
332335
return false;

lib/AST/SubstitutionMap.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,3 +533,24 @@ void SubstitutionMap::dump(llvm::raw_ostream &out) const {
533533
void SubstitutionMap::dump() const {
534534
return dump(llvm::errs());
535535
}
536+
537+
void SubstitutionMap::profile(llvm::FoldingSetNodeID &id) const {
538+
if (empty() || !genericSig) return;
539+
540+
// Replacement types.
541+
for (Type gp : genericSig->getGenericParams()) {
542+
id.AddPointer(gp.subst(*this).getPointer());
543+
}
544+
545+
// Conformance requirements.
546+
for (const auto &req : genericSig->getRequirements()) {
547+
if (req.getKind() != RequirementKind::Conformance)
548+
continue;
549+
550+
auto conformance =
551+
lookupConformance(req.getFirstType()->getCanonicalType(),
552+
req.getSecondType()->castTo<ProtocolType>()->getDecl());
553+
id.AddPointer(conformance ? conformance->getOpaqueValue() : nullptr);
554+
}
555+
}
556+

0 commit comments

Comments
 (0)