Skip to content

Commit

Permalink
Auto merge of #45775 - petrochenkov:patnopat, r=nikomatsakis
Browse files Browse the repository at this point in the history
Accept interpolated patterns in trait method parameters

Permit this, basically
```rust
macro_rules! m {
    ($pat: pat) => {
        trait Tr {
            fn f($pat: u8) {}
        }
    }
}
```
it previously caused a parsing error during expansion because trait methods accept only very restricted set of patterns during parsing due to ambiguities caused by [anonymous parameters](#41686), and this set didn't include interpolated patterns.

Some outdated messages from "no patterns allowed" errors are also removed.

Addresses #35203 (comment)
  • Loading branch information
bors committed Nov 11, 2017
2 parents 965ace5 + f7b4b88 commit b226793
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 49 deletions.
45 changes: 18 additions & 27 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ impl<'a> AstValidator<'a> {
match arg.pat.node {
PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) |
PatKind::Wild => {}
PatKind::Ident(..) => report_err(arg.pat.span, true),
PatKind::Ident(BindingMode::ByValue(Mutability::Mutable), _, None) =>
report_err(arg.pat.span, true),
_ => report_err(arg.pat.span, false),
}
}
Expand Down Expand Up @@ -151,14 +152,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
match ty.node {
TyKind::BareFn(ref bfty) => {
self.check_decl_no_pat(&bfty.decl, |span, _| {
let mut err = struct_span_err!(self.session,
span,
E0561,
"patterns aren't allowed in function pointer \
types");
err.span_note(span,
"this is a recent error, see issue #35203 for more details");
err.emit();
struct_span_err!(self.session, span, E0561,
"patterns aren't allowed in function pointer types").emit();
});
}
TyKind::TraitObject(ref bounds, ..) => {
Expand Down Expand Up @@ -260,12 +255,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
self.check_trait_fn_not_const(sig.constness);
if block.is_none() {
self.check_decl_no_pat(&sig.decl, |span, _| {
self.session.buffer_lint(
lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
trait_item.id, span,
"patterns aren't allowed in methods \
without bodies");
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
if mut_ident {
self.session.buffer_lint(
lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY,
trait_item.id, span,
"patterns aren't allowed in methods without bodies");
} else {
struct_span_err!(self.session, span, E0642,
"patterns aren't allowed in methods without bodies").emit();
}
});
}
}
Expand Down Expand Up @@ -299,18 +298,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
match fi.node {
ForeignItemKind::Fn(ref decl, _) => {
self.check_decl_no_pat(decl, |span, is_recent| {
let mut err = struct_span_err!(self.session,
span,
E0130,
"patterns aren't allowed in foreign function \
declarations");
err.span_label(span, "pattern not allowed in foreign function");
if is_recent {
err.span_note(span,
"this is a recent error, see issue #35203 for more details");
}
err.emit();
self.check_decl_no_pat(decl, |span, _| {
struct_span_err!(self.session, span, E0130,
"patterns aren't allowed in foreign function declarations")
.span_label(span, "pattern not allowed in foreign function").emit();
});
}
ForeignItemKind::Static(..) | ForeignItemKind::Ty => {}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_passes/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,5 @@ register_diagnostics! {
E0226, // only a single explicit lifetime bound is permitted
E0472, // asm! is unsupported on this target
E0561, // patterns aren't allowed in function pointer types
E0642, // patterns aren't allowed in methods without bodies
}
26 changes: 9 additions & 17 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,10 +360,6 @@ impl TokenType {
}
}

fn is_ident_or_underscore(t: &token::Token) -> bool {
t.is_ident() || *t == token::Underscore
}

// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`.
fn can_continue_type_after_ident(t: &token::Token) -> bool {
Expand Down Expand Up @@ -1625,23 +1621,19 @@ impl<'a> Parser<'a> {
Ok(MutTy { ty: t, mutbl: mutbl })
}

pub fn is_named_argument(&mut self) -> bool {
fn is_named_argument(&mut self) -> bool {
let offset = match self.token {
token::BinOp(token::And) |
token::AndAnd => 1,
token::Interpolated(ref nt) => match nt.0 {
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
_ => 0,
}
token::BinOp(token::And) | token::AndAnd => 1,
_ if self.token.is_keyword(keywords::Mut) => 1,
_ => 0
_ => 0,
};

debug!("parser is_named_argument offset:{}", offset);

if offset == 0 {
is_ident_or_underscore(&self.token)
&& self.look_ahead(1, |t| *t == token::Colon)
} else {
self.look_ahead(offset, |t| is_ident_or_underscore(t))
&& self.look_ahead(offset + 1, |t| *t == token::Colon)
}
self.look_ahead(offset, |t| t.is_ident() || t == &token::Underscore) &&
self.look_ahead(offset + 1, |t| t == &token::Colon)
}

/// This version of parse arg doesn't necessarily require
Expand Down
1 change: 0 additions & 1 deletion src/test/compile-fail/no-patterns-in-args-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ trait Tr {
fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
//~^ WARN was previously accepted
fn f2(&arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
//~^ WARN was previously accepted
fn g1(arg: u8); // OK
fn g2(_: u8); // OK
#[allow(anonymous_parameters)]
Expand Down
36 changes: 36 additions & 0 deletions src/test/compile-fail/no-patterns-in-args-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

macro_rules! m {
($pat: pat) => {
trait Tr {
fn trait_method($pat: u8);
}

type A = fn($pat: u8);

extern {
fn foreign_fn($pat: u8);
}
}
}

mod good_pat {
m!(good_pat); // OK
}

mod bad_pat {
m!((bad, pat));
//~^ ERROR patterns aren't allowed in function pointer types
//~| ERROR patterns aren't allowed in foreign function declarations
//~| ERROR patterns aren't allowed in methods without bodies
}

fn main() {}
4 changes: 0 additions & 4 deletions src/test/compile-fail/no-patterns-in-args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,17 @@
extern {
fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations
//~^ NOTE pattern not allowed in foreign function
//~| NOTE this is a recent error
fn f2(&arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations
//~^ NOTE pattern not allowed in foreign function
fn f3(arg @ _: u8); //~ ERROR patterns aren't allowed in foreign function declarations
//~^ NOTE pattern not allowed in foreign function
//~| NOTE this is a recent error
fn g1(arg: u8); // OK
fn g2(_: u8); // OK
// fn g3(u8); // Not yet
}

type A1 = fn(mut arg: u8); //~ ERROR patterns aren't allowed in function pointer types
//~^ NOTE this is a recent error
type A2 = fn(&arg: u8); //~ ERROR patterns aren't allowed in function pointer types
//~^ NOTE this is a recent error
type B1 = fn(arg: u8); // OK
type B2 = fn(_: u8); // OK
type B3 = fn(u8); // OK
Expand Down

0 comments on commit b226793

Please sign in to comment.