diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index f95ffb6e407..df5ea625221 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2154,6 +2154,17 @@ ERROR(lazy_not_observable,none, ERROR(attr_for_debugger_support_only,none, "@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 //------------------------------------------------------------------------------ diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 308adc3af32..77acfff9083 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -756,7 +756,6 @@ public: IGNORED_ATTR(WarnUnqualifiedAccess) IGNORED_ATTR(ShowInInterface) IGNORED_ATTR(ObjCMembers) - IGNORED_ATTR(Implements) #undef IGNORED_ATTR void visitAvailableAttr(AvailableAttr *attr); @@ -797,6 +796,7 @@ public: void visitInlineableAttr(InlineableAttr *attr); void visitDiscardableResultAttr(DiscardableResultAttr *attr); + void visitImplementsAttr(ImplementsAttr *attr); }; } // 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()) { + 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 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) { AttributeChecker Checker(*this, D);