Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sema] Emit a diagnostic when extending a protocol with a redundant requirement #20503

Merged
merged 12 commits into from
Nov 16, 2018
Merged
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsCommon.def
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ NOTE(profile_read_error,none,
ERROR(generic_signature_not_minimal,none,
"generic requirement '%0' is redundant in %1", (StringRef, StringRef))

WARNING(protocol_extension_redundant_requirement,none,
theblixguy marked this conversation as resolved.
Show resolved Hide resolved
"requirement of '%1' to '%2' is redundant in an extension of '%0'",
(StringRef, StringRef, StringRef))

ERROR(attr_only_on_parameters, none,
"'%0' may only be used on parameters", (StringRef))

Expand Down
26 changes: 26 additions & 0 deletions lib/Sema/TypeCheckGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,32 @@ void checkGenericParamList(TypeChecker &tc,
RequirementRequest::visitRequirements(owner, resolution.getStage(),
[&](const Requirement &req, RequirementRepr *reqRepr) {
auto source = FloatingRequirementSource::forExplicit(reqRepr);

// If we're extending a protocol and adding a redundant requirement,
// for example, `extension Foo where Self: Foo`, then emit a
// diagnostic.

if (auto decl = owner.dc->getAsDecl()) {
if (auto extDecl = dyn_cast<ExtensionDecl>(decl)) {
auto extType = extDecl->getExtendedType();
auto extSelfType = extDecl->getSelfInterfaceType();
auto reqLHSType = req.getFirstType();
auto reqRHSType = req.getSecondType();

if (extType->isExistentialType() &&
reqLHSType->isEqual(extSelfType)
&& reqRHSType->isEqual(extType)) {

auto &ctx = extDecl->getASTContext();
ctx.Diags.diagnose(extDecl->getLoc(),
diag::protocol_extension_redundant_requirement,
extType->getString(),
extSelfType->getString(),
reqRHSType->getString());
}
}
}

builder->addRequirement(req, reqRepr, source, nullptr,
lookupDC->getParentModule());
return false;
Expand Down
11 changes: 11 additions & 0 deletions test/decl/ext/protocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,17 @@ extension S1 {
}
}

// ----------------------------------------------------------------------------
// Protocol extensions with redundant requirements
// ----------------------------------------------------------------------------

protocol FooProtocol {}
extension FooProtocol where Self: FooProtocol {} // expected-warning {{requirement of 'Self' to 'FooProtocol' is redundant in an extension of 'FooProtocol'}}

protocol AnotherFooProtocol {}
protocol BazProtocol {}
extension AnotherFooProtocol where Self: BazProtocol, Self: AnotherFooProtocol {} // expected-warning {{requirement of 'Self' to 'AnotherFooProtocol' is redundant in an extension of 'AnotherFooProtocol'}}
theblixguy marked this conversation as resolved.
Show resolved Hide resolved

// ----------------------------------------------------------------------------
// Protocol extensions with additional requirements
// ----------------------------------------------------------------------------
Expand Down