Skip to content

Commit 1e3ed8b

Browse files
committed
Split parsing for typealias & associatedtype, and allow typealias in protocols.
Split up parsing of typealias and associatedtype, including dropping a now unneeded ParseDeclOptions flag. Then made typealias in a protocol valid, and act like you would hope for protocol conformance purposes (i.e. as an alias possibly involved in the types of other func/var conformances, not as a hidden generic param in itself). Also added support for simple type aliases in generic constraints. Aliases to simple (non-sugared) archetype types (and also - trivially - aliases to concrete types) can now be part of same-type constraints. The strategy here is to add type aliases to the tree of PotentialArchetypes, and if they are an alias to an archetype, also to immediately find the real associated type and set it as the representative for the PA. Thus the typealias PA node becomes just a shortcut farther down into the tree for purposes of lookup and generating same type requirements. Then the typealias PA nodes need to be explicitly skipped when walking the tree for building archetype types and other types of requirements, in order to keep from getting extra out-of-order archetypes/witness markers of the real associated type inserted where the typealias is defined. Any constraint with a typealias more complex than pointing to a single nested associated type (e.g. `typealias T = A.B.C.D`), will now get a specialized diagnoses.
1 parent 78b7b96 commit 1e3ed8b

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
@@ -280,6 +280,8 @@ ERROR(expected_equal_in_typealias,PointsToFirstBadToken,
280280
"expected '=' in typealias declaration", ())
281281
ERROR(expected_type_in_typealias,PointsToFirstBadToken,
282282
"expected type in typealias declaration", ())
283+
ERROR(expected_type_in_associatedtype,PointsToFirstBadToken,
284+
"expected type in associatedtype declaration", ())
283285
ERROR(associated_type_generic_parameter_list,PointsToFirstBadToken,
284286
"associated types may not have a generic parameter list", ())
285287
ERROR(typealias_generic_list_constraint,PointsToFirstBadToken,
@@ -756,8 +758,8 @@ ERROR(expected_close_after_else_directive,none,
756758
"further conditions after #else are unreachable", ())
757759

758760
/// Associatedtype Statement
759-
WARNING(typealias_inside_protocol,none,
760-
"use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead", ())
761+
ERROR(typealias_inside_protocol_without_type,none,
762+
"typealias is missing an assigned type; use 'associatedtype' to define an associated type requirement", ())
761763
ERROR(associatedtype_outside_protocol,none,
762764
"associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement", ())
763765

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
@@ -646,15 +646,14 @@ class Parser {
646646
PD_HasContainerType = 1 << 2,
647647
PD_DisallowNominalTypes = 1 << 3,
648648
PD_DisallowInit = 1 << 4,
649-
PD_DisallowTypeAliasDef = 1 << 5,
650-
PD_AllowDestructor = 1 << 6,
651-
PD_AllowEnumElement = 1 << 7,
652-
PD_InProtocol = 1 << 8,
653-
PD_InClass = 1 << 9,
654-
PD_InExtension = 1 << 10,
655-
PD_InStruct = 1 << 11,
656-
PD_InEnum = 1 << 12,
657-
PD_InLoop = 1 << 13
649+
PD_AllowDestructor = 1 << 5,
650+
PD_AllowEnumElement = 1 << 6,
651+
PD_InProtocol = 1 << 7,
652+
PD_InClass = 1 << 8,
653+
PD_InExtension = 1 << 9,
654+
PD_InStruct = 1 << 10,
655+
PD_InEnum = 1 << 11,
656+
PD_InLoop = 1 << 12
658657
};
659658

660659
/// Options that control the parsing of declarations.
@@ -690,9 +689,11 @@ class Parser {
690689
ParserStatus parseDecl(SmallVectorImpl<Decl*> &Entries, ParseDeclOptions Flags);
691690
void parseDeclDelayed();
692691

693-
ParserResult<TypeDecl> parseDeclTypeAlias(bool WantDefinition,
694-
bool isAssociatedType,
692+
ParserResult<TypeDecl> parseDeclTypeAlias(ParseDeclOptions Flags,
695693
DeclAttributes &Attributes);
694+
695+
ParserResult<TypeDecl> parseDeclAssociatedType(ParseDeclOptions Flags,
696+
DeclAttributes &Attributes);
696697

697698
ParserResult<IfConfigDecl> parseDeclIfConfig(ParseDeclOptions Flags);
698699
/// 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)