Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
eed1407
Update std/lib.rs docs to reflect Rust 2018 usage
Xaeroxe Dec 28, 2018
13dc584
Merge visitors in AST validation
Zoxc Jan 18, 2019
a5d4aed
Address some comments
Zoxc Jan 19, 2019
b1f169f
Recover from parse errors in struct literal fields
estebank Jan 20, 2019
acbda76
Recover with suggestion from writing `.42` instead of `0.42`
estebank Jan 20, 2019
e387597
Reword message for incorrect float literal
estebank Jan 20, 2019
15bad8b
Extend incorrect float literal recovery to account for suffixes
estebank Jan 20, 2019
defa61f
Tweak field parse error recovery
estebank Jan 20, 2019
e33f7f7
Explain type mismatch cause pointing to return type when it is `impl …
estebank Jan 21, 2019
45a95b5
Use structured suggestion in stead of notes
estebank Jan 21, 2019
6c399d1
Add error for trailing angle brackets.
davidtwco Jan 21, 2019
3f0fc9b
Pluralize error messages.
davidtwco Jan 21, 2019
ab2479b
Move logic to its own method
estebank Jan 21, 2019
914d142
Extend trailing `>` detection for paths.
davidtwco Jan 21, 2019
4745b86
Accept more invalid code that is close to correct fields
estebank Jan 21, 2019
fb5d3c1
Stabilize Any::get_type_id and rename to type_id
SimonSapin Jan 22, 2019
4781c6f
Remove unused links
Xaeroxe Jan 22, 2019
40faae8
Add initial implementation of 'sort_at_index' for slices -- analog to…
Mokosha Jan 22, 2019
e32c45f
Rollup merge of #55448 - Mokosha:SortAtIndex, r=bluss
Centril Jan 23, 2019
051b5b3
Rollup merge of #57179 - Xaeroxe:patch-1, r=QuietMisdreavus
Centril Jan 23, 2019
8da08cf
Rollup merge of #57730 - Zoxc:combined-ast-validator, r=cramertj
Centril Jan 23, 2019
afc632b
Rollup merge of #57779 - estebank:recover-struct-fields, r=davidtwco
Centril Jan 23, 2019
cf308c5
Rollup merge of #57793 - estebank:impl-trait-resolve, r=oli-obk
Centril Jan 23, 2019
457420d
Rollup merge of #57795 - estebank:did-you-mean, r=zackmdavis
Centril Jan 23, 2019
9235c0f
Rollup merge of #57817 - davidtwco:issue-54521, r=estebank
Centril Jan 23, 2019
569fa82
Rollup merge of #57834 - SimonSapin:type_id, r=Centril
Centril Jan 23, 2019
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
14 changes: 14 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,20 @@ pub enum GenericArgs {
}

impl GenericArgs {
pub fn is_parenthesized(&self) -> bool {
match *self {
Parenthesized(..) => true,
_ => false,
}
}

pub fn is_angle_bracketed(&self) -> bool {
match *self {
AngleBracketed(..) => true,
_ => false,
}
}

pub fn span(&self) -> Span {
match *self {
AngleBracketed(ref data) => data.span,
Expand Down
134 changes: 133 additions & 1 deletion src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2188,7 +2188,27 @@ impl<'a> Parser<'a> {
enable_warning: bool)
-> PResult<'a, ()> {
loop {
segments.push(self.parse_path_segment(style, enable_warning)?);
let segment = self.parse_path_segment(style, enable_warning)?;
if style == PathStyle::Expr {
// In order to check for trailing angle brackets, we must have finished
// recursing (`parse_path_segment` can indirectly call this function),
// that is, the next token must be the highlighted part of the below example:
//
// `Foo::<Bar as Baz<T>>::Qux`
// ^ here
//
// As opposed to the below highlight (if we had only finished the first
// recursion):
//
// `Foo::<Bar as Baz<T>>::Qux`
// ^ here
//
// `PathStyle::Expr` is only provided at the root invocation and never in
// `parse_path_segment` to recurse and therefore can be checked to maintain
// this invariant.
self.check_trailing_angle_brackets(&segment, token::ModSep);
}
segments.push(segment);

if self.is_import_coupler() || !self.eat(&token::ModSep) {
return Ok(());
Expand Down Expand Up @@ -2821,6 +2841,8 @@ impl<'a> Parser<'a> {
// Assuming we have just parsed `.`, continue parsing into an expression.
fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
let segment = self.parse_path_segment(PathStyle::Expr, true)?;
self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));

Ok(match self.token {
token::OpenDelim(token::Paren) => {
// Method call `expr.f()`
Expand Down Expand Up @@ -2848,6 +2870,116 @@ impl<'a> Parser<'a> {
})
}

/// This function checks if there are trailing angle brackets and produces
/// a diagnostic to suggest removing them.
///
/// ```ignore (diagnostic)
/// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
/// ^^ help: remove extra angle brackets
/// ```
fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: token::Token) {
// This function is intended to be invoked after parsing a path segment where there are two
// cases:
//
// 1. A specific token is expected after the path segment.
// eg. `x.foo(`, `x.foo::<u32>(` (parenthesis - method call),
// `Foo::`, or `Foo::<Bar>::` (mod sep - continued path).
// 2. No specific token is expected after the path segment.
// eg. `x.foo` (field access)
//
// This function is called after parsing `.foo` and before parsing the token `end` (if
// present). This includes any angle bracket arguments, such as `.foo::<u32>` or
// `Foo::<Bar>`.

// We only care about trailing angle brackets if we previously parsed angle bracket
// arguments. This helps stop us incorrectly suggesting that extra angle brackets be
// removed in this case:
//
// `x.foo >> (3)` (where `x.foo` is a `u32` for example)
//
// This case is particularly tricky as we won't notice it just looking at the tokens -
// it will appear the same (in terms of upcoming tokens) as below (since the `::<u32>` will
// have already been parsed):
//
// `x.foo::<u32>>>(3)`
let parsed_angle_bracket_args = segment.args
.as_ref()
.map(|args| args.is_angle_bracketed())
.unwrap_or(false);

debug!(
"check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
parsed_angle_bracket_args,
);
if !parsed_angle_bracket_args {
return;
}

// Keep the span at the start so we can highlight the sequence of `>` characters to be
// removed.
let lo = self.span;

// We need to look-ahead to see if we have `>` characters without moving the cursor forward
// (since we might have the field access case and the characters we're eating are
// actual operators and not trailing characters - ie `x.foo >> 3`).
let mut position = 0;

// We can encounter `>` or `>>` tokens in any order, so we need to keep track of how
// many of each (so we can correctly pluralize our error messages) and continue to
// advance.
let mut number_of_shr = 0;
let mut number_of_gt = 0;
while self.look_ahead(position, |t| {
trace!("check_trailing_angle_brackets: t={:?}", t);
if *t == token::BinOp(token::BinOpToken::Shr) {
number_of_shr += 1;
true
} else if *t == token::Gt {
number_of_gt += 1;
true
} else {
false
}
}) {
position += 1;
}

// If we didn't find any trailing `>` characters, then we have nothing to error about.
debug!(
"check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}",
number_of_gt, number_of_shr,
);
if number_of_gt < 1 && number_of_shr < 1 {
return;
}

// Finally, double check that we have our end token as otherwise this is the
// second case.
if self.look_ahead(position, |t| {
trace!("check_trailing_angle_brackets: t={:?}", t);
*t == end
}) {
// Eat from where we started until the end token so that parsing can continue
// as if we didn't have those extra angle brackets.
self.eat_to_tokens(&[&end]);
let span = lo.until(self.span);

let plural = number_of_gt > 1 || number_of_shr >= 1;
self.diagnostic()
.struct_span_err(
span,
&format!("unmatched angle bracket{}", if plural { "s" } else { "" }),
)
.span_suggestion_with_applicability(
span,
&format!("remove extra angle bracket{}", if plural { "s" } else { "" }),
String::new(),
Applicability::MachineApplicable,
)
.emit();
}
}

fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
let mut e = e0;
let mut hi;
Expand Down
16 changes: 16 additions & 0 deletions src/test/ui/issues/issue-54521-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// compile-pass

// This test checks that the `remove extra angle brackets` error doesn't happen for some
// potential edge-cases..

struct X {
len: u32,
}

fn main() {
let x = X { len: 3 };

let _ = x.len > (3);

let _ = x.len >> (3);
}
22 changes: 22 additions & 0 deletions src/test/ui/issues/issue-54521-2.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// run-rustfix

// This test checks that the following error is emitted and the suggestion works:
//
// ```
// let _ = Vec::<usize>>>::new();
// ^^ help: remove extra angle brackets
// ```

fn main() {
let _ = Vec::<usize>::new();
//~^ ERROR unmatched angle bracket

let _ = Vec::<usize>::new();
//~^ ERROR unmatched angle bracket

let _ = Vec::<usize>::new();
//~^ ERROR unmatched angle bracket

let _ = Vec::<usize>::new();
//~^ ERROR unmatched angle bracket
}
22 changes: 22 additions & 0 deletions src/test/ui/issues/issue-54521-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// run-rustfix

// This test checks that the following error is emitted and the suggestion works:
//
// ```
// let _ = Vec::<usize>>>::new();
// ^^ help: remove extra angle brackets
// ```

