Fix @_implements type resolution diagnostics

If a type in an `@_implements` attribute failed to resolve, Sema would assume it was because the type existed but wasn’t a protocol, even if there was another reason for the problem (such as the type not existing). Explicitly resolve the TypeRepr again through a path that will produce diagnostics.
This commit is contained in:
Becca Royal-Gordon
2025-05-09 14:39:34 -07:00
parent df32362c09
commit 7e7f9d024b
2 changed files with 23 additions and 2 deletions

View File

@@ -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;
}

View File

@@ -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() {
}
}