Skip to content

Commit db51588

Browse files
committed
Typecheck contents of @_implements attribute.
1 parent 3d5c995 commit db51588

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,6 +2154,17 @@ ERROR(lazy_not_observable,none,
21542154
ERROR(attr_for_debugger_support_only,none,
21552155
"@LLDBDebuggerSupport may only be used when debugger support is on", ())
21562156

2157+
// @_implements
2158+
ERROR(implements_attr_protocol_lacks_member,none,
2159+
"protocol %0 has no member %1", (DeclName, DeclName))
2160+
2161+
ERROR(implements_attr_non_protocol_type,none,
2162+
"non-protocol type in @_implements attribute", ())
2163+
2164+
ERROR(implements_attr_protocol_not_conformed_to,none,
2165+
"containing type %0 does not conform to protocol %1",
2166+
(DeclName, DeclName))
2167+
21572168
//------------------------------------------------------------------------------
21582169
// Type Check Expressions
21592170
//------------------------------------------------------------------------------

lib/Sema/TypeCheckAttr.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,6 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
756756
IGNORED_ATTR(WarnUnqualifiedAccess)
757757
IGNORED_ATTR(ShowInInterface)
758758
IGNORED_ATTR(ObjCMembers)
759-
IGNORED_ATTR(Implements)
760759
#undef IGNORED_ATTR
761760

762761
void visitAvailableAttr(AvailableAttr *attr);
@@ -797,6 +796,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
797796
void visitInlineableAttr(InlineableAttr *attr);
798797

799798
void visitDiscardableResultAttr(DiscardableResultAttr *attr);
799+
void visitImplementsAttr(ImplementsAttr *attr);
800800
};
801801
} // end anonymous namespace
802802

@@ -1884,6 +1884,52 @@ void AttributeChecker::visitDiscardableResultAttr(DiscardableResultAttr *attr) {
18841884
}
18851885
}
18861886

1887+
void AttributeChecker::visitImplementsAttr(ImplementsAttr *attr) {
1888+
TypeLoc &ProtoTypeLoc = attr->getProtocolType();
1889+
TypeResolutionOptions options;
1890+
options |= TR_AllowUnboundGenerics;
1891+
1892+
DeclContext *DC = D->getDeclContext();
1893+
Type T = TC.resolveType(ProtoTypeLoc.getTypeRepr(),
1894+
DC, options);
1895+
ProtoTypeLoc.setType(T);
1896+
1897+
// Definite error-types were already diagnosed in resolveType.
1898+
if (!T || T->hasError())
1899+
return;
1900+
1901+
// Check that we got a ProtocolType.
1902+
if (auto PT = T->getAs<ProtocolType>()) {
1903+
ProtocolDecl *PD = PT->getDecl();
1904+
1905+
// Check that the ProtocolType has the specified member.
1906+
LookupResult R = TC.lookupMember(PD->getDeclContext(),
1907+
PT, attr->getMemberName());
1908+
if (!R) {
1909+
TC.diagnose(attr->getLocation(),
1910+
diag::implements_attr_protocol_lacks_member,
1911+
PD->getBaseName(), attr->getMemberName())
1912+
.highlight(attr->getMemberNameLoc().getSourceRange());
1913+
}
1914+
1915+
// Check that the decl we're decorating is a member of a type that actually
1916+
// conforms to the specified protocol.
1917+
NominalTypeDecl *NTD = DC->getAsNominalTypeOrNominalTypeExtensionContext();
1918+
SmallVector<ProtocolConformance *, 2> conformances;
1919+
if (!NTD->lookupConformance(DC->getParentModule(), PD, conformances)) {
1920+
TC.diagnose(attr->getLocation(),
1921+
diag::implements_attr_protocol_not_conformed_to,
1922+
NTD->getFullName(), PD->getFullName())
1923+
.highlight(ProtoTypeLoc.getTypeRepr()->getSourceRange());
1924+
}
1925+
1926+
} else {
1927+
TC.diagnose(attr->getLocation(),
1928+
diag::implements_attr_non_protocol_type)
1929+
.highlight(ProtoTypeLoc.getTypeRepr()->getSourceRange());
1930+
}
1931+
}
1932+
18871933
void TypeChecker::checkDeclAttributes(Decl *D) {
18881934
AttributeChecker Checker(*this, D);
18891935

0 commit comments

Comments
 (0)