Skip to content

stdlib: Adopt ExtensionImportVisibility experimental feature #72871

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 4 commits into from
Apr 5, 2024
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/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE(IsolatedAny, true)


// Whether members of extensions respect the enclosing file's imports.
EXPERIMENTAL_FEATURE(ExtensionImportVisibility, true)
EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE(ExtensionImportVisibility, true)
Copy link
Member

Choose a reason for hiding this comment

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

TIL


// Alias for IsolatedAny
EXPERIMENTAL_FEATURE(IsolatedAny2, true)
Expand Down
2 changes: 2 additions & 0 deletions stdlib/cmake/modules/SwiftSource.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,8 @@ function(_compile_swift_files
list(APPEND swift_flags "-enable-experimental-feature" "NonescapableTypes")
endif()

list(APPEND swift_flags "-enable-experimental-feature" "ExtensionImportVisiblity")

if (SWIFT_STDLIB_ENABLE_STRICT_CONCURRENCY_COMPLETE)
list(APPEND swift_flags "-strict-concurrency=complete")
endif()
Expand Down
8 changes: 8 additions & 0 deletions test/NameLookup/Inputs/Categories/Categories_A.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@import Foundation;

@interface X
@end

@interface X (A)
- (void)fromA;
@end
6 changes: 6 additions & 0 deletions test/NameLookup/Inputs/Categories/Categories_A.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@_exported import Categories_A

extension X {
public func fromOverlayForA() {}
@objc public func fromOverlayForAObjC() {}
}
5 changes: 5 additions & 0 deletions test/NameLookup/Inputs/Categories/Categories_B.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import Categories_A;

@interface X (B)
- (void)fromB;
@end
6 changes: 6 additions & 0 deletions test/NameLookup/Inputs/Categories/Categories_B.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@_exported import Categories_B

extension X {
public func fromOverlayForB() {}
@objc public func fromOverlayForBObjC() {}
}
5 changes: 5 additions & 0 deletions test/NameLookup/Inputs/Categories/Categories_C.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import Categories_A;

@interface X (C)
- (void)fromC;
@end
6 changes: 6 additions & 0 deletions test/NameLookup/Inputs/Categories/Categories_C.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@_exported import Categories_C

extension X {
public func fromOverlayForC() {}
@objc public func fromOverlayForCObjC() {}
}
1 change: 1 addition & 0 deletions test/NameLookup/Inputs/Categories/Categories_D.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import Categories_C
14 changes: 14 additions & 0 deletions test/NameLookup/Inputs/Categories/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Categories_A {
header "Categories_A.h"
export *
}

module Categories_B {
header "Categories_B.h"
export *
}

module Categories_C {
header "Categories_C.h"
export *
}
8 changes: 8 additions & 0 deletions test/NameLookup/Inputs/extensions_A.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,11 @@ public struct Y<T> { }
extension Y: P where T: P { }

public struct Z: P { }

extension X {
public func XinA() { }
}

extension Y {
public func YinA() { }
}
4 changes: 2 additions & 2 deletions test/NameLookup/Inputs/extensions_B.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import extensions_A

public extension X {
extension X {
public func XinB() { }
}

public extension Y {
extension Y {
public func YinB() { }
}

6 changes: 3 additions & 3 deletions test/NameLookup/Inputs/extensions_C.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import extensions_A
@_exported import extensions_A
import extensions_B

public extension X {
extension X {
public func XinC() { }
}

public extension Y {
extension Y {
public func YinC() { }
}

4 changes: 3 additions & 1 deletion test/NameLookup/extensions_transitive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
// RUN: %target-swift-frontend -emit-module -I %t -o %t %S/Inputs/extensions_C.swift
// RUN: %target-swift-frontend -typecheck %s -I %t -verify -enable-experimental-feature ExtensionImportVisibility

import extensions_A
import extensions_C
// expected-note 2{{add import of module 'extensions_B'}}{{1-1=import extensions_B\n}}
func test(x: X, y: Y<Z>) {
x.XinA()
y.YinA()

x.XinB() // expected-error{{instance method 'XinB()' is not available due to missing import of defining module 'extensions_B'}}
y.YinB() // expected-error{{instance method 'YinB()' is not available due to missing import of defining module 'extensions_B'}}

Expand Down
32 changes: 32 additions & 0 deletions test/NameLookup/extensions_transitive_objc.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -I %t -I %S/Inputs/Categories -o %t %S/Inputs/Categories/Categories_A.swift
// RUN: %target-swift-frontend -emit-module -I %t -I %S/Inputs/Categories -o %t %S/Inputs/Categories/Categories_B.swift
// RUN: %target-swift-frontend -emit-module -I %t -I %S/Inputs/Categories -o %t %S/Inputs/Categories/Categories_C.swift
// RUN: %target-swift-frontend -emit-module -I %t -I %S/Inputs/Categories -o %t %S/Inputs/Categories/Categories_D.swift
// RUN: %target-swift-frontend -typecheck %s -I %t -I %S/Inputs/Categories -verify -enable-experimental-feature ExtensionImportVisibility

// REQUIRES: objc_interop

import Categories_B
import Categories_D
// expected-note 2 {{add import of module 'Categories_C'}}{{1-1=import Categories_C\n}}
func test(x: X) {
x.fromA()
x.fromOverlayForA()
x.fromB()
x.fromOverlayForB()
x.fromC() // expected-error {{class method 'fromC()' is not available due to missing import of defining module 'Categories_C'}}
x.fromOverlayForC() // expected-error {{instance method 'fromOverlayForC()' is not available due to missing import of defining module 'Categories_C'}}
}

func testAnyObject(a: AnyObject) {
a.fromA()
a.fromOverlayForAObjC()
a.fromB()
a.fromOverlayForBObjC()
// FIXME: Better diagnostics?
// Name lookup for AnyObject already ignored transitive imports, so
// ExtensionImportVisibility has no effect on these diagnostics.
a.fromC() // expected-error {{value of type 'AnyObject' has no member 'fromC'}}
a.fromOverlayForCObjC() // expected-error {{value of type 'AnyObject' has no member 'fromOverlayForCObjC'}}
}