Merge pull request #1610 from gregomni/typealias

[Parse/AST/Sema] Split parsing for typealias & associatedtype, allow typealias in protocols and generic constraints
This commit is contained in:
Greg Titus
2016-03-13 21:50:01 -07:00
16 changed files with 304 additions and 114 deletions

View File

@@ -387,8 +387,10 @@ class ArchetypeBuilder::PotentialArchetype {
/// \brief The name of this potential archetype or, for an /// \brief The name of this potential archetype or, for an
/// associated type, the declaration of the associated type to which /// associated type, the declaration of the associated type to which
/// this potential archetype has been resolved. /// this potential archetype has been resolved. Or, for a type alias,
llvm::PointerUnion<Identifier, AssociatedTypeDecl *> NameOrAssociatedType; /// the type alias decl.
llvm::PointerUnion3<Identifier, AssociatedTypeDecl *,
TypeAliasDecl *> NameOrAssociatedType;
/// \brief The representative of the equivalent class of potential archetypes /// \brief The representative of the equivalent class of potential archetypes
/// to which this potential archetype belongs. /// to which this potential archetype belongs.
@@ -466,6 +468,17 @@ class ArchetypeBuilder::PotentialArchetype {
EquivalenceClass.push_back(this); EquivalenceClass.push_back(this);
} }
/// \brief Construct a new potential archetype for a type alias.
PotentialArchetype(PotentialArchetype *Parent, TypeAliasDecl *TypeAlias)
: ParentOrParam(Parent), NameOrAssociatedType(TypeAlias),
Representative(this), IsRecursive(false), Invalid(false),
SubstitutingConcreteType(false), RecursiveConcreteType(false),
RecursiveSuperclassType(false), Renamed(false)
{
assert(Parent != nullptr && "Not an associated type?");
EquivalenceClass.push_back(this);
}
/// \brief Construct a new potential archetype for a generic parameter. /// \brief Construct a new potential archetype for a generic parameter.
PotentialArchetype(GenericTypeParamType *GenericParam, PotentialArchetype(GenericTypeParamType *GenericParam,
ProtocolDecl *RootProtocol, ProtocolDecl *RootProtocol,
@@ -525,6 +538,11 @@ public:
return ParentOrParam.dyn_cast<GenericTypeParamType *>(); return ParentOrParam.dyn_cast<GenericTypeParamType *>();
} }
/// Retrieve the type alias.
TypeAliasDecl *getTypeAliasDecl() const {
return NameOrAssociatedType.dyn_cast<TypeAliasDecl *>();
}
/// Retrieve the set of protocols to which this type conforms. /// Retrieve the set of protocols to which this type conforms.
const llvm::MapVector<ProtocolDecl *, RequirementSource> & const llvm::MapVector<ProtocolDecl *, RequirementSource> &
getConformsTo() const { getConformsTo() const {

View File

@@ -283,6 +283,8 @@ ERROR(expected_equal_in_typealias,PointsToFirstBadToken,
"expected '=' in typealias declaration", ()) "expected '=' in typealias declaration", ())
ERROR(expected_type_in_typealias,PointsToFirstBadToken, ERROR(expected_type_in_typealias,PointsToFirstBadToken,
"expected type in typealias declaration", ()) "expected type in typealias declaration", ())
ERROR(expected_type_in_associatedtype,PointsToFirstBadToken,
"expected type in associatedtype declaration", ())
ERROR(associated_type_generic_parameter_list,PointsToFirstBadToken, ERROR(associated_type_generic_parameter_list,PointsToFirstBadToken,
"associated types may not have a generic parameter list", ()) "associated types may not have a generic parameter list", ())
ERROR(typealias_generic_list_constraint,PointsToFirstBadToken, ERROR(typealias_generic_list_constraint,PointsToFirstBadToken,
@@ -759,8 +761,8 @@ ERROR(expected_close_after_else_directive,none,
"further conditions after #else are unreachable", ()) "further conditions after #else are unreachable", ())
/// Associatedtype Statement /// Associatedtype Statement
WARNING(typealias_inside_protocol,none, ERROR(typealias_inside_protocol_without_type,none,
"use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead", ()) "typealias is missing an assigned type; use 'associatedtype' to define an associated type requirement", ())
ERROR(associatedtype_outside_protocol,none, ERROR(associatedtype_outside_protocol,none,
"associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement", ()) "associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement", ())

View File

@@ -468,6 +468,9 @@ ERROR(invalid_member_type,none,
ERROR(invalid_member_type_suggest,none, ERROR(invalid_member_type_suggest,none,
"%0 does not have a member type named %1; did you mean %2?", "%0 does not have a member type named %1; did you mean %2?",
(Type, Identifier, Identifier)) (Type, Identifier, Identifier))
ERROR(invalid_member_type_alias,none,
"typealias %0 is too complex to be used as a generic constraint; "
"use an associatedtype instead", (Identifier))
ERROR(ambiguous_member_type,none, ERROR(ambiguous_member_type,none,
"ambiguous type name %0 in %1", (Identifier, Type)) "ambiguous type name %0 in %1", (Identifier, Type))
ERROR(no_module_type,none, ERROR(no_module_type,none,

View File

@@ -657,15 +657,14 @@ public:
PD_HasContainerType = 1 << 2, PD_HasContainerType = 1 << 2,
PD_DisallowNominalTypes = 1 << 3, PD_DisallowNominalTypes = 1 << 3,
PD_DisallowInit = 1 << 4, PD_DisallowInit = 1 << 4,
PD_DisallowTypeAliasDef = 1 << 5, PD_AllowDestructor = 1 << 5,
PD_AllowDestructor = 1 << 6, PD_AllowEnumElement = 1 << 6,
PD_AllowEnumElement = 1 << 7, PD_InProtocol = 1 << 7,
PD_InProtocol = 1 << 8, PD_InClass = 1 << 8,
PD_InClass = 1 << 9, PD_InExtension = 1 << 9,
PD_InExtension = 1 << 10, PD_InStruct = 1 << 10,
PD_InStruct = 1 << 11, PD_InEnum = 1 << 11,
PD_InEnum = 1 << 12, PD_InLoop = 1 << 12
PD_InLoop = 1 << 13
}; };
/// Options that control the parsing of declarations. /// Options that control the parsing of declarations.
@@ -701,8 +700,10 @@ public:
ParserStatus parseDecl(SmallVectorImpl<Decl*> &Entries, ParseDeclOptions Flags); ParserStatus parseDecl(SmallVectorImpl<Decl*> &Entries, ParseDeclOptions Flags);
void parseDeclDelayed(); void parseDeclDelayed();
ParserResult<TypeDecl> parseDeclTypeAlias(bool WantDefinition, ParserResult<TypeDecl> parseDeclTypeAlias(ParseDeclOptions Flags,
bool isAssociatedType, DeclAttributes &Attributes);
ParserResult<TypeDecl> parseDeclAssociatedType(ParseDeclOptions Flags,
DeclAttributes &Attributes); DeclAttributes &Attributes);
ParserResult<IfConfigDecl> parseDeclIfConfig(ParseDeclOptions Flags); ParserResult<IfConfigDecl> parseDeclIfConfig(ParseDeclOptions Flags);

View File

@@ -101,6 +101,10 @@ public:
asDerived().addAssociatedType(td, protos); asDerived().addAssociatedType(td, protos);
} }
void visitTypeAliasDecl(TypeAliasDecl *tad) {
// We don't care about these by themselves for witnesses.
}
void visitPatternBindingDecl(PatternBindingDecl *pbd) { void visitPatternBindingDecl(PatternBindingDecl *pbd) {
// We only care about the contained VarDecls. // We only care about the contained VarDecls.
} }

View File

@@ -1782,6 +1782,10 @@ struct ASTNodeBase {};
continue; continue;
} }
// No witness necessary for type aliases
if (isa<TypeAliasDecl>(member))
continue;
// If this is an accessor for something, ignore it. // If this is an accessor for something, ignore it.
if (auto *FD = dyn_cast<FuncDecl>(member)) if (auto *FD = dyn_cast<FuncDecl>(member))
if (FD->isAccessor()) if (FD->isAccessor())

