Skip to content

Commit 75e4f98

Browse files
authored
rename _forget to discard; deprecate _forget (#65788)
SE-390 concluded with choosing the keyword discard rather than forget for the statement that disables the deinit of a noncopyable type. This commit adds parsing support for `discard self` and adds a deprecation warning for `_forget self`. rdar://108859077
1 parent 14b3e5c commit 75e4f98

36 files changed

+498
-369
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,9 +1091,13 @@ NOTE(indent_expression_to_silence,none,
10911091
ERROR(expected_expr_throw,PointsToFirstBadToken,
10921092
"expected expression in 'throw' statement", ())
10931093

1094-
// Forget Statement
1095-
ERROR(expected_expr_forget,PointsToFirstBadToken,
1096-
"expected expression in 'forget' statement", ())
1094+
// Discard Statement
1095+
ERROR(expected_expr_discard,PointsToFirstBadToken,
1096+
"expected expression in 'discard' statement", ())
1097+
WARNING(forget_is_deprecated,PointsToFirstBadToken,
1098+
"'_forget' keyword is deprecated and will be removed soon; "
1099+
"use 'discard' instead",
1100+
())
10971101

10981102
// Await/Async
10991103
ERROR(expected_await_not_async,none,

include/swift/AST/DiagnosticsSIL.def

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -735,15 +735,15 @@ ERROR(noimplicitcopy_used_on_generic_or_existential, none,
735735
"@_noImplicitCopy can not be used on a generic or existential typed "
736736
"binding or a nominal type containing such typed things", ())
737737

738-
// forget statement
739-
ERROR(forget_nontrivial_storage,none,
740-
"can only 'forget' type %0 if it contains trivially-destroyed "
738+
// discard statement
739+
ERROR(discard_nontrivial_storage,none,
740+
"can only 'discard' type %0 if it contains trivially-destroyed "
741741
"stored properties at this time",
742742
(Type))
743-
NOTE(forget_nontrivial_storage_note,none,
743+
NOTE(discard_nontrivial_storage_note,none,
744744
"type %0 cannot be trivially destroyed",
745745
(Type))
746-
NOTE(forget_nontrivial_implicit_storage_note,none,
746+
NOTE(discard_nontrivial_implicit_storage_note,none,
747747
"type %0 implicitly contains %1 which cannot be trivially destroyed",
748748
(Type, Type))
749749

include/swift/AST/DiagnosticsSema.def

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -493,8 +493,8 @@ ERROR(cannot_convert_yield_value_protocol,none,
493493
ERROR(cannot_convert_yield_value_nil,none,
494494
"nil is not compatible with expected yield type %0", (Type))
495495

496-
ERROR(cannot_convert_forget_value,none,
497-
"cannot convert value of type %0 to expected forget type %1",
496+
ERROR(cannot_convert_discard_value,none,
497+
"cannot convert value of type %0 to expected discard type %1",
498498
(Type,Type))
499499

500500
ERROR(cannot_convert_closure_result,none,
@@ -4604,30 +4604,30 @@ ERROR(opaque_type_var_no_underlying_type,none,
46044604

46054605

46064606
//------------------------------------------------------------------------------
4607-
// MARK: Forget Statement
4607+
// MARK: Discard Statement
46084608
//------------------------------------------------------------------------------
4609-
ERROR(forget_wrong_context_decl,none,
4610-
"'forget' statement cannot appear in %0",
4609+
ERROR(discard_wrong_context_decl,none,
4610+
"'discard' statement cannot appear in %0",
46114611
(DescriptiveDeclKind))
4612-
ERROR(forget_no_deinit,none,
4613-
"'forget' has no effect for type %0 unless it has a deinitializer",
4612+
ERROR(discard_no_deinit,none,
4613+
"'discard' has no effect for type %0 unless it has a deinitializer",
46144614
(Type))
4615-
ERROR(forget_wrong_context_closure,none,
4616-
"'forget' statement cannot appear in closure",
4615+
ERROR(discard_wrong_context_closure,none,
4616+
"'discard' statement cannot appear in closure",
46174617
())
4618-
ERROR(forget_wrong_context_misc,none,
4619-
"'forget' statement cannot appear in this context",
4618+
ERROR(discard_wrong_context_misc,none,
4619+
"'discard' statement cannot appear in this context",
46204620
())
4621-
ERROR(forget_wrong_context_copyable,none,
4622-
"'forget' statement can only appear in noncopyable type's member",
4621+
ERROR(discard_wrong_context_copyable,none,
4622+
"'discard' statement can only appear in noncopyable type's member",
46234623
(DescriptiveDeclKind))
4624-
ERROR(forget_wrong_context_nonconsuming,none,
4625-
"'forget' statement can only appear in consuming %0",
4624+
ERROR(discard_wrong_context_nonconsuming,none,
4625+
"'discard' statement can only appear in consuming %0",
46264626
(DescriptiveDeclKind))
4627-
ERROR(forget_wrong_not_self,none,
4628-
"you can only forget 'self'", ())
4629-
ERROR(forget_wrong_module,none,
4630-
"can only 'forget' from the same module defining type %0",
4627+
ERROR(discard_wrong_not_self,none,
4628+
"you can only discard 'self'", ())
4629+
ERROR(discard_wrong_module,none,
4630+
"can only 'discard' from the same module defining type %0",
46314631
(Type))
46324632

46334633
//------------------------------------------------------------------------------

include/swift/AST/NameLookup.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ class FindLocalVal : public StmtVisitor<FindLocalVal> {
649649
void visitReturnStmt(ReturnStmt *) {}
650650
void visitYieldStmt(YieldStmt *) {}
651651
void visitThrowStmt(ThrowStmt *) {}
652-
void visitForgetStmt(ForgetStmt *) {}
652+
void visitDiscardStmt(DiscardStmt *) {}
653653
void visitPoundAssertStmt(PoundAssertStmt *) {}
654654
void visitDeferStmt(DeferStmt *DS) {
655655
// Nothing in the defer is visible.

include/swift/AST/Stmt.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,25 +1494,26 @@ class ThrowStmt : public Stmt {
14941494
}
14951495
};
14961496

1497-
/// ForgetStmt - Consumes a noncopyable value and performs memberwise
1497+
/// DiscardStmt - Consumes a noncopyable value and performs memberwise
14981498
/// destruction of unconsumed fields, without invoking its deinit. Only
1499-
/// supported form is "forget self".
1500-
class ForgetStmt : public Stmt {
1499+
/// supported form is "discard self".
1500+
class DiscardStmt : public Stmt {
15011501
Expr *SubExpr;
1502-
SourceLoc ForgetLoc;
1502+
SourceLoc DiscardLoc;
15031503
AbstractFunctionDecl *InnermostMethod;
15041504

15051505
public:
1506-
explicit ForgetStmt(SourceLoc forgetLoc, Expr *subExpr)
1507-
: Stmt(StmtKind::Forget, /*Implicit=*/false),
1508-
SubExpr(subExpr), ForgetLoc(forgetLoc), InnermostMethod(nullptr) {}
1506+
explicit DiscardStmt(SourceLoc discardLoc, Expr *subExpr)
1507+
: Stmt(StmtKind::Discard, /*Implicit=*/false),
1508+
SubExpr(subExpr), DiscardLoc(discardLoc), InnermostMethod(nullptr) {}
15091509

1510-
SourceLoc getForgetLoc() const { return ForgetLoc; }
1510+
/// Location of the 'discard' keyword.
1511+
SourceLoc getDiscardLoc() const { return DiscardLoc; }
15111512

1512-
SourceLoc getStartLoc() const { return ForgetLoc; }
1513+
SourceLoc getStartLoc() const { return DiscardLoc; }
15131514
SourceLoc getEndLoc() const;
15141515
SourceRange getSourceRange() const {
1515-
return SourceRange(ForgetLoc, getEndLoc());
1516+
return SourceRange(DiscardLoc, getEndLoc());
15161517
}
15171518

15181519
Expr *getSubExpr() const { return SubExpr; }
@@ -1528,7 +1529,7 @@ class ForgetStmt : public Stmt {
15281529
}
15291530

15301531
static bool classof(const Stmt *S) {
1531-
return S->getKind() == StmtKind::Forget;
1532+
return S->getKind() == StmtKind::Discard;
15321533
}
15331534
};
15341535

include/swift/AST/StmtNodes.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ STMT(Continue, Stmt)
6666
STMT(Fallthrough, Stmt)
6767
STMT(Fail, Stmt)
6868
STMT(Throw, Stmt)
69-
STMT(Forget, Stmt)
69+
STMT(Discard, Stmt)
7070
STMT(PoundAssert, Stmt)
7171
LAST_STMT(PoundAssert)
7272

include/swift/Parse/Parser.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -600,18 +600,19 @@ class Parser {
600600
cast<AccessorDecl>(CurDeclContext)->isCoroutine());
601601
}
602602

603-
/// `forget self` is the only valid phrase, but we peek ahead for just any
604-
/// identifier after `forget` to determine if it's the statement. This helps
605-
/// us avoid interpreting `forget(self)` as the statement and not a call.
606-
/// We also want to be mindful of statements like `forget ++ something` where
603+
/// `discard self` is the only valid phrase, but we peek ahead for just any
604+
/// identifier after `discard` to determine if it's the statement. This helps
605+
/// us avoid interpreting `discard(self)` as the statement and not a call.
606+
/// We also want to be mindful of statements like `discard ++ something` where
607607
/// folks have defined a custom operator returning void.
608608
///
609-
/// Later, type checking will verify that you're forgetting the right thing
610-
/// so that when people make a mistake, thinking they can `forget x` we give
609+
/// Later, type checking will verify that you're discarding the right thing
610+
/// so that when people make a mistake, thinking they can `discard x` we give
611611
/// a nice diagnostic.
612-
bool isContextualForgetKeyword() {
613-
// must be `forget` ...
614-
if (!Tok.isContextualKeyword("_forget"))
612+
bool isContextualDiscardKeyword() {
613+
// must be `discard` ...
614+
if (!(Tok.isContextualKeyword("_forget") // NOTE: support for deprecated _forget
615+
|| Tok.isContextualKeyword("discard")))
615616
return false;
616617

617618
// followed by either an identifier, `self`, or `Self`.
@@ -1860,7 +1861,7 @@ class Parser {
18601861
ParserResult<Stmt> parseStmtReturn(SourceLoc tryLoc);
18611862
ParserResult<Stmt> parseStmtYield(SourceLoc tryLoc);
18621863
ParserResult<Stmt> parseStmtThrow(SourceLoc tryLoc);
1863-
ParserResult<Stmt> parseStmtForget();
1864+
ParserResult<Stmt> parseStmtDiscard();
18641865
ParserResult<Stmt> parseStmtDefer();
18651866
ParserStatus
18661867
parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,

include/swift/Sema/ConstraintLocator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ enum ContextualTypePurpose : uint8_t {
5353
CTP_YieldByValue, ///< By-value yield operand.
5454
CTP_YieldByReference, ///< By-reference yield operand.
5555
CTP_ThrowStmt, ///< Value specified to a 'throw' statement.
56-
CTP_ForgetStmt, ///< Value specified to a 'forget' statement.
56+
CTP_DiscardStmt, ///< Value specified to a 'discard' statement.
5757
CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
5858
CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.
5959

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,8 +1804,8 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
18041804
PrintWithColorRAII(OS, ParenthesisColor) << ')';
18051805
}
18061806

1807-
void visitForgetStmt(ForgetStmt *S) {
1808-
printCommon(S, "forget_stmt") << '\n';
1807+
void visitDiscardStmt(DiscardStmt *S) {
1808+
printCommon(S, "discard_stmt") << '\n';
18091809
printRec(S->getSubExpr());
18101810
PrintWithColorRAII(OS, ParenthesisColor) << ')';
18111811
}

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5403,8 +5403,8 @@ void PrintAST::visitThrowStmt(ThrowStmt *stmt) {
54035403
visit(stmt->getSubExpr());
54045404
}
54055405

5406-
void PrintAST::visitForgetStmt(ForgetStmt *stmt) {
5407-
Printer << "_forget" << " ";
5406+
void PrintAST::visitDiscardStmt(DiscardStmt *stmt) {
5407+
Printer << "discard" << " ";
54085408
visit(stmt->getSubExpr());
54095409
}
54105410

lib/AST/ASTScopeCreation.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -500,9 +500,9 @@ class NodeAdder
500500
return p;
501501
}
502502

503-
ASTScopeImpl *visitForgetStmt(ForgetStmt *fs, ASTScopeImpl *p,
504-
ScopeCreator &scopeCreator) {
505-
visitExpr(fs->getSubExpr(), p, scopeCreator);
503+
ASTScopeImpl *visitDiscardStmt(DiscardStmt *ds, ASTScopeImpl *p,
504+
ScopeCreator &scopeCreator) {
505+
visitExpr(ds->getSubExpr(), p, scopeCreator);
506506
return p;
507507
}
508508

lib/AST/ASTWalker.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,10 +1655,10 @@ Stmt *Traversal::visitThrowStmt(ThrowStmt *TS) {
16551655
return nullptr;
16561656
}
16571657

1658-
Stmt *Traversal::visitForgetStmt(ForgetStmt *FS) {
1659-
if (Expr *E = doIt(FS->getSubExpr())) {
1660-
FS->setSubExpr(E);
1661-
return FS;
1658+
Stmt *Traversal::visitDiscardStmt(DiscardStmt *DS) {
1659+
if (Expr *E = doIt(DS->getSubExpr())) {
1660+
DS->setSubExpr(E);
1661+
return DS;
16621662
}
16631663
return nullptr;
16641664
}

lib/AST/Stmt.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ StringRef Stmt::getDescriptiveKindName(StmtKind K) {
8181
return "return";
8282
case StmtKind::Throw:
8383
return "throw";
84-
case StmtKind::Forget:
85-
return "forget";
84+
case StmtKind::Discard:
85+
return "discard";
8686
case StmtKind::PoundAssert:
8787
return "#assert";
8888
}
@@ -366,7 +366,7 @@ SourceLoc YieldStmt::getEndLoc() const {
366366

367367
SourceLoc ThrowStmt::getEndLoc() const { return SubExpr->getEndLoc(); }
368368

369-
SourceLoc ForgetStmt::getEndLoc() const { return SubExpr->getEndLoc(); }
369+
SourceLoc DiscardStmt::getEndLoc() const { return SubExpr->getEndLoc(); }
370370

371371
SourceLoc DeferStmt::getEndLoc() const {
372372
return tempDecl->getBody()->getEndLoc();

lib/Parse/ParseStmt.cpp

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ bool Parser::isStartOfStmt() {
5555
case tok::kw_case:
5656
case tok::kw_default:
5757
case tok::kw_yield:
58-
case tok::kw_forget:
58+
case tok::kw_forget: // NOTE: support for deprecated _forget
59+
case tok::kw_discard:
5960
case tok::pound_assert:
6061
case tok::pound_if:
6162
case tok::pound_warning:
@@ -90,8 +91,8 @@ bool Parser::isStartOfStmt() {
9091
case tok::identifier: {
9192
// "identifier ':' for/while/do/switch" is a label on a loop/switch.
9293
if (!peekToken().is(tok::colon)) {
93-
// "yield" or "forget" in the right context begins a statement.
94-
if (isContextualYieldKeyword() || isContextualForgetKeyword()) {
94+
// "yield" or "discard" in the right context begins a statement.
95+
if (isContextualYieldKeyword() || isContextualDiscardKeyword()) {
9596
return true;
9697
}
9798
return false;
@@ -558,8 +559,12 @@ ParserResult<Stmt> Parser::parseStmt() {
558559
// to parsing a statement.
559560
if (isContextualYieldKeyword()) {
560561
Tok.setKind(tok::kw_yield);
561-
} else if (isContextualForgetKeyword()) {
562-
Tok.setKind(tok::kw_forget);
562+
} else if (isContextualDiscardKeyword()) {
563+
// NOTE: support for deprecated _forget
564+
if (Tok.isContextualKeyword("_forget"))
565+
Tok.setKind(tok::kw_forget);
566+
else
567+
Tok.setKind(tok::kw_discard);
563568
}
564569

565570
// This needs to handle everything that `Parser::isStartOfStmt()` accepts as
@@ -614,10 +619,11 @@ ParserResult<Stmt> Parser::parseStmt() {
614619
case tok::kw_for:
615620
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
616621
return parseStmtForEach(LabelInfo);
617-
case tok::kw_forget:
622+
case tok::kw_forget: // NOTE: support for deprecated _forget
623+
case tok::kw_discard:
618624
if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt);
619625
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
620-
return parseStmtForget();
626+
return parseStmtDiscard();
621627
case tok::kw_switch:
622628
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
623629
return parseStmtSwitch(LabelInfo);
@@ -930,31 +936,41 @@ ParserResult<Stmt> Parser::parseStmtThrow(SourceLoc tryLoc) {
930936
new (Context) ThrowStmt(throwLoc, Result.get()));
931937
}
932938

933-
/// parseStmtForget
939+
/// parseStmtDiscard
934940
///
935-
/// stmt-forget
936-
/// 'forget' 'self'
941+
/// stmt-discard
942+
/// 'discard' 'self'
937943
///
938-
ParserResult<Stmt> Parser::parseStmtForget() {
939-
SourceLoc forgetLoc = consumeToken(tok::kw_forget);
944+
ParserResult<Stmt> Parser::parseStmtDiscard() {
945+
SourceLoc discardLoc;
946+
947+
// NOTE: support for deprecated _forget
948+
if (Tok.is(tok::kw_forget)) {
949+
discardLoc = consumeToken(tok::kw_forget);
950+
diagnose(discardLoc, diag::forget_is_deprecated)
951+
.fixItReplace(discardLoc, "discard");
952+
} else {
953+
discardLoc = consumeToken(tok::kw_discard);
954+
}
955+
940956
SourceLoc exprLoc;
941957
if (Tok.isNot(tok::eof))
942958
exprLoc = Tok.getLoc();
943959

944960
// We parse the whole expression, because we might have something like:
945-
// forget self.x.y
961+
// discard self.x.y
946962
// and we want to emit good diagnostics for this later on.
947-
ParserResult<Expr> Result = parseExpr(diag::expected_expr_forget);
963+
ParserResult<Expr> Result = parseExpr(diag::expected_expr_discard);
948964
bool hasCodeCompletion = Result.hasCodeCompletion();
949965

950966
if (Result.isNull())
951-
Result = makeParserErrorResult(new (Context) ErrorExpr(forgetLoc));
967+
Result = makeParserErrorResult(new (Context) ErrorExpr(discardLoc));
952968

953969
if (hasCodeCompletion)
954970
Result.setHasCodeCompletionAndIsError();
955971

956972
return makeParserResult(Result,
957-
new (Context) ForgetStmt(forgetLoc, Result.get()));
973+
new (Context) DiscardStmt(discardLoc, Result.get()));
958974
}
959975

960976
/// parseStmtDefer

0 commit comments

Comments
 (0)