Skip to content

Commit 370f4f5

Browse files
committed
Rework generic args parsing
1 parent 279f0a7 commit 370f4f5

File tree

10 files changed

+273
-221
lines changed

10 files changed

+273
-221
lines changed

src/librustc_resolve/late.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -1494,14 +1494,15 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
14941494
);
14951495
}
14961496

1497-
fn smart_resolve_path_fragment(&mut self,
1498-
id: NodeId,
1499-
qself: Option<&QSelf>,
1500-
path: &[Segment],
1501-
span: Span,
1502-
source: PathSource<'_>,
1503-
crate_lint: CrateLint)
1504-
-> PartialRes {
1497+
fn smart_resolve_path_fragment(
1498+
&mut self,
1499+
id: NodeId,
1500+
qself: Option<&QSelf>,
1501+
path: &[Segment],
1502+
span: Span,
1503+
source: PathSource<'_>,
1504+
crate_lint: CrateLint,
1505+
) -> PartialRes {
15051506
let ns = source.namespace();
15061507
let is_expected = &|res| source.is_expected(res);
15071508

@@ -1620,9 +1621,10 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
16201621
match self.resolve_qpath(id, qself, path, ns, span, crate_lint) {
16211622
// If defer_to_typeck, then resolution > no resolution,
16221623
// otherwise full resolution > partial resolution > no resolution.
1623-
Some(partial_res) if partial_res.unresolved_segments() == 0 ||
1624-
defer_to_typeck =>
1625-
return Some(partial_res),
1624+
Some(partial_res)
1625+
if partial_res.unresolved_segments() == 0 || defer_to_typeck => {
1626+
return Some(partial_res)
1627+
}
16261628
partial_res => if fin_res.is_none() { fin_res = partial_res },
16271629
}
16281630
}

src/libsyntax/ast.rs

-26
Original file line numberDiff line numberDiff line change
@@ -1253,32 +1253,6 @@ pub enum ExprKind {
12531253
Err,
12541254
}
12551255

1256-
impl ExprKind {
1257-
/// Whether this expression can appear applied to a `const` parameter without being surrounded
1258-
/// by braces.
1259-
///
1260-
/// Only used in error recovery.
1261-
crate fn is_valid_const_on_its_own(&self) -> bool {
1262-
fn is_const_lit(kind: &ExprKind) -> bool {
1263-
// These are the only literals that can be negated as a bare `const` argument.
1264-
match kind {
1265-
ExprKind::Lit(Lit { node: LitKind::Int(..), ..}) |
1266-
ExprKind::Lit(Lit { node: LitKind::Float(..), ..}) |
1267-
ExprKind::Lit(Lit { node: LitKind::FloatUnsuffixed(..), ..}) => true,
1268-
_ => false,
1269-
}
1270-
}
1271-
1272-
match self {
1273-
ExprKind::Lit(_) | // `foo::<42>()`
1274-
ExprKind::Err => true,
1275-
// `foo::<-42>()`
1276-
ExprKind::Unary(UnOp::Neg, expr) if is_const_lit(&expr.node) => true,
1277-
_ => false,
1278-
}
1279-
}
1280-
}
1281-
12821256
/// The explicit `Self` type in a "qualified path". The actual
12831257
/// path, including the trait and the associated item, is stored
12841258
/// separately. `position` represents the index of the associated

src/libsyntax/parse/parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ bitflags::bitflags! {
4040
struct Restrictions: u8 {
4141
const STMT_EXPR = 1 << 0;
4242
const NO_STRUCT_LITERAL = 1 << 1;
43-
const CONST_EXPR_RECOVERY = 1 << 2;
43+
const CLOSING_ANGLE_BRACKET = 1 << 2;
4444
}
4545
}
4646

src/libsyntax/parse/parser/expr.rs

+27-12
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,12 @@ impl<'a> Parser<'a> {
186186
self.last_type_ascription = None;
187187
return Ok(lhs);
188188
}
189-
(true, Some(AssocOp::Greater)) if self.restrictions.contains(
190-
Restrictions::CONST_EXPR_RECOVERY,
191-
) => { // Recovering likely const argument without braces.
189+
(true, Some(AssocOp::Greater)) |
190+
(true, Some(AssocOp::Less)) |
191+
(true, Some(AssocOp::ShiftLeft)) |
192+
(true, Some(AssocOp::ShiftRight))
193+
if self.restrictions.contains(Restrictions::CLOSING_ANGLE_BRACKET) => {
194+
// Bare `const` argument expression.
192195
self.last_type_ascription = None;
193196
return Ok(lhs);
194197
}
@@ -211,9 +214,13 @@ impl<'a> Parser<'a> {
211214
}
212215
self.expected_tokens.push(TokenType::Operator);
213216
while let Some(op) = AssocOp::from_token(&self.token) {
214-
if let (AssocOp::Greater, true) = (&op, self.restrictions.contains(
215-
Restrictions::CONST_EXPR_RECOVERY,
216-
)) { // Recovering likely const argument without braces.
217+
if let (true, AssocOp::Greater) |
218+
(true, AssocOp::Less) |
219+
(true, AssocOp::ShiftLeft) |
220+
(true, AssocOp::ShiftRight) = (
221+
self.restrictions.contains(Restrictions::CLOSING_ANGLE_BRACKET), &op
222+
) {
223+
// Bare `const` argument expression fully parsed.
217224
return Ok(lhs);
218225
}
219226

@@ -352,12 +359,20 @@ impl<'a> Parser<'a> {
352359

353360
/// Checks if this expression is a successfully parsed statement.
354361
fn expr_is_complete(&self, e: &Expr) -> bool {
355-
(self.restrictions.contains(Restrictions::STMT_EXPR) &&
356-
!classify::expr_requires_semi_to_be_stmt(e)) ||
357-
(self.restrictions.contains(Restrictions::CONST_EXPR_RECOVERY) &&
358-
// `<` is necessary here to avoid cases like `foo::< 1 < 3 >()` where we'll fallback
359-
// to a regular parse error without recovery or suggestions.
360-
[token::Lt, token::Gt, token::Comma].contains(&self.token.kind))
362+
(
363+
self.restrictions.contains(Restrictions::STMT_EXPR) &&
364+
!classify::expr_requires_semi_to_be_stmt(e)
365+
) || (
366+
self.restrictions.contains(Restrictions::CLOSING_ANGLE_BRACKET) &&
367+
// Comparison and bitshift operators are not allowed in bare const expressions.
368+
[
369+
token::Lt,
370+
token::Gt,
371+
token::Comma,
372+
token::BinOp(token::Shl),
373+
token::BinOp(token::Shr),
374+
].contains(&self.token.kind)
375+
)
361376
}
362377

363378
fn is_at_start_of_range_notation_rhs(&self) -> bool {

src/libsyntax/parse/parser/path.rs

+87-93
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use super::{P, Parser, PResult, Restrictions, TokenType};
1+
use super::{Parser, PResult, Restrictions, TokenType};
22

33
use crate::{maybe_whole, ThinVec};
44
use crate::ast::{
55
self, AngleBracketedArgs, AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode,
6-
Expr, GenericArg, Ident, ParenthesizedArgs, Path, PathSegment, QSelf,
6+
GenericArg, Ident, ParenthesizedArgs, Path, PathSegment, QSelf,
77
};
88
use crate::parse::token::{self, Token};
99
use crate::source_map::{Span, BytePos};
@@ -323,7 +323,7 @@ impl<'a> Parser<'a> {
323323
};
324324

325325
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
326-
match self.parse_generic_args() {
326+
match self.parse_generic_args(style) {
327327
Ok(value) => Ok(value),
328328
Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
329329
// Cancel error from being unable to find `>`. We know the error
@@ -370,15 +370,18 @@ impl<'a> Parser<'a> {
370370
.emit();
371371

372372
// Try again without unmatched angle bracket characters.
373-
self.parse_generic_args()
373+
self.parse_generic_args(style)
374374
},
375375
Err(e) => Err(e),
376376
}
377377
}
378378

379379
/// Parses (possibly empty) list of lifetime and type arguments and associated type bindings,
380380
/// possibly including trailing comma.
381-
fn parse_generic_args(&mut self) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
381+
fn parse_generic_args(
382+
&mut self,
383+
style: PathStyle,
384+
) -> PResult<'a, (Vec<GenericArg>, Vec<AssocTyConstraint>)> {
382385
let mut args = Vec::new();
383386
let mut constraints = Vec::new();
384387
let mut misplaced_assoc_ty_constraints: Vec<Span> = Vec::new();
@@ -415,59 +418,13 @@ impl<'a> Parser<'a> {
415418
span,
416419
});
417420
assoc_ty_constraints.push(span);
418-
} else if [
419-
token::Not,
420-
token::OpenDelim(token::Paren),
421-
].contains(&self.token.kind) && self.look_ahead(1, |t| t.is_lit() || t.is_bool_lit()) {
422-
// Parse bad `const` argument. `!` is only allowed here to go through
423-
// `recover_bare_const_expr` for better diagnostics when encountering
424-
// `foo::<!false>()`. `(` is allowed for the case `foo::<(1, 2, 3)>()`.
425-
426-
// This can't possibly be a valid const arg, it is likely missing braces.
427-
let value = AnonConst {
428-
id: ast::DUMMY_NODE_ID,
429-
value: self.recover_bare_const_expr()?,
430-
};
431-
args.push(GenericArg::Const(value));
421+
} else if self.check_possible_const_needing_braces(style) {
422+
args.push(self.parse_const_or_type_arg()?);
432423
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
433424
} else if self.check_const_arg() {
434-
// Parse `const` argument.
435-
436-
// `const` arguments that don't require surrunding braces would have a length of
437-
// one token, so anything that *isn't* surrounded by braces and is not
438-
// immediately followed by `,` or `>` is not a valid `const` argument.
439-
let invalid = self.look_ahead(1, |t| t != &token::Lt && t != &token::Comma);
440-
441-
let expr = if let token::OpenDelim(token::Brace) = self.token.kind {
442-
// Parse `const` argument surrounded by braces.
443-
self.parse_block_expr(
444-
None, self.token.span, BlockCheckMode::Default, ThinVec::new()
445-
)?
446-
} else if invalid {
447-
// This can't possibly be a valid const arg, it is likely missing braces.
448-
self.recover_bare_const_expr()?
449-
} else if self.token.is_ident() {
450-
// FIXME(const_generics): to distinguish between idents for types and consts,
451-
// we should introduce a GenericArg::Ident in the AST and distinguish when
452-
// lowering to the HIR. For now, idents for const args are not permitted.
453-
if self.token.is_bool_lit() {
454-
self.parse_literal_maybe_minus()?
455-
} else {
456-
return Err(
457-
self.fatal("identifiers may currently not be used for const generics")
458-
);
459-
}
460-
} else {
461-
self.parse_literal_maybe_minus()?
462-
};
463-
let value = AnonConst {
464-
id: ast::DUMMY_NODE_ID,
465-
value: expr,
466-
};
467-
args.push(GenericArg::Const(value));
425+
args.push(self.parse_const_arg()?);
468426
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
469427
} else if self.check_type() {
470-
// Parse type argument.
471428
args.push(GenericArg::Type(self.parse_ty()?));
472429
misplaced_assoc_ty_constraints.append(&mut assoc_ty_constraints);
473430
} else {
@@ -499,49 +456,86 @@ impl<'a> Parser<'a> {
499456
Ok((args, constraints))
500457
}
501458

502-
fn recover_bare_const_expr(&mut self) -> PResult<'a, P<Expr>> {
503-
let snapshot = self.clone();
504-
debug!("recover_bare_const_expr {:?}", self.token);
505-
match self.parse_expr_res(Restrictions::CONST_EXPR_RECOVERY, None) {
506-
Ok(expr) => {
507-
debug!("recover_bare_const_expr expr {:?} {:?}", expr, expr.node);
508-
if let token::Comma | token::Gt = self.token.kind {
509-
// We parsed the whole const argument successfully without braces.
510-
debug!("recover_bare_const_expr ok");
511-
if !expr.node.is_valid_const_on_its_own() {
512-
// But it wasn't a literal, so we emit a custom error and
513-
// suggest the appropriate code. `foo::<-1>()` is valid but gets parsed
514-
// here, so we need to gate the error only for invalid cases.
515-
self.span_fatal(
516-
expr.span,
517-
"complex const arguments must be surrounded by braces",
518-
).multipart_suggestion(
519-
"surround this const argument in braces",
520-
vec![
521-
(expr.span.shrink_to_lo(), "{ ".to_string()),
522-
(expr.span.shrink_to_hi(), " }".to_string()),
523-
],
524-
Applicability::MachineApplicable,
525-
).emit();
459+
fn parse_const_arg(&mut self) -> PResult<'a, GenericArg> {
460+
let value = if let token::OpenDelim(token::Brace) = self.token.kind {
461+
// Parse `const` argument surrounded by braces.
462+
self.parse_block_expr(None, self.token.span, BlockCheckMode::Default, ThinVec::new())?
463+
} else {
464+
self.parse_expr_res(Restrictions::CLOSING_ANGLE_BRACKET, None)?
465+
};
466+
let value = AnonConst { id: ast::DUMMY_NODE_ID, value };
467+
Ok(GenericArg::Const(value))
468+
}
469+
470+
/// Check some ambiguous cases between type and non-block const arguments.
471+
fn check_possible_const_needing_braces(&mut self, style: PathStyle) -> bool {
472+
style == PathStyle::Expr && (
473+
self.token.kind == token::Not || // `foo::<!const_bool_fn()>()`
474+
self.token.kind == token::OpenDelim(token::Paren) // `foo::<(1, 2, 3)>()`
475+
)
476+
}
477+
478+
/// There's intent ambiguity for this argument, it could be a const expression missing braces,
479+
/// or it could be a type argument. We try the later as the grammar expects, and if it fails we
480+
/// attempt the former and emit a targetted suggestion if valid.
481+
fn parse_const_or_type_arg(&mut self) -> PResult<'a, GenericArg> {
482+
let mut snapshot = self.clone();
483+
match self.parse_ty() {
484+
// Nothing to do, this was indeed a type argument.
485+
Ok(ty) if [
486+
token::Comma,
487+
token::Gt,
488+
token::BinOp(token::Shr),
489+
].contains(&self.token.kind) => Ok(GenericArg::Type(ty)),
490+
Ok(ty) => { // Could have found `foo::<!false>()`, needs `foo::<{ !false }>()`.
491+
mem::swap(self, &mut snapshot);
492+
match self.parse_bad_const_arg() {
493+
Ok(arg) => Ok(arg),
494+
Err(mut err) => {
495+
mem::swap(self, &mut snapshot);
496+
err.cancel();
497+
Ok(GenericArg::Type(ty))
498+
}
499+
}
500+
}
501+
Err(mut ty_err) => {
502+
mem::swap(self, &mut snapshot);
503+
match self.parse_bad_const_arg() {
504+
Ok(arg) => {
505+
ty_err.cancel();
506+
Ok(arg)
507+
}
508+
Err(mut err) => {
509+
mem::swap(self, &mut snapshot);
510+
err.cancel();
511+
Err(ty_err)
526512
}
527-
Ok(expr)
528-
} else {
529-
debug!("recover_bare_const_expr not");
530-
// We parsed *some* expression, but it isn't the whole argument
531-
// so we can't ensure it was a const argument with missing braces.
532-
// Roll-back and emit a regular parser error.
533-
mem::replace(self, snapshot);
534-
self.parse_literal_maybe_minus()
535513
}
536514
}
537-
Err(mut err) => {
538-
debug!("recover_bare_const_expr err");
539-
// We couldn't parse an expression successfully.
540-
// Roll-back, hide the error and emit a regular parser error.
541-
err.cancel();
542-
mem::replace(self, snapshot);
543-
self.parse_literal_maybe_minus()
515+
}
516+
}
517+
518+
fn parse_bad_const_arg(&mut self) -> PResult<'a, GenericArg> {
519+
let msg = if self.token.kind == token::OpenDelim(token::Paren) {
520+
// `foo::<(1, 2, 3)>()`
521+
"tuples in const arguments must be surrounded by braces"
522+
} else {
523+
"complex const arguments must be surrounded by braces"
524+
};
525+
match self.parse_const_arg() {
526+
Ok(arg) => {
527+
self.span_fatal(arg.span(), msg)
528+
.multipart_suggestion(
529+
"surround this const argument in braces",
530+
vec![
531+
(arg.span().shrink_to_lo(), "{ ".to_string()),
532+
(arg.span().shrink_to_hi(), " }".to_string()),
533+
],
534+
Applicability::MachineApplicable,
535+
).emit();
536+
Ok(arg)
544537
}
538+
Err(err) => Err(err),
545539
}
546540
}
547541
}

src/libsyntax/parse/parser/ty.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,12 @@ impl<'a> Parser<'a> {
4848
}
4949
}
5050

51-
pub(super) fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool,
52-
allow_c_variadic: bool) -> PResult<'a, P<Ty>> {
51+
pub(super) fn parse_ty_common(
52+
&mut self,
53+
allow_plus: bool,
54+
allow_qpath_recovery: bool,
55+
allow_c_variadic: bool,
56+
) -> PResult<'a, P<Ty>> {
5357
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
5458
maybe_whole!(self, NtTy, |x| x);
5559

0 commit comments

Comments
 (0)