Skip to content

[5.9🍒] rename _forget to discard; deprecate _forget #65788

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 1 commit into from
May 9, 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
10 changes: 7 additions & 3 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1091,9 +1091,13 @@ NOTE(indent_expression_to_silence,none,
ERROR(expected_expr_throw,PointsToFirstBadToken,
"expected expression in 'throw' statement", ())

// Forget Statement
ERROR(expected_expr_forget,PointsToFirstBadToken,
"expected expression in 'forget' statement", ())
// Discard Statement
ERROR(expected_expr_discard,PointsToFirstBadToken,
"expected expression in 'discard' statement", ())
WARNING(forget_is_deprecated,PointsToFirstBadToken,
"'_forget' keyword is deprecated and will be removed soon; "
"use 'discard' instead",
())

// Await/Async
ERROR(expected_await_not_async,none,
Expand Down
10 changes: 5 additions & 5 deletions include/swift/AST/DiagnosticsSIL.def
Original file line number Diff line number Diff line change
Expand Up @@ -735,15 +735,15 @@ ERROR(noimplicitcopy_used_on_generic_or_existential, none,
"@_noImplicitCopy can not be used on a generic or existential typed "
"binding or a nominal type containing such typed things", ())

// forget statement
ERROR(forget_nontrivial_storage,none,
"can only 'forget' type %0 if it contains trivially-destroyed "
// discard statement
ERROR(discard_nontrivial_storage,none,
"can only 'discard' type %0 if it contains trivially-destroyed "
"stored properties at this time",
(Type))
NOTE(forget_nontrivial_storage_note,none,
NOTE(discard_nontrivial_storage_note,none,
"type %0 cannot be trivially destroyed",
(Type))
NOTE(forget_nontrivial_implicit_storage_note,none,
NOTE(discard_nontrivial_implicit_storage_note,none,
"type %0 implicitly contains %1 which cannot be trivially destroyed",
(Type, Type))

Expand Down
38 changes: 19 additions & 19 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,8 @@ ERROR(cannot_convert_yield_value_protocol,none,
ERROR(cannot_convert_yield_value_nil,none,
"nil is not compatible with expected yield type %0", (Type))

ERROR(cannot_convert_forget_value,none,
"cannot convert value of type %0 to expected forget type %1",
ERROR(cannot_convert_discard_value,none,
"cannot convert value of type %0 to expected discard type %1",
(Type,Type))

ERROR(cannot_convert_closure_result,none,
Expand Down Expand Up @@ -4604,30 +4604,30 @@ ERROR(opaque_type_var_no_underlying_type,none,


//------------------------------------------------------------------------------
// MARK: Forget Statement
// MARK: Discard Statement
//------------------------------------------------------------------------------
ERROR(forget_wrong_context_decl,none,
"'forget' statement cannot appear in %0",
ERROR(discard_wrong_context_decl,none,
"'discard' statement cannot appear in %0",
(DescriptiveDeclKind))
ERROR(forget_no_deinit,none,
"'forget' has no effect for type %0 unless it has a deinitializer",
ERROR(discard_no_deinit,none,
"'discard' has no effect for type %0 unless it has a deinitializer",
(Type))
ERROR(forget_wrong_context_closure,none,
"'forget' statement cannot appear in closure",
ERROR(discard_wrong_context_closure,none,
"'discard' statement cannot appear in closure",
())
ERROR(forget_wrong_context_misc,none,
"'forget' statement cannot appear in this context",
ERROR(discard_wrong_context_misc,none,
"'discard' statement cannot appear in this context",
())
ERROR(forget_wrong_context_copyable,none,
"'forget' statement can only appear in noncopyable type's member",
ERROR(discard_wrong_context_copyable,none,
"'discard' statement can only appear in noncopyable type's member",
(DescriptiveDeclKind))
ERROR(forget_wrong_context_nonconsuming,none,
"'forget' statement can only appear in consuming %0",
ERROR(discard_wrong_context_nonconsuming,none,
"'discard' statement can only appear in consuming %0",
(DescriptiveDeclKind))
ERROR(forget_wrong_not_self,none,
"you can only forget 'self'", ())
ERROR(forget_wrong_module,none,
"can only 'forget' from the same module defining type %0",
ERROR(discard_wrong_not_self,none,
"you can only discard 'self'", ())
ERROR(discard_wrong_module,none,
"can only 'discard' from the same module defining type %0",
(Type))

//------------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/NameLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ class FindLocalVal : public StmtVisitor<FindLocalVal> {
void visitReturnStmt(ReturnStmt *) {}
void visitYieldStmt(YieldStmt *) {}
void visitThrowStmt(ThrowStmt *) {}
void visitForgetStmt(ForgetStmt *) {}
void visitDiscardStmt(DiscardStmt *) {}
void visitPoundAssertStmt(PoundAssertStmt *) {}
void visitDeferStmt(DeferStmt *DS) {
// Nothing in the defer is visible.
Expand Down
23 changes: 12 additions & 11 deletions include/swift/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -1494,25 +1494,26 @@ class ThrowStmt : public Stmt {
}
};

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

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

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

SourceLoc getStartLoc() const { return ForgetLoc; }
SourceLoc getStartLoc() const { return DiscardLoc; }
SourceLoc getEndLoc() const;
SourceRange getSourceRange() const {
return SourceRange(ForgetLoc, getEndLoc());
return SourceRange(DiscardLoc, getEndLoc());
}

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

static bool classof(const Stmt *S) {
return S->getKind() == StmtKind::Forget;
return S->getKind() == StmtKind::Discard;
}
};

Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/StmtNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ STMT(Continue, Stmt)
STMT(Fallthrough, Stmt)
STMT(Fail, Stmt)
STMT(Throw, Stmt)
STMT(Forget, Stmt)
STMT(Discard, Stmt)
STMT(PoundAssert, Stmt)
LAST_STMT(PoundAssert)

Expand Down
21 changes: 11 additions & 10 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -600,18 +600,19 @@ class Parser {
cast<AccessorDecl>(CurDeclContext)->isCoroutine());
}

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

// followed by either an identifier, `self`, or `Self`.
Expand Down Expand Up @@ -1860,7 +1861,7 @@ class Parser {
ParserResult<Stmt> parseStmtReturn(SourceLoc tryLoc);
ParserResult<Stmt> parseStmtYield(SourceLoc tryLoc);
ParserResult<Stmt> parseStmtThrow(SourceLoc tryLoc);
ParserResult<Stmt> parseStmtForget();
ParserResult<Stmt> parseStmtDiscard();
ParserResult<Stmt> parseStmtDefer();
ParserStatus
parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Sema/ConstraintLocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ enum ContextualTypePurpose : uint8_t {
CTP_YieldByValue, ///< By-value yield operand.
CTP_YieldByReference, ///< By-reference yield operand.
CTP_ThrowStmt, ///< Value specified to a 'throw' statement.
CTP_ForgetStmt, ///< Value specified to a 'forget' statement.
CTP_DiscardStmt, ///< Value specified to a 'discard' statement.
CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.

Expand Down
4 changes: 2 additions & 2 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1804,8 +1804,8 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

void visitForgetStmt(ForgetStmt *S) {
printCommon(S, "forget_stmt") << '\n';
void visitDiscardStmt(DiscardStmt *S) {
printCommon(S, "discard_stmt") << '\n';
printRec(S->getSubExpr());
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5403,8 +5403,8 @@ void PrintAST::visitThrowStmt(ThrowStmt *stmt) {
visit(stmt->getSubExpr());
}

void PrintAST::visitForgetStmt(ForgetStmt *stmt) {
Printer << "_forget" << " ";
void PrintAST::visitDiscardStmt(DiscardStmt *stmt) {
Printer << "discard" << " ";
visit(stmt->getSubExpr());
}

Expand Down
6 changes: 3 additions & 3 deletions lib/AST/ASTScopeCreation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,9 +500,9 @@ class NodeAdder
return p;
}

ASTScopeImpl *visitForgetStmt(ForgetStmt *fs, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
visitExpr(fs->getSubExpr(), p, scopeCreator);
ASTScopeImpl *visitDiscardStmt(DiscardStmt *ds, ASTScopeImpl *p,
ScopeCreator &scopeCreator) {
visitExpr(ds->getSubExpr(), p, scopeCreator);
return p;
}

Expand Down
8 changes: 4 additions & 4 deletions lib/AST/ASTWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1655,10 +1655,10 @@ Stmt *Traversal::visitThrowStmt(ThrowStmt *TS) {
return nullptr;
}

Stmt *Traversal::visitForgetStmt(ForgetStmt *FS) {
if (Expr *E = doIt(FS->getSubExpr())) {
FS->setSubExpr(E);
return FS;
Stmt *Traversal::visitDiscardStmt(DiscardStmt *DS) {
if (Expr *E = doIt(DS->getSubExpr())) {
DS->setSubExpr(E);
return DS;
}
return nullptr;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/AST/Stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ StringRef Stmt::getDescriptiveKindName(StmtKind K) {
return "return";
case StmtKind::Throw:
return "throw";
case StmtKind::Forget:
return "forget";
case StmtKind::Discard:
return "discard";
case StmtKind::PoundAssert:
return "#assert";
}
Expand Down Expand Up @@ -366,7 +366,7 @@ SourceLoc YieldStmt::getEndLoc() const {

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

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

SourceLoc DeferStmt::getEndLoc() const {
return tempDecl->getBody()->getEndLoc();
Expand Down
48 changes: 32 additions & 16 deletions lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ bool Parser::isStartOfStmt() {
case tok::kw_case:
case tok::kw_default:
case tok::kw_yield:
case tok::kw_forget:
case tok::kw_forget: // NOTE: support for deprecated _forget
case tok::kw_discard:
case tok::pound_assert:
case tok::pound_if:
case tok::pound_warning:
Expand Down Expand Up @@ -90,8 +91,8 @@ bool Parser::isStartOfStmt() {
case tok::identifier: {
// "identifier ':' for/while/do/switch" is a label on a loop/switch.
if (!peekToken().is(tok::colon)) {
// "yield" or "forget" in the right context begins a statement.
if (isContextualYieldKeyword() || isContextualForgetKeyword()) {
// "yield" or "discard" in the right context begins a statement.
if (isContextualYieldKeyword() || isContextualDiscardKeyword()) {
return true;
}
return false;
Expand Down Expand Up @@ -558,8 +559,12 @@ ParserResult<Stmt> Parser::parseStmt() {
// to parsing a statement.
if (isContextualYieldKeyword()) {
Tok.setKind(tok::kw_yield);
} else if (isContextualForgetKeyword()) {
Tok.setKind(tok::kw_forget);
} else if (isContextualDiscardKeyword()) {
// NOTE: support for deprecated _forget
if (Tok.isContextualKeyword("_forget"))
Tok.setKind(tok::kw_forget);
else
Tok.setKind(tok::kw_discard);
}

// This needs to handle everything that `Parser::isStartOfStmt()` accepts as
Expand Down Expand Up @@ -614,10 +619,11 @@ ParserResult<Stmt> Parser::parseStmt() {
case tok::kw_for:
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
return parseStmtForEach(LabelInfo);
case tok::kw_forget:
case tok::kw_forget: // NOTE: support for deprecated _forget
case tok::kw_discard:
if (LabelInfo) diagnose(LabelInfo.Loc, diag::invalid_label_on_stmt);
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
return parseStmtForget();
return parseStmtDiscard();
case tok::kw_switch:
if (tryLoc.isValid()) diagnose(tryLoc, diag::try_on_stmt, Tok.getText());
return parseStmtSwitch(LabelInfo);
Expand Down Expand Up @@ -930,31 +936,41 @@ ParserResult<Stmt> Parser::parseStmtThrow(SourceLoc tryLoc) {
new (Context) ThrowStmt(throwLoc, Result.get()));
}

/// parseStmtForget
/// parseStmtDiscard
///
/// stmt-forget
/// 'forget' 'self'
/// stmt-discard
/// 'discard' 'self'
///
ParserResult<Stmt> Parser::parseStmtForget() {
SourceLoc forgetLoc = consumeToken(tok::kw_forget);
ParserResult<Stmt> Parser::parseStmtDiscard() {
SourceLoc discardLoc;

// NOTE: support for deprecated _forget
if (Tok.is(tok::kw_forget)) {
discardLoc = consumeToken(tok::kw_forget);
diagnose(discardLoc, diag::forget_is_deprecated)
.fixItReplace(discardLoc, "discard");
} else {
discardLoc = consumeToken(tok::kw_discard);
}

SourceLoc exprLoc;
if (Tok.isNot(tok::eof))
exprLoc = Tok.getLoc();

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

if (Result.isNull())
Result = makeParserErrorResult(new (Context) ErrorExpr(forgetLoc));
Result = makeParserErrorResult(new (Context) ErrorExpr(discardLoc));

if (hasCodeCompletion)
Result.setHasCodeCompletionAndIsError();

return makeParserResult(Result,
new (Context) ForgetStmt(forgetLoc, Result.get()));
new (Context) DiscardStmt(discardLoc, Result.get()));
}

/// parseStmtDefer
Expand Down
Loading