Skip to content

Commit afd8acc

Browse files
committed
[move-only] Add a move only request to lookup if a ValueDecl is a "move only type".
I also created a SILType::isMoveOnly() helper that returns true if a type is a move only wrapped type or a first class move only type. The verifier check that move only types aren't copied in canonical SIL was rewired to use that as well.
1 parent d73c538 commit afd8acc

14 files changed

+130
-9
lines changed

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/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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,3 +924,9 @@ SILType::getSingletonAggregateFieldType(SILModule &M,
924924

925925
return SILType();
926926
}
927+
928+
bool SILType::isMoveOnly() const {
929+
if (auto *nom = getNominalOrBoundGenericNominal())
930+
return nom->isMoveOnly();
931+
return isMoveOnlyWrapped();
932+
}

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/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) {

lib/Sema/TypeCheckDecl.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,41 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "TypeCheckDecl.h"
1718
#include "CodeSynthesis.h"
1819
#include "DerivedConformances.h"
19-
#include "TypeChecker.h"
20+
#include "MiscDiagnostics.h"
2021
#include "TypeCheckAccess.h"
2122
#include "TypeCheckAvailability.h"
2223
#include "TypeCheckConcurrency.h"
23-
#include "TypeCheckDecl.h"
2424
#include "TypeCheckObjC.h"
2525
#include "TypeCheckType.h"
26-
#include "MiscDiagnostics.h"
27-
#include "swift/AST/AccessScope.h"
26+
#include "TypeChecker.h"
2827
#include "swift/AST/ASTPrinter.h"
2928
#include "swift/AST/ASTVisitor.h"
3029
#include "swift/AST/ASTWalker.h"
30+
#include "swift/AST/AccessScope.h"
31+
#include "swift/AST/Attr.h"
3132
#include "swift/AST/ExistentialLayout.h"
3233
#include "swift/AST/Expr.h"
3334
#include "swift/AST/ForeignErrorConvention.h"
3435
#include "swift/AST/GenericEnvironment.h"
3536
#include "swift/AST/Initializer.h"
3637
#include "swift/AST/NameLookup.h"
38+
#include "swift/AST/NameLookupRequests.h"
3739
#include "swift/AST/OperatorNameLookup.h"
3840
#include "swift/AST/PrettyStackTrace.h"
3941
#include "swift/AST/PropertyWrappers.h"
4042
#include "swift/AST/ProtocolConformance.h"
4143
#include "swift/AST/SourceFile.h"
44+
#include "swift/AST/TypeCheckRequests.h"
4245
#include "swift/AST/TypeWalker.h"
46+
#include "swift/Basic/Defer.h"
4347
#include "swift/Parse/Lexer.h"
4448
#include "swift/Parse/Parser.h"
4549
#include "swift/Sema/IDETypeChecking.h"
4650
#include "swift/Serialization/SerializedModuleLoader.h"
4751
#include "swift/Strings.h"
48-
#include "swift/AST/NameLookupRequests.h"
49-
#include "swift/AST/TypeCheckRequests.h"
50-
#include "swift/Basic/Defer.h"
5152
#include "llvm/ADT/APFloat.h"
5253
#include "llvm/ADT/APInt.h"
5354
#include "llvm/ADT/APSInt.h"
@@ -898,6 +899,13 @@ IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
898899
return false;
899900
}
900901

902+
bool IsMoveOnlyRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
903+
// For now only do this for nominal type decls.
904+
if (isa<NominalTypeDecl>(decl))
905+
return decl->getAttrs().hasAttribute<MoveOnlyAttr>();
906+
return false;
907+
}
908+
901909
bool
902910
IsStaticRequest::evaluate(Evaluator &evaluator, FuncDecl *decl) const {
903911
if (auto *accessor = dyn_cast<AccessorDecl>(decl))

lib/Sema/TypeCheckDecl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@
1818
#ifndef SWIFT_TYPECHECKING_TYPECHECKDECL_H
1919
#define SWIFT_TYPECHECKING_TYPECHECKDECL_H
2020

21+
#include "swift/Basic/LLVM.h"
22+
2123
namespace swift {
2224

2325
class ASTContext;
2426
class DeclContext;
2527
class ValueDecl;
2628
class Pattern;
29+
class ConstructorDecl;
30+
class EnumDecl;
31+
class SourceFile;
32+
class PrecedenceGroupDecl;
2733

2834
/// Walks up the override chain for \p CD until it finds an initializer that is
2935
/// required and non-implicit. If no such initializer exists, returns the

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,7 @@ namespace {
15141514
UNINTERESTING_ATTR(Inlinable)
15151515
UNINTERESTING_ATTR(Effects)
15161516
UNINTERESTING_ATTR(Final)
1517+
UNINTERESTING_ATTR(MoveOnly)
15171518
UNINTERESTING_ATTR(FixedLayout)
15181519
UNINTERESTING_ATTR(Lazy)
15191520
UNINTERESTING_ATTR(LLDBDebuggerFunction)

test/Sema/moveonly_decl_attr.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-typecheck-verify-swift -parse-stdlib -disable-availability-checking -verify-syntax-tree
2+
3+
import Swift
4+
5+
@_moveOnly
6+
class C {
7+
@_moveOnly // expected-error {{'@_moveOnly' attribute cannot be applied to this declaration}}
8+
func foo() {}
9+
}
10+
11+
@_moveOnly
12+
struct S {
13+
@_moveOnly // expected-error {{'@_moveOnly' attribute cannot be applied to this declaration}}
14+
func foo() {}
15+
}
16+
17+
@_moveOnly
18+
enum E {
19+
@_moveOnly // expected-error {{'@_moveOnly' attribute cannot be applied to this declaration}}
20+
func foo() {}
21+
}
22+
23+
@_moveOnly let l = C() // expected-error {{'@_moveOnly' attribute cannot be applied to this declaration}}

0 commit comments

Comments
 (0)