Skip to content

Commit e6f1691

Browse files
committed
[copy-operator] Add support for the copy operator in preparation for making consuming and borrowing no implicit copy.
Some notes: 1. I implemented this as a contextual keyword that can only apply directly to lvalues. This ensures that we can still call functions called copy, define variables named copy, etc. I added tests for both the c++ and swift-syntax based parsers to validate this. So there shouldn't be any source breaks. 2. I did a little bit of type checker work to ensure that we do not treat copy_expr's result as an lvalue. Otherwise, one could call mutating functions on it or assign to it, which we do not want since the result of copy_value is 3. As expected, by creating a specific expr, I was able to have much greater control of the SILGen codegen and thus eliminate extraneous copies and other weirdness than if we used a function and had to go through SILGenApply. rdar://101862423
1 parent ac5cd47 commit e6f1691

21 files changed

+898
-1
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,8 @@ ERROR(expected_expr_after_await, none,
13861386
"expected expression after 'await'", ())
13871387
ERROR(expected_expr_after_move, none,
13881388
"expected expression after 'consume'", ())
1389+
ERROR(expected_expr_after_copy, none,
1390+
"expected expression after 'copy'", ())
13891391
ERROR(expected_expr_after_borrow, none,
13901392
"expected expression after '_borrow'", ())
13911393

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6996,6 +6996,10 @@ ERROR(move_expression_not_passed_lvalue,none,
69966996
"'consume' can only be applied to lvalues", ())
69976997
ERROR(borrow_expression_not_passed_lvalue,none,
69986998
"'borrow' can only be applied to lvalues", ())
6999+
ERROR(copy_expression_not_passed_lvalue,none,
7000+
"'copy' can only be applied to lvalues", ())
7001+
ERROR(copy_expression_cannot_be_used_with_noncopyable_types,none,
7002+
"'copy' cannot be applied to noncopyable types", ())
69997003

