SILGen: Fix key paths that reference internal private(set) decls from other files.

The setter needs to be given hidden linkage so that other files can still form key paths to it.
This commit is contained in:
Joe Groff
2018-07-09 20:19:51 -07:00
parent b607e549f1
commit ae4d40ac85
8 changed files with 81 additions and 5 deletions

View File

@@ -315,7 +315,18 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {
}
}
switch (d->getEffectiveAccess()) {
auto effectiveAccess = d->getEffectiveAccess();
// Private setter implementations for an internal storage declaration should
// be internal as well, so that a dynamically-writable
// keypath can be formed from other files.
if (auto accessor = dyn_cast<AccessorDecl>(d)) {
if (accessor->isSetter()
&& accessor->getStorage()->getEffectiveAccess() == AccessLevel::Internal)
effectiveAccess = AccessLevel::Internal;
}
switch (effectiveAccess) {
case AccessLevel::Private:
case AccessLevel::FilePrivate:
return maybeAddExternal(SILLinkage::Private);

View File

@@ -0,0 +1,11 @@
struct A {
private(set) var x: Int {
get { return 0 }
set {}
}
private(set) subscript(x: Int) -> Int {
get { return x }
set {}
}
}

View File

@@ -105,7 +105,7 @@ internal struct PrivateSettersForReadOnlyInternal : PublicReadOnlyOperations {
// CHECK-DAG: sil hidden{{( \[.+\])*}} @$S22accessibility_warnings33PrivateSettersForReadOnlyInternalV4sizeSivg
public private(set) var size = 0
// CHECK-DAG: sil hidden @$S22accessibility_warnings33PrivateSettersForReadOnlyInternalVyS2icig
// CHECK-DAG: sil private @$S22accessibility_warnings33PrivateSettersForReadOnlyInternalVyS2icis
// CHECK-DAG: sil hidden @$S22accessibility_warnings33PrivateSettersForReadOnlyInternalVyS2icis
internal private(set) subscript (_: Int) -> Int { // no-warning
get { return 42 }
set {}

View File

@@ -213,7 +213,7 @@ struct Foo {
private(set) subscript(withPrivateSet x: Void) -> Void {
// CHECK-DAG: sil hidden @$S9accessors3FooV14withPrivateSetyyt_tcig : $@convention(method) (Foo) -> () {
get {}
// CHECK-DAG: sil private @$S9accessors3FooV14withPrivateSetyyt_tcis : $@convention(method) (@inout Foo) -> () {
// CHECK-DAG: sil hidden @$S9accessors3FooV14withPrivateSetyyt_tcis : $@convention(method) (@inout Foo) -> () {
set {}
}
subscript(withNestedClass x: Void) -> Void {
@@ -229,7 +229,7 @@ struct Foo {
private(set) var variableWithPrivateSet: Void {
// CHECK-DAG: sil hidden @$S9accessors3FooV22variableWithPrivateSetytvg : $@convention(method) (Foo) -> () {
get {}
// CHECK-DAG: sil private @$S9accessors3FooV22variableWithPrivateSetytvs : $@convention(method) (@inout Foo) -> () {
// CHECK-DAG: sil hidden @$S9accessors3FooV22variableWithPrivateSetytvs : $@convention(method) (@inout Foo) -> () {
set {}
}
var propertyWithNestedClass: Void {

View File

@@ -0,0 +1,20 @@
// RUN: %target-swift-emit-silgen -module-name keypaths -primary-file %s %S/Inputs/keypaths_multi_file_b.swift | %FileCheck %s
// RUN: %target-swift-emit-silgen -module-name keypaths %s -primary-file %S/Inputs/keypaths_multi_file_b.swift | %FileCheck --check-prefix=DEFINITION %s
func foo(x: Int) -> KeyPath<A, Int> {
switch x {
case 0:
return \A.x
default:
return \A.[0]
}
return \A.x
}
// A.x setter
// CHECK-LABEL: sil hidden_external @$S8keypaths1AV1xSivs
// DEFINITION-LABEL: sil hidden @$S8keypaths1AV1xSivs
// A.subscript setter
// CHECK-LABEL: sil hidden_external @$S8keypaths1AVyS2icis
// DEFINITION-LABEL: sil hidden @$S8keypaths1AVyS2icis

View File

@@ -0,0 +1,19 @@
struct A {
private(set) var x: Int {
get { return 0 }
set {}
}
private(set) subscript(x: Int) -> Int {
get { return 0 }
set {}
}
}
func A_x_keypath() -> WritableKeyPath<A, Int> {
return \A.x
}
func A_subscript_0_keypath() -> WritableKeyPath<A, Int> {
return \A.[0]
}

View File

@@ -1,5 +1,5 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift %s -Xfrontend -enable-sil-ownership -Xfrontend -g -o %t/a.out
// RUN: %target-build-swift %s -o %t/a.out
// RUN: %target-run %t/a.out
// REQUIRES: executable_test

View File

@@ -0,0 +1,15 @@
// RUN: %empty-directory(%t)
// RUN: cp %s %t/main.swift
// RUN: %target-build-swift -o %t/a.out %t/main.swift %S/Inputs/KeyPathMultiFile_b.swift
// RUN: %target-run %t/a.out
import StdlibUnittest
var keyPathMultiFile = TestSuite("key paths across multiple files")
keyPathMultiFile.test("identity across multiple files") {
expectEqual(A_x_keypath(), \A.x)
expectEqual(A_subscript_0_keypath(), \A.[0])
}
runAllTests()