Skip to content
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
4 changes: 2 additions & 2 deletions lib/Sema/ResilienceDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ static bool diagnoseTypeAliasDeclRefExportability(SourceLoc loc,
auto ignoredDowngradeToWarning = DowngradeToWarning::No;
auto originKind =
getDisallowedOriginKind(D, where, ignoredDowngradeToWarning);
if (originKind == DisallowedOriginKind::None)
if (where.canReferenceOrigin(originKind))
return false;

// As an exception, if the import of the module that defines the desugared
Expand Down Expand Up @@ -442,7 +442,7 @@ TypeChecker::diagnoseConformanceExportability(SourceLoc loc,
});

auto originKind = getDisallowedOriginKind(ext, where);
if (originKind == DisallowedOriginKind::None)
if (where.canReferenceOrigin(originKind))
return false;

auto reason = where.getExportabilityReason();
Expand Down
15 changes: 15 additions & 0 deletions lib/Sema/TypeCheckAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "TypeCheckAvailability.h"
#include "MiscDiagnostics.h"
#include "TypeCheckAccess.h"
#include "TypeCheckConcurrency.h"
#include "TypeCheckObjC.h"
#include "TypeCheckType.h"
Expand Down Expand Up @@ -234,6 +235,20 @@ bool ExportContext::mustOnlyReferenceExportedDecls() const {
return Exported || FragileKind.kind != FragileFunctionKind::None;
}

bool ExportContext::canReferenceOrigin(DisallowedOriginKind originKind) const {
if (originKind == DisallowedOriginKind::None)
return true;

// Non public imports aren't hidden dependencies in embedded mode,
// don't enforce them on implicitly always emit into client code.
if (originKind == DisallowedOriginKind::NonPublicImport &&
getFragileFunctionKind().kind ==
FragileFunctionKind::EmbeddedAlwaysEmitIntoClient)
return true;

return false;
}

