From 2e812e10f4ece10d90ae3315aba16b88c5e870eb Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 2 May 2016 18:22:03 +0200 Subject: [PATCH 1/9] syntax/hir: give loop labels a span This makes the "shadowing labels" warning *not* print the entire loop as a span, but only the lifetime. Also makes #31719 go away, but does not fix its root cause (the span of the expanded loop is still wonky, but not used anymore). --- src/librustc/hir/fold.rs | 8 ++++-- src/librustc/hir/intravisit.rs | 22 ++++++++------- src/librustc/hir/lowering.rs | 23 +++++++--------- src/librustc/hir/mod.rs | 4 +-- src/librustc/hir/print.rs | 12 ++++----- src/librustc/middle/resolve_lifetime.rs | 13 ++++----- src/librustc_incremental/calculate_svh.rs | 2 +- src/librustc_resolve/lib.rs | 6 ++--- src/libsyntax/ast.rs | 8 +++--- src/libsyntax/ext/expand.rs | 14 +++++----- src/libsyntax/fold.rs | 12 ++++++--- src/libsyntax/parse/parser.rs | 17 ++++++------ src/libsyntax/print/pprust.rs | 8 +++--- src/libsyntax/visit.rs | 33 +++++++++++++---------- 14 files changed, 99 insertions(+), 83 deletions(-) diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index a91d16f25a2..58f1006f98e 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -1009,11 +1009,15 @@ pub fn noop_fold_expr(Expr { id, node, span, attrs }: Expr, folder: & ExprWhile(cond, body, opt_name) => { ExprWhile(folder.fold_expr(cond), folder.fold_block(body), - opt_name.map(|i| folder.fold_name(i))) + opt_name.map(|label| { + respan(folder.new_span(label.span), folder.fold_name(label.node)) + })) } ExprLoop(body, opt_name) => { ExprLoop(folder.fold_block(body), - opt_name.map(|i| folder.fold_name(i))) + opt_name.map(|label| { + respan(folder.new_span(label.span), folder.fold_name(label.node)) + })) } ExprMatch(expr, arms, source) => { ExprMatch(folder.fold_expr(expr), diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2e9e433b830..9c61271fbfb 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -28,7 +28,7 @@ use syntax::abi::Abi; use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax::attr::ThinAttributesExt; -use syntax::codemap::Span; +use syntax::codemap::{Span, Spanned}; use hir::*; use std::cmp; @@ -203,11 +203,17 @@ pub trait Visitor<'v> : Sized { } pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { - for name in opt_name { + if let Some(name) = opt_name { visitor.visit_name(span, name); } } +pub fn walk_opt_sp_name<'v, V: Visitor<'v>>(visitor: &mut V, opt_sp_name: &Option>) { + if let Some(ref sp_name) = *opt_sp_name { + visitor.visit_name(sp_name.span, sp_name.node); + } +} + /// Walks the contents of a crate. See also `Crate::visit_all_items`. pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); @@ -737,14 +743,14 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_block(if_block); walk_list!(visitor, visit_expr, optional_else); } - ExprWhile(ref subexpression, ref block, opt_name) => { + ExprWhile(ref subexpression, ref block, ref opt_sp_name) => { visitor.visit_expr(subexpression); visitor.visit_block(block); - walk_opt_name(visitor, expression.span, opt_name) + walk_opt_sp_name(visitor, opt_sp_name); } - ExprLoop(ref block, opt_name) => { + ExprLoop(ref block, ref opt_sp_name) => { visitor.visit_block(block); - walk_opt_name(visitor, expression.span, opt_name) + walk_opt_sp_name(visitor, opt_sp_name); } ExprMatch(ref subexpression, ref arms, _) => { visitor.visit_expr(subexpression); @@ -784,9 +790,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_path(path, expression.id) } ExprBreak(ref opt_sp_name) | ExprAgain(ref opt_sp_name) => { - for sp_name in opt_sp_name { - visitor.visit_name(sp_name.span, sp_name.node); - } + walk_opt_sp_name(visitor, opt_sp_name); } ExprRet(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 28506fd20fe..56777dc41d7 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -192,6 +192,10 @@ impl<'a> LoweringContext<'a> { } } + fn lower_opt_sp_ident(&mut self, o_id: Option>) -> Option> { + o_id.map(|sp_ident| respan(sp_ident.span, self.lower_ident(sp_ident.node))) + } + fn lower_attrs(&mut self, attrs: &Vec) -> hir::HirVec { attrs.clone().into() } @@ -1122,11 +1126,10 @@ impl<'a> LoweringContext<'a> { } ExprKind::While(ref cond, ref body, opt_ident) => { hir::ExprWhile(self.lower_expr(cond), self.lower_block(body), - opt_ident.map(|ident| self.lower_ident(ident))) + self.lower_opt_sp_ident(opt_ident)) } ExprKind::Loop(ref body, opt_ident) => { - hir::ExprLoop(self.lower_block(body), - opt_ident.map(|ident| self.lower_ident(ident))) + hir::ExprLoop(self.lower_block(body), self.lower_opt_sp_ident(opt_ident)) } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(self.lower_expr(expr), @@ -1243,12 +1246,8 @@ impl<'a> LoweringContext<'a> { }; hir::ExprPath(hir_qself, self.lower_path_full(path, rename)) } - ExprKind::Break(opt_ident) => hir::ExprBreak(opt_ident.map(|sp_ident| { - respan(sp_ident.span, self.lower_ident(sp_ident.node)) - })), - ExprKind::Again(opt_ident) => hir::ExprAgain(opt_ident.map(|sp_ident| { - respan(sp_ident.span, self.lower_ident(sp_ident.node)) - })), + ExprKind::Break(opt_ident) => hir::ExprBreak(self.lower_opt_sp_ident(opt_ident)), + ExprKind::Again(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)), ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| self.lower_expr(x))), ExprKind::InlineAsm(InlineAsm { ref inputs, @@ -1422,8 +1421,7 @@ impl<'a> LoweringContext<'a> { // `[opt_ident]: loop { ... }` let loop_block = self.block_expr(match_expr); - let loop_expr = hir::ExprLoop(loop_block, - opt_ident.map(|ident| self.lower_ident(ident))); + let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident)); // add attributes to the outer returned expr node let attrs = e.attrs.clone(); return P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs }); @@ -1503,8 +1501,7 @@ impl<'a> LoweringContext<'a> { // `[opt_ident]: loop { ... }` let loop_block = self.block_expr(match_expr); - let loop_expr = hir::ExprLoop(loop_block, - opt_ident.map(|ident| self.lower_ident(ident))); + let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident)); let loop_expr = P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: None }); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 39a6ec9f3af..b147782316f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -873,11 +873,11 @@ pub enum Expr_ { /// A while loop, with an optional label /// /// `'label: while expr { block }` - ExprWhile(P, P, Option), + ExprWhile(P, P, Option>), /// Conditionless loop (can be exited with break, continue, or return) /// /// `'label: loop { block }` - ExprLoop(P, Option), + ExprLoop(P, Option>), /// A `match` block, with a source that indicates whether or not it is /// the result of a desugaring, and if so, which kind. ExprMatch(P, HirVec, MatchSource), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 4455c7da3ba..74bc688d154 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1351,9 +1351,9 @@ impl<'a> State<'a> { hir::ExprIf(ref test, ref blk, ref elseopt) => { self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; } - hir::ExprWhile(ref test, ref blk, opt_name) => { - if let Some(name) = opt_name { - self.print_name(name)?; + hir::ExprWhile(ref test, ref blk, opt_sp_name) => { + if let Some(sp_name) = opt_sp_name { + self.print_name(sp_name.node)?; self.word_space(":")?; } self.head("while")?; @@ -1361,9 +1361,9 @@ impl<'a> State<'a> { space(&mut self.s)?; self.print_block(&blk)?; } - hir::ExprLoop(ref blk, opt_name) => { - if let Some(name) = opt_name { - self.print_name(name)?; + hir::ExprLoop(ref blk, opt_sp_name) => { + if let Some(sp_name) = opt_sp_name { + self.print_name(sp_name.node)?; self.word_space(":")?; } self.head("loop")?; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2200d72c883..4cc9b0b4353 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -404,23 +404,23 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) { if let hir::ExprClosure(..) = ex.node { return } - if let Some(label) = expression_label(ex) { + if let Some((label, label_span)) = expression_label(ex) { for &(prior, prior_span) in &self.labels_in_fn[..] { // FIXME (#24278): non-hygienic comparison if label == prior { signal_shadowing_problem(self.sess, label, original_label(prior_span), - shadower_label(ex.span)); + shadower_label(label_span)); } } check_if_label_shadows_lifetime(self.sess, self.scope, label, - ex.span); + label_span); - self.labels_in_fn.push((label, ex.span)); + self.labels_in_fn.push((label, label_span)); } intravisit::walk_expr(self, ex) } @@ -430,10 +430,11 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) { } } - fn expression_label(ex: &hir::Expr) -> Option { + fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> { match ex.node { hir::ExprWhile(_, _, Some(label)) | - hir::ExprLoop(_, Some(label)) => Some(label.unhygienize()), + hir::ExprLoop(_, Some(label)) => Some((label.node.unhygienize(), + label.span)), _ => None, } } diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index 24ecce11487..3dd1b6eb205 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -251,7 +251,7 @@ mod svh_visitor { ExprType(..) => SawExprType, ExprIf(..) => SawExprIf, ExprWhile(..) => SawExprWhile, - ExprLoop(_, id) => SawExprLoop(id.map(|id| id.as_str())), + ExprLoop(_, id) => SawExprLoop(id.map(|id| id.node.as_str())), ExprMatch(..) => SawExprMatch, ExprClosure(..) => SawExprClosure, ExprBlock(..) => SawExprBlock, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 61ed88ec173..0dcbb9c2771 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3086,7 +3086,7 @@ impl<'a> Resolver<'a> { { let rib = this.label_ribs.last_mut().unwrap(); - rib.bindings.insert(mtwt::resolve(label), def); + rib.bindings.insert(mtwt::resolve(label.node), def); } visit::walk_expr(this, expr); @@ -3131,7 +3131,7 @@ impl<'a> Resolver<'a> { self.value_ribs.push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, RefutableMode, &mut HashMap::new()); - self.resolve_labeled_block(label, expr.id, block); + self.resolve_labeled_block(label.map(|l| l.node), expr.id, block); self.value_ribs.pop(); } @@ -3141,7 +3141,7 @@ impl<'a> Resolver<'a> { self.value_ribs.push(Rib::new(NormalRibKind)); self.resolve_pattern(pattern, LocalIrrefutableMode, &mut HashMap::new()); - self.resolve_labeled_block(label, expr.id, block); + self.resolve_labeled_block(label.map(|l| l.node), expr.id, block); self.value_ribs.pop(); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d9409d3bbd9..4a94d8b01a3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1007,23 +1007,23 @@ pub enum ExprKind { /// A while loop, with an optional label /// /// `'label: while expr { block }` - While(P, P, Option), + While(P, P, Option), /// A while-let loop, with an optional label /// /// `'label: while let pat = expr { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. - WhileLet(P, P, P, Option), + WhileLet(P, P, P, Option), /// A for loop, with an optional label /// /// `'label: for pat in expr { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. - ForLoop(P, P, P, Option), + ForLoop(P, P, P, Option), /// Conditionless loop (can be exited with break, continue, or return) /// /// `'label: loop { block }` - Loop(P, Option), + Loop(P, Option), /// A `match` block. Match(P, Vec), /// A closure (for example, `move |a, b, c| {a + b + c}`) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f243706eecb..96f4e0d3bdf 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -9,7 +9,7 @@ // except according to those terms. use ast::{Block, Crate, DeclKind, PatKind}; -use ast::{Local, Ident, Mac_, Name}; +use ast::{Local, Ident, Mac_, Name, SpannedIdent}; use ast::{MacStmtStyle, Mrk, Stmt, StmtKind, ItemKind}; use ast::TokenTree; use ast; @@ -277,12 +277,12 @@ fn expand_mac_invoc(mac: ast::Mac, /// body is in a block enclosed by loop head so the renaming of loop label /// must be propagated to the enclosed context. fn expand_loop_block(loop_block: P, - opt_ident: Option, - fld: &mut MacroExpander) -> (P, Option) { + opt_ident: Option, + fld: &mut MacroExpander) -> (P, Option) { match opt_ident { Some(label) => { - let new_label = fresh_name(label); - let rename = (label, new_label); + let new_label = fresh_name(label.node); + let rename = (label.node, new_label); // The rename *must not* be added to the pending list of current // syntax context otherwise an unrelated `break` or `continue` in @@ -290,7 +290,7 @@ fn expand_loop_block(loop_block: P, // and be renamed incorrectly. let mut rename_list = vec!(rename); let mut rename_fld = IdentRenamer{renames: &mut rename_list}; - let renamed_ident = rename_fld.fold_ident(label); + let renamed_ident = rename_fld.fold_ident(label.node); // The rename *must* be added to the enclosed syntax context for // `break` or `continue` to pick up because by definition they are @@ -300,7 +300,7 @@ fn expand_loop_block(loop_block: P, let expanded_block = expand_block_elts(loop_block, fld); fld.cx.syntax_env.pop_frame(); - (expanded_block, Some(renamed_ident)) + (expanded_block, Some(Spanned { node: renamed_ident, span: label.span })) } None => (fld.fold_block(loop_block), opt_ident) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2c325080c0c..f25be190537 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1212,23 +1212,27 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::While(cond, body, opt_ident) => { ExprKind::While(folder.fold_expr(cond), folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_ident.map(|label| respan(folder.new_span(label.span), + folder.fold_ident(label.node)))) } ExprKind::WhileLet(pat, expr, body, opt_ident) => { ExprKind::WhileLet(folder.fold_pat(pat), folder.fold_expr(expr), folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_ident.map(|label| respan(folder.new_span(label.span), + folder.fold_ident(label.node)))) } ExprKind::ForLoop(pat, iter, body, opt_ident) => { ExprKind::ForLoop(folder.fold_pat(pat), folder.fold_expr(iter), folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_ident.map(|label| respan(folder.new_span(label.span), + folder.fold_ident(label.node)))) } ExprKind::Loop(body, opt_ident) => { ExprKind::Loop(folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_ident.map(|label| respan(folder.new_span(label.span), + folder.fold_ident(label.node)))) } ExprKind::Match(expr, arms) => { ExprKind::Match(folder.fold_expr(expr), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fc62cee92fd..b616b9db9c3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2283,18 +2283,19 @@ impl<'a> Parser<'a> { return self.parse_while_expr(None, lo, attrs); } if self.token.is_lifetime() { - let lifetime = self.get_lifetime(); + let label = Spanned { node: self.get_lifetime(), + span: self.span }; let lo = self.span.lo; self.bump(); self.expect(&token::Colon)?; if self.eat_keyword(keywords::While) { - return self.parse_while_expr(Some(lifetime), lo, attrs) + return self.parse_while_expr(Some(label), lo, attrs) } if self.eat_keyword(keywords::For) { - return self.parse_for_expr(Some(lifetime), lo, attrs) + return self.parse_for_expr(Some(label), lo, attrs) } if self.eat_keyword(keywords::Loop) { - return self.parse_loop_expr(Some(lifetime), lo, attrs) + return self.parse_loop_expr(Some(label), lo, attrs) } return Err(self.fatal("expected `while`, `for`, or `loop` after a label")) } @@ -3264,7 +3265,7 @@ impl<'a> Parser<'a> { } /// Parse a 'for' .. 'in' expression ('for' token already eaten) - pub fn parse_for_expr(&mut self, opt_ident: Option, + pub fn parse_for_expr(&mut self, opt_ident: Option, span_lo: BytePos, attrs: ThinAttributes) -> PResult<'a, P> { // Parse: `for in ` @@ -3283,7 +3284,7 @@ impl<'a> Parser<'a> { } /// Parse a 'while' or 'while let' expression ('while' token already eaten) - pub fn parse_while_expr(&mut self, opt_ident: Option, + pub fn parse_while_expr(&mut self, opt_ident: Option, span_lo: BytePos, attrs: ThinAttributes) -> PResult<'a, P> { if self.token.is_keyword(keywords::Let) { @@ -3298,7 +3299,7 @@ impl<'a> Parser<'a> { } /// Parse a 'while let' expression ('while' token already eaten) - pub fn parse_while_let_expr(&mut self, opt_ident: Option, + pub fn parse_while_let_expr(&mut self, opt_ident: Option, span_lo: BytePos, attrs: ThinAttributes) -> PResult<'a, P> { self.expect_keyword(keywords::Let)?; @@ -3312,7 +3313,7 @@ impl<'a> Parser<'a> { } // parse `loop {...}`, `loop` token already eaten - pub fn parse_loop_expr(&mut self, opt_ident: Option, + pub fn parse_loop_expr(&mut self, opt_ident: Option, span_lo: BytePos, attrs: ThinAttributes) -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ebb4927d69c..fec84e912d4 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2021,7 +2021,7 @@ impl<'a> State<'a> { } ast::ExprKind::While(ref test, ref blk, opt_ident) => { if let Some(ident) = opt_ident { - self.print_ident(ident)?; + self.print_ident(ident.node)?; self.word_space(":")?; } self.head("while")?; @@ -2031,7 +2031,7 @@ impl<'a> State<'a> { } ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_ident) => { if let Some(ident) = opt_ident { - self.print_ident(ident)?; + self.print_ident(ident.node)?; self.word_space(":")?; } self.head("while let")?; @@ -2044,7 +2044,7 @@ impl<'a> State<'a> { } ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_ident) => { if let Some(ident) = opt_ident { - self.print_ident(ident)?; + self.print_ident(ident.node)?; self.word_space(":")?; } self.head("for")?; @@ -2057,7 +2057,7 @@ impl<'a> State<'a> { } ast::ExprKind::Loop(ref blk, opt_ident) => { if let Some(ident) = opt_ident { - self.print_ident(ident)?; + self.print_ident(ident.node)?; self.word_space(":")?; } self.head("loop")?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f50a480e5e5..3bd300a8e8c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -26,7 +26,7 @@ use abi::Abi; use ast::*; use attr::ThinAttributesExt; -use codemap::Span; +use codemap::{Span, Spanned}; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { @@ -149,17 +149,24 @@ macro_rules! walk_list { } pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option) { - for name in opt_name { + if let Some(name) = opt_name { visitor.visit_name(span, name); } } pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option) { - for ident in opt_ident { + if let Some(ident) = opt_ident { visitor.visit_ident(span, ident); } } +pub fn walk_opt_sp_ident<'v, V: Visitor<'v>>(visitor: &mut V, + opt_sp_ident: &Option>) { + if let Some(ref sp_ident) = *opt_sp_ident { + visitor.visit_ident(sp_ident.span, sp_ident.node); + } +} + pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) { visitor.visit_name(span, ident.name); } @@ -712,10 +719,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_block(if_block); walk_list!(visitor, visit_expr, optional_else); } - ExprKind::While(ref subexpression, ref block, opt_ident) => { + ExprKind::While(ref subexpression, ref block, ref opt_sp_ident) => { visitor.visit_expr(subexpression); visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_sp_ident(visitor, opt_sp_ident); } ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => { visitor.visit_pat(pattern); @@ -723,21 +730,21 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_block(if_block); walk_list!(visitor, visit_expr, optional_else); } - ExprKind::WhileLet(ref pattern, ref subexpression, ref block, opt_ident) => { + ExprKind::WhileLet(ref pattern, ref subexpression, ref block, ref opt_sp_ident) => { visitor.visit_pat(pattern); visitor.visit_expr(subexpression); visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_sp_ident(visitor, opt_sp_ident); } - ExprKind::ForLoop(ref pattern, ref subexpression, ref block, opt_ident) => { + ExprKind::ForLoop(ref pattern, ref subexpression, ref block, ref opt_sp_ident) => { visitor.visit_pat(pattern); visitor.visit_expr(subexpression); visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_sp_ident(visitor, opt_sp_ident); } - ExprKind::Loop(ref block, opt_ident) => { + ExprKind::Loop(ref block, ref opt_sp_ident) => { visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_sp_ident(visitor, opt_sp_ident); } ExprKind::Match(ref subexpression, ref arms) => { visitor.visit_expr(subexpression); @@ -781,9 +788,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_path(path, expression.id) } ExprKind::Break(ref opt_sp_ident) | ExprKind::Again(ref opt_sp_ident) => { - for sp_ident in opt_sp_ident { - visitor.visit_ident(sp_ident.span, sp_ident.node); - } + walk_opt_sp_ident(visitor, opt_sp_ident); } ExprKind::Ret(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); From 3bef085ea8da749c234fb4afc749810a5b9c6c16 Mon Sep 17 00:00:00 2001 From: Kamal Marhubi Date: Tue, 24 May 2016 16:08:01 +0200 Subject: [PATCH 2/9] syntax: Make codemap::get_filemap() return an Option This is more idiomatic, putting the caller in charge of whether or not to panic. --- src/librustc_driver/pretty.rs | 1 + src/libsyntax/codemap.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 8c84e561e31..0a093887c50 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -757,6 +757,7 @@ fn get_source(input: &Input, sess: &Session) -> (Vec, String) { let src_name = driver::source_name(input); let src = sess.codemap() .get_filemap(&src_name) + .unwrap() .src .as_ref() .unwrap() diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index ca8708fdc83..3b13bf2fc50 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -1191,13 +1191,13 @@ impl CodeMap { } } - pub fn get_filemap(&self, filename: &str) -> Rc { + pub fn get_filemap(&self, filename: &str) -> Option> { for fm in self.files.borrow().iter() { if filename == fm.name { - return fm.clone(); + return Some(fm.clone()); } } - panic!("asking for {} which we don't know about", filename); + None } /// For a global BytePos compute the local offset within the containing FileMap From 5660a004862e5f7634084fd6e9c6e09f60f60121 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 3/9] Remove ExplicitSelf from AST --- src/librustc/hir/lowering.rs | 6 +- src/librustc/hir/mod.rs | 3 + src/librustc/lint/context.rs | 5 - src/librustc/lint/mod.rs | 2 - src/librustc_resolve/build_reduced_graph.rs | 4 +- src/librustc_typeck/astconv.rs | 3 +- src/libsyntax/ast.rs | 84 +++++++------- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/fold.rs | 32 +----- src/libsyntax/parse/parser.rs | 118 ++++++++++---------- src/libsyntax/print/pprust.rs | 78 +++++-------- src/libsyntax/util/node_count.rs | 4 - src/libsyntax/visit.rs | 23 ---- src/libsyntax_ext/deriving/generic/mod.rs | 42 +++---- src/libsyntax_ext/deriving/generic/ty.rs | 10 +- 15 files changed, 155 insertions(+), 261 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 28506fd20fe..48b4b867ee2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -788,10 +788,10 @@ impl<'a> LoweringContext<'a> { fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig { // Check for `self: _` and `self: &_` - if let SelfKind::Explicit(ref ty, _) = sig.explicit_self.node { - match sig.decl.inputs.get(0).and_then(Arg::to_self).map(|eself| eself.node) { + if !sig.self_shortcut { + match sig.decl.get_self().map(|eself| eself.node) { Some(SelfKind::Value(..)) | Some(SelfKind::Region(..)) => { - self.id_assigner.diagnostic().span_err(ty.span, + self.id_assigner.diagnostic().span_err(sig.decl.inputs[0].ty.span, "the type placeholder `_` is not allowed within types on item signatures"); } _ => {} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 39a6ec9f3af..b9f0f6ab5d5 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1175,6 +1175,9 @@ pub struct FnDecl { } impl FnDecl { + pub fn get_self(&self) -> Option { + self.inputs.get(0).and_then(Arg::to_self) + } pub fn has_self(&self) -> bool { self.inputs.get(0).map(Arg::is_self).unwrap_or(false) } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 0801f8f4ac7..94f17ea779a 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1043,11 +1043,6 @@ impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> { run_lints!(self, check_lifetime_def, early_passes, lt); } - fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) { - run_lints!(self, check_explicit_self, early_passes, es); - ast_visit::walk_explicit_self(self, es); - } - fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) { run_lints!(self, check_path, early_passes, p, id); ast_visit::walk_path(self, p); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 28994e1a7c4..cc7fa54bd0a 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -167,7 +167,6 @@ pub trait LateLintPass: LintPass { fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { } fn check_lifetime(&mut self, _: &LateContext, _: &hir::Lifetime) { } fn check_lifetime_def(&mut self, _: &LateContext, _: &hir::LifetimeDef) { } - fn check_explicit_self(&mut self, _: &LateContext, _: &hir::ExplicitSelf) { } fn check_path(&mut self, _: &LateContext, _: &hir::Path, _: ast::NodeId) { } fn check_path_list_item(&mut self, _: &LateContext, _: &hir::PathListItem) { } fn check_attribute(&mut self, _: &LateContext, _: &ast::Attribute) { } @@ -218,7 +217,6 @@ pub trait EarlyLintPass: LintPass { fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { } fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { } fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { } - fn check_explicit_self(&mut self, _: &EarlyContext, _: &ast::ExplicitSelf) { } fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { } fn check_path_list_item(&mut self, _: &EarlyContext, _: &ast::PathListItem) { } fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f56b22f9248..e0243bf4fa6 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -35,7 +35,7 @@ use syntax::codemap::{Span, DUMMY_SP}; use syntax::ast::{Block, Crate, DeclKind}; use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, PathListItemKind}; -use syntax::ast::{SelfKind, Stmt, StmtKind, TraitItemKind}; +use syntax::ast::{Stmt, StmtKind, TraitItemKind}; use syntax::ast::{Variant, ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::visit::{self, Visitor}; @@ -335,7 +335,7 @@ impl<'b> Resolver<'b> { let (def, ns) = match item.node { TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS), TraitItemKind::Method(ref sig, _) => { - is_static_method = sig.explicit_self.node == SelfKind::Static; + is_static_method = !sig.decl.has_self(); (Def::Method(item_def_id), ValueNS) } TraitItemKind::Type(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS), diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1df12b63e0a..fc1abb56d5a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1833,8 +1833,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // lifetime elision, we can determine it in two ways. First (determined // here), if self is by-reference, then the implied output region is the // region of the self parameter. - let explicit_self = decl.inputs.get(0).and_then(hir::Arg::to_self); - let (self_ty, explicit_self_category) = match (opt_untransformed_self_ty, explicit_self) { + let (self_ty, explicit_self_category) = match (opt_untransformed_self_ty, decl.get_self()) { (Some(untransformed_self_ty), Some(explicit_self)) => { let self_type = self.determine_self_type(&rb, untransformed_self_ty, &explicit_self); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d9409d3bbd9..65bc486372b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1387,7 +1387,8 @@ pub struct MethodSig { pub abi: Abi, pub decl: P, pub generics: Generics, - pub explicit_self: ExplicitSelf, + /// A short form of self argument was used (`self`, `&self` etc, but not `self: TYPE`). + pub self_shortcut: bool, } /// Represents an item declaration within a trait declaration, @@ -1677,81 +1678,65 @@ pub struct Arg { pub id: NodeId, } -/// Represents the kind of 'self' associated with a method. -/// String representation of `Ident` here is always "self", but hygiene contexts may differ. +/// Alternative representation for `Arg`s describing `self` parameter of methods. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum SelfKind { - /// No self - Static, /// `self`, `mut self` - Value(Ident), + Value(Mutability), /// `&'lt self`, `&'lt mut self` - Region(Option, Mutability, Ident), + Region(Option, Mutability), /// `self: TYPE`, `mut self: TYPE` - Explicit(P, Ident), + Explicit(P, Mutability), } pub type ExplicitSelf = Spanned; impl Arg { - #[unstable(feature = "rustc_private", issue = "27812")] - #[rustc_deprecated(since = "1.10.0", reason = "use `from_self` instead")] - pub fn new_self(span: Span, mutability: Mutability, self_ident: Ident) -> Arg { - let path = Spanned{span:span,node:self_ident}; - Arg { - // HACK(eddyb) fake type for the self argument. - ty: P(Ty { - id: DUMMY_NODE_ID, - node: TyKind::Infer, - span: DUMMY_SP, - }), - pat: P(Pat { - id: DUMMY_NODE_ID, - node: PatKind::Ident(BindingMode::ByValue(mutability), path, None), - span: span - }), - id: DUMMY_NODE_ID - } - } - pub fn to_self(&self) -> Option { - if let PatKind::Ident(_, ident, _) = self.pat.node { + if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.node { if ident.node.name == keywords::SelfValue.name() { return match self.ty.node { - TyKind::Infer => Some(respan(self.pat.span, SelfKind::Value(ident.node))), + TyKind::Infer => Some(respan(self.pat.span, SelfKind::Value(mutbl))), TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::Infer => { - Some(respan(self.pat.span, SelfKind::Region(lt, mutbl, ident.node))) + Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) } _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi), - SelfKind::Explicit(self.ty.clone(), ident.node))), + SelfKind::Explicit(self.ty.clone(), mutbl))), } } } None } - pub fn from_self(eself: ExplicitSelf, ident_sp: Span, mutbl: Mutability) -> Arg { - let pat = |ident, span| P(Pat { - id: DUMMY_NODE_ID, - node: PatKind::Ident(BindingMode::ByValue(mutbl), respan(ident_sp, ident), None), - span: span, - }); + pub fn is_self(&self) -> bool { + if let PatKind::Ident(_, ident, _) = self.pat.node { + ident.node.name == keywords::SelfValue.name() + } else { + false + } + } + + pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg { let infer_ty = P(Ty { id: DUMMY_NODE_ID, node: TyKind::Infer, span: DUMMY_SP, }); - let arg = |ident, ty, span| Arg { - pat: pat(ident, span), + let arg = |mutbl, ty, span| Arg { + pat: P(Pat { + id: DUMMY_NODE_ID, + node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), + span: span, + }), ty: ty, id: DUMMY_NODE_ID, }; match eself.node { - SelfKind::Static => panic!("bug: `Arg::from_self` is called \ - with `SelfKind::Static` argument"), - SelfKind::Explicit(ty, ident) => arg(ident, ty, mk_sp(eself.span.lo, ident_sp.hi)), - SelfKind::Value(ident) => arg(ident, infer_ty, eself.span), - SelfKind::Region(lt, mutbl, ident) => arg(ident, P(Ty { + SelfKind::Explicit(ty, mutbl) => { + arg(mutbl, ty, mk_sp(eself.span.lo, eself_ident.span.hi)) + } + SelfKind::Value(mutbl) => arg(mutbl, infer_ty, eself.span), + SelfKind::Region(lt, mutbl) => arg(Mutability::Immutable, P(Ty { id: DUMMY_NODE_ID, node: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl: mutbl }), span: DUMMY_SP, @@ -1768,6 +1753,15 @@ pub struct FnDecl { pub variadic: bool } +impl FnDecl { + pub fn get_self(&self) -> Option { + self.inputs.get(0).and_then(Arg::to_self) + } + pub fn has_self(&self) -> bool { + self.inputs.get(0).map(Arg::is_self).unwrap_or(false) + } +} + #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Unsafety { Unsafe, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f243706eecb..d90389bef7f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1128,7 +1128,7 @@ fn expand_and_rename_method(sig: ast::MethodSig, body: P, (ast::MethodSig { generics: fld.fold_generics(sig.generics), abi: sig.abi, - explicit_self: fld.fold_explicit_self(sig.explicit_self), + self_shortcut: sig.self_shortcut, unsafety: sig.unsafety, constness: sig.constness, decl: rewritten_fn_decl diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2c325080c0c..a8f048c6c4e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -179,14 +179,6 @@ pub trait Folder : Sized { // fold::noop_fold_mac(_mac, self) } - fn fold_explicit_self(&mut self, es: ExplicitSelf) -> ExplicitSelf { - noop_fold_explicit_self(es, self) - } - - fn fold_explicit_self_kind(&mut self, es: SelfKind) -> SelfKind { - noop_fold_explicit_self_kind(es, self) - } - fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime { noop_fold_lifetime(l, self) } @@ -523,28 +515,6 @@ pub fn noop_fold_attribute(at: Attribute, fld: &mut T) -> Option(es: SelfKind, fld: &mut T) - -> SelfKind { - match es { - SelfKind::Static | SelfKind::Value(_) => es, - SelfKind::Region(lifetime, m, ident) => { - SelfKind::Region(fld.fold_opt_lifetime(lifetime), m, ident) - } - SelfKind::Explicit(typ, ident) => { - SelfKind::Explicit(fld.fold_ty(typ), ident) - } - } -} - -pub fn noop_fold_explicit_self(Spanned {span, node}: ExplicitSelf, fld: &mut T) - -> ExplicitSelf { - Spanned { - node: fld.fold_explicit_self_kind(node), - span: fld.new_span(span) - } -} - - pub fn noop_fold_mac(Spanned {node, span}: Mac, fld: &mut T) -> Mac { Spanned { node: Mac_ { @@ -1096,7 +1066,7 @@ pub fn noop_fold_method_sig(sig: MethodSig, folder: &mut T) -> Method MethodSig { generics: folder.fold_generics(sig.generics), abi: sig.abi, - explicit_self: folder.fold_explicit_self(sig.explicit_self), + self_shortcut: sig.self_shortcut, unsafety: sig.unsafety, constness: sig.constness, decl: folder.fold_fn_decl(sig.decl) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fc62cee92fd..75f6762af18 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -17,7 +17,7 @@ use ast::Block; use ast::{BlockCheckMode, CaptureBy}; use ast::{Constness, Crate, CrateConfig}; use ast::{Decl, DeclKind, Defaultness}; -use ast::{EMPTY_CTXT, EnumDef, ExplicitSelf}; +use ast::{EMPTY_CTXT, EnumDef}; use ast::{Expr, ExprKind, RangeLimits}; use ast::{Field, FnDecl}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; @@ -1310,7 +1310,7 @@ impl<'a> Parser<'a> { let ident = p.parse_ident()?; let mut generics = p.parse_generics()?; - let (explicit_self, d) = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ + let (d, self_shortcut) = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... @@ -1324,7 +1324,7 @@ impl<'a> Parser<'a> { decl: d, generics: generics, abi: abi, - explicit_self: explicit_self, + self_shortcut: self_shortcut, }; let body = match p.token { @@ -4616,25 +4616,19 @@ impl<'a> Parser<'a> { })) } - /// Parse the parameter list and result type of a function that may have a `self` parameter. - fn parse_fn_decl_with_self(&mut self, - parse_arg_fn: F) - -> PResult<'a, (ExplicitSelf, P)> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, - { + /// Returns the parsed optional self argument and whether a self shortcut was used. + fn parse_self_arg(&mut self) -> PResult<'a, (Option, bool)> { let expect_ident = |this: &mut Self| match this.token { - token::Ident(ident) => { this.bump(); ident } // Preserve hygienic context. + // Preserve hygienic context. + token::Ident(ident) => { this.bump(); codemap::respan(this.last_span, ident) } _ => unreachable!() }; - self.expect(&token::OpenDelim(token::Paren))?; - // Parse optional self parameter of a method. // Only a limited set of initial token sequences is considered self parameters, anything // else is parsed as a normal function parameter list, so some lookahead is required. let eself_lo = self.span.lo; - let mut eself_mutbl = Mutability::Immutable; - let (eself, eself_ident_sp) = match self.token { + let (eself, eself_ident) = match self.token { token::BinOp(token::And) => { // &self // &mut self @@ -4643,30 +4637,26 @@ impl<'a> Parser<'a> { // ¬_self if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); - (SelfKind::Region(None, Mutability::Immutable, expect_ident(self)), - self.last_span) + (SelfKind::Region(None, Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) && self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); self.bump(); - (SelfKind::Region(None, Mutability::Mutable, expect_ident(self)), - self.last_span) + (SelfKind::Region(None, Mutability::Mutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); let lt = self.parse_lifetime()?; - (SelfKind::Region(Some(lt), Mutability::Immutable, expect_ident(self)), - self.last_span) + (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && self.look_ahead(3, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); let lt = self.parse_lifetime()?; self.bump(); - (SelfKind::Region(Some(lt), Mutability::Mutable, expect_ident(self)), - self.last_span) + (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { - (SelfKind::Static, codemap::DUMMY_SP) + return Ok((None, false)); } } token::BinOp(token::Star) => { @@ -4678,15 +4668,15 @@ impl<'a> Parser<'a> { if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); self.span_err(self.span, "cannot pass `self` by raw pointer"); - (SelfKind::Value(expect_ident(self)), self.last_span) + (SelfKind::Value(Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_mutability()) && self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { self.bump(); self.bump(); self.span_err(self.span, "cannot pass `self` by raw pointer"); - (SelfKind::Value(expect_ident(self)), self.last_span) + (SelfKind::Value(Mutability::Immutable), expect_ident(self)) } else { - (SelfKind::Static, codemap::DUMMY_SP) + return Ok((None, false)); } } token::Ident(..) => { @@ -4694,64 +4684,72 @@ impl<'a> Parser<'a> { // self // self: TYPE let eself_ident = expect_ident(self); - let eself_ident_sp = self.last_span; if self.eat(&token::Colon) { - (SelfKind::Explicit(self.parse_ty_sum()?, eself_ident), eself_ident_sp) + let ty = self.parse_ty_sum()?; + (SelfKind::Explicit(ty, Mutability::Immutable), eself_ident) } else { - (SelfKind::Value(eself_ident), eself_ident_sp) + (SelfKind::Value(Mutability::Immutable), eself_ident) } } else if self.token.is_keyword(keywords::Mut) && self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { // mut self // mut self: TYPE - eself_mutbl = Mutability::Mutable; self.bump(); let eself_ident = expect_ident(self); - let eself_ident_sp = self.last_span; if self.eat(&token::Colon) { - (SelfKind::Explicit(self.parse_ty_sum()?, eself_ident), eself_ident_sp) + let ty = self.parse_ty_sum()?; + (SelfKind::Explicit(ty, Mutability::Mutable), eself_ident) } else { - (SelfKind::Value(eself_ident), eself_ident_sp) + (SelfKind::Value(Mutability::Mutable), eself_ident) } } else { - (SelfKind::Static, codemap::DUMMY_SP) + return Ok((None, false)); } } - _ => (SelfKind::Static, codemap::DUMMY_SP) + _ => return Ok((None, false)), }; - let mut eself = codemap::respan(mk_sp(eself_lo, self.last_span.hi), eself); + + let self_shortcut = if let SelfKind::Explicit(..) = eself { false } else { true }; + let eself = codemap::respan(mk_sp(eself_lo, self.last_span.hi), eself); + Ok((Some(Arg::from_self(eself, eself_ident)), self_shortcut)) + } + + /// Parse the parameter list and result type of a function that may have a `self` parameter. + fn parse_fn_decl_with_self(&mut self, + parse_arg_fn: F) + -> PResult<'a, (P, bool)> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, + { + self.expect(&token::OpenDelim(token::Paren))?; + + // Parse optional self argument + let (self_arg, self_shortcut) = self.parse_self_arg()?; // Parse the rest of the function parameter list. let sep = SeqSep::trailing_allowed(token::Comma); - let fn_inputs = match eself.node { - SelfKind::Static => { - eself.span = codemap::DUMMY_SP; - self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn) - } - SelfKind::Value(..) | SelfKind::Region(..) | SelfKind::Explicit(..) => { - if self.check(&token::CloseDelim(token::Paren)) { - vec![Arg::from_self(eself.clone(), eself_ident_sp, eself_mutbl)] - } else if self.check(&token::Comma) { - self.bump(); - let mut fn_inputs = vec![Arg::from_self(eself.clone(), eself_ident_sp, - eself_mutbl)]; - fn_inputs.append(&mut self.parse_seq_to_before_end( - &token::CloseDelim(token::Paren), sep, parse_arg_fn) - ); - fn_inputs - } else { - return self.unexpected(); - } + let fn_inputs = if let Some(self_arg) = self_arg { + if self.check(&token::CloseDelim(token::Paren)) { + vec![self_arg] + } else if self.eat(&token::Comma) { + let mut fn_inputs = vec![self_arg]; + fn_inputs.append(&mut self.parse_seq_to_before_end( + &token::CloseDelim(token::Paren), sep, parse_arg_fn) + ); + fn_inputs + } else { + return self.unexpected(); } + } else { + self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn) }; // Parse closing paren and return type. self.expect(&token::CloseDelim(token::Paren))?; - Ok((eself, P(FnDecl { + Ok((P(FnDecl { inputs: fn_inputs, output: self.parse_ret_ty()?, variadic: false - }))) + }), self_shortcut)) } // parse the |arg, arg| header on a lambda @@ -4944,15 +4942,13 @@ impl<'a> Parser<'a> { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| { - p.parse_arg() - })?; + let (decl, self_shortcut) = self.parse_fn_decl_with_self(|p| p.parse_arg())?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig { generics: generics, abi: abi, - explicit_self: explicit_self, + self_shortcut: self_shortcut, unsafety: unsafety, constness: constness, decl: decl diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ebb4927d69c..cf0c0f584a6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -12,7 +12,7 @@ pub use self::AnnNode::*; use abi::{self, Abi}; use ast::{self, TokenTree, BlockCheckMode, PatKind}; -use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; +use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; use attr::ThinAttributesExt; use util::parser::AssocOp; @@ -382,13 +382,12 @@ pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, constness: ast::Constness, name: ast::Ident, - opt_explicit_self: Option<&ast::SelfKind>, generics: &ast::Generics) -> String { to_string(|s| { s.head("")?; s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name), - generics, opt_explicit_self, &ast::Visibility::Inherited)?; + generics, &ast::Visibility::Inherited)?; s.end()?; // Close the head box s.end() // Close the outer box }) @@ -416,10 +415,6 @@ pub fn lit_to_string(l: &ast::Lit) -> String { to_string(|s| s.print_literal(l)) } -pub fn explicit_self_to_string(explicit_self: &ast::SelfKind) -> String { - to_string(|s| s.print_explicit_self(explicit_self, ast::Mutability::Immutable).map(|_| {})) -} - pub fn variant_to_string(var: &ast::Variant) -> String { to_string(|s| s.print_variant(var)) } @@ -1005,8 +1000,7 @@ impl<'a> State<'a> { f.unsafety, &f.decl, None, - &generics, - None)?; + &generics)?; } ast::TyKind::Path(None, ref path) => { self.print_path(path, false, 0)?; @@ -1054,7 +1048,7 @@ impl<'a> State<'a> { self.print_fn(decl, ast::Unsafety::Normal, ast::Constness::NotConst, Abi::Rust, Some(item.ident), - generics, None, &item.vis)?; + generics, &item.vis)?; self.end()?; // end head-ibox word(&mut self.s, ";")?; self.end() // end the outer fn box @@ -1182,7 +1176,6 @@ impl<'a> State<'a> { abi, Some(item.ident), typarams, - None, &item.vis )?; word(&mut self.s, " ")?; @@ -1522,7 +1515,6 @@ impl<'a> State<'a> { m.abi, Some(ident), &m.generics, - None, vis) } @@ -2610,29 +2602,25 @@ impl<'a> State<'a> { self.end() // close enclosing cbox } - // Returns whether it printed anything - fn print_explicit_self(&mut self, - explicit_self: &ast::SelfKind, - mutbl: ast::Mutability) -> io::Result { - self.print_mutability(mutbl)?; - match *explicit_self { - ast::SelfKind::Static => { return Ok(false); } - ast::SelfKind::Value(_) => { - word(&mut self.s, "self")?; + fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) -> io::Result<()> { + match explicit_self.node { + SelfKind::Value(m) => { + self.print_mutability(m)?; + word(&mut self.s, "self") } - ast::SelfKind::Region(ref lt, m, _) => { + SelfKind::Region(ref lt, m) => { word(&mut self.s, "&")?; self.print_opt_lifetime(lt)?; self.print_mutability(m)?; - word(&mut self.s, "self")?; + word(&mut self.s, "self") } - ast::SelfKind::Explicit(ref typ, _) => { + SelfKind::Explicit(ref typ, m) => { + self.print_mutability(m)?; word(&mut self.s, "self")?; self.word_space(":")?; - self.print_type(&typ)?; + self.print_type(&typ) } } - return Ok(true); } pub fn print_fn(&mut self, @@ -2642,7 +2630,6 @@ impl<'a> State<'a> { abi: abi::Abi, name: Option, generics: &ast::Generics, - opt_explicit_self: Option<&ast::SelfKind>, vis: &ast::Visibility) -> io::Result<()> { self.print_fn_header_info(unsafety, constness, abi, vis)?; @@ -2651,21 +2638,14 @@ impl<'a> State<'a> { self.print_ident(name)?; } self.print_generics(generics)?; - self.print_fn_args_and_ret(decl, opt_explicit_self)?; + self.print_fn_args_and_ret(decl)?; self.print_where_clause(&generics.where_clause) } - pub fn print_fn_args(&mut self, decl: &ast::FnDecl, - _: Option<&ast::SelfKind>, - is_closure: bool) -> io::Result<()> { - self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, is_closure)) - } - - pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl, - opt_explicit_self: Option<&ast::SelfKind>) + pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl) -> io::Result<()> { self.popen()?; - self.print_fn_args(decl, opt_explicit_self, false)?; + self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?; if decl.variadic { word(&mut self.s, ", ...")?; } @@ -2679,7 +2659,7 @@ impl<'a> State<'a> { decl: &ast::FnDecl) -> io::Result<()> { word(&mut self.s, "|")?; - self.print_fn_args(decl, None, true)?; + self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?; word(&mut self.s, "|")?; if let ast::FunctionRetTy::Default(..) = decl.output { @@ -2929,17 +2909,14 @@ impl<'a> State<'a> { match input.ty.node { ast::TyKind::Infer if is_closure => self.print_pat(&input.pat)?, _ => { - let (mutbl, invalid) = match input.pat.node { - PatKind::Ident(ast::BindingMode::ByValue(mutbl), ident, _) | - PatKind::Ident(ast::BindingMode::ByRef(mutbl), ident, _) => { - (mutbl, ident.node.name == keywords::Invalid.name()) - } - _ => (ast::Mutability::Immutable, false) - }; - if let Some(eself) = input.to_self() { - self.print_explicit_self(&eself.node, mutbl)?; + self.print_explicit_self(&eself)?; } else { + let invalid = if let PatKind::Ident(_, ident, _) = input.pat.node { + ident.node.name == keywords::Invalid.name() + } else { + false + }; if !invalid { self.print_pat(&input.pat)?; word(&mut self.s, ":")?; @@ -2980,8 +2957,7 @@ impl<'a> State<'a> { unsafety: ast::Unsafety, decl: &ast::FnDecl, name: Option, - generics: &ast::Generics, - opt_explicit_self: Option<&ast::SelfKind>) + generics: &ast::Generics) -> io::Result<()> { self.ibox(INDENT_UNIT)?; if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { @@ -3002,7 +2978,6 @@ impl<'a> State<'a> { abi, name, &generics, - opt_explicit_self, &ast::Visibility::Inherited)?; self.end() } @@ -3126,8 +3101,7 @@ mod tests { let generics = ast::Generics::default(); assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal, ast::Constness::NotConst, - abba_ident, - None, &generics), + abba_ident, &generics), "fn abba()"); } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index e692ec4452c..919dd84b117 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -129,10 +129,6 @@ impl<'v> Visitor<'v> for NodeCounter { self.count += 1; walk_lifetime_def(self, lifetime) } - fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { - self.count += 1; - walk_explicit_self(self, es) - } fn visit_mac(&mut self, _mac: &'v Mac) { self.count += 1; walk_mac(self, _mac) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f50a480e5e5..c5069210037 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -99,9 +99,6 @@ pub trait Visitor<'v> : Sized { fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { walk_lifetime_def(self, lifetime) } - fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { - walk_explicit_self(self, es) - } fn visit_mac(&mut self, _mac: &'v Mac) { panic!("visit_mac disabled by default"); // NB: see note about macros above. @@ -196,24 +193,6 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); } -pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, - explicit_self: &'v ExplicitSelf) { - match explicit_self.node { - SelfKind::Static => {}, - SelfKind::Value(ident) => { - visitor.visit_ident(explicit_self.span, ident) - } - SelfKind::Region(ref opt_lifetime, _, ident) => { - visitor.visit_ident(explicit_self.span, ident); - walk_list!(visitor, visit_lifetime, opt_lifetime); - } - SelfKind::Explicit(ref typ, ident) => { - visitor.visit_ident(explicit_self.span, ident); - visitor.visit_ty(typ) - } - } -} - pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v PolyTraitRef, _modifier: &'v TraitBoundModifier) @@ -553,7 +532,6 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, } FnKind::Method(_, ref sig, _) => { visitor.visit_generics(&sig.generics); - visitor.visit_explicit_self(&sig.explicit_self); } FnKind::Closure => {} } @@ -578,7 +556,6 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai walk_list!(visitor, visit_expr, default); } TraitItemKind::Method(ref sig, None) => { - visitor.visit_explicit_self(&sig.explicit_self); visitor.visit_generics(&sig.generics); walk_fn_decl(visitor, &sig.decl); } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 20fb4bf32cc..6ecbdb765fa 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -197,7 +197,7 @@ use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::ext::base::{ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; -use syntax::codemap::{self, DUMMY_SP}; +use syntax::codemap::{self, respan, DUMMY_SP}; use syntax::codemap::Span; use syntax::errors::Handler; use syntax::util::move_map::MoveMap; @@ -806,25 +806,21 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef, type_ident: Ident, generics: &Generics) - -> (ast::ExplicitSelf, Vec>, Vec>, Vec<(Ident, P)>) { + -> (Option, Vec>, Vec>, Vec<(Ident, P)>) { let mut self_args = Vec::new(); let mut nonself_args = Vec::new(); let mut arg_tys = Vec::new(); let mut nonstatic = false; - let ast_explicit_self = match self.explicit_self { - Some(ref self_ptr) => { - let (self_expr, explicit_self) = - ty::get_explicit_self(cx, trait_.span, self_ptr); + let ast_explicit_self = self.explicit_self.as_ref().map(|self_ptr| { + let (self_expr, explicit_self) = ty::get_explicit_self(cx, trait_.span, self_ptr); - self_args.push(self_expr); - nonstatic = true; + self_args.push(self_expr); + nonstatic = true; - explicit_self - } - None => codemap::respan(trait_.span, ast::SelfKind::Static), - }; + explicit_self + }); for (i, ty) in self.args.iter().enumerate() { let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); @@ -857,24 +853,22 @@ impl<'a> MethodDef<'a> { type_ident: Ident, generics: &Generics, abi: Abi, - explicit_self: ast::ExplicitSelf, + explicit_self: Option, arg_types: Vec<(Ident, P)> , body: P) -> ast::ImplItem { // create the generics that aren't for Self let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); - let self_arg = match explicit_self.node { - ast::SelfKind::Static => None, - // creating fresh self id - _ => Some(ast::Arg::from_self(explicit_self.clone(), trait_.span, - ast::Mutability::Immutable)), - }; + // derive doesn't generate `self: TYPE` forms + let self_shortcut = explicit_self.is_some(); let args = { - let args = arg_types.into_iter().map(|(name, ty)| { - cx.arg(trait_.span, name, ty) - }); - self_arg.into_iter().chain(args).collect() + let self_args = explicit_self.map(|explicit_self| { + ast::Arg::from_self(explicit_self, respan(trait_.span, keywords::SelfValue.ident())) + }); + let nonself_args = arg_types.into_iter() + .map(|(name, ty)| cx.arg(trait_.span, name, ty)); + self_args.into_iter().chain(nonself_args).collect() }; let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); @@ -900,7 +894,7 @@ impl<'a> MethodDef<'a> { node: ast::ImplItemKind::Method(ast::MethodSig { generics: fn_generics, abi: abi, - explicit_self: explicit_self, + self_shortcut: self_shortcut, unsafety: unsafety, constness: ast::Constness::NotConst, decl: fn_decl diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index e31d45d91a5..b581f5267ea 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -15,11 +15,10 @@ pub use self::PtrTy::*; pub use self::Ty::*; use syntax::ast; -use syntax::ast::{Expr,Generics,Ident}; +use syntax::ast::{Expr, Generics, Ident, SelfKind}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::codemap::{Span,respan}; -use syntax::parse::token::keywords; use syntax::ptr::P; /// The types of pointers @@ -258,12 +257,11 @@ impl<'a> LifetimeBounds<'a> { pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) -> (P, ast::ExplicitSelf) { - // this constructs a fresh `self` path, which will match the fresh `self` binding - // created below. + // this constructs a fresh `self` path let self_path = cx.expr_self(span); match *self_ptr { None => { - (self_path, respan(span, ast::SelfKind::Value(keywords::SelfValue.ident()))) + (self_path, respan(span, SelfKind::Value(ast::Mutability::Immutable))) } Some(ref ptr) => { let self_ty = respan( @@ -271,7 +269,7 @@ pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) match *ptr { Borrowed(ref lt, mutbl) => { let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); - ast::SelfKind::Region(lt, mutbl, keywords::SelfValue.ident()) + SelfKind::Region(lt, mutbl) } Raw(_) => cx.span_bug(span, "attempted to use *self in deriving definition") }); From 1a1de5bf899a15cd97f2a113add070bec46cf209 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 4/9] Add a new AST-only type variant `ImplicitSelf` --- src/librustc/hir/lowering.rs | 23 +++++++++--------- src/libsyntax/ast.rs | 10 ++++---- src/libsyntax/ext/expand.rs | 1 - src/libsyntax/fold.rs | 3 +-- src/libsyntax/parse/parser.rs | 29 ++++++++++------------- src/libsyntax/print/pprust.rs | 3 +++ src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 3 --- 8 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 48b4b867ee2..f8cd3053f54 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -269,7 +269,7 @@ impl<'a> LoweringContext<'a> { P(hir::Ty { id: t.id, node: match t.node { - Infer => hir::TyInfer, + Infer | ImplicitSelf => hir::TyInfer, Vec(ref ty) => hir::TyVec(self.lower_ty(ty)), Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), Rptr(ref region, ref mt) => { @@ -787,23 +787,24 @@ impl<'a> LoweringContext<'a> { } fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig { + let hir_sig = hir::MethodSig { + generics: self.lower_generics(&sig.generics), + abi: sig.abi, + unsafety: self.lower_unsafety(sig.unsafety), + constness: self.lower_constness(sig.constness), + decl: self.lower_fn_decl(&sig.decl), + }; // Check for `self: _` and `self: &_` - if !sig.self_shortcut { - match sig.decl.get_self().map(|eself| eself.node) { - Some(SelfKind::Value(..)) | Some(SelfKind::Region(..)) => { + if let Some(SelfKind::Explicit(..)) = sig.decl.get_self().map(|eself| eself.node) { + match hir_sig.decl.get_self().map(|eself| eself.node) { + Some(hir::SelfKind::Value(..)) | Some(hir::SelfKind::Region(..)) => { self.id_assigner.diagnostic().span_err(sig.decl.inputs[0].ty.span, "the type placeholder `_` is not allowed within types on item signatures"); } _ => {} } } - hir::MethodSig { - generics: self.lower_generics(&sig.generics), - abi: sig.abi, - unsafety: self.lower_unsafety(sig.unsafety), - constness: self.lower_constness(sig.constness), - decl: self.lower_fn_decl(&sig.decl), - } + hir_sig } fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 65bc486372b..9f21b47c34a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1387,8 +1387,6 @@ pub struct MethodSig { pub abi: Abi, pub decl: P, pub generics: Generics, - /// A short form of self argument was used (`self`, `&self` etc, but not `self: TYPE`). - pub self_shortcut: bool, } /// Represents an item declaration within a trait declaration, @@ -1639,6 +1637,8 @@ pub enum TyKind { /// TyKind::Infer means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. Infer, + /// Inferred type of a `self` or `&self` argument in a method. + ImplicitSelf, // A macro in the type position. Mac(Mac), } @@ -1696,8 +1696,8 @@ impl Arg { if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.node { if ident.node.name == keywords::SelfValue.name() { return match self.ty.node { - TyKind::Infer => Some(respan(self.pat.span, SelfKind::Value(mutbl))), - TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::Infer => { + TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), + TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::ImplicitSelf => { Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) } _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi), @@ -1719,7 +1719,7 @@ impl Arg { pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg { let infer_ty = P(Ty { id: DUMMY_NODE_ID, - node: TyKind::Infer, + node: TyKind::ImplicitSelf, span: DUMMY_SP, }); let arg = |mutbl, ty, span| Arg { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index d90389bef7f..8a53342d05a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1128,7 +1128,6 @@ fn expand_and_rename_method(sig: ast::MethodSig, body: P, (ast::MethodSig { generics: fld.fold_generics(sig.generics), abi: sig.abi, - self_shortcut: sig.self_shortcut, unsafety: sig.unsafety, constness: sig.constness, decl: rewritten_fn_decl diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index a8f048c6c4e..aeedafc9f2e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -375,7 +375,7 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { t.map(|Ty {id, node, span}| Ty { id: fld.new_id(id), node: match node { - TyKind::Infer => node, + TyKind::Infer | TyKind::ImplicitSelf => node, TyKind::Vec(ty) => TyKind::Vec(fld.fold_ty(ty)), TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)), TyKind::Rptr(region, mt) => { @@ -1066,7 +1066,6 @@ pub fn noop_fold_method_sig(sig: MethodSig, folder: &mut T) -> Method MethodSig { generics: folder.fold_generics(sig.generics), abi: sig.abi, - self_shortcut: sig.self_shortcut, unsafety: sig.unsafety, constness: sig.constness, decl: folder.fold_fn_decl(sig.decl) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 75f6762af18..da3312ae0fc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1310,7 +1310,7 @@ impl<'a> Parser<'a> { let ident = p.parse_ident()?; let mut generics = p.parse_generics()?; - let (d, self_shortcut) = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ + let d = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{ // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... @@ -1324,7 +1324,6 @@ impl<'a> Parser<'a> { decl: d, generics: generics, abi: abi, - self_shortcut: self_shortcut, }; let body = match p.token { @@ -4617,7 +4616,7 @@ impl<'a> Parser<'a> { } /// Returns the parsed optional self argument and whether a self shortcut was used. - fn parse_self_arg(&mut self) -> PResult<'a, (Option, bool)> { + fn parse_self_arg(&mut self) -> PResult<'a, Option> { let expect_ident = |this: &mut Self| match this.token { // Preserve hygienic context. token::Ident(ident) => { this.bump(); codemap::respan(this.last_span, ident) } @@ -4656,7 +4655,7 @@ impl<'a> Parser<'a> { self.bump(); (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { - return Ok((None, false)); + return Ok(None); } } token::BinOp(token::Star) => { @@ -4676,7 +4675,7 @@ impl<'a> Parser<'a> { self.span_err(self.span, "cannot pass `self` by raw pointer"); (SelfKind::Value(Mutability::Immutable), expect_ident(self)) } else { - return Ok((None, false)); + return Ok(None); } } token::Ident(..) => { @@ -4703,27 +4702,24 @@ impl<'a> Parser<'a> { (SelfKind::Value(Mutability::Mutable), eself_ident) } } else { - return Ok((None, false)); + return Ok(None); } } - _ => return Ok((None, false)), + _ => return Ok(None), }; - let self_shortcut = if let SelfKind::Explicit(..) = eself { false } else { true }; let eself = codemap::respan(mk_sp(eself_lo, self.last_span.hi), eself); - Ok((Some(Arg::from_self(eself, eself_ident)), self_shortcut)) + Ok(Some(Arg::from_self(eself, eself_ident))) } /// Parse the parameter list and result type of a function that may have a `self` parameter. - fn parse_fn_decl_with_self(&mut self, - parse_arg_fn: F) - -> PResult<'a, (P, bool)> + fn parse_fn_decl_with_self(&mut self, parse_arg_fn: F) -> PResult<'a, P> where F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, { self.expect(&token::OpenDelim(token::Paren))?; // Parse optional self argument - let (self_arg, self_shortcut) = self.parse_self_arg()?; + let self_arg = self.parse_self_arg()?; // Parse the rest of the function parameter list. let sep = SeqSep::trailing_allowed(token::Comma); @@ -4745,11 +4741,11 @@ impl<'a> Parser<'a> { // Parse closing paren and return type. self.expect(&token::CloseDelim(token::Paren))?; - Ok((P(FnDecl { + Ok(P(FnDecl { inputs: fn_inputs, output: self.parse_ret_ty()?, variadic: false - }), self_shortcut)) + })) } // parse the |arg, arg| header on a lambda @@ -4942,13 +4938,12 @@ impl<'a> Parser<'a> { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let (decl, self_shortcut) = self.parse_fn_decl_with_self(|p| p.parse_arg())?; + let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig { generics: generics, abi: abi, - self_shortcut: self_shortcut, unsafety: unsafety, constness: constness, decl: decl diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index cf0c0f584a6..416bfab8912 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1030,6 +1030,9 @@ impl<'a> State<'a> { ast::TyKind::Infer => { word(&mut self.s, "_")?; } + ast::TyKind::ImplicitSelf => { + unreachable!(); + } ast::TyKind::Mac(ref m) => { self.print_mac(m, token::Paren)?; } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index c5069210037..51613effea6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -348,7 +348,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyKind::Typeof(ref expression) => { visitor.visit_expr(expression) } - TyKind::Infer => {} + TyKind::Infer | TyKind::ImplicitSelf => {} TyKind::Mac(ref mac) => { visitor.visit_mac(mac) } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 6ecbdb765fa..9095230df63 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -860,8 +860,6 @@ impl<'a> MethodDef<'a> { // create the generics that aren't for Self let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); - // derive doesn't generate `self: TYPE` forms - let self_shortcut = explicit_self.is_some(); let args = { let self_args = explicit_self.map(|explicit_self| { ast::Arg::from_self(explicit_self, respan(trait_.span, keywords::SelfValue.ident())) @@ -894,7 +892,6 @@ impl<'a> MethodDef<'a> { node: ast::ImplItemKind::Method(ast::MethodSig { generics: fn_generics, abi: abi, - self_shortcut: self_shortcut, unsafety: unsafety, constness: ast::Constness::NotConst, decl: fn_decl From dcea4b26268d19b32c7e29bf063638fa5e3bbd91 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 5/9] Fix rebase --- src/librustc_resolve/lib.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 41cc5462816..215109f282d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -67,7 +67,7 @@ use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind}; use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics}; use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Local, Pat, PatKind, Path}; -use syntax::ast::{PathSegment, PathParameters, SelfKind, TraitItemKind, TraitRef, Ty, TyKind}; +use syntax::ast::{PathSegment, PathParameters, TraitItemKind, TraitRef, Ty, TyKind}; use std::collections::{HashMap, HashSet}; use std::cell::{Cell, RefCell}; @@ -607,7 +607,7 @@ impl<'a, 'v> Visitor<'v> for Resolver<'a> { } FnKind::Method(_, sig, _) => { self.visit_generics(&sig.generics); - MethodRibKind(sig.explicit_self.node == SelfKind::Static) + MethodRibKind(!sig.decl.has_self()) } FnKind::Closure => ClosureRibKind(node_id), }; @@ -1676,9 +1676,7 @@ impl<'a> Resolver<'a> { let type_parameters = HasTypeParameters(&sig.generics, FnSpace, - MethodRibKind( - sig.explicit_self.node == - SelfKind::Static)); + MethodRibKind(!sig.decl.has_self())); this.with_type_parameter_rib(type_parameters, |this| { visit::walk_trait_item(this, trait_item) }); @@ -2007,9 +2005,7 @@ impl<'a> Resolver<'a> { let type_parameters = HasTypeParameters(&sig.generics, FnSpace, - MethodRibKind( - sig.explicit_self.node == - SelfKind::Static)); + MethodRibKind(!sig.decl.has_self())); this.with_type_parameter_rib(type_parameters, |this| { visit::walk_impl_item(this, impl_item); }); From d69aeaf662c637b454e8c7a5ddbd69b4978ec211 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 6/9] Implement `..` in tuple (struct) patterns --- src/doc/reference.md | 2 + src/librustc/cfg/construct.rs | 5 +- src/librustc/hir/fold.rs | 8 +- src/librustc/hir/intravisit.rs | 8 +- src/librustc/hir/lowering.rs | 12 +- src/librustc/hir/mod.rs | 16 +- src/librustc/hir/pat_util.rs | 22 ++ src/librustc/hir/print.rs | 41 +++- src/librustc/lib.rs | 2 + src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/mem_categorization.rs | 33 ++- src/librustc/middle/region.rs | 4 +- src/librustc/middle/stability.rs | 9 +- src/librustc_const_eval/check_match.rs | 33 ++- src/librustc_const_eval/eval.rs | 9 +- src/librustc_const_eval/lib.rs | 1 + src/librustc_mir/hair/cx/pattern.rs | 45 ++-- src/librustc_privacy/lib.rs | 13 +- src/librustc_resolve/lib.rs | 2 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_trans/_match.rs | 79 +++---- .../debuginfo/create_scope_map.rs | 10 +- src/librustc_typeck/check/_match.rs | 90 ++++---- src/librustc_typeck/diagnostics.rs | 25 --- src/librustc_typeck/lib.rs | 3 +- src/librustdoc/clean/mod.rs | 4 +- src/libsyntax/ast.rs | 16 +- src/libsyntax/ext/build.rs | 4 +- src/libsyntax/feature_gate.rs | 24 ++- src/libsyntax/fold.rs | 8 +- src/libsyntax/parse/parser.rs | 65 ++---- src/libsyntax/print/pprust.rs | 44 ++-- src/libsyntax/visit.rs | 8 +- src/test/compile-fail/issue-32004.rs | 4 +- .../match-pattern-field-mismatch-2.rs | 2 +- src/test/compile-fail/pat-tuple-bad-type.rs | 27 +++ .../compile-fail/pat-tuple-feature-gate.rs | 17 ++ src/test/compile-fail/pat-tuple-overfield.rs | 28 +++ .../compile-fail/pattern-error-continue.rs | 2 +- src/test/parse-fail/pat-lt-bracket-6.rs | 3 +- src/test/parse-fail/pat-lt-bracket-7.rs | 3 +- .../E0024.rs => parse-fail/pat-tuple-1.rs} | 11 +- src/test/parse-fail/pat-tuple-2.rs | 17 ++ src/test/parse-fail/pat-tuple-3.rs | 17 ++ src/test/parse-fail/pat-tuple-4.rs | 17 ++ src/test/parse-fail/pat-tuple-5.rs | 17 ++ src/test/parse-fail/pat-tuple-6.rs | 17 ++ src/test/run-pass/pat-tuple.rs | 202 ++++++++++++++++++ 48 files changed, 735 insertions(+), 298 deletions(-) create mode 100644 src/test/compile-fail/pat-tuple-bad-type.rs create mode 100644 src/test/compile-fail/pat-tuple-feature-gate.rs create mode 100644 src/test/compile-fail/pat-tuple-overfield.rs rename src/test/{compile-fail/E0024.rs => parse-fail/pat-tuple-1.rs} (74%) create mode 100644 src/test/parse-fail/pat-tuple-2.rs create mode 100644 src/test/parse-fail/pat-tuple-3.rs create mode 100644 src/test/parse-fail/pat-tuple-4.rs create mode 100644 src/test/parse-fail/pat-tuple-5.rs create mode 100644 src/test/parse-fail/pat-tuple-6.rs create mode 100644 src/test/run-pass/pat-tuple.rs diff --git a/src/doc/reference.md b/src/doc/reference.md index ebb111a2e2e..810138e5a29 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2433,6 +2433,8 @@ The currently implemented features of the reference compiler are: * - `abi_vectorcall` - Allows the usage of the vectorcall calling convention (e.g. `extern "vectorcall" func fn_();`) +* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns. + If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled the new feature (because the directive is no longer necessary). However, if a diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 76699f13959..af47617ea92 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -100,7 +100,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex { match pat.node { PatKind::Ident(_, _, None) | - PatKind::TupleStruct(_, None) | PatKind::Path(..) | PatKind::QPath(..) | PatKind::Lit(..) | @@ -116,8 +115,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_ast_node(pat.id, &[subpat_exit]) } - PatKind::TupleStruct(_, Some(ref subpats)) | - PatKind::Tup(ref subpats) => { + PatKind::TupleStruct(_, ref subpats, _) | + PatKind::Tuple(ref subpats, _) => { let pats_exit = self.pats_all(subpats.iter(), pred); self.add_ast_node(pat.id, &[pats_exit]) } diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index a91d16f25a2..9cba790c54b 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -923,9 +923,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { sub.map(|x| folder.fold_pat(x))) } PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)), - PatKind::TupleStruct(pth, pats) => { + PatKind::TupleStruct(pth, pats, ddpos) => { PatKind::TupleStruct(folder.fold_path(pth), - pats.map(|pats| pats.move_map(|x| folder.fold_pat(x)))) + pats.move_map(|x| folder.fold_pat(x)), ddpos) } PatKind::Path(pth) => { PatKind::Path(folder.fold_path(pth)) @@ -948,7 +948,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { }); PatKind::Struct(pth, fs, etc) } - PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))), + PatKind::Tuple(elts, ddpos) => { + PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos) + } PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)), PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl), PatKind::Range(e1, e2) => { diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2e9e433b830..69e38c9646c 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -454,11 +454,9 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { match pattern.node { - PatKind::TupleStruct(ref path, ref opt_children) => { + PatKind::TupleStruct(ref path, ref children, _) => { visitor.visit_path(path, pattern.id); - if let Some(ref children) = *opt_children { - walk_list!(visitor, visit_pat, children); - } + walk_list!(visitor, visit_pat, children); } PatKind::Path(ref path) => { visitor.visit_path(path, pattern.id); @@ -474,7 +472,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_pat(&field.node.pat) } } - PatKind::Tup(ref tuple_elements) => { + PatKind::Tuple(ref tuple_elements, _) => { walk_list!(visitor, visit_pat, tuple_elements); } PatKind::Box(ref subpattern) | diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 28506fd20fe..71153a459bd 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -872,10 +872,10 @@ impl<'a> LoweringContext<'a> { }) } PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), - PatKind::TupleStruct(ref pth, ref pats) => { + PatKind::TupleStruct(ref pth, ref pats, ddpos) => { hir::PatKind::TupleStruct(self.lower_path(pth), - pats.as_ref() - .map(|pats| pats.iter().map(|x| self.lower_pat(x)).collect())) + pats.iter().map(|x| self.lower_pat(x)).collect(), + ddpos) } PatKind::Path(ref pth) => { hir::PatKind::Path(self.lower_path(pth)) @@ -903,8 +903,8 @@ impl<'a> LoweringContext<'a> { .collect(); hir::PatKind::Struct(pth, fs, etc) } - PatKind::Tup(ref elts) => { - hir::PatKind::Tup(elts.iter().map(|x| self.lower_pat(x)).collect()) + PatKind::Tuple(ref elts, ddpos) => { + hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos) } PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)), PatKind::Ref(ref inner, mutbl) => { @@ -1857,7 +1857,7 @@ impl<'a> LoweringContext<'a> { let pt = if subpats.is_empty() { hir::PatKind::Path(path) } else { - hir::PatKind::TupleStruct(path, Some(subpats)) + hir::PatKind::TupleStruct(path, subpats, None) }; let pat = self.pat(span, pt); self.resolver.record_resolution(pat.id, def); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 39a6ec9f3af..961885d1b86 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -470,7 +470,7 @@ impl Pat { PatKind::Struct(_, ref fields, _) => { fields.iter().all(|field| field.node.pat.walk_(it)) } - PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => { + PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => { s.iter().all(|p| p.walk_(it)) } PatKind::Box(ref s) | PatKind::Ref(ref s, _) => { @@ -485,7 +485,6 @@ impl Pat { PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Ident(_, _, _) | - PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::QPath(_, _) => { true @@ -539,9 +538,10 @@ pub enum PatKind { /// The `bool` is `true` in the presence of a `..`. Struct(Path, HirVec>, bool), - /// A tuple struct/variant pattern `Variant(x, y, z)`. - /// "None" means a `Variant(..)` pattern where we don't bind the fields to names. - TupleStruct(Path, Option>>), + /// A tuple struct/variant pattern `Variant(x, y, .., z)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + TupleStruct(Path, HirVec>, Option), /// A path pattern. /// Such pattern can be resolved to a unit struct/variant or a constant. @@ -553,8 +553,10 @@ pub enum PatKind { /// PatKind::Path, and the resolver will have to sort that out. QPath(QSelf, Path), - /// A tuple pattern `(a, b)` - Tup(HirVec>), + /// A tuple pattern `(a, b)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + Tuple(HirVec>, Option), /// A `box` pattern Box(P), /// A reference pattern, e.g. `&mut (a, b)` diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 15f2310607f..f41c4b0840d 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -21,6 +21,28 @@ use std::cell::RefCell; pub type PatIdMap = FnvHashMap; +#[derive(Clone, Copy)] +pub struct AjustPos { + gap_pos: usize, + gap_len: usize, +} + +impl FnOnce<(usize,)> for AjustPos { + type Output = usize; + extern "rust-call" fn call_once(self, (i,): (usize,)) -> usize { + if i < self.gap_pos { i } else { i + self.gap_len } + } +} + +// Returns a functional object used to adjust tuple pattern indexes. Example: for 5-tuple and +// pattern (a, b, .., c) expected_len is 5, actual_len is 3 and gap_pos is Some(2). +pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option) -> AjustPos { + AjustPos { + gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len }, + gap_len: expected_len - actual_len, + } +} + // This is used because same-named variables in alternative patterns need to // use the NodeId of their namesake in the first pattern. pub fn pat_id_map(dm: &RefCell, pat: &hir::Pat) -> PatIdMap { diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 4455c7da3ba..d105a72b986 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1736,16 +1736,23 @@ impl<'a> State<'a> { None => (), } } - PatKind::TupleStruct(ref path, ref args_) => { + PatKind::TupleStruct(ref path, ref elts, ddpos) => { self.print_path(path, true, 0)?; - match *args_ { - None => word(&mut self.s, "(..)")?, - Some(ref args) => { - self.popen()?; - self.commasep(Inconsistent, &args[..], |s, p| s.print_pat(&p))?; - self.pclose()?; + self.popen()?; + if let Some(ddpos) = ddpos { + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?; + if ddpos != 0 { + self.word_space(",")?; } + word(&mut self.s, "..")?; + if ddpos != elts.len() { + word(&mut self.s, ",")?; + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; + } + } else { + try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))); } + try!(self.pclose()); } PatKind::Path(ref path) => { self.print_path(path, true, 0)?; @@ -1778,11 +1785,23 @@ impl<'a> State<'a> { space(&mut self.s)?; word(&mut self.s, "}")?; } - PatKind::Tup(ref elts) => { + PatKind::Tuple(ref elts, ddpos) => { self.popen()?; - self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; - if elts.len() == 1 { - word(&mut self.s, ",")?; + if let Some(ddpos) = ddpos { + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?; + if ddpos != 0 { + self.word_space(",")?; + } + word(&mut self.s, "..")?; + if ddpos != elts.len() { + word(&mut self.s, ",")?; + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; + } + } else { + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; + if elts.len() == 1 { + word(&mut self.s, ",")?; + } } self.pclose()?; } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index e1fb701e641..4ecad7f93a5 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,6 +29,7 @@ #![feature(collections)] #![feature(const_fn)] #![feature(enumset)] +#![feature(fn_traits)] #![feature(iter_arith)] #![feature(libc)] #![feature(nonzero)] @@ -38,6 +39,7 @@ #![feature(slice_patterns)] #![feature(staged_api)] #![feature(question_mark)] +#![feature(unboxed_closures)] #![cfg_attr(test, feature(test))] extern crate arena; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 4cee8c5d89a..b0add5a23dc 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -1127,7 +1127,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // will visit the substructure recursively. } - PatKind::Wild | PatKind::Tup(..) | PatKind::Box(..) | + PatKind::Wild | PatKind::Tuple(..) | PatKind::Box(..) | PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) | PatKind::Vec(..) => { // Similarly, each of these cases does not diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3999b02425d..da3df7ad3e9 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -80,6 +80,7 @@ use ty::adjustment; use ty::{self, Ty, TyCtxt}; use hir::{MutImmutable, MutMutable, PatKind}; +use hir::pat_util::pat_adjust_pos; use hir; use syntax::ast; use syntax::codemap::Span; @@ -1225,31 +1226,40 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // _ } - PatKind::TupleStruct(_, None) => { - // variant(..) - } - PatKind::TupleStruct(_, Some(ref subpats)) => { + PatKind::TupleStruct(_, ref subpats, ddpos) => { match opt_def { - Some(Def::Variant(..)) => { + Some(Def::Variant(enum_def, def_id)) => { // variant(x, y, z) + let variant = self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id); + let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos); for (i, subpat) in subpats.iter().enumerate() { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let subcmt = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + InteriorField(PositionalField(adjust(i)))); self.cat_pattern_(subcmt, &subpat, op)?; } } Some(Def::Struct(..)) => { + let expected_len = match self.pat_ty(&pat) { + Ok(&ty::TyS{sty: ty::TyStruct(adt_def, _), ..}) => { + adt_def.struct_variant().fields.len() + } + ref ty => { + span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty); + } + }; + + let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos); for (i, subpat) in subpats.iter().enumerate() { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let cmt_field = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + InteriorField(PositionalField(adjust(i)))); self.cat_pattern_(cmt_field, &subpat, op)?; } } @@ -1284,14 +1294,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - PatKind::Tup(ref subpats) => { + PatKind::Tuple(ref subpats, ddpos) => { // (p1, ..., pN) + let expected_len = match self.pat_ty(&pat) { + Ok(&ty::TyS{sty: ty::TyTuple(ref tys), ..}) => tys.len(), + ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty), + }; + let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos); for (i, subpat) in subpats.iter().enumerate() { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let subcmt = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + InteriorField(PositionalField(adjust(i)))); self.cat_pattern_(subcmt, &subpat, op)?; } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 56b4036b7d7..6b2c2dfcd72 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -970,8 +970,8 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) { pats3.iter().any(|p| is_binding_pat(&p)) } - PatKind::TupleStruct(_, Some(ref subpats)) | - PatKind::Tup(ref subpats) => { + PatKind::TupleStruct(_, ref subpats, _) | + PatKind::Tuple(ref subpats, _) => { subpats.iter().any(|p| is_binding_pat(&p)) } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index c2db6de0370..50b6d661fa8 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -33,6 +33,7 @@ use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; use hir; use hir::{Item, Generics, StructField, Variant, PatKind}; use hir::intravisit::{self, Visitor}; +use hir::pat_util::pat_adjust_pos; use std::mem::replace; use std::cmp::Ordering; @@ -614,10 +615,10 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, }; match pat.node { // Foo(a, b, c) - // A Variant(..) pattern `PatKind::TupleStruct(_, None)` doesn't have to be recursed into. - PatKind::TupleStruct(_, Some(ref pat_fields)) => { - for (field, struct_field) in pat_fields.iter().zip(&v.fields) { - maybe_do_stability_check(tcx, struct_field.did, field.span, cb) + PatKind::TupleStruct(_, ref pat_fields, ddpos) => { + let adjust = pat_adjust_pos(v.fields.len(), pat_fields.len(), ddpos); + for (i, field) in pat_fields.iter().enumerate() { + maybe_do_stability_check(tcx, v.fields[adjust(i)].did, field.span, cb) } } // Foo { a, b, c } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 2fb5d796589..f98734f21ad 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -374,7 +374,7 @@ fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool { PatKind::Ident(_, _, None) => pat_is_binding(dm, p), PatKind::Ident(_, _, Some(ref s)) => pat_is_catchall(dm, &s), PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s), - PatKind::Tup(ref v) => v.iter().all(|p| pat_is_catchall(dm, &p)), + PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(dm, &p)), _ => false } } @@ -398,7 +398,7 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir: hir::MatchSource::ForLoopDesugar => { // `witnesses[0]` has the form `Some()`, peel off the `Some` let witness = match witnesses[0].node { - PatKind::TupleStruct(_, Some(ref pats)) => match &pats[..] { + PatKind::TupleStruct(_, ref pats, _) => match &pats[..] { [ref pat] => &**pat, _ => bug!(), }, @@ -559,7 +559,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, let pats_len = pats.len(); let mut pats = pats.into_iter().map(|p| P((*p).clone())); let pat = match left_ty.sty { - ty::TyTuple(_) => PatKind::Tup(pats.collect()), + ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { let v = ctor.variant_for_adt(adt); @@ -580,7 +580,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, PatKind::Struct(def_to_path(cx.tcx, v.did), field_pats, has_more_fields) } VariantKind::Tuple => { - PatKind::TupleStruct(def_to_path(cx.tcx, v.did), Some(pats.collect())) + PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None) } VariantKind::Unit => { PatKind::Path(def_to_path(cx.tcx, v.did)) @@ -832,7 +832,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, vec!(Slice(before.len() + after.len())) } }, - PatKind::Box(_) | PatKind::Tup(_) | PatKind::Ref(..) => + PatKind::Box(..) | PatKind::Tuple(..) | PatKind::Ref(..) => vec!(Single), PatKind::Wild => vec!(), @@ -914,7 +914,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } } - PatKind::TupleStruct(_, ref args) => { + PatKind::TupleStruct(_, ref args, ddpos) => { let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def(); match def { Def::Const(..) | Def::AssociatedConst(..) => @@ -922,10 +922,15 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], been rewritten"), Def::Variant(_, id) if *constructor != Variant(id) => None, Def::Variant(..) | Def::Struct(..) => { - Some(match args { - &Some(ref args) => args.iter().map(|p| &**p).collect(), - &None => vec![DUMMY_WILD_PAT; arity], - }) + match ddpos { + Some(ddpos) => { + let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>; + pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); + pats.extend(args[ddpos..].iter().map(|p| &**p)); + Some(pats) + } + None => Some(args.iter().map(|p| &**p).collect()) + } } _ => None } @@ -952,7 +957,13 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } } - PatKind::Tup(ref args) => + PatKind::Tuple(ref args, Some(ddpos)) => { + let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>; + pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); + pats.extend(args[ddpos..].iter().map(|p| &**p)); + Some(pats) + } + PatKind::Tuple(ref args, None) => Some(args.iter().map(|p| &**p).collect()), PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) => diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 9db24fa4770..b727b778fcd 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -271,10 +271,9 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let pat = match expr.node { hir::ExprTup(ref exprs) => - PatKind::Tup(try!(exprs.iter() - .map(|expr| const_expr_to_pat(tcx, &expr, - pat_id, span)) - .collect())), + PatKind::Tuple(try!(exprs.iter() + .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) + .collect()), None), hir::ExprCall(ref callee, ref args) => { let def = *tcx.def_map.borrow().get(&callee.id).unwrap(); @@ -295,7 +294,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span)) .collect()); - PatKind::TupleStruct(path, Some(pats)) + PatKind::TupleStruct(path, pats, None) } hir::ExprStruct(ref path, ref fields, None) => { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 9ab6a437a5a..2c796690df4 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -31,6 +31,7 @@ #![feature(question_mark)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(type_ascription)] #[macro_use] extern crate syntax; #[macro_use] extern crate log; diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 0118b97dd7f..494d8a5c035 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -13,7 +13,7 @@ use hair::cx::Cx; use rustc_data_structures::fnv::FnvHashMap; use rustc_const_eval as const_eval; use rustc::hir::def::Def; -use rustc::hir::pat_util::{pat_is_resolved_const, pat_is_binding}; +use rustc::hir::pat_util::{pat_adjust_pos, pat_is_resolved_const, pat_is_binding}; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use rustc::hir::{self, PatKind}; @@ -148,17 +148,24 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { } } - PatKind::Tup(ref subpatterns) => { - let subpatterns = - subpatterns.iter() - .enumerate() - .map(|(i, subpattern)| FieldPattern { - field: Field::new(i), - pattern: self.to_pattern(subpattern), - }) - .collect(); + PatKind::Tuple(ref subpatterns, ddpos) => { + match self.cx.tcx.node_id_to_type(pat.id).sty { + ty::TyTuple(ref tys) => { + let adjust = pat_adjust_pos(tys.len(), subpatterns.len(), ddpos); + let subpatterns = + subpatterns.iter() + .enumerate() + .map(|(i, subpattern)| FieldPattern { + field: Field::new(adjust(i)), + pattern: self.to_pattern(subpattern), + }) + .collect(); - PatternKind::Leaf { subpatterns: subpatterns } + PatternKind::Leaf { subpatterns: subpatterns } + } + + ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), + } } PatKind::Ident(bm, ref ident, ref sub) @@ -208,13 +215,21 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { self.variant_or_leaf(pat, vec![]) } - PatKind::TupleStruct(_, ref opt_subpatterns) => { + PatKind::TupleStruct(_, ref subpatterns, ddpos) => { + let pat_ty = self.cx.tcx.node_id_to_type(pat.id); + let adt_def = match pat_ty.sty { + ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def, + _ => span_bug!(pat.span, "tuple struct pattern not applied to struct or enum"), + }; + let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); + let variant_def = adt_def.variant_of_def(def); + + let adjust = pat_adjust_pos(variant_def.fields.len(), subpatterns.len(), ddpos); let subpatterns = - opt_subpatterns.iter() - .flat_map(|v| v.iter()) + subpatterns.iter() .enumerate() .map(|(i, field)| FieldPattern { - field: Field::new(i), + field: Field::new(adjust(i)), pattern: self.to_pattern(field), }) .collect(); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index f1e744098b9..953bcf457b8 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -31,7 +31,7 @@ use std::mem::replace; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::{self, Visitor}; - +use rustc::hir::pat_util::pat_adjust_pos; use rustc::dep_graph::DepNode; use rustc::lint; use rustc::hir::def::{self, Def}; @@ -488,17 +488,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { self.check_field(pattern.span, adt, variant.field_named(field.node.name)); } } - - // Patterns which bind no fields are allowable (the path is check - // elsewhere). - PatKind::TupleStruct(_, Some(ref fields)) => { + PatKind::TupleStruct(_, ref fields, ddpos) => { match self.tcx.pat_ty(pattern).sty { ty::TyStruct(def, _) => { + let adjust = pat_adjust_pos(def.struct_variant().fields.len(), + fields.len(), ddpos); for (i, field) in fields.iter().enumerate() { if let PatKind::Wild = field.node { continue } - self.check_field(field.span, def, &def.struct_variant().fields[i]); + self.check_field(field.span, def, + &def.struct_variant().fields[adjust(i)]); } } ty::TyEnum(..) => { @@ -506,7 +506,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } _ => {} } - } _ => {} } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 41cc5462816..e0aa46eda18 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2360,7 +2360,7 @@ impl<'a> Resolver<'a> { } } - PatKind::TupleStruct(ref path, _) | PatKind::Path(ref path) => { + PatKind::TupleStruct(ref path, _, _) | PatKind::Path(ref path) => { // This must be an enum variant, struct or const. let resolution = match self.resolve_possibly_assoc_item(pat_id, None, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 8c00a569993..7b0ae100f05 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -696,7 +696,7 @@ impl<'v> Visitor<'v> for PathCollector { self.collected_paths.push((p.id, path.clone(), ast::Mutability::Mutable, recorder::TypeRef)); } - PatKind::TupleStruct(ref path, _) | + PatKind::TupleStruct(ref path, _, _) | PatKind::Path(ref path) | PatKind::QPath(_, ref path) => { self.collected_paths.push((p.id, path.clone(), diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index dbc277f2432..9b168301f73 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -792,7 +792,7 @@ fn any_irrefutable_adt_pat(tcx: TyCtxt, m: &[Match], col: usize) -> bool { m.iter().any(|br| { let pat = br.pats[col]; match pat.node { - PatKind::Tup(_) => true, + PatKind::Tuple(..) => true, PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::Ident(_, _, None) => { match tcx.def_map.borrow().get(&pat.id).unwrap().full_def() { @@ -1833,7 +1833,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx = bind_irrefutable_pat(bcx, &inner_pat, val, cleanup_scope); } } - PatKind::TupleStruct(_, ref sub_pats) => { + PatKind::TupleStruct(_, ref sub_pats, ddpos) => { let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def()); match opt_def { Some(Def::Variant(enum_id, var_id)) => { @@ -1843,35 +1843,36 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, &repr, Disr::from(vinfo.disr_val), val); - if let Some(ref sub_pat) = *sub_pats { - for (i, &argval) in args.vals.iter().enumerate() { - bcx = bind_irrefutable_pat( - bcx, - &sub_pat[i], - MatchInput::from_val(argval), - cleanup_scope); - } + let adjust = pat_adjust_pos(vinfo.fields.len(), sub_pats.len(), ddpos); + for (i, subpat) in sub_pats.iter().enumerate() { + bcx = bind_irrefutable_pat( + bcx, + subpat, + MatchInput::from_val(args.vals[adjust(i)]), + cleanup_scope); } } Some(Def::Struct(..)) => { - match *sub_pats { - None => { - // This is a unit-like struct. Nothing to do here. + let expected_len = match *ccx.tcx().pat_ty(&pat) { + ty::TyS{sty: ty::TyStruct(adt_def, _), ..} => { + adt_def.struct_variant().fields.len() } - Some(ref elems) => { - // This is the tuple struct case. - let repr = adt::represent_node(bcx, pat.id); - let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in elems.iter().enumerate() { - let fldptr = adt::trans_field_ptr(bcx, &repr, - val, Disr(0), i); - bcx = bind_irrefutable_pat( - bcx, - &elem, - MatchInput::from_val(fldptr), - cleanup_scope); - } + ref ty => { + span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty); } + }; + + let adjust = pat_adjust_pos(expected_len, sub_pats.len(), ddpos); + let repr = adt::represent_node(bcx, pat.id); + let val = adt::MaybeSizedValue::sized(val.val); + for (i, elem) in sub_pats.iter().enumerate() { + let fldptr = adt::trans_field_ptr(bcx, &repr, + val, Disr(0), adjust(i)); + bcx = bind_irrefutable_pat( + bcx, + &elem, + MatchInput::from_val(fldptr), + cleanup_scope); } } _ => { @@ -1919,16 +1920,22 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, cleanup_scope); } } - PatKind::Tup(ref elems) => { - let repr = adt::represent_node(bcx, pat.id); - let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in elems.iter().enumerate() { - let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i); - bcx = bind_irrefutable_pat( - bcx, - &elem, - MatchInput::from_val(fldptr), - cleanup_scope); + PatKind::Tuple(ref elems, ddpos) => { + match tcx.node_id_to_type(pat.id).sty { + ty::TyTuple(ref tys) => { + let adjust = pat_adjust_pos(tys.len(), elems.len(), ddpos); + let repr = adt::represent_node(bcx, pat.id); + let val = adt::MaybeSizedValue::sized(val.val); + for (i, elem) in elems.iter().enumerate() { + let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), adjust(i)); + bcx = bind_irrefutable_pat( + bcx, + &elem, + MatchInput::from_val(fldptr), + cleanup_scope); + } + } + ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), } } PatKind::Box(ref inner) => { diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index ba592382d1a..aec43e69e51 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -318,13 +318,11 @@ fn walk_pattern(cx: &CrateContext, scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); } - PatKind::TupleStruct(_, ref sub_pats_opt) => { + PatKind::TupleStruct(_, ref sub_pats, _) => { scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); - if let Some(ref sub_pats) = *sub_pats_opt { - for p in sub_pats { - walk_pattern(cx, &p, scope_stack, scope_map); - } + for p in sub_pats { + walk_pattern(cx, &p, scope_stack, scope_map); } } @@ -343,7 +341,7 @@ fn walk_pattern(cx: &CrateContext, } } - PatKind::Tup(ref sub_pats) => { + PatKind::Tuple(ref sub_pats, _) => { scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); for sub_pat in sub_pats { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 10c8ea84bfd..ce4ac4e815c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,7 @@ use hir::def::{self, Def}; use rustc::infer::{self, InferOk, TypeOrigin}; use hir::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; -use hir::pat_util::pat_is_resolved_const; +use hir::pat_util::{pat_adjust_pos, pat_is_resolved_const}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation}; @@ -213,13 +213,13 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { } PatKind::Ident(_, ref path, _) => { let path = hir::Path::from_name(path.span, path.node); - self.check_pat_enum(pat, &path, Some(&[]), expected, false); + self.check_pat_enum(pat, &path, &[], None, expected, false); } - PatKind::TupleStruct(ref path, ref subpats) => { - self.check_pat_enum(pat, path, subpats.as_ref().map(|v| &v[..]), expected, true); + PatKind::TupleStruct(ref path, ref subpats, ddpos) => { + self.check_pat_enum(pat, path, &subpats, ddpos, expected, true); } PatKind::Path(ref path) => { - self.check_pat_enum(pat, path, Some(&[]), expected, false); + self.check_pat_enum(pat, path, &[], None, expected, false); } PatKind::QPath(ref qself, ref path) => { let self_ty = self.to_ty(&qself.ty); @@ -260,14 +260,24 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { PatKind::Struct(ref path, ref fields, etc) => { self.check_pat_struct(pat, path, fields, etc, expected); } - PatKind::Tup(ref elements) => { - let element_tys: Vec<_> = - (0..elements.len()).map(|_| self.next_ty_var()).collect(); + PatKind::Tuple(ref elements, ddpos) => { + let mut expected_len = elements.len(); + if ddpos.is_some() { + // Require known type only when `..` is present + if let ty::TyTuple(ref tys) = + self.structurally_resolved_type(pat.span, expected).sty { + expected_len = tys.len(); + } + } + let max_len = cmp::max(expected_len, elements.len()); + + let element_tys = (0 .. max_len).map(|_| self.next_ty_var()).collect(): Vec<_>; let pat_ty = tcx.mk_tup(element_tys.clone()); self.write_ty(pat.id, pat_ty); self.demand_eqtype(pat.span, expected, pat_ty); - for (element_pat, element_ty) in elements.iter().zip(element_tys) { - self.check_pat(&element_pat, element_ty); + let adjust = pat_adjust_pos(expected_len, elements.len(), ddpos); + for i in 0 .. elements.len() { + self.check_pat(&elements[i], &element_tys[adjust(i)]); } } PatKind::Box(ref inner) => { @@ -615,7 +625,8 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { fn check_pat_enum(&self, pat: &hir::Pat, path: &hir::Path, - subpats: Option<&'gcx [P]>, + subpats: &'gcx [P], + ddpos: Option, expected: Ty<'tcx>, is_tuple_struct_pat: bool) { @@ -628,12 +639,9 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { self.set_tainted_by_errors(); self.write_error(pat.id); - if let Some(subpats) = subpats { - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } + for pat in subpats { + self.check_pat(&pat, tcx.types.err); } - return; } }; @@ -670,15 +678,12 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { }; self.instantiate_path(segments, path_scheme, &ctor_predicates, opt_ty, def, pat.span, pat.id); - let report_bad_struct_kind = |is_warning| { bad_struct_kind_err(tcx.sess, pat, path, is_warning); if is_warning { return; } self.write_error(pat.id); - if let Some(subpats) = subpats { - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } + for pat in subpats { + self.check_pat(&pat, tcx.types.err); } }; @@ -715,11 +720,13 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { }; match (is_tuple_struct_pat, variant.kind()) { - (true, ty::VariantKind::Unit) => { + (true, ty::VariantKind::Unit) if subpats.is_empty() && ddpos.is_some() => { // Matching unit structs with tuple variant patterns (`UnitVariant(..)`) // is allowed for backward compatibility. report_bad_struct_kind(true); } + (true, ty::VariantKind::Unit) | + (false, ty::VariantKind::Tuple) | (_, ty::VariantKind::Struct) => { report_bad_struct_kind(false); return @@ -727,30 +734,23 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { _ => {} } - if let Some(subpats) = subpats { - if subpats.len() == variant.fields.len() { - for (subpat, field) in subpats.iter().zip(&variant.fields) { - let field_ty = self.field_ty(subpat.span, field, expected_substs); - self.check_pat(&subpat, field_ty); - } - } else if variant.fields.is_empty() { - span_err!(tcx.sess, pat.span, E0024, - "this pattern has {} field{}, but the corresponding {} has no fields", - subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name); + let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos); + if subpats.len() == variant.fields.len() || + subpats.len() < variant.fields.len() && ddpos.is_some() { + for (i, subpat) in subpats.iter().enumerate() { + let field_ty = self.field_ty(subpat.span, + &variant.fields[adjust(i)], expected_substs); + self.check_pat(&subpat, field_ty); + } + } else { + span_err!(tcx.sess, pat.span, E0023, + "this pattern has {} field{}, but the corresponding {} has {} field{}", + subpats.len(), if subpats.len() == 1 {""} else {"s"}, + kind_name, + variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"}); - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } - } else { - span_err!(tcx.sess, pat.span, E0023, - "this pattern has {} field{}, but the corresponding {} has {} field{}", - subpats.len(), if subpats.len() == 1 {""} else {"s"}, - kind_name, - variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"}); - - for pat in subpats { - self.check_pat(&pat, tcx.types.err); - } + for pat in subpats { + self.check_pat(&pat, tcx.types.err); } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 40b9b0e01ab..77ff818aa88 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -62,31 +62,6 @@ Check how many fields the enum was declared with and ensure that your pattern uses the same number. "##, -E0024: r##" -This error indicates that a pattern attempted to extract the fields of an enum -variant with no fields. Here's a tiny example of this error: - -```compile_fail -// This enum has two variants. -enum Number { - // This variant has no fields. - Zero, - // This variant has one field. - One(u32) -} - -// Assuming x is a Number we can pattern match on its contents. -match x { - Number::Zero(inside) => {}, - Number::One(inside) => {}, -} -``` - -The pattern match `Zero(inside)` is incorrect because the `Zero` variant -contains no fields, yet the `inside` name attempts to bind the first field of -the enum. -"##, - E0025: r##" Each field of a struct can only be bound once in a pattern. Erroneous code example: diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0b23951db36..282b7582393 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,11 +77,12 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(iter_arith)] +#![feature(question_mark)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] -#![feature(question_mark)] +#![feature(type_ascription)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ca138168b29..4831ee9a2e0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2579,7 +2579,7 @@ fn name_from_pat(p: &hir::Pat) -> String { match p.node { PatKind::Wild => "_".to_string(), PatKind::Ident(_, ref p, _) => p.node.to_string(), - PatKind::TupleStruct(ref p, _) | PatKind::Path(ref p) => path_to_string(p), + PatKind::TupleStruct(ref p, _, _) | PatKind::Path(ref p) => path_to_string(p), PatKind::QPath(..) => panic!("tried to get argument name from PatKind::QPath, \ which is not allowed in function arguments"), PatKind::Struct(ref name, ref fields, etc) => { @@ -2590,7 +2590,7 @@ fn name_from_pat(p: &hir::Pat) -> String { if etc { ", ..." } else { "" } ) }, - PatKind::Tup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) + PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) .collect::>().join(", ")), PatKind::Box(ref p) => name_from_pat(&**p), PatKind::Ref(ref p, _) => name_from_pat(&**p), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d9409d3bbd9..6eb588767c4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -567,7 +567,7 @@ impl Pat { PatKind::Struct(_, ref fields, _) => { fields.iter().all(|field| field.node.pat.walk(it)) } - PatKind::TupleStruct(_, Some(ref s)) | PatKind::Tup(ref s) => { + PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => { s.iter().all(|p| p.walk(it)) } PatKind::Box(ref s) | PatKind::Ref(ref s, _) => { @@ -582,7 +582,6 @@ impl Pat { PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Ident(_, _, _) | - PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::QPath(_, _) | PatKind::Mac(_) => { @@ -631,9 +630,10 @@ pub enum PatKind { /// The `bool` is `true` in the presence of a `..`. Struct(Path, Vec>, bool), - /// A tuple struct/variant pattern `Variant(x, y, z)`. - /// "None" means a `Variant(..)` pattern where we don't bind the fields to names. - TupleStruct(Path, Option>>), + /// A tuple struct/variant pattern `Variant(x, y, .., z)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + TupleStruct(Path, Vec>, Option), /// A path pattern. /// Such pattern can be resolved to a unit struct/variant or a constant. @@ -645,8 +645,10 @@ pub enum PatKind { /// PatKind::Path, and the resolver will have to sort that out. QPath(QSelf, Path), - /// A tuple pattern `(a, b)` - Tup(Vec>), + /// A tuple pattern `(a, b)`. + /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// 0 <= position <= subpats.len() + Tuple(Vec>, Option), /// A `box` pattern Box(P), /// A reference pattern, e.g. `&mut (a, b)` diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 7958162986c..3a1cdae9bfb 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -832,7 +832,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let pat = if subpats.is_empty() { PatKind::Path(path) } else { - PatKind::TupleStruct(path, Some(subpats)) + PatKind::TupleStruct(path, subpats, None) }; self.pat(span, pat) } @@ -842,7 +842,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.pat(span, pat) } fn pat_tuple(&self, span: Span, pats: Vec>) -> P { - self.pat(span, PatKind::Tup(pats)) + self.pat(span, PatKind::Tuple(pats, None)) } fn pat_some(&self, span: Span, pat: P) -> P { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index acef98f2afc..b5bab09c70e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -274,7 +274,10 @@ declare_features! ( (active, drop_types_in_const, "1.9.0", Some(33156)), // Allows cfg(target_has_atomic = "..."). - (active, cfg_target_has_atomic, "1.9.0", Some(32976)) + (active, cfg_target_has_atomic, "1.9.0", Some(32976)), + + // Allows `..` in tuple (struct) patterns + (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)) ); declare_features! ( @@ -315,7 +318,6 @@ declare_features! ( // Allows `#[deprecated]` attribute (accepted, deprecated, "1.9.0", Some(29935)) ); - // (changing above list without updating src/doc/reference.md makes @cmr sad) #[derive(PartialEq, Copy, Clone, Debug)] @@ -1021,6 +1023,24 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { pattern.span, "box pattern syntax is experimental"); } + PatKind::Tuple(_, ddpos) + if ddpos.is_some() => { + gate_feature_post!(&self, dotdot_in_tuple_patterns, + pattern.span, + "`..` in tuple patterns is experimental"); + } + PatKind::TupleStruct(_, ref fields, ddpos) + if ddpos.is_some() && !fields.is_empty() => { + gate_feature_post!(&self, dotdot_in_tuple_patterns, + pattern.span, + "`..` in tuple struct patterns is experimental"); + } + PatKind::TupleStruct(_, ref fields, ddpos) + if ddpos.is_none() && fields.is_empty() => { + self.context.span_handler.struct_span_err(pattern.span, + "nullary enum variants are written with \ + no trailing `( )`").emit(); + } _ => {} } visit::walk_pat(self, pattern) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2c325080c0c..c9d23427657 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1115,9 +1115,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { sub.map(|x| folder.fold_pat(x))) } PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)), - PatKind::TupleStruct(pth, pats) => { + PatKind::TupleStruct(pth, pats, ddpos) => { PatKind::TupleStruct(folder.fold_path(pth), - pats.map(|pats| pats.move_map(|x| folder.fold_pat(x)))) + pats.move_map(|x| folder.fold_pat(x)), ddpos) } PatKind::Path(pth) => { PatKind::Path(folder.fold_path(pth)) @@ -1138,7 +1138,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { }); PatKind::Struct(pth, fs, etc) } - PatKind::Tup(elts) => PatKind::Tup(elts.move_map(|x| folder.fold_pat(x))), + PatKind::Tuple(elts, ddpos) => { + PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos) + } PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)), PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl), PatKind::Range(e1, e2) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fc62cee92fd..a4f12769b5c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -954,25 +954,6 @@ impl<'a> Parser<'a> { Ok(result) } - /// Parse a sequence parameter of enum variant. For consistency purposes, - /// these should not be empty. - pub fn parse_enum_variant_seq(&mut self, - bra: &token::Token, - ket: &token::Token, - sep: SeqSep, - f: F) - -> PResult<'a, Vec> where - F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, - { - let result = self.parse_unspanned_seq(bra, ket, sep, f)?; - if result.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, - "nullary enum variants are written with no trailing `( )`"); - } - Ok(result) - } - // NB: Do not use this function unless you actually plan to place the // spanned list in the AST. pub fn parse_seq(&mut self, @@ -3433,21 +3414,29 @@ impl<'a> Parser<'a> { }; } - fn parse_pat_tuple_elements(&mut self) -> PResult<'a, Vec>> { + fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool) + -> PResult<'a, (Vec>, Option)> { let mut fields = vec![]; - if !self.check(&token::CloseDelim(token::Paren)) { - fields.push(self.parse_pat()?); - if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) { - while self.eat(&token::Comma) && - !self.check(&token::CloseDelim(token::Paren)) { + let mut ddpos = None; + + while !self.check(&token::CloseDelim(token::Paren)) { + if ddpos.is_none() && self.eat(&token::DotDot) { + ddpos = Some(fields.len()); + if self.eat(&token::Comma) { + // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed. fields.push(self.parse_pat()?); } + } else { + fields.push(self.parse_pat()?); } - if fields.len() == 1 { + + if !self.check(&token::CloseDelim(token::Paren)) || + (unary_needs_comma && fields.len() == 1 && ddpos.is_none()) { self.expect(&token::Comma)?; } } - Ok(fields) + + Ok((fields, ddpos)) } fn parse_pat_vec_elements( @@ -3626,9 +3615,9 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Paren) => { // Parse (pat,pat,pat,...) as tuple pattern self.bump(); - let fields = self.parse_pat_tuple_elements()?; + let (fields, ddpos) = self.parse_pat_tuple_elements(true)?; self.expect(&token::CloseDelim(token::Paren))?; - pat = PatKind::Tup(fields); + pat = PatKind::Tuple(fields, ddpos); } token::OpenDelim(token::Bracket) => { // Parse [pat,pat,...] as slice pattern @@ -3713,20 +3702,10 @@ impl<'a> Parser<'a> { return Err(self.fatal("unexpected `(` after qualified path")); } // Parse tuple struct or enum pattern - if self.look_ahead(1, |t| *t == token::DotDot) { - // This is a "top constructor only" pat - self.bump(); - self.bump(); - self.expect(&token::CloseDelim(token::Paren))?; - pat = PatKind::TupleStruct(path, None); - } else { - let args = self.parse_enum_variant_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - SeqSep::trailing_allowed(token::Comma), - |p| p.parse_pat())?; - pat = PatKind::TupleStruct(path, Some(args)); - } + self.bump(); + let (fields, ddpos) = self.parse_pat_tuple_elements(false)?; + self.expect(&token::CloseDelim(token::Paren))?; + pat = PatKind::TupleStruct(path, fields, ddpos) } _ => { pat = match qself { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ebb4927d69c..6c3f3e28727 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2472,17 +2472,23 @@ impl<'a> State<'a> { None => () } } - PatKind::TupleStruct(ref path, ref args_) => { + PatKind::TupleStruct(ref path, ref elts, ddpos) => { self.print_path(path, true, 0)?; - match *args_ { - None => word(&mut self.s, "(..)")?, - Some(ref args) => { - self.popen()?; - self.commasep(Inconsistent, &args[..], - |s, p| s.print_pat(&p))?; - self.pclose()?; + self.popen()?; + if let Some(ddpos) = ddpos { + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?; + if ddpos != 0 { + self.word_space(",")?; } + word(&mut self.s, "..")?; + if ddpos != elts.len() { + word(&mut self.s, ",")?; + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; + } + } else { + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; } + self.pclose()?; } PatKind::Path(ref path) => { self.print_path(path, true, 0)?; @@ -2513,13 +2519,23 @@ impl<'a> State<'a> { space(&mut self.s)?; word(&mut self.s, "}")?; } - PatKind::Tup(ref elts) => { + PatKind::Tuple(ref elts, ddpos) => { self.popen()?; - self.commasep(Inconsistent, - &elts[..], - |s, p| s.print_pat(&p))?; - if elts.len() == 1 { - word(&mut self.s, ",")?; + if let Some(ddpos) = ddpos { + self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?; + if ddpos != 0 { + self.word_space(",")?; + } + word(&mut self.s, "..")?; + if ddpos != elts.len() { + word(&mut self.s, ",")?; + self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; + } + } else { + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; + if elts.len() == 1 { + word(&mut self.s, ",")?; + } } self.pclose()?; } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f50a480e5e5..d41d170c084 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -423,11 +423,9 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { match pattern.node { - PatKind::TupleStruct(ref path, ref opt_children) => { + PatKind::TupleStruct(ref path, ref children, _) => { visitor.visit_path(path, pattern.id); - if let Some(ref children) = *opt_children { - walk_list!(visitor, visit_pat, children); - } + walk_list!(visitor, visit_pat, children); } PatKind::Path(ref path) => { visitor.visit_path(path, pattern.id); @@ -443,7 +441,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_pat(&field.node.pat) } } - PatKind::Tup(ref tuple_elements) => { + PatKind::Tuple(ref tuple_elements, _) => { walk_list!(visitor, visit_pat, tuple_elements); } PatKind::Box(ref subpattern) | diff --git a/src/test/compile-fail/issue-32004.rs b/src/test/compile-fail/issue-32004.rs index 0227a80fd75..8d74154655f 100644 --- a/src/test/compile-fail/issue-32004.rs +++ b/src/test/compile-fail/issue-32004.rs @@ -18,12 +18,12 @@ struct S; fn main() { match Foo::Baz { Foo::Bar => {} - //~^ ERROR this pattern has 0 fields, but the corresponding variant + //~^ ERROR `Foo::Bar` does not name a tuple variant or a tuple struct _ => {} } match S { S(()) => {} - //~^ ERROR this pattern has 1 field, but the corresponding struct + //~^ ERROR `S` does not name a tuple variant or a tuple struct } } diff --git a/src/test/compile-fail/match-pattern-field-mismatch-2.rs b/src/test/compile-fail/match-pattern-field-mismatch-2.rs index e63ddf6c7fd..a4ba93ea173 100644 --- a/src/test/compile-fail/match-pattern-field-mismatch-2.rs +++ b/src/test/compile-fail/match-pattern-field-mismatch-2.rs @@ -20,7 +20,7 @@ fn main() { color::rgb(_, _, _) => { } color::cmyk(_, _, _, _) => { } color::no_color(_) => { } - //~^ ERROR this pattern has 1 field, but the corresponding variant has no fields + //~^ ERROR `color::no_color` does not name a tuple variant or a tuple struct } } } diff --git a/src/test/compile-fail/pat-tuple-bad-type.rs b/src/test/compile-fail/pat-tuple-bad-type.rs new file mode 100644 index 00000000000..0d50a30dd05 --- /dev/null +++ b/src/test/compile-fail/pat-tuple-bad-type.rs @@ -0,0 +1,27 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn main() { + let x; + + match x { + (..) => {} //~ ERROR the type of this value must be known in this context + _ => {} + } + + match 0u8 { + (..) => {} //~ ERROR mismatched types + _ => {} + } + + x = 10; +} diff --git a/src/test/compile-fail/pat-tuple-feature-gate.rs b/src/test/compile-fail/pat-tuple-feature-gate.rs new file mode 100644 index 00000000000..55ca05bdef3 --- /dev/null +++ b/src/test/compile-fail/pat-tuple-feature-gate.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + match 0 { + (..) => {} //~ ERROR `..` in tuple patterns is experimental + (pat, ..) => {} //~ ERROR `..` in tuple patterns is experimental + S(pat, ..) => {} //~ ERROR `..` in tuple struct patterns is experimental + } +} diff --git a/src/test/compile-fail/pat-tuple-overfield.rs b/src/test/compile-fail/pat-tuple-overfield.rs new file mode 100644 index 00000000000..034ef4a72e2 --- /dev/null +++ b/src/test/compile-fail/pat-tuple-overfield.rs @@ -0,0 +1,28 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +struct S(u8, u8, u8); + +fn main() { + match (1, 2, 3) { + (1, 2, 3, 4) => {} //~ ERROR mismatched types + (1, 2, .., 3, 4) => {} //~ ERROR mismatched types + _ => {} + } + match S(1, 2, 3) { + S(1, 2, 3, 4) => {} + //~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields + S(1, 2, .., 3, 4) => {} + //~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields + _ => {} + } +} diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs index d9f3bb3c40f..507012e8c5c 100644 --- a/src/test/compile-fail/pattern-error-continue.rs +++ b/src/test/compile-fail/pattern-error-continue.rs @@ -25,7 +25,7 @@ fn f(_c: char) {} fn main() { match A::B(1, 2) { A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but - A::D(_) => (), //~ ERROR this pattern has 1 field, but + A::D(_) => (), //~ ERROR `A::D` does not name a tuple variant or a tuple struct _ => () } match 'c' { diff --git a/src/test/parse-fail/pat-lt-bracket-6.rs b/src/test/parse-fail/pat-lt-bracket-6.rs index 5ed8f6dee8c..fb78e558a95 100644 --- a/src/test/parse-fail/pat-lt-bracket-6.rs +++ b/src/test/parse-fail/pat-lt-bracket-6.rs @@ -9,6 +9,5 @@ // except according to those terms. fn main() { - let Test(&desc[..]) = x; //~ error: expected one of `,` or `@`, found `[` - //~^ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` + let Test(&desc[..]) = x; //~ ERROR: expected one of `)`, `,`, or `@`, found `[` } diff --git a/src/test/parse-fail/pat-lt-bracket-7.rs b/src/test/parse-fail/pat-lt-bracket-7.rs index 00681e61497..d75589d8889 100644 --- a/src/test/parse-fail/pat-lt-bracket-7.rs +++ b/src/test/parse-fail/pat-lt-bracket-7.rs @@ -9,6 +9,5 @@ // except according to those terms. fn main() { - for thing(x[]) in foo {} //~ error: expected one of `,` or `@`, found `[` - //~^ ERROR expected one of `@` or `in`, found `[` + for thing(x[]) in foo {} //~ ERROR: expected one of `)`, `,`, or `@`, found `[` } diff --git a/src/test/compile-fail/E0024.rs b/src/test/parse-fail/pat-tuple-1.rs similarity index 74% rename from src/test/compile-fail/E0024.rs rename to src/test/parse-fail/pat-tuple-1.rs index 18f4dcf19d7..945d0740654 100644 --- a/src/test/compile-fail/E0024.rs +++ b/src/test/parse-fail/pat-tuple-1.rs @@ -8,15 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum Number { - Zero, - One(u32) -} +// compile-flags: -Z parse-only fn main() { - let x = Number::Zero; - match x { - Number::Zero(inside) => {}, //~ ERROR E0024 - Number::One(inside) => {}, + match 0 { + (, ..) => {} //~ ERROR expected pattern, found `,` } } diff --git a/src/test/parse-fail/pat-tuple-2.rs b/src/test/parse-fail/pat-tuple-2.rs new file mode 100644 index 00000000000..ad52fa57870 --- /dev/null +++ b/src/test/parse-fail/pat-tuple-2.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (pat, ..,) => {} //~ ERROR expected pattern, found `)` + } +} diff --git a/src/test/parse-fail/pat-tuple-3.rs b/src/test/parse-fail/pat-tuple-3.rs new file mode 100644 index 00000000000..95e44ae134c --- /dev/null +++ b/src/test/parse-fail/pat-tuple-3.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (.., pat, ..) => {} //~ ERROR expected pattern, found `..` + } +} diff --git a/src/test/parse-fail/pat-tuple-4.rs b/src/test/parse-fail/pat-tuple-4.rs new file mode 100644 index 00000000000..f4c3afa07f1 --- /dev/null +++ b/src/test/parse-fail/pat-tuple-4.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (.. pat) => {} //~ ERROR expected one of `)` or `,`, found `pat` + } +} diff --git a/src/test/parse-fail/pat-tuple-5.rs b/src/test/parse-fail/pat-tuple-5.rs new file mode 100644 index 00000000000..145d1f9d8ec --- /dev/null +++ b/src/test/parse-fail/pat-tuple-5.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (pat ..) => {} //~ ERROR expected one of `)`, `,`, or `@`, found `..` + } +} diff --git a/src/test/parse-fail/pat-tuple-6.rs b/src/test/parse-fail/pat-tuple-6.rs new file mode 100644 index 00000000000..3252d92fe1b --- /dev/null +++ b/src/test/parse-fail/pat-tuple-6.rs @@ -0,0 +1,17 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() { + match 0 { + (pat) => {} //~ ERROR expected one of `,` or `@`, found `)` + } +} diff --git a/src/test/run-pass/pat-tuple.rs b/src/test/run-pass/pat-tuple.rs new file mode 100644 index 00000000000..ccea068f715 --- /dev/null +++ b/src/test/run-pass/pat-tuple.rs @@ -0,0 +1,202 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn b() { + let x = (1, 2, 3); + match x { + (a, b, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + } + } + match x { + (.., b, c) => { + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + (a, .., c) => { + assert_eq!(a, 1); + assert_eq!(c, 3); + } + } + match x { + (a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } +} + +fn bs() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + match x { + S(a, b, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + } + } + match x { + S(.., b, c) => { + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + S(a, .., c) => { + assert_eq!(a, 1); + assert_eq!(c, 3); + } + } + match x { + S(a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } +} + +fn c() { + let x = (1,); + match x { + (2, ..) => panic!(), + (..) => () + } +} + +fn cs() { + struct S(u8); + + let x = S(1); + match x { + S(2, ..) => panic!(), + S(..) => () + } +} + +fn d() { + let x = (1, 2, 3); + let branch = match x { + (1, 1, ..) => 0, + (1, 2, 3, ..) => 1, + (1, 2, ..) => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + +fn ds() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + let branch = match x { + S(1, 1, ..) => 0, + S(1, 2, 3, ..) => 1, + S(1, 2, ..) => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + +fn f() { + let x = (1, 2, 3); + match x { + (1, 2, 4) => unreachable!(), + (0, 2, 3, ..) => unreachable!(), + (0, .., 3) => unreachable!(), + (0, ..) => unreachable!(), + (1, 2, 3) => (), + (_, _, _) => unreachable!(), + } + match x { + (..) => (), + } + match x { + (_, _, _, ..) => (), + } + match x { + (a, b, c) => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +fn fs() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + match x { + S(1, 2, 4) => unreachable!(), + S(0, 2, 3, ..) => unreachable!(), + S(0, .., 3) => unreachable!(), + S(0, ..) => unreachable!(), + S(1, 2, 3) => (), + S(_, _, _) => unreachable!(), + } + match x { + S(..) => (), + } + match x { + S(_, _, _, ..) => (), + } + match x { + S(a, b, c) => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +fn g() { + struct S; + struct Z; + struct W; + let x = (S, Z, W); + match x { (S, ..) => {} } + match x { (.., W) => {} } + match x { (S, .., W) => {} } + match x { (.., Z, _) => {} } +} + +fn gs() { + struct SS(S, Z, W); + + struct S; + struct Z; + struct W; + let x = SS(S, Z, W); + match x { SS(S, ..) => {} } + match x { SS(.., W) => {} } + match x { SS(S, .., W) => {} } + match x { SS(.., Z, _) => {} } +} + +fn main() { + b(); + bs(); + c(); + cs(); + d(); + ds(); + f(); + fs(); + g(); + gs(); +} From c038b454239a30cb8a734bcb2ff8a7e5e543939a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 7/9] Address review comments --- src/librustc/hir/mod.rs | 4 +- src/librustc/hir/pat_util.rs | 8 +- src/libsyntax/ast.rs | 4 +- src/libsyntax/parse/parser.rs | 4 + src/test/parse-fail/pat-tuple-3.rs | 2 +- src/test/run-pass/pat-tuple-1.rs | 104 +++++++++++++++ src/test/run-pass/pat-tuple-2.rs | 34 +++++ src/test/run-pass/pat-tuple-3.rs | 40 ++++++ src/test/run-pass/pat-tuple-4.rs | 68 ++++++++++ src/test/run-pass/pat-tuple-5.rs | 40 ++++++ src/test/run-pass/pat-tuple-6.rs | 56 ++++++++ src/test/run-pass/pat-tuple.rs | 202 ----------------------------- 12 files changed, 355 insertions(+), 211 deletions(-) create mode 100644 src/test/run-pass/pat-tuple-1.rs create mode 100644 src/test/run-pass/pat-tuple-2.rs create mode 100644 src/test/run-pass/pat-tuple-3.rs create mode 100644 src/test/run-pass/pat-tuple-4.rs create mode 100644 src/test/run-pass/pat-tuple-5.rs create mode 100644 src/test/run-pass/pat-tuple-6.rs delete mode 100644 src/test/run-pass/pat-tuple.rs diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 961885d1b86..dff17d8c17b 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -539,7 +539,7 @@ pub enum PatKind { Struct(Path, HirVec>, bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() TupleStruct(Path, HirVec>, Option), @@ -554,7 +554,7 @@ pub enum PatKind { QPath(QSelf, Path), /// A tuple pattern `(a, b)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() Tuple(HirVec>, Option), /// A `box` pattern diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index f41c4b0840d..cf4842a25d6 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -22,12 +22,12 @@ use std::cell::RefCell; pub type PatIdMap = FnvHashMap; #[derive(Clone, Copy)] -pub struct AjustPos { +pub struct AdjustPos { gap_pos: usize, gap_len: usize, } -impl FnOnce<(usize,)> for AjustPos { +impl FnOnce<(usize,)> for AdjustPos { type Output = usize; extern "rust-call" fn call_once(self, (i,): (usize,)) -> usize { if i < self.gap_pos { i } else { i + self.gap_len } @@ -36,8 +36,8 @@ impl FnOnce<(usize,)> for AjustPos { // Returns a functional object used to adjust tuple pattern indexes. Example: for 5-tuple and // pattern (a, b, .., c) expected_len is 5, actual_len is 3 and gap_pos is Some(2). -pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option) -> AjustPos { - AjustPos { +pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option) -> AdjustPos { + AdjustPos { gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len }, gap_len: expected_len - actual_len, } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6eb588767c4..7c3c33c28f6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -631,7 +631,7 @@ pub enum PatKind { Struct(Path, Vec>, bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() TupleStruct(Path, Vec>, Option), @@ -646,7 +646,7 @@ pub enum PatKind { QPath(QSelf, Path), /// A tuple pattern `(a, b)`. - /// If the `..` pattern fragment presents, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `Option` denotes its position. /// 0 <= position <= subpats.len() Tuple(Vec>, Option), /// A `box` pattern diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a4f12769b5c..943910b1570 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3426,6 +3426,10 @@ impl<'a> Parser<'a> { // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed. fields.push(self.parse_pat()?); } + } else if ddpos.is_some() && self.eat(&token::DotDot) { + // Emit a friendly error, ignore `..` and continue parsing + self.span_err(self.last_span, "`..` can only be used once per \ + tuple or tuple struct pattern"); } else { fields.push(self.parse_pat()?); } diff --git a/src/test/parse-fail/pat-tuple-3.rs b/src/test/parse-fail/pat-tuple-3.rs index 95e44ae134c..029dc7a2956 100644 --- a/src/test/parse-fail/pat-tuple-3.rs +++ b/src/test/parse-fail/pat-tuple-3.rs @@ -12,6 +12,6 @@ fn main() { match 0 { - (.., pat, ..) => {} //~ ERROR expected pattern, found `..` + (.., pat, ..) => {} //~ ERROR `..` can only be used once per tuple or tuple struct pattern } } diff --git a/src/test/run-pass/pat-tuple-1.rs b/src/test/run-pass/pat-tuple-1.rs new file mode 100644 index 00000000000..c3796210a8e --- /dev/null +++ b/src/test/run-pass/pat-tuple-1.rs @@ -0,0 +1,104 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1, 2, 3); + match x { + (a, b, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + } + } + match x { + (.., b, c) => { + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + (a, .., c) => { + assert_eq!(a, 1); + assert_eq!(c, 3); + } + } + match x { + (a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + (a, b, c, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + (.., a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } +} + +fn tuple_struct() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + match x { + S(a, b, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + } + } + match x { + S(.., b, c) => { + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + S(a, .., c) => { + assert_eq!(a, 1); + assert_eq!(c, 3); + } + } + match x { + S(a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + S(a, b, c, ..) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } + match x { + S(.., a, b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + } + } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-2.rs b/src/test/run-pass/pat-tuple-2.rs new file mode 100644 index 00000000000..881e96a9d78 --- /dev/null +++ b/src/test/run-pass/pat-tuple-2.rs @@ -0,0 +1,34 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1,); + match x { + (2, ..) => panic!(), + (..) => () + } +} + +fn tuple_struct() { + struct S(u8); + + let x = S(1); + match x { + S(2, ..) => panic!(), + S(..) => () + } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-3.rs b/src/test/run-pass/pat-tuple-3.rs new file mode 100644 index 00000000000..94d33d41899 --- /dev/null +++ b/src/test/run-pass/pat-tuple-3.rs @@ -0,0 +1,40 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1, 2, 3); + let branch = match x { + (1, 1, ..) => 0, + (1, 2, 3, ..) => 1, + (1, 2, ..) => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + +fn tuple_struct() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + let branch = match x { + S(1, 1, ..) => 0, + S(1, 2, 3, ..) => 1, + S(1, 2, ..) => 2, + _ => 3 + }; + assert_eq!(branch, 1); +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-4.rs b/src/test/run-pass/pat-tuple-4.rs new file mode 100644 index 00000000000..ffd82fea996 --- /dev/null +++ b/src/test/run-pass/pat-tuple-4.rs @@ -0,0 +1,68 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1, 2, 3); + match x { + (1, 2, 4) => unreachable!(), + (0, 2, 3, ..) => unreachable!(), + (0, .., 3) => unreachable!(), + (0, ..) => unreachable!(), + (1, 2, 3) => (), + (_, _, _) => unreachable!(), + } + match x { + (..) => (), + } + match x { + (_, _, _, ..) => (), + } + match x { + (a, b, c) => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +fn tuple_struct() { + struct S(u8, u8, u8); + + let x = S(1, 2, 3); + match x { + S(1, 2, 4) => unreachable!(), + S(0, 2, 3, ..) => unreachable!(), + S(0, .., 3) => unreachable!(), + S(0, ..) => unreachable!(), + S(1, 2, 3) => (), + S(_, _, _) => unreachable!(), + } + match x { + S(..) => (), + } + match x { + S(_, _, _, ..) => (), + } + match x { + S(a, b, c) => { + assert_eq!(1, a); + assert_eq!(2, b); + assert_eq!(3, c); + } + } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-5.rs b/src/test/run-pass/pat-tuple-5.rs new file mode 100644 index 00000000000..41c4d02abcb --- /dev/null +++ b/src/test/run-pass/pat-tuple-5.rs @@ -0,0 +1,40 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + struct S; + struct Z; + struct W; + let x = (S, Z, W); + match x { (S, ..) => {} } + match x { (.., W) => {} } + match x { (S, .., W) => {} } + match x { (.., Z, _) => {} } +} + +fn tuple_struct() { + struct SS(S, Z, W); + + struct S; + struct Z; + struct W; + let x = SS(S, Z, W); + match x { SS(S, ..) => {} } + match x { SS(.., W) => {} } + match x { SS(S, .., W) => {} } + match x { SS(.., Z, _) => {} } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple-6.rs b/src/test/run-pass/pat-tuple-6.rs new file mode 100644 index 00000000000..6f3f2b3aed5 --- /dev/null +++ b/src/test/run-pass/pat-tuple-6.rs @@ -0,0 +1,56 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(dotdot_in_tuple_patterns)] + +fn tuple() { + let x = (1, 2, 3, 4, 5); + match x { + (a, .., b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 4); + assert_eq!(c, 5); + } + } + match x { + (a, b, c, .., d) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + assert_eq!(d, 5); + } + } +} + +fn tuple_struct() { + struct S(u8, u8, u8, u8, u8); + + let x = S(1, 2, 3, 4, 5); + match x { + S(a, .., b, c) => { + assert_eq!(a, 1); + assert_eq!(b, 4); + assert_eq!(c, 5); + } + } + match x { + S(a, b, c, .., d) => { + assert_eq!(a, 1); + assert_eq!(b, 2); + assert_eq!(c, 3); + assert_eq!(d, 5); + } + } +} + +fn main() { + tuple(); + tuple_struct(); +} diff --git a/src/test/run-pass/pat-tuple.rs b/src/test/run-pass/pat-tuple.rs deleted file mode 100644 index ccea068f715..00000000000 --- a/src/test/run-pass/pat-tuple.rs +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(dotdot_in_tuple_patterns)] - -fn b() { - let x = (1, 2, 3); - match x { - (a, b, ..) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - } - } - match x { - (.., b, c) => { - assert_eq!(b, 2); - assert_eq!(c, 3); - } - } - match x { - (a, .., c) => { - assert_eq!(a, 1); - assert_eq!(c, 3); - } - } - match x { - (a, b, c) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - assert_eq!(c, 3); - } - } -} - -fn bs() { - struct S(u8, u8, u8); - - let x = S(1, 2, 3); - match x { - S(a, b, ..) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - } - } - match x { - S(.., b, c) => { - assert_eq!(b, 2); - assert_eq!(c, 3); - } - } - match x { - S(a, .., c) => { - assert_eq!(a, 1); - assert_eq!(c, 3); - } - } - match x { - S(a, b, c) => { - assert_eq!(a, 1); - assert_eq!(b, 2); - assert_eq!(c, 3); - } - } -} - -fn c() { - let x = (1,); - match x { - (2, ..) => panic!(), - (..) => () - } -} - -fn cs() { - struct S(u8); - - let x = S(1); - match x { - S(2, ..) => panic!(), - S(..) => () - } -} - -fn d() { - let x = (1, 2, 3); - let branch = match x { - (1, 1, ..) => 0, - (1, 2, 3, ..) => 1, - (1, 2, ..) => 2, - _ => 3 - }; - assert_eq!(branch, 1); -} - -fn ds() { - struct S(u8, u8, u8); - - let x = S(1, 2, 3); - let branch = match x { - S(1, 1, ..) => 0, - S(1, 2, 3, ..) => 1, - S(1, 2, ..) => 2, - _ => 3 - }; - assert_eq!(branch, 1); -} - -fn f() { - let x = (1, 2, 3); - match x { - (1, 2, 4) => unreachable!(), - (0, 2, 3, ..) => unreachable!(), - (0, .., 3) => unreachable!(), - (0, ..) => unreachable!(), - (1, 2, 3) => (), - (_, _, _) => unreachable!(), - } - match x { - (..) => (), - } - match x { - (_, _, _, ..) => (), - } - match x { - (a, b, c) => { - assert_eq!(1, a); - assert_eq!(2, b); - assert_eq!(3, c); - } - } -} - -fn fs() { - struct S(u8, u8, u8); - - let x = S(1, 2, 3); - match x { - S(1, 2, 4) => unreachable!(), - S(0, 2, 3, ..) => unreachable!(), - S(0, .., 3) => unreachable!(), - S(0, ..) => unreachable!(), - S(1, 2, 3) => (), - S(_, _, _) => unreachable!(), - } - match x { - S(..) => (), - } - match x { - S(_, _, _, ..) => (), - } - match x { - S(a, b, c) => { - assert_eq!(1, a); - assert_eq!(2, b); - assert_eq!(3, c); - } - } -} - -fn g() { - struct S; - struct Z; - struct W; - let x = (S, Z, W); - match x { (S, ..) => {} } - match x { (.., W) => {} } - match x { (S, .., W) => {} } - match x { (.., Z, _) => {} } -} - -fn gs() { - struct SS(S, Z, W); - - struct S; - struct Z; - struct W; - let x = SS(S, Z, W); - match x { SS(S, ..) => {} } - match x { SS(.., W) => {} } - match x { SS(S, .., W) => {} } - match x { SS(.., Z, _) => {} } -} - -fn main() { - b(); - bs(); - c(); - cs(); - d(); - ds(); - f(); - fs(); - g(); - gs(); -} From 35ef09c38b3887a1880ad80874868afb41d28dd3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 8/9] Replace pat_adjust_pos with an iterator adapter --- src/librustc/hir/pat_util.rs | 36 +++++++++++++++-------- src/librustc/lib.rs | 2 -- src/librustc/middle/mem_categorization.rs | 20 ++++++------- src/librustc/middle/stability.rs | 7 ++--- src/librustc_const_eval/check_match.rs | 4 +-- src/librustc_const_eval/lib.rs | 1 - src/librustc_mir/hair/cx/pattern.rs | 12 ++++---- src/librustc_privacy/lib.rs | 10 +++---- src/librustc_trans/_match.rs | 17 +++++------ src/librustc_typeck/check/_match.rs | 15 ++++------ src/librustc_typeck/lib.rs | 3 +- 11 files changed, 61 insertions(+), 66 deletions(-) diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index cf4842a25d6..1008ba7a6e6 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -18,28 +18,40 @@ use hir::{self, PatKind}; use syntax::codemap::{respan, Span, Spanned, DUMMY_SP}; use std::cell::RefCell; +use std::iter::{Enumerate, ExactSizeIterator}; pub type PatIdMap = FnvHashMap; -#[derive(Clone, Copy)] -pub struct AdjustPos { +pub struct EnumerateAndAdjust { + enumerate: Enumerate, gap_pos: usize, gap_len: usize, } -impl FnOnce<(usize,)> for AdjustPos { - type Output = usize; - extern "rust-call" fn call_once(self, (i,): (usize,)) -> usize { - if i < self.gap_pos { i } else { i + self.gap_len } +impl Iterator for EnumerateAndAdjust where I: Iterator { + type Item = (usize, ::Item); + + fn next(&mut self) -> Option<(usize, ::Item)> { + self.enumerate.next().map(|(i, elem)| { + (if i < self.gap_pos { i } else { i + self.gap_len }, elem) + }) } } -// Returns a functional object used to adjust tuple pattern indexes. Example: for 5-tuple and -// pattern (a, b, .., c) expected_len is 5, actual_len is 3 and gap_pos is Some(2). -pub fn pat_adjust_pos(expected_len: usize, actual_len: usize, gap_pos: Option) -> AdjustPos { - AdjustPos { - gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len }, - gap_len: expected_len - actual_len, +pub trait EnumerateAndAdjustIterator { + fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option) + -> EnumerateAndAdjust where Self: Sized; +} + +impl EnumerateAndAdjustIterator for T { + fn enumerate_and_adjust(self, expected_len: usize, gap_pos: Option) + -> EnumerateAndAdjust where Self: Sized { + let actual_len = self.len(); + EnumerateAndAdjust { + enumerate: self.enumerate(), + gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len }, + gap_len: expected_len - actual_len, + } } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 4ecad7f93a5..e1fb701e641 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,7 +29,6 @@ #![feature(collections)] #![feature(const_fn)] #![feature(enumset)] -#![feature(fn_traits)] #![feature(iter_arith)] #![feature(libc)] #![feature(nonzero)] @@ -39,7 +38,6 @@ #![feature(slice_patterns)] #![feature(staged_api)] #![feature(question_mark)] -#![feature(unboxed_closures)] #![cfg_attr(test, feature(test))] extern crate arena; diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index da3df7ad3e9..e933b22f607 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -80,7 +80,7 @@ use ty::adjustment; use ty::{self, Ty, TyCtxt}; use hir::{MutImmutable, MutMutable, PatKind}; -use hir::pat_util::pat_adjust_pos; +use hir::pat_util::EnumerateAndAdjustIterator; use hir; use syntax::ast; use syntax::codemap::Span; @@ -1230,15 +1230,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match opt_def { Some(Def::Variant(enum_def, def_id)) => { // variant(x, y, z) - let variant = self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id); - let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos); - for (i, subpat) in subpats.iter().enumerate() { + let expected_len = self.tcx().lookup_adt_def(enum_def) + .variant_with_id(def_id).fields.len(); + for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let subcmt = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(adjust(i)))); + InteriorField(PositionalField(i))); self.cat_pattern_(subcmt, &subpat, op)?; } @@ -1253,13 +1253,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } }; - let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos); - for (i, subpat) in subpats.iter().enumerate() { + for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let cmt_field = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(adjust(i)))); + InteriorField(PositionalField(i))); self.cat_pattern_(cmt_field, &subpat, op)?; } } @@ -1300,13 +1299,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Ok(&ty::TyS{sty: ty::TyTuple(ref tys), ..}) => tys.len(), ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty), }; - let adjust = pat_adjust_pos(expected_len, subpats.len(), ddpos); - for (i, subpat) in subpats.iter().enumerate() { + for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) let subcmt = self.cat_imm_interior( pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(adjust(i)))); + InteriorField(PositionalField(i))); self.cat_pattern_(subcmt, &subpat, op)?; } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 50b6d661fa8..fcb03aba6d1 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -33,7 +33,7 @@ use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; use hir; use hir::{Item, Generics, StructField, Variant, PatKind}; use hir::intravisit::{self, Visitor}; -use hir::pat_util::pat_adjust_pos; +use hir::pat_util::EnumerateAndAdjustIterator; use std::mem::replace; use std::cmp::Ordering; @@ -616,9 +616,8 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, match pat.node { // Foo(a, b, c) PatKind::TupleStruct(_, ref pat_fields, ddpos) => { - let adjust = pat_adjust_pos(v.fields.len(), pat_fields.len(), ddpos); - for (i, field) in pat_fields.iter().enumerate() { - maybe_do_stability_check(tcx, v.fields[adjust(i)].did, field.span, cb) + for (i, field) in pat_fields.iter().enumerate_and_adjust(v.fields.len(), ddpos) { + maybe_do_stability_check(tcx, v.fields[i].did, field.span, cb) } } // Foo { a, b, c } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index f98734f21ad..16b61534ee9 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -924,7 +924,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], Def::Variant(..) | Def::Struct(..) => { match ddpos { Some(ddpos) => { - let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>; + let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect(); pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); pats.extend(args[ddpos..].iter().map(|p| &**p)); Some(pats) @@ -958,7 +958,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } PatKind::Tuple(ref args, Some(ddpos)) => { - let mut pats = args[..ddpos].iter().map(|p| &**p).collect(): Vec<_>; + let mut pats: Vec<_> = args[..ddpos].iter().map(|p| &**p).collect(); pats.extend(repeat(DUMMY_WILD_PAT).take(arity - args.len())); pats.extend(args[ddpos..].iter().map(|p| &**p)); Some(pats) diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 2c796690df4..9ab6a437a5a 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -31,7 +31,6 @@ #![feature(question_mark)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(type_ascription)] #[macro_use] extern crate syntax; #[macro_use] extern crate log; diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 494d8a5c035..b9ba860e8d0 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -13,7 +13,7 @@ use hair::cx::Cx; use rustc_data_structures::fnv::FnvHashMap; use rustc_const_eval as const_eval; use rustc::hir::def::Def; -use rustc::hir::pat_util::{pat_adjust_pos, pat_is_resolved_const, pat_is_binding}; +use rustc::hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const, pat_is_binding}; use rustc::ty::{self, Ty}; use rustc::mir::repr::*; use rustc::hir::{self, PatKind}; @@ -151,12 +151,11 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::Tuple(ref subpatterns, ddpos) => { match self.cx.tcx.node_id_to_type(pat.id).sty { ty::TyTuple(ref tys) => { - let adjust = pat_adjust_pos(tys.len(), subpatterns.len(), ddpos); let subpatterns = subpatterns.iter() - .enumerate() + .enumerate_and_adjust(tys.len(), ddpos) .map(|(i, subpattern)| FieldPattern { - field: Field::new(adjust(i)), + field: Field::new(i), pattern: self.to_pattern(subpattern), }) .collect(); @@ -224,12 +223,11 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); let variant_def = adt_def.variant_of_def(def); - let adjust = pat_adjust_pos(variant_def.fields.len(), subpatterns.len(), ddpos); let subpatterns = subpatterns.iter() - .enumerate() + .enumerate_and_adjust(variant_def.fields.len(), ddpos) .map(|(i, field)| FieldPattern { - field: Field::new(adjust(i)), + field: Field::new(i), pattern: self.to_pattern(field), }) .collect(); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 953bcf457b8..c90d152e3c3 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -31,7 +31,7 @@ use std::mem::replace; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::{self, Visitor}; -use rustc::hir::pat_util::pat_adjust_pos; +use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::dep_graph::DepNode; use rustc::lint; use rustc::hir::def::{self, Def}; @@ -491,14 +491,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { PatKind::TupleStruct(_, ref fields, ddpos) => { match self.tcx.pat_ty(pattern).sty { ty::TyStruct(def, _) => { - let adjust = pat_adjust_pos(def.struct_variant().fields.len(), - fields.len(), ddpos); - for (i, field) in fields.iter().enumerate() { + let expected_len = def.struct_variant().fields.len(); + for (i, field) in fields.iter().enumerate_and_adjust(expected_len, ddpos) { if let PatKind::Wild = field.node { continue } - self.check_field(field.span, def, - &def.struct_variant().fields[adjust(i)]); + self.check_field(field.span, def, &def.struct_variant().fields[i]); } } ty::TyEnum(..) => { diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 9b168301f73..4b22e410f4c 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -1843,12 +1843,12 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, &repr, Disr::from(vinfo.disr_val), val); - let adjust = pat_adjust_pos(vinfo.fields.len(), sub_pats.len(), ddpos); - for (i, subpat) in sub_pats.iter().enumerate() { + for (i, subpat) in sub_pats.iter() + .enumerate_and_adjust(vinfo.fields.len(), ddpos) { bcx = bind_irrefutable_pat( bcx, subpat, - MatchInput::from_val(args.vals[adjust(i)]), + MatchInput::from_val(args.vals[i]), cleanup_scope); } } @@ -1862,12 +1862,10 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } }; - let adjust = pat_adjust_pos(expected_len, sub_pats.len(), ddpos); let repr = adt::represent_node(bcx, pat.id); let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in sub_pats.iter().enumerate() { - let fldptr = adt::trans_field_ptr(bcx, &repr, - val, Disr(0), adjust(i)); + for (i, elem) in sub_pats.iter().enumerate_and_adjust(expected_len, ddpos) { + let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i); bcx = bind_irrefutable_pat( bcx, &elem, @@ -1923,11 +1921,10 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, PatKind::Tuple(ref elems, ddpos) => { match tcx.node_id_to_type(pat.id).sty { ty::TyTuple(ref tys) => { - let adjust = pat_adjust_pos(tys.len(), elems.len(), ddpos); let repr = adt::represent_node(bcx, pat.id); let val = adt::MaybeSizedValue::sized(val.val); - for (i, elem) in elems.iter().enumerate() { - let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), adjust(i)); + for (i, elem) in elems.iter().enumerate_and_adjust(tys.len(), ddpos) { + let fldptr = adt::trans_field_ptr(bcx, &repr, val, Disr(0), i); bcx = bind_irrefutable_pat( bcx, &elem, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ce4ac4e815c..693703c7236 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,7 @@ use hir::def::{self, Def}; use rustc::infer::{self, InferOk, TypeOrigin}; use hir::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; -use hir::pat_util::{pat_adjust_pos, pat_is_resolved_const}; +use hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation}; @@ -271,13 +271,12 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { } let max_len = cmp::max(expected_len, elements.len()); - let element_tys = (0 .. max_len).map(|_| self.next_ty_var()).collect(): Vec<_>; + let element_tys: Vec<_> = (0 .. max_len).map(|_| self.next_ty_var()).collect(); let pat_ty = tcx.mk_tup(element_tys.clone()); self.write_ty(pat.id, pat_ty); self.demand_eqtype(pat.span, expected, pat_ty); - let adjust = pat_adjust_pos(expected_len, elements.len(), ddpos); - for i in 0 .. elements.len() { - self.check_pat(&elements[i], &element_tys[adjust(i)]); + for (i, elem) in elements.iter().enumerate_and_adjust(expected_len, ddpos) { + self.check_pat(elem, &element_tys[i]); } } PatKind::Box(ref inner) => { @@ -734,12 +733,10 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { _ => {} } - let adjust = pat_adjust_pos(variant.fields.len(), subpats.len(), ddpos); if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { - for (i, subpat) in subpats.iter().enumerate() { - let field_ty = self.field_ty(subpat.span, - &variant.fields[adjust(i)], expected_substs); + for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { + let field_ty = self.field_ty(subpat.span, &variant.fields[i], expected_substs); self.check_pat(&subpat, field_ty); } } else { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 282b7582393..0b23951db36 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,12 +77,11 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(iter_arith)] -#![feature(question_mark)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] -#![feature(type_ascription)] +#![feature(question_mark)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; From 0ca9bf394006fe635a4a76ca6fa78a70633666f0 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 6 Mar 2016 15:54:44 +0300 Subject: [PATCH 9/9] Fix overflow in type checking of tuple patterns --- src/librustc_typeck/check/_match.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 693703c7236..9030a6f222b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -275,7 +275,7 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { let pat_ty = tcx.mk_tup(element_tys.clone()); self.write_ty(pat.id, pat_ty); self.demand_eqtype(pat.span, expected, pat_ty); - for (i, elem) in elements.iter().enumerate_and_adjust(expected_len, ddpos) { + for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, &element_tys[i]); } }