Skip to content

Commit a11e911

Browse files
committed
Merge pull request #1610 from gregomni/typealias
[Parse/AST/Sema] Split parsing for typealias & associatedtype, allow typealias in protocols and generic constraints
2 parents 1868856 + 1e3ed8b commit a11e911

16 files changed

+304
-114
lines changed

include/swift/AST/ArchetypeBuilder.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,10 @@ class ArchetypeBuilder::PotentialArchetype {
387387

388388
/// \brief The name of this potential archetype or, for an
389389
/// associated type, the declaration of the associated type to which
390-
/// this potential archetype has been resolved.
391-
llvm::PointerUnion<Identifier, AssociatedTypeDecl *> NameOrAssociatedType;
390+
/// this potential archetype has been resolved. Or, for a type alias,
391+
/// the type alias decl.
392+
llvm::PointerUnion3<Identifier, AssociatedTypeDecl *,
393+
TypeAliasDecl *> NameOrAssociatedType;
392394

393395
/// \brief The representative of the equivalent class of potential archetypes
394396
/// to which this potential archetype belongs.
@@ -466,6 +468,17 @@ class ArchetypeBuilder::PotentialArchetype {
466468
EquivalenceClass.push_back(this);
467469
}
468470

471+
/// \brief Construct a new potential archetype for a type alias.
472+
PotentialArchetype(PotentialArchetype *Parent, TypeAliasDecl *TypeAlias)
473+
: ParentOrParam(Parent), NameOrAssociatedType(TypeAlias),
474+
Representative(this), IsRecursive(false), Invalid(false),
475+
SubstitutingConcreteType(false), RecursiveConcreteType(false),
476+
RecursiveSuperclassType(false), Renamed(false)
477+
{
478+
assert(Parent != nullptr && "Not an associated type?");
479+
EquivalenceClass.push_back(this);
480+
}
481+
469482
/// \brief Construct a new potential archetype for a generic parameter.
470483
PotentialArchetype(GenericTypeParamType *GenericParam,
471484
ProtocolDecl *RootProtocol,
@@ -524,6 +537,11 @@ class ArchetypeBuilder::PotentialArchetype {
524537
GenericTypeParamType *getGenericParam() const {
525538
return ParentOrParam.dyn_cast<GenericTypeParamType *>();
526539
}
540+
541+
/// Retrieve the type alias.
542+
TypeAliasDecl *getTypeAliasDecl() const {
543+
return NameOrAssociatedType.dyn_cast<TypeAliasDecl *>();
544+
}
527545

528546
/// Retrieve the set of protocols to which this type conforms.
529547
const llvm::MapVector<ProtocolDecl *, RequirementSource> &

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ ERROR(expected_equal_in_typealias,PointsToFirstBadToken,
283283
"expected '=' in typealias declaration", ())
284284
ERROR(expected_type_in_typealias,PointsToFirstBadToken,
285285
"expected type in typealias declaration", ())
286+
ERROR(expected_type_in_associatedtype,PointsToFirstBadToken,
287+
"expected type in associatedtype declaration", ())
286288
ERROR(associated_type_generic_parameter_list,PointsToFirstBadToken,
287289
"associated types may not have a generic parameter list", ())
288290
ERROR(typealias_generic_list_constraint,PointsToFirstBadToken,
@@ -759,8 +761,8 @@ ERROR(expected_close_after_else_directive,none,
759761
"further conditions after #else are unreachable", ())
760762

761763
/// Associatedtype Statement
762-
WARNING(typealias_inside_protocol,none,
763-
"use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead", ())
764+
ERROR(typealias_inside_protocol_without_type,none,
765+
"typealias is missing an assigned type; use 'associatedtype' to define an associated type requirement", ())
764766
ERROR(associatedtype_outside_protocol,none,
765767
"associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement", ())
766768

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,9 @@ ERROR(invalid_member_type,none,
468468
ERROR(invalid_member_type_suggest,none,
469469
"%0 does not have a member type named %1; did you mean %2?",
470470
(Type, Identifier, Identifier))
471+
ERROR(invalid_member_type_alias,none,
472+
"typealias %0 is too complex to be used as a generic constraint; "
473+
"use an associatedtype instead", (Identifier))
471474
ERROR(ambiguous_member_type,none,
472475
"ambiguous type name %0 in %1", (Identifier, Type))
473476
ERROR(no_module_type,none,

include/swift/Parse/Parser.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -657,15 +657,14 @@ class Parser {
657657
PD_HasContainerType = 1 << 2,
658658
PD_DisallowNominalTypes = 1 << 3,
659659
PD_DisallowInit = 1 << 4,
660-
PD_DisallowTypeAliasDef = 1 << 5,
661-
PD_AllowDestructor = 1 << 6,
662-
PD_AllowEnumElement = 1 << 7,
663-
PD_InProtocol = 1 << 8,
664-
PD_InClass = 1 << 9,
665-
PD_InExtension = 1 << 10,
666-
PD_InStruct = 1 << 11,
667-
PD_InEnum = 1 << 12,
668-
PD_InLoop = 1 << 13
660+
PD_AllowDestructor = 1 << 5,
661+
PD_AllowEnumElement = 1 << 6,
662+
PD_InProtocol = 1 << 7,
663+
PD_InClass = 1 << 8,
664+
PD_InExtension = 1 << 9,
665+
PD_InStruct = 1 << 10,
666+
PD_InEnum = 1 << 11,
667+
PD_InLoop = 1 << 12
669668
};
670669

671670
/// Options that control the parsing of declarations.
@@ -701,9 +700,11 @@ class Parser {
701700
ParserStatus parseDecl(SmallVectorImpl<Decl*> &Entries, ParseDeclOptions Flags);
702701
void parseDeclDelayed();
703702

704-
ParserResult<TypeDecl> parseDeclTypeAlias(bool WantDefinition,
705-
bool isAssociatedType,
703+
ParserResult<TypeDecl> parseDeclTypeAlias(ParseDeclOptions Flags,
706704
DeclAttributes &Attributes);
705+
706+
ParserResult<TypeDecl> parseDeclAssociatedType(ParseDeclOptions Flags,
707+
DeclAttributes &Attributes);
707708

708709
ParserResult<IfConfigDecl> parseDeclIfConfig(ParseDeclOptions Flags);
709710
/// Parse a #line/#setline directive.

include/swift/SIL/SILWitnessVisitor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
100100
ProtocolType::canonicalizeProtocols(protos);
101101
asDerived().addAssociatedType(td, protos);
102102
}
103+
104+
void visitTypeAliasDecl(TypeAliasDecl *tad) {
105+
// We don't care about these by themselves for witnesses.
106+
}
103107

104108
void visitPatternBindingDecl(PatternBindingDecl *pbd) {
105109
// We only care about the contained VarDecls.

lib/AST/ASTVerifier.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,6 +1781,10 @@ struct ASTNodeBase {};
17811781
.verifyChecked(replacementType);
17821782
continue;
17831783
}
1784+
1785+
// No witness necessary for type aliases
1786+
if (isa<TypeAliasDecl>(member))
1787+
continue;
17841788

17851789
// If this is an accessor for something, ignore it.
17861790
if (auto *FD = dyn_cast<FuncDecl>(member))

lib/AST/ArchetypeBuilder.cpp

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ void ArchetypeBuilder::PotentialArchetype::buildFullName(
219219
Identifier ArchetypeBuilder::PotentialArchetype::getName() const {
220220
if (auto assocType = NameOrAssociatedType.dyn_cast<AssociatedTypeDecl *>())
221221
return assocType->getName();
222-
222+
if (auto typeAlias = NameOrAssociatedType.dyn_cast<TypeAliasDecl *>())
223+
return typeAlias->getName();
223224
return NameOrAssociatedType.get<Identifier>();
224225
}
225226

@@ -303,12 +304,12 @@ static void maybeAddSameTypeRequirementForNestedType(
303304
RequirementSource fromSource,
304305
ProtocolConformance *superConformance,
305306
ArchetypeBuilder &builder) {
306-
auto assocType = nestedPA->getResolvedAssociatedType();
307-
assert(assocType && "Not resolved to an associated type?");
308-
309307
// If there's no super conformance, we're done.
310308
if (!superConformance) return;
311309

310+
auto assocType = nestedPA->getResolvedAssociatedType();
311+
assert(assocType && "Not resolved to an associated type?");
312+
312313
// Dig out the type witness.
313314
auto concreteType =
314315
superConformance->getTypeWitness(assocType, builder.getLazyResolver())
@@ -467,20 +468,73 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType(
467468
// archetype conforms.
468469
for (auto &conforms : ConformsTo) {
469470
for (auto member : conforms.first->lookupDirect(nestedName)) {
470-
auto assocType = dyn_cast<AssociatedTypeDecl>(member);
471-
if (!assocType)
471+
PotentialArchetype *pa;
472+
473+
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
474+
// Resolve this nested type to this associated type.
475+
pa = new PotentialArchetype(this, assocType);
476+
} else if (auto alias = dyn_cast<TypeAliasDecl>(member)) {
477+
// Resolve this nested type to this type alias.
478+
pa = new PotentialArchetype(this, alias);
479+
480+
if (!alias->hasUnderlyingType())
481+
builder.getLazyResolver()->resolveDeclSignature(alias);
482+
if (!alias->hasUnderlyingType())
483+
continue;
484+
485+
auto type = alias->getUnderlyingType();
486+
if (auto archetype = type->getAs<ArchetypeType>()) {
487+
auto containingProtocol = cast<ProtocolDecl>(alias->getParent());
488+
SmallVector<Identifier, 4> identifiers;
489+
490+
// Go up archetype parents until we find our containing protocol.
491+
while (archetype->getSelfProtocol() != containingProtocol) {
492+
identifiers.push_back(archetype->getName());
493+
archetype = archetype->getParent();
494+
if (!archetype)
495+
break;
496+
}
497+
if (!archetype)
498+
continue;
499+
500+
// Go down our PAs until we find the referenced PA.
501+
auto existingPA = this;
502+
while(identifiers.size()) {
503+
existingPA = existingPA->getNestedType(identifiers.back(), builder);
504+
identifiers.pop_back();
505+
}
506+
pa->Representative = existingPA;
507+
RequirementSource source(RequirementSource::Inferred, SourceLoc());
508+
pa->SameTypeSource = source;
509+
} else if (type->hasArchetype()) {
510+
// This is a complex type involving other associatedtypes, we'll fail
511+
// to resolve and get a special diagnosis in finalize.
512+
continue;
513+
} else {
514+
pa->ArchetypeOrConcreteType = NestedType::forConcreteType(type);
515+
}
516+
} else
472517
continue;
473518

474-
// Resolve this nested type to this associated type.
475-
auto pa = new PotentialArchetype(this, assocType);
476-
477519
// If we have resolved this nested type to more than one associated
478520
// type, create same-type constraints between them.
479521
RequirementSource source(RequirementSource::Inferred, SourceLoc());
480522
if (!nested.empty()) {
481-
pa->Representative = nested.front()->getRepresentative();
482-
pa->Representative->EquivalenceClass.push_back(pa);
483-
pa->SameTypeSource = source;
523+
auto existing = nested.front();
524+
if (auto alias = existing->getTypeAliasDecl()) {
525+
// If we found a typealias first, and now have an associatedtype
526+
// with the same name, it was a Swift 2 style declaration of the
527+
// type an inherited associatedtype should be bound to. In such a
528+
// case we want to make sure the associatedtype is frontmost to
529+
// generate generics/witness lists correctly, and the alias
530+
// will be unused/useless for generic constraining anyway.
531+
alias->setInvalid();
532+
nested.clear();
533+
} else {
534+
pa->Representative = existing->getRepresentative();
535+
pa->Representative->EquivalenceClass.push_back(pa);
536+
pa->SameTypeSource = source;
537+
}
484538
}
485539

486540
// Add this resolved nested type.
@@ -677,6 +731,9 @@ ArchetypeBuilder::PotentialArchetype::getType(ArchetypeBuilder &builder) {
677731
builder.getASTContext().registerLazyArchetype(arch, builder, this);
678732
SmallVector<std::pair<Identifier, NestedType>, 4> FlatNestedTypes;
679733
for (auto Nested : NestedTypes) {
734+
// Skip type aliases, which are just shortcuts.
735+
if (Nested.second.front()->getTypeAliasDecl())
736+
continue;
680737
bool anyNotRenamed = false;
681738
for (auto NestedPA : Nested.second) {
682739
if (!NestedPA->wasRenamed()) {
@@ -1646,6 +1703,23 @@ bool ArchetypeBuilder::finalize(SourceLoc loc) {
16461703
/* FIXME: Should be able to handle this earlier */pa->getSuperclass())
16471704
return;
16481705

1706+
// If a typealias with this name exists in one of the parent protocols,
1707+
// give a special diagnosis.
1708+
auto parentConformances = pa->getParent()->getConformsTo();
1709+
for (auto &conforms : parentConformances) {
1710+
for (auto member : conforms.first->getMembers()) {
1711+
auto typealias = dyn_cast<TypeAliasDecl>(member);
1712+
if (!typealias || typealias->getName() != pa->getName())
1713+
continue;
1714+
1715+
Context.Diags.diagnose(loc, diag::invalid_member_type_alias,
1716+
pa->getName());
1717+
invalid = true;
1718+
pa->setInvalid();
1719+
return;
1720+
}
1721+
}
1722+
16491723
// Try to typo correct to a nested type name.
16501724
Identifier correction = typoCorrectNestedType(pa);
16511725
if (correction.empty()) {
@@ -1702,7 +1776,7 @@ ArrayRef<ArchetypeType *> ArchetypeBuilder::getAllArchetypes() {
17021776
continue;
17031777

17041778
PotentialArchetype *PA = Entry.second;
1705-
if (!PA->isConcreteType()) {
1779+
if (!PA->isConcreteType() && !PA->getTypeAliasDecl()) {
17061780
auto Archetype = PA->getType(*this).castToArchetype();
17071781
GenericParamList::addNestedArchetypes(Archetype, KnownArchetypes,
17081782
Impl->AllArchetypes);
@@ -2105,6 +2179,9 @@ addNestedRequirements(
21052179
for (const auto &nested : pa->getNestedTypes()) {
21062180
// FIXME: Dropping requirements among different associated types of the
21072181
// same name.
2182+
// Skip type aliases, which are just shortcuts down the tree.
2183+
if (nested.second.front()->getTypeAliasDecl())
2184+
continue;
21082185
nestedTypes.push_back(std::make_pair(nested.first, nested.second.front()));
21092186
}
21102187
std::sort(nestedTypes.begin(), nestedTypes.end(),

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1733,7 +1733,7 @@ Type TypeDecl::getDeclaredType() const {
17331733

17341734
Type TypeDecl::getDeclaredInterfaceType() const {
17351735
Type interfaceType = getInterfaceType();
1736-
if (interfaceType->is<ErrorType>())
1736+
if (interfaceType.isNull() || interfaceType->is<ErrorType>())
17371737
return interfaceType;
17381738

17391739
return interfaceType->castTo<MetatypeType>()->getInstanceType();

0 commit comments

Comments
 (0)