Skip to content

Commit cc0b668

Browse files
authored
Merge pull request #63922 from kavon/standard-issue-neuralyzer
Implement the `forget` statement (as `_forget`)
2 parents 3bf7805 + 8559d3c commit cc0b668

31 files changed

+1127
-2
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,10 @@ NOTE(indent_expression_to_silence,none,
10711071
ERROR(expected_expr_throw,PointsToFirstBadToken,
10721072
"expected expression in 'throw' statement", ())
10731073

1074+
// Forget Statement
1075+
ERROR(expected_expr_forget,PointsToFirstBadToken,
1076+
"expected expression in 'forget' statement", ())
1077+
10741078
// Await/Async
10751079
ERROR(expected_await_not_async,none,
10761080
"found 'async' in expression; did you mean 'await'?", ())

include/swift/AST/DiagnosticsSema.def

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,10 @@ 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",
498+
(Type,Type))
499+
496500
ERROR(cannot_convert_closure_result,none,
497501
"cannot convert value of type %0 to closure result type %1",
498502
(Type,Type))
@@ -4497,6 +4501,27 @@ ERROR(opaque_type_var_no_underlying_type,none,
44974501
"property declares an opaque return type, but cannot infer the "
44984502
"underlying type from its initializer expression", ())
44994503

4504+
ERROR(forget_wrong_context_decl,none,
4505+
"'forget' statement cannot appear in %0",
4506+
(DescriptiveDeclKind))
4507+
ERROR(forget_wrong_context_closure,none,
4508+
"'forget' statement cannot appear in closure",
4509+
())
4510+
ERROR(forget_wrong_context_misc,none,
4511+
"'forget' statement cannot appear in this context",
4512+
())
4513+
ERROR(forget_wrong_context_copyable,none,
4514+
"'forget' statement can only appear in noncopyable type's member",
4515+
(DescriptiveDeclKind))
4516+
ERROR(forget_wrong_context_nonconsuming,none,
4517+
"'forget' statement can only appear in consuming %0",
4518+
(DescriptiveDeclKind))
4519+
ERROR(forget_wrong_not_self,none,
4520+
"you can only forget 'self'", ())
4521+
ERROR(forget_wrong_module,none,
4522+
"can only 'forget' from the same module defining type %0",
4523+
(Type))
4524+
45004525
//------------------------------------------------------------------------------
45014526
// MARK: Type Check Patterns
45024527
//------------------------------------------------------------------------------

