Skip to content

Commit b044958

Browse files
authored
Merge pull request #60187 from gottesmm/moveonly_type_begin
[move-only] Implement very initial work for move only
2 parents e796ec7 + 65c21b6 commit b044958

24 files changed

+515
-21
lines changed

include/swift/AST/Attr.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,12 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(_local, KnownToBeLocal,
735735
APIBreakingToAdd | APIBreakingToRemove,
736736
130)
737737

738+
SIMPLE_DECL_ATTR(_moveOnly, MoveOnly,
739+
OnNominalType |
740+
UserInaccessible |
741+
ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
742+
131)
743+
738744
// If you're adding a new underscored attribute here, please document it in
739745
// docs/ReferenceGuides/UnderscoredAttributes.md.
740746

include/swift/AST/Decl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2262,12 +2262,19 @@ class ValueDecl : public Decl {
22622262
/// Whether this declaration produces an implicitly unwrapped
22632263
/// optional result.
22642264
unsigned isIUO : 1;
2265+
2266+
/// Whether the "isMoveOnly" bit has been computed yet.
2267+
unsigned isMoveOnlyComputed : 1;
2268+
2269+
/// Whether this declaration can not be copied and thus is move only.
2270+
unsigned isMoveOnly : 1;
22652271
} LazySemanticInfo = { };
22662272

22672273
friend class DynamicallyReplacedDeclRequest;
22682274
friend class OverriddenDeclsRequest;
22692275
friend class IsObjCRequest;
22702276
friend class IsFinalRequest;
2277+
friend class IsMoveOnlyRequest;
22712278
friend class IsDynamicRequest;
22722279
friend class IsImplicitlyUnwrappedOptionalRequest;
22732280
friend class InterfaceTypeRequest;
@@ -2542,6 +2549,9 @@ class ValueDecl : public Decl {
25422549
/// Is this declaration 'final'?
25432550
bool isFinal() const;
25442551

2552+
/// Is this declaration 'moveOnly'?
2553+
bool isMoveOnly() const;
2554+
25452555
/// Is this declaration marked with 'dynamic'?
25462556
bool isDynamic() const;
25472557

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6396,5 +6396,8 @@ ERROR(concurrency_task_to_thread_model_global_actor_annotation,none,
63966396
"annotating a type with a global actor %0 is not permitted within %1",
63976397
(TypeRepr*, StringRef))
63986398

6399+
ERROR(moveOnly_not_allowed_here,none,
6400+
"'moveOnly' may only be applied to classes, structs, and enums", ())
6401+
63996402
#define UNDEFINE_DIAGNOSTIC_MACROS
64006403
#include "DefineDiagnosticMacros.h"

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,26 @@ class IsFinalRequest :
395395
void cacheResult(bool value) const;
396396
};
397397

