Skip to content
Draft
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
2 changes: 2 additions & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,8 @@ EXPERIMENTAL_FEATURE(CheckImplementationOnlyStrict, false)
/// Check that use sites have the required @_spi import for operators.
EXPERIMENTAL_FEATURE(EnforceSPIOperatorGroup, true)

EXPERIMENTAL_FEATURE(StrictSemaForTextualInterface, true)

#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
#undef EXPERIMENTAL_FEATURE
#undef UPCOMING_FEATURE
Expand Down
1 change: 1 addition & 0 deletions lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ static bool usesFeatureTildeSendable(Decl *decl) {
}

UNINTERESTING_FEATURE(AnyAppleOSAvailability)
UNINTERESTING_FEATURE(StrictSemaForTextualInterface)

// ----------------------------------------------------------------------------
// MARK: - FeatureSet
Expand Down
18 changes: 12 additions & 6 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1762,11 +1762,14 @@ static bool checkWitnessAccess(DeclContext *dc,

auto actualScopeToCheck = requiredAccessScope.first;

// without StrictTextualInterfaceChecking feature forConformance is set true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is unnecessary in my opinion

bool forConformance = not dc->getASTContext().LangOpts.hasFeature(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Please use ! instead of not
  • Can you extract a local variable for dc->getASTContext()

Feature::StrictSemaForTextualInterface);
// Setting the 'forConformance' flag means that we admit witnesses in
// protocol extensions that we can see, but are not necessarily as
// visible as the conforming type and protocol.
if (!witness->isAccessibleFrom(actualScopeToCheck.getDeclContext(),
/*forConformance=*/true)) {
forConformance)) {
// Special case: if we have `@testable import` of the witness's module,
// allow the witness to match if it would have matched for just this file.
// That is, if '@testable' allows us to see the witness here, it should
Expand Down Expand Up @@ -4449,11 +4452,14 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
bool isSetter = check.isForSetterAccess();

auto &diags = DC->getASTContext().Diags;
diags.diagnose(getLocForDiagnosingWitness(conformance, witness),
diagKind, getProtocolRequirementKind(requirement),
witness, isSetter, requiredAccess,
protoAccessScope.accessLevelForDiagnostics(),
proto);
diags
.diagnose(getLocForDiagnosingWitness(conformance, witness),
diagKind, getProtocolRequirementKind(requirement),
witness, isSetter, requiredAccess,
protoAccessScope.accessLevelForDiagnostics(), proto)
.warnUntilFutureSwiftVersionIf(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change, all access control errors from conformance checking now become warnings, we don't want that

DC->getASTContext().LangOpts.hasFeature(
Feature::StrictSemaForTextualInterface));

auto *decl = dyn_cast<AbstractFunctionDecl>(witness);
if (decl && decl->isSynthesized())
Expand Down
36 changes: 36 additions & 0 deletions test/Sema/diag_internal_protocol_access_check.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: %empty-directory(%t)
// RUN: %target-typecheck-verify-swift -enable-library-evolution -enable-experimental-feature StrictSemaForTextualInterface -language-mode 6 -verify-additional-prefix swift6-
// RUN: %target-typecheck-verify-swift -enable-library-evolution -enable-experimental-feature StrictSemaForTextualInterface -language-mode 7 -verify-additional-prefix swift7-

public protocol P {
func foo() -> Int
}
internal protocol Q: P {
func fooImpl() -> Int32
}
extension Q {
public func foo() -> Int { // expected-note {{mark the instance method as 'public' to satisfy the requirement}}
return Int(self.fooImpl())
}
}
public struct S: Q {
// expected-swift7-error@-1 {{method 'foo()' must be declared public because it matches a requirement in public protocol 'P'}}
// expected-swift6-warning@-2 {{method 'foo()' must be declared public because it matches a requirement in public protocol 'P'; this will be an error in a future Swift language mode}}
internal func fooImpl() -> Int32 {
return 42
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too many blank lines

public struct Foo {
public init(value: Int) {}
}
public protocol PublicProtocol {
init?(integer: Int)
}
protocol InternalProtocol: PublicProtocol {}
extension InternalProtocol {
public init(integer: Int) {} // expected-note {{mark the initializer as 'public' to satisfy the requirement}}
}
extension Foo: PublicProtocol, InternalProtocol {}
// expected-swift7-error@-1 {{initializer 'init(integer:)' must be declared public because it matches a requirement in public protocol 'PublicProtocol'}}
// expected-swift6-warning@-2 {{initializer 'init(integer:)' must be declared public because it matches a requirement in public protocol 'PublicProtocol'; this will be an error in a future Swift language mode}}