mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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 {
|
||||||
|
|||||||
@@ -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", ())
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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}}
|
||||||
|
|||||||
@@ -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^#
|
||||||
}
|
}
|
||||||
|
|
||||||
//===---
|
//===---
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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}}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user