Rollup merge of #134797 - spastorino:ergonomic-ref-counting-1, r=nikomatsakis
Ergonomic ref counting This is an experimental first version of ergonomic ref counting. This first version implements most of the RFC but doesn't implement any of the optimizations. This was left for following iterations. RFC: https://github.com/rust-lang/rfcs/pull/3680 Tracking issue: https://github.com/rust-lang/rust/issues/132290 Project goal: https://github.com/rust-lang/rust-project-goals/issues/107 r? ```@nikomatsakis```
This commit is contained in:
commit
f5a143f796
119 changed files with 1401 additions and 79 deletions
|
@ -31,15 +31,15 @@ use super::{
|
|||
SeqSep, TokenType,
|
||||
};
|
||||
use crate::errors::{
|
||||
AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion,
|
||||
BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
|
||||
ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces,
|
||||
ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
|
||||
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
||||
AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType,
|
||||
AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
|
||||
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
|
||||
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
|
||||
DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
||||
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
||||
HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
|
||||
IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
|
||||
QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
|
||||
IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody,
|
||||
QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
|
||||
StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
|
||||
SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
|
||||
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
|
||||
|
@ -572,10 +572,17 @@ impl<'a> Parser<'a> {
|
|||
return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
|
||||
}
|
||||
|
||||
if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) {
|
||||
// The 2015 edition is in use because parsing of `async move` has failed.
|
||||
if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use))
|
||||
&& self.prev_token.is_keyword(kw::Async)
|
||||
{
|
||||
// The 2015 edition is in use because parsing of `async move` or `async use` has failed.
|
||||
let span = self.prev_token.span.to(self.token.span);
|
||||
return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
|
||||
if self.token.is_keyword(kw::Move) {
|
||||
return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
|
||||
} else {
|
||||
// kw::Use
|
||||
return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span }));
|
||||
}
|
||||
}
|
||||
|
||||
let expect = tokens_to_string(&expected);
|
||||
|
@ -1991,7 +1998,7 @@ impl<'a> Parser<'a> {
|
|||
self.parse_expr()
|
||||
}
|
||||
.map_err(|mut err| {
|
||||
err.span_label(await_sp, "while parsing this incorrect await expression");
|
||||
err.span_label(await_sp, format!("while parsing this incorrect await expression"));
|
||||
err
|
||||
})?;
|
||||
Ok((expr.span, expr, is_question))
|
||||
|
@ -2030,6 +2037,21 @@ impl<'a> Parser<'a> {
|
|||
self.dcx().emit_err(IncorrectUseOfAwait { span });
|
||||
}
|
||||
}
|
||||
///
|
||||
/// If encountering `x.use()`, consumes and emits an error.
|
||||
pub(super) fn recover_from_use(&mut self) {
|
||||
if self.token == token::OpenDelim(Delimiter::Parenthesis)
|
||||
&& self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
|
||||
{
|
||||
// var.use()
|
||||
let lo = self.token.span;
|
||||
self.bump(); // (
|
||||
let span = lo.to(self.token.span);
|
||||
self.bump(); // )
|
||||
|
||||
self.dcx().emit_err(IncorrectUseOfUse { span });
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
|
||||
let is_try = self.token.is_keyword(kw::Try);
|
||||
|
|
|
@ -778,6 +778,7 @@ impl<'a> Parser<'a> {
|
|||
ExprKind::MethodCall(_) => "a method call",
|
||||
ExprKind::Call(_, _) => "a function call",
|
||||
ExprKind::Await(_, _) => "`.await`",
|
||||
ExprKind::Use(_, _) => "`.use`",
|
||||
ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
|
||||
ExprKind::Err(_) => return Ok(with_postfix),
|
||||
_ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
|
||||
|
@ -1296,6 +1297,12 @@ impl<'a> Parser<'a> {
|
|||
return Ok(self.mk_await_expr(self_arg, lo));
|
||||
}
|
||||
|
||||
if self.eat_keyword(exp!(Use)) {
|
||||
let use_span = self.prev_token.span;
|
||||
self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
|
||||
return Ok(self.mk_use_expr(self_arg, lo));
|
||||
}
|
||||
|
||||
// Post-fix match
|
||||
if self.eat_keyword(exp!(Match)) {
|
||||
let match_span = self.prev_token.span;
|
||||
|
@ -1397,6 +1404,7 @@ impl<'a> Parser<'a> {
|
|||
} else if this.check_path() {
|
||||
this.parse_expr_path_start()
|
||||
} else if this.check_keyword(exp!(Move))
|
||||
|| this.check_keyword(exp!(Use))
|
||||
|| this.check_keyword(exp!(Static))
|
||||
|| this.check_const_closure()
|
||||
{
|
||||
|
@ -2388,7 +2396,7 @@ impl<'a> Parser<'a> {
|
|||
Ok(closure)
|
||||
}
|
||||
|
||||
/// Parses an optional `move` prefix to a closure-like construct.
|
||||
/// Parses an optional `move` or `use` prefix to a closure-like construct.
|
||||
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
|
||||
if self.eat_keyword(exp!(Move)) {
|
||||
let move_kw_span = self.prev_token.span;
|
||||
|
@ -2401,6 +2409,16 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
Ok(CaptureBy::Value { move_kw: move_kw_span })
|
||||
}
|
||||
} else if self.eat_keyword(exp!(Use)) {
|
||||
let use_kw_span = self.prev_token.span;
|
||||
self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
|
||||
// Check for `use async` and recover
|
||||
if self.check_keyword(exp!(Async)) {
|
||||
let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
|
||||
Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span }))
|
||||
} else {
|
||||
Ok(CaptureBy::Use { use_kw: use_kw_span })
|
||||
}
|
||||
} else {
|
||||
Ok(CaptureBy::Ref)
|
||||
}
|
||||
|
@ -3415,7 +3433,7 @@ impl<'a> Parser<'a> {
|
|||
self.is_keyword_ahead(lookahead, &[kw])
|
||||
&& ((
|
||||
// `async move {`
|
||||
self.is_keyword_ahead(lookahead + 1, &[kw::Move])
|
||||
self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
|
||||
&& self.look_ahead(lookahead + 2, |t| {
|
||||
*t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
|
||||
})
|
||||
|
@ -3818,6 +3836,13 @@ impl<'a> Parser<'a> {
|
|||
await_expr
|
||||
}
|
||||
|
||||
fn mk_use_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
|
||||
let span = lo.to(self.prev_token.span);
|
||||
let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
|
||||
self.recover_from_use();
|
||||
use_expr
|
||||
}
|
||||
|
||||
pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
|
||||
P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
|
||||
}
|
||||
|
@ -3966,6 +3991,7 @@ impl MutVisitor for CondChecker<'_> {
|
|||
}
|
||||
ExprKind::Unary(_, _)
|
||||
| ExprKind::Await(_, _)
|
||||
| ExprKind::Use(_, _)
|
||||
| ExprKind::AssignOp(_, _, _)
|
||||
| ExprKind::Range(_, _, _)
|
||||
| ExprKind::Try(_)
|
||||
|
|
|
@ -209,7 +209,7 @@ impl<'a> Parser<'a> {
|
|||
let check_pub = def == &Defaultness::Final;
|
||||
let mut def_ = || mem::replace(def, Defaultness::Final);
|
||||
|
||||
let info = if self.eat_keyword_case(exp!(Use), case) {
|
||||
let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {
|
||||
self.parse_use_item()?
|
||||
} else if self.check_fn_front_matter(check_pub, case) {
|
||||
// FUNCTION ITEM
|
||||
|
@ -1277,6 +1277,21 @@ impl<'a> Parser<'a> {
|
|||
None
|
||||
}
|
||||
|
||||
fn is_use_closure(&self) -> bool {
|
||||
if self.token.is_keyword(kw::Use) {
|
||||
// Check if this could be a closure.
|
||||
self.look_ahead(1, |token| {
|
||||
// Move or Async here would be an error but still we're parsing a closure
|
||||
let dist =
|
||||
if token.is_keyword(kw::Move) || token.is_keyword(kw::Async) { 2 } else { 1 };
|
||||
|
||||
self.look_ahead(dist, |token| matches!(token.kind, token::Or | token::OrOr))
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_unsafe_foreign_mod(&self) -> bool {
|
||||
self.token.is_keyword(kw::Unsafe)
|
||||
&& self.is_keyword_ahead(1, &[kw::Extern])
|
||||
|
@ -1290,7 +1305,7 @@ impl<'a> Parser<'a> {
|
|||
if self.check_keyword(exp!(Static)) {
|
||||
// Check if this could be a closure.
|
||||
!self.look_ahead(1, |token| {
|
||||
if token.is_keyword(kw::Move) {
|
||||
if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) {
|
||||
return true;
|
||||
}
|
||||
matches!(token.kind, token::Or | token::OrOr)
|
||||
|
|
|
@ -813,9 +813,9 @@ impl<'a> Parser<'a> {
|
|||
self.is_keyword_ahead(0, &[kw::Const])
|
||||
&& self.look_ahead(1, |t| match &t.kind {
|
||||
// async closures do not work with const closures, so we do not parse that here.
|
||||
token::Ident(kw::Move | kw::Static, IdentIsRaw::No) | token::OrOr | token::Or => {
|
||||
true
|
||||
}
|
||||
token::Ident(kw::Move | kw::Use | kw::Static, IdentIsRaw::No)
|
||||
| token::OrOr
|
||||
| token::Or => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue