mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Implement default definitions for associated types.
Addresses <rdar://problem/14292873>. Swift SVN r11422
This commit is contained in:
@@ -1301,7 +1301,7 @@ an lvalue unless it has a <code>var-get</code> clause but not
|
|||||||
<h4 id="protocol-member-typealias">'typealias' protocol elements (associated types)</h4>
|
<h4 id="protocol-member-typealias">'typealias' protocol elements (associated types)</h4>
|
||||||
|
|
||||||
<pre class="grammar">
|
<pre class="grammar">
|
||||||
protocol-member ::= <a href="#typealias-head">typealias-head</a>
|
protocol-member ::= <a href="#typealias-head">typealias-head</a> ('=' <a href="#type">type</a>)?
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>'typealias' members of a protocol define associated types, which
|
<p>'typealias' members of a protocol define associated types, which
|
||||||
@@ -1310,14 +1310,17 @@ an lvalue unless it has a <code>var-get</code> clause but not
|
|||||||
conforming type to another. When an associated type has an <a
|
conforming type to another. When an associated type has an <a
|
||||||
href="#inheritance">inheritance</a> clause, any type meant to
|
href="#inheritance">inheritance</a> clause, any type meant to
|
||||||
satisfy the associated type requirement must conform to each of the
|
satisfy the associated type requirement must conform to each of the
|
||||||
protocols specified within that inheritance clause.</p>
|
protocols specified within that inheritance clause. If a type is
|
||||||
|
provided after the '=', it is a default definition for the
|
||||||
|
associated type that will be used as the type witness if the type
|
||||||
|
witness cannot be determined in any other way.</p>
|
||||||
|
|
||||||
<pre class="example">
|
<pre class="example">
|
||||||
protocol Enumerable {
|
protocol Enumerable {
|
||||||
typename EnumeratorType : Enumerator
|
typename EnumeratorType : Enumerator
|
||||||
func getElements() -> EnumeratorType
|
func getElements() -> EnumeratorType
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<!-- ===================================================================== -->
|
<!-- ===================================================================== -->
|
||||||
<h3 id="decl-subscript">subscript Declarations</h3>
|
<h3 id="decl-subscript">subscript Declarations</h3>
|
||||||
|
|||||||
@@ -1508,15 +1508,23 @@ class AssociatedTypeDecl : public AbstractTypeParamDecl {
|
|||||||
/// The location of the initial keyword.
|
/// The location of the initial keyword.
|
||||||
SourceLoc KeywordLoc;
|
SourceLoc KeywordLoc;
|
||||||
|
|
||||||
|
/// The default definition.
|
||||||
|
TypeLoc DefaultDefinition;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc, Identifier name,
|
AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc, Identifier name,
|
||||||
SourceLoc nameLoc);
|
SourceLoc nameLoc, TypeLoc defaultDefinition);
|
||||||
|
|
||||||
/// Get the protocol in which this associated type is declared.
|
/// Get the protocol in which this associated type is declared.
|
||||||
ProtocolDecl *getProtocol() const {
|
ProtocolDecl *getProtocol() const {
|
||||||
return cast<ProtocolDecl>(getDeclContext());
|
return cast<ProtocolDecl>(getDeclContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve the default definition type.
|
||||||
|
Type getDefaultDefinitionType() const { return DefaultDefinition.getType(); }
|
||||||
|
|
||||||
|
TypeLoc &getDefaultDefinitionLoc() { return DefaultDefinition; }
|
||||||
|
|
||||||
SourceLoc getStartLoc() const { return KeywordLoc; }
|
SourceLoc getStartLoc() const { return KeywordLoc; }
|
||||||
SourceRange getSourceRange() const;
|
SourceRange getSourceRange() const;
|
||||||
|
|
||||||
|
|||||||
@@ -225,8 +225,6 @@ ERROR(expected_equal_in_typealias,decl_parsing,PointsToFirstBadToken,
|
|||||||
"expected '=' in typealias declaration", ())
|
"expected '=' in typealias declaration", ())
|
||||||
ERROR(expected_type_in_typealias,decl_parsing,PointsToFirstBadToken,
|
ERROR(expected_type_in_typealias,decl_parsing,PointsToFirstBadToken,
|
||||||
"expected type in typealias declaration", ())
|
"expected type in typealias declaration", ())
|
||||||
ERROR(associated_type_def,decl_parsing,none,
|
|
||||||
"typealias %0 in protocol cannot have a definition", (Identifier))
|
|
||||||
|
|
||||||
// Func
|
// Func
|
||||||
ERROR(func_decl_nonglobal_operator,decl_parsing,none,
|
ERROR(func_decl_nonglobal_operator,decl_parsing,none,
|
||||||
@@ -1139,6 +1137,9 @@ NOTE(ambiguous_witnesses,sema_tcd,none,
|
|||||||
"with type %2", (int, Identifier, Type))
|
"with type %2", (int, Identifier, Type))
|
||||||
NOTE(no_witnesses_type,sema_tcd,none,
|
NOTE(no_witnesses_type,sema_tcd,none,
|
||||||
"protocol requires nested type %0", (Identifier))
|
"protocol requires nested type %0", (Identifier))
|
||||||
|
NOTE(default_assocated_type_req_fail,sema_tcd,none,
|
||||||
|
"default associated type definition %0 does not conform to %1",
|
||||||
|
(Type, Type))
|
||||||
NOTE(ambiguous_witnesses_type,sema_tcd,none,
|
NOTE(ambiguous_witnesses_type,sema_tcd,none,
|
||||||
"multiple matching types named %0", (Identifier))
|
"multiple matching types named %0", (Identifier))
|
||||||
NOTE(protocol_witness_exact_match,sema_tcd,none,
|
NOTE(protocol_witness_exact_match,sema_tcd,none,
|
||||||
|
|||||||
@@ -334,6 +334,10 @@ namespace {
|
|||||||
|
|
||||||
void visitAssociatedTypeDecl(AssociatedTypeDecl *decl) {
|
void visitAssociatedTypeDecl(AssociatedTypeDecl *decl) {
|
||||||
printCommon(decl, "associated_type_decl");
|
printCommon(decl, "associated_type_decl");
|
||||||
|
if (auto defaultDef = decl->getDefaultDefinitionType()) {
|
||||||
|
OS << " default=";
|
||||||
|
defaultDef.print(OS);
|
||||||
|
}
|
||||||
OS << ")";
|
OS << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -568,6 +568,11 @@ void PrintAST::visitAssociatedTypeDecl(AssociatedTypeDecl *decl) {
|
|||||||
recordDeclLoc(decl);
|
recordDeclLoc(decl);
|
||||||
Printer << decl->getName().str();
|
Printer << decl->getName().str();
|
||||||
printInheritedWithSuperclass(decl);
|
printInheritedWithSuperclass(decl);
|
||||||
|
|
||||||
|
if (!decl->getDefaultDefinitionLoc().isNull()) {
|
||||||
|
Printer << " = ";
|
||||||
|
decl->getDefaultDefinitionLoc().getType().print(Printer, Options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintAST::visitEnumDecl(EnumDecl *decl) {
|
void PrintAST::visitEnumDecl(EnumDecl *decl) {
|
||||||
|
|||||||
@@ -722,9 +722,10 @@ SourceRange GenericTypeParamDecl::getSourceRange() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
|
AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
|
||||||
Identifier name, SourceLoc nameLoc)
|
Identifier name, SourceLoc nameLoc,
|
||||||
|
TypeLoc defaultDefinition)
|
||||||
: AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
|
: AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
|
||||||
KeywordLoc(keywordLoc)
|
KeywordLoc(keywordLoc), DefaultDefinition(defaultDefinition)
|
||||||
{
|
{
|
||||||
auto &ctx = dc->getASTContext();
|
auto &ctx = dc->getASTContext();
|
||||||
auto type = new (ctx, AllocationArena::Permanent) AssociatedTypeType(this);
|
auto type = new (ctx, AllocationArena::Permanent) AssociatedTypeType(this);
|
||||||
|
|||||||
@@ -986,17 +986,14 @@ ParserResult<TypeDecl> Parser::parseDeclTypeAlias(bool WantDefinition,
|
|||||||
Status |= UnderlyingTy;
|
Status |= UnderlyingTy;
|
||||||
if (UnderlyingTy.isNull())
|
if (UnderlyingTy.isNull())
|
||||||
return Status;
|
return Status;
|
||||||
|
|
||||||
if (!WantDefinition) {
|
|
||||||
diagnose(IdLoc, diag::associated_type_def, Id);
|
|
||||||
UnderlyingTy = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is an associated type, build the AST for it.
|
// If this is an associated type, build the AST for it.
|
||||||
if (isAssociatedType) {
|
if (isAssociatedType) {
|
||||||
auto assocType = new (Context) AssociatedTypeDecl(CurDeclContext,
|
auto assocType = new (Context) AssociatedTypeDecl(
|
||||||
TypeAliasLoc, Id, IdLoc);
|
CurDeclContext,
|
||||||
|
TypeAliasLoc, Id, IdLoc,
|
||||||
|
UnderlyingTy.getPtrOrNull());
|
||||||
if (!Inherited.empty())
|
if (!Inherited.empty())
|
||||||
assocType->setInherited(Context.AllocateCopy(Inherited));
|
assocType->setInherited(Context.AllocateCopy(Inherited));
|
||||||
addToScope(assocType);
|
addToScope(assocType);
|
||||||
|
|||||||
@@ -1235,6 +1235,16 @@ public:
|
|||||||
checkExplicitConformance(TAD, TAD->getDeclaredType());
|
checkExplicitConformance(TAD, TAD->getDeclaredType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visitAssociatedTypeDecl(AssociatedTypeDecl *assocType) {
|
||||||
|
// Check the default definition, if there is one.
|
||||||
|
TypeLoc &defaultDefinition = assocType->getDefaultDefinitionLoc();
|
||||||
|
if (!defaultDefinition.isNull() &&
|
||||||
|
TC.validateType(defaultDefinition, assocType->getDeclContext(),
|
||||||
|
/*allowUnboundGenerics=*/false)) {
|
||||||
|
defaultDefinition.setInvalidType(TC.Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Given the raw value literal expression for an enum case, produces the
|
// Given the raw value literal expression for an enum case, produces the
|
||||||
// auto-incremented raw value for the subsequent case, or returns null if
|
// auto-incremented raw value for the subsequent case, or returns null if
|
||||||
// the value is not auto-incrementable.
|
// the value is not auto-incrementable.
|
||||||
@@ -2186,8 +2196,13 @@ void TypeChecker::validateDecl(ValueDecl *D, bool resolveTypeParams) {
|
|||||||
case DeclKind::GenericTypeParam:
|
case DeclKind::GenericTypeParam:
|
||||||
case DeclKind::AssociatedType: {
|
case DeclKind::AssociatedType: {
|
||||||
auto typeParam = cast<AbstractTypeParamDecl>(D);
|
auto typeParam = cast<AbstractTypeParamDecl>(D);
|
||||||
if (!resolveTypeParams || typeParam->getArchetype())
|
if (!resolveTypeParams || typeParam->getArchetype()) {
|
||||||
|
if (auto assocType = dyn_cast<AssociatedTypeDecl>(typeParam)) {
|
||||||
|
DeclChecker(*this, false, false).visitAssociatedTypeDecl(assocType);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Avoid full check in these cases?
|
// FIXME: Avoid full check in these cases?
|
||||||
DeclContext *DC = typeParam->getDeclContext();
|
DeclContext *DC = typeParam->getDeclContext();
|
||||||
|
|||||||
@@ -124,8 +124,6 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME: Generic substitutions here.
|
|
||||||
|
|
||||||
/// \brief Associated types determined by matching this requirement.
|
/// \brief Associated types determined by matching this requirement.
|
||||||
SmallVector<std::pair<AssociatedTypeDecl *, Type>, 2>
|
SmallVector<std::pair<AssociatedTypeDecl *, Type>, 2>
|
||||||
AssociatedTypeDeductions;
|
AssociatedTypeDeductions;
|
||||||
@@ -751,7 +749,53 @@ static ResolveWitnessResult resolveTypeWitnessViaLookup(
|
|||||||
return ResolveWitnessResult::ExplicitFailed;
|
return ResolveWitnessResult::ExplicitFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to resolve a type witness via member name lookup.
|
/// Attempt to resolve a type witness via a default definition.
|
||||||
|
static ResolveWitnessResult resolveTypeWitnessViaDefault(
|
||||||
|
TypeChecker &tc,
|
||||||
|
ProtocolDecl *proto,
|
||||||
|
Type type,
|
||||||
|
DeclContext *dc,
|
||||||
|
SourceLoc loc,
|
||||||
|
AssociatedTypeDecl *assocType,
|
||||||
|
TypeWitnessMap &typeWitnesses,
|
||||||
|
bool alreadyComplained) {
|
||||||
|
// If we don't have a default definition, we're done.
|
||||||
|
if (assocType->getDefaultDefinitionLoc().isNull())
|
||||||
|
return ResolveWitnessResult::Missing;
|
||||||
|
|
||||||
|
// Create a set of type substitutions for all known associated type.
|
||||||
|
// FIXME: Base this on dependent types rather than archetypes?
|
||||||
|
TypeSubstitutionMap substitutions;
|
||||||
|
substitutions[proto->getSelf()->getArchetype()] = type;
|
||||||
|
for (const auto &witness: typeWitnesses) {
|
||||||
|
substitutions[witness.second.Archetype] = witness.second.Replacement;
|
||||||
|
}
|
||||||
|
auto defaultType = tc.substType(dc->getParentModule(),
|
||||||
|
assocType->getDefaultDefinitionLoc().getType(),
|
||||||
|
substitutions,
|
||||||
|
/*IgnoreMissing=*/true);
|
||||||
|
if (!defaultType)
|
||||||
|
return ResolveWitnessResult::Missing;
|
||||||
|
|
||||||
|
if (auto checkResult = checkTypeWitness(tc, dc, assocType, defaultType)) {
|
||||||
|
if (!alreadyComplained)
|
||||||
|
tc.diagnose(loc, diag::type_does_not_conform, type,
|
||||||
|
proto->getDeclaredType());
|
||||||
|
|
||||||
|
tc.diagnose(assocType, diag::default_assocated_type_req_fail,
|
||||||
|
defaultType, checkResult.getProtocol()->getDeclaredType());
|
||||||
|
|
||||||
|
return ResolveWitnessResult::ExplicitFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in the type witness and declare success.
|
||||||
|
auto archetype = assocType->getArchetype();
|
||||||
|
typeWitnesses[assocType] = getArchetypeSubstitution(tc, dc, archetype,
|
||||||
|
defaultType);
|
||||||
|
return ResolveWitnessResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempt to resolve a type witness via derivation.
|
||||||
static ResolveWitnessResult resolveTypeWitnessViaDerivation(
|
static ResolveWitnessResult resolveTypeWitnessViaDerivation(
|
||||||
TypeChecker &tc,
|
TypeChecker &tc,
|
||||||
ProtocolDecl *proto,
|
ProtocolDecl *proto,
|
||||||
@@ -1101,12 +1145,16 @@ checkConformsToProtocol(TypeChecker &TC, Type T, ProtocolDecl *Proto,
|
|||||||
if (Complained || invalid)
|
if (Complained || invalid)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// If any associated types were left unresolved, try to derive them.
|
// If any associated types were left unresolved, try default types
|
||||||
|
// or compiler-supported derivation.
|
||||||
auto resolveAssocType = [&](AssociatedTypeDecl *assocType) -> bool {
|
auto resolveAssocType = [&](AssociatedTypeDecl *assocType) -> bool {
|
||||||
switch (resolveTypeWitnessViaDerivation(TC, Proto, T, DC, ComplainLoc,
|
// Default implementations.
|
||||||
assocType, TypeWitnesses,
|
switch (resolveTypeWitnessViaDefault(TC, Proto, T, DC, ComplainLoc,
|
||||||
Complained)) {
|
assocType, TypeWitnesses,
|
||||||
|
Complained)) {
|
||||||
case ResolveWitnessResult::Success:
|
case ResolveWitnessResult::Success:
|
||||||
|
deducedAssocTypes.push_back(
|
||||||
|
{assocType, TypeWitnesses[assocType].Replacement});
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ResolveWitnessResult::ExplicitFailed:
|
case ResolveWitnessResult::ExplicitFailed:
|
||||||
@@ -1117,7 +1165,23 @@ checkConformsToProtocol(TypeChecker &TC, Type T, ProtocolDecl *Proto,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Default implementation
|
switch (resolveTypeWitnessViaDerivation(TC, Proto, T, DC, ComplainLoc,
|
||||||
|
assocType, TypeWitnesses,
|
||||||
|
Complained)) {
|
||||||
|
case ResolveWitnessResult::Success:
|
||||||
|
deducedAssocTypes.push_back(
|
||||||
|
{assocType, TypeWitnesses[assocType].Replacement});
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case ResolveWitnessResult::ExplicitFailed:
|
||||||
|
Complained = true;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case ResolveWitnessResult::Missing:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No other options.
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
unresolvedAssocTypes.erase(std::remove_if(unresolvedAssocTypes.begin(),
|
unresolvedAssocTypes.erase(std::remove_if(unresolvedAssocTypes.begin(),
|
||||||
@@ -1131,6 +1195,11 @@ checkConformsToProtocol(TypeChecker &TC, Type T, ProtocolDecl *Proto,
|
|||||||
|
|
||||||
// Diagnose all missing associated types.
|
// Diagnose all missing associated types.
|
||||||
for (auto assocType : unresolvedAssocTypes) {
|
for (auto assocType : unresolvedAssocTypes) {
|
||||||
|
// If we had a default that didn't work out, we already
|
||||||
|
// complained about it.
|
||||||
|
if (!assocType->getDefaultDefinitionLoc().isNull())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!Complained) {
|
if (!Complained) {
|
||||||
TC.diagnose(ComplainLoc, diag::type_does_not_conform,
|
TC.diagnose(ComplainLoc, diag::type_does_not_conform,
|
||||||
T, Proto->getDeclaredType());
|
T, Proto->getDeclaredType());
|
||||||
|
|||||||
@@ -1274,12 +1274,14 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
|||||||
DeclID contextID;
|
DeclID contextID;
|
||||||
TypeID superclassID;
|
TypeID superclassID;
|
||||||
TypeID archetypeID;
|
TypeID archetypeID;
|
||||||
|
TypeID defaultDefinitionID;
|
||||||
bool isImplicit;
|
bool isImplicit;
|
||||||
|
|
||||||
decls_block::AssociatedTypeDeclLayout::readRecord(scratch, nameID,
|
decls_block::AssociatedTypeDeclLayout::readRecord(scratch, nameID,
|
||||||
contextID,
|
contextID,
|
||||||
superclassID,
|
superclassID,
|
||||||
archetypeID,
|
archetypeID,
|
||||||
|
defaultDefinitionID,
|
||||||
isImplicit);
|
isImplicit);
|
||||||
|
|
||||||
auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID);
|
auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID);
|
||||||
@@ -1287,9 +1289,12 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
|||||||
if (declOrOffset.isComplete())
|
if (declOrOffset.isComplete())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
TypeLoc defaultDefinitionType =
|
||||||
|
TypeLoc::withoutLoc(getType(defaultDefinitionID));
|
||||||
auto assocType = new (ctx) AssociatedTypeDecl(DC, SourceLoc(),
|
auto assocType = new (ctx) AssociatedTypeDecl(DC, SourceLoc(),
|
||||||
getIdentifier(nameID),
|
getIdentifier(nameID),
|
||||||
SourceLoc());
|
SourceLoc(),
|
||||||
|
defaultDefinitionType);
|
||||||
declOrOffset = assocType;
|
declOrOffset = assocType;
|
||||||
|
|
||||||
assocType->setSuperclass(getType(superclassID));
|
assocType->setSuperclass(getType(superclassID));
|
||||||
|
|||||||
@@ -503,6 +503,7 @@ namespace decls_block {
|
|||||||
DeclIDField, // context decl
|
DeclIDField, // context decl
|
||||||
TypeIDField, // underlying type
|
TypeIDField, // underlying type
|
||||||
TypeIDField, // archetype type
|
TypeIDField, // archetype type
|
||||||
|
TypeIDField, // default definition
|
||||||
BCFixed<1> // implicit flag
|
BCFixed<1> // implicit flag
|
||||||
// Trailed by the conformance info (if any).
|
// Trailed by the conformance info (if any).
|
||||||
>;
|
>;
|
||||||
|
|||||||
@@ -1130,12 +1130,14 @@ void Serializer::writeDecl(const Decl *D) {
|
|||||||
const Decl *DC = getDeclForContext(assocType->getDeclContext());
|
const Decl *DC = getDeclForContext(assocType->getDeclContext());
|
||||||
|
|
||||||
unsigned abbrCode = DeclTypeAbbrCodes[AssociatedTypeDeclLayout::Code];
|
unsigned abbrCode = DeclTypeAbbrCodes[AssociatedTypeDeclLayout::Code];
|
||||||
AssociatedTypeDeclLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
AssociatedTypeDeclLayout::emitRecord(
|
||||||
addIdentifierRef(assocType->getName()),
|
Out, ScratchRecord, abbrCode,
|
||||||
addDeclRef(DC),
|
addIdentifierRef(assocType->getName()),
|
||||||
addTypeRef(assocType->getSuperclass()),
|
addDeclRef(DC),
|
||||||
addTypeRef(assocType->getArchetype()),
|
addTypeRef(assocType->getSuperclass()),
|
||||||
assocType->isImplicit());
|
addTypeRef(assocType->getArchetype()),
|
||||||
|
addTypeRef(assocType->getDefaultDefinitionType()),
|
||||||
|
assocType->isImplicit());
|
||||||
|
|
||||||
writeConformances(assocType->getProtocols(),
|
writeConformances(assocType->getProtocols(),
|
||||||
assocType->getConformances(),
|
assocType->getConformances(),
|
||||||
|
|||||||
30
test/decl/protocol/req/associated_type_default.swift
Normal file
30
test/decl/protocol/req/associated_type_default.swift
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// RUN: %swift -parse %s -verify
|
||||||
|
|
||||||
|
struct X { }
|
||||||
|
|
||||||
|
// Simple default definition for associated types.
|
||||||
|
protocol P1 {
|
||||||
|
typealias AssocType1 = Int
|
||||||
|
}
|
||||||
|
|
||||||
|
extension X : P1 { }
|
||||||
|
|
||||||
|
var i: X.AssocType1 = 17
|
||||||
|
|
||||||
|
// Dependent default definition for associated types
|
||||||
|
protocol P2 {
|
||||||
|
typealias AssocType2 = Self
|
||||||
|
}
|
||||||
|
|
||||||
|
extension X : P2 { }
|
||||||
|
var xAssoc2: X.AssocType2 = X()
|
||||||
|
|
||||||
|
// Dependent default definition for associated types that doesn't meet
|
||||||
|
// requirements.
|
||||||
|
protocol P3 {
|
||||||
|
typealias AssocType3 : P1 = Self // expected-note{{default associated type definition 'X2' does not conform to 'P1'}}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension X : P3 { } // okay
|
||||||
|
|
||||||
|
struct X2 : P3 { } // expected-error{{type 'X2' does not conform to protocol 'P3'}}
|
||||||
Reference in New Issue
Block a user