Files
swift-mirror/test/Sema/embedded-implicit-init.swift
T
Alexis Laferrière dd798e0079 Embedded: Accept and enforce @_implementationOnly class properties
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.
2026-03-24 13:18:23 -07:00

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'}}
}
}