398+
/// Determine whether the given declaration is 'moveOnly'.
399+
class IsMoveOnlyRequest
400+
: public SimpleRequest<IsMoveOnlyRequest, bool(ValueDecl *),
401+
RequestFlags::SeparatelyCached> {
402+
public:
403+
using SimpleRequest::SimpleRequest;
404+
405+
private:
406+
friend SimpleRequest;
407+
408+
// Evaluation.
409+
bool evaluate(Evaluator &evaluator, ValueDecl *decl) const;
410+
411+
public:
412+
// Separate caching.
413+
bool isCached() const { return true; }
414+
Optional<bool> getCachedResult() const;
415+
void cacheResult(bool value) const;
416+
};
417+
398418
/// Determine whether the given declaration is 'dynamic''.
399419
class IsDynamicRequest :
400420
public SimpleRequest<IsDynamicRequest,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),
207207
SeparatelyCached, NoLocationInfo)
208208
SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,
209209
NoLocationInfo)
210+
SWIFT_REQUEST(TypeChecker, IsMoveOnlyRequest, bool(ValueDecl *), SeparatelyCached,
211+
NoLocationInfo)
210212
SWIFT_REQUEST(TypeChecker, IsGetterMutatingRequest, bool(AbstractStorageDecl *),
211213
SeparatelyCached, NoLocationInfo)
212214
SWIFT_REQUEST(TypeChecker, IsImplicitlyUnwrappedOptionalRequest,

include/swift/SIL/SILInstruction.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7587,8 +7587,8 @@ class MarkMustCheckInst
75877587
OwnershipForwardingMixin(SILInstructionKind::MarkMustCheckInst,
75887588
operand->getOwnershipKind()),
75897589
kind(checkKind) {
7590-
assert(operand->getType().isMoveOnlyWrapped() &&
7591-
"mark_must_check can only take a move only wrapped value");
7590+
assert(operand->getType().isMoveOnly() &&
7591+
"mark_must_check can only take a move only typed value");
75927592
}
75937593

75947594
public:

include/swift/SIL/SILType.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,10 @@ class SILType {
601601
/// Returns true if this is the AnyObject SILType;
602602
bool isAnyObject() const { return getASTType()->isAnyObject(); }
603603

604+
/// Returns true if this type is a first class move only type or a move only
605+
/// wrapped type.
606+
bool isMoveOnly() const;
607+
604608
/// Returns true if this SILType is a move only wrapper type.
605609
///
606610
/// Canonical way to check if a SILType is move only. Using is/getAs/castTo

lib/AST/Decl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3102,6 +3102,12 @@ bool ValueDecl::isFinal() const {
31023102
getAttrs().hasAttribute<FinalAttr>());
31033103
}
31043104

3105+
bool ValueDecl::isMoveOnly() const {
3106+
return evaluateOrDefault(getASTContext().evaluator,
3107+
IsMoveOnlyRequest{const_cast<ValueDecl *>(this)},
3108+
getAttrs().hasAttribute<MoveOnlyAttr>());
3109+
}
3110+
31053111
bool ValueDecl::isDynamic() const {
31063112
ASTContext &ctx = getASTContext();
31073113
return evaluateOrDefault(ctx.evaluator,

lib/AST/TypeCheckRequests.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,29 @@ void IsFinalRequest::cacheResult(bool value) const {
305305
decl->getAttrs().add(new (decl->getASTContext()) FinalAttr(/*Implicit=*/true));
306306
}
307307

308+
//----------------------------------------------------------------------------//
309+
// isMoveOnly computation.
310+
//----------------------------------------------------------------------------//
311+
312+
Optional<bool> IsMoveOnlyRequest::getCachedResult() const {
313+
auto decl = std::get<0>(getStorage());
314+
if (decl->LazySemanticInfo.isMoveOnlyComputed)
315+
return decl->LazySemanticInfo.isMoveOnly;
316+
317+
return None;
318+
}
319+
320+
void IsMoveOnlyRequest::cacheResult(bool value) const {
321+
auto decl = std::get<0>(getStorage());
322+
decl->LazySemanticInfo.isMoveOnlyComputed = true;
323+
decl->LazySemanticInfo.isMoveOnly = value;
324+
325+
// Add an attribute for printing
326+
if (value && !decl->getAttrs().hasAttribute<MoveOnlyAttr>())
327+
decl->getAttrs().add(new (decl->getASTContext())
328+
MoveOnlyAttr(/*Implicit=*/true));
329+
}
330+
308331
//----------------------------------------------------------------------------//
309332
// isDynamic computation.
310333
//----------------------------------------------------------------------------//

lib/SIL/IR/SILType.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,3 +924,11 @@ SILType::getSingletonAggregateFieldType(SILModule &M,
924924

925925
return SILType();
926926
}
927+
928+
// TODO: Create isPureMoveOnly.
929+
bool SILType::isMoveOnly() const {
930+
if (auto *nom = getNominalOrBoundGenericNominal())
931+
if (nom->isMoveOnly())
932+
return true;
933+
return isMoveOnlyWrapped();
934+
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2701,8 +2701,8 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
27012701
"copy_value is only valid in functions with qualified "
27022702
"ownership");
27032703
require(I->getModule().getStage() == SILStage::Raw ||
2704-
!I->getOperand()->getType().isMoveOnlyWrapped(),
2705-
"@moveOnly types can only be copied in Raw SIL?!");
2704+
!I->getOperand()->getType().isMoveOnly(),
2705+
"'MoveOnly' types can only be copied in Raw SIL?!");
27062706
}
27072707

27082708
void checkDestroyValueInst(DestroyValueInst *I) {

lib/SILGen/SILGenConstructor.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/AST/PropertyWrappers.h"
2727
#include "swift/Basic/Defer.h"
2828
#include "swift/SIL/SILArgument.h"
29+
#include "swift/SIL/SILInstruction.h"
2930
#include "swift/SIL/SILUndef.h"
3031
#include "swift/SIL/TypeLowering.h"
3132

@@ -386,6 +387,7 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
386387

387388
// Allocate the local variable for 'self'.
388389
emitLocalVariableWithCleanup(selfDecl, MUIKind)->finishInitialization(*this);
390+
389391
SILValue selfLV = VarLocs[selfDecl].value;
390392

391393
// Emit the prolog.
@@ -831,6 +833,11 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
831833
StoreOwnershipQualifier::Init);
832834
} else {
833835
selfArg = B.createMarkUninitialized(selfDecl, selfArg, MUKind);
836+
if (selfArg.getType().isMoveOnly()) {
837+
assert(selfArg.getOwnershipKind() == OwnershipKind::Owned);
838+
selfArg = B.createMarkMustCheckInst(
839+
selfDecl, selfArg, MarkMustCheckInst::CheckKind::NoImplicitCopy);
840+
}
834841
VarLocs[selfDecl] = VarLoc::get(selfArg.getValue());
835842
}
836843
}

