Skip to content

Commit e4c3b49

Browse files
committed
Emit an error during parsing
1 parent a478cd4 commit e4c3b49

File tree

3 files changed

+74
-60
lines changed

3 files changed

+74
-60
lines changed

src/librustc_passes/ast_validation.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -336,24 +336,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
336336
if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
337337
self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness);
338338
self.check_trait_fn_not_const(sig.header.constness);
339-
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
340-
if mut_ident {
341-
if block.is_none() {
339+
if block.is_none() {
340+
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
341+
if mut_ident {
342342
self.session.buffer_lint(
343343
lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
344344
trait_item.id, span,
345345
"patterns aren't allowed in trait methods");
346+
} else {
347+
struct_span_err!(self.session, span, E0642,
348+
"patterns aren't allowed in trait methods").emit();
346349
}
347-
} else {
348-
let mut err = struct_span_err!(self.session, span, E0642,
349-
"patterns aren't allowed in trait methods");
350-
let suggestion = "give this argument a name or use an \
351-
underscore to ignore it instead of using a \
352-
tuple pattern";
353-
err.span_suggestion(span, suggestion, "_".to_owned());
354-
err.emit();
355-
}
356-
});
350+
});
351+
}
357352
}
358353
}
359354
}

src/libsyntax/parse/parser.rs

+62-42
Original file line numberDiff line numberDiff line change
@@ -1744,54 +1744,74 @@ impl<'a> Parser<'a> {
17441744
fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
17451745
maybe_whole!(self, NtArg, |x| x);
17461746

1747-
// If we see `ident :`, then we know that the argument is not just of the
1748-
// form `type`, which means we won't need to recover from parsing a
1749-
// pattern and so we don't need to store a parser snapshot.
1750-
let parser_snapshot_before_pat = if
1751-
self.look_ahead(1, |t| t.is_ident()) &&
1752-
self.look_ahead(2, |t| t == &token::Colon) {
1753-
None
1754-
} else {
1755-
Some(self.clone())
1756-
};
1757-
1758-
// We're going to try parsing the argument as a pattern (even if it's not
1759-
// allowed, such as for trait methods without bodies). This way we can provide
1760-
// better errors to the user.
1761-
let pat_arg: PResult<'a, (P<Pat>, P<Ty>)> = do catch {
1747+
let (pat, ty) = if require_name || self.is_named_argument() {
1748+
debug!("parse_arg_general parse_pat (require_name:{})",
1749+
require_name);
17621750
let pat = self.parse_pat()?;
1751+
17631752
self.expect(&token::Colon)?;
17641753
(pat, self.parse_ty()?)
1765-
};
1754+
} else {
1755+
debug!("parse_arg_general ident_to_pat");
1756+
1757+
// If we see `ident :`, then we know that the argument is not just of the
1758+
// form `type`, which means we won't need to recover from parsing a
1759+
// pattern and so we don't need to store a parser snapshot.
1760+
let parser_snapshot_before_pat = if
1761+
self.look_ahead(1, |t| t.is_ident()) &&
1762+
self.look_ahead(2, |t| t == &token::Colon) {
1763+
None
1764+
} else {
1765+
Some(self.clone())
1766+
};
17661767

1767-
match pat_arg {
1768-
Ok((pat, ty)) => {
1769-
Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
1770-
}
1771-
Err(mut err) => {
1772-
match (require_name || self.is_named_argument(), parser_snapshot_before_pat) {
1773-
(true, _) | (_, None) => {
1774-
Err(err)
1775-
}
1776-
(false, Some(parser_snapshot_before_pat)) => {
1777-
err.cancel();
1778-
// Recover from attempting to parse the argument as a pattern. This means
1779-
// the type is alone, with no name, e.g. `fn foo(u32)`.
1780-
mem::replace(self, parser_snapshot_before_pat);
1781-
debug!("parse_arg_general ident_to_pat");
1782-
let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
1783-
let ty = self.parse_ty()?;
1784-
let pat = P(Pat {
1785-
id: ast::DUMMY_NODE_ID,
1786-
node: PatKind::Ident(
1787-
BindingMode::ByValue(Mutability::Immutable), ident, None),
1788-
span: ty.span,
1789-
});
1790-
Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
1791-
}
1768+
// We're going to try parsing the argument as a pattern (even though it's not
1769+
// allowed). This way we can provide better errors to the user.
1770+
let pat_arg: PResult<'a, _> = do catch {
1771+
let pat = self.parse_pat()?;
1772+
self.expect(&token::Colon)?;
1773+
(pat, self.parse_ty()?)
1774+
};
1775+
1776+
match pat_arg {
1777+
Ok((pat, ty)) => {
1778+
let mut err = self.diagnostic()
1779+
.struct_span_err(pat.span, "patterns aren't allowed in trait methods");
1780+
err.span_suggestion_short_with_applicability(
1781+
pat.span,
1782+
"give this argument a name or use an underscore to ignore it",
1783+
"_".to_owned(),
1784+
Applicability::MachineApplicable,
1785+
);
1786+
err.emit();
1787+
// Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
1788+
let pat = P(Pat {
1789+
node: PatKind::Wild,
1790+
span: pat.span,
1791+
id: ast::DUMMY_NODE_ID
1792+
});
1793+
(pat, ty)
1794+
}
1795+
Err(mut err) => {
1796+
err.cancel();
1797+
// Recover from attempting to parse the argument as a pattern. This means
1798+
// the type is alone, with no name, e.g. `fn foo(u32)`.
1799+
mem::replace(self, parser_snapshot_before_pat.unwrap());
1800+
debug!("parse_arg_general ident_to_pat");
1801+
let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
1802+
let ty = self.parse_ty()?;
1803+
let pat = P(Pat {
1804+
id: ast::DUMMY_NODE_ID,
1805+
node: PatKind::Ident(
1806+
BindingMode::ByValue(Mutability::Immutable), ident, None),
1807+
span: ty.span,
1808+
});
1809+
(pat, ty)
17921810
}
17931811
}
1794-
}
1812+
};
1813+
1814+
Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
17951815
}
17961816

17971817
/// Parse a single function argument

src/test/ui/E0642.stderr

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
1-
error[E0642]: patterns aren't allowed in trait methods
1+
error: patterns aren't allowed in trait methods
22
--> $DIR/E0642.rs:12:12
33
|
44
LL | fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in trait methods
55
| ^^^^^^
6-
help: give this argument a name or use an underscore to ignore it instead of using a tuple pattern
6+
help: give this argument a name or use an underscore to ignore it
77
|
88
LL | fn foo(_: (i32, i32)); //~ ERROR patterns aren't allowed in trait methods
99
| ^
1010

11-
error[E0642]: patterns aren't allowed in trait methods
11+
error: patterns aren't allowed in trait methods
1212
--> $DIR/E0642.rs:16:12
1313
|
1414
LL | fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods
1515
| ^^^^^^
16-
help: give this argument a name or use an underscore to ignore it instead of using a tuple pattern
16+
help: give this argument a name or use an underscore to ignore it
1717
|
1818
LL | fn bar(_: (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods
1919
| ^
2020

2121
error: aborting due to 2 previous errors
2222

23-
For more information about this error, try `rustc --explain E0642`.

0 commit comments

Comments
 (0)