From ba92b01e9a20964e60dcfd86f8fcba7eafdb65f3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 9 Nov 2016 02:35:36 +0000 Subject: [PATCH 1/9] question_mark was stabilized in 1.13 --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c5fae9f3236d7..97eba5e875a34 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -355,7 +355,7 @@ declare_features! ( // Allows `#[deprecated]` attribute (accepted, deprecated, "1.9.0", Some(29935)), // `expr?` - (accepted, question_mark, "1.14.0", Some(31436)), + (accepted, question_mark, "1.13.0", Some(31436)), // Allows `..` in tuple (struct) patterns (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)), ); From 1e9aad752beb789df4f2232adf6b9a24efbdac8d Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 9 Nov 2016 07:23:57 +0100 Subject: [PATCH 2/9] Document the question mark operator --- src/doc/book/syntax-index.md | 2 ++ src/doc/reference.md | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md index 1e05b01d30d46..28403711cd701 100644 --- a/src/doc/book/syntax-index.md +++ b/src/doc/book/syntax-index.md @@ -94,6 +94,7 @@ * `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical or. * `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]). +* `?` (`expr?`): Error propagation. Returns early when `Err(_)` is encountered, unwraps otherwise. Similar to the [`try!` macro]. ## Other Syntax @@ -210,6 +211,7 @@ [Functions]: functions.html [Generics]: generics.html [Iterators]: iterators.html +[`try!` macro]: error-handling.html#the-try-macro [Lifetimes]: lifetimes.html [Loops (`for`)]: loops.html#for [Loops (`loop`)]: loops.html#loop diff --git a/src/doc/reference.md b/src/doc/reference.md index 4838ecd2d42e6..eb3a6c0de6d42 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2860,8 +2860,8 @@ assert_eq!(x, y); ### Unary operator expressions -Rust defines the following unary operators. They are all written as prefix operators, -before the expression they apply to. +Rust defines the following unary operators. With the exception of `?`, they are +all written as prefix operators, before the expression they apply to. * `-` : Negation. Signed integer types and floating-point types support negation. It @@ -2890,6 +2890,10 @@ before the expression they apply to. If the `&` or `&mut` operators are applied to an rvalue, a temporary value is created; the lifetime of this temporary value is defined by [syntactic rules](#temporary-lifetimes). +* `?` + : Propagating errors if applied to `Err(_)` and unwrapping if + applied to `Ok(_)`. Only works on the `Result` type, + and written in postfix notation. ### Binary operator expressions From cc2c812701c9bc1ac4a4165f37bacbe69c80a334 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 9 Nov 2016 09:12:38 -0800 Subject: [PATCH 3/9] rustc_llvm: Require 3.9 for --link-static Apparently stock Ubuntu 16.04 includes LLVM 3.8 which doesn't have this flag. --- src/librustc_llvm/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 4d3a4d09dcea0..8656bb8bf0036 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -136,7 +136,7 @@ fn main() { let mut parts = version_output.split('.'); if let (Some(major), Some(minor)) = (parts.next().and_then(|s| s.parse::().ok()), parts.next().and_then(|s| s.parse::().ok())) { - if major > 3 || (major == 3 && minor >= 8) { + if major > 3 || (major == 3 && minor >= 9) { cmd.arg("--link-static"); } } From 49772fbf5dc1137a031086999b20ab7b961f3655 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 26 Oct 2016 02:17:29 +0300 Subject: [PATCH 4/9] syntax: don't fake a block around closures' bodies during parsing. --- src/librustc/lint/context.rs | 8 +-- src/librustc/lint/mod.rs | 4 +- src/librustc_passes/hir_stats.rs | 3 +- src/librustc_resolve/lib.rs | 69 ++++++++++---------- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/libsyntax/ast.rs | 4 +- src/libsyntax/ext/build.rs | 45 +++++-------- src/libsyntax/feature_gate.rs | 9 ++- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 19 +----- src/libsyntax/print/pprust.rs | 22 +------ src/libsyntax/util/node_count.rs | 4 +- src/libsyntax/visit.rs | 53 ++++++++------- src/libsyntax_ext/deriving/decodable.rs | 6 +- src/libsyntax_ext/deriving/encodable.rs | 6 +- src/test/parse-fail/closure-return-syntax.rs | 3 +- 16 files changed, 106 insertions(+), 153 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 9cc2337e3dd1e..6f56f6858ce40 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -994,10 +994,10 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { } fn visit_fn(&mut self, fk: ast_visit::FnKind, decl: &ast::FnDecl, - body: &ast::Block, span: Span, id: ast::NodeId) { - run_lints!(self, check_fn, early_passes, fk, decl, body, span, id); - ast_visit::walk_fn(self, fk, decl, body, span); - run_lints!(self, check_fn_post, early_passes, fk, decl, body, span, id); + span: Span, id: ast::NodeId) { + run_lints!(self, check_fn, early_passes, fk, decl, span, id); + ast_visit::walk_fn(self, fk, decl, span); + run_lints!(self, check_fn_post, early_passes, fk, decl, span, id); } fn visit_variant_data(&mut self, diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 34e0ce7da1461..5fba14768bf28 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -200,9 +200,9 @@ pub trait EarlyLintPass: LintPass { fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { } fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { } fn check_fn(&mut self, _: &EarlyContext, - _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { } + _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { } fn check_fn_post(&mut self, _: &EarlyContext, - _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { } + _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { } fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } fn check_trait_item_post(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 84cf85e2fc4e6..f8994de54a137 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -295,11 +295,10 @@ impl<'v> ast_visit::Visitor for StatCollector<'v> { fn visit_fn(&mut self, fk: ast_visit::FnKind, fd: &ast::FnDecl, - b: &ast::Block, s: Span, _: NodeId) { self.record("FnDecl", Id::None, fd); - ast_visit::walk_fn(self, fk, fd, b, s) + ast_visit::walk_fn(self, fk, fd, s) } fn visit_trait_item(&mut self, ti: &ast::TraitItem) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0c7c1a55a6182..664efc27fbb53 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -596,7 +596,6 @@ impl<'a> Visitor for Resolver<'a> { fn visit_fn(&mut self, function_kind: FnKind, declaration: &FnDecl, - block: &Block, _: Span, node_id: NodeId) { let rib_kind = match function_kind { @@ -604,13 +603,45 @@ impl<'a> Visitor for Resolver<'a> { self.visit_generics(generics); ItemRibKind } - FnKind::Method(_, sig, _) => { + FnKind::Method(_, sig, _, _) => { self.visit_generics(&sig.generics); MethodRibKind(!sig.decl.has_self()) } - FnKind::Closure => ClosureRibKind(node_id), + FnKind::Closure(_) => ClosureRibKind(node_id), }; - self.resolve_function(rib_kind, declaration, block); + + // Create a value rib for the function. + self.value_ribs.push(Rib::new(rib_kind)); + + // Create a label rib for the function. + self.label_ribs.push(Rib::new(rib_kind)); + + // Add each argument to the rib. + let mut bindings_list = FxHashMap(); + for argument in &declaration.inputs { + self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); + + self.visit_ty(&argument.ty); + + debug!("(resolving function) recorded argument"); + } + visit::walk_fn_ret_ty(self, &declaration.output); + + // Resolve the function body. + match function_kind { + FnKind::ItemFn(.., body) | + FnKind::Method(.., body) => { + self.visit_block(body); + } + FnKind::Closure(body) => { + self.visit_expr(body); + } + }; + + debug!("(resolving function) leaving function"); + + self.label_ribs.pop(); + self.value_ribs.pop(); } } @@ -1856,36 +1887,6 @@ impl<'a> Resolver<'a> { self.value_ribs.pop(); } - fn resolve_function(&mut self, - rib_kind: RibKind<'a>, - declaration: &FnDecl, - block: &Block) { - // Create a value rib for the function. - self.value_ribs.push(Rib::new(rib_kind)); - - // Create a label rib for the function. - self.label_ribs.push(Rib::new(rib_kind)); - - // Add each argument to the rib. - let mut bindings_list = FxHashMap(); - for argument in &declaration.inputs { - self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); - - self.visit_ty(&argument.ty); - - debug!("(resolving function) recorded argument"); - } - visit::walk_fn_ret_ty(self, &declaration.output); - - // Resolve the function body. - self.visit_block(block); - - debug!("(resolving function) leaving function"); - - self.label_ribs.pop(); - self.value_ribs.pop(); - } - fn resolve_trait_reference(&mut self, id: NodeId, trait_path: &Path, diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index db4788c3ceadb..7f7ef6d3ab7af 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1414,7 +1414,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } // walk the body - self.nest(ex.id, |v| v.visit_block(&body)); + self.nest(ex.id, |v| v.visit_expr(body)); } ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) | ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9751ad6aa43c3..f5cd089e923d7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1017,10 +1017,10 @@ pub enum ExprKind { Loop(P, Option), /// A `match` block. Match(P, Vec), - /// A closure (for example, `move |a, b, c| {a + b + c}`) + /// A closure (for example, `move |a, b, c| a + b + c`) /// /// The final span is the span of the argument block `|...|` - Closure(CaptureBy, P, P, Span), + Closure(CaptureBy, P, P, Span), /// A block (`{ ... }`) Block(P), diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 37bd83be7b4d4..c3e28cbb006a0 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -198,17 +198,13 @@ pub trait AstBuilder { fn lambda_fn_decl(&self, span: Span, fn_decl: P, - blk: P, + body: P, fn_decl_span: Span) -> P; - fn lambda(&self, span: Span, ids: Vec, blk: P) -> P; - fn lambda0(&self, span: Span, blk: P) -> P; - fn lambda1(&self, span: Span, blk: P, ident: ast::Ident) -> P; - - fn lambda_expr(&self, span: Span, ids: Vec , blk: P) -> P; - fn lambda_expr_0(&self, span: Span, expr: P) -> P; - fn lambda_expr_1(&self, span: Span, expr: P, ident: ast::Ident) -> P; + fn lambda(&self, span: Span, ids: Vec, body: P) -> P; + fn lambda0(&self, span: Span, body: P) -> P; + fn lambda1(&self, span: Span, body: P, ident: ast::Ident) -> P; fn lambda_stmts(&self, span: Span, ids: Vec, blk: Vec) -> P; @@ -940,19 +936,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn lambda_fn_decl(&self, span: Span, fn_decl: P, - blk: P, + body: P, fn_decl_span: Span) // span of the `|...|` part -> P { self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, - blk, + body, fn_decl_span)) } fn lambda(&self, span: Span, ids: Vec, - blk: P) + body: P) -> P { let fn_decl = self.fn_decl( ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(), @@ -962,26 +958,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> { // part of the lambda, but it probably (maybe?) corresponds to // the entire lambda body. Probably we should extend the API // here, but that's not entirely clear. - self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, blk, span)) - } - - fn lambda0(&self, span: Span, blk: P) -> P { - self.lambda(span, Vec::new(), blk) + self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, body, span)) } - fn lambda1(&self, span: Span, blk: P, ident: ast::Ident) -> P { - self.lambda(span, vec![ident], blk) + fn lambda0(&self, span: Span, body: P) -> P { + self.lambda(span, Vec::new(), body) } - fn lambda_expr(&self, span: Span, ids: Vec, - expr: P) -> P { - self.lambda(span, ids, self.block_expr(expr)) - } - fn lambda_expr_0(&self, span: Span, expr: P) -> P { - self.lambda0(span, self.block_expr(expr)) - } - fn lambda_expr_1(&self, span: Span, expr: P, ident: ast::Ident) -> P { - self.lambda1(span, self.block_expr(expr), ident) + fn lambda1(&self, span: Span, body: P, ident: ast::Ident) -> P { + self.lambda(span, vec![ident], body) } fn lambda_stmts(&self, @@ -989,14 +974,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ids: Vec, stmts: Vec) -> P { - self.lambda(span, ids, self.block(span, stmts)) + self.lambda(span, ids, self.expr_block(self.block(span, stmts))) } fn lambda_stmts_0(&self, span: Span, stmts: Vec) -> P { - self.lambda0(span, self.block(span, stmts)) + self.lambda0(span, self.expr_block(self.block(span, stmts))) } fn lambda_stmts_1(&self, span: Span, stmts: Vec, ident: ast::Ident) -> P { - self.lambda1(span, self.block(span, stmts), ident) + self.lambda1(span, self.expr_block(self.block(span, stmts)), ident) } fn arg(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Arg { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a6493872338fa..f51822ec2fe80 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1228,12 +1228,11 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_fn(&mut self, fn_kind: FnKind, fn_decl: &ast::FnDecl, - block: &ast::Block, span: Span, _node_id: NodeId) { // check for const fn declarations match fn_kind { - FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => { + FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => { gate_feature_post!(&self, const_fn, span, "const fn is unstable"); } _ => { @@ -1245,13 +1244,13 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } match fn_kind { - FnKind::ItemFn(_, _, _, _, abi, _) | - FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => { + FnKind::ItemFn(_, _, _, _, abi, _, _) | + FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => { self.check_abi(abi, span); } _ => {} } - visit::walk_fn(self, fn_kind, fn_decl, block, span); + visit::walk_fn(self, fn_kind, fn_decl, span); } fn visit_trait_item(&mut self, ti: &ast::TraitItem) { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1deeaf422316c..2e62f23578d81 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1201,7 +1201,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Closure(capture_clause, decl, body, span) => { ExprKind::Closure(capture_clause, folder.fold_fn_decl(decl), - folder.fold_block(body), + folder.fold_expr(body), folder.new_span(span)) } ExprKind::Block(blk) => ExprKind::Block(folder.fold_block(blk)), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b670a7384739b..7d15334ff9f4e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3162,25 +3162,12 @@ impl<'a> Parser<'a> { let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_span.hi; let body = match decl.output { - FunctionRetTy::Default(_) => { - // If no explicit return type is given, parse any - // expr and wrap it up in a dummy block: - let body_expr = self.parse_expr()?; - P(ast::Block { - id: ast::DUMMY_NODE_ID, - span: body_expr.span, - stmts: vec![Stmt { - span: body_expr.span, - node: StmtKind::Expr(body_expr), - id: ast::DUMMY_NODE_ID, - }], - rules: BlockCheckMode::Default, - }) - } + FunctionRetTy::Default(_) => self.parse_expr()?, _ => { // If an explicit return type is given, require a // block to appear (RFC 968). - self.parse_block()? + let body_lo = self.span.lo; + self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())? } }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 7352792a8a252..203c19285ac2c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2128,26 +2128,8 @@ impl<'a> State<'a> { try!(self.print_fn_block_args(&decl)); try!(space(&mut self.s)); - - let default_return = match decl.output { - ast::FunctionRetTy::Default(..) => true, - _ => false - }; - - match body.stmts.last().map(|stmt| &stmt.node) { - Some(&ast::StmtKind::Expr(ref i_expr)) if default_return && - body.stmts.len() == 1 => { - // we extract the block, so as not to create another set of boxes - if let ast::ExprKind::Block(ref blk) = i_expr.node { - try!(self.print_block_unclosed_with_attrs(&blk, &i_expr.attrs)); - } else { - // this is a bare expression - try!(self.print_expr(&i_expr)); - try!(self.end()); // need to close a box - } - } - _ => try!(self.print_block_unclosed(&body)), - } + try!(self.print_expr(body)); + try!(self.end()); // need to close a box // a box will be closed by print_expr, but we didn't want an overall // wrapper so we closed the corresponding opening. so create an diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index 14244bbdddf28..a1f07381db705 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -75,9 +75,9 @@ impl Visitor for NodeCounter { self.count += 1; walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) { + fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, s: Span, _: NodeId) { self.count += 1; - walk_fn(self, fk, fd, b, s) + walk_fn(self, fk, fd, s) } fn visit_trait_item(&mut self, ti: &TraitItem) { self.count += 1; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 7fb3e5c6bee1d..7c1ff617ab64d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -31,13 +31,13 @@ use codemap::Spanned; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - ItemFn(Ident, &'a Generics, Unsafety, Spanned, Abi, &'a Visibility), + ItemFn(Ident, &'a Generics, Unsafety, Spanned, Abi, &'a Visibility, &'a Block), /// fn foo(&self) - Method(Ident, &'a MethodSig, Option<&'a Visibility>), + Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block), - /// |x, y| {} - Closure, + /// |x, y| body + Closure(&'a Expr), } /// Each method of the Visitor trait is a hook to be potentially @@ -68,8 +68,8 @@ pub trait Visitor: Sized { fn visit_expr_post(&mut self, _ex: &Expr) { } fn visit_ty(&mut self, t: &Ty) { walk_ty(self, t) } fn visit_generics(&mut self, g: &Generics) { walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) { - walk_fn(self, fk, fd, b, s) + fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, s: Span, _: NodeId) { + walk_fn(self, fk, fd, s) } fn visit_trait_item(&mut self, ti: &TraitItem) { walk_trait_item(self, ti) } fn visit_impl_item(&mut self, ii: &ImplItem) { walk_impl_item(self, ii) } @@ -246,9 +246,8 @@ pub fn walk_item(visitor: &mut V, item: &Item) { } ItemKind::Fn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { visitor.visit_fn(FnKind::ItemFn(item.ident, generics, unsafety, - constness, abi, &item.vis), + constness, abi, &item.vis, body), declaration, - body, item.span, item.id) } @@ -519,26 +518,27 @@ pub fn walk_fn_decl(visitor: &mut V, function_declaration: &FnDecl) visitor.visit_fn_ret_ty(&function_declaration.output) } -pub fn walk_fn_kind(visitor: &mut V, function_kind: FnKind) { - match function_kind { - FnKind::ItemFn(_, generics, _, _, _, _) => { +pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, _span: Span) + where V: Visitor, +{ + match kind { + FnKind::ItemFn(_, generics, _, _, _, _, body) => { visitor.visit_generics(generics); + walk_fn_decl(visitor, declaration); + visitor.visit_block(body); } - FnKind::Method(_, ref sig, _) => { + FnKind::Method(_, ref sig, _, body) => { visitor.visit_generics(&sig.generics); + walk_fn_decl(visitor, declaration); + visitor.visit_block(body); + } + FnKind::Closure(body) => { + walk_fn_decl(visitor, declaration); + visitor.visit_expr(body); } - FnKind::Closure => {} } } -pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, body: &Block, _span: Span) - where V: Visitor, -{ - walk_fn_kind(visitor, kind); - walk_fn_decl(visitor, declaration); - visitor.visit_block(body) -} - pub fn walk_trait_item(visitor: &mut V, trait_item: &TraitItem) { visitor.visit_ident(trait_item.span, trait_item.ident); walk_list!(visitor, visit_attribute, &trait_item.attrs); @@ -552,8 +552,8 @@ pub fn walk_trait_item(visitor: &mut V, trait_item: &TraitItem) { walk_fn_decl(visitor, &sig.decl); } TraitItemKind::Method(ref sig, Some(ref body)) => { - visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None), &sig.decl, - body, trait_item.span, trait_item.id); + visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None, body), + &sig.decl, trait_item.span, trait_item.id); } TraitItemKind::Type(ref bounds, ref default) => { walk_list!(visitor, visit_ty_param_bound, bounds); @@ -575,8 +575,8 @@ pub fn walk_impl_item(visitor: &mut V, impl_item: &ImplItem) { visitor.visit_expr(expr); } ImplItemKind::Method(ref sig, ref body) => { - visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis)), &sig.decl, - body, impl_item.span, impl_item.id); + visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), body), + &sig.decl, impl_item.span, impl_item.id); } ImplItemKind::Type(ref ty) => { visitor.visit_ty(ty); @@ -711,9 +711,8 @@ pub fn walk_expr(visitor: &mut V, expression: &Expr) { walk_list!(visitor, visit_arm, arms); } ExprKind::Closure(_, ref function_declaration, ref body, _decl_span) => { - visitor.visit_fn(FnKind::Closure, + visitor.visit_fn(FnKind::Closure(body), function_declaration, - body, expression.span, expression.id) } diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 10db56d46f6df..dc1f7b4e6201e 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -133,7 +133,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, cx.ident_of("read_struct"), vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), cx.expr_usize(trait_span, nfields), - cx.lambda_expr_1(trait_span, result, blkarg)]) + cx.lambda1(trait_span, result, blkarg)]) } StaticEnum(_, ref fields) => { let variant = cx.ident_of("i"); @@ -165,7 +165,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, let result = cx.expr_ok(trait_span, cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms)); - let lambda = cx.lambda_expr(trait_span, vec![blkarg, variant], result); + let lambda = cx.lambda(trait_span, vec![blkarg, variant], result); let variant_vec = cx.expr_vec(trait_span, variants); let variant_vec = cx.expr_addr_of(trait_span, variant_vec); let result = cx.expr_method_call(trait_span, @@ -176,7 +176,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, decoder, cx.ident_of("read_enum"), vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.lambda_expr_1(trait_span, result, blkarg)]) + cx.lambda1(trait_span, result, blkarg)]) } _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"), }; diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 640296d7f06fc..ebbddc6e48084 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -197,7 +197,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, }; let self_ref = cx.expr_addr_of(span, self_.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda_expr_1(span, enc, blkarg); + let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_method_call(span, blkencoder.clone(), emit_struct_field, @@ -246,7 +246,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, let self_ref = cx.expr_addr_of(span, self_.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda_expr_1(span, enc, blkarg); + let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_method_call(span, blkencoder.clone(), emit_variant_arg, @@ -273,7 +273,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, cx.expr_usize(trait_span, idx), cx.expr_usize(trait_span, fields.len()), blk]); - let blk = cx.lambda_expr_1(trait_span, call, blkarg); + let blk = cx.lambda1(trait_span, call, blkarg); let ret = cx.expr_method_call(trait_span, encoder, cx.ident_of("emit_enum"), diff --git a/src/test/parse-fail/closure-return-syntax.rs b/src/test/parse-fail/closure-return-syntax.rs index da6245597f8f4..1da6735918012 100644 --- a/src/test/parse-fail/closure-return-syntax.rs +++ b/src/test/parse-fail/closure-return-syntax.rs @@ -12,5 +12,6 @@ // unless it uses braces. fn main() { - let x = || -> i32 22; //~ ERROR expected `{`, found `22` + let x = || -> i32 22; + //~^ ERROR expected one of `!`, `(`, `::`, `<`, or `{`, found `22` } From ff0830d74985246c2e2bbd28e7d8c0ef072e2458 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 26 Oct 2016 02:27:14 +0300 Subject: [PATCH 5/9] rustc: use an Expr instead of a Block for function bodies. --- src/librustc/cfg/construct.rs | 12 +- src/librustc/cfg/mod.rs | 4 +- src/librustc/diagnostics.rs | 114 ------------------ src/librustc/hir/intravisit.rs | 8 +- src/librustc/hir/lowering.rs | 13 +- src/librustc/hir/map/blocks.rs | 43 +++---- src/librustc/hir/map/collector.rs | 2 +- src/librustc/hir/mod.rs | 8 +- src/librustc/hir/print.rs | 34 ++---- src/librustc/lint/context.rs | 2 +- src/librustc/lint/mod.rs | 4 +- src/librustc/middle/dataflow.rs | 8 +- src/librustc/middle/dead.rs | 8 +- src/librustc/middle/effect.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 6 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/liveness.rs | 93 ++++---------- src/librustc/middle/reachable.rs | 12 +- src/librustc/middle/region.rs | 13 +- src/librustc/middle/resolve_lifetime.rs | 10 +- src/librustc_borrowck/borrowck/check_loans.rs | 2 +- .../borrowck/gather_loans/mod.rs | 2 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 12 +- src/librustc_borrowck/borrowck/move_data.rs | 2 +- src/librustc_const_eval/check_match.rs | 4 +- src/librustc_const_eval/eval.rs | 3 +- src/librustc_driver/pretty.rs | 11 +- src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 4 +- src/librustc_lint/unused.rs | 2 +- src/librustc_mir/build/mod.rs | 22 ++-- src/librustc_mir/mir_map.rs | 2 +- src/librustc_passes/consts.rs | 4 +- src/librustc_passes/hir_stats.rs | 2 +- src/librustc_passes/loops.rs | 2 +- src/librustc_passes/rvalues.rs | 2 +- src/librustc_typeck/check/closure.rs | 4 +- src/librustc_typeck/check/mod.rs | 20 ++- src/librustc_typeck/check/regionck.rs | 14 +-- src/librustc_typeck/check/upvar.rs | 19 +-- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/check/writeback.rs | 4 +- 43 files changed, 169 insertions(+), 372 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index a2fc6e044e74c..22c7d14be29d2 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -33,16 +33,16 @@ struct LoopScope { } pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - blk: &hir::Block) -> CFG { + body: &hir::Expr) -> CFG { let mut graph = graph::Graph::new(); let entry = graph.add_node(CFGNodeData::Entry); // `fn_exit` is target of return exprs, which lies somewhere - // outside input `blk`. (Distinguishing `fn_exit` and `block_exit` + // outside input `body`. (Distinguishing `fn_exit` and `body_exit` // also resolves chicken-and-egg problem that arises if you try to - // have return exprs jump to `block_exit` during construction.) + // have return exprs jump to `body_exit` during construction.) let fn_exit = graph.add_node(CFGNodeData::Exit); - let block_exit; + let body_exit; let mut cfg_builder = CFGBuilder { graph: graph, @@ -50,8 +50,8 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: tcx, loop_scopes: Vec::new() }; - block_exit = cfg_builder.block(blk, entry); - cfg_builder.add_contained_edge(block_exit, fn_exit); + body_exit = cfg_builder.expr(body, entry); + cfg_builder.add_contained_edge(body_exit, fn_exit); let CFGBuilder {graph, ..} = cfg_builder; CFG {graph: graph, entry: entry, diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index d06f51073df06..43434b884c8d4 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -59,8 +59,8 @@ pub type CFGEdge = graph::Edge; impl CFG { pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - blk: &hir::Block) -> CFG { - construct::construct(tcx, blk) + body: &hir::Expr) -> CFG { + construct::construct(tcx, body) } pub fn node_is_reachable(&self, id: ast::NodeId) -> bool { diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 465a09505e4a7..ec09877ae121c 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -672,120 +672,6 @@ extern "C" { ``` "##, -E0269: r##" -A returned value was expected but not all control paths return one. - -Erroneous code example: - -```compile_fail,E0269 -fn abracada_FAIL() -> String { - "this won't work".to_string(); - // error: not all control paths return a value -} -``` - -In the previous code, the function is supposed to return a `String`, however, -the code returns nothing (because of the ';'). Another erroneous code would be: - -```compile_fail -fn abracada_FAIL(b: bool) -> u32 { - if b { - 0 - } else { - "a" // It fails because an `u32` was expected and something else is - // returned. - } -} -``` - -It is advisable to find out what the unhandled cases are and check for them, -returning an appropriate value or panicking if necessary. Check if you need -to remove a semicolon from the last expression, like in the first erroneous -code example. -"##, - -E0270: r##" -Rust lets you define functions which are known to never return, i.e. are -'diverging', by marking its return type as `!`. - -For example, the following functions never return: - -```no_run -fn foo() -> ! { - loop {} -} - -fn bar() -> ! { - foo() // foo() is diverging, so this will diverge too -} - -fn baz() -> ! { - panic!(); // this macro internally expands to a call to a diverging function -} -``` - -Such functions can be used in a place where a value is expected without -returning a value of that type, for instance: - -```no_run -fn foo() -> ! { - loop {} -} - -let x = 3; - -let y = match x { - 1 => 1, - 2 => 4, - _ => foo() // diverging function called here -}; - -println!("{}", y) -``` - -If the third arm of the match block is reached, since `foo()` doesn't ever -return control to the match block, it is fine to use it in a place where an -integer was expected. The `match` block will never finish executing, and any -point where `y` (like the print statement) is needed will not be reached. - -However, if we had a diverging function that actually does finish execution: - -```ignore -fn foo() -> ! { - loop {break;} -} -``` - -Then we would have an unknown value for `y` in the following code: - -```no_run -fn foo() -> ! { - loop {} -} - -let x = 3; - -let y = match x { - 1 => 1, - 2 => 4, - _ => foo() -}; - -println!("{}", y); -``` - -In the previous example, the print statement was never reached when the -wildcard match arm was hit, so we were okay with `foo()` not returning an -integer that we could set to `y`. But in this example, `foo()` actually does -return control, so the print statement will be executed with an uninitialized -value. - -Obviously we cannot have functions which are allowed to be used in such -positions and yet can return control. So, if you are defining a function that -returns `!`, make sure that there is no way for it to actually finish -executing. -"##, - E0271: r##" This is because of a type mismatch between the associated type of some trait (e.g. `T::Bar`, where `T` implements `trait Quux { type Bar; }`) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index b1771f52da2c6..9932e5fe68623 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -138,7 +138,7 @@ pub trait Visitor<'v> : Sized { fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) { walk_where_predicate(self, predicate) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) { + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Expr, s: Span, id: NodeId) { walk_fn(self, fk, fd, b, s, id) } fn visit_trait_item(&mut self, ti: &'v TraitItem) { @@ -635,13 +635,13 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<' pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>, function_declaration: &'v FnDecl, - function_body: &'v Block, + function_body: &'v Expr, _span: Span, id: NodeId) { visitor.visit_id(id); walk_fn_decl(visitor, function_declaration); walk_fn_kind(visitor, function_kind); - visitor.visit_block(function_body) + visitor.visit_expr(function_body) } pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { @@ -925,7 +925,7 @@ impl<'v> Visitor<'v> for IdRangeComputingVisitor { /// Computes the id range for a single fn body, ignoring nested items. pub fn compute_id_range_for_fn_body(fk: FnKind, decl: &FnDecl, - body: &Block, + body: &Expr, sp: Span, id: NodeId) -> IdRange { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e1fec898e41e4..b985298e47cc2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -595,12 +595,13 @@ impl<'a> LoweringContext<'a> { hir::ItemConst(self.lower_ty(t), self.lower_expr(e)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { + let body = self.lower_block(body); hir::ItemFn(self.lower_fn_decl(decl), self.lower_unsafety(unsafety), self.lower_constness(constness), abi, self.lower_generics(generics), - self.lower_block(body)) + self.expr_block(body, ThinVec::new())) } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), @@ -665,7 +666,10 @@ impl<'a> LoweringContext<'a> { } TraitItemKind::Method(ref sig, ref body) => { hir::MethodTraitItem(this.lower_method_sig(sig), - body.as_ref().map(|x| this.lower_block(x))) + body.as_ref().map(|x| { + let body = this.lower_block(x); + this.expr_block(body, ThinVec::new()) + })) } TraitItemKind::Type(ref bounds, ref default) => { hir::TypeTraitItem(this.lower_bounds(bounds), @@ -691,8 +695,9 @@ impl<'a> LoweringContext<'a> { hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr)) } ImplItemKind::Method(ref sig, ref body) => { + let body = this.lower_block(body); hir::ImplItemKind::Method(this.lower_method_sig(sig), - this.lower_block(body)) + this.expr_block(body, ThinVec::new())) } ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)), ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), @@ -1110,7 +1115,7 @@ impl<'a> LoweringContext<'a> { self.with_parent_def(e.id, |this| { hir::ExprClosure(this.lower_capture_clause(capture_clause), this.lower_fn_decl(decl), - this.lower_block(body), + this.lower_expr(body), fn_decl_span) }) } diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 4487234885692..325a90ea91e0e 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -21,11 +21,9 @@ //! nested within a uniquely determined `FnLike`), and users can ask //! for the `Code` associated with a particular NodeId. -pub use self::Code::*; - use hir as ast; use hir::map::{self, Node}; -use hir::{Block, FnDecl}; +use hir::{Expr, FnDecl}; use hir::intravisit::FnKind; use syntax::abi; use syntax::ast::{Attribute, Name, NodeId}; @@ -50,7 +48,7 @@ pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; } /// Components shared by fn-like things (fn items, methods, closures). pub struct FnParts<'a> { pub decl: &'a FnDecl, - pub body: &'a Block, + pub body: &'a Expr, pub kind: FnKind<'a>, pub span: Span, pub id: NodeId, @@ -77,29 +75,32 @@ impl MaybeFnLike for ast::Expr { } } -/// Carries either an FnLikeNode or a Block, as these are the two +/// Carries either an FnLikeNode or a Expr, as these are the two /// constructs that correspond to "code" (as in, something from which /// we can construct a control-flow graph). #[derive(Copy, Clone)] pub enum Code<'a> { - FnLikeCode(FnLikeNode<'a>), - BlockCode(&'a Block), + FnLike(FnLikeNode<'a>), + Expr(&'a Expr), } impl<'a> Code<'a> { pub fn id(&self) -> NodeId { match *self { - FnLikeCode(node) => node.id(), - BlockCode(block) => block.id, + Code::FnLike(node) => node.id(), + Code::Expr(block) => block.id, } } - /// Attempts to construct a Code from presumed FnLike or Block node input. - pub fn from_node(node: Node) -> Option { - if let map::NodeBlock(block) = node { - Some(BlockCode(block)) - } else { - FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like)) + /// Attempts to construct a Code from presumed FnLike or Expr node input. + pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option> { + match map.get(id) { + map::NodeBlock(_) => { + // Use the parent, hopefully an expression node. + Code::from_node(map, map.get_parent_node(id)) + } + map::NodeExpr(expr) => Some(Code::Expr(expr)), + node => FnLikeNode::from_node(node).map(Code::FnLike) } } } @@ -114,7 +115,7 @@ struct ItemFnParts<'a> { abi: abi::Abi, vis: &'a ast::Visibility, generics: &'a ast::Generics, - body: &'a Block, + body: &'a Expr, id: NodeId, span: Span, attrs: &'a [Attribute], @@ -124,14 +125,14 @@ struct ItemFnParts<'a> { /// for use when implementing FnLikeNode operations. struct ClosureParts<'a> { decl: &'a FnDecl, - body: &'a Block, + body: &'a Expr, id: NodeId, span: Span, attrs: &'a [Attribute], } impl<'a> ClosureParts<'a> { - fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self { + fn new(d: &'a FnDecl, b: &'a Expr, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self { ClosureParts { decl: d, body: b, @@ -171,9 +172,9 @@ impl<'a> FnLikeNode<'a> { } } - pub fn body(self) -> &'a Block { + pub fn body(self) -> &'a Expr { self.handle(|i: ItemFnParts<'a>| &*i.body, - |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _, _| body, + |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Expr, _, _| body, |c: ClosureParts<'a>| c.body) } @@ -214,7 +215,7 @@ impl<'a> FnLikeNode<'a> { Name, &'a ast::MethodSig, Option<&'a ast::Visibility>, - &'a ast::Block, + &'a ast::Expr, Span, &'a [Attribute]) -> A, diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 3d9031a136e28..e23a721da08a6 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -211,7 +211,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { } fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl, - b: &'ast Block, s: Span, id: NodeId) { + b: &'ast Expr, s: Span, id: NodeId) { assert_eq!(self.parent_node, id); intravisit::walk_fn(self, fk, fd, b, s, id); } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index cbd3e39f8703a..6b5b8101a146c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -904,7 +904,7 @@ pub enum Expr_ { /// A closure (for example, `move |a, b, c| {a + b + c}`). /// /// The final span is the span of the argument block `|...|` - ExprClosure(CaptureClause, P, P, Span), + ExprClosure(CaptureClause, P, P, Span), /// A block (`{ ... }`) ExprBlock(P), @@ -1035,7 +1035,7 @@ pub enum TraitItem_ { /// must contain a value) ConstTraitItem(P, Option>), /// A method with an optional body - MethodTraitItem(MethodSig, Option>), + MethodTraitItem(MethodSig, Option>), /// An associated type with (possibly empty) bounds and optional concrete /// type TypeTraitItem(TyParamBounds, Option>), @@ -1060,7 +1060,7 @@ pub enum ImplItemKind { /// of the expression Const(P, P), /// A method implementation with the given signature and body - Method(MethodSig, P), + Method(MethodSig, P), /// An associated type Type(P), } @@ -1501,7 +1501,7 @@ pub enum Item_ { /// A `const` item ItemConst(P, P), /// A function declaration - ItemFn(P, Unsafety, Constness, Abi, Generics, P), + ItemFn(P, Unsafety, Constness, Abi, Generics, P), /// A module ItemMod(Mod), /// An external module diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 657c10bab12eb..2c4ffb853c1f3 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -713,7 +713,9 @@ impl<'a> State<'a> { typarams, &item.vis)?; word(&mut self.s, " ")?; - self.print_block_with_attrs(&body, &item.attrs)?; + self.end()?; // need to close a box + self.end()?; // need to close a box + self.print_expr(&body)?; } hir::ItemMod(ref _mod) => { self.head(&visibility_qualified(&item.vis, "mod"))?; @@ -1002,7 +1004,9 @@ impl<'a> State<'a> { self.print_method_sig(ti.name, sig, &hir::Inherited)?; if let Some(ref body) = *body { self.nbsp()?; - self.print_block_with_attrs(body, &ti.attrs)?; + self.end()?; // need to close a box + self.end()?; // need to close a box + self.print_expr(body)?; } else { word(&mut self.s, ";")?; } @@ -1034,7 +1038,9 @@ impl<'a> State<'a> { self.head("")?; self.print_method_sig(ii.name, sig, &ii.vis)?; self.nbsp()?; - self.print_block_with_attrs(body, &ii.attrs)?; + self.end()?; // need to close a box + self.end()?; // need to close a box + self.print_expr(body)?; } hir::ImplItemKind::Type(ref ty) => { self.print_associated_type(ii.name, None, Some(ty))?; @@ -1402,26 +1408,10 @@ impl<'a> State<'a> { self.print_fn_block_args(&decl)?; space(&mut self.s)?; - let default_return = match decl.output { - hir::DefaultReturn(..) => true, - _ => false, - }; + // this is a bare expression + self.print_expr(body)?; + self.end()?; // need to close a box - if !default_return || !body.stmts.is_empty() || body.expr.is_none() { - self.print_block_unclosed(&body)?; - } else { - // we extract the block, so as not to create another set of boxes - match body.expr.as_ref().unwrap().node { - hir::ExprBlock(ref blk) => { - self.print_block_unclosed(&blk)?; - } - _ => { - // this is a bare expression - self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap())?; - self.end()?; // need to close a box - } - } - } // a box will be closed by print_expr, but we didn't want an overall // wrapper so we closed the corresponding opening. so create an // empty box to satisfy the close. diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 6f56f6858ce40..f44f82860077e 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -838,7 +838,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { } fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl, - body: &'v hir::Block, span: Span, id: ast::NodeId) { + body: &'v hir::Expr, span: Span, id: ast::NodeId) { run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); hir_visit::walk_fn(self, fk, decl, body, span, id); run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 5fba14768bf28..6f7102229f8d6 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -151,9 +151,9 @@ pub trait LateLintPass: LintPass { fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { } fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { } fn check_fn(&mut self, _: &LateContext, - _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { } + _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { } fn check_fn_post(&mut self, _: &LateContext, - _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { } + _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { } fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { } fn check_trait_item_post(&mut self, _: &LateContext, _: &hir::TraitItem) { } fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 7f3a58808c225..1ec3d0db8e0aa 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -498,7 +498,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { // ^^^^^^^^^^^^^ only needed for pretty printing - pub fn propagate(&mut self, cfg: &cfg::CFG, blk: &hir::Block) { + pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) { //! Performs the data flow analysis. if self.bits_per_id == 0 { @@ -524,17 +524,17 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { debug!("Dataflow result for {}:", self.analysis_name); debug!("{}", { let mut v = Vec::new(); - self.pretty_print_to(box &mut v, blk).unwrap(); + self.pretty_print_to(box &mut v, body).unwrap(); String::from_utf8(v).unwrap() }); } fn pretty_print_to<'b>(&self, wr: Box, - blk: &hir::Block) -> io::Result<()> { + body: &hir::Expr) -> io::Result<()> { let mut ps = pprust::rust_printer_annotated(wr, self, None); ps.cbox(pprust::indent_unit)?; ps.ibox(0)?; - ps.print_block(blk)?; + ps.print_expr(body)?; pp::eof(&mut ps.s) } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 7fc698fdbebf5..a32d5542a79e2 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -567,7 +567,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { self.warn_dead_code(impl_item.id, impl_item.span, impl_item.name, "method"); } - intravisit::walk_block(self, body) + intravisit::walk_expr(self, body) } hir::ImplItemKind::Type(..) => {} } @@ -576,11 +576,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { // Overwrite so that we don't warn the trait item itself. fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { match trait_item.node { - hir::ConstTraitItem(_, Some(ref expr)) => { - intravisit::walk_expr(self, expr) - } + hir::ConstTraitItem(_, Some(ref body))| hir::MethodTraitItem(_, Some(ref body)) => { - intravisit::walk_block(self, body) + intravisit::walk_expr(self, body) } hir::ConstTraitItem(_, None) | hir::MethodTraitItem(_, None) | diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 8ca3c75eaa4b1..5634e2012c971 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_fn(&mut self, fn_kind: FnKind<'v>, fn_decl: &'v hir::FnDecl, - block: &'v hir::Block, span: Span, id: ast::NodeId) { + block: &'v hir::Expr, span: Span, id: ast::NodeId) { let (is_item_fn, is_unsafe_fn) = match fn_kind { FnKind::ItemFn(_, _, unsafety, ..) => diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0543d1303a5f1..711a131a68e17 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -290,14 +290,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn walk_fn(&mut self, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { self.walk_arg_patterns(decl, body); - self.walk_block(body); + self.consume_expr(body); } fn walk_arg_patterns(&mut self, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { for arg in &decl.inputs { let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 57503398cfe57..7dbf9aa74144d 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, id: ast::NodeId) { + b: &'v hir::Expr, s: Span, id: ast::NodeId) { if let FnKind::Closure(..) = fk { span_bug!(s, "intrinsicck: closure outside of function") } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 46bea00cca3cb..a654d65bc6796 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -123,10 +123,9 @@ use std::io::prelude::*; use std::io; use std::rc::Rc; use syntax::ast::{self, NodeId}; -use syntax::codemap::original_sp; use syntax::parse::token::keywords; use syntax::ptr::P; -use syntax_pos::{BytePos, Span}; +use syntax_pos::Span; use hir::Expr; use hir; @@ -187,7 +186,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt) -> String { impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> { fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, id: NodeId) { + b: &'v hir::Expr, s: Span, id: NodeId) { visit_fn(self, fk, fd, b, s, id); } fn visit_local(&mut self, l: &hir::Local) { visit_local(self, l); } @@ -352,9 +351,9 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { } impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> { - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, n: NodeId) { - check_fn(self, fk, fd, b, s, n); + fn visit_fn(&mut self, _: FnKind<'v>, _: &'v hir::FnDecl, + _: &'v hir::Expr, _: Span, _: NodeId) { + // do not check contents of nested fns } fn visit_local(&mut self, l: &hir::Local) { check_local(self, l); @@ -370,7 +369,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> { fn visit_fn(ir: &mut IrMaps, fk: FnKind, decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId) { debug!("visit_fn"); @@ -405,10 +404,10 @@ fn visit_fn(ir: &mut IrMaps, // compute liveness let mut lsets = Liveness::new(&mut fn_maps, specials); - let entry_ln = lsets.compute(decl, body); + let entry_ln = lsets.compute(body); // check for various error conditions - lsets.visit_block(body); + lsets.visit_expr(body); lsets.check_ret(id, sp, fk, entry_ln, body); lsets.warn_about_unused_args(decl, entry_ln); } @@ -821,17 +820,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // _______________________________________________________________________ - fn compute(&mut self, decl: &hir::FnDecl, body: &hir::Block) -> LiveNode { + fn compute(&mut self, body: &hir::Expr) -> LiveNode { // if there is a `break` or `again` at the top level, then it's // effectively a return---this only occurs in `for` loops, // where the body is really a closure. - debug!("compute: using id for block, {}", block_to_string(body)); + debug!("compute: using id for body, {}", expr_to_string(body)); let exit_ln = self.s.exit_ln; - let entry_ln: LiveNode = - self.with_loop_nodes(body.id, exit_ln, exit_ln, - |this| this.propagate_through_fn_block(decl, body)); + let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| { + // the fallthrough exit is only for those cases where we do not + // explicitly return: + let s = this.s; + this.init_from_succ(s.fallthrough_ln, s.exit_ln); + this.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ); + + this.propagate_through_expr(body, s.fallthrough_ln) + }); // hack to skip the loop unless debug! is enabled: debug!("^^ liveness computation results for body {} (entry={:?})", @@ -846,20 +851,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { entry_ln } - fn propagate_through_fn_block(&mut self, _: &hir::FnDecl, blk: &hir::Block) - -> LiveNode { - // the fallthrough exit is only for those cases where we do not - // explicitly return: - let s = self.s; - self.init_from_succ(s.fallthrough_ln, s.exit_ln); - if blk.expr.is_none() { - self.acc(s.fallthrough_ln, s.no_ret_var, ACC_READ) - } - self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ); - - self.propagate_through_block(blk, s.fallthrough_ln) - } - fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode) -> LiveNode { let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ); @@ -1448,15 +1439,6 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { } } -fn check_fn(_v: &Liveness, - _fk: FnKind, - _decl: &hir::FnDecl, - _body: &hir::Block, - _sp: Span, - _id: NodeId) { - // do not check contents of nested fns -} - impl<'a, 'tcx> Liveness<'a, 'tcx> { fn fn_ret(&self, id: NodeId) -> ty::Binder> { let fn_ty = self.ir.tcx.tables().node_id_to_type(id); @@ -1472,7 +1454,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { sp: Span, _fk: FnKind, entry_ln: LiveNode, - body: &hir::Block) + body: &hir::Expr) { // within the fn body, late-bound regions are liberated // and must outlive the *call-site* of the function. @@ -1481,13 +1463,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.ir.tcx.region_maps.call_site_extent(id, body.id), &self.fn_ret(id)); - if fn_ret.is_never() { - // FIXME(durka) this rejects code like `fn foo(x: !) -> ! { x }` - if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() { - span_err!(self.ir.tcx.sess, sp, E0270, - "computation may converge in a function marked as diverging"); - } - } else if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { + if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { let param_env = ParameterEnvironment::for_item(self.ir.tcx, id); let t_ret_subst = fn_ret.subst(self.ir.tcx, ¶m_env.free_substs); let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env), @@ -1498,32 +1474,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // for nil return types, it is ok to not return a value expl. if !is_nil { - let ends_with_stmt = match body.expr { - None if !body.stmts.is_empty() => - match body.stmts.last().unwrap().node { - hir::StmtSemi(ref e, _) => { - self.ir.tcx.tables().expr_ty(&e) == fn_ret - }, - _ => false - }, - _ => false - }; - let mut err = struct_span_err!(self.ir.tcx.sess, - sp, - E0269, - "not all control paths return a value"); - if ends_with_stmt { - let last_stmt = body.stmts.last().unwrap(); - let original_span = original_sp(self.ir.tcx.sess.codemap(), - last_stmt.span, sp); - let span_semicolon = Span { - lo: original_span.hi - BytePos(1), - hi: original_span.hi, - expn_id: original_span.expn_id - }; - err.span_help(span_semicolon, "consider removing this semicolon:"); - } - err.emit(); + span_bug!(sp, "not all control paths return a value"); } } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 9898ec7597d90..7868e700f2701 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -248,9 +248,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match *node { ast_map::NodeItem(item) => { match item.node { - hir::ItemFn(.., ref search_block) => { + hir::ItemFn(.., ref body) => { if item_might_be_inlined(&item) { - intravisit::walk_block(self, &search_block) + self.visit_expr(body); } } @@ -278,11 +278,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::MethodTraitItem(_, None) => { // Keep going, nothing to get exported } - hir::ConstTraitItem(_, Some(ref expr)) => { - self.visit_expr(&expr); - } + hir::ConstTraitItem(_, Some(ref body)) | hir::MethodTraitItem(_, Some(ref body)) => { - intravisit::walk_block(self, body); + self.visit_expr(body); } hir::TypeTraitItem(..) => {} } @@ -295,7 +293,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ImplItemKind::Method(ref sig, ref body) => { let did = self.tcx.map.get_parent_did(search_item); if method_might_be_inlined(self.tcx, sig, impl_item, did) { - intravisit::walk_block(self, body) + self.visit_expr(body) } } hir::ImplItemKind::Type(_) => {} diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 8d51fda0cf2b1..34a6a547d9440 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -490,12 +490,7 @@ impl RegionMaps { // if there's one. Static items, for instance, won't // have an enclosing scope, hence no scope will be // returned. - let expr_extent = self.node_extent(expr_id); - // For some reason, the expr's scope itself is skipped here. - let mut id = match scope_map[expr_extent.0 as usize].into_option() { - Some(i) => i, - _ => return None - }; + let mut id = self.node_extent(expr_id); while let Some(p) = scope_map[id.0 as usize].into_option() { match code_extents[p.0 as usize] { @@ -1086,7 +1081,7 @@ fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &hir::Item) { fn resolve_fn(visitor: &mut RegionResolutionVisitor, kind: FnKind, decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId) { debug!("region::resolve_fn(id={:?}, \ @@ -1128,7 +1123,7 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, parent: fn_decl_scope, var_parent: fn_decl_scope }; - visitor.visit_block(body); + visitor.visit_expr(body); // Restore context we had at the start. visitor.cx = outer_cx; @@ -1191,7 +1186,7 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, - b: &'v Block, s: Span, n: NodeId) { + b: &'v Expr, s: Span, n: NodeId) { resolve_fn(self, fk, fd, b, s, n); } fn visit_arm(&mut self, a: &Arm) { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index e6d960735299c..292d9592ceb0c 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -202,7 +202,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, fn_id: ast::NodeId) { + b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { match fk { FnKind::ItemFn(_, generics, ..) => { self.visit_early_late(fn_id,decl, generics, |this| { @@ -403,7 +403,7 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning // if one of the label shadows a lifetime or another label. -fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) { +fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) { struct GatherLabels<'a> { sess: &'a Session, scope: Scope<'a>, @@ -415,7 +415,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) { scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn, }; - gather.visit_block(b); + gather.visit_expr(b); return; impl<'v, 'a> Visitor<'v> for GatherLabels<'a> { @@ -493,7 +493,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn add_scope_and_walk_fn<'b>(&mut self, fk: FnKind, fd: &hir::FnDecl, - fb: &'b hir::Block, + fb: &'b hir::Expr, _span: Span, fn_id: ast::NodeId) { @@ -516,7 +516,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { extract_labels(self, fb); self.with(FnScope { fn_id: fn_id, body_id: fb.id, s: self.scope }, - |_old_scope, this| this.visit_block(fb)) + |_old_scope, this| this.visit_expr(fb)) } fn with(&mut self, wrap_scope: ScopeChain, f: F) where diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index b2032e6a1bf9f..5ed628d7dcae5 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -190,7 +190,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, all_loans: &[Loan<'tcx>], fn_id: ast::NodeId, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { debug!("check_loans(body id={})", body.id); let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id); diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 763c012a8f8ab..8f2afa7f80822 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -42,7 +42,7 @@ mod move_error; pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, fn_id: NodeId, decl: &hir::FnDecl, - body: &hir::Block) + body: &hir::Expr) -> (Vec>, move_data::MoveData<'tcx>) { let mut glcx = GatherLoanCtxt { diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index cea9170da9ffd..836832de5b9c4 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -58,7 +58,7 @@ pub struct MoveDataParamEnv<'tcx> { pub fn borrowck_mir(bcx: &mut BorrowckCtxt, fk: FnKind, _decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, _sp: Span, id: ast::NodeId, attributes: &[ast::Attribute]) { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 2f74ea3e475b5..fb842f70a54a1 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -47,9 +47,7 @@ use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; -use rustc::hir::{FnDecl, Block}; -use rustc::hir::intravisit; -use rustc::hir::intravisit::{Visitor, FnKind}; +use rustc::hir::intravisit::{self, Visitor, FnKind}; pub mod check_loans; @@ -65,8 +63,8 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> { - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, - b: &'v Block, s: Span, id: ast::NodeId) { + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, + b: &'v hir::Expr, s: Span, id: ast::NodeId) { match fk { FnKind::ItemFn(..) | FnKind::Method(..) => { @@ -159,7 +157,7 @@ pub struct AnalysisData<'a, 'tcx: 'a> { fn borrowck_fn(this: &mut BorrowckCtxt, fk: FnKind, decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId, attributes: &[ast::Attribute]) { @@ -200,7 +198,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, fk: FnKind, decl: &hir::FnDecl, cfg: &cfg::CFG, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId) -> AnalysisData<'a, 'tcx> diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index afc4ccef0cc0f..32bda5e11620a 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -656,7 +656,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { cfg: &cfg::CFG, id_range: IdRange, decl: &hir::FnDecl, - body: &hir::Block) + body: &hir::Expr) -> FlowedMoveData<'a, 'tcx> { let mut dfcx_moves = DataFlowContext::new(tcx, diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 615aca90db8bf..e0e8a21591921 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -65,7 +65,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, id: ast::NodeId) { + b: &'v hir::Expr, s: Span, id: ast::NodeId) { if let FnKind::Closure(..) = fk { span_bug!(s, "check_match: closure outside of function") } @@ -113,7 +113,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, n: ast::NodeId) { + b: &'v hir::Expr, s: Span, n: ast::NodeId) { intravisit::walk_fn(self, fk, fd, b, s, n); for input in &fd.inputs { diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 57a5400ecadf8..ee6c27655d68c 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -857,11 +857,10 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callee => signal!(e, CallOn(callee)), }; let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) { - (fn_like.decl(), &fn_like.body().expr) + (fn_like.decl(), fn_like.body()) } else { signal!(e, NonConstPath) }; - let result = result.as_ref().expect("const fn has no result expression"); assert_eq!(decl.inputs.len(), args.len()); let mut call_args = DefIdMap(); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index b4ab9da92e9d0..ecbf28c1082f9 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -701,8 +701,8 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, mut out: W) -> io::Result<()> { let cfg = match code { - blocks::BlockCode(block) => cfg::CFG::new(tcx, &block), - blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &fn_like.body()), + blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr), + blocks::Code::FnLike(fn_like) => cfg::CFG::new(tcx, fn_like.body()), }; let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; let lcfg = LabelledCFG { @@ -717,12 +717,12 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, let r = dot::render(&lcfg, &mut out); return expand_err_details(r); } - blocks::BlockCode(_) => { + blocks::Code::Expr(_) => { tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \ fn-like node id."); return Ok(()); } - blocks::FnLikeCode(fn_like) => { + blocks::Code::FnLike(fn_like) => { let (bccx, analysis_data) = borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.to_fn_parts(), &cfg); @@ -990,8 +990,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) }); - let code = blocks::Code::from_node(node); - match code { + match blocks::Code::from_node(&tcx.map, nodeid) { Some(code) => { let variants = gather_flowgraph_variants(tcx.sess); diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index fea3de59520ca..e095bde18fd85 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -250,7 +250,7 @@ impl LateLintPass for NonSnakeCase { cx: &LateContext, fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, + _: &hir::Expr, span: Span, id: ast::NodeId) { match fk { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 28dc71fd59bae..192d7be6774af 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -222,7 +222,7 @@ impl LateLintPass for UnsafeCode { cx: &LateContext, fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, + _: &hir::Expr, span: Span, _: ast::NodeId) { match fk { @@ -812,7 +812,7 @@ impl LateLintPass for UnconditionalRecursion { cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl, - blk: &hir::Block, + blk: &hir::Expr, sp: Span, id: ast::NodeId) { let method = match fn_kind { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index d3fd638d6b5ff..0668d362037dd 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -99,7 +99,7 @@ impl LateLintPass for UnusedMut { cx: &LateContext, _: FnKind, decl: &hir::FnDecl, - _: &hir::Block, + _: &hir::Expr, _: Span, _: ast::NodeId) { for a in &decl.inputs { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index b37dd8dd0a907..902798ec98006 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -156,7 +156,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, fn_id: ast::NodeId, arguments: A, return_ty: Ty<'gcx>, - ast_block: &'gcx hir::Block) + ast_body: &'gcx hir::Expr) -> (Mir<'tcx>, ScopeAuxiliaryVec) where A: Iterator, Option<&'gcx hir::Pat>)> { @@ -166,7 +166,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let span = tcx.map.span(fn_id); let mut builder = Builder::new(hir, span, arguments.len(), return_ty); - let body_id = ast_block.id; + let body_id = ast_body.id; let call_site_extent = tcx.region_maps.lookup_code_extent( CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id }); @@ -176,7 +176,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let mut block = START_BLOCK; unpack!(block = builder.in_scope(call_site_extent, block, |builder| { unpack!(block = builder.in_scope(arg_extent, block, |builder| { - builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block) + builder.args_and_body(block, &arguments, arg_extent, ast_body) })); // Attribute epilogue to function's closing brace let fn_end = Span { lo: span.hi, ..span }; @@ -310,10 +310,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn args_and_body(&mut self, mut block: BasicBlock, - return_ty: Ty<'tcx>, arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)], argument_extent: CodeExtent, - ast_block: &'gcx hir::Block) + ast_body: &'gcx hir::Expr) -> BlockAnd<()> { // Allocate locals for the function arguments @@ -342,12 +341,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(pattern) = pattern { let pattern = Pattern::from_hir(self.hir.tcx(), pattern); - scope = self.declare_bindings(scope, ast_block.span, &pattern); + scope = self.declare_bindings(scope, ast_body.span, &pattern); unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue)); } // Make sure we drop (parts of) the argument even when not matched on. - self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span), + self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span), argument_extent, &lvalue, ty); } @@ -357,13 +356,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.visibility_scope = visibility_scope; } - // FIXME(#32959): temporary hack for the issue at hand - let return_is_unit = return_ty.is_nil(); - // start the first basic block and translate the body - unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER), - return_is_unit, block, ast_block)); - - block.unit() + let body = self.hir.mirror(ast_body); + self.into(&Lvalue::Local(RETURN_POINTER), block, body) } fn get_unit_temp(&mut self) -> Lvalue<'tcx> { diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 0ffc59fe6bf45..af2f9adfc9a8c 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -209,7 +209,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block, + body: &'tcx hir::Expr, span: Span, id: ast::NodeId) { // fetch the fully liberated fn signature (that is, all bound diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index f23539e88f78d..7a93d4594ee99 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -134,7 +134,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { fn fn_like(&mut self, fk: FnKind, fd: &hir::FnDecl, - b: &hir::Block, + b: &hir::Expr, s: Span, fn_id: ast::NodeId) -> ConstQualif { @@ -265,7 +265,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, + b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { self.fn_like(fk, fd, b, s, fn_id); diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index f8994de54a137..417987d9664e0 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -164,7 +164,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, + b: &'v hir::Expr, s: Span, id: NodeId) { self.record("FnDecl", Id::None, fd); diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index e942707acd56b..e58cd89381933 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -54,7 +54,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { self.with_context(Loop, |v| v.visit_block(&b)); } hir::ExprClosure(.., ref b, _) => { - self.with_context(Closure, |v| v.visit_block(&b)); + self.with_context(Closure, |v| v.visit_expr(&b)); } hir::ExprBreak(_) => self.require_loop("break", e.span), hir::ExprAgain(_) => self.require_loop("continue", e.span), diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index c3ef5a72a2944..d55ce4c356384 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -35,7 +35,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> { fn visit_fn(&mut self, fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, + b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { // FIXME (@jroesch) change this to be an inference context diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d478f1092bd87..af834f3f84d47 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &hir::Expr, _capture: hir::CaptureClause, decl: &'gcx hir::FnDecl, - body: &'gcx hir::Block, + body: &'gcx hir::Expr, expected: Expectation<'tcx>) -> Ty<'tcx> { debug!("check_expr_closure(expr={:?},expected={:?})", @@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &hir::Expr, opt_kind: Option, decl: &'gcx hir::FnDecl, - body: &'gcx hir::Block, + body: &'gcx hir::Expr, expected_sig: Option>) -> Ty<'tcx> { let expr_def_id = self.tcx.map.local_def_id(expr.id); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f7e05f4777ecc..725862022c59a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -534,7 +534,7 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult { fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block, + body: &'tcx hir::Expr, fn_id: ast::NodeId, span: Span) { let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty; @@ -558,7 +558,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body); fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze_fn(body); + fcx.closure_analyze(body); fcx.select_obligations_where_possible(); fcx.check_casts(); fcx.select_all_obligations_or_error(); // Casts can introduce new obligations. @@ -654,7 +654,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // Don't descend into the bodies of nested closures fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl, - _: &'gcx hir::Block, _: Span, _: ast::NodeId) { } + _: &'gcx hir::Expr, _: Span, _: ast::NodeId) { } } /// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function @@ -669,7 +669,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fn_sig: &ty::FnSig<'tcx>, decl: &'gcx hir::FnDecl, fn_id: ast::NodeId, - body: &'gcx hir::Block) + body: &'gcx hir::Expr) -> FnCtxt<'a, 'gcx, 'tcx> { let mut fn_sig = fn_sig.clone(); @@ -709,18 +709,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.write_ty(input.id, arg_ty); } - visit.visit_block(body); + visit.visit_expr(body); } inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - // FIXME(aburka) do we need this special case? and should it be is_uninhabited? - let expected = if fcx.ret_ty.is_never() { - NoExpectation - } else { - ExpectHasType(fcx.ret_ty) - }; - fcx.check_block_with_expected(body, expected); + fcx.check_expr_coercable_to_type(body, fcx.ret_ty); fcx } @@ -1198,7 +1192,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, fcx.check_expr_coercable_to_type(expr, expected_type); fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze_const(expr); + fcx.closure_analyze(expr); fcx.select_obligations_where_possible(); fcx.check_casts(); fcx.select_all_obligations_or_error(); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 6f6538254c46b..d4e5e9a5bb355 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -142,13 +142,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn regionck_fn(&self, fn_id: ast::NodeId, decl: &hir::FnDecl, - blk: &hir::Block) { + body: &hir::Expr) { debug!("regionck_fn(id={})", fn_id); - let mut rcx = RegionCtxt::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id)); + let mut rcx = RegionCtxt::new(self, RepeatingScope(body.id), body.id, Subject(fn_id)); if self.err_count_since_creation() == 0 { // regionck assumes typeck succeeded - rcx.visit_fn_body(fn_id, decl, blk, self.tcx.map.span(fn_id)); + rcx.visit_fn_body(fn_id, decl, body, self.tcx.map.span(fn_id)); } rcx.free_region_map.relate_free_regions_from_predicates( @@ -268,7 +268,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn visit_fn_body(&mut self, id: ast::NodeId, // the id of the fn itself fn_decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, span: Span) { // When we enter a function, we can derive @@ -305,7 +305,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.relate_free_regions(&fn_sig_tys[..], body.id, span); self.link_fn_args(self.tcx.region_maps.node_extent(body.id), &fn_decl.inputs[..]); - self.visit_block(body); + self.visit_expr(body); self.visit_region_obligations(body.id); let call_site_scope = self.call_site_scope.unwrap(); @@ -480,7 +480,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { // regions, until regionck, as described in #3238. fn visit_fn(&mut self, _fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, span: Span, id: ast::NodeId) { + b: &'v hir::Expr, span: Span, id: ast::NodeId) { self.visit_fn_body(id, fd, b, span) } @@ -825,7 +825,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn check_expr_fn_block(&mut self, expr: &hir::Expr, - body: &hir::Block) { + body: &hir::Expr) { let repeating_scope = self.set_repeating_scope(body.id); intravisit::walk_expr(self, expr); self.set_repeating_scope(repeating_scope); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index aa221c33b5ddb..2fea86cb21207 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -57,18 +57,7 @@ use rustc::util::nodemap::NodeMap; // PUBLIC ENTRY POINTS impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn closure_analyze_fn(&self, body: &hir::Block) { - let mut seed = SeedBorrowKind::new(self); - seed.visit_block(body); - - let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); - adjust.visit_block(body); - - // it's our job to process these. - assert!(self.deferred_call_resolutions.borrow().is_empty()); - } - - pub fn closure_analyze_const(&self, body: &hir::Expr) { + pub fn closure_analyze(&self, body: &hir::Expr) { let mut seed = SeedBorrowKind::new(self); seed.visit_expr(body); @@ -110,7 +99,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { fn check_closure(&mut self, expr: &hir::Expr, capture_clause: hir::CaptureClause, - _body: &hir::Block) + _body: &hir::Expr) { let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id); if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) { @@ -164,7 +153,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { id: ast::NodeId, span: Span, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { /*! * Analysis starting point. */ @@ -497,7 +486,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'gcx, 'tcx> { fn visit_fn(&mut self, fn_kind: intravisit::FnKind<'v>, decl: &'v hir::FnDecl, - body: &'v hir::Block, + body: &'v hir::Expr, span: Span, id: ast::NodeId) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 741f327ac99e1..2c1a9a7b17748 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -347,7 +347,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn check_item_fn(&mut self, item: &hir::Item, - body: &hir::Block) + body: &hir::Expr) { self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 5ef3e8699602b..9f3214a0d813e 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -49,11 +49,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, - blk: &hir::Block, + body: &hir::Expr, item_id: ast::NodeId) { assert_eq!(self.writeback_errors.get(), false); let mut wbcx = WritebackCx::new(self); - wbcx.visit_block(blk); + wbcx.visit_expr(body); for arg in &decl.inputs { wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); wbcx.visit_pat(&arg.pat); From 6b3cc0b8c8094407a3b5ea75f946c682d6d0142a Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 26 Oct 2016 02:28:20 +0300 Subject: [PATCH 6/9] rustc_typeck: correctly track "always-diverges" and "has-type-errors". --- src/libpanic_abort/lib.rs | 2 +- src/librustc_driver/lib.rs | 2 - src/librustc_typeck/check/_match.rs | 26 +- src/librustc_typeck/check/mod.rs | 457 +++++++++++------- src/librustc_typeck/check/op.rs | 5 + src/test/compile-fail/E0138.rs | 4 +- .../consider-removing-last-semi.rs | 4 +- .../compile-fail/diverging-fn-tail-35849.rs | 4 +- src/test/compile-fail/issue-11714.rs | 2 +- src/test/compile-fail/issue-13428.rs | 4 +- src/test/compile-fail/issue-22645.rs | 2 +- src/test/compile-fail/issue-22684.rs | 2 +- src/test/compile-fail/issue-29161.rs | 2 +- src/test/compile-fail/issue-32323.rs | 2 +- src/test/compile-fail/issue-5239-1.rs | 2 +- src/test/compile-fail/issue-6458-4.rs | 7 +- src/test/compile-fail/liveness-forgot-ret.rs | 3 +- src/test/compile-fail/liveness-issue-2163.rs | 2 +- .../compile-fail/liveness-missing-ret2.rs | 4 +- .../liveness-return-last-stmt-semi.rs | 8 +- src/test/compile-fail/main-wrong-type-2.rs | 1 + .../compile-fail/on-unimplemented/on-trait.rs | 2 +- .../compile-fail/private-in-public-lint.rs | 4 +- src/test/compile-fail/required-lang-item.rs | 1 + src/test/compile-fail/unreachable-in-call.rs | 2 +- .../compile-fail/where-clauses-unsatisfied.rs | 3 +- 26 files changed, 345 insertions(+), 212 deletions(-) diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index b87160dd75d04..853f81ceaa9b8 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -53,7 +53,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8), // now hopefully. #[no_mangle] pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { - return abort(); + abort(); #[cfg(unix)] unsafe fn abort() -> ! { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6551bad3bc92e..7e60c40220f84 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -455,8 +455,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { 1 => panic!("make_input should have provided valid inputs"), _ => early_error(sopts.error_format, "multiple input filenames provided"), } - - None } fn late_callback(&mut self, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 15b29573ac4e8..ca630624cdb38 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -13,7 +13,7 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; -use check::{FnCtxt, Expectation}; +use check::{FnCtxt, Expectation, Diverges}; use util::nodemap::FxHashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -360,9 +360,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } true } -} -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_match(&self, expr: &'gcx hir::Expr, discrim: &'gcx hir::Expr, @@ -390,14 +388,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { discrim_ty = self.next_ty_var(); self.check_expr_has_type(discrim, discrim_ty); }; + let discrim_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); // Typecheck the patterns first, so that we get types for all the // bindings. - for arm in arms { + let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| { + let mut all_pats_diverge = Diverges::WarnedAlways; for p in &arm.pats { + self.diverges.set(Diverges::Maybe); self.check_pat(&p, discrim_ty); + all_pats_diverge &= self.diverges.get(); } - } + all_pats_diverge + }).collect(); // Now typecheck the blocks. // @@ -410,6 +414,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // type in that case) let expected = expected.adjust_for_branches(self); let mut result_ty = self.next_diverging_ty_var(); + let mut all_arms_diverge = Diverges::WarnedAlways; let coerce_first = match expected { // We don't coerce to `()` so that if the match expression is a // statement it's branches can have any consistent type. That allows @@ -422,11 +427,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => result_ty }; - for (i, arm) in arms.iter().enumerate() { + for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { if let Some(ref e) = arm.guard { + self.diverges.set(pats_diverge); self.check_expr_has_type(e, tcx.types.bool); } + + self.diverges.set(pats_diverge); let arm_ty = self.check_expr_with_expectation(&arm.body, expected); + all_arms_diverge &= self.diverges.get(); if result_ty.references_error() || arm_ty.references_error() { result_ty = tcx.types.err; @@ -476,11 +485,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; } + // We won't diverge unless the discriminant or all arms diverge. + self.diverges.set(discrim_diverges | all_arms_diverge); + result_ty } -} -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_pat_struct(&self, pat: &'gcx hir::Pat, path: &hir::Path, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 725862022c59a..f6f585eb05f5f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -106,17 +106,18 @@ use util::common::{block_query, ErrorReported, indenter, loop_query}; use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap}; use std::cell::{Cell, Ref, RefCell}; +use std::cmp; use std::mem::replace; -use std::ops::Deref; +use std::ops::{self, Deref}; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::codemap::{self, Spanned}; +use syntax::codemap::{self, original_sp, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::parse::token::{self, InternedString, keywords}; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{self, Span}; +use syntax_pos::{self, BytePos, Span}; use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::{self, PatKind}; @@ -351,6 +352,59 @@ impl UnsafetyState { } } +/// Whether a node ever exits normally or not. +/// Tracked semi-automatically (through type variables +/// marked as diverging), with some manual adjustments +/// for control-flow primitives (approximating a CFG). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +enum Diverges { + /// Potentially unknown, some cases converge, + /// others require a CFG to determine them. + Maybe, + + /// Definitely known to diverge and therefore + /// not reach the next sibling or its parent. + Always, + + /// Same as `Always` but with a reachability + /// warning already emitted + WarnedAlways +} + +// Convenience impls for combinig `Diverges`. + +impl ops::BitAnd for Diverges { + type Output = Self; + fn bitand(self, other: Self) -> Self { + cmp::min(self, other) + } +} + +impl ops::BitOr for Diverges { + type Output = Self; + fn bitor(self, other: Self) -> Self { + cmp::max(self, other) + } +} + +impl ops::BitAndAssign for Diverges { + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } +} + +impl ops::BitOrAssign for Diverges { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl Diverges { + fn always(self) -> bool { + self >= Diverges::Always + } +} + #[derive(Clone)] pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ast_ty_to_ty_cache: RefCell>>, @@ -371,6 +425,12 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ps: RefCell, + /// Whether the last checked node can ever exit. + diverges: Cell, + + /// Whether any child nodes have any type errors. + has_errors: Cell, + inh: &'a Inherited<'a, 'gcx, 'tcx>, } @@ -1491,6 +1551,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ret_ty: rty, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), + diverges: Cell::new(Diverges::Maybe), + has_errors: Cell::new(false), inh: inh, } } @@ -1507,6 +1569,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.sess.err_count() - self.err_count_on_creation } + /// Produce warning on the given node, if the current point in the + /// function is unreachable, and there hasn't been another warning. + fn warn_if_unreachable(&self, id: ast::NodeId, span: Span, kind: &str) { + if self.diverges.get() == Diverges::Always { + self.diverges.set(Diverges::WarnedAlways); + + self.tcx.sess.add_lint(lint::builtin::UNREACHABLE_CODE, + id, span, + format!("unreachable {}", kind)); + } + } + /// Resolves type variables in `ty` if possible. Unlike the infcx /// version (resolve_type_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort @@ -1577,6 +1651,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("write_ty({}, {:?}) in fcx {}", node_id, ty, self.tag()); self.tables.borrow_mut().node_types.insert(node_id, ty); + + if ty.references_error() { + self.has_errors.set(true); + } + + // FIXME(canndrew): This is_never should probably be an is_uninhabited + if ty.is_never() || self.type_var_diverges(ty) { + self.diverges.set(self.diverges.get() | Diverges::Always); + } } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -2512,21 +2595,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Check the arguments. // We do this in a pretty awful way: first we typecheck any arguments - // that are not anonymous functions, then we typecheck the anonymous - // functions. This is so that we have more information about the types - // of arguments when we typecheck the functions. This isn't really the - // right way to do this. - let xs = [false, true]; - let mut any_diverges = false; // has any of the arguments diverged? - let mut warned = false; // have we already warned about unreachable code? - for check_blocks in &xs { - let check_blocks = *check_blocks; - debug!("check_blocks={}", check_blocks); + // that are not closures, then we typecheck the closures. This is so + // that we have more information about the types of arguments when we + // typecheck the functions. This isn't really the right way to do this. + for &check_closures in &[false, true] { + debug!("check_closures={}", check_closures); // More awful hacks: before we check argument types, try to do // an "opportunistic" vtable resolution of any trait bounds on // the call. This helps coercions. - if check_blocks { + if check_closures { self.select_obligations_where_possible(); } @@ -2541,61 +2619,43 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { supplied_arg_count }; for (i, arg) in args.iter().take(t).enumerate() { - if any_diverges && !warned { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - arg.id, - arg.span, - "unreachable expression".to_string()); - warned = true; + // Warn only for the first loop (the "no closures" one). + // Closure arguments themselves can't be diverging, but + // a previous argument can, e.g. `foo(panic!(), || {})`. + if !check_closures { + self.warn_if_unreachable(arg.id, arg.span, "expression"); } - let is_block = match arg.node { + + let is_closure = match arg.node { hir::ExprClosure(..) => true, _ => false }; - if is_block == check_blocks { - debug!("checking the argument"); - let formal_ty = formal_tys[i]; + if is_closure != check_closures { + continue; + } - // The special-cased logic below has three functions: - // 1. Provide as good of an expected type as possible. - let expected = expected_arg_tys.get(i).map(|&ty| { - Expectation::rvalue_hint(self, ty) - }); + debug!("checking the argument"); + let formal_ty = formal_tys[i]; - let checked_ty = self.check_expr_with_expectation(&arg, - expected.unwrap_or(ExpectHasType(formal_ty))); - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.and_then(|e| e.only_has_type(self)); - self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty)); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); - } + // The special-cased logic below has three functions: + // 1. Provide as good of an expected type as possible. + let expected = expected_arg_tys.get(i).map(|&ty| { + Expectation::rvalue_hint(self, ty) + }); - if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) { - // FIXME(canndrew): This is_never should probably be an is_uninhabited - any_diverges = any_diverges || - self.type_var_diverges(arg_ty) || - arg_ty.is_never(); - } - } - if any_diverges && !warned { - let parent = self.tcx.map.get_parent_node(args[0].id); - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - parent, - sp, - "unreachable call".to_string()); - warned = true; + let checked_ty = self.check_expr_with_expectation(&arg, + expected.unwrap_or(ExpectHasType(formal_ty))); + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerce_ty = expected.and_then(|e| e.only_has_type(self)); + self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty)); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); } - } // We also need to make sure we at least write the ty of the other @@ -2846,18 +2906,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { sp: Span, expected: Expectation<'tcx>) -> Ty<'tcx> { let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool); + let cond_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); let expected = expected.adjust_for_branches(self); let then_ty = self.check_block_with_expected(then_blk, expected); + let then_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); let unit = self.tcx.mk_nil(); let (origin, expected, found, result) = if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); - let origin = TypeOrigin::IfExpression(sp); + let else_diverges = self.diverges.get(); // Only try to coerce-unify if we have a then expression // to assign coercions to, otherwise it's () or diverging. + let origin = TypeOrigin::IfExpression(sp); let result = if let Some(ref then) = then_blk.expr { let res = self.try_find_coercion_lub(origin, || Some(&**then), then_ty, else_expr, else_ty); @@ -2883,8 +2948,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) }) }; + + // We won't diverge unless both branches do (or the condition does). + self.diverges.set(cond_diverges | then_diverges & else_diverges); + (origin, then_ty, else_ty, result) } else { + // If the condition is false we can't diverge. + self.diverges.set(cond_diverges); + let origin = TypeOrigin::IfExpressionWithNoElse(sp); (origin, unit, then_ty, self.eq_types(true, origin, unit, then_ty) @@ -3346,10 +3418,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lvalue_pref: LvaluePreference) -> Ty<'tcx> { debug!(">> typechecking: expr={:?} expected={:?}", expr, expected); + + // Warn for expressions after diverging siblings. + self.warn_if_unreachable(expr.id, expr.span, "expression"); + + // Hide the outer diverging and has_errors flags. + let old_diverges = self.diverges.get(); + let old_has_errors = self.has_errors.get(); + self.diverges.set(Diverges::Maybe); + self.has_errors.set(false); + let ty = self.check_expr_kind(expr, expected, lvalue_pref); + // Warn for non-block expressions with diverging children. + match expr.node { + hir::ExprBlock(_) | + hir::ExprLoop(..) | hir::ExprWhile(..) | + hir::ExprIf(..) | hir::ExprMatch(..) => {} + + _ => self.warn_if_unreachable(expr.id, expr.span, "expression") + } + + // Record the type, which applies it effects. + // We need to do this after the warning above, so that + // we don't warn for the diverging expression itself. self.write_ty(expr.id, ty); + // Combine the diverging and has_error flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); + debug!("type of expr({}) {} is...", expr.id, pprust::expr_to_string(expr)); debug!("... {:?}, expected is {:?}", @@ -3574,22 +3672,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { - let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool); + self.check_expr_has_type(&cond, tcx.types.bool); + let cond_diverging = self.diverges.get(); self.check_block_no_value(&body); - let body_ty = self.node_ty(body.id); - if cond_ty.references_error() || body_ty.references_error() { + + // We may never reach the body so it diverging means nothing. + self.diverges.set(cond_diverging); + + if self.has_errors.get() { tcx.types.err - } - else { + } else { tcx.mk_nil() } } hir::ExprLoop(ref body, _) => { self.check_block_no_value(&body); - if !may_break(tcx, expr.id, &body) { - tcx.types.never - } else { + if may_break(tcx, expr.id, &body) { + // No way to know whether it's diverging because + // of a `break` or an outer `break` or `return. + self.diverges.set(Diverges::Maybe); + tcx.mk_nil() + } else { + tcx.types.never } } hir::ExprMatch(ref discrim, ref arms, match_src) => { @@ -3922,55 +4027,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) { - let node_id; - let mut saw_bot = false; - let mut saw_err = false; + // Don't do all the complex logic below for DeclItem. match stmt.node { - hir::StmtDecl(ref decl, id) => { - node_id = id; - match decl.node { - hir::DeclLocal(ref l) => { - self.check_decl_local(&l); - let l_t = self.node_ty(l.id); - saw_bot = saw_bot || self.type_var_diverges(l_t); - saw_err = saw_err || l_t.references_error(); - } - hir::DeclItem(_) => {/* ignore for now */ } + hir::StmtDecl(ref decl, id) => { + match decl.node { + hir::DeclLocal(_) => {} + hir::DeclItem(_) => { + self.write_nil(id); + return; + } + } } - } - hir::StmtExpr(ref expr, id) => { - node_id = id; - // Check with expected type of () - let ty = self.check_expr_has_type(&expr, self.tcx.mk_nil()); - saw_bot = saw_bot || self.type_var_diverges(ty); - saw_err = saw_err || ty.references_error(); - } - hir::StmtSemi(ref expr, id) => { - node_id = id; - let ty = self.check_expr(&expr); - saw_bot |= self.type_var_diverges(ty); - saw_err |= ty.references_error(); - } + hir::StmtExpr(..) | hir::StmtSemi(..) => {} } - if saw_bot { - self.write_ty(node_id, self.next_diverging_ty_var()); - } - else if saw_err { + + self.warn_if_unreachable(stmt.node.id(), stmt.span, "statement"); + + // Hide the outer diverging and has_errors flags. + let old_diverges = self.diverges.get(); + let old_has_errors = self.has_errors.get(); + self.diverges.set(Diverges::Maybe); + self.has_errors.set(false); + + let node_id = match stmt.node { + hir::StmtDecl(ref decl, id) => { + match decl.node { + hir::DeclLocal(ref l) => { + self.check_decl_local(&l); + } + hir::DeclItem(_) => {/* ignore for now */ } + } + id + } + hir::StmtExpr(ref expr, id) => { + // Check with expected type of () + self.check_expr_has_type(&expr, self.tcx.mk_nil()); + id + } + hir::StmtSemi(ref expr, id) => { + self.check_expr(&expr); + id + } + }; + + if self.has_errors.get() { self.write_error(node_id); - } - else { + } else if self.diverges.get().always() { + self.write_ty(node_id, self.next_diverging_ty_var()); + } else { self.write_nil(node_id); } + + // Combine the diverging and has_error flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); } pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { - let blkty = self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil())); - if blkty.references_error() { - self.write_error(blk.id); - } else { - let nilty = self.tcx.mk_nil(); - self.demand_suptype(blk.span, nilty, blkty); - } + let unit = self.tcx.mk_nil(); + let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); + self.demand_suptype(blk.span, unit, ty); } fn check_block_with_expected(&self, @@ -3982,72 +4098,81 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { replace(&mut *fcx_ps, unsafety_state) }; - let mut warned = false; - let mut any_diverges = false; - let mut any_err = false; for s in &blk.stmts { self.check_stmt(s); - let s_id = s.node.id(); - let s_ty = self.node_ty(s_id); - if any_diverges && !warned && match s.node { - hir::StmtDecl(ref decl, _) => { - match decl.node { - hir::DeclLocal(_) => true, - _ => false, + } + + let mut ty = match blk.expr { + Some(ref e) => self.check_expr_with_expectation(e, expected), + None => self.tcx.mk_nil() + }; + + if self.diverges.get().always() { + if let ExpectHasType(ety) = expected { + // Avoid forcing a type (only `!` for now) in unreachable code. + // FIXME(aburka) do we need this special case? and should it be is_uninhabited? + if !ety.is_never() { + if let Some(ref e) = blk.expr { + // Coerce the tail expression to the right type. + self.demand_coerce(e, ty, ety); } } - hir::StmtExpr(..) | hir::StmtSemi(..) => true, - } { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - s_id, - s.span, - "unreachable statement".to_string()); - warned = true; } - // FIXME(canndrew): This is_never should probably be an is_uninhabited - any_diverges = any_diverges || - self.type_var_diverges(s_ty) || - s_ty.is_never(); - any_err = any_err || s_ty.references_error(); - } - let ty = match blk.expr { - None => if any_err { - self.tcx.types.err - } else if any_diverges { - self.next_diverging_ty_var() + + ty = self.next_diverging_ty_var(); + } else if let ExpectHasType(ety) = expected { + if let Some(ref e) = blk.expr { + // Coerce the tail expression to the right type. + self.demand_coerce(e, ty, ety); } else { - self.tcx.mk_nil() - }, - Some(ref e) => { - if any_diverges && !warned { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - e.id, - e.span, - "unreachable expression".to_string()); - } - let ety = match expected { - ExpectHasType(ety) => { - self.check_expr_coercable_to_type(&e, ety); - ety - } - _ => { - self.check_expr_with_expectation(&e, expected) - } - }; + // We're not diverging and there's an expected type, which, + // in case it's not `()`, could result in an error higher-up. + // We have a chance to error here early and be more helpful. + let origin = TypeOrigin::Misc(blk.span); + let trace = TypeTrace::types(origin, false, ty, ety); + match self.sub_types(false, origin, ty, ety) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }, + Err(err) => { + let mut err = self.report_and_explain_type_error(trace, &err); + + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let mut extra_semi = None; + if let Some(stmt) = blk.stmts.last() { + if let hir::StmtSemi(ref e, _) = stmt.node { + if self.can_sub_types(self.node_ty(e.id), ety).is_ok() { + extra_semi = Some(stmt); + } + } + } + if let Some(last_stmt) = extra_semi { + let original_span = original_sp(self.tcx.sess.codemap(), + last_stmt.span, blk.span); + let span_semi = Span { + lo: original_span.hi - BytePos(1), + hi: original_span.hi, + expn_id: original_span.expn_id + }; + err.span_help(span_semi, "consider removing this semicolon:"); + } - if any_err { - self.tcx.types.err - } else if any_diverges { - self.next_diverging_ty_var() - } else { - ety + err.emit(); + } } } - }; + + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } + + if self.has_errors.get() || ty.references_error() { + ty = self.tcx.types.err + } + self.write_ty(blk.id, ty); *self.ps.borrow_mut() = prev; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 411bd7e7b5ca1..8b4975b7e3a2f 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -75,8 +75,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. + let lhs_diverges = self.diverges.get(); self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool()); + + // Depending on the LHS' value, the RHS can never execute. + self.diverges.set(lhs_diverges); + tcx.mk_bool() } _ => { diff --git a/src/test/compile-fail/E0138.rs b/src/test/compile-fail/E0138.rs index d4630d7c2effb..11d90658ab26a 100644 --- a/src/test/compile-fail/E0138.rs +++ b/src/test/compile-fail/E0138.rs @@ -11,10 +11,10 @@ #![feature(start)] #[start] -fn foo(argc: isize, argv: *const *const u8) -> isize {} +fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } //~^ NOTE previous `start` function here #[start] -fn f(argc: isize, argv: *const *const u8) -> isize {} +fn f(argc: isize, argv: *const *const u8) -> isize { 0 } //~^ ERROR E0138 //~| NOTE multiple `start` functions diff --git a/src/test/compile-fail/consider-removing-last-semi.rs b/src/test/compile-fail/consider-removing-last-semi.rs index 2e110cb3d0bc8..530a0e4156228 100644 --- a/src/test/compile-fail/consider-removing-last-semi.rs +++ b/src/test/compile-fail/consider-removing-last-semi.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f() -> String { //~ ERROR E0269 +fn f() -> String { //~ ERROR mismatched types 0u8; "bla".to_string(); //~ HELP consider removing this semicolon } -fn g() -> String { //~ ERROR E0269 +fn g() -> String { //~ ERROR mismatched types "this won't work".to_string(); "removeme".to_string(); //~ HELP consider removing this semicolon } diff --git a/src/test/compile-fail/diverging-fn-tail-35849.rs b/src/test/compile-fail/diverging-fn-tail-35849.rs index 6dc447b4dc887..3a27c08413328 100644 --- a/src/test/compile-fail/diverging-fn-tail-35849.rs +++ b/src/test/compile-fail/diverging-fn-tail-35849.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn _converge() -> ! { //~ ERROR computation may converge - 42 +fn _converge() -> ! { + 42 //~ ERROR mismatched types } fn main() { } diff --git a/src/test/compile-fail/issue-11714.rs b/src/test/compile-fail/issue-11714.rs index 998576097a0a0..192f78e41cb43 100644 --- a/src/test/compile-fail/issue-11714.rs +++ b/src/test/compile-fail/issue-11714.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn blah() -> i32 { //~ ERROR not all control paths return a value +fn blah() -> i32 { //~ ERROR mismatched types 1 ; //~ HELP consider removing this semicolon: diff --git a/src/test/compile-fail/issue-13428.rs b/src/test/compile-fail/issue-13428.rs index c771970650d31..9406199afc231 100644 --- a/src/test/compile-fail/issue-13428.rs +++ b/src/test/compile-fail/issue-13428.rs @@ -10,7 +10,7 @@ // Regression test for #13428 -fn foo() -> String { //~ ERROR not all control paths return a value +fn foo() -> String { //~ ERROR mismatched types format!("Hello {}", "world") // Put the trailing semicolon on its own line to test that the @@ -18,7 +18,7 @@ fn foo() -> String { //~ ERROR not all control paths return a value ; //~ HELP consider removing this semicolon } -fn bar() -> String { //~ ERROR not all control paths return a value +fn bar() -> String { //~ ERROR mismatched types "foobar".to_string() ; //~ HELP consider removing this semicolon } diff --git a/src/test/compile-fail/issue-22645.rs b/src/test/compile-fail/issue-22645.rs index 402b9a04496e9..81f66e3e2cfee 100644 --- a/src/test/compile-fail/issue-22645.rs +++ b/src/test/compile-fail/issue-22645.rs @@ -17,7 +17,7 @@ struct Bob; impl Add for Bob { type Output = Bob; - fn add(self, rhs : RHS) -> Bob {} + fn add(self, rhs : RHS) -> Bob { Bob } } fn main() { diff --git a/src/test/compile-fail/issue-22684.rs b/src/test/compile-fail/issue-22684.rs index b7ffbefba6a08..a791758ad1763 100644 --- a/src/test/compile-fail/issue-22684.rs +++ b/src/test/compile-fail/issue-22684.rs @@ -15,7 +15,7 @@ mod foo { } pub trait Baz { - fn bar(&self) -> bool {} + fn bar(&self) -> bool { true } } impl Baz for Foo {} } diff --git a/src/test/compile-fail/issue-29161.rs b/src/test/compile-fail/issue-29161.rs index bc09f61a754c2..97ba222fe45f0 100644 --- a/src/test/compile-fail/issue-29161.rs +++ b/src/test/compile-fail/issue-29161.rs @@ -13,7 +13,7 @@ mod a { impl Default for A { pub fn default() -> A { //~ ERROR unnecessary visibility qualifier - A; + A } } } diff --git a/src/test/compile-fail/issue-32323.rs b/src/test/compile-fail/issue-32323.rs index e3461e52e1c71..e5cb813032771 100644 --- a/src/test/compile-fail/issue-32323.rs +++ b/src/test/compile-fail/issue-32323.rs @@ -13,6 +13,6 @@ pub trait Tr<'a> { } pub fn f<'a, T: Tr<'a>>() -> >::Out {} -//~^ ERROR not all control paths return a value +//~^ ERROR mismatched types pub fn main() {} diff --git a/src/test/compile-fail/issue-5239-1.rs b/src/test/compile-fail/issue-5239-1.rs index 06e3c9a207b78..a77b27150d797 100644 --- a/src/test/compile-fail/issue-5239-1.rs +++ b/src/test/compile-fail/issue-5239-1.rs @@ -11,7 +11,7 @@ // Regression test for issue #5239 fn main() { - let x = |ref x: isize| -> isize { x += 1; }; + let x = |ref x: isize| { x += 1; }; //~^ ERROR E0368 //~| NOTE cannot use `+=` on type `&isize` } diff --git a/src/test/compile-fail/issue-6458-4.rs b/src/test/compile-fail/issue-6458-4.rs index c3f3a718ad0e2..a078cdea4ac4d 100644 --- a/src/test/compile-fail/issue-6458-4.rs +++ b/src/test/compile-fail/issue-6458-4.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(b: bool) -> Result { - Err("bar".to_string()); - //~^ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` - //~| NOTE type annotations or generic parameter binding +fn foo(b: bool) -> Result { //~ ERROR mismatched types + Err("bar".to_string()); //~ HELP consider removing this semicolon } fn main() { diff --git a/src/test/compile-fail/liveness-forgot-ret.rs b/src/test/compile-fail/liveness-forgot-ret.rs index e08515e40af78..1ee4be08a1c50 100644 --- a/src/test/compile-fail/liveness-forgot-ret.rs +++ b/src/test/compile-fail/liveness-forgot-ret.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: not all control paths return a value - fn god_exists(a: isize) -> bool { return god_exists(a); } fn f(a: isize) -> isize { if god_exists(a) { return 5; }; } +//~^ ERROR mismatched types fn main() { f(12); } diff --git a/src/test/compile-fail/liveness-issue-2163.rs b/src/test/compile-fail/liveness-issue-2163.rs index 7c94e33b47b38..69bceec8c3225 100644 --- a/src/test/compile-fail/liveness-issue-2163.rs +++ b/src/test/compile-fail/liveness-issue-2163.rs @@ -13,6 +13,6 @@ use std::vec::Vec; fn main() { let a: Vec = Vec::new(); a.iter().all(|_| -> bool { - //~^ ERROR not all control paths return a value + //~^ ERROR mismatched types }); } diff --git a/src/test/compile-fail/liveness-missing-ret2.rs b/src/test/compile-fail/liveness-missing-ret2.rs index b53bb6159e8dd..a35eb1af4f336 100644 --- a/src/test/compile-fail/liveness-missing-ret2.rs +++ b/src/test/compile-fail/liveness-missing-ret2.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: not all control paths return a value - -fn f() -> isize { +fn f() -> isize { //~ ERROR mismatched types // Make sure typestate doesn't interpret this match expression as // the function result match true { true => { } _ => {} }; diff --git a/src/test/compile-fail/liveness-return-last-stmt-semi.rs b/src/test/compile-fail/liveness-return-last-stmt-semi.rs index 03733cc2eb596..ada91c38d48c3 100644 --- a/src/test/compile-fail/liveness-return-last-stmt-semi.rs +++ b/src/test/compile-fail/liveness-return-last-stmt-semi.rs @@ -11,16 +11,16 @@ // regression test for #8005 macro_rules! test { () => { fn foo() -> i32 { 1; } } } - //~^ ERROR not all control paths return a value + //~^ ERROR mismatched types //~| HELP consider removing this semicolon -fn no_return() -> i32 {} //~ ERROR not all control paths return a value +fn no_return() -> i32 {} //~ ERROR mismatched types -fn bar(x: u32) -> u32 { //~ ERROR not all control paths return a value +fn bar(x: u32) -> u32 { //~ ERROR mismatched types x * 2; //~ HELP consider removing this semicolon } -fn baz(x: u64) -> u32 { //~ ERROR not all control paths return a value +fn baz(x: u64) -> u32 { //~ ERROR mismatched types x * 2; } diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs index 7434a6c960b2d..2878cbc7fc154 100644 --- a/src/test/compile-fail/main-wrong-type-2.rs +++ b/src/test/compile-fail/main-wrong-type-2.rs @@ -10,4 +10,5 @@ fn main() -> char { //~^ ERROR: main function has wrong type + ' ' } diff --git a/src/test/compile-fail/on-unimplemented/on-trait.rs b/src/test/compile-fail/on-unimplemented/on-trait.rs index 3a789f3faeb2a..0f4b0919b6500 100644 --- a/src/test/compile-fail/on-unimplemented/on-trait.rs +++ b/src/test/compile-fail/on-unimplemented/on-trait.rs @@ -16,7 +16,7 @@ trait Foo {} fn foobar>() -> T { - + panic!() } #[rustc_on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"] diff --git a/src/test/compile-fail/private-in-public-lint.rs b/src/test/compile-fail/private-in-public-lint.rs index 8e23bfcfb1051..4796548112d9e 100644 --- a/src/test/compile-fail/private-in-public-lint.rs +++ b/src/test/compile-fail/private-in-public-lint.rs @@ -13,7 +13,7 @@ mod m1 { struct Priv; impl Pub { - pub fn f() -> Priv {} //~ ERROR private type in public interface + pub fn f() -> Priv {Priv} //~ ERROR private type in public interface } } @@ -24,7 +24,7 @@ mod m2 { struct Priv; impl Pub { - pub fn f() -> Priv {} //~ ERROR private type in public interface + pub fn f() -> Priv {Priv} //~ ERROR private type in public interface } } diff --git a/src/test/compile-fail/required-lang-item.rs b/src/test/compile-fail/required-lang-item.rs index 1aa22a1676ef2..ce40702b3dc2a 100644 --- a/src/test/compile-fail/required-lang-item.rs +++ b/src/test/compile-fail/required-lang-item.rs @@ -11,6 +11,7 @@ #![feature(lang_items, no_core)] #![no_core] +#[lang="copy"] pub trait Copy { } #[lang="sized"] pub trait Sized { } // error-pattern:requires `start` lang_item diff --git a/src/test/compile-fail/unreachable-in-call.rs b/src/test/compile-fail/unreachable-in-call.rs index 5a3257d54db21..72462468432d9 100644 --- a/src/test/compile-fail/unreachable-in-call.rs +++ b/src/test/compile-fail/unreachable-in-call.rs @@ -24,7 +24,7 @@ fn diverge_first() { get_u8()); //~ ERROR unreachable expression } fn diverge_second() { - call( //~ ERROR unreachable call + call( //~ ERROR unreachable expression get_u8(), diverge()); } diff --git a/src/test/compile-fail/where-clauses-unsatisfied.rs b/src/test/compile-fail/where-clauses-unsatisfied.rs index 278a8db4e1ad4..ffc39008c4e5a 100644 --- a/src/test/compile-fail/where-clauses-unsatisfied.rs +++ b/src/test/compile-fail/where-clauses-unsatisfied.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn equal(_: &T, _: &T) -> bool where T : Eq { -} +fn equal(a: &T, b: &T) -> bool where T : Eq { a == b } struct Struct; From 9ce1044bd5460260f15c63df6f7f537466800f7d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 26 Oct 2016 07:39:04 +0300 Subject: [PATCH 7/9] tests: fix fallout in flowgraph graphviz comparison dot files. --- src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot | 4 +++- src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot | 4 +++- 26 files changed, 78 insertions(+), 26 deletions(-) diff --git a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot index f699771ef24c6..8ea8370ab235d 100644 --- a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot @@ -2,6 +2,8 @@ digraph block { N0[label="entry"]; N1[label="exit"]; N2[label="block { }"]; + N3[label="expr { }"]; N0 -> N2; - N2 -> N1; + N2 -> N3; + N3 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot index d924890b3118c..5982fbea76902 100644 --- a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot @@ -4,8 +4,10 @@ digraph block { N2[label="expr 1"]; N3[label="stmt 1;"]; N4[label="block { 1; }"]; + N5[label="expr { 1; }"]; N0 -> N2; N2 -> N3; N3 -> N4; - N4 -> N1; + N4 -> N5; + N5 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot index 1f4a58ba0a3c2..1639785bd68c0 100644 --- a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot @@ -4,8 +4,10 @@ digraph block { N2[label="local _x"]; N3[label="stmt let _x: isize;"]; N4[label="block { let _x: isize; }"]; + N5[label="expr { let _x: isize; }"]; N0 -> N2; N2 -> N3; N3 -> N4; - N4 -> N1; + N4 -> N5; + N5 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot index 8b6500761850f..b0ae00d81675a 100644 --- a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot @@ -6,10 +6,12 @@ digraph block { N4[label="expr 3 + 4"]; N5[label="stmt 3 + 4;"]; N6[label="block { 3 + 4; }"]; + N7[label="expr { 3 + 4; }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; - N6 -> N1; + N6 -> N7; + N7 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot index fde6cc2900550..41ace15a4c680 100644 --- a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot @@ -5,9 +5,11 @@ digraph block { N3[label="local _x"]; N4[label="stmt let _x = 4;"]; N5[label="block { let _x = 4; }"]; + N6[label="expr { let _x = 4; }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; - N5 -> N1; + N5 -> N6; + N6 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot index efd56cd0c75e4..72b8ae71751c2 100644 --- a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot @@ -9,6 +9,7 @@ digraph block { N7[label="pat (_x, _y)"]; N8[label="stmt let (_x, _y) = (5, 55);"]; N9[label="block { let (_x, _y) = (5, 55); }"]; + N10[label="expr { let (_x, _y) = (5, 55); }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -17,5 +18,6 @@ digraph block { N6 -> N7; N7 -> N8; N8 -> N9; - N9 -> N1; + N9 -> N10; + N10 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot index 54e9d89d3fb56..acba71ef625ff 100644 --- a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot @@ -7,11 +7,13 @@ digraph block { N5[label="pat S6 { val: _x }"]; N6[label="stmt let S6 { val: _x } = S6{val: 6,};"]; N7[label="block { let S6 { val: _x } = S6{val: 6,}; }"]; + N8[label="expr { let S6 { val: _x } = S6{val: 6,}; }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; N6 -> N7; - N7 -> N1; + N7 -> N8; + N8 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot index c60cd1cfd2774..251e2b39f14c8 100644 --- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot @@ -17,6 +17,7 @@ digraph block { N15[label="expr x + y"]; N16[label="stmt match [7, 77, 777, 7777] { [x, y, ..] => x + y, };"]; N17[label="block { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; + N18[label="expr { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -33,5 +34,6 @@ digraph block { N15 -> N7; N7 -> N16; N16 -> N17; - N17 -> N1; + N17 -> N18; + N18 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot index da0120b7bdc52..e2779c9414a9e 100644 --- a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot @@ -16,6 +16,7 @@ digraph block { N14[label="block { _y = 888; }"]; N15[label="expr if x > 88 { _y = 888; }"]; N16[label="block { let x = 8; let _y; if x > 88 { _y = 888; } }"]; + N17[label="expr { let x = 8; let _y; if x > 88 { _y = 888; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -32,5 +33,6 @@ digraph block { N9 -> N15; N14 -> N15; N15 -> N16; - N16 -> N1; + N16 -> N17; + N17 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot index c98d1b0bed5de..536abde91e81a 100644 --- a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot @@ -24,6 +24,7 @@ digraph block { N22[label="expr { _y = 94 + 95; }"]; N23[label="expr if x > 92 { _y = 93; } else { _y = 94 + 95; }"]; N24[label="block { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; + N25[label="expr { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -48,5 +49,6 @@ digraph block { N14 -> N23; N22 -> N23; N23 -> N24; - N24 -> N1; + N24 -> N25; + N25 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot index 516c39ef560a2..a3b531b1e2f41 100644 --- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot @@ -15,6 +15,7 @@ digraph block { N13[label="stmt x -= 1;"]; N14[label="block { x -= 1; }"]; N15[label="block { let mut x = 10; while x > 0 { x -= 1; } }"]; + N16[label="expr { let mut x = 10; while x > 0 { x -= 1; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -30,5 +31,6 @@ digraph block { N13 -> N14; N14 -> N5; N9 -> N15; - N15 -> N1; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot index 9b66fd581cb43..70034d299ba95 100644 --- a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot @@ -15,6 +15,7 @@ digraph block { N13[label="expr \"unreachable\""]; N14[label="stmt \"unreachable\";"]; N15[label="block { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; + N16[label="expr { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -29,5 +30,6 @@ digraph block { N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N1; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot index 071af6faf6f96..245afc43504c4 100644 --- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot @@ -22,6 +22,7 @@ digraph block { N20[label="expr if x == 2 { break ; \"unreachable\"; }"]; N21[label="block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; N22[label="block { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; + N23[label="expr { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -44,5 +45,6 @@ digraph block { N20 -> N21; N21 -> N5; N6 -> N22; - N22 -> N1; + N22 -> N23; + N23 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot index fb7d2ad97bd5f..0f268bd0f2aeb 100644 --- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot @@ -24,6 +24,7 @@ digraph block { N22[label="expr _y"]; N23[label="expr _y = v + 1"]; N24[label="block {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; + N25[label="expr {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -48,5 +49,6 @@ digraph block { N22 -> N23; N23 -> N10; N10 -> N24; - N24 -> N1; + N24 -> N25; + N25 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot index 66250aa441e43..719a6cf2619d3 100644 --- a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot @@ -15,6 +15,7 @@ digraph block { N13[label="block { return; \"unreachable\"; }"]; N14[label="expr if x > 1 { return; \"unreachable\"; }"]; N15[label="block { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; + N16[label="expr { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -30,5 +31,6 @@ digraph block { N7 -> N14; N13 -> N14; N14 -> N15; - N15 -> N1; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot index 4c94630f4e1fb..d8cbd8411e209 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -49,6 +49,7 @@ digraph block { N47[label="stmt x -= 5;"]; N48[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; N49[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; + N50[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -99,5 +100,6 @@ digraph block { N47 -> N48; N48 -> N8; N9 -> N49; - N49 -> N1; + N49 -> N50; + N50 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot index d7d027cefb59b..b11881247fb6a 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -52,6 +52,7 @@ digraph block { N50[label="expr \"unreachable\""]; N51[label="stmt \"unreachable\";"]; N52[label="block {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; + N53[label="expr {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -105,5 +106,6 @@ digraph block { N49 -> N50; N50 -> N51; N51 -> N52; - N52 -> N1; + N52 -> N53; + N53 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot index f87b70a71caea..705eece77558d 100644 --- a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot @@ -8,6 +8,7 @@ digraph block { N6[label="local _v"]; N7[label="stmt let _v = [1, 7, 17];"]; N8[label="block { let _v = [1, 7, 17]; }"]; + N9[label="expr { let _v = [1, 7, 17]; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -15,5 +16,6 @@ digraph block { N5 -> N6; N6 -> N7; N7 -> N8; - N8 -> N1; + N8 -> N9; + N9 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot index 8ea4256133296..c1d6e3023fbc1 100644 --- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot @@ -9,6 +9,7 @@ digraph block { N7[label="expr inner(inner(18))"]; N8[label="stmt inner(inner(18));"]; N9[label="block { inner(inner(18)); }"]; + N10[label="expr { inner(inner(18)); }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -17,5 +18,6 @@ digraph block { N6 -> N7; N7 -> N8; N8 -> N9; - N9 -> N1; + N9 -> N10; + N10 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot index bc0ca08d42257..d2f9f41f647be 100644 --- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot @@ -12,6 +12,7 @@ digraph block { N10[label="expr s.inner().inner()"]; N11[label="stmt s.inner().inner();"]; N12[label="block { let s = S19{x: 19,}; s.inner().inner(); }"]; + N13[label="expr { let s = S19{x: 19,}; s.inner().inner(); }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -23,5 +24,6 @@ digraph block { N9 -> N10; N10 -> N11; N11 -> N12; - N12 -> N1; + N12 -> N13; + N13 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot index 21e84fb858bcf..120eab4dac909 100644 --- a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot @@ -12,6 +12,7 @@ digraph block { N10[label="expr v[20]"]; N11[label="stmt v[20];"]; N12[label="block { let v = [2, 0, 20]; v[20]; }"]; + N13[label="expr { let v = [2, 0, 20]; v[20]; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -23,5 +24,6 @@ digraph block { N9 -> N10; N10 -> N11; N11 -> N12; - N12 -> N1; + N12 -> N13; + N13 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot index 796bf4910c9e2..370dcdd8554da 100644 --- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot @@ -47,6 +47,7 @@ digraph block { N45[label="stmt \"unreachable\";"]; N46[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l}\l"]; N47[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; + N48[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -95,5 +96,6 @@ digraph block { N45 -> N46; N46 -> N8; N9 -> N47; - N47 -> N1; + N47 -> N48; + N48 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot index 9e8049f07415a..9d3bc22831a13 100644 --- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot @@ -50,6 +50,7 @@ digraph block { N48[label="expr \"unreachable\""]; N49[label="stmt \"unreachable\";"]; N50[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; + N51[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -101,5 +102,6 @@ digraph block { N47 -> N48; N48 -> N49; N49 -> N50; - N50 -> N1; + N50 -> N51; + N51 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot index b3f285049c576..f152977438c50 100644 --- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot @@ -52,6 +52,7 @@ digraph block { N50[label="block { y -= 1; while z > 0 { z -= 1; } if x > 10 { return; \"unreachable\"; } }"]; N51[label="block {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; N52[label="block {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; + N53[label="expr {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -107,5 +108,6 @@ digraph block { N24 -> N51; N51 -> N11; N15 -> N52; - N52 -> N1; + N52 -> N53; + N53 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot index 43b3295bf3be9..e40dd014f0a4d 100644 --- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot @@ -76,6 +76,7 @@ digraph block { N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; N76[label="block {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; + N77[label="expr {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -155,5 +156,6 @@ digraph block { N29 -> N75; N75 -> N11; N12 -> N76; - N76 -> N1; + N76 -> N77; + N77 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot index 50fdffb781d11..1e2df1ab5e7b7 100644 --- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot @@ -76,6 +76,7 @@ digraph block { N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"]; N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l}\l"]; N76[label="block {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; + N77[label="expr {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -155,5 +156,6 @@ digraph block { N29 -> N75; N75 -> N11; N12 -> N76; - N76 -> N1; + N76 -> N77; + N77 -> N1; } From 8e9106c531c559bf923de93cccbeb0fa0a47451f Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 26 Oct 2016 10:43:34 +0300 Subject: [PATCH 8/9] tests: fix fallout in pretty-printing output exact-match tests. --- src/test/pretty/issue-4264.pp | 124 +++++++++++++----------- src/test/pretty/stmt_expr_attributes.rs | 22 +++-- 2 files changed, 80 insertions(+), 66 deletions(-) diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 40ff4852e3856..24b0f90d08e4d 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -18,18 +18,18 @@ // #4264 fixed-length vector types -pub fn foo(_: [i32; (3 as usize)]) { } +pub fn foo(_: [i32; (3 as usize)]) ({ } as ()) -pub fn bar() { - const FOO: usize = ((5 as usize) - (4 as usize) as usize); - let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); +pub fn bar() ({ + const FOO: usize = ((5 as usize) - (4 as usize) as usize); + let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); - let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); + let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); - let _ = - (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as &[i32; 3]) - as *const _ as *const [i32; 3]) as *const [i32; (3 as usize)] as - *const [i32; 3]); + let _ = + (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) + as &[i32; 3]) as *const _ as *const [i32; 3]) as + *const [i32; (3 as usize)] as *const [i32; 3]); @@ -38,58 +38,66 @@ - (($crate::fmt::format as - fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1 - as - fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({ - static __STATIC_FMTSTR: - &'static [&'static str] - = - (&([("test" - as - &'static str)] - as - [&'static str; 1]) - as - &'static [&'static str; 1]); - (__STATIC_FMTSTR - as - &'static [&'static str]) - } - as - &[&str]), - (&(match (() - as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1<'_>; 0]), - } - as - [std::fmt::ArgumentV1<'_>; 0]) - as - &[std::fmt::ArgumentV1<'_>; 0])) - as - std::fmt::Arguments<'_>)) - as std::string::String); -} + + (($crate::fmt::format as + fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1 + as + fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({ + static __STATIC_FMTSTR: + &'static [&'static str] + = + (&([("test" + as + &'static str)] + as + [&'static str; 1]) + as + &'static [&'static str; 1]); + (__STATIC_FMTSTR + as + &'static [&'static str]) + } + as + &[&str]), + (&(match (() + as + ()) + { + () + => + ([] + as + [std::fmt::ArgumentV1<'_>; 0]), + } + as + [std::fmt::ArgumentV1<'_>; 0]) + as + &[std::fmt::ArgumentV1<'_>; 0])) + as + std::fmt::Arguments<'_>)) + as std::string::String); + } as ()) pub type Foo = [i32; (3 as usize)]; pub struct Bar { pub x: [i32; (3 as usize)], } pub struct TupleBar([i32; (4 as usize)]); pub enum Baz { BazVariant([i32; (5 as usize)]), } -pub fn id(x: T) -> T { (x as T) } -pub fn use_id() { - let _ = - ((id::<[i32; (3 as usize)]> as - fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32), - (2 as i32), - (3 as i32)] as - [i32; 3])) as - [i32; 3]); -} -fn main() { } +pub fn id(x: T) -> T ({ (x as T) } as T) +pub fn use_id() ({ + let _ = + ((id::<[i32; (3 as usize)]> as + fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 + as + i32), + (2 + as + i32), + (3 + as + i32)] + as + [i32; 3])) + as [i32; 3]); + } as ()) +fn main() ({ } as ()) diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index e52932cd7befa..1c443020d2e93 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -198,14 +198,20 @@ fn _11() { }; let _ = #[attr] || #[attr] (); let _ = #[attr] move || #[attr] (); - let _ = #[attr] || { - #![attr] - #[attr] - () }; - let _ = #[attr] move || { - #![attr] - #[attr] - () }; + let _ = + #[attr] || + { + #![attr] + #[attr] + () + }; + let _ = + #[attr] move || + { + #![attr] + #[attr] + () + }; let _ = #[attr] { #![attr] From de0ffadb6722371b9eb636ee9b2d4627db9e02fa Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 10 Nov 2016 02:06:34 +0200 Subject: [PATCH 9/9] rustc: unify and simplify managing associated items. --- src/librustc/dep_graph/dep_node.rs | 12 +- src/librustc/middle/cstore.rs | 14 +- src/librustc/middle/dead.rs | 5 +- src/librustc/middle/expr_use_visitor.rs | 4 +- src/librustc/middle/stability.rs | 20 +- src/librustc/traits/error_reporting.rs | 14 +- src/librustc/traits/mod.rs | 20 +- src/librustc/traits/object_safety.rs | 48 +-- src/librustc/traits/project.rs | 26 +- src/librustc/traits/specialize/mod.rs | 3 +- .../traits/specialize/specialization_graph.rs | 142 +------ src/librustc/traits/util.rs | 16 +- src/librustc/ty/context.rs | 22 +- src/librustc/ty/maps.rs | 8 +- src/librustc/ty/mod.rs | 396 +++++++----------- src/librustc/util/ppaux.rs | 26 -- src/librustc_const_eval/eval.rs | 9 +- src/librustc_lint/bad_style.rs | 4 +- src/librustc_lint/builtin.rs | 12 +- src/librustc_metadata/cstore_impl.rs | 12 +- src/librustc_metadata/decoder.rs | 45 +- src/librustc_metadata/encoder.rs | 84 ++-- src/librustc_metadata/schema.rs | 10 +- src/librustc_mir/hair/cx/mod.rs | 22 +- src/librustc_passes/consts.rs | 4 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 24 +- src/librustc_save_analysis/lib.rs | 57 +-- src/librustc_trans/collector.rs | 21 +- src/librustc_trans/mir/constant.rs | 9 +- src/librustc_typeck/astconv.rs | 234 +++++------ src/librustc_typeck/check/compare_method.rs | 153 ++++--- src/librustc_typeck/check/dropck.rs | 6 +- src/librustc_typeck/check/method/confirm.rs | 90 ++-- src/librustc_typeck/check/method/mod.rs | 142 +++---- src/librustc_typeck/check/method/probe.rs | 109 ++--- src/librustc_typeck/check/method/suggest.rs | 31 +- src/librustc_typeck/check/mod.rs | 193 +++------ src/librustc_typeck/check/wfcheck.rs | 113 ++--- src/librustc_typeck/coherence/mod.rs | 24 +- src/librustc_typeck/coherence/overlap.rs | 30 +- src/librustc_typeck/collect.rs | 237 +++-------- src/librustdoc/clean/inline.rs | 51 +-- src/librustdoc/clean/mod.rs | 224 +++++----- 45 files changed, 1039 insertions(+), 1691 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e99ffa95ed63c..351feaba0346a 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -103,11 +103,11 @@ pub enum DepNode { // nodes. Often we map multiple tables to the same node if there // is no point in distinguishing them (e.g., both the type and // predicates for an item wind up in `ItemSignature`). - ImplOrTraitItems(D), + AssociatedItems(D), ItemSignature(D), FieldTy(D), SizedConstraint(D), - ImplOrTraitItemDefIds(D), + AssociatedItemDefIds(D), InherentImpls(D), // The set of impls for a given trait. Ultimately, it would be @@ -153,10 +153,10 @@ impl DepNode { TransCrateItem, TypeckItemType, TypeckItemBody, - ImplOrTraitItems, + AssociatedItems, ItemSignature, FieldTy, - ImplOrTraitItemDefIds, + AssociatedItemDefIds, InherentImpls, TraitImpls, ReprHints, @@ -219,11 +219,11 @@ impl DepNode { RvalueCheck(ref d) => op(d).map(RvalueCheck), TransCrateItem(ref d) => op(d).map(TransCrateItem), TransInlinedItem(ref d) => op(d).map(TransInlinedItem), - ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems), + AssociatedItems(ref d) => op(d).map(AssociatedItems), ItemSignature(ref d) => op(d).map(ItemSignature), FieldTy(ref d) => op(d).map(FieldTy), SizedConstraint(ref d) => op(d).map(SizedConstraint), - ImplOrTraitItemDefIds(ref d) => op(d).map(ImplOrTraitItemDefIds), + AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 59a5147ed1c16..a1f226ab11d80 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -147,7 +147,7 @@ pub trait CrateStore<'tcx> { fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info - fn impl_or_trait_items(&self, def_id: DefId) -> Vec; + fn associated_item_def_ids(&self, def_id: DefId) -> Vec; fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option>; fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity; @@ -157,8 +157,8 @@ pub trait CrateStore<'tcx> { // trait/impl-item info fn trait_of_item(&self, def_id: DefId) -> Option; - fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option>; + fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Option; // flags fn is_const_fn(&self, did: DefId) -> bool; @@ -311,8 +311,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { } // impl info - fn impl_or_trait_items(&self, def_id: DefId) -> Vec - { bug!("impl_or_trait_items") } + fn associated_item_def_ids(&self, def_id: DefId) -> Vec + { bug!("associated_items") } fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { bug!("impl_trait_ref") } fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") } @@ -323,8 +323,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // trait/impl-item info fn trait_of_item(&self, def_id: DefId) -> Option { bug!("trait_of_item") } - fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option> { bug!("impl_or_trait_item") } + fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Option { bug!("associated_item") } // flags fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 7fc698fdbebf5..294cdd3b7614b 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -471,11 +471,10 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { // This is done to handle the case where, for example, the static // method of a private type is used, but the type itself is never // called directly. - let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow(); if let Some(impl_list) = self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) { - for impl_did in impl_list.iter() { - for &item_did in &impl_items[impl_did][..] { + for &impl_did in impl_list.iter() { + for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] { if let Some(item_node_id) = self.tcx.map.as_local_node_id(item_did) { if self.live_symbols.contains(&item_node_id) { return true; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0543d1303a5f1..0127ac9dc7223 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -227,8 +227,8 @@ impl OverloadedCallType { } fn from_method_id(tcx: TyCtxt, method_id: DefId) -> OverloadedCallType { - let method = tcx.impl_or_trait_item(method_id); - OverloadedCallType::from_trait_id(tcx, method.container().id()) + let method = tcx.associated_item(method_id); + OverloadedCallType::from_trait_id(tcx, method.container.id()) } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f1755c82b8cbd..d79833998d6c8 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -529,14 +529,11 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // items. hir::ItemImpl(.., Some(ref t), _, ref impl_items) => { let trait_did = tcx.expect_def(t.ref_id).def_id(); - let trait_items = tcx.trait_items(trait_did); - for impl_item in impl_items { - let item = trait_items.iter().find(|item| { - item.name() == impl_item.name - }).unwrap(); + let item = tcx.associated_items(trait_did) + .find(|item| item.name == impl_item.name).unwrap(); if warn_about_defns { - maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb); + maybe_do_stability_check(tcx, item.def_id, impl_item.span, cb); } } } @@ -685,15 +682,8 @@ fn is_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) -> bool { } fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> bool { - match tcx.trait_item_of_item(id) { - Some(trait_method_id) if trait_method_id != id => { - is_staged_api(tcx, trait_method_id) - } - _ => { - *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with( - || tcx.sess.cstore.is_staged_api(id.krate)) - } - } + *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with( + || tcx.sess.cstore.is_staged_api(id.krate)) } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3522c738c160c..7e70fdb92e68b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -663,25 +663,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { in the supertrait listing" } - ObjectSafetyViolation::Method(method, + ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) => { - buf = format!("method `{}` has no receiver", - method.name); + buf = format!("method `{}` has no receiver", name); &buf } - ObjectSafetyViolation::Method(method, + ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) => { buf = format!("method `{}` references the `Self` type \ in its arguments or return type", - method.name); + name); &buf } - ObjectSafetyViolation::Method(method, + ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => { - buf = format!("method `{}` has generic type parameters", - method.name); + buf = format!("method `{}` has generic type parameters", name); &buf } }; diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 017b34d914f80..36405df6325af 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -578,18 +578,14 @@ pub fn get_vtable_methods<'a, 'tcx>( supertraits(tcx, trait_ref).flat_map(move |trait_ref| { tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id()); - let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id()); - let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| { - match tcx.impl_or_trait_item(trait_item_def_ids[i]) { - ty::MethodTraitItem(m) => Some(m), - _ => None - } - }); + let trait_methods = tcx.associated_items(trait_ref.def_id()) + .filter(|item| item.kind == ty::AssociatedKind::Method); // Now list each method's DefId and Substs (for within its trait). // If the method can never be called from this object, produce None. trait_methods.map(move |trait_method| { debug!("get_vtable_methods: trait_method={:?}", trait_method); + let def_id = trait_method.def_id; // Some methods cannot be called on an object; skip those. if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) { @@ -599,21 +595,21 @@ pub fn get_vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those - let substs = Substs::for_item(tcx, trait_method.def_id, - |_, _| tcx.mk_region(ty::ReErased), - |def, _| trait_ref.substs().type_for_def(def)); + let substs = Substs::for_item(tcx, def_id, + |_, _| tcx.mk_region(ty::ReErased), + |def, _| trait_ref.substs().type_for_def(def)); // It's possible that the method relies on where clauses that // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we // do not want to try and trans it, in that case (see #23435). - let predicates = trait_method.predicates.instantiate_own(tcx, substs); + let predicates = tcx.lookup_predicates(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { debug!("get_vtable_methods: predicates do not hold"); return None; } - Some((trait_method.def_id, substs)) + Some((def_id, substs)) }) }) } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 5f7b71518291a..c783bd561bb1a 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -22,11 +22,10 @@ use super::elaborate_predicates; use hir::def_id::DefId; use traits; use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; -use std::rc::Rc; use syntax::ast; #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum ObjectSafetyViolation<'tcx> { +pub enum ObjectSafetyViolation { /// Self : Sized declared on the trait SizedSelf, @@ -35,7 +34,7 @@ pub enum ObjectSafetyViolation<'tcx> { SupertraitSelf, /// Method has something illegal - Method(Rc>, MethodViolationCode), + Method(ast::Name, MethodViolationCode), } /// Reasons a method might not be object-safe. @@ -77,7 +76,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// because `object_safety_violations` can't be used during /// type collection. pub fn astconv_object_safety_violations(self, trait_def_id: DefId) - -> Vec> + -> Vec { let mut violations = vec![]; @@ -93,7 +92,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn object_safety_violations(self, trait_def_id: DefId) - -> Vec> + -> Vec { traits::supertrait_def_ids(self, trait_def_id) .flat_map(|def_id| self.object_safety_violations_for_trait(def_id)) @@ -101,21 +100,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } fn object_safety_violations_for_trait(self, trait_def_id: DefId) - -> Vec> + -> Vec { // Check methods for violations. - let mut violations: Vec<_> = - self.trait_items(trait_def_id).iter() + let mut violations: Vec<_> = self.associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssociatedKind::Method) .filter_map(|item| { - match *item { - ty::MethodTraitItem(ref m) => { - self.object_safety_violation_for_method(trait_def_id, &m) - .map(|code| ObjectSafetyViolation::Method(m.clone(), code)) - } - _ => None, - } - }) - .collect(); + self.object_safety_violation_for_method(trait_def_id, &item) + .map(|code| ObjectSafetyViolation::Method(item.name, code)) + }).collect(); // Check the trait itself. if self.trait_has_sized_self(trait_def_id) { @@ -198,7 +191,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns `Some(_)` if this method makes the containing trait not object safe. fn object_safety_violation_for_method(self, trait_def_id: DefId, - method: &ty::Method<'gcx>) + method: &ty::AssociatedItem) -> Option { // Any method that has a `Self : Sized` requisite is otherwise @@ -216,7 +209,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// otherwise ensure that they cannot be used when `Self=Trait`. pub fn is_vtable_safe_method(self, trait_def_id: DefId, - method: &ty::Method<'gcx>) + method: &ty::AssociatedItem) -> bool { // Any method that has a `Self : Sized` requisite can't be called. @@ -233,26 +226,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// `Self:Sized`. fn virtual_call_violation_for_method(self, trait_def_id: DefId, - method: &ty::Method<'tcx>) + method: &ty::AssociatedItem) -> Option { // The method's first parameter must be something that derefs (or // autorefs) to `&self`. For now, we only accept `self`, `&self` // and `Box`. - match method.explicit_self { - ty::ExplicitSelfCategory::Static => { - return Some(MethodViolationCode::StaticMethod); - } - - ty::ExplicitSelfCategory::ByValue | - ty::ExplicitSelfCategory::ByReference(..) | - ty::ExplicitSelfCategory::ByBox => { - } + if !method.method_has_self_argument { + return Some(MethodViolationCode::StaticMethod); } // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. - let ref sig = method.fty.sig; + let ref sig = self.lookup_item_type(method.def_id).ty.fn_sig(); for &input_ty in &sig.0.inputs[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); @@ -263,7 +249,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if !method.generics.types.is_empty() { + if !self.lookup_generics(method.def_id).types.is_empty() { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index ce882c48377f7..b1ab61b09757e 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,8 +33,6 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; -use std::rc::Rc; - /// Depending on the stage of compilation, we want projection to be /// more or less conservative. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -945,7 +943,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // an error when we confirm the candidate // (which will ultimately lead to `normalize_to_error` // being invoked). - node_item.item.ty.is_some() + node_item.item.has_value } else { node_item.item.defaultness.is_default() }; @@ -1305,7 +1303,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( match assoc_ty { Some(node_item) => { - let ty = node_item.item.ty.unwrap_or_else(|| { + let ty = if !node_item.item.has_value { // This means that the impl is missing a definition for the // associated type. This error will be reported by the type // checker method `check_impl_items_against_trait`, so here we @@ -1314,7 +1312,9 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( node_item.item.name, obligation.predicate.trait_ref); tcx.types.err - }); + } else { + tcx.lookup_item_type(node_item.item.def_id).ty + }; let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); Progress { ty: ty.subst(tcx, substs), @@ -1339,27 +1339,25 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( selcx: &SelectionContext<'cx, 'gcx, 'tcx>, impl_def_id: DefId, assoc_ty_name: ast::Name) - -> Option>>> + -> Option> { let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; if selcx.projection_mode() == Reveal::ExactMatch { let impl_node = specialization_graph::Node::Impl(impl_def_id); for item in impl_node.items(selcx.tcx()) { - if let ty::TypeTraitItem(assoc_ty) = item { - if assoc_ty.name == assoc_ty_name { - return Some(specialization_graph::NodeItem { - node: specialization_graph::Node::Impl(impl_def_id), - item: assoc_ty, - }); - } + if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name { + return Some(specialization_graph::NodeItem { + node: specialization_graph::Node::Impl(impl_def_id), + item: item, + }); } } None } else { selcx.tcx().lookup_trait_def(trait_def_id) .ancestors(impl_def_id) - .type_defs(selcx.tcx(), assoc_ty_name) + .defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type) .next() } } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 4eef6944974c0..91c40a5cc8516 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -120,7 +120,8 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); let trait_def = tcx.lookup_trait_def(trait_def_id); - match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() { + let ancestors = trait_def.ancestors(impl_data.impl_def_id); + match ancestors.defs(tcx, name, ty::AssociatedKind::Method).next() { Some(node_item) => { let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index c746145474c75..5a6809f1fad68 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::rc::Rc; - use super::{OverlapError, specializes}; use hir::def_id::DefId; use traits::{self, Reveal}; -use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable}; +use ty::{self, TyCtxt, TraitDef, TypeFoldable}; use ty::fast_reject::{self, SimplifiedType}; use syntax::ast::Name; use util::nodemap::{DefIdMap, FxHashMap}; @@ -285,12 +283,10 @@ impl<'a, 'gcx, 'tcx> Node { } /// Iterate over the items defined directly by the given (impl or trait) node. - pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> NodeItems<'a, 'gcx> { - NodeItems { - tcx: tcx.global_tcx(), - items: tcx.impl_or_trait_items(self.def_id()), - idx: 0, - } + #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. + pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) + -> impl Iterator + 'a { + tcx.associated_items(self.def_id()) } pub fn def_id(&self) -> DefId { @@ -301,28 +297,6 @@ impl<'a, 'gcx, 'tcx> Node { } } -/// An iterator over the items defined within a trait or impl. -pub struct NodeItems<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - items: Rc>, - idx: usize -} - -impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> { - type Item = ImplOrTraitItem<'tcx>; - fn next(&mut self) -> Option> { - if self.idx < self.items.len() { - let item_def_id = self.items[self.idx]; - let items_table = self.tcx.impl_or_trait_items.borrow(); - let item = items_table[&item_def_id].clone(); - self.idx += 1; - Some(item) - } else { - None - } - } -} - pub struct Ancestors<'a, 'tcx: 'a> { trait_def: &'a TraitDef<'tcx>, current_source: Option, @@ -358,104 +332,16 @@ impl NodeItem { } } -pub struct TypeDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - -pub struct FnDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - -pub struct ConstDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - impl<'a, 'gcx, 'tcx> Ancestors<'a, 'tcx> { - /// Search the items from the given ancestors, returning each type definition - /// with the given name. - pub fn type_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> TypeDefs<'a, 'gcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::TypeTraitItem(assoc_ty) = item { - if assoc_ty.name == name { - return Some(NodeItem { - node: node, - item: assoc_ty, - }); - } - } - None - }) - - }); - TypeDefs { iter: Box::new(iter) } - } - - /// Search the items from the given ancestors, returning each fn definition - /// with the given name. - pub fn fn_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> FnDefs<'a, 'gcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::MethodTraitItem(method) = item { - if method.name == name { - return Some(NodeItem { - node: node, - item: method, - }); - } - } - None - }) - - }); - FnDefs { iter: Box::new(iter) } - } - - /// Search the items from the given ancestors, returning each const - /// definition with the given name. - pub fn const_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> ConstDefs<'a, 'gcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::ConstTraitItem(konst) = item { - if konst.name == name { - return Some(NodeItem { - node: node, - item: konst, - }); - } - } - None - }) - - }); - ConstDefs { iter: Box::new(iter) } + /// Search the items from the given ancestors, returning each definition + /// with the given name and the given kind. + #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. + pub fn defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name, kind: ty::AssociatedKind) + -> impl Iterator> + 'a { + self.flat_map(move |node| { + node.items(tcx).filter(move |item| item.kind == kind && item.name == name) + .map(move |item| NodeItem { node: node, item: item }) + }) } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 52830164d1d91..9346bbd30f9ce 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -477,8 +477,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let mut entries = 0; // Count number of methods and add them to the total offset. // Skip over associated types and constants. - for trait_item in &self.trait_items(trait_ref.def_id())[..] { - if let ty::MethodTraitItem(_) = *trait_item { + for trait_item in self.associated_items(trait_ref.def_id()) { + if trait_item.kind == ty::AssociatedKind::Method { entries += 1; } } @@ -495,17 +495,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // add them to the total offset. // Skip over associated types and constants. let mut entries = object.vtable_base; - for trait_item in &self.trait_items(object.upcast_trait_ref.def_id())[..] { - if trait_item.def_id() == method_def_id { + for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) { + if trait_item.def_id == method_def_id { // The item with the ID we were given really ought to be a method. - assert!(match *trait_item { - ty::MethodTraitItem(_) => true, - _ => false - }); - + assert_eq!(trait_item.kind, ty::AssociatedKind::Method); return entries; } - if let ty::MethodTraitItem(_) = *trait_item { + if trait_item.kind == ty::AssociatedKind::Method { entries += 1; } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index b19f935123519..60a48ba580a0d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -403,14 +403,10 @@ pub struct GlobalCtxt<'tcx> { pub tables: RefCell>, /// Maps from a trait item to the trait item "descriptor" - pub impl_or_trait_items: RefCell>>, + pub associated_items: RefCell>>, /// Maps from an impl/trait def-id to a list of the def-ids of its items - pub impl_or_trait_item_def_ids: RefCell>>, - - /// A cache for the trait_items() routine; note that the routine - /// itself pushes the `TraitItems` dependency node. - trait_items_cache: RefCell>>, + pub associated_item_def_ids: RefCell>>, pub impl_trait_refs: RefCell>>, pub trait_defs: RefCell>>, @@ -822,9 +818,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), rcache: RefCell::new(FxHashMap()), tc_cache: RefCell::new(FxHashMap()), - impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - impl_or_trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - trait_items_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + associated_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + associated_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), ty_param_defs: RefCell::new(NodeMap()), normalized_cache: RefCell::new(FxHashMap()), lang_items: lang_items, @@ -1539,15 +1534,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from)) } - pub fn trait_items(self, trait_did: DefId) -> Rc>> { - self.trait_items_cache.memoize(trait_did, || { - let def_ids = self.impl_or_trait_items(trait_did); - Rc::new(def_ids.iter() - .map(|&def_id| self.impl_or_trait_item(def_id)) - .collect()) - }) - } - /// Obtain the representation annotation for a struct definition. pub fn lookup_repr_hints(self, did: DefId) -> Rc> { self.repr_hint_cache.memoize(did, || { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index cad87081a93b4..43abb61e7fcd8 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -16,7 +16,7 @@ use ty::{self, Ty}; use std::cell::RefCell; use std::marker::PhantomData; use std::rc::Rc; -use syntax::{attr, ast}; +use syntax::attr; macro_rules! dep_map_ty { ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => { @@ -32,18 +32,16 @@ macro_rules! dep_map_ty { } } -dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> } +dep_map_ty! { AssociatedItems: AssociatedItems(DefId) -> ty::AssociatedItem } dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> } dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> } dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } -dep_map_ty! { ImplOrTraitItemDefIds: ImplOrTraitItemDefIds(DefId) -> Rc> } +dep_map_ty! { AssociatedItemDefIds: AssociatedItemDefIds(DefId) -> Rc> } dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option> } dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc> } dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec } -dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc> } -dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId } dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index fcf9b5ff2730c..1d260fd65feff 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -10,9 +10,8 @@ pub use self::Variance::*; pub use self::DtorKind::*; -pub use self::ImplOrTraitItemContainer::*; +pub use self::AssociatedItemContainer::*; pub use self::BorrowKind::*; -pub use self::ImplOrTraitItem::*; pub use self::IntVarValue::*; pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; @@ -135,12 +134,12 @@ impl DtorKind { } #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum ImplOrTraitItemContainer { +pub enum AssociatedItemContainer { TraitContainer(DefId), ImplContainer(DefId), } -impl ImplOrTraitItemContainer { +impl AssociatedItemContainer { pub fn id(&self) -> DefId { match *self { TraitContainer(id) => id, @@ -183,58 +182,34 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { } } -#[derive(Clone)] -pub enum ImplOrTraitItem<'tcx> { - ConstTraitItem(Rc>), - MethodTraitItem(Rc>), - TypeTraitItem(Rc>), -} - -impl<'tcx> ImplOrTraitItem<'tcx> { - pub fn def(&self) -> Def { - match *self { - ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id), - MethodTraitItem(ref method) => Def::Method(method.def_id), - TypeTraitItem(ref ty) => Def::AssociatedTy(ty.def_id), - } - } - - pub fn def_id(&self) -> DefId { - match *self { - ConstTraitItem(ref associated_const) => associated_const.def_id, - MethodTraitItem(ref method) => method.def_id, - TypeTraitItem(ref associated_type) => associated_type.def_id, - } - } - - pub fn name(&self) -> Name { - match *self { - ConstTraitItem(ref associated_const) => associated_const.name, - MethodTraitItem(ref method) => method.name, - TypeTraitItem(ref associated_type) => associated_type.name, - } - } +#[derive(Copy, Clone, Debug)] +pub struct AssociatedItem { + pub def_id: DefId, + pub name: Name, + pub kind: AssociatedKind, + pub vis: Visibility, + pub defaultness: hir::Defaultness, + pub has_value: bool, + pub container: AssociatedItemContainer, - pub fn vis(&self) -> Visibility { - match *self { - ConstTraitItem(ref associated_const) => associated_const.vis, - MethodTraitItem(ref method) => method.vis, - TypeTraitItem(ref associated_type) => associated_type.vis, - } - } + /// Whether this is a method with an explicit self + /// as its first argument, allowing method calls. + pub method_has_self_argument: bool, +} - pub fn container(&self) -> ImplOrTraitItemContainer { - match *self { - ConstTraitItem(ref associated_const) => associated_const.container, - MethodTraitItem(ref method) => method.container, - TypeTraitItem(ref associated_type) => associated_type.container, - } - } +#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] +pub enum AssociatedKind { + Const, + Method, + Type +} - pub fn as_opt_method(&self) -> Option>> { - match *self { - MethodTraitItem(ref m) => Some((*m).clone()), - _ => None, +impl AssociatedItem { + pub fn def(&self) -> Def { + match self.kind { + AssociatedKind::Const => Def::AssociatedConst(self.def_id), + AssociatedKind::Method => Def::Method(self.def_id), + AssociatedKind::Type => Def::AssociatedTy(self.def_id), } } } @@ -308,64 +283,6 @@ impl Visibility { } } -#[derive(Clone, Debug)] -pub struct Method<'tcx> { - pub name: Name, - pub generics: &'tcx Generics<'tcx>, - pub predicates: GenericPredicates<'tcx>, - pub fty: &'tcx BareFnTy<'tcx>, - pub explicit_self: ExplicitSelfCategory<'tcx>, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub has_body: bool, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, -} - -impl<'tcx> Method<'tcx> { - pub fn container_id(&self) -> DefId { - match self.container { - TraitContainer(id) => id, - ImplContainer(id) => id, - } - } -} - -impl<'tcx> PartialEq for Method<'tcx> { - #[inline] - fn eq(&self, other: &Self) -> bool { self.def_id == other.def_id } -} - -impl<'tcx> Eq for Method<'tcx> {} - -impl<'tcx> Hash for Method<'tcx> { - #[inline] - fn hash(&self, s: &mut H) { - self.def_id.hash(s) - } -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedConst<'tcx> { - pub name: Name, - pub ty: Ty<'tcx>, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, - pub has_value: bool -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedType<'tcx> { - pub name: Name, - pub ty: Option>, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, -} - #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type @@ -1288,19 +1205,10 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { tcx.region_maps.item_extent(id)) } hir::ImplItemKind::Method(_, ref body) => { - let method_def_id = tcx.map.local_def_id(id); - match tcx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - tcx.construct_parameter_environment( - impl_item.span, - method_ty.def_id, - tcx.region_maps.call_site_extent(id, body.id)) - } - _ => { - bug!("ParameterEnvironment::for_item(): \ - got non-method item from impl method?!") - } - } + tcx.construct_parameter_environment( + impl_item.span, + tcx.map.local_def_id(id), + tcx.region_maps.call_site_extent(id, body.id)) } } } @@ -1319,27 +1227,17 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { // Use call-site for extent (unless this is a // trait method with no default; then fallback // to the method id). - let method_def_id = tcx.map.local_def_id(id); - match tcx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - let extent = if let Some(ref body) = *body { - // default impl: use call_site extent as free_id_outlive bound. - tcx.region_maps.call_site_extent(id, body.id) - } else { - // no default impl: use item extent as free_id_outlive bound. - tcx.region_maps.item_extent(id) - }; - tcx.construct_parameter_environment( - trait_item.span, - method_ty.def_id, - extent) - } - _ => { - bug!("ParameterEnvironment::for_item(): \ - got non-method item from provided \ - method?!") - } - } + let extent = if let Some(ref body) = *body { + // default impl: use call_site extent as free_id_outlive bound. + tcx.region_maps.call_site_extent(id, body.id) + } else { + // no default impl: use item extent as free_id_outlive bound. + tcx.region_maps.item_extent(id) + }; + tcx.construct_parameter_environment( + trait_item.span, + tcx.map.local_def_id(id), + extent) } } } @@ -2065,7 +1963,7 @@ impl LvaluePreference { } /// Helper for looking things up in the various maps that are populated during -/// typeck::collect (e.g., `tcx.impl_or_trait_items`, `tcx.tcache`, etc). All of +/// typeck::collect (e.g., `tcx.associated_items`, `tcx.tcache`, etc). All of /// these share the pattern that if the id is local, it should have been loaded /// into the map by the `typeck::collect` phase. If the def-id is external, /// then we have to go consult the crate loading code (and cache the result for @@ -2204,13 +2102,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn provided_trait_methods(self, id: DefId) -> Vec>> { - self.impl_or_trait_items(id).iter().filter_map(|&def_id| { - match self.impl_or_trait_item(def_id) { - MethodTraitItem(ref m) if m.has_body => Some(m.clone()), - _ => None - } - }).collect() + pub fn provided_trait_methods(self, id: DefId) -> Vec { + self.associated_items(id) + .filter(|item| item.kind == AssociatedKind::Method && item.has_value) + .collect() } pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity { @@ -2243,17 +2138,105 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } - pub fn impl_or_trait_item(self, id: DefId) -> ImplOrTraitItem<'gcx> { - lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &self.impl_or_trait_items, - || self.sess.cstore.impl_or_trait_item(self.global_tcx(), id) - .expect("missing ImplOrTraitItem in metadata")) + pub fn associated_item(self, def_id: DefId) -> AssociatedItem { + self.associated_items.memoize(def_id, || { + if !def_id.is_local() { + return self.sess.cstore.associated_item(self.global_tcx(), def_id) + .expect("missing AssociatedItem in metadata"); + } + + let id = self.map.as_local_node_id(def_id).unwrap(); + let parent_id = self.map.get_parent(id); + let parent_def_id = self.map.local_def_id(parent_id); + match self.map.get(id) { + ast_map::NodeTraitItem(trait_item) => { + let (kind, has_self, has_value) = match trait_item.node { + hir::MethodTraitItem(ref sig, ref body) => { + (AssociatedKind::Method, sig.decl.get_self().is_some(), + body.is_some()) + } + hir::ConstTraitItem(_, ref value) => { + (AssociatedKind::Const, false, value.is_some()) + } + hir::TypeTraitItem(_, ref ty) => { + (AssociatedKind::Type, false, ty.is_some()) + } + }; + + AssociatedItem { + name: trait_item.name, + kind: kind, + vis: Visibility::from_hir(&hir::Inherited, id, self), + defaultness: hir::Defaultness::Default, + has_value: has_value, + def_id: def_id, + container: TraitContainer(parent_def_id), + method_has_self_argument: has_self + } + } + ast_map::NodeImplItem(impl_item) => { + let (kind, has_self) = match impl_item.node { + hir::ImplItemKind::Method(ref sig, _) => { + (AssociatedKind::Method, sig.decl.get_self().is_some()) + } + hir::ImplItemKind::Const(..) => (AssociatedKind::Const, false), + hir::ImplItemKind::Type(..) => (AssociatedKind::Type, false) + }; + + // Trait impl items are always public. + let public = hir::Public; + let parent_item = self.map.expect_item(parent_id); + let vis = if let hir::ItemImpl(.., Some(_), _, _) = parent_item.node { + &public + } else { + &impl_item.vis + }; + + AssociatedItem { + name: impl_item.name, + kind: kind, + vis: Visibility::from_hir(vis, id, self), + defaultness: impl_item.defaultness, + has_value: true, + def_id: def_id, + container: ImplContainer(parent_def_id), + method_has_self_argument: has_self + } + } + item => bug!("associated_item: {:?} not an associated item", item) + } + }) } - pub fn impl_or_trait_items(self, id: DefId) -> Rc> { - lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &self.impl_or_trait_item_def_ids, - || Rc::new(self.sess.cstore.impl_or_trait_items(id))) + pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { + self.associated_item_def_ids.memoize(def_id, || { + if !def_id.is_local() { + return Rc::new(self.sess.cstore.associated_item_def_ids(def_id)); + } + + let id = self.map.as_local_node_id(def_id).unwrap(); + let item = self.map.expect_item(id); + match item.node { + hir::ItemTrait(.., ref trait_items) => { + Rc::new(trait_items.iter().map(|trait_item| { + self.map.local_def_id(trait_item.id) + }).collect()) + } + hir::ItemImpl(.., ref impl_items) => { + Rc::new(impl_items.iter().map(|impl_item| { + self.map.local_def_id(impl_item.id) + }).collect()) + } + _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") + } + }) + } + + #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. + pub fn associated_items(self, def_id: DefId) + -> impl Iterator + 'a { + let def_ids = self.associated_item_def_ids(def_id); + (0..def_ids.len()).map(move |i| self.associated_item(def_ids[i])) } /// Returns the trait-ref corresponding to a given impl, or None if it is @@ -2539,31 +2522,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) } - /// Load primitive inherent implementations if necessary - pub fn populate_implementations_for_primitive_if_necessary(self, - primitive_def_id: DefId) { - if primitive_def_id.is_local() { - return - } - - // The primitive is not local, hence we are reading this out - // of metadata. - let _ignore = self.dep_graph.in_ignore(); - - if self.populated_external_primitive_impls.borrow().contains(&primitive_def_id) { - return - } - - debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", - primitive_def_id); - - let impl_items = self.sess.cstore.impl_or_trait_items(primitive_def_id); - - // Store the implementation info. - self.impl_or_trait_item_def_ids.borrow_mut().insert(primitive_def_id, Rc::new(impl_items)); - self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); - } - /// Populates the type context with all the inherent implementations for /// the given type if necessary. pub fn populate_inherent_implementations_for_type_if_necessary(self, @@ -2584,11 +2542,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { type_id); let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id); - for &impl_def_id in &inherent_impls { - // Store the implementation info. - let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id); - self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); - } self.inherent_impls.borrow_mut().insert(type_id, inherent_impls); self.populated_external_types.borrow_mut().insert(type_id); @@ -2617,23 +2570,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) { - let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id); let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); // Record the trait->implementation mapping. let parent = self.sess.cstore.impl_parent(impl_def_id).unwrap_or(trait_id); def.record_remote_impl(self, impl_def_id, trait_ref, parent); - - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for &impl_item_def_id in &impl_items { - // load impl items eagerly for convenience - // FIXME: we may want to load these lazily - self.impl_or_trait_item(impl_item_def_id); - } - - // Store the implementation info. - self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); } def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); @@ -2679,17 +2620,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// ID of the impl that the method belongs to. Otherwise, return `None`. pub fn impl_of_method(self, def_id: DefId) -> Option { if def_id.krate != LOCAL_CRATE { - return self.sess.cstore.impl_or_trait_item(self.global_tcx(), def_id) + return self.sess.cstore.associated_item(self.global_tcx(), def_id) .and_then(|item| { - match item.container() { + match item.container { TraitContainer(_) => None, ImplContainer(def_id) => Some(def_id), } }); } - match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + match self.associated_items.borrow().get(&def_id).cloned() { Some(trait_item) => { - match trait_item.container() { + match trait_item.container { TraitContainer(_) => None, ImplContainer(def_id) => Some(def_id), } @@ -2705,9 +2646,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if def_id.krate != LOCAL_CRATE { return self.sess.cstore.trait_of_item(def_id); } - match self.impl_or_trait_items.borrow().get(&def_id) { - Some(impl_or_trait_item) => { - match impl_or_trait_item.container() { + match self.associated_items.borrow().get(&def_id) { + Some(associated_item) => { + match associated_item.container { TraitContainer(def_id) => Some(def_id), ImplContainer(_) => None } @@ -2716,30 +2657,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// If the given def ID describes an item belonging to a trait, (either a - /// default method or an implementation of a trait method), return the ID of - /// the method inside trait definition (this means that if the given def ID - /// is already that of the original trait method, then the return value is - /// the same). - /// Otherwise, return `None`. - pub fn trait_item_of_item(self, def_id: DefId) -> Option { - let impl_or_trait_item = match self.impl_or_trait_items.borrow().get(&def_id) { - Some(m) => m.clone(), - None => return None, - }; - match impl_or_trait_item.container() { - TraitContainer(_) => Some(impl_or_trait_item.def_id()), - ImplContainer(def_id) => { - self.trait_id_of_impl(def_id).and_then(|trait_did| { - let name = impl_or_trait_item.name(); - self.trait_items(trait_did).iter() - .find(|item| item.name() == name) - .map(|item| item.def_id()) - }) - } - } - } - /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { @@ -2856,15 +2773,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -/// The category of explicit self. -#[derive(Clone, Copy, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)] -pub enum ExplicitSelfCategory<'tcx> { - Static, - ByValue, - ByReference(&'tcx Region, hir::Mutability), - ByBox, -} - impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn with_freevars(self, fid: NodeId, f: F) -> T where F: FnOnce(&[hir::Freevar]) -> T, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 31304fb7b4993..01b44ced8e08e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -670,18 +670,6 @@ impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ImplOrTraitItem<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ImplOrTraitItem(")?; - match *self { - ty::ImplOrTraitItem::MethodTraitItem(ref i) => write!(f, "{:?}", i), - ty::ImplOrTraitItem::ConstTraitItem(ref i) => write!(f, "{:?}", i), - ty::ImplOrTraitItem::TypeTraitItem(ref i) => write!(f, "{:?}", i), - }?; - write!(f, ")") - } -} - impl<'tcx> fmt::Display for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "fn")?; @@ -995,20 +983,6 @@ impl fmt::Display for ty::InferTy { } } -impl<'tcx> fmt::Display for ty::ExplicitSelfCategory<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match *self { - ty::ExplicitSelfCategory::Static => "static", - ty::ExplicitSelfCategory::ByValue => "self", - ty::ExplicitSelfCategory::ByReference(_, hir::MutMutable) => { - "&mut self" - } - ty::ExplicitSelfCategory::ByReference(_, hir::MutImmutable) => "&self", - ty::ExplicitSelfCategory::ByBox => "Box", - }) - } -} - impl fmt::Display for ty::ParamTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.name) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 57a5400ecadf8..08b8f4c8941cc 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -1091,13 +1091,8 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // when constructing the inference context above. match selection { traits::VtableImpl(ref impl_data) => { - let ac = tcx.impl_or_trait_items(impl_data.impl_def_id) - .iter().filter_map(|&def_id| { - match tcx.impl_or_trait_item(def_id) { - ty::ConstTraitItem(ic) => Some(ic), - _ => None - } - }).find(|ic| ic.name == ti.name); + let ac = tcx.associated_items(impl_data.impl_def_id) + .find(|item| item.kind == ty::AssociatedKind::Const && item.name == ti.name); match ac { Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), None => match ti.node { diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index fea3de59520ca..28d45080284cd 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -29,10 +29,10 @@ pub enum MethodLateContext { pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext { let def_id = cx.tcx.map.local_def_id(id); - match cx.tcx.impl_or_trait_items.borrow().get(&def_id) { + match cx.tcx.associated_items.borrow().get(&def_id) { None => span_bug!(span, "missing method descriptor?!"), Some(item) => { - match item.container() { + match item.container { ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl, ty::ImplContainer(cid) => { match cx.tcx.impl_trait_ref(cid) { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 28dc71fd59bae..af05724d9f951 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -818,7 +818,7 @@ impl LateLintPass for UnconditionalRecursion { let method = match fn_kind { FnKind::ItemFn(..) => None, FnKind::Method(..) => { - cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method() + Some(cx.tcx.associated_item(cx.tcx.map.local_def_id(id))) } // closures can't recur, so they don't matter. FnKind::Closure(_) => return, @@ -937,7 +937,7 @@ impl LateLintPass for UnconditionalRecursion { // Check if the expression `id` performs a call to `method`. fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - method: &ty::Method, + method: &ty::AssociatedItem, id: ast::NodeId) -> bool { use rustc::ty::adjustment::*; @@ -986,14 +986,14 @@ impl LateLintPass for UnconditionalRecursion { // Check if the method call to the method with the ID `callee_id` // and instantiated with `callee_substs` refers to method `method`. fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - method: &ty::Method, + method: &ty::AssociatedItem, callee_id: DefId, callee_substs: &Substs<'tcx>, expr_id: ast::NodeId) -> bool { - let callee_item = tcx.impl_or_trait_item(callee_id); + let callee_item = tcx.associated_item(callee_id); - match callee_item.container() { + match callee_item.container { // This is an inherent method, so the `def_id` refers // directly to the method definition. ty::ImplContainer(_) => callee_id == method.def_id, @@ -1034,7 +1034,7 @@ impl LateLintPass for UnconditionalRecursion { let container = ty::ImplContainer(vtable_impl.impl_def_id); // It matches if it comes from the same impl, // and has the same method name. - container == method.container && callee_item.name() == method.name + container == method.container && callee_item.name == method.name } // There's no way to know if this call is diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index a618c98ff774c..18ce514c9c42d 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -144,7 +144,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn impl_or_trait_items(&self, def_id: DefId) -> Vec { + fn associated_item_def_ids(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; self.get_crate_data(def_id.krate) @@ -182,11 +182,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index) } - fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option> + fn associated_item<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Option { self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).get_impl_or_trait_item(def.index, tcx) + self.get_crate_data(def.krate).get_associated_item(def.index) } fn is_const_fn(&self, did: DefId) -> bool @@ -427,9 +427,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { // the logic to do that already exists in `middle`. In order to // reuse that code, it needs to be able to look up the traits for // inlined items. - let ty_trait_item = tcx.impl_or_trait_item(def_id).clone(); + let ty_trait_item = tcx.associated_item(def_id).clone(); let trait_item_def_id = tcx.map.local_def_id(trait_item.id); - tcx.impl_or_trait_items.borrow_mut() + tcx.associated_items.borrow_mut() .insert(trait_item_def_id, ty_trait_item); } Some(&InlinedItem::ImplItem(_, ref impl_item)) => { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 630b07744249b..7973cd880fe34 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -36,7 +36,6 @@ use std::borrow::Cow; use std::cell::Ref; use std::io; use std::mem; -use std::rc::Rc; use std::str; use std::u32; @@ -792,10 +791,7 @@ impl<'a, 'tcx> CrateMetadata { self.entry(id).mir.map(|mir| mir.decode((self, tcx))) } - pub fn get_impl_or_trait_item(&self, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option> { + pub fn get_associated_item(&self, id: DefIndex) -> Option { let item = self.entry(id); let parent_and_name = || { let def_key = item.def_key.decode(self); @@ -806,52 +802,43 @@ impl<'a, 'tcx> CrateMetadata { Some(match item.kind { EntryKind::AssociatedConst(container) => { let (parent, name) = parent_and_name(); - ty::ConstTraitItem(Rc::new(ty::AssociatedConst { + ty::AssociatedItem { name: name, - ty: item.ty.unwrap().decode((self, tcx)), + kind: ty::AssociatedKind::Const, vis: item.visibility, defaultness: container.defaultness(), + has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), - has_value: container.has_body(), - })) + method_has_self_argument: false + } } EntryKind::Method(data) => { let (parent, name) = parent_and_name(); - let ity = item.ty.unwrap().decode((self, tcx)); - let fty = match ity.sty { - ty::TyFnDef(.., fty) => fty, - _ => { - bug!("the type {:?} of the method {:?} is not a function?", - ity, - name) - } - }; - let data = data.decode(self); - ty::MethodTraitItem(Rc::new(ty::Method { + ty::AssociatedItem { name: name, - generics: tcx.lookup_generics(self.local_def_id(id)), - predicates: item.predicates.unwrap().decode((self, tcx)), - fty: fty, - explicit_self: data.explicit_self.decode((self, tcx)), + kind: ty::AssociatedKind::Method, vis: item.visibility, defaultness: data.container.defaultness(), - has_body: data.container.has_body(), + has_value: data.container.has_value(), def_id: self.local_def_id(id), container: data.container.with_def_id(parent), - })) + method_has_self_argument: data.has_self + } } EntryKind::AssociatedType(container) => { let (parent, name) = parent_and_name(); - ty::TypeTraitItem(Rc::new(ty::AssociatedType { + ty::AssociatedItem { name: name, - ty: item.ty.map(|ty| ty.decode((self, tcx))), + kind: ty::AssociatedKind::Type, vis: item.visibility, defaultness: container.defaultness(), + has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), - })) + method_has_self_argument: false + } } _ => return None, }) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index fb4fb50729628..2379e744c49e1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -457,19 +457,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let node_id = tcx.map.as_local_node_id(def_id).unwrap(); let ast_item = tcx.map.expect_trait_item(node_id); - let trait_item = tcx.impl_or_trait_item(def_id); + let trait_item = tcx.associated_item(def_id); - let container = |has_body| if has_body { + let container = if trait_item.has_value { AssociatedContainer::TraitWithDefault } else { AssociatedContainer::TraitRequired }; - let kind = match trait_item { - ty::ConstTraitItem(ref associated_const) => { - EntryKind::AssociatedConst(container(associated_const.has_value)) - } - ty::MethodTraitItem(ref method_ty) => { + let kind = match trait_item.kind { + ty::AssociatedKind::Const => EntryKind::AssociatedConst(container), + ty::AssociatedKind::Method => { let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node { FnData { constness: hir::Constness::NotConst, @@ -478,30 +476,35 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { bug!() }; - let data = MethodData { + EntryKind::Method(self.lazy(&MethodData { fn_data: fn_data, - container: container(method_ty.has_body), - explicit_self: self.lazy(&method_ty.explicit_self), - }; - EntryKind::Method(self.lazy(&data)) + container: container, + has_self: trait_item.method_has_self_argument, + })) } - ty::TypeTraitItem(_) => EntryKind::AssociatedType(container(false)), + ty::AssociatedKind::Type => EntryKind::AssociatedType(container), }; Entry { kind: kind, - visibility: trait_item.vis().simplify(), + visibility: trait_item.vis.simplify(), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&ast_item.attrs), children: LazySeq::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), - ty: match trait_item { - ty::ConstTraitItem(_) | - ty::MethodTraitItem(_) => Some(self.encode_item_type(def_id)), - ty::TypeTraitItem(ref associated_type) => { - associated_type.ty.map(|ty| self.lazy(&ty)) + ty: match trait_item.kind { + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => { + Some(self.encode_item_type(def_id)) + } + ty::AssociatedKind::Type => { + if trait_item.has_value { + Some(self.encode_item_type(def_id)) + } else { + None + } } }, inherent_impls: LazySeq::empty(), @@ -509,8 +512,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: if let ty::ConstTraitItem(_) = trait_item { - let trait_def_id = trait_item.container().id(); + ast: if trait_item.kind == ty::AssociatedKind::Const { + let trait_def_id = trait_item.container.id(); Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item))) } else { None @@ -522,17 +525,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { let node_id = self.tcx.map.as_local_node_id(def_id).unwrap(); let ast_item = self.tcx.map.expect_impl_item(node_id); - let impl_item = self.tcx.impl_or_trait_item(def_id); - let impl_def_id = impl_item.container().id(); + let impl_item = self.tcx.associated_item(def_id); + let impl_def_id = impl_item.container.id(); - let container = match ast_item.defaultness { + let container = match impl_item.defaultness { hir::Defaultness::Default => AssociatedContainer::ImplDefault, hir::Defaultness::Final => AssociatedContainer::ImplFinal, }; - let kind = match impl_item { - ty::ConstTraitItem(_) => EntryKind::AssociatedConst(container), - ty::MethodTraitItem(ref method_ty) => { + let kind = match impl_item.kind { + ty::AssociatedKind::Const => EntryKind::AssociatedConst(container), + ty::AssociatedKind::Method => { let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { FnData { constness: sig.constness, @@ -541,17 +544,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { bug!() }; - let data = MethodData { + EntryKind::Method(self.lazy(&MethodData { fn_data: fn_data, container: container, - explicit_self: self.lazy(&method_ty.explicit_self), - }; - EntryKind::Method(self.lazy(&data)) + has_self: impl_item.method_has_self_argument, + })) } - ty::TypeTraitItem(_) => EntryKind::AssociatedType(container), + ty::AssociatedKind::Type => EntryKind::AssociatedType(container) }; - let (ast, mir) = if let ty::ConstTraitItem(_) = impl_item { + let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const { (true, true) } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { let generics = self.tcx.lookup_generics(def_id); @@ -565,20 +567,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: kind, - visibility: impl_item.vis().simplify(), + visibility: impl_item.vis.simplify(), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&ast_item.attrs), children: LazySeq::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), - ty: match impl_item { - ty::ConstTraitItem(_) | - ty::MethodTraitItem(_) => Some(self.encode_item_type(def_id)), - ty::TypeTraitItem(ref associated_type) => { - associated_type.ty.map(|ty| self.lazy(&ty)) - } - }, + ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), generics: Some(self.encode_generics(def_id)), @@ -758,7 +754,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemImpl(..) | hir::ItemTrait(..) => { - self.lazy_seq(tcx.impl_or_trait_items(def_id).iter().map(|&def_id| { + self.lazy_seq(tcx.associated_item_def_ids(def_id).iter().map(|&def_id| { assert!(def_id.is_local()); def_id.index })) @@ -880,14 +876,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { self.encode_fields(def_id); } hir::ItemImpl(..) => { - for &trait_item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] { + for &trait_item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { self.record(trait_item_def_id, EncodeContext::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemTrait(..) => { - for &item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] { + for &item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { self.record(item_def_id, EncodeContext::encode_info_for_trait_item, item_def_id); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 3d1bd77d8bc28..ff2a764571025 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -245,7 +245,7 @@ pub enum EntryKind<'tcx> { Trait(Lazy>), Impl(Lazy>), DefaultImpl(Lazy>), - Method(Lazy>), + Method(Lazy), AssociatedType(AssociatedContainer), AssociatedConst(AssociatedContainer), } @@ -300,7 +300,7 @@ pub enum AssociatedContainer { } impl AssociatedContainer { - pub fn with_def_id(&self, def_id: DefId) -> ty::ImplOrTraitItemContainer { + pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer { match *self { AssociatedContainer::TraitRequired | AssociatedContainer::TraitWithDefault => ty::TraitContainer(def_id), @@ -310,7 +310,7 @@ impl AssociatedContainer { } } - pub fn has_body(&self) -> bool { + pub fn has_value(&self) -> bool { match *self { AssociatedContainer::TraitRequired => false, @@ -332,10 +332,10 @@ impl AssociatedContainer { } #[derive(RustcEncodable, RustcDecodable)] -pub struct MethodData<'tcx> { +pub struct MethodData { pub fn_data: FnData, pub container: AssociatedContainer, - pub explicit_self: Lazy>, + pub has_self: bool, } #[derive(RustcEncodable, RustcDecodable)] diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 678db1e544cb0..ecc2d8fe050ad 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -147,20 +147,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { -> (Ty<'tcx>, Literal<'tcx>) { let method_name = token::intern(method_name); let substs = self.tcx.mk_substs_trait(self_ty, params); - for trait_item in self.tcx.trait_items(trait_def_id).iter() { - match *trait_item { - ty::ImplOrTraitItem::MethodTraitItem(ref method) => { - if method.name == method_name { - let method_ty = self.tcx.lookup_item_type(method.def_id); - let method_ty = method_ty.ty.subst(self.tcx, substs); - return (method_ty, Literal::Item { - def_id: method.def_id, - substs: substs, - }); - } - } - ty::ImplOrTraitItem::ConstTraitItem(..) | - ty::ImplOrTraitItem::TypeTraitItem(..) => {} + for item in self.tcx.associated_items(trait_def_id) { + if item.kind == ty::AssociatedKind::Method && item.name == method_name { + let method_ty = self.tcx.lookup_item_type(item.def_id); + let method_ty = method_ty.ty.subst(self.tcx, substs); + return (method_ty, Literal::Item { + def_id: item.def_id, + substs: substs, + }); } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index f23539e88f78d..1ab99b822d08d 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -542,7 +542,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node v.handle_const_fn_call(e, did, node_ty) } Some(Def::Method(did)) => { - match v.tcx.impl_or_trait_item(did).container() { + match v.tcx.associated_item(did).container { ty::ImplContainer(_) => { v.handle_const_fn_call(e, did, node_ty) } @@ -557,7 +557,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } hir::ExprMethodCall(..) => { let method = v.tcx.tables().method_map[&method_call]; - let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() { + let is_const = match v.tcx.associated_item(method.def_id).container { ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty), ty::TraitContainer(_) => false }; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index cbe2cd2628d29..dc7399e228908 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -399,7 +399,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a method is in scope. fn check_method(&mut self, span: Span, method_def_id: DefId) { - match self.tcx.impl_or_trait_item(method_def_id).container() { + match self.tcx.associated_item(method_def_id).container { // Trait methods are always all public. The only controlling factor // is whether the trait itself is accessible or not. ty::TraitContainer(trait_def_id) if !self.item_is_accessible(trait_def_id) => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 1e998a2a4d5b0..cb8dd7250b496 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -456,7 +456,7 @@ impl<'b> Resolver<'b> { self.define(parent, name, TypeNS, (module, DUMMY_SP, vis)); // If this is a trait, add all the trait item names to the trait info. - let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id); + let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id); for trait_item_def_id in trait_item_def_ids { let trait_item_name = self.session.cstore.def_key(trait_item_def_id) .disambiguated_data.data.get_opt_name() diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index db4788c3ceadb..148a24f1358c5 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -32,7 +32,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir::map::{Node, NodeItem}; use rustc::session::Session; -use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer}; +use rustc::ty::{self, TyCtxt, AssociatedItemContainer}; use std::collections::HashSet; use std::collections::hash_map::DefaultHasher; @@ -402,19 +402,19 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // with the right name. if !self.span.filter_generated(Some(method_data.span), span) { let container = - self.tcx.impl_or_trait_item(self.tcx.map.local_def_id(id)).container(); + self.tcx.associated_item(self.tcx.map.local_def_id(id)).container; let mut trait_id; let mut decl_id = None; match container { - ImplOrTraitItemContainer::ImplContainer(id) => { + AssociatedItemContainer::ImplContainer(id) => { trait_id = self.tcx.trait_id_of_impl(id); match trait_id { Some(id) => { - for item in &**self.tcx.trait_items(id) { - if let &ImplOrTraitItem::MethodTraitItem(ref m) = item { - if m.name == name { - decl_id = Some(m.def_id); + for item in self.tcx.associated_items(id) { + if item.kind == ty::AssociatedKind::Method { + if item.name == name { + decl_id = Some(item.def_id); break; } } @@ -429,7 +429,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } } - ImplOrTraitItemContainer::TraitContainer(id) => { + AssociatedItemContainer::TraitContainer(id) => { trait_id = Some(id); } } @@ -916,11 +916,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // Modules or types in the path prefix. match self.tcx.expect_def(id) { Def::Method(did) => { - let ti = self.tcx.impl_or_trait_item(did); - if let ty::MethodTraitItem(m) = ti { - if m.explicit_self == ty::ExplicitSelfCategory::Static { - self.write_sub_path_trait_truncated(path); - } + let ti = self.tcx.associated_item(did); + if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument { + self.write_sub_path_trait_truncated(path); } } Def::Fn(..) | diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index e1b67d211a333..fded34d2c856c 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -313,7 +313,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let (qualname, parent_scope, vis, docs) = + let (qualname, parent_scope, decl_id, vis, docs) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { @@ -323,12 +323,19 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push_str(&rustc::hir::print::ty_to_string(&ty)); let trait_id = self.tcx.trait_id_of_impl(impl_id); + let mut decl_id = None; if let Some(def_id) = trait_id { result.push_str(" as "); result.push_str(&self.tcx.item_path_str(def_id)); + self.tcx.associated_items(def_id) + .find(|item| item.name == name) + .map(|item| decl_id = Some(item.def_id)); } result.push_str(">"); - (result, trait_id, From::from(&item.vis), docs_for_attrs(&item.attrs)) + + (result, trait_id, decl_id, + From::from(&item.vis), + docs_for_attrs(&item.attrs)) } _ => { span_bug!(span, @@ -351,7 +358,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match self.tcx.map.get_if_local(def_id) { Some(NodeItem(item)) => { (format!("::{}", self.tcx.item_path_str(def_id)), - Some(def_id), + Some(def_id), None, From::from(&item.vis), docs_for_attrs(&item.attrs)) } @@ -373,15 +380,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let qualname = format!("{}::{}", qualname, name); - let def_id = self.tcx.map.local_def_id(id); - let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_def_id| { - if new_def_id != def_id { - Some(new_def_id) - } else { - None - } - }); - let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); Some(FunctionData { @@ -473,7 +471,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ast::ExprKind::MethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); let method_id = self.tcx.tables().method_map[&method_call].def_id; - let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() { + let (def_id, decl_id) = match self.tcx.associated_item(method_id).container { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), }; @@ -535,21 +533,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_for_meth_name(path.span); filter!(self.span_utils, sub_span, path.span, None); let def_id = if decl_id.is_local() { - let ti = self.tcx.impl_or_trait_item(decl_id); - match ti.container() { - ty::TraitContainer(def_id) => { - self.tcx - .trait_items(def_id) - .iter() - .find(|mr| mr.name() == ti.name() && self.trait_method_has_body(mr)) - .map(|mr| mr.def_id()) - } - ty::ImplContainer(def_id) => { - Some(*self.tcx.impl_or_trait_items(def_id).iter().find(|&&mr| { - self.tcx.impl_or_trait_item(mr).name() == ti.name() - }).unwrap()) - } - } + let ti = self.tcx.associated_item(decl_id); + self.tcx.associated_items(ti.container.id()) + .find(|item| item.name == ti.name && item.has_value) + .map(|item| item.def_id) } else { None }; @@ -582,20 +569,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } - fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool { - let def_id = mr.def_id(); - if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { - let trait_item = self.tcx.map.expect_trait_item(node_id); - if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node { - true - } else { - false - } - } else { - false - } - } - pub fn get_field_ref_data(&self, field_ref: &ast::Field, variant: ty::VariantDef, diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 548554af9727f..2c0ba36f3b412 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -844,17 +844,12 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, param_substs); if let Some(trait_def_id) = scx.tcx().trait_of_item(fn_def_id) { - match scx.tcx().impl_or_trait_item(fn_def_id) { - ty::MethodTraitItem(ref method) => { - debug!(" => trait method, attempting to find impl"); - do_static_trait_method_dispatch(scx, - method, - trait_def_id, - fn_substs, - param_substs) - } - _ => bug!() - } + debug!(" => trait method, attempting to find impl"); + do_static_trait_method_dispatch(scx, + &scx.tcx().associated_item(fn_def_id), + trait_def_id, + fn_substs, + param_substs) } else { debug!(" => regular function"); // The function is not part of an impl or trait, no dispatching @@ -866,7 +861,7 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // Given a trait-method and substitution information, find out the actual // implementation of the trait method. fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - trait_method: &ty::Method, + trait_method: &ty::AssociatedItem, trait_id: DefId, callee_substs: &'tcx Substs<'tcx>, param_substs: &'tcx Substs<'tcx>) @@ -1187,7 +1182,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' continue; } - if !method.generics.types.is_empty() { + if !tcx.lookup_generics(method.def_id).types.is_empty() { continue; } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 3d0d889760943..b8d346b11c13f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -248,13 +248,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref); if let traits::VtableImpl(vtable_impl) = vtable { let name = ccx.tcx().item_name(instance.def); - let ac = ccx.tcx().impl_or_trait_items(vtable_impl.impl_def_id) - .iter().filter_map(|&def_id| { - match ccx.tcx().impl_or_trait_item(def_id) { - ty::ConstTraitItem(ac) => Some(ac), - _ => None - } - }).find(|ic| ic.name == name); + let ac = ccx.tcx().associated_items(vtable_impl.impl_def_id) + .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); if let Some(ac) = ac { instance = Instance::new(ac.def_id, vtable_impl.substs); } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 57936f8a4b3be..513b4860d5e87 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -107,11 +107,6 @@ pub trait AstConv<'gcx, 'tcx> { fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId) -> Result>, ErrorReported>; - /// Returns true if the trait with id `trait_def_id` defines an - /// associated type with the name `name`. - fn trait_defines_associated_type_named(&self, trait_def_id: DefId, name: ast::Name) - -> bool; - /// Return an (optional) substitution to convert bound type parameters that /// are in scope into free ones. This function should only return Some /// within a fn body. @@ -831,6 +826,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Some(self_ty)) } + fn trait_defines_associated_type_named(&self, + trait_def_id: DefId, + assoc_name: ast::Name) + -> bool + { + self.tcx().associated_items(trait_def_id).any(|item| { + item.kind == ty::AssociatedKind::Type && item.name == assoc_name + }) + } + fn ast_type_binding_to_poly_projection_predicate( &self, path_id: ast::NodeId, @@ -1144,20 +1149,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut associated_types = FxHashSet::default(); for tr in traits::supertraits(tcx, principal) { - if let Some(trait_id) = tcx.map.as_local_node_id(tr.def_id()) { - use collect::trait_associated_type_names; - - associated_types.extend(trait_associated_type_names(tcx, trait_id) - .map(|name| (tr.def_id(), name))) - } else { - let trait_items = tcx.impl_or_trait_items(tr.def_id()); - associated_types.extend(trait_items.iter().filter_map(|&def_id| { - match tcx.impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => Some(item.name), - _ => None - } - }).map(|name| (tr.def_id(), name))); - } + associated_types.extend(tcx.associated_items(tr.def_id()) + .filter(|item| item.kind == ty::AssociatedKind::Type) + .map(|item| (tr.def_id(), item.name))); } for projection_bound in &projection_bounds { @@ -1260,14 +1254,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if bounds.len() > 1 { let spans = bounds.iter().map(|b| { - self.tcx().impl_or_trait_items(b.def_id()).iter() - .find(|&&def_id| { - match self.tcx().impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => item.name.as_str() == assoc_name, - _ => false - } + self.tcx().associated_items(b.def_id()).find(|item| { + item.kind == ty::AssociatedKind::Type && item.name.as_str() == assoc_name }) - .and_then(|&def_id| self.tcx().map.as_local_node_id(def_id)) + .and_then(|item| self.tcx().map.as_local_node_id(item.def_id)) .and_then(|node_id| self.tcx().map.opt_span(node_id)) }); @@ -1383,25 +1373,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_did = bound.0.def_id; let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name); - let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) { - // `ty::trait_items` used below requires information generated - // by type collection, which may be in progress at this point. - match tcx.map.expect_item(trait_id).node { - hir::ItemTrait(.., ref trait_items) => { - let item = trait_items.iter() - .find(|i| i.name == assoc_name) - .expect("missing associated type"); - tcx.map.local_def_id(item.id) - } - _ => bug!() - } - } else { - let trait_items = tcx.trait_items(trait_did); - let item = trait_items.iter().find(|i| i.name() == assoc_name); - item.expect("missing associated type").def_id() - }; - - (ty, Def::AssociatedTy(item_did)) + let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name); + (ty, Def::AssociatedTy(item.expect("missing associated type").def_id)) } fn qpath_to_ty(&self, @@ -1694,13 +1667,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); let anon_scope = rscope.anon_type_scope(); - let (bare_fn_ty, _) = - self.ty_of_method_or_bare_fn(bf.unsafety, - bf.abi, - None, - &bf.decl, - anon_scope, - anon_scope); + let bare_fn_ty = self.ty_of_method_or_bare_fn(bf.unsafety, + bf.abi, + None, + &bf.decl, + anon_scope, + anon_scope); // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not wellformed. @@ -1842,7 +1814,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { sig: &hir::MethodSig, untransformed_self_ty: Ty<'tcx>, anon_scope: Option) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) { + -> &'tcx ty::BareFnTy<'tcx> { self.ty_of_method_or_bare_fn(sig.unsafety, sig.abi, Some(untransformed_self_ty), @@ -1857,7 +1829,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { decl: &hir::FnDecl, anon_scope: Option) -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope).0 + self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope) } fn ty_of_method_or_bare_fn(&self, @@ -1867,7 +1839,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { decl: &hir::FnDecl, arg_anon_scope: Option, ret_anon_scope: Option) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) + -> &'tcx ty::BareFnTy<'tcx> { debug!("ty_of_method_or_bare_fn"); @@ -1880,13 +1852,13 @@ 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 (self_ty, explicit_self_category) = match (opt_untransformed_self_ty, decl.get_self()) { + let (self_ty, explicit_self) = 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); - (Some(self_type.0), self_type.1) + (Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type))) } - _ => (None, ty::ExplicitSelfCategory::Static), + _ => (None, None), }; // HACK(eddyb) replace the fake self type in the AST with the actual type. @@ -1901,8 +1873,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Second, if there was exactly one lifetime (either a substitution or a // reference) in the arguments, then any anonymous regions in the output // have that lifetime. - let implied_output_region = match explicit_self_category { - ty::ExplicitSelfCategory::ByReference(region, _) => Ok(*region), + let implied_output_region = match explicit_self { + Some(ExplicitSelf::ByReference(region, _)) => Ok(*region), _ => { // `pat_to_string` is expensive and // `find_implied_output_region` only needs its result when @@ -1928,7 +1900,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("ty_of_method_or_bare_fn: input_tys={:?}", input_tys); debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty); - (self.tcx().mk_bare_fn(ty::BareFnTy { + self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: ty::Binder(ty::FnSig { @@ -1936,95 +1908,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { output: output_ty, variadic: decl.variadic }), - }), explicit_self_category) + }) } fn determine_self_type<'a>(&self, rscope: &RegionScope, untransformed_self_ty: Ty<'tcx>, explicit_self: &hir::ExplicitSelf) - -> (Ty<'tcx>, ty::ExplicitSelfCategory<'tcx>) + -> Ty<'tcx> { - return match explicit_self.node { - SelfKind::Value(..) => { - (untransformed_self_ty, ty::ExplicitSelfCategory::ByValue) - } + match explicit_self.node { + SelfKind::Value(..) => untransformed_self_ty, SelfKind::Region(ref lifetime, mutability) => { let region = self.opt_ast_region_to_region( rscope, explicit_self.span, lifetime); - (self.tcx().mk_ref(region, + self.tcx().mk_ref(region, ty::TypeAndMut { ty: untransformed_self_ty, mutbl: mutability - }), - ty::ExplicitSelfCategory::ByReference(region, mutability)) - } - SelfKind::Explicit(ref ast_type, _) => { - let explicit_type = self.ast_ty_to_ty(rscope, &ast_type); - - // We wish to (for now) categorize an explicit self - // declaration like `self: SomeType` into either `self`, - // `&self`, `&mut self`, or `Box`. We do this here - // by some simple pattern matching. A more precise check - // is done later in `check_method_self_type()`. - // - // Examples: - // - // ``` - // impl Foo for &T { - // // Legal declarations: - // fn method1(self: &&T); // ExplicitSelfCategory::ByReference - // fn method2(self: &T); // ExplicitSelfCategory::ByValue - // fn method3(self: Box<&T>); // ExplicitSelfCategory::ByBox - // - // // Invalid cases will be caught later by `check_method_self_type`: - // fn method_err1(self: &mut T); // ExplicitSelfCategory::ByReference - // } - // ``` - // - // To do the check we just count the number of "modifiers" - // on each type and compare them. If they are the same or - // the impl has more, we call it "by value". Otherwise, we - // look at the outermost modifier on the method decl and - // call it by-ref, by-box as appropriate. For method1, for - // example, the impl type has one modifier, but the method - // type has two, so we end up with - // ExplicitSelfCategory::ByReference. - - let impl_modifiers = count_modifiers(untransformed_self_ty); - let method_modifiers = count_modifiers(explicit_type); - - debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \ - explicit_type={:?} \ - modifiers=({},{})", - untransformed_self_ty, - explicit_type, - impl_modifiers, - method_modifiers); - - let category = if impl_modifiers >= method_modifiers { - ty::ExplicitSelfCategory::ByValue - } else { - match explicit_type.sty { - ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(r, mt.mutbl), - ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox, - _ => ty::ExplicitSelfCategory::ByValue, - } - }; - - (explicit_type, category) - } - }; - - fn count_modifiers(ty: Ty) -> usize { - match ty.sty { - ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1, - ty::TyBox(t) => count_modifiers(t) + 1, - _ => 0, + }) } + SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type) } } @@ -2334,3 +2241,64 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { vec } } + +pub enum ExplicitSelf<'tcx> { + ByValue, + ByReference(&'tcx ty::Region, hir::Mutability), + ByBox +} + +impl<'tcx> ExplicitSelf<'tcx> { + /// We wish to (for now) categorize an explicit self + /// declaration like `self: SomeType` into either `self`, + /// `&self`, `&mut self`, or `Box`. We do this here + /// by some simple pattern matching. A more precise check + /// is done later in `check_method_self_type()`. + /// + /// Examples: + /// + /// ``` + /// impl Foo for &T { + /// // Legal declarations: + /// fn method1(self: &&T); // ExplicitSelf::ByReference + /// fn method2(self: &T); // ExplicitSelf::ByValue + /// fn method3(self: Box<&T>); // ExplicitSelf::ByBox + /// + /// // Invalid cases will be caught later by `check_method_self_type`: + /// fn method_err1(self: &mut T); // ExplicitSelf::ByReference + /// } + /// ``` + /// + /// To do the check we just count the number of "modifiers" + /// on each type and compare them. If they are the same or + /// the impl has more, we call it "by value". Otherwise, we + /// look at the outermost modifier on the method decl and + /// call it by-ref, by-box as appropriate. For method1, for + /// example, the impl type has one modifier, but the method + /// type has two, so we end up with + /// ExplicitSelf::ByReference. + pub fn determine(untransformed_self_ty: Ty<'tcx>, + self_arg_ty: Ty<'tcx>) + -> ExplicitSelf<'tcx> { + fn count_modifiers(ty: Ty) -> usize { + match ty.sty { + ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1, + ty::TyBox(t) => count_modifiers(t) + 1, + _ => 0, + } + } + + let impl_modifiers = count_modifiers(untransformed_self_ty); + let method_modifiers = count_modifiers(self_arg_ty); + + if impl_modifiers >= method_modifiers { + ExplicitSelf::ByValue + } else { + match self_arg_ty.sty { + ty::TyRef(r, mt) => ExplicitSelf::ByReference(r, mt.mutbl), + ty::TyBox(_) => ExplicitSelf::ByBox, + _ => ExplicitSelf::ByValue, + } + } + } +} diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2cb719675ac48..ffde940b3f48a 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc::hir; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::middle::free_region::FreeRegionMap; use rustc::ty; @@ -23,6 +24,7 @@ use syntax_pos::Span; use CrateCtxt; use super::assoc; use super::{Inherited, FnCtxt}; +use astconv::ExplicitSelf; /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. @@ -36,11 +38,11 @@ use super::{Inherited, FnCtxt}; /// - impl_trait_ref: the TraitRef corresponding to the trait implementation pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, impl_m_body_id: ast::NodeId, - trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>, + trait_m: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>, trait_item_span: Option, old_broken_mode: bool) { debug!("compare_impl_method(impl_trait_ref={:?})", @@ -49,7 +51,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, if let Err(ErrorReported) = compare_self_type(ccx, impl_m, impl_m_span, - trait_m) { + trait_m, + impl_trait_ref) { return; } @@ -81,16 +84,16 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, impl_m_body_id: ast::NodeId, - trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>, + trait_m: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>, old_broken_mode: bool) -> Result<(), ErrorReported> { let tcx = ccx.tcx; - let trait_to_impl_substs = &impl_trait_ref.substs; + let trait_to_impl_substs = impl_trait_ref.substs; // This code is best explained by example. Consider a trait: // @@ -165,18 +168,23 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Create mapping from trait to skolemized. let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx, - impl_m.container_id(), + impl_m.container.id(), trait_to_impl_substs.subst(tcx, impl_to_skol_substs)); debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); + let impl_m_generics = tcx.lookup_generics(impl_m.def_id); + let trait_m_generics = tcx.lookup_generics(trait_m.def_id); + let impl_m_predicates = tcx.lookup_predicates(impl_m.def_id); + let trait_m_predicates = tcx.lookup_predicates(trait_m.def_id); + // Check region bounds. check_region_bounds_on_impl_method(ccx, impl_m_span, impl_m, - &trait_m.generics, - &impl_m.generics, + &trait_m_generics, + &impl_m_generics, trait_to_skol_substs, impl_to_skol_substs)?; @@ -185,7 +193,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // environment. We can't just use `impl_env.caller_bounds`, // however, because we want to replace all late-bound regions with // region variables. - let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap()); + let impl_predicates = tcx.lookup_predicates(impl_m_predicates.parent.unwrap()); let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); @@ -198,7 +206,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // We then register the obligations from the impl_m and check to see // if all constraints hold. hybrid_preds.predicates - .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); + .extend(trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); // Construct trait parameter environment and then shift it into the skolemized viewpoint. // The key step here is to update the caller_bounds's predicates to be @@ -219,7 +227,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut selcx = traits::SelectionContext::new(&infcx); - let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs); + let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs); let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, infer::HigherRankedType, &ty::Binder(impl_m_own_bounds.predicates)); @@ -260,10 +268,19 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let tcx = infcx.tcx; let origin = TypeOrigin::MethodCompatCheck(impl_m_span); + let m_fty = |method: &ty::AssociatedItem| { + match tcx.lookup_item_type(method.def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + } + }; + let impl_m_fty = m_fty(impl_m); + let trait_m_fty = m_fty(trait_m); + let (impl_sig, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, infer::HigherRankedType, - &impl_m.fty.sig); + &impl_m_fty.sig); let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs); let impl_sig = @@ -273,15 +290,15 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_body_id, &impl_sig); let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: impl_m.fty.unsafety, - abi: impl_m.fty.abi, + unsafety: impl_m_fty.unsafety, + abi: impl_m_fty.abi, sig: ty::Binder(impl_sig.clone()), })); debug!("compare_impl_method: impl_fty={:?}", impl_fty); let trait_sig = tcx.liberate_late_bound_regions( infcx.parameter_environment.free_id_outlive, - &trait_m.fty.sig); + &trait_m_fty.sig); let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = @@ -291,8 +308,8 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_body_id, &trait_sig); let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: trait_m.fty.unsafety, - abi: trait_m.fty.abi, + unsafety: trait_m_fty.unsafety, + abi: trait_m_fty.abi, sig: ty::Binder(trait_sig.clone()), })); @@ -367,7 +384,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, trait_generics: &ty::Generics<'tcx>, impl_generics: &ty::Generics<'tcx>, trait_to_skol_substs: &Substs<'tcx>, @@ -413,9 +430,9 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, terr: &TypeError, origin: TypeOrigin, - impl_m: &ty::Method, + impl_m: &ty::AssociatedItem, impl_sig: ty::FnSig<'tcx>, - trait_m: &ty::Method, + trait_m: &ty::AssociatedItem, trait_sig: ty::FnSig<'tcx>) -> (Span, Option) { let tcx = infcx.tcx; @@ -505,9 +522,10 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a } fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, - trait_m: &ty::Method<'tcx>) + trait_m: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>) -> Result<(), ErrorReported> { let tcx = ccx.tcx; @@ -518,58 +536,75 @@ fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // that the error messages you get out of this code are a bit more // inscrutable, particularly for cases where one method has no // self. - match (&trait_m.explicit_self, &impl_m.explicit_self) { - (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {} - (&ty::ExplicitSelfCategory::Static, _) => { + + let self_string = |method: &ty::AssociatedItem| { + let untransformed_self_ty = match method.container { + ty::ImplContainer(_) => impl_trait_ref.self_ty(), + ty::TraitContainer(_) => tcx.mk_self_type() + }; + let method_ty = tcx.lookup_item_type(method.def_id).ty; + let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder(); + match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) { + ExplicitSelf::ByValue => "self".to_string(), + ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(), + ExplicitSelf::ByReference(_, hir::MutMutable) => "&mut self".to_string(), + _ => format!("self: {}", self_arg_ty) + } + }; + + match (trait_m.method_has_self_argument, impl_m.method_has_self_argument) { + (false, false) | (true, true) => {} + + (false, true) => { + let self_descr = self_string(impl_m); let mut err = struct_span_err!(tcx.sess, impl_m_span, E0185, "method `{}` has a `{}` declaration in the impl, but \ not in the trait", trait_m.name, - impl_m.explicit_self); - err.span_label(impl_m_span, - &format!("`{}` used in impl", impl_m.explicit_self)); + self_descr); + err.span_label(impl_m_span, &format!("`{}` used in impl", self_descr)); if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { - err.span_label(span, - &format!("trait declared without `{}`", impl_m.explicit_self)); + err.span_label(span, &format!("trait declared without `{}`", self_descr)); } err.emit(); return Err(ErrorReported); } - (_, &ty::ExplicitSelfCategory::Static) => { + + (true, false) => { + let self_descr = self_string(trait_m); let mut err = struct_span_err!(tcx.sess, impl_m_span, E0186, "method `{}` has a `{}` declaration in the trait, but \ not in the impl", trait_m.name, - trait_m.explicit_self); + self_descr); err.span_label(impl_m_span, - &format!("expected `{}` in impl", trait_m.explicit_self)); + &format!("expected `{}` in impl", self_descr)); if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { - err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self)); + err.span_label(span, &format!("`{}` used in trait", self_descr)); } err.emit(); return Err(ErrorReported); } - _ => { - // Let the type checker catch other errors below - } } Ok(()) } fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, - trait_m: &ty::Method<'tcx>, + trait_m: &ty::AssociatedItem, trait_item_span: Option) -> Result<(), ErrorReported> { let tcx = ccx.tcx; - let num_impl_m_type_params = impl_m.generics.types.len(); - let num_trait_m_type_params = trait_m.generics.types.len(); + let impl_m_generics = tcx.lookup_generics(impl_m.def_id); + let trait_m_generics = tcx.lookup_generics(trait_m.def_id); + let num_impl_m_type_params = impl_m_generics.types.len(); + let num_trait_m_type_params = trait_m_generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); let span = match tcx.map.expect_impl_item(impl_m_node_id).node { @@ -630,15 +665,23 @@ fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, - trait_m: &ty::Method<'tcx>, + trait_m: &ty::AssociatedItem, trait_item_span: Option) -> Result<(), ErrorReported> { let tcx = ccx.tcx; - if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() { - let trait_number_args = trait_m.fty.sig.0.inputs.len(); - let impl_number_args = impl_m.fty.sig.0.inputs.len(); + let m_fty = |method: &ty::AssociatedItem| { + match tcx.lookup_item_type(method.def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + } + }; + let impl_m_fty = m_fty(impl_m); + let trait_m_fty = m_fty(trait_m); + if impl_m_fty.sig.0.inputs.len() != trait_m_fty.sig.0.inputs.len() { + let trait_number_args = trait_m_fty.sig.0.inputs.len(); + let impl_number_args = impl_m_fty.sig.0.inputs.len(); let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id); let trait_span = if let Some(trait_id) = trait_m_node_id { match tcx.map.expect_trait_item(trait_id).node { @@ -708,10 +751,10 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_c: &ty::AssociatedConst<'tcx>, + impl_c: &ty::AssociatedItem, impl_c_span: Span, - trait_c: &ty::AssociatedConst<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>) { + trait_c: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>) { debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); let tcx = ccx.tcx; @@ -723,7 +766,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // because we shouldn't really have to deal with lifetimes or // predicates. In fact some of this should probably be put into // shared functions because of DRY violations... - let trait_to_impl_substs = &impl_trait_ref.substs; + let trait_to_impl_substs = impl_trait_ref.substs; // Create a parameter environment that represents the implementation's // method. @@ -742,8 +785,8 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_to_skol_substs); // Compute skolemized form of impl and trait const tys. - let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs); - let trait_ty = trait_c.ty.subst(tcx, trait_to_skol_substs); + let impl_ty = tcx.lookup_item_type(impl_c.def_id).ty.subst(tcx, impl_to_skol_substs); + let trait_ty = tcx.lookup_item_type(trait_c.def_id).ty.subst(tcx, trait_to_skol_substs); let mut origin = TypeOrigin::Misc(impl_c_span); let err = infcx.commit_if_ok(|_| { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index d28eb85ebb49d..a06b3e70881a5 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -553,9 +553,9 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // attributes attached to the impl's generics. let dtor_method = adt_def.destructor() .expect("dtorck type without destructor impossible"); - let method = tcx.impl_or_trait_item(dtor_method); - let impl_id: DefId = method.container().id(); - let revised_ty = revise_self_ty(tcx, adt_def, impl_id, substs); + let method = tcx.associated_item(dtor_method); + let impl_def_id = method.container.id(); + let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs); return DropckKind::RevisedSelf(revised_ty); } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index f88bb355d1270..3894a7a2097eb 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -37,16 +37,6 @@ impl<'a, 'gcx, 'tcx> Deref for ConfirmContext<'a, 'gcx, 'tcx> { } } -struct InstantiatedMethodSig<'tcx> { - /// Function signature of the method being invoked. The 0th - /// argument is the receiver. - method_sig: ty::FnSig<'tcx>, - - /// Generic bounds on the method's parameters which must be added - /// as pending obligations. - method_predicates: ty::InstantiatedPredicates<'tcx>, -} - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn confirm_method(&self, span: Span, @@ -98,31 +88,18 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { debug!("all_substs={:?}", all_substs); // Create the final signature for the method, replacing late-bound regions. - let InstantiatedMethodSig { method_sig, method_predicates } = - self.instantiate_method_sig(&pick, all_substs); - let method_self_ty = method_sig.inputs[0]; + let (method_ty, method_predicates) = self.instantiate_method_sig(&pick, all_substs); // Unify the (adjusted) self type with what the method expects. - self.unify_receivers(self_ty, method_self_ty); - - // Create the method type - let def_id = pick.item.def_id(); - let method_ty = pick.item.as_opt_method().unwrap(); - let fty = self.tcx.mk_fn_def(def_id, - all_substs, - self.tcx.mk_bare_fn(ty::BareFnTy { - sig: ty::Binder(method_sig), - unsafety: method_ty.fty.unsafety, - abi: method_ty.fty.abi.clone(), - })); + self.unify_receivers(self_ty, method_ty.fn_sig().input(0).skip_binder()); // Add any trait/regions obligations specified on the method's type parameters. - self.add_obligations(fty, all_substs, &method_predicates); + self.add_obligations(method_ty, all_substs, &method_predicates); // Create the final `MethodCallee`. let callee = ty::MethodCallee { - def_id: def_id, - ty: fty, + def_id: pick.item.def_id, + ty: method_ty, substs: all_substs, }; @@ -193,7 +170,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { -> &'tcx Substs<'tcx> { match pick.kind { probe::InherentImplPick => { - let impl_def_id = pick.item.container().id(); + let impl_def_id = pick.item.container.id(); assert!(self.tcx.impl_trait_ref(impl_def_id).is_none(), "impl {:?} is not an inherent impl", impl_def_id); @@ -201,7 +178,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } probe::ObjectPick => { - let trait_def_id = pick.item.container().id(); + let trait_def_id = pick.item.container.id(); self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| { // The object data has no entry for the Self // Type. For the purposes of this method call, we @@ -244,7 +221,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } probe::TraitPick => { - let trait_def_id = pick.item.container().id(); + let trait_def_id = pick.item.container.id(); // Make a trait reference `$0 : Trait<$1...$n>` // consisting entirely of type variables. Later on in @@ -299,8 +276,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let num_supplied_types = supplied_method_types.len(); - let method = pick.item.as_opt_method().unwrap(); - let num_method_types = method.generics.types.len(); + let method_generics = self.tcx.lookup_generics(pick.item.def_id); + let num_method_types = method_generics.types.len(); if num_supplied_types > 0 && num_supplied_types != num_method_types { if num_method_types == 0 { @@ -332,18 +309,15 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. // // FIXME -- permit users to manually specify lifetimes - let supplied_start = substs.params().len() + method.generics.regions.len(); - Substs::for_item(self.tcx, - method.def_id, - |def, _| { + let supplied_start = substs.params().len() + method_generics.regions.len(); + Substs::for_item(self.tcx, pick.item.def_id, |def, _| { let i = def.index as usize; if i < substs.params().len() { substs.region_at(i) } else { self.region_var_for_def(self.span, def) } - }, - |def, cur_substs| { + }, |def, cur_substs| { let i = def.index as usize; if i < substs.params().len() { substs.type_at(i) @@ -376,7 +350,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_sig(&mut self, pick: &probe::Pick<'tcx>, all_substs: &'tcx Substs<'tcx>) - -> InstantiatedMethodSig<'tcx> { + -> (Ty<'tcx>, ty::InstantiatedPredicates<'tcx>) { debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", pick, all_substs); @@ -384,36 +358,40 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Instantiate the bounds on the method with the // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. - let method_predicates = pick.item - .as_opt_method() - .unwrap() - .predicates - .instantiate(self.tcx, all_substs); - let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates); + let def_id = pick.item.def_id; + let method_predicates = self.tcx.lookup_predicates(def_id) + .instantiate(self.tcx, all_substs); + let method_predicates = self.normalize_associated_types_in(self.span, + &method_predicates); debug!("method_predicates after subst = {:?}", method_predicates); + let fty = match self.tcx.lookup_item_type(def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + }; + // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. // // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.item - .as_opt_method() - .unwrap() - .fty - .sig); + let method_sig = self.replace_late_bound_regions_with_fresh_var(&fty.sig); debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig); let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig); debug!("type scheme substituted, method_sig={:?}", method_sig); - InstantiatedMethodSig { - method_sig: method_sig, - method_predicates: method_predicates, - } + let method_ty = self.tcx.mk_fn_def(def_id, all_substs, + self.tcx.mk_bare_fn(ty::BareFnTy { + sig: ty::Binder(method_sig), + unsafety: fty.unsafety, + abi: fty.abi, + })); + + (method_ty, method_predicates) } fn add_obligations(&mut self, @@ -587,7 +565,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) { // Disallow calls to the method `drop` defined in the `Drop` trait. - match pick.item.container() { + match pick.item.container { ty::TraitContainer(trait_def_id) => { callee::check_legal_trait_for_method_call(self.ccx, self.span, trait_def_id) } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 2df562f9ade46..579a54fb5318d 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -228,14 +228,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. let tcx = self.tcx; - let method_item = self.impl_or_trait_item(trait_def_id, m_name).unwrap(); - let method_ty = method_item.as_opt_method().unwrap(); - assert_eq!(method_ty.generics.types.len(), 0); - assert_eq!(method_ty.generics.regions.len(), 0); + let method_item = self.associated_item(trait_def_id, m_name).unwrap(); + let def_id = method_item.def_id; + let generics = tcx.lookup_generics(def_id); + assert_eq!(generics.types.len(), 0); + assert_eq!(generics.regions.len(), 0); - debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}", - method_item, - method_ty); + debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -243,22 +242,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let fn_sig = - self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &method_ty.fty.sig) - .0; + let original_method_ty = tcx.lookup_item_type(def_id).ty; + let fty = match original_method_ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + }; + let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, + infer::FnCall, + &fty.sig).0; let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); let transformed_self_ty = fn_sig.inputs[0]; - let def_id = method_item.def_id(); - let fty = tcx.mk_fn_def(def_id, - trait_ref.substs, - tcx.mk_bare_fn(ty::BareFnTy { - sig: ty::Binder(fn_sig), - unsafety: method_ty.fty.unsafety, - abi: method_ty.fty.abi.clone(), - })); - - debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}", - fty, + let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs, + tcx.mk_bare_fn(ty::BareFnTy { + sig: ty::Binder(fn_sig), + unsafety: fty.unsafety, + abi: fty.abi + })); + + debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", + method_ty, obligation); // Register obligations for the parameters. This will include the @@ -269,13 +271,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates); + let method_bounds = self.instantiate_bounds(span, def_id, trait_ref.substs); assert!(!method_bounds.has_escaping_regions()); self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id), &method_bounds); // Also register an obligation for the method type being well-formed. - self.register_wf_obligation(fty, span, traits::MiscObligation); + self.register_wf_obligation(method_ty, span, traits::MiscObligation); // FIXME(#18653) -- Try to resolve obligations, giving us more // typing information, which can sometimes be needed to avoid @@ -283,61 +285,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); // Insert any adjustments needed (always an autoref of some mutability). - match self_expr { - None => {} - - Some(self_expr) => { - debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ - (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})", - self_expr.id, - autoderefs, - unsize, - method_ty.explicit_self); - - let autoref = match method_ty.explicit_self { - ty::ExplicitSelfCategory::ByValue => { - // Trait method is fn(self), no transformation needed. - assert!(!unsize); - None - } - - ty::ExplicitSelfCategory::ByReference(..) => { - // Trait method is fn(&self) or fn(&mut self), need an - // autoref. Pull the region etc out of the type of first argument. - match transformed_self_ty.sty { - ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { - Some(AutoBorrow::Ref(region, mutbl)) - } - - _ => { - span_bug!(span, - "trait method is &self but first arg is: {}", - transformed_self_ty); - } - } - } - - _ => { - span_bug!(span, - "unexpected explicit self type in operator method: {:?}", - method_ty.explicit_self); - } - }; - - self.write_adjustment(self_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: autoderefs, - autoref: autoref, - unsize: unsize - }, - target: transformed_self_ty - }); - } + if let Some(self_expr) = self_expr { + debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ + (self-id={}, autoderefs={}, unsize={}, fty={:?})", + self_expr.id, autoderefs, unsize, original_method_ty); + + let original_sig = original_method_ty.fn_sig(); + let autoref = match (&original_sig.input(0).skip_binder().sty, + &transformed_self_ty.sty) { + (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => { + // Trait method is fn(&self) or fn(&mut self), need an + // autoref. Pull the region etc out of the type of first argument. + Some(AutoBorrow::Ref(region, mutbl)) + } + _ => { + // Trait method is fn(self), no transformation needed. + assert!(!unsize); + None + } + }; + + self.write_adjustment(self_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: autoderefs, + autoref: autoref, + unsize: unsize + }, + target: transformed_self_ty + }); } let callee = ty::MethodCallee { def_id: def_id, - ty: fty, + ty: method_ty, substs: trait_ref.substs, }; @@ -361,7 +341,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let def = pick.item.def(); if let probe::InherentImplPick = pick.kind { - if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx.map) { + if !pick.item.vis.is_accessible_from(self.body_id, &self.tcx.map) { let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str()); self.tcx.sess.span_err(span, &msg); } @@ -371,14 +351,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. - pub fn impl_or_trait_item(&self, - def_id: DefId, - item_name: ast::Name) - -> Option> { - self.tcx - .impl_or_trait_items(def_id) - .iter() - .map(|&did| self.tcx.impl_or_trait_item(did)) - .find(|m| m.name() == item_name) + pub fn associated_item(&self, def_id: DefId, item_name: ast::Name) + -> Option { + self.tcx.associated_items(def_id).find(|item| item.name == item_name) } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 54b1b6c6807db..7068b2dea7263 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -72,7 +72,7 @@ struct CandidateStep<'tcx> { #[derive(Debug)] struct Candidate<'tcx> { xform_self_ty: Ty<'tcx>, - item: ty::ImplOrTraitItem<'tcx>, + item: ty::AssociatedItem, kind: CandidateKind<'tcx>, import_id: Option, } @@ -95,7 +95,7 @@ enum CandidateKind<'tcx> { #[derive(Debug)] pub struct Pick<'tcx> { - pub item: ty::ImplOrTraitItem<'tcx>, + pub item: ty::AssociatedItem, pub kind: PickKind<'tcx>, pub import_id: Option, @@ -384,8 +384,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option) { if let Some(impl_def_id) = lang_def_id { - self.tcx.populate_implementations_for_primitive_if_necessary(impl_def_id); - self.assemble_inherent_impl_probe(impl_def_id); } } @@ -409,7 +407,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { debug!("assemble_inherent_impl_probe {:?}", impl_def_id); - let item = match self.impl_or_trait_item(impl_def_id) { + let item = match self.associated_item(impl_def_id) { Some(m) => m, None => { return; @@ -421,7 +419,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return self.record_static_candidate(ImplSource(impl_def_id)); } - if !item.vis().is_accessible_from(self.body_id, &self.tcx.map) { + if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) { self.private_candidate = Some(item.def()); return; } @@ -512,17 +510,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let xform_self_ty = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs); - if let Some(ref m) = item.as_opt_method() { - debug!("found match: trait_ref={:?} substs={:?} m={:?}", - trait_ref, - trait_ref.substs, - m); - assert_eq!(m.generics.parent_types as usize, - trait_ref.substs.types().count()); - assert_eq!(m.generics.parent_regions as usize, - trait_ref.substs.regions().count()); - } - // Because this trait derives from a where-clause, it // should not contain any inference variables or other // artifacts. This means it is safe to put into the @@ -544,13 +531,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn elaborate_bounds(&mut self, bounds: &[ty::PolyTraitRef<'tcx>], mut mk_cand: F) where F: for<'b> FnMut(&mut ProbeContext<'b, 'gcx, 'tcx>, ty::PolyTraitRef<'tcx>, - ty::ImplOrTraitItem<'tcx>) + ty::AssociatedItem) { debug!("elaborate_bounds(bounds={:?})", bounds); let tcx = self.tcx; for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { - let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) { + let item = match self.associated_item(bound_trait_ref.def_id()) { Some(v) => v, None => { continue; @@ -601,9 +588,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { trait_def_id); // Check whether `trait_def_id` defines a method with suitable name: - let trait_items = self.tcx.trait_items(trait_def_id); - let maybe_item = trait_items.iter() - .find(|item| item.name() == self.item_name); + let maybe_item = self.tcx.associated_items(trait_def_id) + .find(|item| item.name == self.item_name); let item = match maybe_item { Some(i) => i, None => { @@ -612,7 +598,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { }; // Check whether `trait_def_id` defines a method with suitable name: - if !self.has_applicable_self(item) { + if !self.has_applicable_self(&item) { debug!("method has inapplicable self"); self.record_static_candidate(TraitSource(trait_def_id)); return Ok(()); @@ -631,7 +617,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_extension_candidates_for_trait_impls(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) { + item: ty::AssociatedItem) { let trait_def = self.tcx.lookup_trait_def(trait_def_id); // FIXME(arielb1): can we use for_each_relevant_impl here? @@ -700,7 +686,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_closure_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) + item: ty::AssociatedItem) -> Result<(), MethodError<'tcx>> { // Check if this is one of the Fn,FnMut,FnOnce traits. let tcx = self.tcx; @@ -765,7 +751,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_projection_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) { + item: ty::AssociatedItem) { debug!("assemble_projection_candidates(\ trait_def_id={:?}, \ item={:?})", @@ -820,7 +806,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_where_clause_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) { + item: ty::AssociatedItem) { debug!("assemble_where_clause_candidates(trait_def_id={:?})", trait_def_id); @@ -865,7 +851,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_extension_candidates_for_all_traits()?; let out_of_scope_traits = match self.pick_core() { - Some(Ok(p)) => vec![p.item.container().id()], + Some(Ok(p)) => vec![p.item.container.id()], Some(Err(MethodError::Ambiguity(v))) => { v.into_iter() .map(|source| { @@ -1065,7 +1051,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // don't have enough information to fully evaluate). let (impl_def_id, substs, ref_obligations) = match probe.kind { InherentImplCandidate(ref substs, ref ref_obligations) => { - (probe.item.container().id(), substs, ref_obligations) + (probe.item.container.id(), substs, ref_obligations) } ExtensionImplCandidate(impl_def_id, ref substs, ref ref_obligations) => { @@ -1128,12 +1114,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// use, so it's ok to just commit to "using the method from the trait Foo". fn collapse_candidates_to_trait_pick(&self, probes: &[&Candidate<'tcx>]) -> Option> { // Do all probes correspond to the same trait? - let container = probes[0].item.container(); + let container = probes[0].item.container; match container { ty::TraitContainer(_) => {} ty::ImplContainer(_) => return None, } - if probes[1..].iter().any(|p| p.item.container() != container) { + if probes[1..].iter().any(|p| p.item.container != container) { return None; } @@ -1150,19 +1136,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // MISCELLANY - fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool { + fn has_applicable_self(&self, item: &ty::AssociatedItem) -> bool { // "fast track" -- check for usage of sugar - match *item { - ty::ImplOrTraitItem::MethodTraitItem(ref method) => { - match method.explicit_self { - ty::ExplicitSelfCategory::Static => self.mode == Mode::Path, - ty::ExplicitSelfCategory::ByValue | - ty::ExplicitSelfCategory::ByReference(..) | - ty::ExplicitSelfCategory::ByBox => true, - } - } - ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path, - _ => false, + match self.mode { + Mode::MethodCall => item.method_has_self_argument, + Mode::Path => true } // FIXME -- check for types that deref to `Self`, // like `Rc` and so on. @@ -1177,24 +1155,26 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn xform_self_ty(&self, - item: &ty::ImplOrTraitItem<'tcx>, + item: &ty::AssociatedItem, impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { - match item.as_opt_method() { - Some(ref method) => self.xform_method_self_ty(method, impl_ty, substs), - None => impl_ty, + if item.kind == ty::AssociatedKind::Method && self.mode == Mode::MethodCall { + self.xform_method_self_ty(item.def_id, impl_ty, substs) + } else { + impl_ty } } fn xform_method_self_ty(&self, - method: &Rc>, + method: DefId, impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { + let self_ty = self.tcx.lookup_item_type(method).ty.fn_sig().input(0); debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", impl_ty, - method.fty.sig.0.inputs.get(0), + self_ty, substs); assert!(!substs.has_escaping_regions()); @@ -1204,26 +1184,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - assert_eq!(substs.types().count(), - method.generics.parent_types as usize); - assert_eq!(substs.regions().count(), - method.generics.parent_regions as usize); - - if self.mode == Mode::Path { - return impl_ty; - } + let generics = self.tcx.lookup_generics(method); + assert_eq!(substs.types().count(), generics.parent_types as usize); + assert_eq!(substs.regions().count(), generics.parent_regions as usize); // Erase any late-bound regions from the method and substitute // in the values from the substitution. - let xform_self_ty = method.fty.sig.input(0); - let xform_self_ty = self.erase_late_bound_regions(&xform_self_ty); + let xform_self_ty = self.erase_late_bound_regions(&self_ty); - if method.generics.types.is_empty() && method.generics.regions.is_empty() { + if generics.types.is_empty() && generics.regions.is_empty() { xform_self_ty.subst(self.tcx, substs) } else { - let substs = Substs::for_item(self.tcx, - method.def_id, - |def, _| { + let substs = Substs::for_item(self.tcx, method, |def, _| { let i = def.index as usize; if i < substs.params().len() { substs.region_at(i) @@ -1232,8 +1204,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // `impl_self_ty()` for an explanation. self.tcx.mk_region(ty::ReErased) } - }, - |def, cur_substs| { + }, |def, cur_substs| { let i = def.index as usize; if i < substs.params().len() { substs.type_at(i) @@ -1283,8 +1254,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. - fn impl_or_trait_item(&self, def_id: DefId) -> Option> { - self.fcx.impl_or_trait_item(def_id, self.item_name) + fn associated_item(&self, def_id: DefId) -> Option { + self.fcx.associated_item(def_id, self.item_name) } } @@ -1317,11 +1288,11 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { - InherentImplCandidate(..) => ImplSource(self.item.container().id()), + InherentImplCandidate(..) => ImplSource(self.item.container.id()), ExtensionImplCandidate(def_id, ..) => ImplSource(def_id), ObjectCandidate | TraitCandidate | - WhereClauseCandidate(_) => TraitSource(self.item.container().id()), + WhereClauseCandidate(_) => TraitSource(self.item.container.id()), } } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 98d3957db7059..0cb8cf2a58886 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -89,20 +89,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { CandidateSource::ImplSource(impl_did) => { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else nothing. - let item = self.impl_or_trait_item(impl_did, item_name) + let item = self.associated_item(impl_did, item_name) .or_else(|| { - self.impl_or_trait_item(self.tcx - .impl_trait_ref(impl_did) - .unwrap() - .def_id, - - item_name) - }) - .unwrap(); - let note_span = self.tcx - .map - .span_if_local(item.def_id()) - .or_else(|| self.tcx.map.span_if_local(impl_did)); + self.associated_item( + self.tcx.impl_trait_ref(impl_did).unwrap().def_id, + + item_name + ) + }).unwrap(); + let note_span = self.tcx.map.span_if_local(item.def_id).or_else(|| { + self.tcx.map.span_if_local(impl_did) + }); let impl_ty = self.impl_self_ty(span, impl_did).ty; @@ -127,8 +124,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } CandidateSource::TraitSource(trait_did) => { - let item = self.impl_or_trait_item(trait_did, item_name).unwrap(); - let item_span = self.tcx.map.def_id_span(item.def_id(), span); + let item = self.associated_item(trait_did, item_name).unwrap(); + let item_span = self.tcx.map.def_id_span(item.def_id, span); span_note!(err, item_span, "candidate #{} is defined in the trait `{}`", @@ -334,8 +331,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - (type_is_local || info.def_id.is_local()) && - self.impl_or_trait_item(info.def_id, item_name).is_some() + (type_is_local || info.def_id.is_local()) + && self.associated_item(info.def_id, item_name).is_some() }) .collect::>(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f7e05f4777ecc..0265e397ef6c4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -760,7 +760,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_impl_items_against_trait(ccx, it.span, impl_def_id, - &impl_trait_ref, + impl_trait_ref, impl_items); let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); @@ -942,21 +942,13 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let ancestors = trait_def.ancestors(impl_id); - let parent = match impl_item.node { - hir::ImplItemKind::Const(..) => { - ancestors.const_defs(tcx, impl_item.name).skip(1).next() - .map(|node_item| node_item.map(|parent| parent.defaultness)) - } - hir::ImplItemKind::Method(..) => { - ancestors.fn_defs(tcx, impl_item.name).skip(1).next() - .map(|node_item| node_item.map(|parent| parent.defaultness)) - - } - hir::ImplItemKind::Type(_) => { - ancestors.type_defs(tcx, impl_item.name).skip(1).next() - .map(|node_item| node_item.map(|parent| parent.defaultness)) - } + let kind = match impl_item.node { + hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const, + hir::ImplItemKind::Method(..) => ty::AssociatedKind::Method, + hir::ImplItemKind::Type(_) => ty::AssociatedKind::Type }; + let parent = ancestors.defs(tcx, impl_item.name, kind).skip(1).next() + .map(|node_item| node_item.map(|parent| parent.defaultness)); if let Some(parent) = parent { if parent.item.is_final() { @@ -969,7 +961,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, impl_id: DefId, - impl_trait_ref: &ty::TraitRef<'tcx>, + impl_trait_ref: ty::TraitRef<'tcx>, impl_items: &[hir::ImplItem]) { // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` @@ -979,72 +971,61 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Locate trait definition and items let tcx = ccx.tcx; let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id); - let trait_items = tcx.trait_items(impl_trait_ref.def_id); let mut overridden_associated_type = None; // Check existing impl methods to see if they are both present in trait // and compatible with trait signature for impl_item in impl_items { - let ty_impl_item = tcx.impl_or_trait_item(tcx.map.local_def_id(impl_item.id)); - let ty_trait_item = trait_items.iter() - .find(|ac| ac.name() == ty_impl_item.name()); + let ty_impl_item = tcx.associated_item(tcx.map.local_def_id(impl_item.id)); + let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id) + .find(|ac| ac.name == ty_impl_item.name); // Check that impl definition matches trait definition if let Some(ty_trait_item) = ty_trait_item { match impl_item.node { hir::ImplItemKind::Const(..) => { - let impl_const = match ty_impl_item { - ty::ConstTraitItem(ref cti) => cti, - _ => span_bug!(impl_item.span, "non-const impl-item for const") - }; - // Find associated const definition. - if let &ty::ConstTraitItem(ref trait_const) = ty_trait_item { + if ty_trait_item.kind == ty::AssociatedKind::Const { compare_const_impl(ccx, - &impl_const, + &ty_impl_item, impl_item.span, - trait_const, - &impl_trait_ref); + &ty_trait_item, + impl_trait_ref); } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0323, "item `{}` is an associated const, \ which doesn't match its trait `{:?}`", - impl_const.name, + ty_impl_item.name, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); // We can only get the spans from local trait definition // Same for E0324 and E0325 - if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { + if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, &format!("item in trait")); } err.emit() } } hir::ImplItemKind::Method(_, ref body) => { - let impl_method = match ty_impl_item { - ty::MethodTraitItem(ref mti) => mti, - _ => span_bug!(impl_item.span, "non-method impl-item for method") - }; - - let trait_span = tcx.map.span_if_local(ty_trait_item.def_id()); - if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { + let trait_span = tcx.map.span_if_local(ty_trait_item.def_id); + if ty_trait_item.kind == ty::AssociatedKind::Method { let err_count = tcx.sess.err_count(); compare_impl_method(ccx, - &impl_method, + &ty_impl_item, impl_item.span, body.id, - &trait_method, - &impl_trait_ref, + &ty_trait_item, + impl_trait_ref, trait_span, true); // start with old-broken-mode if err_count == tcx.sess.err_count() { // old broken mode did not report an error. Try with the new mode. compare_impl_method(ccx, - &impl_method, + &ty_impl_item, impl_item.span, body.id, - &trait_method, - &impl_trait_ref, + &ty_trait_item, + impl_trait_ref, trait_span, false); // use the new mode } @@ -1052,33 +1033,28 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324, "item `{}` is an associated method, \ which doesn't match its trait `{:?}`", - impl_method.name, + ty_impl_item.name, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); - if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { + if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, &format!("item in trait")); } err.emit() } } hir::ImplItemKind::Type(_) => { - let impl_type = match ty_impl_item { - ty::TypeTraitItem(ref tti) => tti, - _ => span_bug!(impl_item.span, "non-type impl-item for type") - }; - - if let &ty::TypeTraitItem(ref at) = ty_trait_item { - if let Some(_) = at.ty { + if ty_trait_item.kind == ty::AssociatedKind::Type { + if ty_trait_item.has_value { overridden_associated_type = Some(impl_item); } } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0325, "item `{}` is an associated type, \ which doesn't match its trait `{:?}`", - impl_type.name, + ty_impl_item.name, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); - if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { + if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, &format!("item in trait")); } err.emit() @@ -1091,70 +1067,55 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // Check for missing items from trait - let provided_methods = tcx.provided_trait_methods(impl_trait_ref.def_id); let mut missing_items = Vec::new(); let mut invalidated_items = Vec::new(); let associated_type_overridden = overridden_associated_type.is_some(); - for trait_item in trait_items.iter() { - let is_implemented; - let is_provided; - - match *trait_item { - ty::ConstTraitItem(ref associated_const) => { - is_provided = associated_const.has_value; - is_implemented = impl_items.iter().any(|ii| { - match ii.node { - hir::ImplItemKind::Const(..) => { - ii.name == associated_const.name - } - _ => false, - } - }); - } - ty::MethodTraitItem(ref trait_method) => { - is_provided = provided_methods.iter().any(|m| m.name == trait_method.name); - is_implemented = trait_def.ancestors(impl_id) - .fn_defs(tcx, trait_method.name) - .next() - .map(|node_item| !node_item.node.is_from_trait()) - .unwrap_or(false); - } - ty::TypeTraitItem(ref trait_assoc_ty) => { - is_provided = trait_assoc_ty.ty.is_some(); - is_implemented = trait_def.ancestors(impl_id) - .type_defs(tcx, trait_assoc_ty.name) - .next() - .map(|node_item| !node_item.node.is_from_trait()) - .unwrap_or(false); - } - } + for trait_item in tcx.associated_items(impl_trait_ref.def_id) { + let is_implemented = trait_def.ancestors(impl_id) + .defs(tcx, trait_item.name, trait_item.kind) + .next() + .map(|node_item| !node_item.node.is_from_trait()) + .unwrap_or(false); if !is_implemented { - if !is_provided { + if !trait_item.has_value { missing_items.push(trait_item); } else if associated_type_overridden { - invalidated_items.push(trait_item.name()); + invalidated_items.push(trait_item.name); } } } + let signature = |item: &ty::AssociatedItem| { + match item.kind { + ty::AssociatedKind::Method => { + format!("{}", tcx.lookup_item_type(item.def_id).ty.fn_sig().0) + } + ty::AssociatedKind::Type => format!("type {};", item.name.to_string()), + ty::AssociatedKind::Const => { + format!("const {}: {:?};", item.name.to_string(), + tcx.lookup_item_type(item.def_id).ty) + } + } + }; + if !missing_items.is_empty() { let mut err = struct_span_err!(tcx.sess, impl_span, E0046, "not all trait items implemented, missing: `{}`", missing_items.iter() - .map(|trait_item| trait_item.name().to_string()) + .map(|trait_item| trait_item.name.to_string()) .collect::>().join("`, `")); err.span_label(impl_span, &format!("missing `{}` in implementation", missing_items.iter() - .map(|trait_item| trait_item.name().to_string()) + .map(|trait_item| trait_item.name.to_string()) .collect::>().join("`, `"))); for trait_item in missing_items { - if let Some(span) = tcx.map.span_if_local(trait_item.def_id()) { - err.span_label(span, &format!("`{}` from trait", trait_item.name())); + if let Some(span) = tcx.map.span_if_local(trait_item.def_id) { + err.span_label(span, &format!("`{}` from trait", trait_item.name)); } else { err.note(&format!("`{}` from trait: `{}`", - trait_item.name(), - signature(trait_item))); + trait_item.name, + signature(&trait_item))); } } err.emit(); @@ -1172,14 +1133,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn signature<'a, 'tcx>(item: &ty::ImplOrTraitItem) -> String { - match *item { - ty::MethodTraitItem(ref item) => format!("{}", item.fty.sig.0), - ty::TypeTraitItem(ref item) => format!("type {};", item.name.to_string()), - ty::ConstTraitItem(ref item) => format!("const {}: {:?};", item.name.to_string(), item.ty), - } -} - /// Checks a constant with a given type. fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, @@ -1385,19 +1338,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { Ok(r) } - fn trait_defines_associated_type_named(&self, - trait_def_id: DefId, - assoc_name: ast::Name) - -> bool - { - self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| { - match self.tcx().impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => item.name == assoc_name, - _ => false - } - }) - } - fn ty_infer(&self, _span: Span) -> Ty<'tcx> { self.next_ty_var() } @@ -1643,12 +1583,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// As `instantiate_type_scheme`, but for the bounds found in a /// generic type scheme. - fn instantiate_bounds(&self, - span: Span, - substs: &Substs<'tcx>, - bounds: &ty::GenericPredicates<'tcx>) - -> ty::InstantiatedPredicates<'tcx> - { + fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: &Substs<'tcx>) + -> ty::InstantiatedPredicates<'tcx> { + let bounds = self.tcx.lookup_predicates(def_id); let result = bounds.instantiate(self.tcx, substs); let result = self.normalize_associated_types_in(span, &result.predicates); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", @@ -3279,8 +3216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some((variant, did, substs)) = variant { // Check bounds on type arguments used in the path. - let type_predicates = self.tcx.lookup_predicates(did); - let bounds = self.instantiate_bounds(path.span, substs, &type_predicates); + let bounds = self.instantiate_bounds(path.span, did, substs); let cause = traits::ObligationCause::new(path.span, self.body_id, traits::ItemObligation(did)); self.add_obligations_for_parameters(cause, &bounds); @@ -4149,7 +4085,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Case 3. Reference to a method or associated const. Def::Method(def_id) | Def::AssociatedConst(def_id) => { - let container = self.tcx.impl_or_trait_item(def_id).container(); + let container = self.tcx.associated_item(def_id).container; match container { ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) @@ -4290,13 +4226,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. let scheme = self.tcx.lookup_item_type(def.def_id()); - let type_predicates = self.tcx.lookup_predicates(def.def_id()); assert!(!substs.has_escaping_regions()); assert!(!scheme.ty.has_escaping_regions()); // Add all the obligations that are required, substituting and // normalized appropriately. - let bounds = self.instantiate_bounds(span, &substs, &type_predicates); + let bounds = self.instantiate_bounds(span, def.def_id(), &substs); self.add_obligations_for_parameters( traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())), &bounds); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 741f327ac99e1..07415bab2f100 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use astconv::ExplicitSelf; use check::FnCtxt; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; + use hir::def_id::DefId; use middle::region::{CodeExtent}; use rustc::infer::TypeOrigin; @@ -156,8 +158,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { self.check_variances_for_type_defn(item, ast_generics); } - hir::ItemTrait(.., ref items) => { - self.check_trait(item, items); + hir::ItemTrait(..) => { + self.check_trait(item); } _ => {} } @@ -172,32 +174,39 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let free_substs = &fcx.parameter_environment.free_substs; let free_id_outlive = fcx.parameter_environment.free_id_outlive; - let item = fcx.tcx.impl_or_trait_item(fcx.tcx.map.local_def_id(item_id)); + let item = fcx.tcx.associated_item(fcx.tcx.map.local_def_id(item_id)); - let (mut implied_bounds, self_ty) = match item.container() { + let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()), ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), fcx.tcx.lookup_item_type(def_id).ty) }; - match item { - ty::ConstTraitItem(assoc_const) => { - let ty = fcx.instantiate_type_scheme(span, free_substs, &assoc_const.ty); + match item.kind { + ty::AssociatedKind::Const => { + let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } - ty::MethodTraitItem(method) => { - reject_shadowing_type_parameters(fcx.tcx, span, &method.generics); - let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); - let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates); - this.check_fn_or_method(fcx, span, &method_ty, &predicates, + ty::AssociatedKind::Method => { + reject_shadowing_type_parameters(fcx.tcx, span, item.def_id); + let method_ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); + let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); + let fty = match method_ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + }; + this.check_fn_or_method(fcx, span, fty, &predicates, free_id_outlive, &mut implied_bounds); let sig_if_method = sig_if_method.expect("bad signature for method"); - this.check_method_receiver(fcx, sig_if_method, &method, + this.check_method_receiver(fcx, sig_if_method, &item, free_id_outlive, self_ty); } - ty::TypeTraitItem(assoc_type) => { - if let Some(ref ty) = assoc_type.ty { - let ty = fcx.instantiate_type_scheme(span, free_substs, ty); + ty::AssociatedKind::Type => { + if item.has_value { + let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } } @@ -248,19 +257,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } let free_substs = &fcx.parameter_environment.free_substs; - let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id)); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let def_id = fcx.tcx.map.local_def_id(item.id); + let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); vec![] // no implied bounds in a struct def'n }); } - fn check_auto_trait(&mut self, - trait_def_id: DefId, - items: &[hir::TraitItem], - span: Span) - { + fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) { // We want to ensure: // // 1) that there are no items contained within @@ -302,7 +307,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { // extraneous predicates created by things like // an associated type inside the trait. let mut err = None; - if !items.is_empty() { + if !self.tcx().associated_item_def_ids(trait_def_id).is_empty() { error_380(self.ccx, span); } else if has_ty_params { err = Some(struct_span_err!(self.tcx().sess, span, E0567, @@ -326,20 +331,16 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } - fn check_trait(&mut self, - item: &hir::Item, - items: &[hir::TraitItem]) - { + fn check_trait(&mut self, item: &hir::Item) { let trait_def_id = self.tcx().map.local_def_id(item.id); if self.tcx().trait_has_default_impl(trait_def_id) { - self.check_auto_trait(trait_def_id, items, item.span); + self.check_auto_trait(trait_def_id, item.span); } self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; - let predicates = fcx.tcx.lookup_predicates(trait_def_id); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let predicates = fcx.instantiate_bounds(item.span, trait_def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); vec![] }); @@ -351,7 +352,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { { self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; - let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id)); + let def_id = fcx.tcx.map.local_def_id(item.id); + let type_scheme = fcx.tcx.lookup_item_type(def_id); let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty); let bare_fn_ty = match item_ty.sty { ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty, @@ -360,8 +362,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } }; - let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id)); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs); let mut implied_bounds = vec![]; let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body.id); @@ -422,8 +423,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } - let predicates = fcx.tcx.lookup_predicates(item_def_id); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let predicates = fcx.instantiate_bounds(item.span, item_def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); fcx.impl_implied_bounds(fcx.tcx.map.local_def_id(item.id), item.span) @@ -476,35 +476,39 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn check_method_receiver<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, method_sig: &hir::MethodSig, - method: &ty::Method<'tcx>, + method: &ty::AssociatedItem, free_id_outlive: CodeExtent, self_ty: ty::Ty<'tcx>) { // check that the type of the method's receiver matches the // method's first parameter. - debug!("check_method_receiver({:?},cat={:?},self_ty={:?})", - method.name, method.explicit_self, self_ty); + debug!("check_method_receiver({:?}, self_ty={:?})", + method, self_ty); - let rcvr_ty = match method.explicit_self { - ty::ExplicitSelfCategory::Static => return, - ty::ExplicitSelfCategory::ByValue => self_ty, - ty::ExplicitSelfCategory::ByReference(region, mutability) => { - fcx.tcx.mk_ref(region, ty::TypeAndMut { - ty: self_ty, - mutbl: mutability - }) - } - ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty) - }; + if !method.method_has_self_argument { + return; + } let span = method_sig.decl.inputs[0].pat.span; let free_substs = &fcx.parameter_environment.free_substs; - let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); - let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); + let method_ty = fcx.tcx.lookup_item_type(method.def_id).ty; + let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); + let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig()); debug!("check_method_receiver: sig={:?}", sig); + let self_arg_ty = sig.inputs[0]; + let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) { + ExplicitSelf::ByValue => self_ty, + ExplicitSelf::ByReference(region, mutbl) => { + fcx.tcx.mk_ref(region, ty::TypeAndMut { + ty: self_ty, + mutbl: mutbl + }) + } + ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty) + }; let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty); let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(rcvr_ty)); @@ -512,7 +516,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); let origin = TypeOrigin::MethodReceiver(span); - fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]); + fcx.demand_eqtype_with_origin(origin, rcvr_ty, self_arg_ty); } fn check_variances_for_type_defn(&self, @@ -578,7 +582,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } -fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, generics: &ty::Generics) { +fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) { + let generics = tcx.lookup_generics(def_id); let parent = tcx.lookup_generics(generics.parent.unwrap()); let impl_params: FxHashMap<_, _> = parent.types .iter() diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 4a4dea5b514e5..90541539c1e23 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -38,8 +38,6 @@ use rustc::hir::intravisit; use rustc::hir::{Item, ItemImpl}; use rustc::hir; -use std::rc::Rc; - mod orphan; mod overlap; mod unsafety; @@ -113,8 +111,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // If there are no traits, then this implementation must have a // base type. - let impl_items = self.create_impl_from_item(item); - if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) { debug!("(checking implementation) adding impl for trait '{:?}', item '{}'", trait_ref, @@ -144,8 +140,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { self.add_inherent_impl(base_def_id, impl_did); } } - - tcx.impl_or_trait_item_def_ids.borrow_mut().insert(impl_did, Rc::new(impl_items)); } fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { @@ -161,20 +155,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref); } - // Converts an implementation in the AST to a vector of items. - fn create_impl_from_item(&self, item: &Item) -> Vec { - match item.node { - ItemImpl(.., ref impl_items) => { - impl_items.iter() - .map(|impl_item| self.crate_context.tcx.map.local_def_id(impl_item.id)) - .collect() - } - _ => { - span_bug!(item.span, "can't convert a non-impl to an impl"); - } - } - } - // Destructors // @@ -187,10 +167,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { tcx.populate_implementations_for_trait_if_necessary(drop_trait); let drop_trait = tcx.lookup_trait_def(drop_trait); - let impl_items = tcx.impl_or_trait_item_def_ids.borrow(); - drop_trait.for_each_impl(tcx, |impl_did| { - let items = impl_items.get(&impl_did).unwrap(); + let items = tcx.associated_item_def_ids(impl_did); if items.is_empty() { // We'll error out later. For now, just don't ICE. return; diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 1bf140c21a5a5..b5aba512a66bd 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -48,25 +48,23 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { Value, } - fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> (ast::Name, Namespace) { - let item = tcx.impl_or_trait_item(def_id); - (item.name(), - match item { - ty::TypeTraitItem(..) => Namespace::Type, - ty::ConstTraitItem(..) => Namespace::Value, - ty::MethodTraitItem(..) => Namespace::Value, - }) - } + let name_and_namespace = |def_id| { + let item = self.tcx.associated_item(def_id); + (item.name, match item.kind { + ty::AssociatedKind::Type => Namespace::Type, + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => Namespace::Value, + }) + }; - let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow(); + let impl_items1 = self.tcx.associated_item_def_ids(impl1); + let impl_items2 = self.tcx.associated_item_def_ids(impl2); - for &item1 in &impl_items[&impl1][..] { - let (name, namespace) = name_and_namespace(self.tcx, item1); + for &item1 in &impl_items1[..] { + let (name, namespace) = name_and_namespace(item1); - for &item2 in &impl_items[&impl2][..] { - if (name, namespace) == name_and_namespace(self.tcx, item2) { + for &item2 in &impl_items2[..] { + if (name, namespace) == name_and_namespace(item2) { let msg = format!("duplicate definitions with name `{}`", name); let node_id = self.tcx.map.as_local_node_id(item1).unwrap(); self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5c51877ae743e..d92a98485103c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,7 +66,7 @@ use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::Substs; -use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; +use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::util::IntTypeExt; use rscope::*; @@ -79,7 +79,6 @@ use rustc_const_math::ConstInt; use std::cell::RefCell; use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::rc::Rc; use syntax::{abi, ast, attr}; use syntax::parse::token::keywords; @@ -351,24 +350,6 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { }) } - fn trait_defines_associated_type_named(&self, - trait_def_id: DefId, - assoc_name: ast::Name) - -> bool - { - if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) { - trait_associated_type_names(self.tcx(), trait_id) - .any(|name| name == assoc_name) - } else { - self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| { - match self.tcx().impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => item.name == assoc_name, - _ => false - } - }) - } - } - fn get_free_substs(&self) -> Option<&Substs<'tcx>> { None } @@ -557,60 +538,6 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - name: ast::Name, - id: ast::NodeId, - vis: &hir::Visibility, - sig: &hir::MethodSig, - defaultness: hir::Defaultness, - has_body: bool, - untransformed_rcvr_ty: Ty<'tcx>, - rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) { - let def_id = ccx.tcx.map.local_def_id(id); - let ty_generics = generics_of_def_id(ccx, def_id); - - let ty_generic_predicates = - ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false); - - let (fty, explicit_self_category) = { - let anon_scope = match container { - ImplContainer(_) => Some(AnonTypeScope::new(def_id)), - TraitContainer(_) => None - }; - AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - sig, untransformed_rcvr_ty, anon_scope) - }; - - let ty_method = ty::Method { - name: name, - generics: ty_generics, - predicates: ty_generic_predicates, - fty: fty, - explicit_self: explicit_self_category, - vis: ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness: defaultness, - has_body: has_body, - def_id: def_id, - container: container, - }; - - let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - ccx.tcx.map.span(id), def_id); - let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty); - debug!("method {} (id {}) has type {:?}", - name, id, fty); - ccx.tcx.tcache.borrow_mut().insert(def_id, fty); - write_ty_to_tcx(ccx, id, fty); - ccx.tcx.predicates.borrow_mut().insert(def_id, ty_method.predicates.clone()); - - debug!("writing method type: def_id={:?} mty={:?}", - def_id, ty_method); - - ccx.tcx.impl_or_trait_items.borrow_mut().insert(def_id, - ty::MethodTraitItem(Rc::new(ty_method))); -} - fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_generics: &'tcx ty::Generics<'tcx>, struct_predicates: &ty::GenericPredicates<'tcx>, @@ -631,62 +558,65 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_predicates.clone()); } +fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + container: AssociatedItemContainer, + id: ast::NodeId, + sig: &hir::MethodSig, + untransformed_rcvr_ty: Ty<'tcx>, + rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) { + let def_id = ccx.tcx.map.local_def_id(id); + let ty_generics = generics_of_def_id(ccx, def_id); + + let ty_generic_predicates = + ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false); + + let anon_scope = match container { + ImplContainer(_) => Some(AnonTypeScope::new(def_id)), + TraitContainer(_) => None + }; + let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + sig, untransformed_rcvr_ty, anon_scope); + + let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + ccx.tcx.map.span(id), def_id); + let fty = ccx.tcx.mk_fn_def(def_id, substs, fty); + ccx.tcx.tcache.borrow_mut().insert(def_id, fty); + write_ty_to_tcx(ccx, id, fty); + ccx.tcx.predicates.borrow_mut().insert(def_id, ty_generic_predicates); +} + fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - name: ast::Name, + container: AssociatedItemContainer, id: ast::NodeId, - vis: &hir::Visibility, - defaultness: hir::Defaultness, - ty: ty::Ty<'tcx>, - has_value: bool) + ty: ty::Ty<'tcx>) { let predicates = ty::GenericPredicates { parent: Some(container.id()), predicates: vec![] }; - ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), - predicates); + let def_id = ccx.tcx.map.local_def_id(id); + ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); + ccx.tcx.tcache.borrow_mut().insert(def_id, ty); write_ty_to_tcx(ccx, id, ty); - - let associated_const = Rc::new(ty::AssociatedConst { - name: name, - vis: ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness: defaultness, - def_id: ccx.tcx.map.local_def_id(id), - container: container, - ty: ty, - has_value: has_value - }); - ccx.tcx.impl_or_trait_items.borrow_mut() - .insert(ccx.tcx.map.local_def_id(id), ty::ConstTraitItem(associated_const)); } fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - name: ast::Name, + container: AssociatedItemContainer, id: ast::NodeId, - vis: &hir::Visibility, - defaultness: hir::Defaultness, ty: Option>) { let predicates = ty::GenericPredicates { parent: Some(container.id()), predicates: vec![] }; - ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), - predicates); + let def_id = ccx.tcx.map.local_def_id(id); + ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); - let associated_type = Rc::new(ty::AssociatedType { - name: name, - vis: ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness: defaultness, - ty: ty, - def_id: ccx.tcx.map.local_def_id(id), - container: container - }); - ccx.tcx.impl_or_trait_items.borrow_mut() - .insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type)); + if let Some(ty) = ty { + ccx.tcx.tcache.borrow_mut().insert(def_id, ty); + write_ty_to_tcx(ccx, id, ty); + } } fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, @@ -820,14 +750,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { generics: ty_generics, ty: ty, }); - // Trait-associated constants are always public. - let public = &hir::Public; - let visibility = if opt_trait_ref.is_some() { public } else { &impl_item.vis }; convert_associated_const(ccx, ImplContainer(def_id), - impl_item.name, impl_item.id, - visibility, - impl_item.defaultness, - ty, true /* has_value */); + impl_item.id, ty); } } @@ -844,21 +768,14 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); - convert_associated_type(ccx, ImplContainer(def_id), - impl_item.name, impl_item.id, &impl_item.vis, - impl_item.defaultness, Some(typ)); + convert_associated_type(ccx, ImplContainer(def_id), impl_item.id, Some(typ)); } } for impl_item in impl_items { if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - // Trait methods are always public. - let public = &hir::Public; - let method_vis = if opt_trait_ref.is_some() { public } else { &impl_item.vis }; - convert_method(ccx, ImplContainer(def_id), - impl_item.name, impl_item.id, method_vis, - sig, impl_item.defaultness, true, selfty, + impl_item.id, sig, selfty, &ty_predicates); } } @@ -880,7 +797,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Convert all the associated constants. for trait_item in trait_items { - if let hir::ConstTraitItem(ref ty, ref default) = trait_item.node { + if let hir::ConstTraitItem(ref ty, _) = trait_item.node { let const_def_id = ccx.tcx.map.local_def_id(trait_item.id); let ty_generics = generics_of_def_id(ccx, const_def_id); let ty = ccx.icx(&trait_predicates) @@ -890,14 +807,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { generics: ty_generics, ty: ty, }); - convert_associated_const(ccx, - container, - trait_item.name, - trait_item.id, - &hir::Public, - hir::Defaultness::Default, - ty, - default.is_some()) + convert_associated_const(ccx, container, trait_item.id, ty) } } @@ -911,39 +821,21 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) }); - convert_associated_type(ccx, - container, - trait_item.name, - trait_item.id, - &hir::Public, - hir::Defaultness::Default, - typ); + convert_associated_type(ccx, container, trait_item.id, typ); } } // Convert all the methods for trait_item in trait_items { - if let hir::MethodTraitItem(ref sig, ref body) = trait_item.node { + if let hir::MethodTraitItem(ref sig, _) = trait_item.node { convert_method(ccx, container, - trait_item.name, trait_item.id, - &hir::Inherited, sig, - hir::Defaultness::Default, - body.is_some(), tcx.mk_self_type(), &trait_predicates); - } } - - // Add an entry mapping - let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| { - ccx.tcx.map.local_def_id(trait_item.id) - }).collect()); - tcx.impl_or_trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), - trait_item_def_ids); }, hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { @@ -1308,28 +1200,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, tcx.intern_trait_def(trait_def) } -pub fn trait_associated_type_names<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_node_id: ast::NodeId) - -> impl Iterator + 'a -{ - let item = match tcx.map.get(trait_node_id) { - hir_map::NodeItem(item) => item, - _ => bug!("trait_node_id {} is not an item", trait_node_id) - }; - - let trait_items = match item.node { - hir::ItemTrait(.., ref trait_items) => trait_items, - _ => bug!("trait_node_id {} is not a trait", trait_node_id) - }; - - trait_items.iter().filter_map(|trait_item| { - match trait_item.node { - hir::TypeTraitItem(..) => Some(trait_item.name), - _ => None, - } - }) -} - fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) { let tcx = ccx.tcx; let trait_def = trait_def_of_item(ccx, it); @@ -2209,13 +2079,14 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); let lifetimes_in_associated_types: FxHashSet<_> = impl_items.iter() - .map(|item| ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(item.id))) - .filter_map(|item| match item { - ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, - ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None + .map(|item| ccx.tcx.map.local_def_id(item.id)) + .filter(|&def_id| { + let item = ccx.tcx.associated_item(def_id); + item.kind == ty::AssociatedKind::Type && item.has_value }) - .flat_map(|ty| ctp::parameters_for(&ty, true)) - .collect(); + .flat_map(|def_id| { + ctp::parameters_for(&ccx.tcx.lookup_item_type(def_id).ty, true) + }).collect(); for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() .zip(&ast_generics.lifetimes) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 1885b4276cc41..a2955169cbb81 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -163,7 +163,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Trait { let def = tcx.lookup_trait_def(did); - let trait_items = tcx.trait_items(did).clean(cx); + let trait_items = tcx.associated_items(did).map(|item| item.clean(cx)).collect(); let predicates = tcx.lookup_predicates(did); let generics = (def.generics, &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); @@ -307,7 +307,6 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext, for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { if !def_id.is_local() { - tcx.populate_implementations_for_primitive_if_necessary(def_id); build_impl(cx, tcx, def_id, &mut impls); } } @@ -367,21 +366,18 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } let predicates = tcx.lookup_predicates(did); - let trait_items = tcx.sess.cstore.impl_or_trait_items(did) - .iter() - .filter_map(|&did| { - match tcx.impl_or_trait_item(did) { - ty::ConstTraitItem(ref assoc_const) => { - let did = assoc_const.def_id; - let type_scheme = tcx.lookup_item_type(did); - let default = if assoc_const.has_value { + let trait_items = tcx.associated_items(did).filter_map(|item| { + match item.kind { + ty::AssociatedKind::Const => { + let type_scheme = tcx.lookup_item_type(item.def_id); + let default = if item.has_value { Some(pprust::expr_to_string( - lookup_const_by_id(tcx, did, None).unwrap().0)) + lookup_const_by_id(tcx, item.def_id, None).unwrap().0)) } else { None }; Some(clean::Item { - name: Some(assoc_const.name.clean(cx)), + name: Some(item.name.clean(cx)), inner: clean::AssociatedConstItem( type_scheme.ty.clean(cx), default, @@ -389,21 +385,21 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, source: clean::Span::empty(), attrs: vec![], visibility: None, - stability: tcx.lookup_stability(did).clean(cx), - deprecation: tcx.lookup_deprecation(did).clean(cx), - def_id: did + stability: tcx.lookup_stability(item.def_id).clean(cx), + deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), + def_id: item.def_id }) } - ty::MethodTraitItem(method) => { - if method.vis != ty::Visibility::Public && associated_trait.is_none() { + ty::AssociatedKind::Method => { + if item.vis != ty::Visibility::Public && associated_trait.is_none() { return None } - let mut item = method.clean(cx); - item.inner = match item.inner.clone() { + let mut cleaned = item.clean(cx); + cleaned.inner = match cleaned.inner.clone() { clean::TyMethodItem(clean::TyMethod { unsafety, decl, generics, abi }) => { - let constness = if tcx.sess.cstore.is_const_fn(did) { + let constness = if tcx.sess.cstore.is_const_fn(item.def_id) { hir::Constness::Const } else { hir::Constness::NotConst @@ -419,12 +415,11 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } _ => panic!("not a tymethod"), }; - Some(item) + Some(cleaned) } - ty::TypeTraitItem(ref assoc_ty) => { - let did = assoc_ty.def_id; + ty::AssociatedKind::Type => { let typedef = clean::Typedef { - type_: assoc_ty.ty.unwrap().clean(cx), + type_: tcx.lookup_item_type(item.def_id).ty.clean(cx), generics: clean::Generics { lifetimes: vec![], type_params: vec![], @@ -432,14 +427,14 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } }; Some(clean::Item { - name: Some(assoc_ty.name.clean(cx)), + name: Some(item.name.clean(cx)), inner: clean::TypedefItem(typedef, true), source: clean::Span::empty(), attrs: vec![], visibility: None, - stability: tcx.lookup_stability(did).clean(cx), - deprecation: tcx.lookup_deprecation(did).clean(cx), - def_id: did + stability: tcx.lookup_stability(item.def_id).clean(cx), + deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), + def_id: item.def_id }) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index df13e384d9615..9e29d191946b7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1338,48 +1338,117 @@ impl Clean for hir::ImplItem { } } -impl<'tcx> Clean for ty::Method<'tcx> { +impl<'tcx> Clean for ty::AssociatedItem { fn clean(&self, cx: &DocContext) -> Item { - let generics = (self.generics, &self.predicates).clean(cx); - let mut decl = (self.def_id, &self.fty.sig).clean(cx); - match self.explicit_self { - ty::ExplicitSelfCategory::ByValue => { - decl.inputs.values[0].type_ = Infer; + let inner = match self.kind { + ty::AssociatedKind::Const => { + let ty = cx.tcx().lookup_item_type(self.def_id).ty; + AssociatedConstItem(ty.clean(cx), None) } - ty::ExplicitSelfCategory::ByReference(..) => { - match decl.inputs.values[0].type_ { - BorrowedRef{ref mut type_, ..} => **type_ = Infer, - _ => unreachable!(), + ty::AssociatedKind::Method => { + let generics = (cx.tcx().lookup_generics(self.def_id), + &cx.tcx().lookup_predicates(self.def_id)).clean(cx); + let fty = match cx.tcx().lookup_item_type(self.def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => unreachable!() + }; + let mut decl = (self.def_id, &fty.sig).clean(cx); + + if self.method_has_self_argument { + let self_ty = match self.container { + ty::ImplContainer(def_id) => { + cx.tcx().lookup_item_type(def_id).ty + } + ty::TraitContainer(_) => cx.tcx().mk_self_type() + }; + let self_arg_ty = *fty.sig.input(0).skip_binder(); + if self_arg_ty == self_ty { + decl.inputs.values[0].type_ = Infer; + } else if let ty::TyRef(_, mt) = self_arg_ty.sty { + if mt.ty == self_ty { + match decl.inputs.values[0].type_ { + BorrowedRef{ref mut type_, ..} => **type_ = Infer, + _ => unreachable!(), + } + } + } + } + let provided = match self.container { + ty::ImplContainer(_) => false, + ty::TraitContainer(_) => self.has_value + }; + if provided { + MethodItem(Method { + unsafety: fty.unsafety, + generics: generics, + decl: decl, + abi: fty.abi, + + // trait methods canot (currently, at least) be const + constness: hir::Constness::NotConst, + }) + } else { + TyMethodItem(TyMethod { + unsafety: fty.unsafety, + generics: generics, + decl: decl, + abi: fty.abi, + }) } } - _ => {} - } - let provided = match self.container { - ty::ImplContainer(..) => false, - ty::TraitContainer(did) => { - cx.tcx().provided_trait_methods(did).iter().any(|m| { - m.def_id == self.def_id - }) + ty::AssociatedKind::Type => { + let my_name = self.name.clean(cx); + + let mut bounds = if let ty::TraitContainer(did) = self.container { + // When loading a cross-crate associated type, the bounds for this type + // are actually located on the trait/impl itself, so we need to load + // all of the generics from there and then look for bounds that are + // applied to this associated type in question. + let def = cx.tcx().lookup_trait_def(did); + let predicates = cx.tcx().lookup_predicates(did); + let generics = (def.generics, &predicates).clean(cx); + generics.where_predicates.iter().filter_map(|pred| { + let (name, self_type, trait_, bounds) = match *pred { + WherePredicate::BoundPredicate { + ty: QPath { ref name, ref self_type, ref trait_ }, + ref bounds + } => (name, self_type, trait_, bounds), + _ => return None, + }; + if *name != my_name { return None } + match **trait_ { + ResolvedPath { did, .. } if did == self.container.id() => {} + _ => return None, + } + match **self_type { + Generic(ref s) if *s == "Self" => {} + _ => return None, + } + Some(bounds) + }).flat_map(|i| i.iter().cloned()).collect::>() + } else { + vec![] + }; + + // Our Sized/?Sized bound didn't get handled when creating the generics + // because we didn't actually get our whole set of bounds until just now + // (some of them may have come from the trait). If we do have a sized + // bound, we remove it, and if we don't then we add the `?Sized` bound + // at the end. + match bounds.iter().position(|b| b.is_sized_bound(cx)) { + Some(i) => { bounds.remove(i); } + None => bounds.push(TyParamBound::maybe_sized(cx)), + } + + let ty = if self.has_value { + Some(cx.tcx().lookup_item_type(self.def_id).ty) + } else { + None + }; + + AssociatedTypeItem(bounds, ty.clean(cx)) } }; - let inner = if provided { - MethodItem(Method { - unsafety: self.fty.unsafety, - generics: generics, - decl: decl, - abi: self.fty.abi, - - // trait methods canot (currently, at least) be const - constness: hir::Constness::NotConst, - }) - } else { - TyMethodItem(TyMethod { - unsafety: self.fty.unsafety, - generics: generics, - decl: decl, - abi: self.fty.abi, - }) - }; Item { name: Some(self.name.clean(cx)), @@ -1394,16 +1463,6 @@ impl<'tcx> Clean for ty::Method<'tcx> { } } -impl<'tcx> Clean for ty::ImplOrTraitItem<'tcx> { - fn clean(&self, cx: &DocContext) -> Item { - match *self { - ty::ConstTraitItem(ref cti) => cti.clean(cx), - ty::MethodTraitItem(ref mti) => mti.clean(cx), - ty::TypeTraitItem(ref tti) => tti.clean(cx), - } - } -} - /// A trait reference, which may have higher ranked lifetimes. #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub struct PolyTrait { @@ -2884,79 +2943,6 @@ impl Clean for attr::Deprecation { } } -impl<'tcx> Clean for ty::AssociatedConst<'tcx> { - fn clean(&self, cx: &DocContext) -> Item { - Item { - source: DUMMY_SP.clean(cx), - name: Some(self.name.clean(cx)), - attrs: Vec::new(), - inner: AssociatedConstItem(self.ty.clean(cx), None), - visibility: None, - def_id: self.def_id, - stability: None, - deprecation: None, - } - } -} - -impl<'tcx> Clean for ty::AssociatedType<'tcx> { - fn clean(&self, cx: &DocContext) -> Item { - let my_name = self.name.clean(cx); - - let mut bounds = if let ty::TraitContainer(did) = self.container { - // When loading a cross-crate associated type, the bounds for this type - // are actually located on the trait/impl itself, so we need to load - // all of the generics from there and then look for bounds that are - // applied to this associated type in question. - let def = cx.tcx().lookup_trait_def(did); - let predicates = cx.tcx().lookup_predicates(did); - let generics = (def.generics, &predicates).clean(cx); - generics.where_predicates.iter().filter_map(|pred| { - let (name, self_type, trait_, bounds) = match *pred { - WherePredicate::BoundPredicate { - ty: QPath { ref name, ref self_type, ref trait_ }, - ref bounds - } => (name, self_type, trait_, bounds), - _ => return None, - }; - if *name != my_name { return None } - match **trait_ { - ResolvedPath { did, .. } if did == self.container.id() => {} - _ => return None, - } - match **self_type { - Generic(ref s) if *s == "Self" => {} - _ => return None, - } - Some(bounds) - }).flat_map(|i| i.iter().cloned()).collect::>() - } else { - vec![] - }; - - // Our Sized/?Sized bound didn't get handled when creating the generics - // because we didn't actually get our whole set of bounds until just now - // (some of them may have come from the trait). If we do have a sized - // bound, we remove it, and if we don't then we add the `?Sized` bound - // at the end. - match bounds.iter().position(|b| b.is_sized_bound(cx)) { - Some(i) => { bounds.remove(i); } - None => bounds.push(TyParamBound::maybe_sized(cx)), - } - - Item { - source: DUMMY_SP.clean(cx), - name: Some(self.name.clean(cx)), - attrs: inline::load_attrs(cx, cx.tcx(), self.def_id), - inner: AssociatedTypeItem(bounds, self.ty.clean(cx)), - visibility: self.vis.clean(cx), - def_id: self.def_id, - stability: cx.tcx().lookup_stability(self.def_id).clean(cx), - deprecation: cx.tcx().lookup_deprecation(self.def_id).clean(cx), - } - } -} - fn lang_struct(cx: &DocContext, did: Option, t: ty::Ty, name: &str, fallback: fn(Box) -> Type) -> Type {