View File

@@ -219,7 +219,8 @@ void ArchetypeBuilder::PotentialArchetype::buildFullName(
Identifier ArchetypeBuilder::PotentialArchetype::getName() const { Identifier ArchetypeBuilder::PotentialArchetype::getName() const {
if (auto assocType = NameOrAssociatedType.dyn_cast<AssociatedTypeDecl *>()) if (auto assocType = NameOrAssociatedType.dyn_cast<AssociatedTypeDecl *>())
return assocType->getName(); return assocType->getName();
if (auto typeAlias = NameOrAssociatedType.dyn_cast<TypeAliasDecl *>())
return typeAlias->getName();
return NameOrAssociatedType.get<Identifier>(); return NameOrAssociatedType.get<Identifier>();
} }
@@ -303,12 +304,12 @@ static void maybeAddSameTypeRequirementForNestedType(
RequirementSource fromSource, RequirementSource fromSource,
ProtocolConformance *superConformance, ProtocolConformance *superConformance,
ArchetypeBuilder &builder) { ArchetypeBuilder &builder) {
auto assocType = nestedPA->getResolvedAssociatedType();
assert(assocType && "Not resolved to an associated type?");
// If there's no super conformance, we're done. // If there's no super conformance, we're done.
if (!superConformance) return; if (!superConformance) return;
auto assocType = nestedPA->getResolvedAssociatedType();
assert(assocType && "Not resolved to an associated type?");
// Dig out the type witness. // Dig out the type witness.
auto concreteType = auto concreteType =
superConformance->getTypeWitness(assocType, builder.getLazyResolver()) superConformance->getTypeWitness(assocType, builder.getLazyResolver())
@@ -467,21 +468,74 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType(
// archetype conforms. // archetype conforms.
for (auto &conforms : ConformsTo) { for (auto &conforms : ConformsTo) {
for (auto member : conforms.first->lookupDirect(nestedName)) { for (auto member : conforms.first->lookupDirect(nestedName)) {
auto assocType = dyn_cast<AssociatedTypeDecl>(member); PotentialArchetype *pa;
if (!assocType)
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
// Resolve this nested type to this associated type.
pa = new PotentialArchetype(this, assocType);
} else if (auto alias = dyn_cast<TypeAliasDecl>(member)) {
// Resolve this nested type to this type alias.
pa = new PotentialArchetype(this, alias);
if (!alias->hasUnderlyingType())
builder.getLazyResolver()->resolveDeclSignature(alias);
if (!alias->hasUnderlyingType())
continue; continue;
// Resolve this nested type to this associated type. auto type = alias->getUnderlyingType();
auto pa = new PotentialArchetype(this, assocType); if (auto archetype = type->getAs<ArchetypeType>()) {
auto containingProtocol = cast<ProtocolDecl>(alias->getParent());
SmallVector<Identifier, 4> identifiers;
// Go up archetype parents until we find our containing protocol.
while (archetype->getSelfProtocol() != containingProtocol) {
identifiers.push_back(archetype->getName());
archetype = archetype->getParent();
if (!archetype)
break;
}
if (!archetype)
continue;
// Go down our PAs until we find the referenced PA.
auto existingPA = this;
while(identifiers.size()) {
existingPA = existingPA->getNestedType(identifiers.back(), builder);
identifiers.pop_back();
}
pa->Representative = existingPA;
RequirementSource source(RequirementSource::Inferred, SourceLoc());
pa->SameTypeSource = source;
} else if (type->hasArchetype()) {
// This is a complex type involving other associatedtypes, we'll fail
// to resolve and get a special diagnosis in finalize.
continue;
} else {
pa->ArchetypeOrConcreteType = NestedType::forConcreteType(type);
}
} else
continue;
// If we have resolved this nested type to more than one associated // If we have resolved this nested type to more than one associated
// type, create same-type constraints between them. // type, create same-type constraints between them.
RequirementSource source(RequirementSource::Inferred, SourceLoc()); RequirementSource source(RequirementSource::Inferred, SourceLoc());
if (!nested.empty()) { if (!nested.empty()) {
pa->Representative = nested.front()->getRepresentative(); auto existing = nested.front();
if (auto alias = existing->getTypeAliasDecl()) {
// If we found a typealias first, and now have an associatedtype
// with the same name, it was a Swift 2 style declaration of the
// type an inherited associatedtype should be bound to. In such a
// case we want to make sure the associatedtype is frontmost to
// generate generics/witness lists correctly, and the alias
// will be unused/useless for generic constraining anyway.
alias->setInvalid();
nested.clear();
} else {
pa->Representative = existing->getRepresentative();
pa->Representative->EquivalenceClass.push_back(pa); pa->Representative->EquivalenceClass.push_back(pa);
pa->SameTypeSource = source; pa->SameTypeSource = source;
} }
}
// Add this resolved nested type. // Add this resolved nested type.
nested.push_back(pa); nested.push_back(pa);
@@ -677,6 +731,9 @@ ArchetypeBuilder::PotentialArchetype::getType(ArchetypeBuilder &builder) {
builder.getASTContext().registerLazyArchetype(arch, builder, this); builder.getASTContext().registerLazyArchetype(arch, builder, this);
SmallVector<std::pair<Identifier, NestedType>, 4> FlatNestedTypes; SmallVector<std::pair<Identifier, NestedType>, 4> FlatNestedTypes;
for (auto Nested : NestedTypes) { for (auto Nested : NestedTypes) {
// Skip type aliases, which are just shortcuts.
if (Nested.second.front()->getTypeAliasDecl())
continue;
bool anyNotRenamed = false; bool anyNotRenamed = false;
for (auto NestedPA : Nested.second) { for (auto NestedPA : Nested.second) {
if (!NestedPA->wasRenamed()) { if (!NestedPA->wasRenamed()) {
@@ -1646,6 +1703,23 @@ bool ArchetypeBuilder::finalize(SourceLoc loc) {
/* FIXME: Should be able to handle this earlier */pa->getSuperclass()) /* FIXME: Should be able to handle this earlier */pa->getSuperclass())
return; return;
// If a typealias with this name exists in one of the parent protocols,
// give a special diagnosis.
auto parentConformances = pa->getParent()->getConformsTo();
for (auto &conforms : parentConformances) {
for (auto member : conforms.first->getMembers()) {
auto typealias = dyn_cast<TypeAliasDecl>(member);
if (!typealias || typealias->getName() != pa->getName())
continue;
Context.Diags.diagnose(loc, diag::invalid_member_type_alias,
pa->getName());
invalid = true;
pa->setInvalid();
return;
}
}
// Try to typo correct to a nested type name. // Try to typo correct to a nested type name.
Identifier correction = typoCorrectNestedType(pa); Identifier correction = typoCorrectNestedType(pa);
if (correction.empty()) { if (correction.empty()) {
@@ -1702,7 +1776,7 @@ ArrayRef<ArchetypeType *> ArchetypeBuilder::getAllArchetypes() {
continue; continue;
PotentialArchetype *PA = Entry.second; PotentialArchetype *PA = Entry.second;
if (!PA->isConcreteType()) { if (!PA->isConcreteType() && !PA->getTypeAliasDecl()) {
auto Archetype = PA->getType(*this).castToArchetype(); auto Archetype = PA->getType(*this).castToArchetype();
GenericParamList::addNestedArchetypes(Archetype, KnownArchetypes, GenericParamList::addNestedArchetypes(Archetype, KnownArchetypes,
Impl->AllArchetypes); Impl->AllArchetypes);
@@ -2105,6 +2179,9 @@ addNestedRequirements(
for (const auto &nested : pa->getNestedTypes()) { for (const auto &nested : pa->getNestedTypes()) {
// FIXME: Dropping requirements among different associated types of the // FIXME: Dropping requirements among different associated types of the
// same name. // same name.
// Skip type aliases, which are just shortcuts down the tree.
if (nested.second.front()->getTypeAliasDecl())
continue;
nestedTypes.push_back(std::make_pair(nested.first, nested.second.front())); nestedTypes.push_back(std::make_pair(nested.first, nested.second.front()));
} }
std::sort(nestedTypes.begin(), nestedTypes.end(), std::sort(nestedTypes.begin(), nestedTypes.end(),

View File

@@ -1733,7 +1733,7 @@ Type TypeDecl::getDeclaredType() const {
Type TypeDecl::getDeclaredInterfaceType() const { Type TypeDecl::getDeclaredInterfaceType() const {
Type interfaceType = getInterfaceType(); Type interfaceType = getInterfaceType();
if (interfaceType->is<ErrorType>()) if (interfaceType.isNull() || interfaceType->is<ErrorType>())
return interfaceType; return interfaceType;
return interfaceType->castTo<MetatypeType>()->getInstanceType(); return interfaceType->castTo<MetatypeType>()->getInstanceType();

View File

@@ -2086,10 +2086,11 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
MayNeedOverrideCompletion = true; MayNeedOverrideCompletion = true;
break; break;
case tok::kw_typealias: case tok::kw_typealias:
DeclResult = parseDeclTypeAlias(Flags, Attributes);
Status = DeclResult;
break;
case tok::kw_associatedtype: case tok::kw_associatedtype:
DeclResult = parseDeclTypeAlias(!(Flags & PD_DisallowTypeAliasDef), DeclResult = parseDeclAssociatedType(Flags, Attributes);
Flags.contains(PD_InProtocol),
Attributes);
Status = DeclResult; Status = DeclResult;
break; break;
case tok::kw_enum: case tok::kw_enum:
@@ -2833,44 +2834,24 @@ ParserResult<IfConfigDecl> Parser::parseDeclIfConfig(ParseDeclOptions Flags) {
/// ///
/// \verbatim /// \verbatim
/// decl-typealias: /// decl-typealias:
/// 'typealias' identifier inheritance? '=' type /// 'typealias' identifier generic-params? '=' type
/// 'associatedtype' identifier inheritance? '=' type
/// \endverbatim /// \endverbatim
ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition, ParserResult<TypeDecl> Parser::parseDeclTypeAlias(Parser::ParseDeclOptions Flags,
bool isAssociatedType,
DeclAttributes &Attributes) { DeclAttributes &Attributes) {
SourceLoc TypeAliasLoc; ParserPosition startPosition = getParserPosition();
SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias);
if (isAssociatedType) {
if (consumeIf(tok::kw_typealias, TypeAliasLoc)) {
diagnose(TypeAliasLoc, diag::typealias_inside_protocol)
.fixItReplace(TypeAliasLoc, "associatedtype");
} else {
TypeAliasLoc = consumeToken(tok::kw_associatedtype);
}
} else {
if (consumeIf(tok::kw_associatedtype, TypeAliasLoc)) {
diagnose(TypeAliasLoc, diag::associatedtype_outside_protocol)
.fixItReplace(TypeAliasLoc, "typealias");
} else {
TypeAliasLoc = consumeToken(tok::kw_typealias);
}
}
Identifier Id; Identifier Id;
SourceLoc IdLoc; SourceLoc IdLoc;
ParserStatus Status; ParserStatus Status;
Status |= Status |=
parseIdentifierDeclName(*this, Id, IdLoc, tok::colon, tok::equal, parseIdentifierDeclName(*this, Id, IdLoc, tok::colon, tok::equal,
diag::expected_identifier_in_decl, isAssociatedType ? "associatedtype" : "typealias"); diag::expected_identifier_in_decl, "typealias");
if (Status.isError()) if (Status.isError())
return nullptr; return nullptr;
DebuggerContextChange DCC(*this, Id, DeclKind::TypeAlias); DebuggerContextChange DCC(*this, Id, DeclKind::TypeAlias);
Optional<Scope> GenericsScope; Optional<Scope> GenericsScope;
GenericsScope.emplace(this, ScopeKind::Generics); GenericsScope.emplace(this, ScopeKind::Generics);
@@ -2884,14 +2865,6 @@ ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition,
if (!genericParams) { if (!genericParams) {
// If the parser returned null, it is an already diagnosed parse error. // If the parser returned null, it is an already diagnosed parse error.
} else if (isAssociatedType || !WantDefinition) {
// If the parameter list isn't valid here, reject it with a specific
// error. If a constraint is present within the parameter list, reject
// that.
diagnose(genericParams->getLAngleLoc(),
diag::associated_type_generic_parameter_list)
.fixItRemove(genericParams->getSourceRange());
genericParams = nullptr;
} else if (!genericParams->getRequirements().empty()) { } else if (!genericParams->getRequirements().empty()) {
// Reject a where clause. // Reject a where clause.
diagnose(genericParams->getWhereLoc(), diagnose(genericParams->getWhereLoc(),
@@ -2911,46 +2884,28 @@ ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition,
} }
} }
// Parse optional inheritance clause. if (Flags.contains(PD_InProtocol) && !genericParams && !Tok.is(tok::equal)) {
// FIXME: Allow class requirements here. // If we're in a protocol and don't see an '=' this looks like leftover Swift 2
SmallVector<TypeLoc, 2> Inherited; // code intending to be an associatedtype.
if (isAssociatedType && Tok.is(tok::colon)) backtrackToPosition(startPosition);
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr); return parseDeclAssociatedType(Flags, Attributes);
}
ParserResult<TypeRepr> UnderlyingTy;
if (WantDefinition || Tok.is(tok::equal)) {
if (Tok.is(tok::colon)) { if (Tok.is(tok::colon)) {
// It is a common mistake to write "typealias A : Int" instead of = Int. // It is a common mistake to write "typealias A : Int" instead of = Int.
// Recognize this and produce a fixit. // Recognize this and produce a fixit.
diagnose(Tok, diag::expected_equal_in_typealias) diagnose(Tok, diag::expected_equal_in_typealias)
.fixItReplace(Tok.getLoc(), "="); .fixItReplace(Tok.getLoc(), "=");
consumeToken(tok::colon); consumeToken(tok::colon);
} else if (parseToken(tok::equal, diag::expected_equal_in_typealias)) { } else if (parseToken(tok::equal, diag::expected_equal_in_typealias)) {
Status.setIsParseError(); Status.setIsParseError();
return Status; return Status;
} }
UnderlyingTy = parseType(diag::expected_type_in_typealias); ParserResult<TypeRepr> UnderlyingTy = parseType(diag::expected_type_in_typealias);
Status |= UnderlyingTy; Status |= UnderlyingTy;
if (UnderlyingTy.isNull()) if (UnderlyingTy.isNull())
return Status; return Status;
}
// If this is an associated type, build the AST for it.
if (isAssociatedType) {
assert(!genericParams && "Associated types don't allow generic params");
auto assocType = new (Context) AssociatedTypeDecl(
CurDeclContext,
TypeAliasLoc, Id, IdLoc,
UnderlyingTy.getPtrOrNull());
assocType->getAttrs() = Attributes;
if (!Inherited.empty())
assocType->setInherited(Context.AllocateCopy(Inherited));
addToScope(assocType);
return makeParserResult(Status, assocType);
}
// Otherwise, build a typealias.
auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, Id, IdLoc, auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, Id, IdLoc,
UnderlyingTy.getPtrOrNull(), UnderlyingTy.getPtrOrNull(),
genericParams, CurDeclContext); genericParams, CurDeclContext);
@@ -2963,6 +2918,79 @@ ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition,
return DCC.fixupParserResult(Status, TAD); return DCC.fixupParserResult(Status, TAD);
} }
/// \brief Parse an associatedtype decl.
///
/// \verbatim
/// decl-associatedtype:
/// 'associatedtype' identifier inheritance? ('=' type)?
/// \endverbatim
ParserResult<TypeDecl> Parser::parseDeclAssociatedType(Parser::ParseDeclOptions Flags,
DeclAttributes &Attributes) {
SourceLoc AssociatedTypeLoc;
ParserStatus Status;
Identifier Id;
SourceLoc IdLoc;
// Look for 'typealias' here and diagnose a fixit because parseDeclTypeAlias can
// ask us to fix up leftover Swift 2 code intending to be an associatedtype.
if (Tok.is(tok::kw_typealias)) {
AssociatedTypeLoc = consumeToken(tok::kw_typealias);
diagnose(AssociatedTypeLoc, diag::typealias_inside_protocol_without_type)
.fixItReplace(AssociatedTypeLoc, "associatedtype");
} else {
AssociatedTypeLoc = consumeToken(tok::kw_associatedtype);
}
Status =
parseIdentifierDeclName(*this, Id, IdLoc, tok::colon, tok::equal,
diag::expected_identifier_in_decl, "associatedtype");
if (Status.isError())
return nullptr;
DebuggerContextChange DCC(*this, Id, DeclKind::AssociatedType);
// Reject generic parameters with a specific error.
if (startsWithLess(Tok)) {
if (auto genericParams = parseGenericParameters().getPtrOrNull()) {
diagnose(genericParams->getLAngleLoc(),
diag::associated_type_generic_parameter_list)
.fixItRemove(genericParams->getSourceRange());
}
}
// Parse optional inheritance clause.
// FIXME: Allow class requirements here.
SmallVector<TypeLoc, 2> Inherited;
if (Tok.is(tok::colon))
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
ParserResult<TypeRepr> UnderlyingTy;
if (Tok.is(tok::equal)) {
consumeToken(tok::equal);
UnderlyingTy = parseType(diag::expected_type_in_associatedtype);
Status |= UnderlyingTy;
if (UnderlyingTy.isNull())
return Status;
}
if (!Flags.contains(PD_InProtocol)) {
diagnose(AssociatedTypeLoc, diag::associatedtype_outside_protocol)
.fixItReplace(AssociatedTypeLoc, "typealias");
Status.setIsParseError();
return Status;
}
auto assocType = new (Context) AssociatedTypeDecl(CurDeclContext,
AssociatedTypeLoc, Id, IdLoc,
UnderlyingTy.getPtrOrNull());
assocType->getAttrs() = Attributes;
if (!Inherited.empty())
assocType->setInherited(Context.AllocateCopy(Inherited));
addToScope(assocType);
return makeParserResult(Status, assocType);
}
/// This function creates an accessor function (with no body) for a computed /// This function creates an accessor function (with no body) for a computed
/// property or subscript. /// property or subscript.
static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param, static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param,
@@ -5068,7 +5096,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
// Parse the members. // Parse the members.
ParseDeclOptions Options(PD_HasContainerType | ParseDeclOptions Options(PD_HasContainerType |
PD_DisallowNominalTypes | PD_DisallowNominalTypes |
PD_DisallowInit | PD_DisallowTypeAliasDef | PD_DisallowInit |
PD_InProtocol); PD_InProtocol);
if (parseNominalDeclMembers(Members, LBraceLoc, RBraceLoc, if (parseNominalDeclMembers(Members, LBraceLoc, RBraceLoc,
diag::expected_rbrace_protocol, diag::expected_rbrace_protocol,

View File

@@ -174,6 +174,16 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
return DependentMemberType::get(baseTy, assocType, TC.Context); return DependentMemberType::get(baseTy, assocType, TC.Context);
} }
// If the nested type comes from a type alias, use either the alias's
// concrete type, or resolve its components down to another dependent member.
if (auto alias = nestedPA->getTypeAliasDecl()) {
if (nestedPA->isConcreteType())
return nestedPA->getConcreteType();
return TC.substMemberTypeWithBase(DC->getParentModule(), alias,
baseTy, true);
}
Identifier name = ref->getIdentifier(); Identifier name = ref->getIdentifier();
SourceLoc nameLoc = ref->getIdLoc(); SourceLoc nameLoc = ref->getIdLoc();

View File

@@ -3711,6 +3711,10 @@ void ConformanceChecker::checkConformance() {
if (isa<AssociatedTypeDecl>(requirement)) if (isa<AssociatedTypeDecl>(requirement))
continue; continue;
// Type aliases don't have requirements themselves.
if (isa<TypeAliasDecl>(requirement))
continue;
// If we've already determined this witness, skip it. // If we've already determined this witness, skip it.
if (Conformance->hasWitness(requirement)) { if (Conformance->hasWitness(requirement)) {
// If this is an unsatisfied @objc optional requirement, // If this is an unsatisfied @objc optional requirement,

View File

@@ -173,7 +173,7 @@ struct C<a : B> : B { // expected-error {{type 'C<a>' does not conform to protoc
// SR-511 // SR-511
protocol sr511 { protocol sr511 {
typealias Foo // expected-warning {{use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead}} {{3-12=associatedtype}} typealias Foo // expected-error {{typealias is missing an assigned type; use 'associatedtype' to define an associated type requirement}}
} }
associatedtype Foo = Int // expected-error {{associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement}} associatedtype Foo = Int // expected-error {{associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement}}

View File

@@ -648,7 +648,7 @@ func resyncParser1() {}
//===--- //===---
protocol AssocType1 { protocol AssocType1 {
typealias AssocType = #^TYPE_IN_ASSOC_TYPE_1^# associatedtype AssocType = #^TYPE_IN_ASSOC_TYPE_1^#
} }
//===--- //===---
@@ -656,7 +656,7 @@ protocol AssocType1 {
//===--- //===---
protocol AssocType1 { protocol AssocType1 {
typealias AssocType : #^TYPE_IN_ASSOC_TYPE_INHERITANCE_1^# associatedtype AssocType : #^TYPE_IN_ASSOC_TYPE_INHERITANCE_1^#
} }
//===--- //===---

View File

@@ -69,8 +69,7 @@ internal func _splitRandomAccessIndexRange<Index : RandomAccessIndex>(
public protocol CollectionBuilder { public protocol CollectionBuilder {
associatedtype Destination : Collection associatedtype Destination : Collection
// FIXME: should really be a typealias once that is supported typealias Element = Destination.Iterator.Element
associatedtype Element = Destination.Iterator.Element
init() init()

View File

@@ -469,9 +469,9 @@ func h<T : C3>(x : T) {
protocol P4 { protocol P4 {
associatedtype T associatedtype T // expected-note {{protocol requires nested type 'T'}}
} }
class C4 : P4 { class C4 : P4 { // expected-error {{type 'C4' does not conform to protocol 'P4'}}
associatedtype T = Int // expected-error {{associated types can only be defined in a protocol}} {{3-17=typealias}} associatedtype T = Int // expected-error {{associated types can only be defined in a protocol; define a type or introduce a 'typealias' to satisfy an associated type requirement}} {{3-17=typealias}}
} }

View File

@@ -30,8 +30,7 @@ struct MyType<TyA, TyB> {
protocol P { protocol P {
associatedtype X<T> // expected-error {{associated types may not have a generic parameter list}} associatedtype X<T> // expected-error {{associated types may not have a generic parameter list}}
// expected-error @+1 {{associated types may not have a generic parameter list}} typealias Y<T> // expected-error {{expected '=' in typealias declaration}}
typealias Y<T> // expected-warning {{use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead}}
} }
typealias basicTypealias = Int typealias basicTypealias = Int
@@ -122,3 +121,44 @@ extension A<Float,Int> {} // expected-error {{constrained extension must be dec
extension C<T> {} // expected-error {{use of undeclared type 'T'}} extension C<T> {} // expected-error {{use of undeclared type 'T'}}
extension C<Int> {} // expected-error {{constrained extension must be declared on the unspecialized generic type 'MyType' with constraints specified by a 'where' clause}} extension C<Int> {} // expected-error {{constrained extension must be declared on the unspecialized generic type 'MyType' with constraints specified by a 'where' clause}}
// Allow typealias inside protocol, but don't allow it in where clauses (at least not yet)
protocol Col {
associatedtype Elem
var elem: Elem { get }
}
protocol CB {
associatedtype C : Col
typealias E = C.Elem
func setIt(element: E)
}
func go1<T : CB, U : Col where U.Elem == T.E>(col: U, builder: T) {
builder.setIt(col.elem)
}
func go2<T : CB, U : Col where U.Elem == T.C.Elem>(col: U, builder: T) { // OK
builder.setIt(col.elem)
}
// Specific diagnosis for trying to use complex typealiases in generic constraints
protocol P1 {
associatedtype A
typealias F = A -> ()
}
protocol P2 {
associatedtype B
}
func go3<T : P1, U : P2 where T.F == U.B>(x: T) -> U { // expected-error {{typealias 'F' is too complex to be used as a generic constraint; use an associatedtype instead}} expected-error {{'F' is not a member type of 'T'}}
}
// Specific diagnosis for things that look like Swift 2.x typealiases
protocol P3 {
typealias T // expected-error {{typealias is missing an assigned type; use 'associatedtype' to define an associated type requirement}}
typealias U : P2 // expected-error {{typealias is missing an assigned type; use 'associatedtype' to define an associated type requirement}}
associatedtype V : P2 = // expected-error {{expected type in associatedtype declaration}}
}