Skip to content

[6.0][AST/Sema] Make it possible to use init accessors in inlinable initializers #75243

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 5 commits into from
Sep 3, 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
4 changes: 2 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -6855,8 +6855,8 @@ ERROR(frozen_attr_on_internal_type,

ERROR(usable_from_inline_attr_with_explicit_access,
none, "'@usableFromInline' attribute can only be applied to internal or package "
"declarations, but %0 is %select{private|fileprivate|%error|package|public|open}1",
(DeclName, AccessLevel))
"declarations, but %kind0 is %select{private|fileprivate|%error|package|public|open}1",
(const ValueDecl *, AccessLevel))

WARNING(inlinable_implies_usable_from_inline,none,
"'@usableFromInline' attribute has no effect on '@inlinable' %kind0",
Expand Down
5 changes: 0 additions & 5 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,11 +352,6 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
}
}

if (auto *accessor = dyn_cast<AccessorDecl>(D)) {
if (accessor->isInitAccessor() && !options.PrintForSIL)
return false;
}

return ShouldPrintChecker::shouldPrint(D, options);
}
};
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/AccessRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ AccessLevelRequest::evaluate(Evaluator &evaluator, ValueDecl *D) const {
// These are only needed to synthesize the setter.
return AccessLevel::Private;
case AccessorKind::Init:
// These are only called from designated initializers.
return AccessLevel::Private;
// These are only called from within the same module.
return AccessLevel::Internal;
}
}

Expand Down
13 changes: 12 additions & 1 deletion lib/Sema/ResilienceDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
auto *DC = where.getDeclContext();
auto &Context = DC->getASTContext();

if (auto *init = dyn_cast<ConstructorDecl>(DC)) {
if (init->isDesignatedInit()) {
auto *storage = dyn_cast<AbstractStorageDecl>(D);
if (storage && storage->hasInitAccessor()) {
if (diagnoseInlinableDeclRefAccess(
loc, storage->getAccessor(AccessorKind::Init), where))
return true;
}
}
}

ImportAccessLevel problematicImport = D->getImportAccessFrom(DC);
if (problematicImport.has_value()) {
auto SF = DC->getParentSourceFile();
Expand Down Expand Up @@ -111,7 +122,7 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,

// Swift 4.2 did not check accessor accessibility.
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
if (!Context.isSwiftVersionAtLeast(5))
if (!accessor->isInitAccessor() && !Context.isSwiftVersionAtLeast(5))
downgradeToWarning = DowngradeToWarning::Yes;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3206,7 +3206,7 @@ void AttributeChecker::visitUsableFromInlineAttr(UsableFromInlineAttr *attr) {
VD->getFormalAccess() != AccessLevel::Package) {
diagnoseAndRemoveAttr(attr,
diag::usable_from_inline_attr_with_explicit_access,
VD->getName(), VD->getFormalAccess());
VD, VD->getFormalAccess());
return;
}

Expand Down
8 changes: 4 additions & 4 deletions test/Compatibility/attr_usableFromInline_swift4.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// RUN: %target-typecheck-verify-swift -enable-testing -swift-version 4 -disable-objc-attr-requires-foundation-module -enable-objc-interop

@usableFromInline private func privateVersioned() {}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'privateVersioned()' is private}}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'privateVersioned()' is private}}

@usableFromInline fileprivate func fileprivateVersioned() {}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'fileprivateVersioned()' is fileprivate}}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'fileprivateVersioned()' is fileprivate}}

@usableFromInline internal func internalVersioned() {}
// OK
Expand All @@ -14,11 +14,11 @@
// OK

@usableFromInline public func publicVersioned() {}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'publicVersioned()' is public}}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'publicVersioned()' is public}}

internal class InternalClass {
@usableFromInline public func publicVersioned() {}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'publicVersioned()' is public}}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but instance method 'publicVersioned()' is public}}
}

fileprivate class filePrivateClass {
Expand Down
8 changes: 4 additions & 4 deletions test/Compatibility/attr_usableFromInline_swift42.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// RUN: %target-typecheck-verify-swift -enable-testing -swift-version 4.2 -disable-objc-attr-requires-foundation-module -enable-objc-interop

@usableFromInline private func privateVersioned() {}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'privateVersioned()' is private}}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'privateVersioned()' is private}}

