Skip to content

[5.9][borrowing][consuming] Make borrowing and consuming no implicit copy parameters #66388

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 15 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
2471323
Revert "temporarily prevent Copyable types from using `consuming` and…
gottesmm May 29, 2023
b1c6c63
Revert "add and update tests for Copyable types not having ownership …
gottesmm May 29, 2023
96d58a4
Restore sema code that bans consuming from being applied to no escape…
gottesmm Jun 6, 2023
9e18031
[noimplicitcopy] When serializing SIL types, always use getRawASTType…
gottesmm May 30, 2023
76950f3
[noimplicitcopy] Be sure to register SILMoveOnlyWrappedTypeLayout wit…
gottesmm May 30, 2023
e4d0f31
[move-only] Expand FuncDecl's SelfAccessKind field so it can fit Cons…
gottesmm Jun 3, 2023
fb8078b
[borrowing/consuming] Add new instruction: moveonlywrapper_to_copyabl…
gottesmm May 30, 2023
ca8341a
[borrowing/consuming] Add a new instruction called copyable_to_moveon…
gottesmm Jun 4, 2023
c2c890a
Add some docs for copyable_to_moveonlywrapper_addr and moveonlywrappe…
gottesmm Jun 4, 2023
18b4d67
[sil-mode.el] Add syntax highlighting for noimplicit copy instructions.
gottesmm Jun 4, 2023
ae2e714
[move-only] Add a new instruction: moveonlywrapper_to_copyable_box.
gottesmm Jun 6, 2023
617fd26
[move-only] Fix class setters of address only move only types.
gottesmm May 31, 2023
72cd7c5
[borrowing] Add support for borrowing/consuming copyable types to be …
gottesmm May 29, 2023
bc3c631
[borrowing/consuming] Make both noimplicitcopy diagnostic tests run w…
gottesmm Jun 7, 2023
98cbeec
[borrowing/consuming] Be sure to visit boxes with trivial moveonly ty…
gottesmm Jun 7, 2023
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
27 changes: 27 additions & 0 deletions docs/SIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8460,6 +8460,33 @@ need for the guaranteed form in the future.
@moveOnly trivial type, we convert from the non-trivial representation to the
trivial representation.

copyable_to_moveonlywrapper_addr
````````````````````````````````
::

sil-instruction ::= 'copyable_to_moveonlywrapper_addr'

`copyable_to_moveonlywrapper_addr`_ takes in a '*T' and maps it to a move only
wrapped '*@moveOnly T'. This is semantically used by a code generator
initializing a new moveOnly binding from a copyable value. It semantically acts
as an address cast. If one thinks of '@moveOnly' as a monad, this is how one
injects a copyable value into the move only space.

moveonlywrapper_to_copyable_addr
````````````````````````````````
::

sil-instruction ::= 'moveonlywrapper_to_copyable_addr'

`moveonlywrapper_to_copyable_addr`_ takes in a '*@moveOnly T' and produces a new
'*T' value. This instruction acts like an address cast that projects out the
underlying T from an @moveOnly T.

NOTE: From the perspective of the address checker, a trivial `load`_ with a
`moveonlywrapper_to_copyable_addr`_ operand is considered to be a use of a
noncopyable type.


Assertion configuration
~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
42 changes: 29 additions & 13 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,26 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, StaticSpellingKind SSK);
/// Diagnostic printing of \c ReferenceOwnership.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceOwnership RO);

enum class SelfAccessKind : uint8_t {
NonMutating,
Mutating,
LegacyConsuming,
Consuming,
Borrowing,
LastSelfAccessKind = Borrowing,
};
enum : unsigned {
NumSelfAccessKindBits =
countBitsUsed(static_cast<unsigned>(SelfAccessKind::LastSelfAccessKind))
};
static_assert(uint8_t(SelfAccessKind::LastSelfAccessKind) <
(NumSelfAccessKindBits << 1),
"Self Access Kind is too small to fit in SelfAccess kind bits. "
"Please expand ");

/// Diagnostic printing of \c SelfAccessKind.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SelfAccessKind SAK);

/// Encapsulation of the overload signature of a given declaration,
/// which is used to determine uniqueness of a declaration within a
/// given context.
Expand Down Expand Up @@ -315,6 +335,10 @@ enum class ArtificialMainKind : uint8_t {
/// Decl - Base class for all declarations in Swift.
class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
protected:
// clang-format off
//
// We format these different than clang-format wishes us to... so turn if off
// for the inline bitfields.
union { uint64_t OpaqueBits;

SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+1,
Expand Down Expand Up @@ -456,7 +480,8 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
DistributedThunk: 1
);

SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2+1,
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl,
1+1+2+1+1+NumSelfAccessKindBits+1,
/// Whether we've computed the 'static' flag yet.
IsStaticComputed : 1,

Expand All @@ -473,7 +498,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
SelfAccessComputed : 1,

/// Backing bits for 'self' access kind.
SelfAccess : 2,
SelfAccess : NumSelfAccessKindBits,

/// Whether this is a top-level function which should be treated
/// as if it were in local context for the purposes of capture
Expand Down Expand Up @@ -735,6 +760,8 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
);

} Bits;
// Turn back on clang-format now that we have defined our inline bitfields.
// clang-format on