include/swift/AST/NameLookup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ class FindLocalVal : public StmtVisitor<FindLocalVal> {
636636
void visitReturnStmt(ReturnStmt *) {}
637637
void visitYieldStmt(YieldStmt *) {}
638638
void visitThrowStmt(ThrowStmt *) {}
639+
void visitForgetStmt(ForgetStmt *) {}
639640
void visitPoundAssertStmt(PoundAssertStmt *) {}
640641
void visitDeferStmt(DeferStmt *DS) {
641642
// Nothing in the defer is visible.

include/swift/AST/Stmt.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class DeclContext;
3838
class Evaluator;
3939
class Expr;
4040
class FuncDecl;
41+
class AbstractFunctionDecl;
4142
class Pattern;
4243
class PatternBindingDecl;
4344
class VarDecl;
@@ -1482,6 +1483,44 @@ class ThrowStmt : public Stmt {
14821483
}
14831484
};
14841485

1486+
/// ForgetStmt - Consumes a noncopyable value and performs memberwise
1487+
/// destruction of unconsumed fields, without invoking its deinit. Only
1488+
/// supported form is "forget self".
1489+
class ForgetStmt : public Stmt {
1490+
Expr *SubExpr;
1491+
SourceLoc ForgetLoc;
1492+
AbstractFunctionDecl *InnermostMethod;
1493+
1494+
public:
1495+
explicit ForgetStmt(SourceLoc forgetLoc, Expr *subExpr)
1496+
: Stmt(StmtKind::Forget, /*Implicit=*/false),
1497+
SubExpr(subExpr), ForgetLoc(forgetLoc), InnermostMethod(nullptr) {}
1498+
1499+
SourceLoc getForgetLoc() const { return ForgetLoc; }
1500+
1501+
SourceLoc getStartLoc() const { return ForgetLoc; }
1502+
SourceLoc getEndLoc() const;
1503+
SourceRange getSourceRange() const {
1504+
return SourceRange(ForgetLoc, getEndLoc());
1505+
}
1506+
1507+
Expr *getSubExpr() const { return SubExpr; }
1508+
void setSubExpr(Expr *subExpr) { SubExpr = subExpr; }
1509+
1510+
/// Retrieves the saved innermost method / accessor decl in which this Stmt
1511+
/// resides. Corresponds to \c DeclContext::getInnermostMethodContext.
1512+
/// Must be saved with \c setInnermostMethodContext during typechecking.
1513+
AbstractFunctionDecl *getInnermostMethodContext() { return InnermostMethod; }
1514+
void setInnermostMethodContext(AbstractFunctionDecl *afd) {
1515+
assert(afd); // shouldn't be clearing this
1516+
InnermostMethod = afd;
1517+
}
1518+
1519+
static bool classof(const Stmt *S) {
1520+
return S->getKind() == StmtKind::Forget;
1521+
}
1522+
};
1523+
14851524
/// PoundAssertStmt - Asserts that a condition is true, at compile time.
14861525
class PoundAssertStmt : public Stmt {
14871526
SourceRange Range;

include/swift/AST/StmtNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ STMT(Continue, Stmt)
6666
STMT(Fallthrough, Stmt)
6767
STMT(Fail, Stmt)
6868
STMT(Throw, Stmt)
69+
STMT(Forget, Stmt)
6970
STMT(PoundAssert, Stmt)
7071
LAST_STMT(PoundAssert)
7172

include/swift/Parse/Parser.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,24 @@ class Parser {
615615
isa<AccessorDecl>(CurDeclContext) &&
616616
cast<AccessorDecl>(CurDeclContext)->isCoroutine());
617617
}
618+
619+
/// `forget self` is the only valid phrase, but we peek ahead for just any
620+
/// identifier after `forget` to determine if it's the statement. This helps
621+
/// us avoid interpreting `forget(self)` as the statement and not a call.
622+
/// We also want to be mindful of statements like `forget ++ something` where
623+
/// folks have defined a custom operator returning void.
624+
///
625+
/// Later, type checking will verify that you're forgetting the right thing
626+
/// so that when people make a mistake, thinking they can `forget x` we give
627+
/// a nice diagnostic.
628+
bool isContextualForgetKeyword() {
629+
// must be `forget` ...
630+
if (!Tok.isContextualKeyword("_forget"))
631+
return false;
632+
633+
// followed by either an identifier, `self`, or `Self`.
634+
return peekToken().isAny(tok::identifier, tok::kw_self, tok::kw_Self);
635+
}
618636

619637
/// Read tokens until we get to one of the specified tokens, then
620638
/// return without consuming it. Because we cannot guarantee that the token
@@ -1848,6 +1866,7 @@ class Parser {
18481866
ParserResult<Stmt> parseStmtReturn(SourceLoc tryLoc);
18491867
ParserResult<Stmt> parseStmtYield(SourceLoc tryLoc);
18501868
ParserResult<Stmt> parseStmtThrow(SourceLoc tryLoc);
1869+
ParserResult<Stmt> parseStmtForget();
18511870
ParserResult<Stmt> parseStmtDefer();
18521871
ParserStatus
18531872
parseStmtConditionElement(SmallVectorImpl<StmtConditionElement> &result,

include/swift/Sema/ConstraintLocator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +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.
5657
CTP_EnumCaseRawValue, ///< Raw value specified for "case X = 42" in enum.
5758
CTP_DefaultParameter, ///< Default value in parameter 'foo(a : Int = 42)'.
5859

lib/AST/ASTDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,6 +1803,12 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
18031803
PrintWithColorRAII(OS, ParenthesisColor) << ')';
18041804
}
18051805

1806+
void visitForgetStmt(ForgetStmt *S) {
1807+
printCommon(S, "forget_stmt") << '\n';
1808+
printRec(S->getSubExpr());
1809+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
1810+
}
1811+
18061812
void visitPoundAssertStmt(PoundAssertStmt *S) {
18071813
printCommon(S, "pound_assert");
18081814
OS << " message=" << QuotedString(S->getMessage()) << "\n";

lib/AST/ASTPrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5176,6 +5176,11 @@ void PrintAST::visitThrowStmt(ThrowStmt *stmt) {
51765176
visit(stmt->getSubExpr());
51775177
}
51785178

5179+
void PrintAST::visitForgetStmt(ForgetStmt *stmt) {
5180+
Printer << "_forget" << " ";
5181+
visit(stmt->getSubExpr());
5182+
}
5183+
51795184
void PrintAST::visitPoundAssertStmt(PoundAssertStmt *stmt) {
51805185
Printer << tok::pound_assert << " ";
51815186
// FIXME: print expression.

lib/AST/ASTScopeCreation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,12 @@ class NodeAdder
489489
return p;
490490
}
491491

492+
ASTScopeImpl *visitForgetStmt(ForgetStmt *fs, ASTScopeImpl *p,
493+
ScopeCreator &scopeCreator) {
494+
visitExpr(fs->getSubExpr(), p, scopeCreator);
495+
return p;
496+
}
497+
492498
ASTScopeImpl *visitPoundAssertStmt(PoundAssertStmt *pas,
493499
ASTScopeImpl *p,
494500
ScopeCreator &scopeCreator) {

0 commit comments

Comments
 (0)