lib/SILGen/SILGenDecl.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -572,15 +572,21 @@ class LetValueInitialization : public Initialization {
572572
// why we want this is even if we are only performing a borrow for our
573573
// lexical lifetime, we want to ensure that our defs see this
574574
// initialization as consuming this value.
575-
if (value->getType().isMoveOnlyWrapped() &&
576-
value->getOwnershipKind() == OwnershipKind::Owned) {
575+
if (value->getOwnershipKind() == OwnershipKind::Owned) {
577576
assert(wasPlusOne);
578577
// NOTE: If our type is trivial when not wrapped in a
579578
// SILMoveOnlyWrappedType, this will return a trivial value. We rely
580579
// on the checker to determine if this is an acceptable use of the
581580
// value.
582-
value = SGF.B.createOwnedMoveOnlyWrapperToCopyableValue(PrologueLoc,
583-
value);
581+
if (value->getType().isMoveOnly()) {
582+
if (value->getType().isMoveOnlyWrapped()) {
583+
value = SGF.B.createOwnedMoveOnlyWrapperToCopyableValue(
584+
PrologueLoc, value);
585+
} else {
586+
// Change this to be lexical and get rid of borrow scope?
587+
value = SGF.B.createMoveValue(PrologueLoc, value);
588+
}
589+
}
584590
}
585591

586592
// If we still have a non-trivial thing, emit code that will need to

lib/SILGen/SILGenPattern.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2835,9 +2835,13 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
28352835
auto subject = ([&]() -> ConsumableManagedValue {
28362836
// If we have a move only value, ensure plus one and convert it. Switches
28372837
// always consume move only values.
2838-
if (subjectMV.getType().isMoveOnlyWrapped()) {
2839-
subjectMV = B.createOwnedMoveOnlyWrapperToCopyableValue(
2840-
S, subjectMV.ensurePlusOne(*this, S));
2838+
if (subjectMV.getType().isMoveOnly()) {
2839+
if (subjectMV.getType().isMoveOnlyWrapped()) {
2840+
subjectMV = B.createOwnedMoveOnlyWrapperToCopyableValue(
2841+
S, subjectMV.ensurePlusOne(*this, S));
2842+
} else {
2843+
subjectMV = B.createMoveValue(S, subjectMV.ensurePlusOne(*this, S));
2844+
}
28412845
}
28422846

28432847
// If we have a plus one value...

lib/SILGen/SILGenProlog.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,20 @@ struct ArgumentInitHelper {
314314
loc, value, MarkMustCheckInst::CheckKind::NoImplicitCopy);
315315
SGF.emitManagedRValueWithCleanup(value);
316316
}
317+
} else if (value->getType().isMoveOnly()) {
318+
if (value->getOwnershipKind() == OwnershipKind::Owned) {
319+
value = SGF.B.createMoveValue(loc, argrv.forward(SGF),
320+
/*isLexical*/ true);
321+
value = SGF.B.createMarkMustCheckInst(
322+
loc, value, MarkMustCheckInst::CheckKind::NoImplicitCopy);
323+
SGF.emitManagedRValueWithCleanup(value);
324+
} else {
325+
assert(value->getOwnershipKind() == OwnershipKind::Guaranteed);
326+
value = SGF.B.createCopyValue(loc, value);
327+
value = SGF.B.createMarkMustCheckInst(
328+
loc, value, MarkMustCheckInst::CheckKind::NoCopy);
329+
SGF.emitManagedRValueWithCleanup(value);
330+
}
317331
} else {
318332
if (value->getOwnershipKind() == OwnershipKind::Owned) {
319333
value = SILValue(

lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#define DEBUG_TYPE "definite-init"
14+
1415
#include "DIMemoryUseCollector.h"
1516
#include "swift/AST/Expr.h"
1617
#include "swift/SIL/ApplySite.h"
1718
#include "swift/SIL/InstructionUtils.h"
1819
#include "swift/SIL/SILArgument.h"
1920
#include "swift/SIL/SILBuilder.h"
21+
#include "swift/SIL/SILInstruction.h"
2022
#include "swift/SILOptimizer/Utils/DistributedActor.h"
2123
#include "llvm/ADT/StringExtras.h"
2224
#include "llvm/Support/Debug.h"
@@ -1211,6 +1213,7 @@ void ElementUseCollector::collectClassSelfUses(SILValue ClassPointer) {
12111213
Uses.append(beginAccess->getUses().begin(), beginAccess->getUses().end());
12121214
continue;
12131215
}
1216+
12141217
if (isa<EndAccessInst>(User))
12151218
continue;
12161219

@@ -1489,9 +1492,9 @@ void ElementUseCollector::collectClassSelfUses(
14891492

14901493
// Look through begin_borrow, upcast, unchecked_ref_cast
14911494
// and copy_value.
1492-
if (isa<BeginBorrowInst>(User) || isa<BeginAccessInst>(User)
1493-
|| isa<UpcastInst>(User) || isa<UncheckedRefCastInst>(User)
1494-
|| isa<CopyValueInst>(User)) {
1495+
if (isa<BeginBorrowInst>(User) || isa<BeginAccessInst>(User) ||
1496+
isa<UpcastInst>(User) || isa<UncheckedRefCastInst>(User) ||
1497+
isa<CopyValueInst>(User) || isa<MarkMustCheckInst>(User)) {
14951498
auto value = cast<SingleValueInstruction>(User);
14961499
std::copy(value->use_begin(), value->use_end(),
14971500
std::back_inserter(Worklist));

lib/SILOptimizer/Mandatory/MoveOnlyChecker.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,46 @@ bool MoveOnlyChecker::searchForCandidateMarkMustChecks() {
543543
if (!mmci || !mmci->hasMoveCheckerKind())
544544
continue;
545545

546+
// Handle guaranteed/owned move only typed arguments.
547+
//
548+
// We are pattern matching against these patterns:
549+
//
550+
// bb0(%0 : @guaranteed $T):
551+
// %1 = copy_value %0
552+
// %2 = mark_must_check [no_copy] %1
553+
// bb0(%0 : @owned $T):
554+
// %1 = copy_value %0
555+
// %2 = mark_must_check [no_copy] %1
556+
if (mmci->getOperand()->getType().isMoveOnly() &&
557+
!mmci->getOperand()->getType().isMoveOnlyWrapped()) {
558+
if (auto *cvi = dyn_cast<CopyValueInst>(mmci->getOperand())) {
559+
if (auto *arg = dyn_cast<SILFunctionArgument>(cvi->getOperand())) {
560+
if (arg->getOwnershipKind() == OwnershipKind::Guaranteed) {
561+
moveIntroducersToProcess.insert(mmci);
562+
continue;
563+
}
564+
}
565+
}
566+
567+
if (auto *mvi = dyn_cast<MoveValueInst>(mmci->getOperand())) {
568+
if (mvi->isLexical()) {
569+
if (auto *arg = dyn_cast<SILFunctionArgument>(mvi->getOperand())) {
570+
if (arg->getOwnershipKind() == OwnershipKind::Owned) {
571+
moveIntroducersToProcess.insert(mmci);
572+
continue;
573+
}
574+
}
575+
}
576+
}
577+
578+
if (auto *arg = dyn_cast<SILFunctionArgument>(mmci->getOperand())) {
579+
if (arg->getOwnershipKind() == OwnershipKind::Owned) {
580+
moveIntroducersToProcess.insert(mmci);
581+
continue;
582+
}
583+
}
584+
}
585+
546586
// Handle guaranteed arguments.
547587
//
548588
// We are pattern matching this pattern:

lib/Sema/TypeCheckAttr.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
218218
}
219219

220220
void visitFinalAttr(FinalAttr *attr);
221+
void visitMoveOnlyAttr(MoveOnlyAttr *attr);
221222
void visitCompileTimeConstAttr(CompileTimeConstAttr *attr) {}
222223
void visitIBActionAttr(IBActionAttr *attr);
223224
void visitIBSegueActionAttr(IBSegueActionAttr *attr);
@@ -1909,6 +1910,14 @@ void AttributeChecker::visitFinalAttr(FinalAttr *attr) {
19091910
}
19101911
}
19111912

1913+
void AttributeChecker::visitMoveOnlyAttr(MoveOnlyAttr *attr) {
1914+
if (isa<NominalTypeDecl>(D))
1915+
return;
1916+
1917+
diagnose(attr->getLocation(), diag::moveOnly_not_allowed_here)
1918+
.fixItRemove(attr->getRange());
1919+
}
1920+
19121921
/// Return true if this is a builtin operator that cannot be defined in user
19131922
/// code.
19141923
static bool isBuiltinOperator(StringRef name, DeclAttribute *attr) {

0 commit comments

Comments
 (0)