Skip to content

[Type checker] Warn about unavailable witnesses used to satisfy a requirement #9093

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

Merged
merged 1 commit into from
Apr 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1533,6 +1533,10 @@ NOTE(declared_protocol_conformance_here,none,
"%0 implicitly conforms to protocol %2}1 here",
(Type, unsigned, DeclName, DeclName))

WARNING(witness_unavailable,none,
"unavailable %0 %1 was used to satisfy a requirement of protocol %2",
(DescriptiveDeclKind, DeclName, DeclName))

ERROR(redundant_conformance,none,
"redundant conformance of %0 to protocol %1", (Type, DeclName))

Expand Down
23 changes: 22 additions & 1 deletion lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ namespace {
/// The witness is a constructor which is more failable than the
/// requirement.
ConstructorFailability,

/// The witness itself is inaccessible.
WitnessUnavailable,
};

/// Describes an optional adjustment made to a witness.
Expand Down Expand Up @@ -1539,6 +1542,11 @@ checkWitness(AccessScope requiredAccessScope,
}
}

if (match.Witness->getAttrs().isUnavailable(TC.Context) &&
!requirement->getAttrs().isUnavailable(TC.Context)) {
return CheckKind::WitnessUnavailable;
}

return CheckKind::Success;
}

Expand Down Expand Up @@ -2905,7 +2913,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
auto ctor = cast<ConstructorDecl>(requirement);
auto witnessCtor = cast<ConstructorDecl>(witness);
auto &diags = witness->getASTContext().Diags;
diags.diagnose(witness->getLoc(),
diags.diagnose(witness,
diag::witness_initializer_failability,
ctor->getFullName(),
witnessCtor->getFailability()
Expand All @@ -2914,6 +2922,19 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
});

break;

case CheckKind::WitnessUnavailable:
diagnoseOrDefer(requirement, /*isError=*/false,
[witness, requirement](NormalProtocolConformance *conformance) {
auto &diags = witness->getASTContext().Diags;
diags.diagnose(witness, diag::witness_unavailable,
witness->getDescriptiveKind(),
witness->getFullName(),
conformance->getProtocol()->getFullName());
diags.diagnose(requirement, diag::protocol_requirement_here,
requirement->getFullName());
});
break;
}

ClassDecl *classDecl = Adoptee->getClassOrBoundGenericClass();
Expand Down
10 changes: 10 additions & 0 deletions test/decl/protocol/req/unavailable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ class Bar : NonObjCProto { // expected-error {{type 'Bar' does not conform to pr
func good() {}
}


// Warn about unavailable witnesses.
protocol P {
func foo(bar: Foo) // expected-note{{requirement 'foo(bar:)' declared here}}
}

struct ConformsToP : P {
@available(*, unavailable)
func foo(bar: Foo) { } // expected-warning{{unavailable instance method 'foo(bar:)' was used to satisfy a requirement of protocol 'P'}}
}