Skip to content

Commit

Permalink
AST: Change TypeAliasDecls to store an interface type as their underl…
Browse files Browse the repository at this point in the history
…ying type

- TypeAliasDecl::getAliasType() is gone. Now, getDeclaredInterfaceType()
  always returns the NameAliasType.

- NameAliasTypes now always desugar to the underlying type as an
  interface type.

- The NameAliasType of a generic type alias no longer desugars to an
  UnboundGenericType; call TypeAliasDecl::getUnboundGenericType() if you
  want that.

- The "lazy mapTypeOutOfContext()" hack for deserialized TypeAliasDecls
  is gone.

- The process of constructing a synthesized TypeAliasDecl is much simpler
  now; instead of calling computeType(), setInterfaceType() and then
  setting the recursive properties in the right order, just call
  setUnderlyingType(), passing it either an interface type or a
  contextual type.

  In particular, many places weren't setting the recursive properties,
  such as the ClangImporter and deserialization. This meant that queries
  such as hasArchetype() or hasTypeParameter() would return incorrect
  results on NameAliasTypes, which caused various subtle problems.

- Finally, add some more tests for generic typealiases, most of which
  fail because they're still pretty broken.
  • Loading branch information
slavapestov committed Dec 16, 2016
1 parent 757f253 commit 2c6b9f7
Show file tree
Hide file tree
Showing 39 changed files with 392 additions and 285 deletions.
62 changes: 21 additions & 41 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ namespace swift {
class TypeAliasDecl;
class Stmt;
class SubscriptDecl;
class UnboundGenericType;
class ValueDecl;
class VarDecl;

Expand Down Expand Up @@ -413,9 +414,10 @@ class alignas(1 << DeclAlignInBits) Decl {
friend class TypeAliasDecl;
unsigned : NumGenericTypeDeclBits;

/// Whether the underlying type is an interface type that will be lazily
/// resolved to a context type.
unsigned HasInterfaceUnderlyingType : 1;
/// Whether we have completed validation of the typealias.
/// This is necessary because unlike other declarations, a
/// typealias will not get an interface type right away.
unsigned HasCompletedValidation : 1;
};
enum { NumTypeAliasDeclBits = NumGenericTypeDeclBits + 1 };
static_assert(NumTypeAliasDeclBits <= 32, "fits in an unsigned");
Expand Down Expand Up @@ -2391,60 +2393,38 @@ class GenericTypeDecl : public TypeDecl, public DeclContext {
/// TypeAliasDecl's always have 'MetatypeType' type.
///
class TypeAliasDecl : public GenericTypeDecl {
/// The type that represents this (sugared) name alias.
mutable NameAliasType *AliasTy;

SourceLoc TypeAliasLoc; // The location of the 'typealias' keyword
mutable TypeLoc UnderlyingTy;

Type computeUnderlyingContextType() const;
TypeLoc UnderlyingTy;

public:
TypeAliasDecl(SourceLoc TypeAliasLoc, Identifier Name,
SourceLoc NameLoc, TypeLoc UnderlyingTy,
GenericParamList *GenericParams, DeclContext *DC);
SourceLoc NameLoc, GenericParamList *GenericParams,
DeclContext *DC);

SourceLoc getStartLoc() const { return TypeAliasLoc; }
SourceRange getSourceRange() const;

/// getUnderlyingType - Returns the underlying type, which is
/// assumed to have been set.
Type getUnderlyingType() const {
if (TypeAliasDeclBits.HasInterfaceUnderlyingType)
return computeUnderlyingContextType();

assert(!UnderlyingTy.getType().isNull() &&
"getting invalid underlying type");
return UnderlyingTy.getType();
}

/// computeType - Compute the type (and declared type) of this type alias;
/// can only be called after the alias type has been resolved.
void computeType();

/// \brief Determine whether this type alias has an underlying type.
bool hasUnderlyingType() const {
return !UnderlyingTy.getType().isNull();
}

TypeLoc &getUnderlyingTypeLoc() {
if (TypeAliasDeclBits.HasInterfaceUnderlyingType)
(void)computeUnderlyingContextType();

return UnderlyingTy;
}
const TypeLoc &getUnderlyingTypeLoc() const {
if (TypeAliasDeclBits.HasInterfaceUnderlyingType)
(void)computeUnderlyingContextType();

return UnderlyingTy;
}

/// Set the underlying type after deserialization.
void setDeserializedUnderlyingType(Type type);
/// Set the underlying type, for deserialization and synthesized
/// aliases.
void setUnderlyingType(Type type);

bool hasCompletedValidation() const {
return TypeAliasDeclBits.HasCompletedValidation;
}

void setHasCompletedValidation() {
TypeAliasDeclBits.HasCompletedValidation = 1;
}

/// getAliasType - Return the sugared version of this decl as a Type.
NameAliasType *getAliasType() const { return AliasTy; }
/// For generic typealiases, return the unbound generic type.
UnboundGenericType *getUnboundGenericType() const;

static bool classof(const Decl *D) {
return D->getKind() == DeclKind::TypeAlias;
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3661,7 +3661,7 @@ static NominalTypeDecl *findUnderlyingTypeInModule(ASTContext &ctx,
if (auto typealias = dyn_cast<TypeAliasDecl>(result)) {
if (auto resolver = ctx.getLazyResolver())
resolver->resolveDeclSignature(typealias);
return typealias->getUnderlyingType()->getAnyNominal();
return typealias->getDeclaredInterfaceType()->getAnyNominal();
}
}

Expand Down
4 changes: 2 additions & 2 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,8 @@ namespace {
void visitTypeAliasDecl(TypeAliasDecl *TAD) {
printCommon(TAD, "typealias");
OS << " type='";
if (TAD->hasUnderlyingType())
OS << TAD->getUnderlyingType().getString();
if (TAD->getUnderlyingTypeLoc().getType())
OS << TAD->getUnderlyingTypeLoc().getType().getString();
else
OS << "<<<unresolved>>>";
printInherited(TAD->getInherited());
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ void ASTMangler::appendType(Type type) {
TypeAliasDecl *decl = NameAliasTy->getDecl();
if (decl->getModuleContext() == decl->getASTContext().TheBuiltinModule) {
// It's not possible to mangle the context of the builtin module.
return appendType(decl->getUnderlyingType());
return appendType(decl->getDeclaredInterfaceType());
}

// For the DWARF output we want to mangle the type alias + context,
Expand Down
5 changes: 2 additions & 3 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2141,9 +2141,8 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) {
printGenericSignature(genericSig, PrintParams | InnermostOnly);
});
bool ShouldPrint = true;
Type Ty;
if (decl->hasUnderlyingType())
Ty = decl->getUnderlyingType();
Type Ty = decl->getUnderlyingTypeLoc().getType();

// If the underlying type is private, don't print it.
if (Options.SkipPrivateStdlibDecls && Ty && Ty.isPrivateStdlibType())
ShouldPrint = false;
Expand Down
11 changes: 3 additions & 8 deletions lib/AST/ArchetypeBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,19 +413,14 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType(
// Resolve this nested type to this type alias.
pa = new PotentialArchetype(this, alias);

if (!alias->hasUnderlyingType())
if (!alias->hasInterfaceType())
builder.getLazyResolver()->resolveDeclSignature(alias);
if (!alias->hasUnderlyingType())
if (!alias->hasInterfaceType())
continue;

auto type = alias->getUnderlyingType();
auto type = alias->getDeclaredInterfaceType();
SmallVector<Identifier, 4> identifiers;

// Map the type out of its context.
if (auto genericEnv = alias->getGenericEnvironmentOfContext()) {
type = genericEnv->mapTypeOutOfContext(type);
}

if (auto existingPA = builder.resolveArchetype(type)) {
builder.addSameTypeRequirementBetweenArchetypes(pa, existingPA,
redundantSource);
Expand Down
63 changes: 34 additions & 29 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -622,8 +622,8 @@ ImportKind ImportDecl::getBestImportKind(const ValueDecl *VD) {
return ImportKind::Struct;

case DeclKind::TypeAlias: {
Type underlyingTy = cast<TypeAliasDecl>(VD)->getUnderlyingType();
return getBestImportKind(underlyingTy->getAnyNominal());
Type type = cast<TypeAliasDecl>(VD)->getDeclaredInterfaceType();
return getBestImportKind(type->getAnyNominal());
}

case DeclKind::Func:
Expand Down Expand Up @@ -1907,7 +1907,7 @@ Type TypeDecl::getDeclaredInterfaceType() const {
return NTD->getDeclaredInterfaceType();

Type interfaceType = getInterfaceType();
if (interfaceType.isNull() || interfaceType->hasError())
if (interfaceType.isNull() || interfaceType->is<ErrorType>())
return interfaceType;

if (isa<ModuleDecl>(this))
Expand Down Expand Up @@ -2191,17 +2191,11 @@ void GenericTypeDecl::setLazyGenericEnvironment(LazyMemberLoader *lazyLoader,
}

TypeAliasDecl::TypeAliasDecl(SourceLoc TypeAliasLoc, Identifier Name,
SourceLoc NameLoc, TypeLoc UnderlyingTy,
GenericParamList *GenericParams, DeclContext *DC)
SourceLoc NameLoc, GenericParamList *GenericParams,
DeclContext *DC)
: GenericTypeDecl(DeclKind::TypeAlias, DC, Name, NameLoc, {}, GenericParams),
AliasTy(nullptr), TypeAliasLoc(TypeAliasLoc), UnderlyingTy(UnderlyingTy) {
TypeAliasDeclBits.HasInterfaceUnderlyingType = false;
}

void TypeAliasDecl::computeType() {
ASTContext &Ctx = getASTContext();
assert(!AliasTy && "already called computeType()");
AliasTy = new (Ctx, AllocationArena::Permanent) NameAliasType(this);
TypeAliasLoc(TypeAliasLoc) {
TypeAliasDeclBits.HasCompletedValidation = false;
}

SourceRange TypeAliasDecl::getSourceRange() const {
Expand All @@ -2210,6 +2204,33 @@ SourceRange TypeAliasDecl::getSourceRange() const {
return { TypeAliasLoc, getNameLoc() };
}

void TypeAliasDecl::setUnderlyingType(Type underlying) {
setHasCompletedValidation();

// lldb creates global typealiases containing archetypes
// sometimes...
if (underlying->hasArchetype() && isGenericContext())
underlying = mapTypeOutOfContext(underlying);
UnderlyingTy.setType(underlying);

// Create a NameAliasType which will resolve to the underlying type.
ASTContext &Ctx = getASTContext();
auto aliasTy = new (Ctx, AllocationArena::Permanent) NameAliasType(this);
aliasTy->setRecursiveProperties(getUnderlyingTypeLoc().getType()
->getRecursiveProperties());

// Set the interface type of this declaration.
setInterfaceType(MetatypeType::get(aliasTy, Ctx));
}

UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const {
assert(getGenericParams());
return UnboundGenericType::get(
const_cast<TypeAliasDecl *>(this),
getDeclContext()->getDeclaredTypeOfContext(),
getASTContext());
}

Type AbstractTypeParamDecl::getSuperclass() const {
auto *dc = getDeclContext();
if (!dc->isValidGenericContext())
Expand All @@ -2223,22 +2244,6 @@ Type AbstractTypeParamDecl::getSuperclass() const {
return nullptr;
}

Type TypeAliasDecl::computeUnderlyingContextType() const {
Type type = UnderlyingTy.getType();
if (auto genericEnv = getGenericEnvironmentOfContext()) {
type = genericEnv->mapTypeIntoContext(getParentModule(), type);
UnderlyingTy.setType(type);
}

return type;
}

void TypeAliasDecl::setDeserializedUnderlyingType(Type underlying) {
UnderlyingTy.setType(underlying);
if (underlying->hasTypeParameter())
TypeAliasDeclBits.HasInterfaceUnderlyingType = true;
}

ArrayRef<ProtocolDecl *>
AbstractTypeParamDecl::getConformingProtocols() const {
auto *dc = getDeclContext();
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@ void Mangler::mangleType(Type type, unsigned uncurryLevel) {
TypeAliasDecl *decl = NameAliasTy->getDecl();
if (decl->getModuleContext() == decl->getASTContext().TheBuiltinModule) {
// It's not possible to mangle the context of the builtin module.
return mangleType(decl->getUnderlyingType(), uncurryLevel);
return mangleType(NameAliasTy->getSinglyDesugaredType(), uncurryLevel);
}

Buffer << "a";
Expand Down
4 changes: 1 addition & 3 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,9 @@ void BuiltinUnit::LookupCache::lookupValue(
if (!Entry) {
if (Type Ty = getBuiltinType(Ctx, Name.str())) {
auto *TAD = new (Ctx) TypeAliasDecl(SourceLoc(), Name, SourceLoc(),
TypeLoc::withoutLoc(Ty),
/*genericparams*/nullptr,
const_cast<BuiltinUnit*>(&M));
TAD->computeType();
TAD->setInterfaceType(MetatypeType::get(TAD->getAliasType(), Ctx));
TAD->setUnderlyingType(Ty);
TAD->setAccessibility(Accessibility::Public);
Entry = TAD;
}
Expand Down
20 changes: 6 additions & 14 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1308,15 +1308,7 @@ TypeBase *ParenType::getSinglyDesugaredType() {
}

TypeBase *NameAliasType::getSinglyDesugaredType() {
auto *TAD = getDecl();

// The type for a generic TypeAliasDecl is an UnboundGenericType.
if (TAD->getGenericParams())
return UnboundGenericType::get(TAD,
TAD->getDeclContext()->getDeclaredTypeInContext(),
TAD->getASTContext());

return getDecl()->getUnderlyingType().getPointer();
return getDecl()->getUnderlyingTypeLoc().getType().getPointer();
}

TypeBase *SyntaxSugarType::getSinglyDesugaredType() {
Expand Down Expand Up @@ -3436,15 +3428,15 @@ case TypeKind::Id:

case TypeKind::NameAlias: {
auto alias = cast<NameAliasType>(base);
auto underlyingTy = alias->getDecl()->getUnderlyingType().transform(fn);
if (!underlyingTy)
auto underlyingTy = Type(alias->getSinglyDesugaredType());
auto transformedTy = underlyingTy.transform(fn);
if (!transformedTy)
return Type();

if (underlyingTy.getPointer() ==
alias->getDecl()->getUnderlyingType().getPointer())
if (transformedTy.getPointer() == underlyingTy.getPointer())
return *this;

return underlyingTy;
return transformedTy;
}

case TypeKind::Paren: {
Expand Down
Loading

0 comments on commit 2c6b9f7

Please sign in to comment.