Skip to content

[copy-operator] Add support for the copy operator in preparation for making consuming and borrowing no implicit copy. #65935

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 5 commits into from
May 19, 2023
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
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,8 @@ ERROR(expected_expr_after_await, none,
"expected expression after 'await'", ())
ERROR(expected_expr_after_move, none,
"expected expression after 'consume'", ())
ERROR(expected_expr_after_copy, none,
"expected expression after 'copy'", ())
ERROR(expected_expr_after_borrow, none,
"expected expression after '_borrow'", ())

Expand Down
6 changes: 5 additions & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -6992,10 +6992,14 @@ ERROR(concurrency_task_to_thread_model_global_actor_annotation,none,

ERROR(moveOnly_not_allowed_here,none,
"'moveOnly' only applies to structs or enums", ())
ERROR(move_expression_not_passed_lvalue,none,
ERROR(consume_expression_not_passed_lvalue,none,
"'consume' can only be applied to lvalues", ())
ERROR(borrow_expression_not_passed_lvalue,none,
"'borrow' can only be applied to lvalues", ())
ERROR(copy_expression_not_passed_lvalue,none,
"'copy' can only be applied to lvalues", ())
ERROR(copy_expression_cannot_be_used_with_noncopyable_types,none,
"'copy' cannot be applied to noncopyable types", ())

ERROR(moveOnly_requires_lexical_lifetimes,none,
"noncopyable types require lexical borrow scopes "
Expand Down
60 changes: 45 additions & 15 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2050,31 +2050,61 @@ class AwaitExpr final : public IdentityExpr {
}
};

/// MoveExpr - A 'move' surrounding an lvalue expression marking the lvalue as
/// needing to be moved.
///
/// getSemanticsProvidingExpr() looks through this because it doesn't
/// provide the value and only very specific clients care where the
/// 'move' was written.
class MoveExpr final : public IdentityExpr {
SourceLoc MoveLoc;
/// ConsumeExpr - A 'consume' surrounding an lvalue expression marking the
/// lvalue as needing to be moved.
class ConsumeExpr final : public Expr {
Expr *SubExpr;
SourceLoc ConsumeLoc;

public:
MoveExpr(SourceLoc moveLoc, Expr *sub, Type type = Type(),
ConsumeExpr(SourceLoc consumeLoc, Expr *sub, Type type = Type(),
bool implicit = false)
: Expr(ExprKind::Consume, implicit, type), SubExpr(sub),
ConsumeLoc(consumeLoc) {}

static ConsumeExpr *createImplicit(ASTContext &ctx, SourceLoc moveLoc,
Expr *sub, Type type = Type()) {
return new (ctx) ConsumeExpr(moveLoc, sub, type, /*implicit=*/true);
}

SourceLoc getLoc() const { return ConsumeLoc; }

Expr *getSubExpr() const { return SubExpr; }
void setSubExpr(Expr *E) { SubExpr = E; }

SourceLoc getStartLoc() const { return getLoc(); }
SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }

static bool classof(const Expr *e) {
return e->getKind() == ExprKind::Consume;
}
};

/// CopyExpr - A 'copy' surrounding an lvalue expression marking the lvalue as
/// needing a semantic copy. Used to force a copy of a no implicit copy type.
class CopyExpr final : public Expr {
Expr *SubExpr;
SourceLoc CopyLoc;

public:
CopyExpr(SourceLoc copyLoc, Expr *sub, Type type = Type(),
bool implicit = false)
: IdentityExpr(ExprKind::Move, sub, type, implicit), MoveLoc(moveLoc) {}
: Expr(ExprKind::Copy, implicit, type), SubExpr(sub), CopyLoc(copyLoc) {}

static MoveExpr *createImplicit(ASTContext &ctx, SourceLoc moveLoc, Expr *sub,
static CopyExpr *createImplicit(ASTContext &ctx, SourceLoc copyLoc, Expr *sub,
Type type = Type()) {
return new (ctx) MoveExpr(moveLoc, sub, type, /*implicit=*/true);
return new (ctx) CopyExpr(copyLoc, sub, type, /*implicit=*/true);
}

SourceLoc getLoc() const { return MoveLoc; }
SourceLoc getLoc() const { return CopyLoc; }

Expr *getSubExpr() const { return SubExpr; }
void setSubExpr(Expr *E) { SubExpr = E; }

SourceLoc getStartLoc() const { return MoveLoc; }
SourceLoc getStartLoc() const { return CopyLoc; }
SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }

static bool classof(const Expr *e) { return e->getKind() == ExprKind::Move; }
static bool classof(const Expr *e) { return e->getKind() == ExprKind::Copy; }
};

/// BorrowExpr - A 'borrow' surrounding an lvalue/accessor expression at an
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/ExprNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,11 @@ ABSTRACT_EXPR(Identity, Expr)
EXPR(Paren, IdentityExpr)
EXPR(DotSelf, IdentityExpr)
EXPR(Await, IdentityExpr)
EXPR(Move, IdentityExpr)
EXPR(Borrow, IdentityExpr)
EXPR(UnresolvedMemberChainResult, IdentityExpr)
EXPR_RANGE(Identity, Paren, UnresolvedMemberChainResult)
EXPR(Copy, Expr)
EXPR(Consume, Expr)
ABSTRACT_EXPR(AnyTry, Expr)
EXPR(Try, AnyTryExpr)
EXPR(ForceTry, AnyTryExpr)
Expand Down
10 changes: 8 additions & 2 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2194,8 +2194,14 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
printRec(E->getSubExpr());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void visitMoveExpr(MoveExpr *E) {
printCommon(E, "move_expr");
void visitConsumeExpr(ConsumeExpr *E) {
printCommon(E, "consume_expr");
OS << '\n';
printRec(E->getSubExpr());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
void visitCopyExpr(CopyExpr *E) {
printCommon(E, "copy_expr");
OS << '\n';
printRec(E->getSubExpr());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
Expand Down
9 changes: 7 additions & 2 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4995,8 +4995,13 @@ void PrintAST::visitAwaitExpr(AwaitExpr *expr) {
visit(expr->getSubExpr());
}

void PrintAST::visitMoveExpr(MoveExpr *expr) {
Printer << "move ";
void PrintAST::visitConsumeExpr(ConsumeExpr *expr) {
Printer << "consume ";
visit(expr->getSubExpr());
}

void PrintAST::visitCopyExpr(CopyExpr *expr) {
Printer << "copy ";
visit(expr->getSubExpr());
}

Expand Down
17 changes: 17 additions & 0 deletions lib/AST/ASTWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,23 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
}
return nullptr;
}

Expr *visitCopyExpr(CopyExpr *E) {
if (Expr *subExpr = doIt(E->getSubExpr())) {
E->setSubExpr(subExpr);
return E;
}
return nullptr;
}

Expr *visitConsumeExpr(ConsumeExpr *E) {
if (Expr *subExpr = doIt(E->getSubExpr())) {
E->setSubExpr(subExpr);
return E;
}
return nullptr;
}

Expr *visitTupleExpr(TupleExpr *E) {
for (unsigned i = 0, e = E->getNumElements(); i != e; ++i)
if (E->getElement(i)) {
Expand Down
10 changes: 6 additions & 4 deletions lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ SourceLoc Expr::getLoc() const {
Expr *Expr::getSemanticsProvidingExpr() {
if (auto *IE = dyn_cast<IdentityExpr>(this))
return IE->getSubExpr()->getSemanticsProvidingExpr();

if (auto *TE = dyn_cast<TryExpr>(this))
return TE->getSubExpr()->getSemanticsProvidingExpr();

Expand Down Expand Up @@ -371,7 +370,8 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
PASS_THROUGH_REFERENCE(UnresolvedMemberChainResult, getSubExpr);
PASS_THROUGH_REFERENCE(DotSelf, getSubExpr);
PASS_THROUGH_REFERENCE(Await, getSubExpr);
PASS_THROUGH_REFERENCE(Move, getSubExpr);
PASS_THROUGH_REFERENCE(Consume, getSubExpr);
PASS_THROUGH_REFERENCE(Copy, getSubExpr);
PASS_THROUGH_REFERENCE(Borrow, getSubExpr);
PASS_THROUGH_REFERENCE(Try, getSubExpr);
PASS_THROUGH_REFERENCE(ForceTry, getSubExpr);
Expand Down Expand Up @@ -743,7 +743,8 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
return true;

case ExprKind::Await:
case ExprKind::Move:
case ExprKind::Consume:
case ExprKind::Copy:
case ExprKind::Borrow:
case ExprKind::Try:
case ExprKind::ForceTry:
Expand Down Expand Up @@ -935,7 +936,8 @@ bool Expr::isValidParentOfTypeExpr(Expr *typeExpr) const {
case ExprKind::Sequence:
case ExprKind::Paren:
case ExprKind::Await:
case ExprKind::Move:
case ExprKind::Consume:
case ExprKind::Copy:
case ExprKind::Borrow:
case ExprKind::UnresolvedMemberChainResult:
case ExprKind::Try:
Expand Down
24 changes: 20 additions & 4 deletions lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,15 +409,31 @@ ParserResult<Expr> Parser::parseExprSequenceElement(Diag<> message,
}

if (Tok.isContextualKeyword("consume")
&& peekToken().isAny(tok::identifier, tok::kw_self)
&& peekToken().isAny(tok::identifier, tok::kw_self, tok::dollarident,
tok::code_complete)
&& !peekToken().isAtStartOfLine()) {
Tok.setKind(tok::contextual_keyword);

SourceLoc consumeLoc = consumeToken();
ParserResult<Expr> sub =
parseExprSequenceElement(diag::expected_expr_after_move, isExprBasic);
if (!sub.hasCodeCompletion() && !sub.isNull()) {
sub = makeParserResult(new (Context) MoveExpr(consumeLoc, sub.get()));
if (!sub.isNull()) {
sub = makeParserResult(new (Context) ConsumeExpr(consumeLoc, sub.get()));
}
return sub;
}

if (Tok.isContextualKeyword("copy") &&
peekToken().isAny(tok::identifier, tok::kw_self, tok::dollarident,
tok::code_complete) &&
!peekToken().isAtStartOfLine()) {
Tok.setKind(tok::contextual_keyword);

SourceLoc copyLoc = consumeToken();
ParserResult<Expr> sub =
parseExprSequenceElement(diag::expected_expr_after_copy, isExprBasic);
if (!sub.isNull()) {
sub = makeParserResult(new (Context) CopyExpr(copyLoc, sub.get()));
}
return sub;
}
Expand All @@ -432,7 +448,7 @@ ParserResult<Expr> Parser::parseExprSequenceElement(Diag<> message,
ParserResult<Expr> sub =
parseExprSequenceElement(diag::expected_expr_after_move, isExprBasic);
if (!sub.hasCodeCompletion() && !sub.isNull()) {
sub = makeParserResult(new (Context) MoveExpr(awaitLoc, sub.get()));
sub = makeParserResult(new (Context) ConsumeExpr(awaitLoc, sub.get()));
}
return sub;
}
Expand Down
6 changes: 6 additions & 0 deletions lib/SILGen/SILGenBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1050,3 +1050,9 @@ void SILGenBuilder::emitCopyAddrOperation(SILLocation loc, SILValue srcAddr,
auto &lowering = getTypeLowering(srcAddr->getType());
lowering.emitCopyInto(*this, loc, srcAddr, destAddr, isTake, isInitialize);
}

ManagedValue SILGenBuilder::createExplicitCopyValue(SILLocation loc,
ManagedValue operand) {
auto cvi = SILBuilder::createExplicitCopyValue(loc, operand.getValue());
return SGF.emitManagedRValueWithCleanup(cvi);
}
7 changes: 7 additions & 0 deletions lib/SILGen/SILGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ class SILGenBuilder : public SILBuilder {
ManagedValue createFormalAccessCopyValue(SILLocation loc,
ManagedValue originalValue);

using SILBuilder::createExplicitCopyValue;

/// A copy_value operation that to the move checker looks like just a normal
/// liveness use. Used to implement an explicit copy for no implicit copy
/// values.
ManagedValue createExplicitCopyValue(SILLocation Loc, ManagedValue operand);

#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
using SILBuilder::createStrongCopy##Name##Value; \
ManagedValue createStrongCopy##Name##Value(SILLocation loc, \
Expand Down
Loading