Skip to content
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

Support lifetime dependence inference on getters #71677

Merged
merged 3 commits into from
Feb 16, 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
18 changes: 12 additions & 6 deletions lib/Sema/LifetimeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,18 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd, Type resultType) {
return llvm::None;
}

if (afd->getKind() == DeclKind::Func && afd->hasImplicitSelfDecl()) {
auto ownership = afd->getImplicitSelfDecl()->getValueOwnership();
if (afd->getKind() != DeclKind::Constructor && afd->hasImplicitSelfDecl()) {
ValueOwnership ownership = ValueOwnership::Default;
if (auto *AD = dyn_cast<AccessorDecl>(afd)) {
if (AD->getAccessorKind() == AccessorKind::Get) {
// We don't support "borrowing/consuming" ownership modifiers on
// getters, by default they are guaranteed for now.
ownership = ValueOwnership::Shared;
}
} else {
ownership = afd->getImplicitSelfDecl()->getValueOwnership();
}

if (ownership == ValueOwnership::Default) {
diags.diagnose(
returnLoc,
Expand Down Expand Up @@ -338,10 +348,6 @@ LifetimeDependenceInfo::infer(AbstractFunctionDecl *afd, Type resultType) {
llvm::Optional<LifetimeDependenceInfo>
LifetimeDependenceInfo::get(AbstractFunctionDecl *afd, Type resultType,
bool allowIndex) {
if (afd->getKind() != DeclKind::Func &&
afd->getKind() != DeclKind::Constructor) {
return llvm::None;
}
auto *returnTypeRepr = afd->getResultTypeRepr();
if (isa_and_nonnull<LifetimeDependentReturnTypeRepr>(returnTypeRepr)) {
return LifetimeDependenceInfo::fromTypeRepr(afd, resultType, allowIndex);
Expand Down
5 changes: 3 additions & 2 deletions lib/Sema/TypeCheckStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1709,8 +1709,9 @@ Stmt *PreCheckReturnStmtRequest::evaluate(Evaluator &evaluator, ReturnStmt *RS,

auto *E = RS->getResult();

// In an initializer, the only expression allowed is "nil", which indicates
// failure from a failable initializer.
// In an initializer, the only expressions allowed are "nil", which indicates
// failure from a failable initializer or "self" in the case of ~Escapable
// initializers with explicit lifetime dependence.
if (auto *ctor =
dyn_cast_or_null<ConstructorDecl>(fn->getAbstractFunctionDecl())) {

Expand Down
60 changes: 60 additions & 0 deletions test/SIL/buffer_view_prototype.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// RUN: %target-swift-frontend %s -emit-sil \
// RUN: -disable-experimental-parser-round-trip \
// RUN: -enable-experimental-feature NonescapableTypes \
// RUN: -enable-experimental-feature NoncopyableGenerics \
// RUN: -enable-experimental-lifetime-dependence-inference \
// RUN: -Xllvm -enable-lifetime-dependence-diagnostics
// REQUIRES: noncopyable_generics

public struct BufferView<Element> : ~Escapable {
public typealias Index = Int
public typealias Pointer = UnsafePointer<Element>
public let baseAddress: Pointer
public let count: Int

// TODO: This should be a failable initializer
// Currently optional is Escapable, so we cant yet write it.
public init<Storage>(unsafeBuffer: UnsafeBufferPointer<Element>,
storage: borrowing Storage)
-> _borrow(storage) Self {
let baseAddress = unsafeBuffer.baseAddress!
self = BufferView<Element>(baseAddress: baseAddress,
count: unsafeBuffer.count)
return self
}
// unsafe private API
@_unsafeNonescapableResult
init(baseAddress: Pointer, count: Int) {
precondition(count >= 0, "Count must not be negative")
self.baseAddress = baseAddress
self.count = count
}
subscript(_ index: Index) -> Element? {
if (index < 0 || index >= count) {
return nil
}
return baseAddress[index]
}
}

extension Array {
// var view: BufferView<Element> {
// withUnsafeBufferPointer {
// return BufferView(unsafeBuffer: $0, storage: self)
// }
// }
// TODO: Implementation of getter should not need a temporary
// rdar://123071321
var view: BufferView<Element> {
var _view : BufferView<Element>?
withUnsafeBufferPointer {
_view = BufferView(unsafeBuffer: $0, storage: self)
}
return _view!
}
}

public func array_view_element(a: [Int] , i: Int) -> Int {
a.view[i]!
}

13 changes: 13 additions & 0 deletions test/SIL/implicit_lifetime_dependence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,16 @@ struct Wrapper : ~Escapable {
return view
}
}

struct Container : ~Copyable {
var ptr: UnsafeRawBufferPointer
// CHECK: sil hidden @$s28implicit_lifetime_dependence9ContainerV4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container) -> _scope(0) @owned BufferView {
var view: BufferView {
get {
return BufferView(ptr)
}
set(newView) {
ptr = newView.ptr
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,19 @@ public func consumeAndCreate(_ view: consuming BufferView) -> BufferView {
return BufferView(view.ptr)
}

public struct Container : ~Copyable {
var ptr: UnsafeRawBufferPointer

public init(_ ptr: UnsafeRawBufferPointer) {
self.ptr = ptr
}

public var view: BufferView {
get {
return BufferView(ptr)
}
set(newView) {
ptr = newView.ptr
}
}
}
11 changes: 11 additions & 0 deletions test/Serialization/implicit_lifetime_dependence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ func unsafetest(_ ptr: UnsafeRawBufferPointer) {
use(view3)
}

func testGetter() {
let capacity = 4
let a = Array(0..<capacity)
a.withUnsafeBytes {
let c = Container($0)
let view = c.view
use(view)
}
}

// CHECK: sil @$s32def_implicit_lifetime_dependence6deriveyAA10BufferViewVADYlsF : $@convention(thin) (@guaranteed BufferView) -> _scope(1) @owned BufferView

// CHECK: sil @$s32def_implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnYliF : $@convention(thin) (@owned BufferView) -> _inherit(1) @owned BufferView
Expand All @@ -54,3 +64,4 @@ func unsafetest(_ ptr: UnsafeRawBufferPointer) {

// CHECK: sil @$s32def_implicit_lifetime_dependence10BufferViewVyA2ChYlscfC : $@convention(method) (@guaranteed BufferView, @thin BufferView.Type) -> _scope(1) @owned BufferView

// CHECK: sil @$s32def_implicit_lifetime_dependence9ContainerV4viewAA10BufferViewVvg : $@convention(method) (@guaranteed Container) -> _scope(0) @owned BufferView