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
|
||||
/// associated type, the declaration of the associated type to which
|
||||
/// this potential archetype has been resolved.
|
||||
llvm::PointerUnion<Identifier, AssociatedTypeDecl *> NameOrAssociatedType;
|
||||
/// this potential archetype has been resolved. Or, for a type alias,
|
||||
/// the type alias decl.
|
||||
llvm::PointerUnion3<Identifier, AssociatedTypeDecl *,
|
||||
TypeAliasDecl *> NameOrAssociatedType;
|
||||
|
||||
/// \brief The representative of the equivalent class of potential archetypes
|
||||
/// to which this potential archetype belongs.
|
||||
@@ -466,6 +468,17 @@ class ArchetypeBuilder::PotentialArchetype {
|
||||
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.
|
||||
PotentialArchetype(GenericTypeParamType *GenericParam,
|
||||
ProtocolDecl *RootProtocol,
|
||||
@@ -525,6 +538,11 @@ public:
|
||||
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.
|
||||
const llvm::MapVector<ProtocolDecl *, RequirementSource> &
|
||||
getConformsTo() const {
|
||||
|
||||
@@ -283,6 +283,8 @@ ERROR(expected_equal_in_typealias,PointsToFirstBadToken,
|
||||
"expected '=' in typealias declaration", ())
|
||||
ERROR(expected_type_in_typealias,PointsToFirstBadToken,
|
||||
"expected type in typealias declaration", ())
|
||||
ERROR(expected_type_in_associatedtype,PointsToFirstBadToken,
|
||||
"expected type in associatedtype declaration", ())
|
||||
ERROR(associated_type_generic_parameter_list,PointsToFirstBadToken,
|
||||
"associated types may not have a generic parameter list", ())
|
||||
ERROR(typealias_generic_list_constraint,PointsToFirstBadToken,
|
||||
@@ -759,8 +761,8 @@ ERROR(expected_close_after_else_directive,none,
|
||||
"further conditions after #else are unreachable", ())
|
||||
|
||||
/// Associatedtype Statement
|
||||
WARNING(typealias_inside_protocol,none,
|
||||
"use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead", ())
|
||||
ERROR(typealias_inside_protocol_without_type,none,
|
||||
"typealias is missing an assigned type; use 'associatedtype' to define an associated type requirement", ())
|
||||
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", ())
|
||||
|
||||
|
||||
@@ -468,6 +468,9 @@ ERROR(invalid_member_type,none,
|
||||
ERROR(invalid_member_type_suggest,none,
|
||||
"%0 does not have a member type named %1; did you mean %2?",
|
||||
(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,
|
||||
"ambiguous type name %0 in %1", (Identifier, Type))
|
||||
ERROR(no_module_type,none,
|
||||
|
||||
@@ -657,15 +657,14 @@ public:
|
||||
PD_HasContainerType = 1 << 2,
|
||||
PD_DisallowNominalTypes = 1 << 3,
|
||||
PD_DisallowInit = 1 << 4,
|
||||
PD_DisallowTypeAliasDef = 1 << 5,
|
||||
PD_AllowDestructor = 1 << 6,
|
||||
PD_AllowEnumElement = 1 << 7,
|
||||
PD_InProtocol = 1 << 8,
|
||||
PD_InClass = 1 << 9,
|
||||
PD_InExtension = 1 << 10,
|
||||
PD_InStruct = 1 << 11,
|
||||
PD_InEnum = 1 << 12,
|
||||
PD_InLoop = 1 << 13
|
||||
PD_AllowDestructor = 1 << 5,
|
||||
PD_AllowEnumElement = 1 << 6,
|
||||
PD_InProtocol = 1 << 7,
|
||||
PD_InClass = 1 << 8,
|
||||
PD_InExtension = 1 << 9,
|
||||
PD_InStruct = 1 << 10,
|
||||
PD_InEnum = 1 << 11,
|
||||
PD_InLoop = 1 << 12
|
||||
};
|
||||
|
||||
/// Options that control the parsing of declarations.
|
||||
@@ -701,10 +700,12 @@ public:
|
||||
ParserStatus parseDecl(SmallVectorImpl<Decl*> &Entries, ParseDeclOptions Flags);
|
||||
void parseDeclDelayed();
|
||||
|
||||
ParserResult<TypeDecl> parseDeclTypeAlias(bool WantDefinition,
|
||||
bool isAssociatedType,
|
||||
ParserResult<TypeDecl> parseDeclTypeAlias(ParseDeclOptions Flags,
|
||||
DeclAttributes &Attributes);
|
||||
|
||||
ParserResult<TypeDecl> parseDeclAssociatedType(ParseDeclOptions Flags,
|
||||
DeclAttributes &Attributes);
|
||||
|
||||
ParserResult<IfConfigDecl> parseDeclIfConfig(ParseDeclOptions Flags);
|
||||
/// Parse a #line/#setline directive.
|
||||
/// 'isLine = true' indicates parsing #line instead of #setline
|
||||
|
||||
@@ -101,6 +101,10 @@ public:
|
||||
asDerived().addAssociatedType(td, protos);
|
||||
}
|
||||
|
||||
void visitTypeAliasDecl(TypeAliasDecl *tad) {
|
||||
// We don't care about these by themselves for witnesses.
|
||||
}
|
||||
|
||||
void visitPatternBindingDecl(PatternBindingDecl *pbd) {
|
||||
// We only care about the contained VarDecls.
|
||||
}
|
||||
|
||||
@@ -1782,6 +1782,10 @@ struct ASTNodeBase {};
|
||||
continue;
|
||||
}
|
||||
|
||||
// No witness necessary for type aliases
|
||||
if (isa<TypeAliasDecl>(member))
|
||||
continue;
|
||||
|
||||
// If this is an accessor for something, ignore it.
|
||||
if (auto *FD = dyn_cast<FuncDecl>(member))
|
||||
if (FD->isAccessor())
|
||||
|
||||
@@ -219,7 +219,8 @@ void ArchetypeBuilder::PotentialArchetype::buildFullName(
|
||||
Identifier ArchetypeBuilder::PotentialArchetype::getName() const {
|
||||
if (auto assocType = NameOrAssociatedType.dyn_cast<AssociatedTypeDecl *>())
|
||||
return assocType->getName();
|
||||
|
||||
if (auto typeAlias = NameOrAssociatedType.dyn_cast<TypeAliasDecl *>())
|
||||
return typeAlias->getName();
|
||||
return NameOrAssociatedType.get<Identifier>();
|
||||
}
|
||||
|
||||
@@ -303,12 +304,12 @@ static void maybeAddSameTypeRequirementForNestedType(
|
||||
RequirementSource fromSource,
|
||||
ProtocolConformance *superConformance,
|
||||
ArchetypeBuilder &builder) {
|
||||
auto assocType = nestedPA->getResolvedAssociatedType();
|
||||
assert(assocType && "Not resolved to an associated type?");
|
||||
|
||||
// If there's no super conformance, we're done.
|
||||
if (!superConformance) return;
|
||||
|
||||
auto assocType = nestedPA->getResolvedAssociatedType();
|
||||
assert(assocType && "Not resolved to an associated type?");
|
||||
|
||||
// Dig out the type witness.
|
||||
auto concreteType =
|
||||
superConformance->getTypeWitness(assocType, builder.getLazyResolver())
|
||||
@@ -467,20 +468,73 @@ auto ArchetypeBuilder::PotentialArchetype::getNestedType(
|
||||
// archetype conforms.
|
||||
for (auto &conforms : ConformsTo) {
|
||||
for (auto member : conforms.first->lookupDirect(nestedName)) {
|
||||
auto assocType = dyn_cast<AssociatedTypeDecl>(member);
|
||||
if (!assocType)
|
||||
continue;
|
||||
PotentialArchetype *pa;
|
||||
|
||||
// Resolve this nested type to this associated type.
|
||||
auto pa = new PotentialArchetype(this, 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;
|
||||
|
||||
auto type = alias->getUnderlyingType();
|
||||
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
|
||||
// type, create same-type constraints between them.
|
||||
RequirementSource source(RequirementSource::Inferred, SourceLoc());
|
||||
if (!nested.empty()) {
|
||||
pa->Representative = nested.front()->getRepresentative();
|
||||
pa->Representative->EquivalenceClass.push_back(pa);
|
||||
pa->SameTypeSource = source;
|
||||
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->SameTypeSource = source;
|
||||
}
|
||||
}
|
||||
|
||||
// Add this resolved nested type.
|
||||
@@ -677,6 +731,9 @@ ArchetypeBuilder::PotentialArchetype::getType(ArchetypeBuilder &builder) {
|
||||
builder.getASTContext().registerLazyArchetype(arch, builder, this);
|
||||
SmallVector<std::pair<Identifier, NestedType>, 4> FlatNestedTypes;
|
||||
for (auto Nested : NestedTypes) {
|
||||
// Skip type aliases, which are just shortcuts.
|
||||
if (Nested.second.front()->getTypeAliasDecl())
|
||||
continue;
|
||||
bool anyNotRenamed = false;
|
||||
for (auto NestedPA : Nested.second) {
|
||||
if (!NestedPA->wasRenamed()) {
|
||||
@@ -1646,6 +1703,23 @@ bool ArchetypeBuilder::finalize(SourceLoc loc) {
|
||||
/* FIXME: Should be able to handle this earlier */pa->getSuperclass())
|
||||
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.
|
||||
Identifier correction = typoCorrectNestedType(pa);
|
||||
if (correction.empty()) {
|
||||
@@ -1702,7 +1776,7 @@ ArrayRef<ArchetypeType *> ArchetypeBuilder::getAllArchetypes() {
|
||||
continue;
|
||||
|
||||
PotentialArchetype *PA = Entry.second;
|
||||
if (!PA->isConcreteType()) {
|
||||
if (!PA->isConcreteType() && !PA->getTypeAliasDecl()) {
|
||||
auto Archetype = PA->getType(*this).castToArchetype();
|
||||
GenericParamList::addNestedArchetypes(Archetype, KnownArchetypes,
|
||||
Impl->AllArchetypes);
|
||||
@@ -2105,6 +2179,9 @@ addNestedRequirements(
|
||||
for (const auto &nested : pa->getNestedTypes()) {
|
||||
// FIXME: Dropping requirements among different associated types of the
|
||||
// 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()));
|
||||
}
|
||||
std::sort(nestedTypes.begin(), nestedTypes.end(),
|
||||
|
||||
@@ -1733,7 +1733,7 @@ Type TypeDecl::getDeclaredType() const {
|
||||
|
||||
Type TypeDecl::getDeclaredInterfaceType() const {
|
||||
Type interfaceType = getInterfaceType();
|
||||
if (interfaceType->is<ErrorType>())
|
||||
if (interfaceType.isNull() || interfaceType->is<ErrorType>())
|
||||
return interfaceType;
|
||||
|
||||
return interfaceType->castTo<MetatypeType>()->getInstanceType();
|
||||
|
||||
@@ -2086,10 +2086,11 @@ ParserStatus Parser::parseDecl(SmallVectorImpl<Decl*> &Entries,
|
||||
MayNeedOverrideCompletion = true;
|
||||
break;
|
||||
case tok::kw_typealias:
|
||||
DeclResult = parseDeclTypeAlias(Flags, Attributes);
|
||||
Status = DeclResult;
|
||||
break;
|
||||
case tok::kw_associatedtype:
|
||||
DeclResult = parseDeclTypeAlias(!(Flags & PD_DisallowTypeAliasDef),
|
||||
Flags.contains(PD_InProtocol),
|
||||
Attributes);
|
||||
DeclResult = parseDeclAssociatedType(Flags, Attributes);
|
||||
Status = DeclResult;
|
||||
break;
|
||||
case tok::kw_enum:
|
||||
@@ -2833,44 +2834,24 @@ ParserResult<IfConfigDecl> Parser::parseDeclIfConfig(ParseDeclOptions Flags) {
|
||||
///
|
||||
/// \verbatim
|
||||
/// decl-typealias:
|
||||
/// 'typealias' identifier inheritance? '=' type
|
||||
/// 'associatedtype' identifier inheritance? '=' type
|
||||
/// 'typealias' identifier generic-params? '=' type
|
||||
/// \endverbatim
|
||||
ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition,
|
||||
bool isAssociatedType,
|
||||
ParserResult<TypeDecl> Parser::parseDeclTypeAlias(Parser::ParseDeclOptions Flags,
|
||||
DeclAttributes &Attributes) {
|
||||
SourceLoc TypeAliasLoc;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
ParserPosition startPosition = getParserPosition();
|
||||
SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias);
|
||||
Identifier Id;
|
||||
SourceLoc IdLoc;
|
||||
ParserStatus Status;
|
||||
|
||||
Status |=
|
||||
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())
|
||||
return nullptr;
|
||||
|
||||
DebuggerContextChange DCC(*this, Id, DeclKind::TypeAlias);
|
||||
|
||||
|
||||
|
||||
Optional<Scope> GenericsScope;
|
||||
GenericsScope.emplace(this, ScopeKind::Generics);
|
||||
|
||||
@@ -2884,19 +2865,11 @@ ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition,
|
||||
|
||||
if (!genericParams) {
|
||||
// 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()) {
|
||||
// Reject a where clause.
|
||||
diagnose(genericParams->getWhereLoc(),
|
||||
diag::associated_type_generic_parameter_list)
|
||||
.highlight(genericParams->getWhereClauseSourceRange());
|
||||
.highlight(genericParams->getWhereClauseSourceRange());
|
||||
} else {
|
||||
// Reject inheritance clauses.
|
||||
for (auto *P : genericParams->getParams()) {
|
||||
@@ -2911,46 +2884,28 @@ ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition,
|
||||
}
|
||||
}
|
||||
|
||||
// Parse optional inheritance clause.
|
||||
// FIXME: Allow class requirements here.
|
||||
SmallVector<TypeLoc, 2> Inherited;
|
||||
if (isAssociatedType && Tok.is(tok::colon))
|
||||
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
|
||||
if (Flags.contains(PD_InProtocol) && !genericParams && !Tok.is(tok::equal)) {
|
||||
// If we're in a protocol and don't see an '=' this looks like leftover Swift 2
|
||||
// code intending to be an associatedtype.
|
||||
backtrackToPosition(startPosition);
|
||||
return parseDeclAssociatedType(Flags, Attributes);
|
||||
}
|
||||
|
||||
ParserResult<TypeRepr> UnderlyingTy;
|
||||
if (WantDefinition || Tok.is(tok::equal)) {
|
||||
if (Tok.is(tok::colon)) {
|
||||
// It is a common mistake to write "typealias A : Int" instead of = Int.
|
||||
// Recognize this and produce a fixit.
|
||||
diagnose(Tok, diag::expected_equal_in_typealias)
|
||||
if (Tok.is(tok::colon)) {
|
||||
// It is a common mistake to write "typealias A : Int" instead of = Int.
|
||||
// Recognize this and produce a fixit.
|
||||
diagnose(Tok, diag::expected_equal_in_typealias)
|
||||
.fixItReplace(Tok.getLoc(), "=");
|
||||
consumeToken(tok::colon);
|
||||
|
||||
} else if (parseToken(tok::equal, diag::expected_equal_in_typealias)) {
|
||||
Status.setIsParseError();
|
||||
return Status;
|
||||
}
|
||||
UnderlyingTy = parseType(diag::expected_type_in_typealias);
|
||||
Status |= UnderlyingTy;
|
||||
if (UnderlyingTy.isNull())
|
||||
return Status;
|
||||
consumeToken(tok::colon);
|
||||
} else if (parseToken(tok::equal, diag::expected_equal_in_typealias)) {
|
||||
Status.setIsParseError();
|
||||
return Status;
|
||||
}
|
||||
ParserResult<TypeRepr> UnderlyingTy = parseType(diag::expected_type_in_typealias);
|
||||
Status |= UnderlyingTy;
|
||||
if (UnderlyingTy.isNull())
|
||||
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,
|
||||
UnderlyingTy.getPtrOrNull(),
|
||||
genericParams, CurDeclContext);
|
||||
@@ -2963,6 +2918,79 @@ ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition,
|
||||
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
|
||||
/// property or subscript.
|
||||
static FuncDecl *createAccessorFunc(SourceLoc DeclLoc, ParameterList *param,
|
||||
@@ -5068,7 +5096,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
|
||||
// Parse the members.
|
||||
ParseDeclOptions Options(PD_HasContainerType |
|
||||
PD_DisallowNominalTypes |
|
||||
PD_DisallowInit | PD_DisallowTypeAliasDef |
|
||||
PD_DisallowInit |
|
||||
PD_InProtocol);
|
||||
if (parseNominalDeclMembers(Members, LBraceLoc, RBraceLoc,
|
||||
diag::expected_rbrace_protocol,
|
||||
|
||||
@@ -174,6 +174,16 @@ Type CompleteGenericTypeResolver::resolveDependentMemberType(
|
||||
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();
|
||||
SourceLoc nameLoc = ref->getIdLoc();
|
||||
|
||||
|
||||
@@ -3711,6 +3711,10 @@ void ConformanceChecker::checkConformance() {
|
||||
if (isa<AssociatedTypeDecl>(requirement))
|
||||
continue;
|
||||
|
||||
// Type aliases don't have requirements themselves.
|
||||
if (isa<TypeAliasDecl>(requirement))
|
||||
continue;
|
||||
|
||||
// If we've already determined this witness, skip it.
|
||||
if (Conformance->hasWitness(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
|
||||
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}}
|
||||
|
||||
@@ -648,7 +648,7 @@ func resyncParser1() {}
|
||||
//===---
|
||||
|
||||
protocol AssocType1 {
|
||||
typealias AssocType = #^TYPE_IN_ASSOC_TYPE_1^#
|
||||
associatedtype AssocType = #^TYPE_IN_ASSOC_TYPE_1^#
|
||||
}
|
||||
|
||||
//===---
|
||||
@@ -656,7 +656,7 @@ 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 {
|
||||
associatedtype Destination : Collection
|
||||
|
||||
// FIXME: should really be a typealias once that is supported
|
||||
associatedtype Element = Destination.Iterator.Element
|
||||
typealias Element = Destination.Iterator.Element
|
||||
|
||||
init()
|
||||
|
||||
|
||||
@@ -469,9 +469,9 @@ func h<T : C3>(x : T) {
|
||||
|
||||
|
||||
protocol P4 {
|
||||
associatedtype T
|
||||
associatedtype T // expected-note {{protocol requires nested type 'T'}}
|
||||
}
|
||||
|
||||
class C4 : P4 {
|
||||
associatedtype T = Int // expected-error {{associated types can only be defined in a protocol}} {{3-17=typealias}}
|
||||
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; 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 {
|
||||
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-warning {{use of 'typealias' to declare associated types is deprecated; use 'associatedtype' instead}}
|
||||
typealias Y<T> // expected-error {{expected '=' in typealias declaration}}
|
||||
}
|
||||
|
||||
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<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