Skip to content

Commit 4e68ddc

Browse files
committed
review comments: move back some methods and clean up wording
1 parent d1364d5 commit 4e68ddc

File tree

10 files changed

+196
-192
lines changed

10 files changed

+196
-192
lines changed

src/libsyntax/parse/diagnostics.rs

+145-40
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,15 @@ use crate::ast::{
55
};
66
use crate::parse::{SeqSep, token, PResult, Parser};
77
use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType};
8-
use crate::parse::token;
98
use crate::print::pprust;
109
use crate::ptr::P;
1110
use crate::source_map::Spanned;
1211
use crate::symbol::kw;
1312
use crate::ThinVec;
14-
use crate::tokenstream::TokenTree;
1513
use crate::util::parser::AssocOp;
16-
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
14+
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
1715
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
1816
use log::{debug, trace};
19-
use std::slice;
2017

2118
pub enum Error {
2219
FileNotFoundForModule {
@@ -148,36 +145,8 @@ impl RecoverQPath for Expr {
148145
}
149146

150147
impl<'a> Parser<'a> {
151-
pub fn look_ahead<R, F>(&self, dist: usize, f: F) -> R where
152-
F: FnOnce(&token::Token) -> R,
153-
{
154-
if dist == 0 {
155-
return f(&self.token)
156-
}
157-
158-
f(&match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) {
159-
Some(tree) => match tree {
160-
TokenTree::Token(_, tok) => tok,
161-
TokenTree::Delimited(_, delim, _) => token::OpenDelim(delim),
162-
},
163-
None => token::CloseDelim(self.token_cursor.frame.delim),
164-
})
165-
}
166-
167-
crate fn look_ahead_span(&self, dist: usize) -> Span {
168-
if dist == 0 {
169-
return self.span
170-
}
171-
172-
match self.token_cursor.frame.tree_cursor.look_ahead(dist - 1) {
173-
Some(TokenTree::Token(span, _)) => span,
174-
Some(TokenTree::Delimited(span, ..)) => span.entire(),
175-
None => self.look_ahead_span(dist - 1),
176-
}
177-
}
178-
179148
pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> {
180-
self.sess.span_diagnostic.struct_span_fatal(self.span, m)
149+
self.span_fatal(self.span, m)
181150
}
182151

183152
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
@@ -243,6 +212,145 @@ impl<'a> Parser<'a> {
243212
err
244213
}
245214

215+
pub fn expected_one_of_not_found(
216+
&mut self,
217+
edible: &[token::Token],
218+
inedible: &[token::Token],
219+
) -> PResult<'a, bool /* recovered */> {
220+
fn tokens_to_string(tokens: &[TokenType]) -> String {
221+
let mut i = tokens.iter();
222+
// This might be a sign we need a connect method on Iterator.
223+
let b = i.next()
224+
.map_or(String::new(), |t| t.to_string());
225+
i.enumerate().fold(b, |mut b, (i, a)| {
226+
if tokens.len() > 2 && i == tokens.len() - 2 {
227+
b.push_str(", or ");
228+
} else if tokens.len() == 2 && i == tokens.len() - 2 {
229+
b.push_str(" or ");
230+
} else {
231+
b.push_str(", ");
232+
}
233+
b.push_str(&a.to_string());
234+
b
235+
})
236+
}
237+
238+
let mut expected = edible.iter()
239+
.map(|x| TokenType::Token(x.clone()))
240+
.chain(inedible.iter().map(|x| TokenType::Token(x.clone())))
241+
.chain(self.expected_tokens.iter().cloned())
242+
.collect::<Vec<_>>();
243+
expected.sort_by_cached_key(|x| x.to_string());
244+
expected.dedup();
245+
let expect = tokens_to_string(&expected[..]);
246+
let actual = self.this_token_to_string();
247+
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
248+
let short_expect = if expected.len() > 6 {
249+
format!("{} possible tokens", expected.len())
250+
} else {
251+
expect.clone()
252+
};
253+
(format!("expected one of {}, found `{}`", expect, actual),
254+
(self.sess.source_map().next_point(self.prev_span),
255+
format!("expected one of {} here", short_expect)))
256+
} else if expected.is_empty() {
257+
(format!("unexpected token: `{}`", actual),
258+
(self.prev_span, "unexpected token after this".to_string()))
259+
} else {
260+
(format!("expected {}, found `{}`", expect, actual),
261+
(self.sess.source_map().next_point(self.prev_span),
262+
format!("expected {} here", expect)))
263+
};
264+
self.last_unexpected_token_span = Some(self.span);
265+
let mut err = self.fatal(&msg_exp);
266+
if self.token.is_ident_named("and") {
267+
err.span_suggestion_short(
268+
self.span,
269+
"use `&&` instead of `and` for the boolean operator",
270+
"&&".to_string(),
271+
Applicability::MaybeIncorrect,
272+
);
273+
}
274+
if self.token.is_ident_named("or") {
275+
err.span_suggestion_short(
276+
self.span,
277+
"use `||` instead of `or` for the boolean operator",
278+
"||".to_string(),
279+
Applicability::MaybeIncorrect,
280+
);
281+
}
282+
let sp = if self.token == token::Token::Eof {
283+
// This is EOF, don't want to point at the following char, but rather the last token
284+
self.prev_span
285+
} else {
286+
label_sp
287+
};
288+
match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt {
289+
TokenType::Token(t) => Some(t.clone()),
290+
_ => None,
291+
}).collect::<Vec<_>>(), err) {
292+
Err(e) => err = e,
293+
Ok(recovered) => {
294+
return Ok(recovered);
295+
}
296+
}
297+
298+
let is_semi_suggestable = expected.iter().any(|t| match t {
299+
TokenType::Token(token::Semi) => true, // we expect a `;` here
300+
_ => false,
301+
}) && ( // a `;` would be expected before the current keyword
302+
self.token.is_keyword(kw::Break) ||
303+
self.token.is_keyword(kw::Continue) ||
304+
self.token.is_keyword(kw::For) ||
305+
self.token.is_keyword(kw::If) ||
306+
self.token.is_keyword(kw::Let) ||
307+
self.token.is_keyword(kw::Loop) ||
308+
self.token.is_keyword(kw::Match) ||
309+
self.token.is_keyword(kw::Return) ||
310+
self.token.is_keyword(kw::While)
311+
);
312+
let cm = self.sess.source_map();
313+
match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) {
314+
(Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => {
315+
// The spans are in different lines, expected `;` and found `let` or `return`.
316+
// High likelihood that it is only a missing `;`.
317+
err.span_suggestion_short(
318+
label_sp,
319+
"a semicolon may be missing here",
320+
";".to_string(),
321+
Applicability::MaybeIncorrect,
322+
);
323+
err.emit();
324+
return Ok(true);
325+
}
326+
(Ok(ref a), Ok(ref b)) if a.line == b.line => {
327+
// When the spans are in the same line, it means that the only content between
328+
// them is whitespace, point at the found token in that case:
329+
//
330+
// X | () => { syntax error };
331+
// | ^^^^^ expected one of 8 possible tokens here
332+
//
333+
// instead of having:
334+
//
335+
// X | () => { syntax error };
336+
// | -^^^^^ unexpected token
337+
// | |
338+
// | expected one of 8 possible tokens here
339+
err.span_label(self.span, label_exp);
340+
}
341+
_ if self.prev_span == syntax_pos::DUMMY_SP => {
342+
// Account for macro context where the previous span might not be
343+
// available to avoid incorrect output (#54841).
344+
err.span_label(self.span, "unexpected token");
345+
}
346+
_ => {
347+
err.span_label(sp, label_exp);
348+
err.span_label(self.span, "unexpected token");
349+
}
350+
}
351+
Err(err)
352+
}
353+
246354
/// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
247355
/// passes through any errors encountered. Used for error recovery.
248356
crate fn eat_to_tokens(&mut self, kets: &[&token::Token]) {
@@ -939,9 +1047,6 @@ impl<'a> Parser<'a> {
9391047
String::new(),
9401048
Applicability::MachineApplicable,
9411049
);
942-
err.note("if you meant to use emplacement syntax, it is obsolete (for now, anyway)");
943-
err.note("for more information on the status of emplacement syntax, see <\
944-
https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>");
9451050
err.emit();
9461051
}
9471052
}
@@ -1050,12 +1155,12 @@ impl<'a> Parser<'a> {
10501155
) -> PResult<'a, ast::Arg> {
10511156
let sp = arg.pat.span;
10521157
arg.ty.node = TyKind::Err;
1053-
let mut err = self.struct_span_err(sp, "unexpected `self` argument in function");
1158+
let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function");
10541159
if is_trait_item {
1055-
err.span_label(sp, "must be the first associated function argument");
1160+
err.span_label(sp, "must be the first associated function parameter");
10561161
} else {
1057-
err.span_label(sp, "not valid as function argument");
1058-
err.note("`self` is only valid as the first argument of an associated function");
1162+
err.span_label(sp, "not valid as function parameter");
1163+
err.note("`self` is only valid as the first parameter of an associated function");
10591164
}
10601165
err.emit();
10611166
Ok(arg)

0 commit comments

Comments
 (0)