std::optional<ExportabilityReason>
ExportContext::getExportabilityReason() const {
if (Exported)
Expand Down
5 changes: 5 additions & 0 deletions lib/Sema/TypeCheckAvailability.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace swift {
class TypeRepr;
class UnsafeUse;
class ValueDecl;
enum class DisallowedOriginKind : uint8_t;

enum class DeclAvailabilityFlag : uint8_t {
/// Do not diagnose uses of protocols in versions before they were introduced.
Expand Down Expand Up @@ -192,6 +193,10 @@ class ExportContext {
/// because it is the function body context of an inlinable function.
bool mustOnlyReferenceExportedDecls() const;

/// If true, the context reference a dependency of \p originKind without
/// restriction.
bool canReferenceOrigin(DisallowedOriginKind originKind) const;

/// Get the ExportabilityReason for diagnostics. If this is 'None', there
/// are no restrictions on referencing unexported declarations.
std::optional<ExportabilityReason> getExportabilityReason() const;
Expand Down
4 changes: 4 additions & 0 deletions test/Sema/access-level-import-embedded.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import indirects

internal func localInternalFunc() {} // expected-note {{global function 'localInternalFunc()' is not '@usableFromInline' or public}}

typealias AliasToDirect = StructFromDirect

@inlinable
public func explicitlyInlinable(arg: StructFromDirect = StructFromDirect()) {
// expected-error @-1 {{initializer 'init()' is internal and cannot be referenced from a default argument value}}
Expand Down Expand Up @@ -75,6 +77,8 @@ public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect()
implicitlyInlinablePublic()
implicitlyInlinablePrivate()
explicitNonInliable()

let _: AliasToDirect
}

internal func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect()) {
Expand Down
4 changes: 4 additions & 0 deletions test/Sema/implementation-only-import-embedded.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ internal func localInternalFunc() {} // expected-note {{global function 'localIn

@_spi(S) public func localSPI() {}

typealias AliasToDirect = StructFromDirect

@inlinable
public func explicitlyInlinable(arg: StructFromDirect = StructFromDirect()) {
// expected-error @-1 {{initializer 'init()' cannot be used in a default argument value because 'directs' was imported implementation-only}}
Expand Down Expand Up @@ -82,6 +84,8 @@ public func implicitlyInlinablePublic(arg: StructFromDirect = StructFromDirect()

localSPI()
spiFunctionFromDirect()

let _: AliasToDirect // expected-error {{AliasToDirect' aliases 'directs.StructFromDirect' and cannot be used in an embedded function not marked '@_neverEmitIntoClient' because 'directs' has been imported as implementation-only}}
}

private func implicitlyInlinablePrivate(arg: StructFromDirect = StructFromDirect()) {
Expand Down
237 changes: 237 additions & 0 deletions test/Sema/restricted-import-embedded-inlinable-conformances.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -o %t/NormalLibrary.swiftmodule \
// RUN: %S/Inputs/implementation-only-import-in-decls-public-helper.swift \
// RUN: -swift-version 5 -target arm64-apple-none-macho \
// RUN: -enable-experimental-feature Embedded
// RUN: %target-swift-frontend -emit-module -o %t/BADLibrary.swiftmodule \
// RUN: %S/Inputs/implementation-only-import-in-decls-helper.swift -I %t \
// RUN: -swift-version 5 -target arm64-apple-none-macho \
// RUN: -enable-experimental-feature Embedded

/// Access-level on imports allow references from implicitly inlinable code.
// RUN: %target-typecheck-verify-swift -I %t \
// RUN: -swift-version 5 -target arm64-apple-none-macho \
// RUN: -enable-experimental-feature Embedded \
// RUN: -verify-additional-prefix access-level-

/// @_implementationOnly rejects references from implicitly inlinable code.
// RUN: %target-typecheck-verify-swift -I %t \
// RUN: -swift-version 5 -target arm64-apple-none-macho \
// RUN: -enable-experimental-feature Embedded \
// RUN: -D IOI -verify-additional-prefix ioi-

// REQUIRES: swift_feature_Embedded
// REQUIRES: embedded_stdlib_cross_compiling

#if IOI
@_implementationOnly import BADLibrary // expected-ioi-warning {{using '@_implementationOnly' without enabling library evolution for 'main' may lead to instability during execution}}
#else
internal import BADLibrary // expected-access-level-note 35 {{imported as 'internal' from 'BADLibrary' here}}
#endif
import NormalLibrary

public typealias NormalProtoAssoc<T: NormalProto> = T.Assoc
@inlinable func testConformanceInTypealias() {
let x: NormalProtoAssoc<NormalStruct>? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
_ = x
_ = NormalProtoAssoc<NormalStruct>() // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
}

func internalConformanceInTypealias() {
let x: NormalProtoAssoc<NormalStruct>? = nil // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
_ = x
_ = NormalProtoAssoc<NormalStruct>() // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
}

@_neverEmitIntoClient
func internalConformanceInTypealiasNEIC() {
let x: NormalProtoAssoc<NormalStruct>? = nil // okay
_ = x
_ = NormalProtoAssoc<NormalStruct>() // okay
}

public struct NormalProtoAssocHolder<T: NormalProto> {
public var value: T.Assoc?
public init() {}
public init(_ value: T?) {}
}
@inlinable func testConformanceInBoundGeneric() {
let x: NormalProtoAssocHolder<NormalStruct>? = nil // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
_ = x
// FIXME: We get this error twice: once for the TypeExpr and once for the implicit init.
_ = NormalProtoAssocHolder<NormalStruct>() // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
_ = NormalProtoAssocHolder(nil as NormalStruct?) // expected-error 2{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
}

func internalConformanceInBoundGeneric() {
let x: NormalProtoAssocHolder<NormalStruct>? = nil // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
_ = x
_ = NormalProtoAssocHolder<NormalStruct>() // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
_ = NormalProtoAssocHolder(nil as NormalStruct?) // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}}
}

@_neverEmitIntoClient
func internalConformanceInBoundGenericNEIC() {
let x: NormalProtoAssocHolder<NormalStruct>? = nil // okay
_ = x
_ = NormalProtoAssocHolder<NormalStruct>() // okay
_ = NormalProtoAssocHolder(nil as NormalStruct?) // okay
}

@inlinable func testDowncast(_ x: Any) -> Bool {
let normal = x is NormalProtoAssocHolder<NormalStruct> // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
let alias = x is NormalProtoAssoc<NormalStruct> // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
return normal || alias
}

func internalDowncast(_ x: Any) -> Bool {
let normal = x is NormalProtoAssocHolder<NormalStruct> // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
let alias = x is NormalProtoAssoc<NormalStruct> // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
return normal || alias
}

@_neverEmitIntoClient
func internalDowncastNEIC(_ x: Any) -> Bool {
let normal = x is NormalProtoAssocHolder<NormalStruct> // okay
let alias = x is NormalProtoAssoc<NormalStruct> // okay
return normal || alias
}

@inlinable func testSwitch(_ x: Any) {
switch x {
case let holder as NormalProtoAssocHolder<NormalStruct>: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
_ = holder
break
case is NormalProtoAssoc<NormalStruct>: // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
break
default:
break
}
}

func internalSwitch(_ x: Any) {
switch x {
case let holder as NormalProtoAssocHolder<NormalStruct>: // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
_ = holder
break
case is NormalProtoAssoc<NormalStruct>: // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
break
default:
break
}
}

@_neverEmitIntoClient
func internalSwitchNEIC(_ x: Any) {
switch x {
case let holder as NormalProtoAssocHolder<NormalStruct>: // okay
_ = holder
break
case is NormalProtoAssoc<NormalStruct>: // okay
break
default:
break
}
}

public enum NormalProtoEnumUser<T: NormalProto> {
case a
}

@inlinable func testEnum() {
// FIXME: We get this error twice: once for the pattern and once for the implicit TypeExpr.
let x: NormalProtoEnumUser<NormalStruct> = .a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
_ = x
// FIXME: We get this error twice: once for the TypeExpr and once for the case.
_ = NormalProtoEnumUser<NormalStruct>.a // expected-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
}

func internalEnum() {
let x: NormalProtoEnumUser<NormalStruct> = .a // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
_ = x
_ = NormalProtoEnumUser<NormalStruct>.a // expected-ioi-error 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
}

@_neverEmitIntoClient
func internalEnumNEIC() {
let x: NormalProtoEnumUser<NormalStruct> = .a // okay
_ = x
_ = NormalProtoEnumUser<NormalStruct>.a // okay
}

@usableFromInline func testFuncImpl<T: NormalProto>(_: T.Type) {}

@inlinable func testFunc() {
testFuncImpl(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
}

func internalFunc() {
testFuncImpl(NormalStruct.self) // expected-ioi-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary' has been imported as implementation-only}}
}

@_neverEmitIntoClient
func internalFuncNEIC() {
testFuncImpl(NormalStruct.self) // okay
}

public struct ForTestingMembers {
public init() {}
public init<T: NormalProto>(_: T.Type) {}

public subscript<T: NormalProto>(_: T.Type) -> Int {
get { return 0 }
set {}
}

public func method<T: NormalProto>(_: T.Type) {}
}

@inlinable func testMembers() {
_ = ForTestingMembers(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
_ = ForTestingMembers.init(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}

_ = ForTestingMembers()[NormalStruct.self] // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
var instance = ForTestingMembers()
instance[NormalStruct.self] = 1 // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}

ForTestingMembers().method(NormalStruct.self) // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
}

extension NormalProtoAssocHolder {
public static func testAnotherConformance<U: NormalProto>(_: U.Type) {}
}

@inlinable func testMultipleConformances() {
NormalProtoAssocHolder<NormalStruct>.testAnotherConformance(NormalClass.self)
// expected-error@-1 2 {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
// expected-error@-2 {{cannot use conformance of 'NormalClass' to 'NormalProto' here; 'BADLibrary'}}
}

@inlinable func localTypeAlias() {
typealias LocalUser = NormalProtoAssocHolder<NormalStruct> // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
typealias LocalGenericUser<T> = (T, NormalProtoAssocHolder<NormalStruct>) // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}

typealias LocalProtoAssoc<T: NormalProto> = T.Assoc
_ = LocalProtoAssoc<NormalStruct>() // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
}

@inlinable func localFunctions() {
func local(_: NormalProtoAssocHolder<NormalStruct>) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
func localReturn() -> NormalProtoAssocHolder<NormalStruct> { fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
let _ = { (_: NormalProtoAssocHolder<NormalStruct>) in return } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
let _ = { () -> NormalProtoAssocHolder<NormalStruct> in fatalError() } // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}
}

@inlinable public func signatureOfInlinable(_: NormalProtoAssocHolder<NormalStruct>) {} // expected-error{{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}

public func testDefaultArgument(_: Int = NormalProtoAssoc<NormalStruct>()) {} // expected-error {{cannot use conformance of 'NormalStruct' to 'NormalProto' here; 'BADLibrary'}}


public class SubclassOfNormalClass: NormalClass {}

@inlinable public func testInheritedConformance() {
_ = NormalProtoAssocHolder<SubclassOfNormalClass>.self // expected-error {{cannot use conformance of 'NormalClass' to 'NormalProto' here; 'BADLibrary'}}
}
@inlinable public func testSpecializedConformance() {
_ = NormalProtoAssocHolder<GenericStruct<Int>>.self // expected-error {{cannot use conformance of 'GenericStruct<T>' to 'NormalProto' here; 'BADLibrary'}}
}