70007004
ERROR(moveOnly_requires_lexical_lifetimes,none,
70017005
"noncopyable types require lexical borrow scopes "

include/swift/AST/Expr.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,33 @@ class MoveExpr final : public IdentityExpr {
20772077
static bool classof(const Expr *e) { return e->getKind() == ExprKind::Move; }
20782078
};
20792079

2080+
/// CopyExpr - A 'copy' surrounding an lvalue expression marking the lvalue as
2081+
/// needing a semantic copy. Used to force a copy of a no implicit copy type.
2082+
class CopyExpr final : public Expr {
2083+
Expr *SubExpr;
2084+
SourceLoc CopyLoc;
2085+
2086+
public:
2087+
CopyExpr(SourceLoc copyLoc, Expr *sub, Type type = Type(),
2088+
bool implicit = false)
2089+
: Expr(ExprKind::Copy, implicit, type), SubExpr(sub), CopyLoc(copyLoc) {}
2090+
2091+
static CopyExpr *createImplicit(ASTContext &ctx, SourceLoc copyLoc, Expr *sub,
2092+
Type type = Type()) {
2093+
return new (ctx) CopyExpr(copyLoc, sub, type, /*implicit=*/true);
2094+
}
2095+
2096+
SourceLoc getLoc() const { return CopyLoc; }
2097+
2098+
Expr *getSubExpr() const { return SubExpr; }
2099+
void setSubExpr(Expr *E) { SubExpr = E; }
2100+
2101+
SourceLoc getStartLoc() const { return CopyLoc; }
2102+
SourceLoc getEndLoc() const { return getSubExpr()->getEndLoc(); }
2103+
2104+
static bool classof(const Expr *e) { return e->getKind() == ExprKind::Copy; }
2105+
};
2106+
20802107
/// BorrowExpr - A 'borrow' surrounding an lvalue/accessor expression at an
20812108
/// apply site marking the lvalue/accessor as being borrowed when passed to the
20822109
/// callee.

include/swift/AST/ExprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ ABSTRACT_EXPR(Identity, Expr)
111111
EXPR(Borrow, IdentityExpr)
112112
EXPR(UnresolvedMemberChainResult, IdentityExpr)
113113
EXPR_RANGE(Identity, Paren, UnresolvedMemberChainResult)
114+
EXPR(Copy, Expr)
114115
ABSTRACT_EXPR(AnyTry, Expr)
115116
EXPR(Try, AnyTryExpr)
116117
EXPR(ForceTry, AnyTryExpr)

lib/AST/ASTDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,6 +2200,12 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
22002200
printRec(E->getSubExpr());
22012201
PrintWithColorRAII(OS, ParenthesisColor) << ')';
22022202
}
2203+
void visitCopyExpr(CopyExpr *E) {
2204+
printCommon(E, "copy_expr");
2205+
OS << '\n';
2206+
printRec(E->getSubExpr());
2207+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
2208+
}
22032209
void visitBorrowExpr(BorrowExpr *E) {
22042210
printCommon(E, "borrow_expr");
22052211
OS << '\n';

lib/AST/ASTPrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5000,6 +5000,11 @@ void PrintAST::visitMoveExpr(MoveExpr *expr) {
50005000
visit(expr->getSubExpr());
50015001
}
50025002

5003+
void PrintAST::visitCopyExpr(CopyExpr *expr) {
5004+
Printer << "copy ";
5005+
visit(expr->getSubExpr());
5006+
}
5007+
50035008
void PrintAST::visitBorrowExpr(BorrowExpr *expr) {
50045009
Printer << "borrow ";
50055010
visit(expr->getSubExpr());

lib/AST/ASTWalker.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,15 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
690690
}
691691
return nullptr;
692692
}
693+
694+
Expr *visitCopyExpr(CopyExpr *E) {
695+
if (Expr *subExpr = doIt(E->getSubExpr())) {
696+
E->setSubExpr(subExpr);
697+
return E;
698+
}
699+
return nullptr;
700+
}
701+
693702
Expr *visitTupleExpr(TupleExpr *E) {
694703
for (unsigned i = 0, e = E->getNumElements(); i != e; ++i)
695704
if (E->getElement(i)) {

lib/AST/Expr.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,6 @@ SourceLoc Expr::getLoc() const {
192192
Expr *Expr::getSemanticsProvidingExpr() {
193193
if (auto *IE = dyn_cast<IdentityExpr>(this))
194194
return IE->getSubExpr()->getSemanticsProvidingExpr();
195-
196195
if (auto *TE = dyn_cast<TryExpr>(this))
197196
return TE->getSubExpr()->getSemanticsProvidingExpr();
198197

@@ -372,6 +371,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
372371
PASS_THROUGH_REFERENCE(DotSelf, getSubExpr);
373372
PASS_THROUGH_REFERENCE(Await, getSubExpr);
374373
PASS_THROUGH_REFERENCE(Move, getSubExpr);
374+
PASS_THROUGH_REFERENCE(Copy, getSubExpr);
375375
PASS_THROUGH_REFERENCE(Borrow, getSubExpr);
376376
PASS_THROUGH_REFERENCE(Try, getSubExpr);
377377
PASS_THROUGH_REFERENCE(ForceTry, getSubExpr);
@@ -744,6 +744,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
744744

745745
case ExprKind::Await:
746746
case ExprKind::Move:
747+
case ExprKind::Copy:
747748
case ExprKind::Borrow:
748749
case ExprKind::Try:
749750
case ExprKind::ForceTry:
@@ -936,6 +937,7 @@ bool Expr::isValidParentOfTypeExpr(Expr *typeExpr) const {
936937
case ExprKind::Paren:
937938
case ExprKind::Await:
938939
case ExprKind::Move:
940+
case ExprKind::Copy:
939941
case ExprKind::Borrow:
940942
case ExprKind::UnresolvedMemberChainResult:
941943
case ExprKind::Try:

lib/Parse/ParseExpr.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,21 @@ ParserResult<Expr> Parser::parseExprSequenceElement(Diag<> message,
422422
return sub;
423423
}
424424

425+
if (Tok.isContextualKeyword("copy") &&
426+
peekToken().isAny(tok::identifier, tok::kw_self, tok::dollarident,
427+
tok::code_complete) &&
428+
!peekToken().isAtStartOfLine()) {
429+
Tok.setKind(tok::contextual_keyword);
430+
431+
SourceLoc copyLoc = consumeToken();
432+
ParserResult<Expr> sub =
433+
parseExprSequenceElement(diag::expected_expr_after_copy, isExprBasic);
434+
if (!sub.isNull()) {
435+
sub = makeParserResult(new (Context) CopyExpr(copyLoc, sub.get()));
436+
}
437+
return sub;
438+
}
439+
425440
if (Context.LangOpts.hasFeature(Feature::OldOwnershipOperatorSpellings)) {
426441
if (Tok.isContextualKeyword("_move")) {
427442
Tok.setKind(tok::contextual_keyword);

lib/SILGen/SILGenBuilder.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,3 +1050,9 @@ void SILGenBuilder::emitCopyAddrOperation(SILLocation loc, SILValue srcAddr,
10501050
auto &lowering = getTypeLowering(srcAddr->getType());
10511051
lowering.emitCopyInto(*this, loc, srcAddr, destAddr, isTake, isInitialize);
10521052
}
1053+
1054+
ManagedValue SILGenBuilder::createExplicitCopyValue(SILLocation loc,
1055+
ManagedValue operand) {
1056+
auto cvi = SILBuilder::createExplicitCopyValue(loc, operand.getValue());
1057+
return SGF.emitManagedRValueWithCleanup(cvi);
1058+
}

0 commit comments

Comments
 (0)