// Storage for the declaration attributes.
DeclAttributes Attrs;
Expand Down Expand Up @@ -7234,17 +7261,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {

class OperatorDecl;

enum class SelfAccessKind : uint8_t {
NonMutating,
Mutating,
LegacyConsuming,
Consuming,
Borrowing,
};

/// Diagnostic printing of \c SelfAccessKind.
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SelfAccessKind SAK);

/// FuncDecl - 'func' declaration.
class FuncDecl : public AbstractFunctionDecl {
friend class AbstractFunctionDecl;
Expand Down
8 changes: 7 additions & 1 deletion include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,11 @@ ERROR(sil_ref_inst_wrong_field,none,
ERROR(sil_invalid_instr_operands,none,
"invalid instruction operands", ())
ERROR(sil_operand_not_address,none,
"%0 operand of '%1' must have address type", (StringRef, StringRef))
"%0 of '%1' must have address type", (StringRef, StringRef))
ERROR(sil_operand_not_object,none,
"%0 of '%1' must have object type", (StringRef, StringRef))
ERROR(sil_operand_has_incorrect_moveonlywrapped,none,
"%0 of '%1' %select{must|must not}2 be of moveonlywrapped type", (StringRef, StringRef, unsigned))
ERROR(sil_operand_not_ref_storage_address,none,
"%0 operand of '%1' must have address of %2 type",
(StringRef, StringRef, ReferenceOwnership))
Expand Down Expand Up @@ -910,6 +914,8 @@ ERROR(sil_box_expected_r_brace,none,
"expected '}' to complete SIL box field type list", ())
ERROR(sil_box_expected_r_angle,none,
"expected '>' to complete SIL box generic argument list", ())
ERROR(sil_box_expected,none,
"%0 expects its operand to be of SIL box field type", (StringRef))

// SIL function types
ERROR(sil_function_subst_expected_l_angle,none,
Expand Down
4 changes: 3 additions & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -5291,7 +5291,9 @@ class SILMoveOnlyWrappedType final : public TypeBase,
SILMoveOnlyWrappedType(CanType innerType)
: TypeBase(TypeKind::SILMoveOnlyWrapped, &innerType->getASTContext(),
innerType->getRecursiveProperties()),
innerType(innerType) {}
innerType(innerType) {
assert(!innerType->isPureMoveOnly() && "Inner type must be copyable");
}

public:
CanType getInnerType() const { return innerType; }
Expand Down
3 changes: 3 additions & 0 deletions include/swift/SIL/MemAccessUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,9 @@ inline bool isAccessStorageTypeCast(SingleValueInstruction *svi) {
default:
return false;
// Simply pass-thru the incoming address. But change its type!
case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst:
case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst:
// Simply pass-thru the incoming address. But change its type!
case SILInstructionKind::UncheckedAddrCastInst:
// Casting to RawPointer does not affect the AccessPath. When converting
// between address types, they must be layout compatible (with truncation).
Expand Down
18 changes: 18 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,24 @@ class SILBuilder {
CopyableToMoveOnlyWrapperValueInst::Guaranteed));
}

MoveOnlyWrapperToCopyableBoxInst *
createMoveOnlyWrapperToCopyableBox(SILLocation loc, SILValue src) {
return insert(new (getModule()) MoveOnlyWrapperToCopyableBoxInst(
getSILDebugLocation(loc), src, src->getOwnershipKind()));
}

MoveOnlyWrapperToCopyableAddrInst *
createMoveOnlyWrapperToCopyableAddr(SILLocation loc, SILValue src) {
return insert(new (getModule()) MoveOnlyWrapperToCopyableAddrInst(
getSILDebugLocation(loc), src));
}

CopyableToMoveOnlyWrapperAddrInst *
createCopyableToMoveOnlyWrapperAddr(SILLocation loc, SILValue src) {
return insert(new (getModule()) CopyableToMoveOnlyWrapperAddrInst(
getSILDebugLocation(loc), src));
}

MoveOnlyWrapperToCopyableValueInst *
createOwnedMoveOnlyWrapperToCopyableValue(SILLocation loc, SILValue src) {
return insert(new (getModule()) MoveOnlyWrapperToCopyableValueInst(
Expand Down
27 changes: 27 additions & 0 deletions include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -1942,6 +1942,33 @@ void SILCloner<ImplClass>::visitMoveOnlyWrapperToCopyableValueInst(
recordClonedInstruction(inst, cvt);
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitMoveOnlyWrapperToCopyableBoxInst(
MoveOnlyWrapperToCopyableBoxInst *inst) {
getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope()));
recordClonedInstruction(
inst, getBuilder().createMoveOnlyWrapperToCopyableBox(
getOpLocation(inst->getLoc()), getOpValue(inst->getOperand())));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitMoveOnlyWrapperToCopyableAddrInst(
MoveOnlyWrapperToCopyableAddrInst *inst) {
getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope()));
recordClonedInstruction(
inst, getBuilder().createMoveOnlyWrapperToCopyableAddr(
getOpLocation(inst->getLoc()), getOpValue(inst->getOperand())));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitCopyableToMoveOnlyWrapperAddrInst(
CopyableToMoveOnlyWrapperAddrInst *inst) {
getBuilder().setCurrentDebugScope(getOpScope(inst->getDebugScope()));
recordClonedInstruction(
inst, getBuilder().createCopyableToMoveOnlyWrapperAddr(
getOpLocation(inst->getLoc()), getOpValue(inst->getOperand())));
}

template <typename ImplClass>
void SILCloner<ImplClass>::visitCopyableToMoveOnlyWrapperValueInst(
CopyableToMoveOnlyWrapperValueInst *inst) {
Expand Down
77 changes: 75 additions & 2 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,7 @@ FirstArgOwnershipForwardingSingleValueInst::classof(SILInstructionKind kind) {
case SILInstructionKind::InitExistentialRefInst:
case SILInstructionKind::MarkDependenceInst:
case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst:
case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst:
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst:
return true;
default:
Expand Down Expand Up @@ -8482,10 +8483,21 @@ class CopyableToMoveOnlyWrapperValueInst
DebugLoc, operand, operand->getType().addingMoveOnlyWrapper(),
kind == InitialKind::Guaranteed ? OwnershipKind::Guaranteed
: OwnershipKind::Owned),
initialKind(kind) {}
initialKind(kind) {
assert(!operand->getType().isMoveOnly() &&
"Cannot be moveonly or moveonly wrapped");
}

public:
InitialKind getInitialKind() const { return initialKind; }

bool hasGuaranteedInitialKind() const {
return getInitialKind() == InitialKind::Guaranteed;
}

bool hasOwnedInitialKind() const {
return getInitialKind() == InitialKind::Owned;
}
};

/// Convert from an @moveOnly wrapper type to the underlying copyable type. Can
Expand Down Expand Up @@ -8534,10 +8546,71 @@ class MoveOnlyWrapperToCopyableValueInst
DebugLoc, operand, operand->getType().removingMoveOnlyWrapper(),
kind == InitialKind::Guaranteed ? OwnershipKind::Guaranteed
: OwnershipKind::Owned),
initialKind(kind) {}
initialKind(kind) {
assert(operand->getType().isMoveOnlyWrapped() &&
"Expected moveonlywrapped argument!");
}

public:
InitialKind getInitialKind() const { return initialKind; }

bool hasGuaranteedInitialKind() const {
return getInitialKind() == InitialKind::Guaranteed;
}

bool hasOwnedInitialKind() const {
return getInitialKind() == InitialKind::Owned;
}
};

/// Convert a ${ @moveOnly T } to $T. This is a forwarding instruction that acts
/// similarly to an object cast like upcast, unlike
/// MoveOnlyWrapperToCopyableValue which provides artificial semantics injected
/// by SILGen.
class MoveOnlyWrapperToCopyableBoxInst
: public UnaryInstructionBase<
SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst,
FirstArgOwnershipForwardingSingleValueInst> {
friend class SILBuilder;

MoveOnlyWrapperToCopyableBoxInst(SILDebugLocation DebugLoc, SILValue operand,
ValueOwnershipKind forwardingOwnershipKind)
: UnaryInstructionBase(
DebugLoc, operand,
operand->getType().removingMoveOnlyWrapperToBoxedType(
operand->getFunction()),
forwardingOwnershipKind) {
assert(
operand->getType().isBoxedMoveOnlyWrappedType(operand->getFunction()) &&
"Expected moveonlywrapped argument!");
}
};

class CopyableToMoveOnlyWrapperAddrInst
: public UnaryInstructionBase<
SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst,
SingleValueInstruction> {
friend class SILBuilder;

CopyableToMoveOnlyWrapperAddrInst(SILDebugLocation DebugLoc, SILValue operand)
: UnaryInstructionBase(DebugLoc, operand,
operand->getType().addingMoveOnlyWrapper()) {
assert(!operand->getType().isMoveOnly() && "Expected copyable argument");
}
};

class MoveOnlyWrapperToCopyableAddrInst
: public UnaryInstructionBase<
SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst,
SingleValueInstruction> {
friend class SILBuilder;

MoveOnlyWrapperToCopyableAddrInst(SILDebugLocation DebugLoc, SILValue operand)
: UnaryInstructionBase(DebugLoc, operand,
operand->getType().removingMoveOnlyWrapper()) {
assert(operand->getType().isMoveOnlyWrapped() &&
"Expected moveonlywrapped argument");
}
};

/// Given an object reference, return true iff it is non-nil and refers
Expand Down
20 changes: 17 additions & 3 deletions include/swift/SIL/SILNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -490,11 +490,25 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
// and owned for assignment/owned function arguments.
SINGLE_VALUE_INST(CopyableToMoveOnlyWrapperValueInst, copyable_to_moveonlywrapper,
SingleValueInstruction, None, DoesNotRelease)
// Convert a $@moveOnly T to $T. Ownership is fixed at construction by
// Convert a $@moveOnly T object to $T. Ownership is fixed at construction by
// frontend to express specific semantics: guaranteed for function arguments
// and owned for assignment/return values.
SINGLE_VALUE_INST(MoveOnlyWrapperToCopyableValueInst, moveonlywrapper_to_copyable,
SingleValueInstruction, None, DoesNotRelease)
SINGLE_VALUE_INST(MoveOnlyWrapperToCopyableValueInst,
moveonlywrapper_to_copyable, SingleValueInstruction, None,
DoesNotRelease)
// Convert a ${ @moveOnly T } to $T. This is a forwarding instruction that
// acts similarly to an object cast, unlike MoveOnlyWrapperToCopyableValue.
SINGLE_VALUE_INST(MoveOnlyWrapperToCopyableBoxInst,
moveonlywrapper_to_copyable_box, SingleValueInstruction, None,
DoesNotRelease)
// Convert a $*@moveOnly T to $*T. Acts just as a cast.
SINGLE_VALUE_INST(MoveOnlyWrapperToCopyableAddrInst,
moveonlywrapper_to_copyable_addr, SingleValueInstruction,
None, DoesNotRelease)
// Convert a $*T to $*@moveOnly T. Acts just as a cast.
SINGLE_VALUE_INST(CopyableToMoveOnlyWrapperAddrInst,
copyable_to_moveonlywrapper_addr, SingleValueInstruction,
None, DoesNotRelease)
// A move_addr is a Raw SIL only instruction that is equivalent to a copy_addr
// [init]. It is lowered during the diagnostic passes to a copy_addr [init] if
// the move checker found uses that prevented us from converting this to a
Expand Down
24 changes: 22 additions & 2 deletions include/swift/SIL/SILType.h
Original file line number Diff line number Diff line change
Expand Up @@ -721,8 +721,8 @@ class SILType {
return getRawASTType()->is<SILMoveOnlyWrappedType>();
}

/// If this is already a move only wrapped type, return *this. Otherwise, wrap
/// the copyable type in the mov eonly wrapper.
/// If this is already a moveonlywrapped type, return *this. Otherwise, wrap
/// the copyable type in the moveonlywrapper.
SILType addingMoveOnlyWrapper() const {
if (isMoveOnlyWrapped())
return *this;
Expand All @@ -749,6 +749,20 @@ class SILType {
return *this;
}

/// If this is a box type containing a moveonlywrapped type, return a new box
/// with the moveonlywrapped type unwrapped.
///
/// DISCUSSION: This is separate from addingMoveOnlyWrapper since this API
/// requires a SILFunction * and is specialized.
SILType addingMoveOnlyWrapperToBoxedType(const SILFunction *fn);

/// If this is a box type containing a copyable type, return a new box type
/// with the copyable type wrapped in a moveonly wrapped type.
///
/// DISCUSSION: This is separate from removingMoveOnlyWrapper since this API
/// requires a SILFunction * and is specialized.
SILType removingMoveOnlyWrapperToBoxedType(const SILFunction *fn);

/// Returns a SILType with any archetypes mapped out of context.
SILType mapTypeOutOfContext() const;

Expand Down Expand Up @@ -799,6 +813,12 @@ class SILType {
return isBoxedNonCopyableType(&fn);
}

bool isBoxedMoveOnlyWrappedType(const SILFunction *fn) const {
if (!this->is<SILBoxType>())
return false;
return getSILBoxFieldType(fn).isMoveOnlyWrapped();
}

SILType getInstanceTypeOfMetatype(SILFunction *function) const;

bool isOrContainsObjectiveCClass() const;
Expand Down
Loading