mirror of
https://github.com/apple/swift.git
synced 2026-06-20 15:42:51 +02:00
dd798e0079
When hiding dependencies in embedded mode there are special rules for classes. Classes properties can safely reference the hidden dependencies, however code referencing these properties must be marked `@export(interface)`. We previously added a check to report implicit code without the requited `@export(interface)`. However explicit references from user written code wasn't fully checked, only explicit references to the imported type or the type's services would be reported, not references to the property itself. We patch that hole here by introducing new requirements and a new layer of check specific to class properies in embedded mode. --- Class properties referencing a hidden dependency must be marked `@_implementationOnly`. This adds on top of the requirement for the class itself to have an explicit `@export(interface) deinit`. This allows to report references from user written code using existing diagnostics.
118 lines
6.6 KiB
Swift
118 lines
6.6 KiB
Swift
// RUN: %empty-directory(%t)
|
|
// RUN: split-file %s %t --leading-lines
|
|
|
|
// RUN: %target-swift-frontend -emit-module %t/Lib.swift -o %t/Lib.swiftmodule \
|
|
// RUN: -swift-version 6
|
|
|
|
// RUN: %target-swift-frontend -emit-module %t/Client.swift -I %t \
|
|
// RUN: -verify -verify-ignore-unrelated \
|
|
// RUN: -swift-version 6 \
|
|
// RUN: -enable-experimental-feature CheckImplementationOnly
|
|
|
|
// RUN: %empty-directory(%t)
|
|
// RUN: split-file %s %t --leading-lines
|
|
|
|
// RUN: %target-swift-frontend -emit-module %t/Lib.swift -o %t/Lib.swiftmodule \
|
|
// RUN: -swift-version 6 -target arm64-apple-none-macho \
|
|
// RUN: -enable-experimental-feature Embedded
|
|
|
|
// RUN: %target-swift-frontend -emit-module %t/Client.swift -I %t \
|
|
// RUN: -verify -verify-ignore-unrelated \
|
|
// RUN: -swift-version 6 -target arm64-apple-none-macho \
|
|
// RUN: -verify-additional-prefix embedded- \
|
|
// RUN: -enable-experimental-feature Embedded \
|
|
// RUN: -enable-experimental-feature CheckImplementationOnly
|
|
|
|
// REQUIRES: swift_feature_Embedded
|
|
// REQUIRES: swift_feature_CheckImplementationOnly
|
|
// REQUIRES: embedded_stdlib_cross_compiling
|
|
|
|
//--- Lib.swift
|
|
|
|
public struct HiddenType {
|
|
public init() {}
|
|
}
|
|
|
|
//--- Client.swift
|
|
|
|
@_implementationOnly import Lib
|
|
|
|
public protocol LocalProto {}
|
|
extension HiddenType: LocalProto {}
|
|
public struct LocalType: LocalProto {}
|
|
|
|
@frozen
|
|
public struct FrozenStruct {
|
|
let propertyWithDefaultInit: LocalProto = HiddenType() // expected-error {{struct 'HiddenType' cannot be used in a property initializer in a '@frozen' type because 'Lib' was imported implementation-only}}
|
|
// expected-error @-1 {{initializer 'init()' cannot be used in a property initializer in a '@frozen' type because 'Lib' was imported implementation-only}}
|
|
|
|
func funcWithDefaultArg(a: LocalProto = HiddenType()) {} // expected-embedded-error {{struct 'HiddenType' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
// expected-embedded-error @-1 {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
}
|
|
|
|
public class PublicClass {
|
|
let propertyOk: LocalProto? = nil // OK
|
|
|
|
let propertyWithDefaultInit: LocalProto = HiddenType() // expected-embedded-error {{struct 'HiddenType' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
// expected-embedded-error @-1 {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
|
|
func funcWithDefaultArg(a: LocalProto = HiddenType()) {} // expected-embedded-error {{struct 'HiddenType' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
// expected-embedded-error @-1 {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
|
|
@export(interface)
|
|
func funcWithDefaultArgExportInterface(a: LocalProto = HiddenType()) {}
|
|
}
|
|
|
|
internal struct InternalStruct {
|
|
let propertyWithDefaultInit: LocalProto = HiddenType() // expected-embedded-error {{struct 'HiddenType' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
// expected-embedded-error @-1 {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
|
|
func funcWithDefaultArg(a: LocalProto = HiddenType()) {} // expected-embedded-error {{struct 'HiddenType' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
// expected-embedded-error @-1 {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
|
|
@export(interface)
|
|
func funcWithDefaultArgExportInterface(a: LocalProto = HiddenType()) {}
|
|
}
|
|
|
|
public class MissingBothIOIAndDeinit { // expected-embedded-note {{add a '@export(interface)' deinit to the parent class}}
|
|
var prop: HiddenType = HiddenType()
|
|
// expected-embedded-error @-1 {{cannot use struct 'HiddenType' in a stored property of a class without meeting the Embedded mode requirements; 'Lib' has been imported as implementation-only}}
|
|
// expected-embedded-note @-2 {{mark the stored property '@_implementationOnly'}}
|
|
// expected-embedded-error @-3 {{struct 'HiddenType' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
// expected-embedded-error @-4 {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
}
|
|
|
|
public class HasDeinitWithoutIOIProperty {
|
|
var prop: HiddenType = HiddenType()
|
|
// expected-embedded-error @-1 {{cannot use struct 'HiddenType' in a stored property of a class without meeting the Embedded mode requirements; 'Lib' has been imported as implementation-only}}
|
|
// expected-embedded-note @-2 {{mark the stored property '@_implementationOnly'}}
|
|
// expected-embedded-error @-3 {{struct 'HiddenType' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
// expected-embedded-error @-4 {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
|
|
@export(interface)
|
|
deinit {}
|
|
}
|
|
|
|
public class HasIOIPropertyWithoutDeinit { // expected-embedded-note {{add a '@export(interface)' deinit to the parent class}}
|
|
@_implementationOnly var prop: HiddenType = HiddenType()
|
|
// expected-embedded-error @-1 {{cannot use struct 'HiddenType' in a stored property of a class without meeting the Embedded mode requirements; 'Lib' has been imported as implementation-only}}
|
|
// expected-embedded-error @-2 {{struct 'HiddenType' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
// expected-embedded-error @-3 {{initializer 'init()' cannot be used in an embedded function not marked '@export(interface)' because 'Lib' was imported implementation-only}}
|
|
}
|
|
|
|
public class HasBothIOIAndDeinit {
|
|
@_implementationOnly var prop: HiddenType? = nil
|
|
|
|
@export(interface)
|
|
deinit {}
|
|
|
|
@export(interface)
|
|
func userOk() {
|
|
let _ = prop
|
|
}
|
|
|
|
func userMissingAttribute() {
|
|
let _ = prop // expected-embedded-error {{property 'prop' cannot be used in an embedded function not marked '@export(interface)' because 'prop' is marked '@_implementationOnly'}}
|
|
}
|
|
}
|