1
Fork 0

Add support for using qualified paths with structs in expression and pattern

position.
This commit is contained in:
Ryan Levick 2020-12-10 13:20:07 +01:00 committed by Ryan Levick
parent c5fbcd35a8
commit 6936349233
38 changed files with 374 additions and 187 deletions

View file

@ -32,7 +32,6 @@ impl<'a> Parser<'a> {
let mut just_parsed_doc_comment = false;
let start_pos = self.token_cursor.num_next_calls;
loop {
debug!("parse_outer_attributes: self.token={:?}", self.token);
let attr = if self.check(&token::Pound) {
let inner_error_reason = if just_parsed_doc_comment {
"an inner attribute is not permitted following an outer doc comment"

View file

@ -366,7 +366,7 @@ impl<'a> Parser<'a> {
let mut snapshot = self.clone();
let path =
Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None };
let struct_expr = snapshot.parse_struct_expr(path, AttrVec::new(), false);
let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false);
let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
return Some(match (struct_expr, block_tail) {
(Ok(expr), Err(mut err)) => {

View file

@ -1108,9 +1108,6 @@ impl<'a> Parser<'a> {
self.parse_closure_expr(attrs)
} else if self.check(&token::OpenDelim(token::Bracket)) {
self.parse_array_or_repeat_expr(attrs)
} else if self.eat_lt() {
let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs))
} else if self.check_path() {
self.parse_path_start_expr(attrs)
} else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
@ -1262,12 +1259,20 @@ impl<'a> Parser<'a> {
}
fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let path = self.parse_path(PathStyle::Expr)?;
let (qself, path) = if self.eat_lt() {
let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
(Some(qself), path)
} else {
(None, self.parse_path(PathStyle::Expr)?)
};
let lo = path.span;
// `!`, as an operator, is prefix, so we know this isn't that.
let (hi, kind) = if self.eat(&token::Not) {
// MACRO INVOCATION expression
if qself.is_some() {
self.struct_span_err(path.span, "macros cannot use qualified paths").emit();
}
let mac = MacCall {
path,
args: self.parse_mac_args()?,
@ -1275,13 +1280,16 @@ impl<'a> Parser<'a> {
};
(self.prev_token.span, ExprKind::MacCall(mac))
} else if self.check(&token::OpenDelim(token::Brace)) {
if let Some(expr) = self.maybe_parse_struct_expr(&path, &attrs) {
if let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path, &attrs) {
if qself.is_some() {
self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
}
return expr;
} else {
(path.span, ExprKind::Path(None, path))
(path.span, ExprKind::Path(qself, path))
}
} else {
(path.span, ExprKind::Path(None, path))
(path.span, ExprKind::Path(qself, path))
};
let expr = self.mk_expr(lo.to(hi), kind, attrs);
@ -2247,6 +2255,7 @@ impl<'a> Parser<'a> {
fn maybe_parse_struct_expr(
&mut self,
qself: Option<&ast::QSelf>,
path: &ast::Path,
attrs: &AttrVec,
) -> Option<PResult<'a, P<Expr>>> {
@ -2255,7 +2264,7 @@ impl<'a> Parser<'a> {
if let Err(err) = self.expect(&token::OpenDelim(token::Brace)) {
return Some(Err(err));
}
let expr = self.parse_struct_expr(path.clone(), attrs.clone(), true);
let expr = self.parse_struct_expr(qself.cloned(), path.clone(), attrs.clone(), true);
if let (Ok(expr), false) = (&expr, struct_allowed) {
// This is a struct literal, but we don't can't accept them here.
self.error_struct_lit_not_allowed_here(path.span, expr.span);
@ -2278,6 +2287,7 @@ impl<'a> Parser<'a> {
/// Precondition: already parsed the '{'.
pub(super) fn parse_struct_expr(
&mut self,
qself: Option<ast::QSelf>,
pth: ast::Path,
attrs: AttrVec,
recover: bool,
@ -2375,7 +2385,7 @@ impl<'a> Parser<'a> {
let expr = if recover_async {
ExprKind::Err
} else {
ExprKind::Struct(P(ast::StructExpr { path: pth, fields, rest: base }))
ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base }))
};
Ok(self.mk_expr(span, expr, attrs))
}

View file

@ -859,7 +859,8 @@ impl<'a> Parser<'a> {
/// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
fn parse_pat_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
if qself.is_some() {
return self.error_qpath_before_pat(&path, "{");
// Feature gate the use of qualified paths in patterns
self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
}
self.bump();
let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| {
@ -869,27 +870,17 @@ impl<'a> Parser<'a> {
(vec![], true)
});
self.bump();
Ok(PatKind::Struct(path, fields, etc))
Ok(PatKind::Struct(qself, path, fields, etc))
}
/// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
fn parse_pat_tuple_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
if qself.is_some() {
return self.error_qpath_before_pat(&path, "(");
}
let (fields, _) =
self.parse_paren_comma_seq(|p| p.parse_pat_allow_top_alt(None, RecoverComma::No))?;
Ok(PatKind::TupleStruct(path, fields))
}
/// Error when there's a qualified path, e.g. `<Foo as Bar>::Baz`
/// as the path of e.g., a tuple or record struct pattern.
fn error_qpath_before_pat(&mut self, path: &Path, token: &str) -> PResult<'a, PatKind> {
let msg = &format!("unexpected `{}` after qualified path", token);
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, msg);
err.span_label(path.span, "the qualified path");
Err(err)
if qself.is_some() {
self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
}
Ok(PatKind::TupleStruct(qself, path, fields))
}
/// Parses the fields of a struct-like pattern.

View file

@ -117,7 +117,7 @@ impl<'a> Parser<'a> {
}
let expr = if this.eat(&token::OpenDelim(token::Brace)) {
this.parse_struct_expr(path, AttrVec::new(), true)?
this.parse_struct_expr(None, path, AttrVec::new(), true)?
} else {
let hi = this.prev_token.span;
this.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())