fn main() {
let _ = Vec::<usize>>>>>::new();
//~^ ERROR unmatched angle bracket

let _ = Vec::<usize>>>>::new();
//~^ ERROR unmatched angle bracket

let _ = Vec::<usize>>>::new();
//~^ ERROR unmatched angle bracket

let _ = Vec::<usize>>::new();
//~^ ERROR unmatched angle bracket
}
26 changes: 26 additions & 0 deletions src/test/ui/issues/issue-54521-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: unmatched angle brackets
--> $DIR/issue-54521-2.rs:11:25
|
LL | let _ = Vec::<usize>>>>>::new();
| ^^^^ help: remove extra angle brackets

error: unmatched angle brackets
--> $DIR/issue-54521-2.rs:14:25
|
LL | let _ = Vec::<usize>>>>::new();
| ^^^ help: remove extra angle brackets

error: unmatched angle brackets
--> $DIR/issue-54521-2.rs:17:25
|
LL | let _ = Vec::<usize>>>::new();
| ^^ help: remove extra angle brackets

error: unmatched angle bracket
--> $DIR/issue-54521-2.rs:20:25
|
LL | let _ = Vec::<usize>>::new();
| ^ help: remove extra angle bracket

error: aborting due to 4 previous errors

22 changes: 22 additions & 0 deletions src/test/ui/issues/issue-54521.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// run-rustfix

// This test checks that the following error is emitted and the suggestion works:
//
// ```
// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
// ^^ help: remove extra angle brackets
// ```

fn main() {
let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
//~^ ERROR unmatched angle bracket

let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
//~^ ERROR unmatched angle bracket

let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
//~^ ERROR unmatched angle bracket

let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
//~^ ERROR unmatched angle bracket
}
22 changes: 22 additions & 0 deletions src/test/ui/issues/issue-54521.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// run-rustfix

// This test checks that the following error is emitted and the suggestion works:
//
// ```
// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
// ^^ help: remove extra angle brackets
// ```

fn main() {
let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>>();
//~^ ERROR unmatched angle bracket

let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>();
//~^ ERROR unmatched angle bracket

let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
//~^ ERROR unmatched angle bracket

let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>();
//~^ ERROR unmatched angle bracket
}
26 changes: 26 additions & 0 deletions src/test/ui/issues/issue-54521.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
error: unmatched angle brackets
--> $DIR/issue-54521.rs:11:60
|
LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>>();
| ^^^^ help: remove extra angle brackets

error: unmatched angle brackets
--> $DIR/issue-54521.rs:14:60
|
LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>();
| ^^^ help: remove extra angle brackets

error: unmatched angle brackets
--> $DIR/issue-54521.rs:17:60
|
LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
| ^^ help: remove extra angle brackets

error: unmatched angle bracket
--> $DIR/issue-54521.rs:20:60
|
LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>();
| ^ help: remove extra angle bracket

error: aborting due to 4 previous errors