Skip to content
Draft
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
2 changes: 1 addition & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5908,7 +5908,7 @@ class AbstractStorageDecl : public ValueDecl {
friend class SetterAccessLevelRequest;
friend class IsGetterMutatingRequest;
friend class IsSetterMutatingRequest;
friend class OpaqueReadOwnershipRequest;
friend class DirectOpaqueReadOwnershipRequest;
friend class StorageImplInfoRequest;
friend class RequiresOpaqueAccessorsRequest;
friend class RequiresOpaqueModifyCoroutineRequest;
Expand Down
8 changes: 4 additions & 4 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -1750,10 +1750,10 @@ class IsSetterMutatingRequest :
};

/// Request whether reading the storage yields a borrowed value.
class OpaqueReadOwnershipRequest :
public SimpleRequest<OpaqueReadOwnershipRequest,
OpaqueReadOwnership(AbstractStorageDecl *),
RequestFlags::SeparatelyCached> {
class DirectOpaqueReadOwnershipRequest
: public SimpleRequest<DirectOpaqueReadOwnershipRequest,
OpaqueReadOwnership(AbstractStorageDecl *),
RequestFlags::SeparatelyCached> {
public:
using SimpleRequest::SimpleRequest;

Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ SWIFT_REQUEST(TypeChecker, EnumElementExprPatternRequest,
SWIFT_REQUEST(TypeChecker, ResolvePatternRequest,
Pattern *(Pattern *, DeclContext *, bool),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, OpaqueReadOwnershipRequest,
SWIFT_REQUEST(TypeChecker, DirectOpaqueReadOwnershipRequest,
OpaqueReadOwnership(AbstractStorageDecl *), SeparatelyCached,
NoLocationInfo)
SWIFT_REQUEST(TypeChecker, OpaqueResultTypeRequest,
Expand Down
21 changes: 18 additions & 3 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3722,10 +3722,25 @@ AbstractStorageDecl::mutabilityInSwift(
return mutability(useDC, base);
}

static OpaqueReadOwnership
getDirectOpaqueReadOwnership(AbstractStorageDecl const *self) {
ASTContext &ctx = self->getASTContext();
return evaluateOrDefault(
ctx.evaluator,
DirectOpaqueReadOwnershipRequest{const_cast<AbstractStorageDecl *>(self)},
{});
}

OpaqueReadOwnership AbstractStorageDecl::getOpaqueReadOwnership() const {
ASTContext &ctx = getASTContext();
return evaluateOrDefault(ctx.evaluator,
OpaqueReadOwnershipRequest{const_cast<AbstractStorageDecl *>(this)}, {});
auto *root = this;
while (true) {
auto *super = root->getOverriddenDecl();
if (!super)
break;
root = super;
}

return getDirectOpaqueReadOwnership(root);
}

bool ValueDecl::isInstanceMember() const {
Expand Down
7 changes: 4 additions & 3 deletions lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -774,18 +774,19 @@ void IsSetterMutatingRequest::cacheResult(bool value) const {
}

//----------------------------------------------------------------------------//
// OpaqueReadOwnershipRequest computation.
// DirectOpaqueReadOwnershipRequest computation.
//----------------------------------------------------------------------------//

std::optional<OpaqueReadOwnership>
OpaqueReadOwnershipRequest::getCachedResult() const {
DirectOpaqueReadOwnershipRequest::getCachedResult() const {
auto *storage = std::get<0>(getStorage());
if (storage->LazySemanticInfo.OpaqueReadOwnershipComputed)
return OpaqueReadOwnership(storage->LazySemanticInfo.OpaqueReadOwnership);
return std::nullopt;
}

void OpaqueReadOwnershipRequest::cacheResult(OpaqueReadOwnership value) const {
void DirectOpaqueReadOwnershipRequest::cacheResult(
OpaqueReadOwnership value) const {
auto *storage = std::get<0>(getStorage());
storage->setOpaqueReadOwnership(value);
}
Expand Down
68 changes: 38 additions & 30 deletions lib/Sema/TypeCheckStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -839,33 +839,34 @@ IsSetterMutatingRequest::evaluate(Evaluator &evaluator,
llvm_unreachable("bad storage kind");
}

OpaqueReadOwnership
OpaqueReadOwnershipRequest::evaluate(Evaluator &evaluator,
AbstractStorageDecl *storage) const {
auto abiRole = ABIRoleInfo(storage);
if (!abiRole.providesAPI() && abiRole.getCounterpart())
return abiRole.getCounterpart()->getOpaqueReadOwnership();

enum class DiagKind {
BorrowedAttr,
NoncopyableType
};
namespace {
enum class DirectOpaqueReadOwnershipRequestDiagKind {
BorrowedAttr,
NoncopyableType
};

void diagnoseEffectfulGetterOnBorrowingRead(
AbstractStorageDecl *storage,
DirectOpaqueReadOwnershipRequestDiagKind kind) {
auto *getter = storage->getEffectfulGetAccessor();
if (!getter)
return;
// Check for effects on the getter.
switch (kind) {
case DirectOpaqueReadOwnershipRequestDiagKind::NoncopyableType:
getter->diagnose(diag::noncopyable_effectful_getter, getter);
break;
case DirectOpaqueReadOwnershipRequestDiagKind::BorrowedAttr:
getter->diagnose(diag::borrowed_with_effect, getter);
break;
}
}

auto usesBorrowed = [&](DiagKind kind) -> OpaqueReadOwnership {
// Check for effects on the getter.
if (auto *getter = storage->getEffectfulGetAccessor()) {
switch (kind) {
case DiagKind::NoncopyableType:
getter->diagnose(diag::noncopyable_effectful_getter, getter);
break;
case DiagKind::BorrowedAttr:
getter->diagnose(diag::borrowed_with_effect, getter);
break;
}
}
return OpaqueReadOwnership::Borrowed;
};
} // end anonymous namespace

OpaqueReadOwnership
DirectOpaqueReadOwnershipRequest::evaluate(Evaluator &evaluator,
AbstractStorageDecl *storage) const {
if (auto *accessorDecl = storage->getAccessor(AccessorKind::Read)) {
auto lifetimeDependencies = accessorDecl->getLifetimeDependencies();
if (lifetimeDependencies.has_value() && !lifetimeDependencies->empty()) {
Expand All @@ -884,12 +885,19 @@ OpaqueReadOwnershipRequest::evaluate(Evaluator &evaluator,
if (storage->getAccessor(AccessorKind::Borrow))
return OpaqueReadOwnership::Borrowed;

if (storage->getAttrs().hasAttribute<BorrowedAttr>())
return usesBorrowed(DiagKind::BorrowedAttr);
using DiagKind = DirectOpaqueReadOwnershipRequestDiagKind;

if (storage->getAttrs().hasAttribute<BorrowedAttr>()) {
diagnoseEffectfulGetterOnBorrowingRead(storage, DiagKind::BorrowedAttr);
return OpaqueReadOwnership::Borrowed;
}

if (storage->getInnermostDeclContext()->mapTypeIntoContext(
storage->getValueInterfaceType())->isNoncopyable())
return usesBorrowed(DiagKind::NoncopyableType);
if (storage->getInnermostDeclContext()
->mapTypeIntoContext(storage->getValueInterfaceType())
->isNoncopyable()) {
diagnoseEffectfulGetterOnBorrowingRead(storage, DiagKind::NoncopyableType);
return OpaqueReadOwnership::Borrowed;
}

return OpaqueReadOwnership::Owned;
}
Expand Down
50 changes: 50 additions & 0 deletions test/Interpreter/borrowed_storage_override.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// RUN: %target-run-simple-swift | %FileCheck %s

// REQUIRES: executable_test

protocol P {
var i: Int { get }
}

class C : P {
@_borrowed
var i: Int

init() {
self.i = 5
}
}

class D : C {
override var i: Int {
get {42}
set {}
}
}

func getFromC(_ c: C) -> Int {
return c.i
}

func getFromD(_ c: D) -> Int {
return c.i
}

func getFromP<T : P>(_ c: T) -> Int {
return c.i
}

func doit() {
let c = D()
let ic = getFromC(c)
print("as C:", ic)
// CHECK: as C: 42
let id = getFromD(c)
print("as D:", id)
// CHECK: as D: 42
let ip = getFromP(c)
print("as P:", ip)
// CHECK: as P: 42
}

doit()