Skip to content

[5.9] Add a missing check for a corner case with package use site / internal decl #64729

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
Mar 29, 2023
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
2 changes: 1 addition & 1 deletion include/swift/IDE/CodeCompletionString.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class CodeCompletionStringChunk {

public:
enum class ChunkKind {
/// "open", "public", "internal", "fileprivate", or "private".
/// "open", "public", "package", "internal", "fileprivate", or "private".
AccessControlKeyword,

/// such as @"available".
Expand Down
1 change: 1 addition & 0 deletions include/swift/IDE/CompletionOverrideLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
hasAccessModifier = isKeywordSpecified("private") ||
isKeywordSpecified("fileprivate") ||
isKeywordSpecified("internal") ||
isKeywordSpecified("package") ||
isKeywordSpecified("public") ||
isKeywordSpecified("open");
hasOverride = isKeywordSpecified("override");
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4112,6 +4112,11 @@ static bool checkAccess(const DeclContext *useDC, const ValueDecl *VD,
}
return true;
case AccessLevel::Internal: {
// Invalid if the use site is > Internal.
// E.g. extension containing a member of a protocol it conforms to has
// `package` access level but the member is `internal`
if (useDC->getContextKind() == DeclContextKind::Package)
return false;
const ModuleDecl *sourceModule = sourceDC->getParentModule();
const DeclContext *useFile = useDC->getModuleScopeContext();
if (useFile->getParentModule() == sourceModule)
Expand Down
6 changes: 5 additions & 1 deletion test/Sema/accessibility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1471,7 +1471,11 @@ public class DerivedFromInternalConcreteGenericComposition : InternalConcreteGen
public func publicReq() {}
}

// FIXME: rdar://104987455 should have expected note and error 'class cannot be declared public because its superclass is internal'
fileprivate typealias FilePrivateConcreteGenericCompositionPkg = InternalGenericClass<Int> & InternalProto
public class DerivedFromFilePrivateConcreteGenericCompositionPkg : FilePrivateConcreteGenericCompositionPkg { // expected-error {{class cannot be declared public because its superclass uses an internal type as a generic parameter}}
public func internalReq() {}
}

internal typealias InternalConcreteGenericCompositionPkg = PackageGenericClass<Int> & PackageProto
public class DerivedFromInternalConcreteGenericCompositionPkg : InternalConcreteGenericCompositionPkg { // expected-error {{class cannot be declared public because its superclass uses a package type as a generic parameter}}
public func packageReq() {}
Expand Down
74 changes: 35 additions & 39 deletions test/Sema/accessibility_package.swift
Original file line number Diff line number Diff line change
@@ -1,34 +1,18 @@
// RUN: %empty-directory(%t)
// RUN: %{python} %utils/split_file.py -o %t %s
// RUN: split-file %s %t

// RUN: %target-swift-frontend -module-name Utils %t/Utils.swift -emit-module -emit-module-path %t/Utils.swiftmodule -package-name myLib
// RUN: %target-swift-frontend -verify -module-name Utils %t/Utils.swift -emit-module -emit-module-path %t/Utils.swiftmodule -package-name myLib
// RUN: test -f %t/Utils.swiftmodule

// RUN: %target-swift-frontend -module-name LibGood %t/LibGood.swift -emit-module -emit-module-path %t/LibGood.swiftmodule -package-name myLib -I %t
// RUN: %target-swift-frontend -verify -module-name LibGood %t/LibGood.swift -emit-module -emit-module-path %t/LibGood.swiftmodule -package-name myLib -I %t
// RUN: test -f %t/LibGood.swiftmodule

// RUN: not %target-swift-frontend -module-name Client %t/Client.swift -emit-module -emit-module-path %t/Client.swiftmodule -package-name client -I %t 2> %t/resultClient.output
// RUN: %FileCheck %s -input-file %t/resultClient.output -check-prefix CHECK-CLIENT
// CHECK-CLIENT: error: 'pkgVar' is inaccessible due to 'package' protection level
// CHECK-CLIENT: error: 'pkgFunc' is inaccessible due to 'package' protection level
// RUN: %target-swift-frontend -verify -module-name Client %t/Client.swift -emit-module -emit-module-path %t/Client.swiftmodule -package-name client -I %t

// RUN: not %target-swift-frontend -typecheck %t/Lib.swift -package-name myLib -I %t 2> %t/result1.output
// RUN: %FileCheck %s -input-file %t/result1.output -check-prefix CHECK-1
// CHECK-1: error: overriding non-open instance method outside of its defining module
// CHECK-1: error: overriding non-open instance method outside of its defining module
// CHECK-1: error: cannot inherit from non-open class 'PublicKlass' outside of its defining module
// CHECK-1: error: cannot inherit from non-open class 'PackageKlass' outside of its defining module
// CHECK-1: error: cannot assign to property: 'publicGetInternal' setter is inaccessible
// CHECK-1: error: cannot assign to property: 'pkgVar' setter is inaccessible
// RUN: %target-swift-frontend -typecheck -verify %t/LibSamePackage.swift -package-name myLib -I %t
// RUN: %target-swift-frontend -typecheck -verify %t/LibOtherPackage.swift -package-name "otherLib" -I %t

// RUN: not %target-swift-frontend -typecheck %t/Lib.swift -package-name "otherLib" -I %t 2> %t/result2.output
// %FileCheck %s -input-file %t/result2.output -check-prefix CHECK-2
// CHECK-2: error: cannot find type 'PackageProto' in scope
// CHECK-2: error: 'pkgFunc' is inaccessible due to 'package' protection level
// CHECK-2: error: cannot find 'PackageKlass' in scope


// BEGIN Utils.swift
//--- Utils.swift
package protocol PackageProto {
var pkgVar: Double { get set }
func pkgFunc()
Expand Down Expand Up @@ -59,40 +43,52 @@ open class OpenKlass {
package func packageFunc() {}
}

// BEGIN Lib.swift
//--- LibSamePackage.swift
import Utils

// Test accessing public and package decls
public func test() {
let x = PublicKlass()
x.publicFunc()
x.pkgFunc() // Allowed if in same package
x.publicGetPkg = 3 // Allowed if in same package
x.publicGetInternal = 4 // Not allowed
x.pkgFunc() // OK
x.publicGetPkg = 3 // OK
x.publicGetInternal = 4 // expected-error {{cannot assign to property: 'publicGetInternal' setter is inaccessible}}

let y = PackageKlass() // Allowed if in same package
y.pkgVar = 1.5 // Not allowed
y.pkgFunc() // Allowed if in same package
let y = PackageKlass() // OK
y.pkgVar = 1.5 // expected-error {{cannot assign to property: 'pkgVar' setter is inaccessible}}
y.pkgFunc() // OK
}

// Test conformance to a package protocol
package struct LibStruct : PackageProto { // Allowed if in same package
package struct LibStruct : PackageProto { // OK
package var pkgVar: Double = 1.0
package func pkgFunc() {}
}

// Test subclassing / overrides
class SubOpenKlass: OpenKlass {
override open func openFunc() {}
override public func publicFunc() {}
override package func packageFunc() {}
override public func publicFunc() {} // expected-error {{overriding non-open instance method outside of its defining module}}
override package func packageFunc() {} // expected-error {{overriding non-open instance method outside of its defining module}}
}
class SubPublicKlass: PublicKlass {} // Not allowed
class SubPackageKlass: PackageKlass {} // Not allowed
class SubPublicKlass: PublicKlass {} // expected-error {{cannot inherit from non-open class 'PublicKlass' outside of its defining module}}
class SubPackageKlass: PackageKlass {} // expected-error {{cannot inherit from non-open class 'PackageKlass' outside of its defining module}}


//--- LibOtherPackage.swift
import Utils

// Test accessing package decls
public func test() {
let x = PublicKlass()
x.publicFunc() // OK
x.pkgFunc() // expected-error {{'pkgFunc' is inaccessible due to 'package' protection level}}
let y = PackageKlass() // expected-error {{cannot find 'PackageKlass' in scope}}
}

package struct LibStruct : PackageProto {} // expected-error {{cannot find type 'PackageProto' in scope}}

// BEGIN LibGood.swift
//--- LibGood.swift
import Utils

public func libFunc() {
Expand All @@ -107,13 +103,13 @@ public struct LibStruct: PackageProto {
public func publicFunc() {}
}

// BEGIN Client.swift
//--- Client.swift
import LibGood

func clientFunc() {
let lib = LibStruct()
_ = lib.pkgVar // Not allowed
_ = lib.pkgVar // expected-error {{'pkgVar' is inaccessible due to 'package' protection level}}
_ = lib.publicVar
lib.pkgFunc() // Not allowed
lib.pkgFunc() // expected-error {{'pkgFunc' is inaccessible due to 'package' protection level}}
lib.publicFunc()
}
90 changes: 41 additions & 49 deletions test/Sema/accessibility_package_inline.swift
Original file line number Diff line number Diff line change
@@ -1,53 +1,22 @@
// RUN: %empty-directory(%t)
// RUN: %{python} %utils/split_file.py -o %t %s
// RUN: split-file %s %t

// RUN: %target-swift-frontend -module-name UtilsGood %t/UtilsGood.swift -emit-module -emit-module-path %t/UtilsGood.swiftmodule -package-name myLib
// RUN: %target-swift-frontend -verify -module-name UtilsGood %t/UtilsGood.swift -emit-module -emit-module-path %t/UtilsGood.swiftmodule -package-name myLib
// RUN: test -f %t/UtilsGood.swiftmodule

// RUN: not %target-swift-frontend -typecheck %t/Utils.swift -package-name myLib -I %t 2> %t/resultUtils.output
// RUN: %FileCheck %s -input-file %t/resultUtils.output -check-prefix CHECK-UTILS
// CHECK-UTILS: error: class 'PackageKlass' is package and cannot be referenced from an '@inlinable' function
// CHECK-UTILS: let a = PackageKlass()
// CHECK-UTILS: ^
// CHECK-UTILS: note: class 'PackageKlass' is not '@usableFromInline' or public
// CHECK-UTILS: package class PackageKlass {
// CHECK-UTILS: ^
// CHECK-UTILS: error: initializer 'init()' is package and cannot be referenced from an '@inlinable' function
// CHECK-UTILS: let a = PackageKlass() // should error
// CHECK-UTILS: ^
// CHECK-UTILS: note: initializer 'init()' is not '@usableFromInline' or public
// CHECK-UTILS: package init() {}
// CHECK-UTILS: ^
// CHECK-UTILS: error: class 'InternalKlass' is internal and cannot be referenced from an '@inlinable' function
// CHECK-UTILS: let b = InternalKlass() // should error
// CHECK-UTILS: ^
// CHECK-UTILS: note: class 'InternalKlass' is not '@usableFromInline' or public
// CHECK-UTILS: class InternalKlass {
// CHECK-UTILS: ^
// CHECK-UTILS: error: initializer 'init()' is internal and cannot be referenced from an '@inlinable' function
// CHECK-UTILS: let b = InternalKlass() // should error
// CHECK-UTILS: ^
// CHECK-UTILS: note: initializer 'init()' is not '@usableFromInline' or public
// CHECK-UTILS: init() {}
// CHECK-UTILS: ^

// RUN: not %target-swift-frontend -typecheck %t/Lib.swift -package-name "otherLib" -I %t 2> %t/resultLib.output
// %FileCheck %s -input-file %t/resultLib.output -check-prefix CHECK-LIB
// CHECK-LIB: error: cannot find 'packageFunc' in scope
// CHECK-LIB: packageFunc()
// CHECK-LIB: ^~~~~~~~~~~

// RUN: %target-swift-frontend -module-name Lib %t/Lib.swift -emit-module -emit-module-path %t/Lib.swiftmodule -package-name myLib -I %t
// RUN: test -f %t/Lib.swiftmodule

// BEGIN Utils.swift
// RUN: %target-swift-frontend -typecheck -verify %t/Utils.swift -package-name myLib -I %t
// RUN: %target-swift-frontend -typecheck -verify %t/LibOtherPackage.swift -package-name otherLib -I %t
// RUN: %target-swift-frontend -typecheck -verify %t/LibSamePackage.swift -package-name myLib -I %t

//--- Utils.swift
package protocol PackageProto {
var pkgVar: Double { get set }
func pkgFunc()
}

// expected-note@+1 *{{class 'PackageKlass' is not '@usableFromInline' or public}}
package class PackageKlass {
package init() {}
package init() {} // expected-note *{{initializer 'init()' is not '@usableFromInline' or public}}
package private(set) var pkgVar: Double = 1.0
package func pkgFunc() {}
}
Expand All @@ -71,8 +40,10 @@ protocol InternalProto {
var internalVar: Double { get set }
func internalFunc()
}

// expected-note@+1 *{{class 'InternalKlass' is not '@usableFromInline' or public}}
class InternalKlass {
init() {}
init() {} // expected-note *{{initializer 'init()' is not '@usableFromInline' or public}}
}
@usableFromInline
class InternalKlassProto: InternalProto {
Expand All @@ -90,8 +61,12 @@ class InternalKlassForInline {

@inlinable
public func publicFunc() {
let a = PackageKlass() // should error
let a = PackageKlass()
// expected-error@-1 {{class 'PackageKlass' is package and cannot be referenced from an '@inlinable' function}}
// expected-error@-2 {{initializer 'init()' is package and cannot be referenced from an '@inlinable' function}}
let b = InternalKlass() // should error
// expected-error@-1 {{class 'InternalKlass' is internal and cannot be referenced from an '@inlinable' function}}
// expected-error@-2 {{initializer 'init()' is internal and cannot be referenced from an '@inlinable' function}}
let c = PackageKlassProto()
let d = InternalKlassProto()
let e = PackageKlassForInline()
Expand All @@ -101,8 +76,12 @@ public func publicFunc() {

@inlinable
func internalFunc() {
let a = PackageKlass() // should error
let b = InternalKlass() // should error
let a = PackageKlass()
// expected-error@-1 {{class 'PackageKlass' is package and cannot be referenced from an '@inlinable' function}}
// expected-error@-2 {{initializer 'init()' is package and cannot be referenced from an '@inlinable' function}}
let b = InternalKlass()
// expected-error@-1 {{class 'InternalKlass' is internal and cannot be referenced from an '@inlinable' function}}
// expected-error@-2 {{initializer 'init()' is internal and cannot be referenced from an '@inlinable' function}}
let c = PackageKlassProto()
let d = InternalKlassProto()
let e = PackageKlassForInline()
Expand All @@ -112,16 +91,20 @@ func internalFunc() {

@inlinable
package func packageFunc() {
let a = PackageKlass() // should error
let b = InternalKlass() // should error
let a = PackageKlass()
// expected-error@-1 {{class 'PackageKlass' is package and cannot be referenced from an '@inlinable' function}}
// expected-error@-2 {{initializer 'init()' is package and cannot be referenced from an '@inlinable' function}}
let b = InternalKlass()
// expected-error@-1 {{class 'InternalKlass' is internal and cannot be referenced from an '@inlinable' function}}
// expected-error@-2 {{initializer 'init()' is internal and cannot be referenced from an '@inlinable' function}}
let c = PackageKlassProto()
let d = InternalKlassProto()
let e = PackageKlassForInline()
let f = InternalKlassForInline()
print(a, b, c, d, e, f)
}

// BEGIN UtilsGood.swift
//--- UtilsGood.swift
package protocol PackageProto {
var pkgVar: Double { get set }
func pkgFunc()
Expand Down Expand Up @@ -170,11 +153,20 @@ package func packageFunc() {
print(x, y)
}

// BEGIN Lib.swift
//--- LibOtherPackage.swift
import UtilsGood

@inlinable
public func libFunc() {
publicFunc()
packageFunc() // expected-error {{cannot find 'packageFunc' in scope}}
}

//--- LibSamePackage.swift
import UtilsGood

@inlinable
public func libFunc() {
publicFunc()
packageFunc() // Allowed if in same package
packageFunc() // OK
}
26 changes: 26 additions & 0 deletions test/attr/accessibility_proto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,29 @@ package protocol PkgEmptyInit {
public struct PkgBuggy: PkgEmptyInit {
// expected-error@-1 {{initializer 'init()' must be declared package because it matches a requirement in package protocol 'PkgEmptyInit'}}
}

package protocol PkgReqProvider {}
extension PkgReqProvider {
fileprivate func foo() {}
// expected-note@-1 {{mark the instance method as 'package' to satisfy the requirement}} {{3-14=package}}
typealias AssocB = String
// expected-note@-1 {{mark the type alias as 'package' to satisfy the requirement}} {{3-3=package }}
}
package struct PkgAdoptViaProtocol : PkgProtoWithReqs, PkgReqProvider {
// expected-error@-1 {{method 'foo()' must be declared package because it matches a requirement in package protocol 'PkgProtoWithReqs'}} {{none}}
// expected-error@-2 {{type alias 'AssocB' must be declared package because it matches a requirement in package protocol 'PkgProtoWithReqs'}} {{none}}
package typealias AssocA = Int
}

package protocol PkgReqProvider2 {}
extension PkgProtoWithReqs where Self : PkgReqProvider2 {
func foo() {}
// expected-note@-1 {{mark the instance method as 'package' to satisfy the requirement}} {{3-3=package }}
typealias AssocB = String
// expected-note@-1 {{mark the type alias as 'package' to satisfy the requirement}} {{3-3=package }}
}
package struct PkgAdoptViaCombinedProtocol : PkgProtoWithReqs, PkgReqProvider2 {
// expected-error@-1 {{method 'foo()' must be declared package because it matches a requirement in package protocol 'PkgProtoWithReqs'}} {{none}}
// expected-error@-2 {{type alias 'AssocB' must be declared package because it matches a requirement in package protocol 'PkgProtoWithReqs'}} {{none}}
public typealias AssocA = Int
}