diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index cee993d42311c..7425d88b7ff5f 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -4281,8 +4281,25 @@ void AttributeChecker::visitImplementsAttr(ImplementsAttr *attr) { ProtocolDecl *PD = attr->getProtocol(DC); if (!PD) { - diagnose(attr->getLocation(), diag::implements_attr_non_protocol_type) - .highlight(attr->getProtocolTypeRepr()->getSourceRange()); + // `ImplementsAttr::getProtocol()` returns `nullptr` both when a type fails + // to resolve, and when it resolves to something other than a protocol. + // Due to layering concerns, it doesn't resolve in a way that emits + // diagnostics. + // + // Distinguish between these situations by trying to resolve the type again. + // If it doesn't resolve, TypeResolution will have diagnosed the problem; if + // it does, it must have resolved to a non-protocol, so emit a diagnostic to + // that effect. + TypeResolutionOptions options(TypeResolverContext::None); + auto resolvedType = TypeResolution::resolveContextualType( + attr->getProtocolTypeRepr(), DC, options, + // Unbound generics and placeholders are not allowed within this attr. + /*unboundTyOpener*/ nullptr, /*placeholderHandler*/ nullptr, + /*packElementOpener*/ nullptr); + + if (resolvedType && !resolvedType->hasError()) + diagnose(attr->getLocation(), diag::implements_attr_non_protocol_type) + .highlight(attr->getProtocolTypeRepr()->getSourceRange()); return; } diff --git a/test/attr/attr_implements_bad_types.swift b/test/attr/attr_implements_bad_types.swift index ea010f343c2d4..8bcc341280a83 100644 --- a/test/attr/attr_implements_bad_types.swift +++ b/test/attr/attr_implements_bad_types.swift @@ -21,5 +21,9 @@ struct S0 : NeedsF0 { // expected-error {{type 'S0' does not conform to protoco @_implements(Equatable, ==(_:_:)) // expected-error {{containing type 'S0' does not conform to protocol 'Equatable'}} static func gg2(x:S0, y:S0) -> Bool { } + + @_implements(NonexistentType, ff3()) // expected-error {{cannot find type 'NonexistentType' in scope}} + func gg3() { + } }