@usableFromInline fileprivate func fileprivateVersioned() {}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'fileprivateVersioned()' is fileprivate}}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'fileprivateVersioned()' is fileprivate}}

@usableFromInline internal func internalVersioned() {}
// OK
Expand All @@ -14,12 +14,12 @@
// OK

@usableFromInline public func publicVersioned() {}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'publicVersioned()' is public}}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but global function 'publicVersioned()' is public}}

internal class InternalClass {
// expected-note@-1 2{{type declared here}}
@usableFromInline public func publicVersioned() {}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but 'publicVersioned()' is public}}
// expected-error@-1 {{'@usableFromInline' attribute can only be applied to internal or package declarations, but instance method 'publicVersioned()' is public}}
}

fileprivate class filePrivateClass {
Expand Down
79 changes: 79 additions & 0 deletions test/Interpreter/inlinable_init_accessors.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// RUN: %empty-directory(%t/src)
// RUN: split-file %s %t/src

// RUN: %target-build-swift %t/src/Library.swift -swift-version 5 -emit-module -emit-library \
// RUN: -enable-library-evolution \
// RUN: -module-name Library \
// RUN: -o %t/%target-library-name(Library) \
// RUN: -emit-module-interface-path %t/Library.swiftinterface

// RUN: %target-codesign %t/%target-library-name(Library)

// RUN: %target-build-swift -I %t -L %t -l Library %t/src/main.swift %target-rpath(%t) -o %t/main.out
// RUN: %target-codesign %t/main.out
// RUN: %target-run %t/main.out %t/%target-library-name(Library) 2>&1 | %FileCheck %t/src/main.swift

// RUN: rm %t/Library.swiftmodule

// RUN: %target-build-swift -I %t -L %t -l Library %t/src/main.swift %target-rpath(%t) -o %t/main.out
// RUN: %target-codesign %t/main.out
// RUN: %target-run %t/main.out %t/%target-library-name(Library) 2>&1 | %FileCheck %t/src/main.swift

// REQUIRES: executable_test

//--- Library.swift
@frozen
public struct Inlinable {
var _x: Int

public var x: Int {
@usableFromInline
@storageRestrictions(initializes: _x)
init {
self._x = newValue
}

get {
_x
}
}

@inlinable
public init(x: Int) {
self.x = x
}
}

@frozen
public struct Transparent {
@usableFromInline
var _x: Int

public var x: Int {
@_alwaysEmitIntoClient
@storageRestrictions(initializes: _x)
init {
self._x = newValue
}

get {
_x
}
}

@_alwaysEmitIntoClient
public init(x: Int) {
self.x = x
}
}

//--- main.swift
import Library

let inlinable = Inlinable(x: 42)
print("Inlinable.x = \(inlinable.x)")
// CHECK: Inlinable.x = 42

let transparent = Transparent(x: -1)
print("Transparent.x = \(transparent.x)")
// CHECK: Transparent.x = -1
123 changes: 123 additions & 0 deletions test/ModuleInterface/init_accessors.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// RUN: %empty-directory(%t/src)
// RUN: split-file %s %t/src

/// Build the library A
// RUN: %target-swift-frontend -emit-module %t/src/A.swift \
// RUN: -module-name A -swift-version 5 -enable-library-evolution \
// RUN: -emit-module-path %t/A.swiftmodule \
// RUN: -emit-module-interface-path %t/A.swiftinterface

// RUN: %FileCheck %t/src/A.swift < %t/A.swiftinterface

// Build the client using module
// RUN: %target-swift-emit-sil -verify -module-name Client -I %t %t/src/Client.swift | %FileCheck %t/src/Client.swift

// RUN: rm %t/A.swiftmodule

// Re-build the client using interface
// RUN: %target-swift-emit-sil -verify -module-name Client -I %t %t/src/Client.swift | %FileCheck %t/src/Client.swift

// REQUIRES: asserts

//--- A.swift
@frozen
public struct Inlinable {
var _x: Int

// CHECK: public var x: Swift.Int {
// CHECK-NEXT: @usableFromInline
// CHECK-NEXT: @storageRestrictions(initializes: _x) init
// CHECK-NEXT: get
// CHECK-NEXT }

public var x: Int {
@usableFromInline
@storageRestrictions(initializes: _x)
init {
self._x = newValue
}

get {
_x
}
}

@inlinable
public init(x: Int) {
self.x = x
}
}

public struct Internal {
// CHECK: public var y: Swift.Int {
// CHECK-NEXT: get
// CHECK-NEXT: }

public var y: Int {
init {
}

get { 0 }
}

init(y: Int) {
self.y = y
}
}

@frozen
public struct Transparent {
@usableFromInline
var _x: Int

// CHECK: public var x: Swift.Int {
// CHECK-NEXT: @_alwaysEmitIntoClient @storageRestrictions(initializes: _x) init {
// CHECK-NEXT: self._x = newValue
// CHECK-NEXT: }
// CHECK-NEXT: get
// CHECK-NEXT }

public var x: Int {
@_alwaysEmitIntoClient
@storageRestrictions(initializes: _x)
init {
self._x = newValue
}

get {
_x
}
}

@_alwaysEmitIntoClient
public init(x: Int) {
self.x = x
}
}

//--- Client.swift
import A

// CHECK-LABEL: sil hidden @$s6Client15testTransparentyyF : $@convention(thin) () -> ()
// CHECK: [[X:%.*]] = struct $Int (%1 : $Builtin.Int64)
// CHECK-NEXT: // function_ref Transparent.init(x:)
// CHECK-NEXT: [[TRANSPARENT_REF:%.*]] = function_ref @$s1A11TransparentV1xACSi_tcfC : $@convention(method) (Int, @thin Transparent.Type) -> Transparent
// CHECK-NEXT: apply [[TRANSPARENT_REF]]([[X]], %0) : $@convention(method) (Int, @thin Transparent.Type) -> Transparent
func testTransparent() {
_ = Transparent(x: 42)
}

// CHECK-LABEL: sil shared @$s1A11TransparentV1xACSi_tcfC : $@convention(method) (Int, @thin Transparent.Type) -> Transparent

// CHECK-LABEL: sil hidden @$s6Client13testInlinableyyF : $@convention(thin) () -> ()
// CHECK: [[X:%.*]] = struct $Int (%1 : $Builtin.Int64)
// CHECK-NEXT: // function_ref Inlinable.init(x:)
// CHECK-NEXT: [[INLINABLE_REF:%.*]] = function_ref @$s1A9InlinableV1xACSi_tcfC : $@convention(method) (Int, @thin Inlinable.Type) -> Inlinable
// CHECK-NEXT: apply [[INLINABLE_REF]]([[X]], %0) : $@convention(method) (Int, @thin Inlinable.Type) -> Inlinable
func testInlinable() {
_ = Inlinable(x: 42)
}

// CHECK-LABEL: sil @$s1A9InlinableV1xACSi_tcfC : $@convention(method) (Int, @thin Inlinable.Type) -> Inlinable

// CHECK-LABEL: sil shared @$s1A11TransparentV1xSivi : $@convention(thin) (Int, @thin Transparent.Type) -> @out Int
8 changes: 4 additions & 4 deletions test/SILOptimizer/init_accessors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ struct TestInit {
var full: (Int, Int)

var point: (Int, Int) {
// CHECK-LABEL: sil private [ossa] @$s14init_accessors8TestInitV5pointSi_Sitvi : $@convention(thin) (Int, Int, @inout Int, @thin TestInit.Type) -> (@out Int, @out (Int, Int))
// CHECK-LABEL: sil hidden [ossa] @$s14init_accessors8TestInitV5pointSi_Sitvi : $@convention(thin) (Int, Int, @inout Int, @thin TestInit.Type) -> (@out Int, @out (Int, Int))
// CHECK: bb0([[Y_REF:%.*]] : $*Int, [[FULL_REF:%.*]] : $*(Int, Int), [[X_VAL:%.*]] : $Int, [[Y_VAL:%.*]] : $Int, [[X_REF:%.*]] : $*Int, [[METATYPE:%.*]] : $@thin TestInit.Type):
//
// CHECK: [[INITIAL_VALUE:%.*]] = tuple ([[X_VAL]] : $Int, [[Y_VAL]] : $Int)
Expand Down Expand Up @@ -230,7 +230,7 @@ class TestClass {
var y: (Int, [String])

var data: (Int, (Int, [String])) {
// CHECK-LABEL: sil private [ossa] @$s14init_accessors9TestClassC4dataSi_Si_SaySSGttvi : $@convention(thin) (Int, Int, @owned Array<String>, @thick TestClass.Type) -> (@out Int, @out (Int, Array<String>))
// CHECK-LABEL: sil hidden [ossa] @$s14init_accessors9TestClassC4dataSi_Si_SaySSGttvi : $@convention(thin) (Int, Int, @owned Array<String>, @thick TestClass.Type) -> (@out Int, @out (Int, Array<String>))
// CHECK: bb0([[X_REF:%.*]] : $*Int, [[Y_REF:%.*]] : $*(Int, Array<String>), [[X_VAL:%.*]] : $Int, [[Y_VAL_0:%.*]] : $Int, [[Y_VAL_1:%.*]] : @owned $Array<String>, [[METATYPE:%.*]] : $@thick TestClass.Type):
//
// CHECK: ([[X_VAL:%.*]], [[Y_VAL:%.*]]) = destructure_tuple {{.*}} : $(Int, (Int, Array<String>))
Expand Down Expand Up @@ -277,7 +277,7 @@ struct TestGeneric<T, U> {
var b: T
var c: U

// CHECK-LABEL: sil private [ossa] @$s14init_accessors11TestGenericV4datax_xtvi : $@convention(thin) <T, U> (@in T, @in T, @inout U, @thin TestGeneric<T, U>.Type) -> (@out T, @out T)
// CHECK-LABEL: sil hidden [ossa] @$s14init_accessors11TestGenericV4datax_xtvi : $@convention(thin) <T, U> (@in T, @in T, @inout U, @thin TestGeneric<T, U>.Type) -> (@out T, @out T)
//
// CHECK: bb0([[A_REF:%.*]] : $*T, [[B_REF:%.*]] : $*T, [[A_VALUE:%.*]] : $*T, [[B_VALUE:%.*]] : $*T, [[C_REF:%.*]] : $*U, [[METATYPE:%.*]] : $@thin TestGeneric<T, U>.Type):
//
Expand Down Expand Up @@ -326,7 +326,7 @@ struct TestGenericTuple<T, U> {
var a: T
var b: (T, U)

// CHECK-LABEL: sil private [ossa] @$s14init_accessors16TestGenericTupleV4datax_x_q_ttvi : $@convention(thin) <T, U> (@in T, @in T, @in U, @thin TestGenericTuple<T, U>.Type) -> (@out T, @out (T, U)) {
// CHECK-LABEL: sil hidden [ossa] @$s14init_accessors16TestGenericTupleV4datax_x_q_ttvi : $@convention(thin) <T, U> (@in T, @in T, @in U, @thin TestGenericTuple<T, U>.Type) -> (@out T, @out (T, U)) {
//
// CHECK: bb0([[A_REF:%.*]] : $*T, [[B_REF:%.*]] : $*(T, U), [[A_VALUE:%.*]] : $*T, [[B_VALUE:%.*]] : $*T, [[C_VALUE:%.*]] : $*U, [[METATYPE:%.*]] : $@thin TestGenericTuple<T, U>.Type):
//
Expand Down
29 changes: 28 additions & 1 deletion test/attr/attr_alwaysEmitIntoClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,31 @@ public func publicFunction() {}
internalFunction() // expected-error {{global function 'internalFunction()' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
versionedFunction()
publicFunction()
}
}

public struct TestInitAccessors {
var _x: Int

public var x: Int {
@storageRestrictions(initializes: _x)
init { // expected-note 2 {{init acecssor for property 'x' is not '@usableFromInline' or public}}
self._x = newValue
}

get {
self._x
}

set {}
}

@_alwaysEmitIntoClient
public init(x: Int) {
self.x = 0 // expected-error {{init acecssor for property 'x' is internal and cannot be referenced from an '@_alwaysEmitIntoClient' function}}
}

@inlinable
public init() {
self.x = 0 // expected-error {{init acecssor for property 'x' is internal and cannot be referenced from an '@inlinable' function}}
}
}
Loading