Typecheck contents of @_implements attribute.

This commit is contained in:
Graydon Hoare
2017-04-14 16:31:47 -07:00
parent 3d5c995615
commit db515885f8
2 changed files with 58 additions and 1 deletions

View File

@@ -2154,6 +2154,17 @@ ERROR(lazy_not_observable,none,
ERROR(attr_for_debugger_support_only,none, ERROR(attr_for_debugger_support_only,none,
"@LLDBDebuggerSupport may only be used when debugger support is on", ()) "@LLDBDebuggerSupport may only be used when debugger support is on", ())
// @_implements
ERROR(implements_attr_protocol_lacks_member,none,
"protocol %0 has no member %1", (DeclName, DeclName))
ERROR(implements_attr_non_protocol_type,none,
"non-protocol type in @_implements attribute", ())
ERROR(implements_attr_protocol_not_conformed_to,none,
"containing type %0 does not conform to protocol %1",
(DeclName, DeclName))
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Type Check Expressions // Type Check Expressions
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -756,7 +756,6 @@ public:
IGNORED_ATTR(WarnUnqualifiedAccess) IGNORED_ATTR(WarnUnqualifiedAccess)
IGNORED_ATTR(ShowInInterface) IGNORED_ATTR(ShowInInterface)
IGNORED_ATTR(ObjCMembers) IGNORED_ATTR(ObjCMembers)
IGNORED_ATTR(Implements)
#undef IGNORED_ATTR #undef IGNORED_ATTR
void visitAvailableAttr(AvailableAttr *attr); void visitAvailableAttr(AvailableAttr *attr);
@@ -797,6 +796,7 @@ public:
void visitInlineableAttr(InlineableAttr *attr); void visitInlineableAttr(InlineableAttr *attr);
void visitDiscardableResultAttr(DiscardableResultAttr *attr); void visitDiscardableResultAttr(DiscardableResultAttr *attr);
void visitImplementsAttr(ImplementsAttr *attr);
}; };
} // end anonymous namespace } // end anonymous namespace
@@ -1884,6 +1884,52 @@ void AttributeChecker::visitDiscardableResultAttr(DiscardableResultAttr *attr) {
} }
} }
void AttributeChecker::visitImplementsAttr(ImplementsAttr *attr) {
TypeLoc &ProtoTypeLoc = attr->getProtocolType();
TypeResolutionOptions options;
options |= TR_AllowUnboundGenerics;
DeclContext *DC = D->getDeclContext();
Type T = TC.resolveType(ProtoTypeLoc.getTypeRepr(),
DC, options);
ProtoTypeLoc.setType(T);
// Definite error-types were already diagnosed in resolveType.
if (!T || T->hasError())
return;
// Check that we got a ProtocolType.
if (auto PT = T->getAs<ProtocolType>()) {
ProtocolDecl *PD = PT->getDecl();
// Check that the ProtocolType has the specified member.
LookupResult R = TC.lookupMember(PD->getDeclContext(),
PT, attr->getMemberName());
if (!R) {
TC.diagnose(attr->getLocation(),
diag::implements_attr_protocol_lacks_member,
PD->getBaseName(), attr->getMemberName())
.highlight(attr->getMemberNameLoc().getSourceRange());
}
// Check that the decl we're decorating is a member of a type that actually
// conforms to the specified protocol.
NominalTypeDecl *NTD = DC->getAsNominalTypeOrNominalTypeExtensionContext();
SmallVector<ProtocolConformance *, 2> conformances;
if (!NTD->lookupConformance(DC->getParentModule(), PD, conformances)) {
TC.diagnose(attr->getLocation(),
diag::implements_attr_protocol_not_conformed_to,
NTD->getFullName(), PD->getFullName())
.highlight(ProtoTypeLoc.getTypeRepr()->getSourceRange());
}
} else {
TC.diagnose(attr->getLocation(),
diag::implements_attr_non_protocol_type)
.highlight(ProtoTypeLoc.getTypeRepr()->getSourceRange());
}
}
void TypeChecker::checkDeclAttributes(Decl *D) { void TypeChecker::checkDeclAttributes(Decl *D) {
AttributeChecker Checker(*this, D); AttributeChecker Checker(*this, D);