Skip to content

Commit 235905c

Browse files
committed
Fix handling of trait methods with bodies and improve efficiency
1 parent b05f0be commit 235905c

File tree

6 files changed

+70
-39
lines changed

6 files changed

+70
-39
lines changed

src/librustc_passes/ast_validation.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -336,22 +336,24 @@ 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-
if block.is_none() {
340-
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
341-
if mut_ident {
339+
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
340+
if mut_ident {
341+
if block.is_none() {
342342
self.session.buffer_lint(
343343
lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
344344
trait_item.id, span,
345-
"patterns aren't allowed in methods without bodies");
346-
} else {
347-
let mut err = struct_span_err!(self.session, span, E0642,
348-
"patterns aren't allowed in methods without bodies");
349-
err.span_suggestion(span,
350-
"use an underscore to ignore the name", "_".to_owned());
351-
err.emit();
345+
"patterns aren't allowed in trait methods");
352346
}
353-
});
354-
}
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 a \
352+
tuple pattern";
353+
err.span_suggestion(span, suggestion, "_".to_owned());
354+
err.emit();
355+
}
356+
});
355357
}
356358
}
357359
}

src/libsyntax/parse/parser.rs

+30-19
Original file line numberDiff line numberDiff line change
@@ -1744,7 +1744,16 @@ 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-
let parser_snapshot_before_pat = self.clone();
1747+
// If we see `ident :`, then we know that the argument is 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+
};
17481757

17491758
// We're going to try parsing the argument as a pattern (even if it's not
17501759
// allowed, such as for trait methods without bodies). This way we can provide
@@ -1755,29 +1764,31 @@ impl<'a> Parser<'a> {
17551764
(pat, self.parse_ty()?)
17561765
};
17571766

1758-
let is_named_argument = self.is_named_argument();
17591767
match pat_arg {
17601768
Ok((pat, ty)) => {
17611769
Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
17621770
}
17631771
Err(mut err) => {
1764-
if require_name || is_named_argument {
1765-
Err(err)
1766-
} else {
1767-
err.cancel();
1768-
// Recover from attempting to parse the argument as a pattern. This means
1769-
// the type is alone, with no name, e.g. `fn foo(u32)`.
1770-
mem::replace(self, parser_snapshot_before_pat);
1771-
debug!("parse_arg_general ident_to_pat");
1772-
let ident = Ident::new(keywords::Invalid.name(), self.prev_span);
1773-
let ty = self.parse_ty()?;
1774-
let pat = P(Pat {
1775-
id: ast::DUMMY_NODE_ID,
1776-
node: PatKind::Ident(
1777-
BindingMode::ByValue(Mutability::Immutable), ident, None),
1778-
span: ty.span,
1779-
});
1780-
Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
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+
}
17811792
}
17821793
}
17831794
}

src/test/compile-fail/no-patterns-in-args-2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
#![deny(patterns_in_fns_without_body)]
1212

1313
trait Tr {
14-
fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
14+
fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in trait methods
1515
//~^ WARN was previously accepted
16-
fn f2(&arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
16+
fn f2(&arg: u8); //~ ERROR patterns aren't allowed in trait methods
1717
fn g1(arg: u8); // OK
1818
fn g2(_: u8); // OK
1919
#[allow(anonymous_parameters)]

src/test/compile-fail/no-patterns-in-args-macro.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ mod bad_pat {
3030
m!((bad, pat));
3131
//~^ ERROR patterns aren't allowed in function pointer types
3232
//~| ERROR patterns aren't allowed in foreign function declarations
33-
//~| ERROR patterns aren't allowed in methods without bodies
33+
//~| ERROR patterns aren't allowed in trait methods
3434
}
3535

3636
fn main() {}

src/test/ui/E0642.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
// except according to those terms.
1010

1111
trait Foo {
12-
fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies
12+
fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in trait methods
13+
}
14+
15+
trait Bar {
16+
fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods
1317
}
1418

1519
fn main() {}

src/test/ui/E0642.stderr

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
error[E0642]: patterns aren't allowed in methods without bodies
1+
error[E0642]: patterns aren't allowed in trait methods
22
--> $DIR/E0642.rs:12:12
33
|
4-
LL | fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in methods without bodies
5-
| ^^^^^^ help: use an underscore to ignore the name: `_`
4+
LL | fn foo((x, y): (i32, i32)); //~ ERROR patterns aren't allowed in trait methods
5+
| ^^^^^^
6+
help: give this argument a name or use an underscore to ignore it, instead of a tuple pattern
7+
|
8+
LL | fn foo(_: (i32, i32)); //~ ERROR patterns aren't allowed in trait methods
9+
| ^
10+
11+
error[E0642]: patterns aren't allowed in trait methods
12+
--> $DIR/E0642.rs:16:12
13+
|
14+
LL | fn bar((x, y): (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods
15+
| ^^^^^^
16+
help: give this argument a name or use an underscore to ignore it, instead of a tuple pattern
17+
|
18+
LL | fn bar(_: (i32, i32)) {} //~ ERROR patterns aren't allowed in trait methods
19+
| ^
620

7-
error: aborting due to previous error
21+
error: aborting due to 2 previous errors
822

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

0 commit comments

Comments
 (0)