Skip to content

Commit 3340009

Browse files
committed
Fixing invalid swiftinterface in presence of an internal protocol
Private member witnessing a public constraint should be deprecated. If StrictSemaForTextualInterface is set, compiler emits a warning (in future versions -- an error) when access check is not passed. rdar://74904373
1 parent 83a9913 commit 3340009

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

include/swift/Basic/Features.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,8 @@ EXPERIMENTAL_FEATURE(CheckImplementationOnlyStrict, false)
564564
/// Check that use sites have the required @_spi import for operators.
565565
EXPERIMENTAL_FEATURE(EnforceSPIOperatorGroup, true)
566566

567+
EXPERIMENTAL_FEATURE(StrictSemaForTextualInterface, true)
568+
567569
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
568570
#undef EXPERIMENTAL_FEATURE
569571
#undef UPCOMING_FEATURE

lib/AST/FeatureSet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ static bool usesFeatureTildeSendable(Decl *decl) {
466466
}
467467

468468
UNINTERESTING_FEATURE(AnyAppleOSAvailability)
469+
UNINTERESTING_FEATURE(StrictSemaForTextualInterface)
469470

470471
// ----------------------------------------------------------------------------
471472
// MARK: - FeatureSet

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,11 +1762,14 @@ static bool checkWitnessAccess(DeclContext *dc,
17621762

17631763
auto actualScopeToCheck = requiredAccessScope.first;
17641764

1765+
// without StrictTextualInterfaceChecking feature forConformance is set true
1766+
bool forConformance = not dc->getASTContext().LangOpts.hasFeature
1767+
(Feature::StrictSemaForTextualInterface);
17651768
// Setting the 'forConformance' flag means that we admit witnesses in
17661769
// protocol extensions that we can see, but are not necessarily as
17671770
// visible as the conforming type and protocol.
17681771
if (!witness->isAccessibleFrom(actualScopeToCheck.getDeclContext(),
1769-
/*forConformance=*/true)) {
1772+
forConformance)) {
17701773
// Special case: if we have `@testable import` of the witness's module,
17711774
// allow the witness to match if it would have matched for just this file.
17721775
// That is, if '@testable' allows us to see the witness here, it should
@@ -4453,7 +4456,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
44534456
diagKind, getProtocolRequirementKind(requirement),
44544457
witness, isSetter, requiredAccess,
44554458
protoAccessScope.accessLevelForDiagnostics(),
4456-
proto);
4459+
proto).warnUntilFutureSwiftVersionIf(DC->getASTContext().LangOpts.hasFeature(Feature::StrictSemaForTextualInterface));
44574460

44584461
auto *decl = dyn_cast<AbstractFunctionDecl>(witness);
44594462
if (decl && decl->isSynthesized())
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-typecheck-verify-swift -enable-library-evolution -enable-experimental-feature StrictSemaForTextualInterface
3+
4+
public protocol P {
5+
func foo() -> Int
6+
}
7+
internal protocol Q: P {
8+
func fooImpl() -> Int32
9+
}
10+
extension Q {
11+
public func foo() -> Int { // expected-note {{mark the instance method as 'public' to satisfy the requirement}}
12+
return Int(self.fooImpl())
13+
}
14+
}
15+
public struct S: Q { // expected-error {{method 'foo()' must be declared public because it matches a requirement in public protocol 'P'}}
16+
internal func fooImpl() -> Int32 {
17+
return 42
18+
}
19+
}
20+
21+
public struct Foo {
22+
public init(value: Int) {}
23+
}
24+
public protocol PublicProtocol {
25+
init?(integer: Int)
26+
}
27+
protocol InternalProtocol: PublicProtocol {}
28+
extension InternalProtocol {
29+
public init(integer: Int) {} // expected-note {{mark the initializer as 'public' to satisfy the requirement}}
30+
}
31+
extension Foo: PublicProtocol, InternalProtocol {} // expected-error {{initializer 'init(integer:)' must be declared public because it matches a requirement in public protocol 'PublicProtocol'}}

0 commit comments

Comments
 (0)