From 0ea66f35a95e3662498881398298dcc553294d5a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 8 Apr 2016 22:47:55 +0000 Subject: [PATCH 01/97] Avoid gated feature checking unconfigured items --- src/librustc_driver/driver.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 67c52bb6c36d7..b6e7080f16c7c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -625,21 +625,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, ret }); - // Needs to go *after* expansion to be able to check the results - // of macro expansion. This runs before #[cfg] to try to catch as - // much as possible (e.g. help the programmer avoid platform - // specific differences) - time(time_passes, "complete gated feature checking 1", || { - sess.track_errors(|| { - let features = syntax::feature_gate::check_crate(sess.codemap(), - &sess.parse_sess.span_diagnostic, - &krate, - &attributes, - sess.opts.unstable_features); - *sess.features.borrow_mut() = features; - }) - })?; - // JBC: make CFG processing part of expansion to avoid this problem: // strip again, in case expansion added anything with a #[cfg]. @@ -662,6 +647,19 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate })?; + // Needs to go *after* expansion to be able to check the results + // of macro expansion. + time(time_passes, "complete gated feature checking 1", || { + sess.track_errors(|| { + let features = syntax::feature_gate::check_crate(sess.codemap(), + &sess.parse_sess.span_diagnostic, + &krate, + &attributes, + sess.opts.unstable_features); + *sess.features.borrow_mut() = features; + }) + })?; + krate = time(time_passes, "maybe building test harness", || { syntax::test::modify_for_testing(&sess.parse_sess, &sess.opts.cfg, krate, sess.diagnostic()) }); From 417a6df9b0764ff086d71fff9808a31715e9cd0d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 8 Apr 2016 23:41:27 +0000 Subject: [PATCH 02/97] Add regression test --- src/test/compile-fail/expanded-cfg.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/test/compile-fail/expanded-cfg.rs diff --git a/src/test/compile-fail/expanded-cfg.rs b/src/test/compile-fail/expanded-cfg.rs new file mode 100644 index 0000000000000..2f74aeba9eb43 --- /dev/null +++ b/src/test/compile-fail/expanded-cfg.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +macro_rules! mac { + {} => { + #[cfg(attr)] + mod m { + #[lang_item] + fn f() {} + } + } +} + +mac! {} + +#[rustc_error] +fn main() {} //~ ERROR compilation successful From 5eb775eedd64d3b3abab63a8ef39ca9664f4cad0 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 9 Apr 2016 00:16:57 +0000 Subject: [PATCH 03/97] Remove redundant gated feature checking pass --- src/librustc_driver/driver.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b6e7080f16c7c..fa7ffec5a6acc 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -647,19 +647,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate })?; - // Needs to go *after* expansion to be able to check the results - // of macro expansion. - time(time_passes, "complete gated feature checking 1", || { - sess.track_errors(|| { - let features = syntax::feature_gate::check_crate(sess.codemap(), - &sess.parse_sess.span_diagnostic, - &krate, - &attributes, - sess.opts.unstable_features); - *sess.features.borrow_mut() = features; - }) - })?; - krate = time(time_passes, "maybe building test harness", || { syntax::test::modify_for_testing(&sess.parse_sess, &sess.opts.cfg, krate, sess.diagnostic()) }); @@ -676,10 +663,8 @@ pub fn phase_2_configure_and_expand(sess: &Session, "checking for inline asm in case the target doesn't support it", || no_asm::check_crate(sess, &krate)); - // One final feature gating of the true AST that gets compiled - // later, to make sure we've got everything (e.g. configuration - // can insert new attributes via `cfg_attr`) - time(time_passes, "complete gated feature checking 2", || { + // Needs to go *after* expansion to be able to check the results of macro expansion. + time(time_passes, "complete gated feature checking", || { sess.track_errors(|| { let features = syntax::feature_gate::check_crate(sess.codemap(), &sess.parse_sess.span_diagnostic, From 86f069d41a89122740d58d0eb8eaeb7496bb03ce Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 9 Apr 2016 05:37:31 +0000 Subject: [PATCH 04/97] Remove redundant call to `expand_item_multi_modifier` --- src/libsyntax/ext/expand.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8550617560df3..27d7234aae216 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -309,9 +309,7 @@ macro_rules! with_exts_frame { // When we enter a module, record it, for the sake of `module!` pub fn expand_item(it: P, fld: &mut MacroExpander) -> SmallVector> { - let it = expand_item_multi_modifier(Annotatable::Item(it), fld); - - expand_annotatable(it, fld) + expand_annotatable(Annotatable::Item(it), fld) .into_iter().map(|i| i.expect_item()).collect() } From 9e167ef60ac6201971867a74a6d00628fd7a0106 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 21 Apr 2016 22:19:49 -0700 Subject: [PATCH 05/97] Add Entry::key This method was present on both variants of Entry, but not the enum cc #32281 --- src/libcollections/btree/map.rs | 9 +++++++++ src/libstd/collections/hash/map.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index de40568fd6704..0dbdad98c8672 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1522,6 +1522,15 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { Vacant(entry) => entry.insert(default()), } } + + /// Returns a reference to this entry's key. + #[unstable(feature = "map_entry_keys", issue = "32281")] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } } impl<'a, K: Ord, V> VacantEntry<'a, K, V> { diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index c20270e830665..4b5696b79133a 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1533,6 +1533,15 @@ impl<'a, K, V> Entry<'a, K, V> { Vacant(entry) => entry.insert(default()), } } + + /// Returns a reference to this entry's key. + #[unstable(feature = "map_entry_keys", issue = "32281")] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } } impl<'a, K, V> OccupiedEntry<'a, K, V> { From c46164b626925083519bfd48733fad48cc1ddec5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 26 Apr 2016 04:20:50 +0000 Subject: [PATCH 06/97] Refactor away field `vis` of `ModuleS` --- src/librustc_resolve/build_reduced_graph.rs | 39 +++++++++++---------- src/librustc_resolve/lib.rs | 33 ++++------------- 2 files changed, 27 insertions(+), 45 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index ed473da19176b..6dfd3e00be864 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -46,9 +46,9 @@ trait ToNameBinding<'a> { fn to_name_binding(self) -> NameBinding<'a>; } -impl<'a> ToNameBinding<'a> for (Module<'a>, Span) { +impl<'a> ToNameBinding<'a> for (Module<'a>, Span, ty::Visibility) { fn to_name_binding(self) -> NameBinding<'a> { - NameBinding::create_from_module(self.0, Some(self.1)) + NameBinding { kind: NameBindingKind::Module(self.0), span: Some(self.1), vis: self.2 } } } @@ -247,8 +247,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { }; let parent_link = ModuleParentLink(parent, name); let def = Def::Mod(def_id); - let module = self.new_extern_crate_module(parent_link, def, vis, item.id); - self.define(parent, name, TypeNS, (module, sp)); + let module = self.new_extern_crate_module(parent_link, def, item.id); + self.define(parent, name, TypeNS, (module, sp, vis)); self.build_reduced_graph_for_external_crate(module); } @@ -257,8 +257,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { ItemMod(..) => { let parent_link = ModuleParentLink(parent, name); let def = Def::Mod(self.ast_map.local_def_id(item.id)); - let module = self.new_module(parent_link, Some(def), false, vis); - self.define(parent, name, TypeNS, (module, sp)); + let module = self.new_module(parent_link, Some(def), false); + self.define(parent, name, TypeNS, (module, sp, vis)); self.module_map.insert(item.id, module); *parent_ref = module; } @@ -289,12 +289,12 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { ItemEnum(ref enum_definition, _) => { let parent_link = ModuleParentLink(parent, name); let def = Def::Enum(self.ast_map.local_def_id(item.id)); - let module = self.new_module(parent_link, Some(def), false, vis); - self.define(parent, name, TypeNS, (module, sp)); + let module = self.new_module(parent_link, Some(def), false); + self.define(parent, name, TypeNS, (module, sp, vis)); for variant in &(*enum_definition).variants { let item_def_id = self.ast_map.local_def_id(item.id); - self.build_reduced_graph_for_variant(variant, item_def_id, module); + self.build_reduced_graph_for_variant(variant, item_def_id, module, vis); } } @@ -328,8 +328,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { // Add all the items within to a new module. let parent_link = ModuleParentLink(parent, name); let def = Def::Trait(def_id); - let module_parent = self.new_module(parent_link, Some(def), false, vis); - self.define(parent, name, TypeNS, (module_parent, sp)); + let module_parent = self.new_module(parent_link, Some(def), false); + self.define(parent, name, TypeNS, (module_parent, sp, vis)); // Add the names of all the items to the trait info. for item in items { @@ -353,7 +353,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { fn build_reduced_graph_for_variant(&mut self, variant: &Variant, item_id: DefId, - parent: Module<'b>) { + parent: Module<'b>, + vis: ty::Visibility) { let name = variant.node.name; if variant.node.data.is_struct() { // Not adding fields for variants as they are not accessed with a self receiver @@ -364,8 +365,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { // Variants are always treated as importable to allow them to be glob used. // All variants are defined in both type and value namespaces as future-proofing. let def = Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id())); - self.define(parent, name, ValueNS, (def, variant.span, parent.vis)); - self.define(parent, name, TypeNS, (def, variant.span, parent.vis)); + self.define(parent, name, ValueNS, (def, variant.span, vis)); + self.define(parent, name, TypeNS, (def, variant.span, vis)); } /// Constructs the reduced graph for one foreign item. @@ -396,7 +397,7 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { block_id); let parent_link = BlockParentLink(parent, block_id); - let new_module = self.new_module(parent_link, None, false, parent.vis); + let new_module = self.new_module(parent_link, None, false); self.module_map.insert(block_id, new_module); *parent = new_module; } @@ -425,8 +426,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { debug!("(building reduced graph for external crate) building module {} {:?}", name, vis); let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), true, vis); - self.try_define(parent, name, TypeNS, (module, DUMMY_SP)); + let module = self.new_module(parent_link, Some(def), true); + self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::Variant(_, variant_id) => { debug!("(building reduced graph for external crate) building variant {}", name); @@ -467,8 +468,8 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { } let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), true, vis); - self.try_define(parent, name, TypeNS, (module, DUMMY_SP)); + let module = self.new_module(parent_link, Some(def), true); + self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::TyAlias(..) | Def::AssociatedTy(..) => { debug!("(building reduced graph for external crate) building type {}", name); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 293b4de71fac4..16954f6bc97b4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -818,7 +818,6 @@ enum ParentLink<'a> { pub struct ModuleS<'a> { parent_link: ParentLink<'a>, def: Option, - vis: ty::Visibility, // If the module is an extern crate, `def` is root of the external crate and `extern_crate_id` // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None). @@ -849,12 +848,10 @@ impl<'a> ModuleS<'a> { fn new(parent_link: ParentLink<'a>, def: Option, external: bool, - vis: ty::Visibility, arenas: &'a ResolverArenas<'a>) -> Self { ModuleS { parent_link: parent_link, def: def, - vis: vis, extern_crate_id: None, resolutions: RefCell::new(HashMap::new()), unresolved_imports: RefCell::new(Vec::new()), @@ -895,7 +892,7 @@ impl<'a> ModuleS<'a> { impl<'a> fmt::Debug for ModuleS<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}, {:?}", self.def, self.vis) + write!(f, "{:?}", self.def) } } @@ -923,14 +920,6 @@ enum NameBindingKind<'a> { struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>); impl<'a> NameBinding<'a> { - fn create_from_module(module: Module<'a>, span: Option) -> Self { - NameBinding { - kind: NameBindingKind::Module(module), - span: span, - vis: module.vis, - } - } - fn module(&self) -> Option> { match self.kind { NameBindingKind::Module(module) => Some(module), @@ -1148,9 +1137,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { arenas: &'a ResolverArenas<'a>) -> Resolver<'a, 'tcx> { let root_def_id = ast_map.local_def_id(CRATE_NODE_ID); - let vis = ty::Visibility::Public; let graph_root = - ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, vis, arenas); + ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, arenas); let graph_root = arenas.alloc_module(graph_root); Resolver { @@ -1208,21 +1196,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn new_module(&self, - parent_link: ParentLink<'a>, - def: Option, - external: bool, - vis: ty::Visibility) -> Module<'a> { - self.arenas.alloc_module(ModuleS::new(parent_link, def, external, vis, self.arenas)) + fn new_module(&self, parent_link: ParentLink<'a>, def: Option, external: bool) + -> Module<'a> { + self.arenas.alloc_module(ModuleS::new(parent_link, def, external, self.arenas)) } - fn new_extern_crate_module(&self, - parent_link: ParentLink<'a>, - def: Def, - vis: ty::Visibility, - local_node_id: NodeId) + fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def, local_node_id: NodeId) -> Module<'a> { - let mut module = ModuleS::new(parent_link, Some(def), false, vis, self.arenas); + let mut module = ModuleS::new(parent_link, Some(def), false, self.arenas); module.extern_crate_id = Some(local_node_id); self.arenas.modules.alloc(module) } From c9d8e1493c840a9901f7caecda26de1a8a48f754 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 27 Apr 2016 01:13:15 +0000 Subject: [PATCH 07/97] Refactor field `span` of `NameBinding` from `Option` to `Span`. --- src/librustc_resolve/build_reduced_graph.rs | 4 ++-- src/librustc_resolve/lib.rs | 15 +++++++-------- src/librustc_resolve/resolve_imports.rs | 8 ++++---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6dfd3e00be864..6a8779d79db6f 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -48,13 +48,13 @@ trait ToNameBinding<'a> { impl<'a> ToNameBinding<'a> for (Module<'a>, Span, ty::Visibility) { fn to_name_binding(self) -> NameBinding<'a> { - NameBinding { kind: NameBindingKind::Module(self.0), span: Some(self.1), vis: self.2 } + NameBinding { kind: NameBindingKind::Module(self.0), span: self.1, vis: self.2 } } } impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) { fn to_name_binding(self) -> NameBinding<'a> { - NameBinding { kind: NameBindingKind::Def(self.0), span: Some(self.1), vis: self.2 } + NameBinding { kind: NameBindingKind::Def(self.0), span: self.1, vis: self.2 } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 16954f6bc97b4..a5831186c8779 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -349,7 +349,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, if let Some(binding) = resolver.current_module .resolve_name_in_lexical_scope(name, ValueNS) { if binding.is_import() { - err.span_note(binding.span.unwrap(), "constant imported here"); + err.span_note(binding.span, "constant imported here"); } } err @@ -900,7 +900,7 @@ impl<'a> fmt::Debug for ModuleS<'a> { #[derive(Clone, Debug)] pub struct NameBinding<'a> { kind: NameBindingKind<'a>, - span: Option, + span: Span, vis: ty::Visibility, } @@ -3293,7 +3293,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { identifier: ident, parameters: params, }; - let span = name_binding.span.unwrap_or(syntax::codemap::DUMMY_SP); + let span = name_binding.span; let mut segms = path_segments.clone(); segms.push(segment); let segms = HirVec::from_vec(segms); @@ -3447,7 +3447,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { binding: &NameBinding, old_binding: &NameBinding) { // Error on the second of two conflicting names - if old_binding.span.unwrap().lo > binding.span.unwrap().lo { + if old_binding.span.lo > binding.span.lo { return self.report_conflict(parent, name, ns, old_binding, binding); } @@ -3463,7 +3463,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { false => ("defined", "definition"), }; - let span = binding.span.unwrap(); + let span = binding.span; let msg = { let kind = match (ns, old_binding.module()) { (ValueNS, _) => "a value", @@ -3488,9 +3488,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }, }; - let span = old_binding.span.unwrap(); - if span != codemap::DUMMY_SP { - err.span_note(span, &format!("previous {} of `{}` here", noun, name)); + if old_binding.span != codemap::DUMMY_SP { + err.span_note(old_binding.span, &format!("previous {} of `{}` here", noun, name)); } err.emit(); } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f335f145a1072..4a87ffe820d4a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -26,7 +26,7 @@ use rustc::hir::def::*; use syntax::ast::{NodeId, Name}; use syntax::attr::AttrMetaMethods; -use syntax::codemap::Span; +use syntax::codemap::{Span, DUMMY_SP}; use syntax::util::lev_distance::find_best_match_for_name; use std::cell::{Cell, RefCell}; @@ -76,7 +76,7 @@ impl<'a> ImportDirective<'a> { directive: self, privacy_error: privacy_error, }, - span: Some(self.span), + span: self.span, vis: self.vis, } } @@ -412,7 +412,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { if let SingleImport { target, .. } = e.import_directive.subclass { let dummy_binding = self.resolver.arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Def(Def::Err), - span: None, + span: DUMMY_SP, vis: ty::Visibility::Public, }); let dummy_binding = e.import_directive.import(dummy_binding, None); @@ -696,7 +696,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { (error E0364), consider declaring its enum as `pub`", name); let lint = lint::builtin::PRIVATE_IN_PUBLIC; - self.resolver.session.add_lint(lint, directive.id, binding.span.unwrap(), msg); + self.resolver.session.add_lint(lint, directive.id, binding.span, msg); } } } From 2ccaeed50efc2d55ea05ad4c1178b6ce38bf9aca Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 26 Apr 2016 07:58:58 +0000 Subject: [PATCH 08/97] Refactor away `FallbackChecks` and remove dead code --- src/librustc_resolve/lib.rs | 69 ++++--------------------------------- 1 file changed, 6 insertions(+), 63 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a5831186c8779..e9bbd686a3f60 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -42,7 +42,6 @@ use self::ModulePrefixResult::*; use self::AssocItemResolveResult::*; use self::BareIdentifierPatternResolution::*; use self::ParentLink::*; -use self::FallbackChecks::*; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; @@ -81,7 +80,7 @@ use rustc::hir::{Pat, PatKind, Path, PrimTy}; use rustc::hir::{PathSegment, PathParameters}; use rustc::hir::HirVec; use rustc::hir::{TraitRef, Ty, TyBool, TyChar, TyFloat, TyInt}; -use rustc::hir::{TyRptr, TyStr, TyUint, TyPath, TyPtr}; +use rustc::hir::{TyRptr, TyStr, TyUint, TyPath}; use std::collections::{HashMap, HashSet}; use std::cell::{Cell, RefCell}; @@ -676,9 +675,7 @@ impl ResolveResult { enum FallbackSuggestion { NoSuggestion, Field, - Method, TraitItem, - StaticMethod(String), TraitMethod(String), } @@ -1124,12 +1121,6 @@ impl<'a> ResolverArenas<'a> { } } -#[derive(PartialEq)] -enum FallbackChecks { - Everything, - OnlyTraitAndStatics, -} - impl<'a, 'tcx> Resolver<'a, 'tcx> { fn new(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>, @@ -2821,13 +2812,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } fn find_fallback_in_self_type(&mut self, name: Name) -> FallbackSuggestion { - fn extract_path_and_node_id(t: &Ty, - allow: FallbackChecks) - -> Option<(Path, NodeId, FallbackChecks)> { + fn extract_node_id(t: &Ty) -> Option { match t.node { - TyPath(None, ref path) => Some((path.clone(), t.id, allow)), - TyPtr(ref mut_ty) => extract_path_and_node_id(&mut_ty.ty, OnlyTraitAndStatics), - TyRptr(_, ref mut_ty) => extract_path_and_node_id(&mut_ty.ty, allow), + TyPath(None, _) => Some(t.id), + TyRptr(_, ref mut_ty) => extract_node_id(&mut_ty.ty), // This doesn't handle the remaining `Ty` variants as they are not // that commonly the self_type, it might be interesting to provide // support for those in future. @@ -2835,23 +2823,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn get_module<'a, 'tcx>(this: &mut Resolver<'a, 'tcx>, - span: Span, - name_path: &[ast::Name]) - -> Option> { - let last_name = name_path.last().unwrap(); - - if name_path.len() == 1 { - match this.primitive_type_table.primitive_types.get(last_name) { - Some(_) => None, - None => this.current_module.resolve_name_in_lexical_scope(*last_name, TypeNS) - .and_then(NameBinding::module) - } - } else { - this.resolve_module_path(&name_path, UseLexicalScope, span).success() - } - } - fn is_static_method(this: &Resolver, did: DefId) -> bool { if let Some(node_id) = this.ast_map.as_local_node_id(did) { let sig = match this.ast_map.get(node_id) { @@ -2871,15 +2842,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - let (path, node_id, allowed) = match self.current_self_type { - Some(ref ty) => match extract_path_and_node_id(ty, Everything) { - Some(x) => x, - None => return NoSuggestion, - }, - None => return NoSuggestion, - }; - - if allowed == Everything { + if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) { // Look for a field with the same name in the current self_type. match self.def_map.borrow().get(&node_id).map(|d| d.full_def()) { Some(Def::Enum(did)) | @@ -2897,24 +2860,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - let name_path = path.segments.iter().map(|seg| seg.identifier.name).collect::>(); - - // Look for a method in the current self type's impl module. - if let Some(module) = get_module(self, path.span, &name_path) { - if let Some(binding) = module.resolve_name_in_lexical_scope(name, ValueNS) { - if let Some(Def::Method(did)) = binding.def() { - if is_static_method(self, did) { - return StaticMethod(path_names_to_string(&path, 0)); - } - if self.current_trait_ref.is_some() { - return TraitItem; - } else if allowed == Everything { - return Method; - } - } - } - } - // Look for a method in the current trait. if let Some((trait_did, ref trait_ref)) = self.current_trait_ref { if let Some(&did) = self.trait_item_map.get(&(name, trait_did)) { @@ -3073,10 +3018,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } Field => format!("`self.{}`", path_name), - Method | TraitItem => format!("to call `self.{}`", path_name), - TraitMethod(path_str) | - StaticMethod(path_str) => + TraitMethod(path_str) => format!("to call `{}::{}`", path_str, path_name), }; From 82e0dd5ac1166426f4b1b91cc184ae3797842467 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 26 Apr 2016 08:29:13 +0000 Subject: [PATCH 09/97] Refactor away `is_static_method` --- src/librustc_resolve/build_reduced_graph.rs | 10 ++++++--- src/librustc_resolve/lib.rs | 25 +++------------------ 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6a8779d79db6f..4dc19434c8024 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -334,15 +334,19 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { // Add the names of all the items to the trait info. for item in items { let item_def_id = self.ast_map.local_def_id(item.id); + let mut is_static_method = false; let (def, ns) = match item.node { hir::ConstTraitItem(..) => (Def::AssociatedConst(item_def_id), ValueNS), - hir::MethodTraitItem(..) => (Def::Method(item_def_id), ValueNS), + hir::MethodTraitItem(ref sig, _) => { + is_static_method = sig.explicit_self.node == hir::SelfStatic; + (Def::Method(item_def_id), ValueNS) + } hir::TypeTraitItem(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS), }; self.define(module_parent, item.name, ns, (def, item.span, vis)); - self.trait_item_map.insert((item.name, def_id), item_def_id); + self.trait_item_map.insert((item.name, def_id), is_static_method); } } } @@ -464,7 +468,7 @@ impl<'b, 'tcx:'b> Resolver<'b, 'tcx> { '{}'", trait_item_name); - self.trait_item_map.insert((trait_item_name, def_id), trait_item_def.def_id()); + self.trait_item_map.insert((trait_item_name, def_id), false); } let parent_link = ModuleParentLink(parent, name); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e9bbd686a3f60..16e97e56755e8 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1016,7 +1016,7 @@ pub struct Resolver<'a, 'tcx: 'a> { graph_root: Module<'a>, - trait_item_map: FnvHashMap<(Name, DefId), DefId>, + trait_item_map: FnvHashMap<(Name, DefId), bool /* is static method? */>, structs: FnvHashMap>, @@ -2823,25 +2823,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn is_static_method(this: &Resolver, did: DefId) -> bool { - if let Some(node_id) = this.ast_map.as_local_node_id(did) { - let sig = match this.ast_map.get(node_id) { - hir_map::NodeTraitItem(trait_item) => match trait_item.node { - hir::MethodTraitItem(ref sig, _) => sig, - _ => return false, - }, - hir_map::NodeImplItem(impl_item) => match impl_item.node { - hir::ImplItemKind::Method(ref sig, _) => sig, - _ => return false, - }, - _ => return false, - }; - sig.explicit_self.node == hir::SelfStatic - } else { - this.session.cstore.is_static_method(did) - } - } - if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) { // Look for a field with the same name in the current self_type. match self.def_map.borrow().get(&node_id).map(|d| d.full_def()) { @@ -2862,8 +2843,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Look for a method in the current trait. if let Some((trait_did, ref trait_ref)) = self.current_trait_ref { - if let Some(&did) = self.trait_item_map.get(&(name, trait_did)) { - if is_static_method(self, did) { + if let Some(&is_static_method) = self.trait_item_map.get(&(name, trait_did)) { + if is_static_method { return TraitMethod(path_names_to_string(&trait_ref.path, 0)); } else { return TraitItem; From 6da115374ffd344f9bc748df36a50b55e61b4ea8 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 25 Apr 2016 05:34:59 +0000 Subject: [PATCH 10/97] Refactor away `get_trait_name` --- src/librustc_resolve/lib.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 16e97e56755e8..d4ef3d365d19e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -829,7 +829,7 @@ pub struct ModuleS<'a> { globs: RefCell>>, // Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell]>>>, + traits: RefCell)]>>>, // Whether this module is populated. If not populated, any attempt to // access the children must be preceded with a @@ -1234,14 +1234,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.glob_map.insert(directive.id, new_set); } - fn get_trait_name(&self, did: DefId) -> Name { - if let Some(node_id) = self.ast_map.as_local_node_id(did) { - self.ast_map.expect_item(node_id).name - } else { - self.session.cstore.item_name(did) - } - } - /// Resolves the given module path from the given root `module_`. fn resolve_module_path_from_root(&mut self, module_: Module<'a>, @@ -3146,20 +3138,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut traits = module.traits.borrow_mut(); if traits.is_none() { let mut collected_traits = Vec::new(); - module.for_each_child(|_, ns, binding| { + module.for_each_child(|name, ns, binding| { if ns != TypeNS { return } if let Some(Def::Trait(_)) = binding.def() { - collected_traits.push(binding); + collected_traits.push((name, binding)); } }); *traits = Some(collected_traits.into_boxed_slice()); } - for binding in traits.as_ref().unwrap().iter() { + for &(trait_name, binding) in traits.as_ref().unwrap().iter() { let trait_def_id = binding.def().unwrap().def_id(); if self.trait_item_map.contains_key(&(name, trait_def_id)) { add_trait_info(&mut found_traits, trait_def_id, name); - let trait_name = self.get_trait_name(trait_def_id); self.record_use(trait_name, TypeNS, binding); } } From 3bcf818a8ff23711a2d0366d440a6bf27e16da03 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 27 Apr 2016 00:59:53 +0000 Subject: [PATCH 11/97] Refactor `resolve_crate_relative_path` and `resolve_module_relative_path` to return a `NameBinding` instead of a `Def` --- src/librustc_resolve/lib.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d4ef3d365d19e..535c0cc7fe191 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1683,8 +1683,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match self.resolve_crate_relative_path(prefix.span, &prefix.segments, TypeNS) { - Ok(def) => - self.record_def(item.id, PathResolution::new(def, 0)), + Ok(binding) => { + let def = binding.def().unwrap(); + self.record_def(item.id, PathResolution::new(def, 0)); + } Err(true) => self.record_def(item.id, err_path_resolution()), Err(false) => { resolve_error(self, @@ -2547,8 +2549,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mk_res = |def| PathResolution::new(def, path_depth); if path.global { - let def = self.resolve_crate_relative_path(span, segments, namespace); - return def.map(mk_res); + let binding = self.resolve_crate_relative_path(span, segments, namespace); + return binding.map(|binding| mk_res(binding.def().unwrap())); } // Try to find a path to an item in a module. @@ -2584,9 +2586,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let unqualified_def = resolve_identifier_with_fallback(self, false); - let def = self.resolve_module_relative_path(span, segments, namespace); - match (def, unqualified_def) { - (Ok(d), Some(ref ud)) if d == ud.def => { + let qualified_binding = self.resolve_module_relative_path(span, segments, namespace); + match (qualified_binding, unqualified_def) { + (Ok(binding), Some(ref ud)) if binding.def().unwrap() == ud.def => { self.session .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, id, @@ -2596,7 +2598,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => {} } - def.map(mk_res) + qualified_binding.map(|binding| mk_res(binding.def().unwrap())) } // Resolve a single identifier @@ -2707,7 +2709,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { span: Span, segments: &[hir::PathSegment], namespace: Namespace) - -> Result { + -> Result<&'a NameBinding<'a>, + bool /* true if an error was reported */> { let module_path = segments.split_last() .unwrap() .1 @@ -2740,7 +2743,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let result = self.resolve_name_in_module(containing_module, name, namespace, false, true); result.success().map(|binding| { self.check_privacy(name, binding, span); - binding.def().unwrap() + binding }).ok_or(false) } @@ -2750,7 +2753,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { span: Span, segments: &[hir::PathSegment], namespace: Namespace) - -> Result { + -> Result<&'a NameBinding<'a>, + bool /* true if an error was reported */> { let module_path = segments.split_last() .unwrap() .1 @@ -2790,7 +2794,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let result = self.resolve_name_in_module(containing_module, name, namespace, false, true); result.success().map(|binding| { self.check_privacy(name, binding, span); - binding.def().unwrap() + binding }).ok_or(false) } From 33bb26998c3ef4982a4e838a626e6837f602263a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 27 Apr 2016 01:18:04 +0000 Subject: [PATCH 12/97] Refactor away a use of `ast_map.span_if_local()` --- src/librustc_resolve/lib.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 535c0cc7fe191..c63776ad9ba88 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1819,11 +1819,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { path_depth))); // If it's a typedef, give a note - if let Def::TyAlias(did) = path_res.base_def { + if let Def::TyAlias(..) = path_res.base_def { err.fileline_note(trait_path.span, "`type` aliases cannot be used for traits"); - if let Some(sp) = self.ast_map.span_if_local(did) { - err.span_note(sp, "type defined here"); + + let definition_site = { + let segments = &trait_path.segments; + if trait_path.global { + self.resolve_crate_relative_path(trait_path.span, segments, TypeNS) + } else { + self.resolve_module_relative_path(trait_path.span, segments, TypeNS) + }.map(|binding| binding.span).unwrap_or(codemap::DUMMY_SP) + }; + + if definition_site != codemap::DUMMY_SP { + err.span_note(definition_site, "type defined here"); } } err.emit(); From 6aa91457535a1bc5433eec5f2bc5630e13b04895 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 27 Apr 2016 02:29:59 +0000 Subject: [PATCH 13/97] Avoid using the hir map when visibility checking in `resolve` Refactor `ty::Visibility` methods to use a new trait `NodeIdTree` instead of the ast map. --- src/librustc/ty/mod.rs | 30 ++++++++++++++++--------- src/librustc_resolve/lib.rs | 21 +++++++++++++++-- src/librustc_resolve/resolve_imports.rs | 9 ++++---- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 238856197feed..0c23f5332982d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -283,6 +283,22 @@ pub enum Visibility { PrivateExternal, } +pub trait NodeIdTree { + fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool; +} + +impl<'a> NodeIdTree for ast_map::Map<'a> { + fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool { + let mut node_ancestor = node; + loop { + if node_ancestor == ancestor { return true } + let node_ancestor_parent = self.get_module_parent(node_ancestor); + if node_ancestor_parent == node_ancestor { return false } + node_ancestor = node_ancestor_parent; + } + } +} + impl Visibility { pub fn from_hir(visibility: &hir::Visibility, id: NodeId, tcx: &TyCtxt) -> Self { match *visibility { @@ -301,7 +317,7 @@ impl Visibility { } /// Returns true if an item with this visibility is accessible from the given block. - pub fn is_accessible_from(self, block: NodeId, map: &ast_map::Map) -> bool { + pub fn is_accessible_from(self, block: NodeId, tree: &T) -> bool { let restriction = match self { // Public items are visible everywhere. Visibility::Public => return true, @@ -311,24 +327,18 @@ impl Visibility { Visibility::Restricted(module) => module, }; - let mut block_ancestor = block; - loop { - if block_ancestor == restriction { return true } - let block_ancestor_parent = map.get_module_parent(block_ancestor); - if block_ancestor_parent == block_ancestor { return false } - block_ancestor = block_ancestor_parent; - } + tree.is_descendant_of(block, restriction) } /// Returns true if this visibility is at least as accessible as the given visibility - pub fn is_at_least(self, vis: Visibility, map: &ast_map::Map) -> bool { + pub fn is_at_least(self, vis: Visibility, tree: &T) -> bool { let vis_restriction = match vis { Visibility::Public => return self == Visibility::Public, Visibility::PrivateExternal => return true, Visibility::Restricted(module) => module, }; - self.is_accessible_from(vis_restriction, map) + self.is_accessible_from(vis_restriction, tree) } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c63776ad9ba88..fdb834a32fbc6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1121,6 +1121,21 @@ impl<'a> ResolverArenas<'a> { } } +impl<'a, 'tcx> ty::NodeIdTree for Resolver<'a, 'tcx> { + fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool { + let ancestor = self.ast_map.local_def_id(ancestor); + let mut module = *self.module_map.get(&node).unwrap(); + loop { + if module.def_id() == Some(ancestor) { return true; } + let module_parent = match self.get_nearest_normal_module_parent(module) { + Some(parent) => parent, + None => return false, + }; + module = module_parent; + } + } +} + impl<'a, 'tcx> Resolver<'a, 'tcx> { fn new(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>, @@ -1131,6 +1146,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let graph_root = ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, arenas); let graph_root = arenas.alloc_module(graph_root); + let mut module_map = NodeMap(); + module_map.insert(CRATE_NODE_ID, graph_root); Resolver { session: session, @@ -1161,7 +1178,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { freevars_seen: NodeMap(), export_map: NodeMap(), trait_map: NodeMap(), - module_map: NodeMap(), + module_map: module_map, used_imports: HashSet::new(), used_crates: HashSet::new(), @@ -3343,7 +3360,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn is_accessible(&self, vis: ty::Visibility) -> bool { let current_module = self.get_nearest_normal_module_parent_or_self(self.current_module); let node_id = self.ast_map.as_local_node_id(current_module.def_id().unwrap()).unwrap(); - vis.is_accessible_from(node_id, &self.ast_map) + vis.is_accessible_from(node_id, self) } fn check_privacy(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Span) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 4a87ffe820d4a..f0639a8517686 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -552,9 +552,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { _ => (), } - let ast_map = self.resolver.ast_map; match (&value_result, &type_result) { - (&Success(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis, ast_map) && + (&Success(binding), _) if !binding.pseudo_vis() + .is_at_least(directive.vis, self.resolver) && self.resolver.is_accessible(binding.vis) => { let msg = format!("`{}` is private, and cannot be reexported", source); let note_msg = format!("consider marking `{}` as `pub` in the imported module", @@ -564,7 +564,8 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { .emit(); } - (_, &Success(binding)) if !binding.pseudo_vis().is_at_least(directive.vis, ast_map) && + (_, &Success(binding)) if !binding.pseudo_vis() + .is_at_least(directive.vis, self.resolver) && self.resolver.is_accessible(binding.vis) => { if binding.is_extern_crate() { let msg = format!("extern crate `{}` is private, and cannot be reexported \ @@ -691,7 +692,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { if ns == TypeNS && orig_binding.is_variant() && - !orig_binding.vis.is_at_least(binding.vis, &self.resolver.ast_map) { + !orig_binding.vis.is_at_least(binding.vis, self.resolver) { let msg = format!("variant `{}` is private, and cannot be reexported \ (error E0364), consider declaring its enum as `pub`", name); From ac264196e2f4c1f3de8b081f72dc78838e423085 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 27 Apr 2016 19:30:16 +0000 Subject: [PATCH 14/97] Address style nits --- src/librustc/ty/mod.rs | 8 +++++--- src/librustc_resolve/lib.rs | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 0c23f5332982d..bc342b235dd42 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -290,12 +290,14 @@ pub trait NodeIdTree { impl<'a> NodeIdTree for ast_map::Map<'a> { fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool { let mut node_ancestor = node; - loop { - if node_ancestor == ancestor { return true } + while node_ancestor != ancestor { let node_ancestor_parent = self.get_module_parent(node_ancestor); - if node_ancestor_parent == node_ancestor { return false } + if node_ancestor_parent == node_ancestor { + return false; + } node_ancestor = node_ancestor_parent; } + true } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fdb834a32fbc6..1674a96c8badc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1125,14 +1125,14 @@ impl<'a, 'tcx> ty::NodeIdTree for Resolver<'a, 'tcx> { fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool { let ancestor = self.ast_map.local_def_id(ancestor); let mut module = *self.module_map.get(&node).unwrap(); - loop { - if module.def_id() == Some(ancestor) { return true; } + while module.def_id() != Some(ancestor) { let module_parent = match self.get_nearest_normal_module_parent(module) { Some(parent) => parent, None => return false, }; module = module_parent; } + true } } From 0cfb5a0bb6f48dcb68d3bf61c4b04db771deb4ce Mon Sep 17 00:00:00 2001 From: Timothy McRoy Date: Tue, 26 Apr 2016 14:38:24 -0500 Subject: [PATCH 15/97] Add detailed error message for E0434 #32777 --- src/librustc_resolve/diagnostics.rs | 46 ++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 8a196768ae516..0a8fce49ebbaf 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -948,6 +948,51 @@ use something_which_doesnt_exist; Please verify you didn't misspell the import's name. "##, +E0434: r##" +This error indicates that a variable usage inside an inner function is invalid +because the variable comes from a dynamic environment. Inner functions do not +have access to their containing environment. + +Example of erroneous code: + +```compile_fail +fn foo() { + let y = 5; + fn bar() -> u32 { + y // error: can't capture dynamic environment in a fn item; use the + // || { ... } closure form instead. + } +} +``` + +Functions do not capture local variables. To fix this error, you can replace the +function with a closure: + +``` +fn foo() { + let y = 5; + let bar = || { + y + }; +} +``` + +or replace the captured variable with a constant or a static item: + +``` +fn foo() { + static mut X: u32 = 4; + const Y: u32 = 5; + fn bar() -> u32 { + unsafe { + X = 3; + } + Y + } +} +``` +"##, + E0435: r##" A non-constant value was used to initialise a constant. Example of erroneous code: @@ -1044,5 +1089,4 @@ register_diagnostics! { E0421, // unresolved associated const E0427, // cannot use `ref` binding mode with ... E0429, // `self` imports are only allowed within a { } list - E0434, // can't capture dynamic environment in a fn item } From b1337d309a67e34c1452b4a9a378a23dbd8b3573 Mon Sep 17 00:00:00 2001 From: Brandon Edens Date: Sun, 27 Mar 2016 12:42:47 -0700 Subject: [PATCH 16/97] Add opt-level options for optimizing for size and minimum size. This attempts to mimic the behavior of clang's options Os and Oz. --- src/librustc/session/config.rs | 22 ++++++++------- src/librustc_llvm/lib.rs | 9 +++++++ src/librustc_trans/back/write.rs | 46 +++++++++++++++++++++++++------- src/librustc_trans/declare.rs | 11 ++++++++ 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 9f29f9050e6a6..6ade74790a519 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -48,7 +48,9 @@ pub enum OptLevel { No, // -O0 Less, // -O1 Default, // -O2 - Aggressive // -O3 + Aggressive, // -O3 + Size, // -Os + SizeMin, // -Oz } #[derive(Clone, Copy, PartialEq)] @@ -567,8 +569,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, debuginfo: Option = (None, parse_opt_uint, "debug info emission level, 0 = no debug info, 1 = line tables only, \ 2 = full debug info with variable and type information"), - opt_level: Option = (None, parse_opt_uint, - "optimize with possible levels 0-3"), + opt_level: Option = (None, parse_opt_string, + "optimize with possible levels 0-3, s, or z"), debug_assertions: Option = (None, parse_opt_bool, "explicitly enable the cfg(debug_assertions) directive"), inline_threshold: Option = (None, parse_opt_uint, @@ -1125,15 +1127,17 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } OptLevel::Default } else { - match cg.opt_level { + match cg.opt_level.as_ref().map(String::as_ref) { None => OptLevel::No, - Some(0) => OptLevel::No, - Some(1) => OptLevel::Less, - Some(2) => OptLevel::Default, - Some(3) => OptLevel::Aggressive, + Some("0") => OptLevel::No, + Some("1") => OptLevel::Less, + Some("2") => OptLevel::Default, + Some("3") => OptLevel::Aggressive, + Some("s") => OptLevel::Size, + Some("z") => OptLevel::SizeMin, Some(arg) => { early_error(error_format, &format!("optimization level needs to be \ - between 0-3 (instead was `{}`)", + between 0-3, s, or z (instead was `{}`)", arg)); } } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 526b6bf68be24..ea0d8eae75d75 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -44,6 +44,7 @@ pub use self::FileType::*; pub use self::MetadataType::*; pub use self::AsmDialect::*; pub use self::CodeGenOptLevel::*; +pub use self::CodeGenOptSize::*; pub use self::RelocMode::*; pub use self::CodeGenModel::*; pub use self::DiagnosticKind::*; @@ -375,6 +376,14 @@ pub enum CodeGenOptLevel { CodeGenLevelAggressive = 3, } +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum CodeGenOptSize { + CodeGenOptSizeNone = 0, + CodeGenOptSizeDefault = 1, + CodeGenOptSizeAggressive = 2, +} + #[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum RelocMode { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 8a915f044053a..777245c4e0cae 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -140,6 +140,15 @@ fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { config::OptLevel::Less => llvm::CodeGenLevelLess, config::OptLevel::Default => llvm::CodeGenLevelDefault, config::OptLevel::Aggressive => llvm::CodeGenLevelAggressive, + _ => llvm::CodeGenLevelDefault, + } +} + +fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize { + match optimize { + config::OptLevel::Size => llvm::CodeGenOptSizeDefault, + config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive, + _ => llvm::CodeGenOptSizeNone, } } @@ -237,6 +246,9 @@ pub struct ModuleConfig { /// absolutely no optimizations (used for the metadata module). opt_level: Option, + /// Some(level) to optimize binary size, or None to not affect program size. + opt_size: Option, + // Flags indicating which outputs to produce. emit_no_opt_bc: bool, emit_bc: bool, @@ -268,6 +280,7 @@ impl ModuleConfig { tm: tm, passes: passes, opt_level: None, + opt_size: None, emit_no_opt_bc: false, emit_bc: false, @@ -637,6 +650,7 @@ pub fn run_passes(sess: &Session, let mut metadata_config = ModuleConfig::new(tm, vec!()); modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize)); + modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize)); // Save all versions of the bytecode if we're saving our temporaries. if sess.opts.cg.save_temps { @@ -991,13 +1005,19 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); - let opt = config.opt_level.unwrap_or(llvm::CodeGenLevelNone); + let opt_level = config.opt_level.unwrap_or(llvm::CodeGenLevelNone); + let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone); let inline_threshold = config.inline_threshold; - llvm::LLVMRustConfigurePassManagerBuilder(builder, opt, + llvm::LLVMRustConfigurePassManagerBuilder(builder, opt_level, config.merge_functions, config.vectorize_slp, config.vectorize_loop); + llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32); + + if opt_size != llvm::CodeGenOptSizeNone { + llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1); + } llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins); @@ -1005,22 +1025,28 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, // always-inline functions (but don't add lifetime intrinsics), at O1 we // inline with lifetime intrinsics, and O2+ we add an inliner with a // thresholds copied from clang. - match (opt, inline_threshold) { - (_, Some(t)) => { + match (opt_level, opt_size, inline_threshold) { + (_, _, Some(t)) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32); } - (llvm::CodeGenLevelNone, _) => { + (llvm::CodeGenLevelAggressive, _, _) => { + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); + } + (_, llvm::CodeGenOptSizeDefault, _) => { + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75); + } + (_, llvm::CodeGenOptSizeAggressive, _) => { + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25); + } + (llvm::CodeGenLevelNone, _, _) => { llvm::LLVMRustAddAlwaysInlinePass(builder, false); } - (llvm::CodeGenLevelLess, _) => { + (llvm::CodeGenLevelLess, _, _) => { llvm::LLVMRustAddAlwaysInlinePass(builder, true); } - (llvm::CodeGenLevelDefault, _) => { + (llvm::CodeGenLevelDefault, _, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); } - (llvm::CodeGenLevelAggressive, _) => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); - } } f(builder); diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index eb520fe744a3d..9a4d20ca3010c 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -69,6 +69,17 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoRedZone) } + match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) { + Some("s") => { + llvm::SetFunctionAttribute(llfn, llvm::Attribute::OptimizeForSize); + }, + Some("z") => { + llvm::SetFunctionAttribute(llfn, llvm::Attribute::MinSize); + llvm::SetFunctionAttribute(llfn, llvm::Attribute::OptimizeForSize); + }, + _ => {}, + } + llfn } From 8a8493a56593c6082b302d00f55232953dc7db47 Mon Sep 17 00:00:00 2001 From: Brandon Edens Date: Sun, 27 Mar 2016 23:04:15 -0700 Subject: [PATCH 17/97] Add opt-level=s and opt-level=z tests to the existing tests that confirm proper compiler of other opt-levels. --- src/test/run-make/debug-assertions/Makefile | 4 ++++ src/test/run-make/emit/Makefile | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/test/run-make/debug-assertions/Makefile b/src/test/run-make/debug-assertions/Makefile index 7129756276864..76ada90f1e25a 100644 --- a/src/test/run-make/debug-assertions/Makefile +++ b/src/test/run-make/debug-assertions/Makefile @@ -11,6 +11,10 @@ all: $(call RUN,debug) good $(RUSTC) debug.rs -C opt-level=3 $(call RUN,debug) good + $(RUSTC) debug.rs -C opt-level=s + $(call RUN,debug) good + $(RUSTC) debug.rs -C opt-level=z + $(call RUN,debug) good $(RUSTC) debug.rs -O $(call RUN,debug) good $(RUSTC) debug.rs diff --git a/src/test/run-make/emit/Makefile b/src/test/run-make/emit/Makefile index be34028fe1d01..e0b57107e5b7b 100644 --- a/src/test/run-make/emit/Makefile +++ b/src/test/run-make/emit/Makefile @@ -5,6 +5,8 @@ all: $(RUSTC) -Copt-level=1 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs $(RUSTC) -Copt-level=2 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs $(RUSTC) -Copt-level=3 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs + $(RUSTC) -Copt-level=s --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs + $(RUSTC) -Copt-level=z --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs $(RUSTC) -Copt-level=0 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs $(call RUN,test-26235) || exit 1 $(RUSTC) -Copt-level=1 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs @@ -13,3 +15,7 @@ all: $(call RUN,test-26235) || exit 1 $(RUSTC) -Copt-level=3 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs $(call RUN,test-26235) || exit 1 + $(RUSTC) -Copt-level=s --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs + $(call RUN,test-26235) || exit 1 + $(RUSTC) -Copt-level=z --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs + $(call RUN,test-26235) || exit 1 From 49d28258a72d70cf7c752caa6b394761a02a5700 Mon Sep 17 00:00:00 2001 From: Brandon Edens Date: Thu, 28 Apr 2016 23:04:45 -0700 Subject: [PATCH 18/97] Place optimize for size and minsize rustc invocation options behind a nightly compiler check to prevent their inclusion in the stable / beta compilers. --- src/librustc/session/config.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 6ade74790a519..ab7537334509c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1127,17 +1127,18 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } OptLevel::Default } else { - match cg.opt_level.as_ref().map(String::as_ref) { - None => OptLevel::No, - Some("0") => OptLevel::No, - Some("1") => OptLevel::Less, - Some("2") => OptLevel::Default, - Some("3") => OptLevel::Aggressive, - Some("s") => OptLevel::Size, - Some("z") => OptLevel::SizeMin, - Some(arg) => { + match (cg.opt_level.as_ref().map(String::as_ref), + nightly_options::is_nightly_build()) { + (None, _) => OptLevel::No, + (Some("0"), _) => OptLevel::No, + (Some("1"), _) => OptLevel::Less, + (Some("2"), _) => OptLevel::Default, + (Some("3"), _) => OptLevel::Aggressive, + (Some("s"), true) => OptLevel::Size, + (Some("z"), true) => OptLevel::SizeMin, + (Some(arg), _) => { early_error(error_format, &format!("optimization level needs to be \ - between 0-3, s, or z (instead was `{}`)", + between 0-3 (instead was `{}`)", arg)); } } @@ -1308,7 +1309,7 @@ pub mod nightly_options { is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") } - fn is_nightly_build() -> bool { + pub fn is_nightly_build() -> bool { match get_unstable_features_setting() { UnstableFeatures::Allow | UnstableFeatures::Cheat => true, _ => false, From 3c1d08744db20cf0e414c597ab3b8d62fe4d7f66 Mon Sep 17 00:00:00 2001 From: Brayden Winterton Date: Fri, 29 Apr 2016 09:59:39 -0600 Subject: [PATCH 19/97] Make Btreeset::Insert docs more consistent --- src/libcollections/btree/set.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 5419d7a301a00..3ee42499a38f8 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -477,9 +477,9 @@ impl BTreeSet { /// Adds a value to the set. /// - /// If the set did not have a value present, `true` is returned. + /// If the set did not have this value present, `true` is returned. /// - /// If the set did have this key present, `false` is returned, and the + /// If the set did have this value present, `false` is returned, and the /// entry is not updated. See the [module-level documentation] for more. /// /// [module-level documentation]: index.html#insert-and-complex-keys From c738d75c00b0554f50aff442579e968c90945af4 Mon Sep 17 00:00:00 2001 From: Garrett Squire Date: Mon, 25 Apr 2016 16:59:54 -0700 Subject: [PATCH 20/97] add Cargo.lock check to ensure it is synced --- src/tools/tidy/src/cargo_lock.rs | 43 ++++++++++++++++++++++++++++++++ src/tools/tidy/src/main.rs | 2 ++ 2 files changed, 45 insertions(+) create mode 100644 src/tools/tidy/src/cargo_lock.rs diff --git a/src/tools/tidy/src/cargo_lock.rs b/src/tools/tidy/src/cargo_lock.rs new file mode 100644 index 0000000000000..4324db489b7f8 --- /dev/null +++ b/src/tools/tidy/src/cargo_lock.rs @@ -0,0 +1,43 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::path::Path; + +const CARGO_LOCK: &'static str = "Cargo.lock"; + +pub fn check(path: &Path, bad: &mut bool) { + use std::process::Command; + + super::walk(path, + &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), + &mut |file| { + let name = file.file_name().unwrap().to_string_lossy(); + if name == CARGO_LOCK { + let rel_path = file.strip_prefix(path).unwrap(); + let ret_code = Command::new("git") + .arg("diff-index") + .arg("--quiet") + .arg("HEAD") + .arg(rel_path) + .current_dir(path) + .status() + .unwrap_or_else(|e| { + panic!("could not run git diff-index: {}", e); + }); + if !ret_code.success() { + let parent_path = file.parent().unwrap().join("Cargo.toml"); + print!("dirty lock file found at {} ", rel_path.display()); + println!("please commit your changes or update the lock file by running:"); + println!("\n\tcargo update --manifest-path {}", parent_path.display()); + *bad = true; + } + } + }); +} diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index e9e2508aba9bd..2839bbded1a5f 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,6 +35,7 @@ mod style; mod errors; mod features; mod cargo; +mod cargo_lock; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -46,6 +47,7 @@ fn main() { errors::check(&path, &mut bad); cargo::check(&path, &mut bad); features::check(&path, &mut bad); + cargo_lock::check(&path, &mut bad); if bad { panic!("some tidy checks failed"); From 60c8f7dbf5788f1c9f3a27be2e7be28ecf7817ff Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 23 Apr 2016 21:20:17 +0000 Subject: [PATCH 21/97] Revert #27493 --- src/librustc_resolve/lib.rs | 83 +++++++------------------------------ 1 file changed, 16 insertions(+), 67 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1674a96c8badc..bca7a6a89e9e9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -97,17 +97,6 @@ mod check_unused; mod build_reduced_graph; mod resolve_imports; -// Perform the callback, not walking deeper if the return is true -macro_rules! execute_callback { - ($node: expr, $walker: expr) => ( - if let Some(ref callback) = $walker.callback { - if callback($node, &mut $walker.resolved) { - return; - } - } - ) -} - enum SuggestionType { Macro(String), Function(token::InternedString), @@ -559,22 +548,18 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { self.visit_item(self.ast_map.expect_item(item.id)) } fn visit_item(&mut self, item: &Item) { - execute_callback!(hir_map::Node::NodeItem(item), self); self.resolve_item(item); } fn visit_arm(&mut self, arm: &Arm) { self.resolve_arm(arm); } fn visit_block(&mut self, block: &Block) { - execute_callback!(hir_map::Node::NodeBlock(block), self); self.resolve_block(block); } fn visit_expr(&mut self, expr: &Expr) { - execute_callback!(hir_map::Node::NodeExpr(expr), self); self.resolve_expr(expr); } fn visit_local(&mut self, local: &Local) { - execute_callback!(hir_map::Node::NodeLocal(&local.pat), self); self.resolve_local(local); } fn visit_ty(&mut self, ty: &Ty) { @@ -597,7 +582,6 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { variant: &hir::Variant, generics: &Generics, item_id: ast::NodeId) { - execute_callback!(hir_map::Node::NodeVariant(variant), self); if let Some(ref dis_expr) = variant.node.disr_expr { // resolve the discriminator expr as a constant self.with_constant_rib(|this| { @@ -613,7 +597,6 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { variant.span); } fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem) { - execute_callback!(hir_map::Node::NodeForeignItem(foreign_item), self); let type_parameters = match foreign_item.node { ForeignItemFn(_, ref generics) => { HasTypeParameters(generics, FnSpace, ItemRibKind) @@ -1080,11 +1063,6 @@ pub struct Resolver<'a, 'tcx: 'a> { used_imports: HashSet<(NodeId, Namespace)>, used_crates: HashSet, - // Callback function for intercepting walks - callback: Option bool>>, - // The intention is that the callback modifies this flag. - // Once set, the resolver falls out of the walk, preserving the ribs. - resolved: bool, privacy_errors: Vec>, arenas: &'a ResolverArenas<'a>, @@ -1186,8 +1164,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { make_glob_map: make_glob_map == MakeGlobMap::Yes, glob_map: NodeMap(), - callback: None, - resolved: false, privacy_errors: Vec::new(), arenas: arenas, @@ -1758,13 +1734,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { f(self); - match type_parameters { - HasTypeParameters(..) => { - if !self.resolved { - self.type_ribs.pop(); - } - } - NoTypeParameters => {} + if let HasTypeParameters(..) = type_parameters { + self.type_ribs.pop(); } } @@ -1773,9 +1744,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { self.label_ribs.push(Rib::new(NormalRibKind)); f(self); - if !self.resolved { - self.label_ribs.pop(); - } + self.label_ribs.pop(); } fn with_constant_rib(&mut self, f: F) @@ -1784,10 +1753,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.value_ribs.push(Rib::new(ConstantItemRibKind)); self.type_ribs.push(Rib::new(ConstantItemRibKind)); f(self); - if !self.resolved { - self.type_ribs.pop(); - self.value_ribs.pop(); - } + self.type_ribs.pop(); + self.value_ribs.pop(); } fn resolve_function(&mut self, rib_kind: RibKind<'a>, declaration: &FnDecl, block: &Block) { @@ -1813,10 +1780,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("(resolving function) leaving function"); - if !self.resolved { - self.label_ribs.pop(); - self.value_ribs.pop(); - } + self.label_ribs.pop(); + self.value_ribs.pop(); } fn resolve_trait_reference(&mut self, @@ -1950,9 +1915,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self_type_rib.bindings.insert(keywords::SelfType.name(), self_def); self.type_ribs.push(self_type_rib); f(self); - if !self.resolved { - self.type_ribs.pop(); - } + self.type_ribs.pop(); } fn resolve_implementation(&mut self, @@ -2117,9 +2080,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { walk_list!(self, visit_expr, &arm.guard); self.visit_expr(&arm.body); - if !self.resolved { - self.value_ribs.pop(); - } + self.value_ribs.pop(); } fn resolve_block(&mut self, block: &Block) { @@ -2141,12 +2102,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { intravisit::walk_block(self, block); // Move back up. - if !self.resolved { - self.current_module = orig_module; - self.value_ribs.pop(); - if let Some(_) = anonymous_module { - self.type_ribs.pop(); - } + self.current_module = orig_module; + self.value_ribs.pop(); + if let Some(_) = anonymous_module { + self.type_ribs.pop(); } debug!("(resolving block) leaving block"); } @@ -3588,7 +3547,7 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session, let krate = ast_map.krate(); let arenas = Resolver::arenas(); - let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, &arenas, None); + let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, &arenas); resolver.resolve_crate(krate); @@ -3608,25 +3567,15 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session, } } -/// Builds a name resolution walker to be used within this module, -/// or used externally, with an optional callback function. -/// -/// The callback takes a &mut bool which allows callbacks to end a -/// walk when set to true, passing through the rest of the walk, while -/// preserving the ribs + current module. This allows resolve_path -/// calls to be made with the correct scope info. The node in the -/// callback corresponds to the current node in the walk. +/// Builds a name resolution walker. fn create_resolver<'a, 'tcx>(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>, krate: &'a Crate, make_glob_map: MakeGlobMap, - arenas: &'a ResolverArenas<'a>, - callback: Option bool>>) + arenas: &'a ResolverArenas<'a>) -> Resolver<'a, 'tcx> { let mut resolver = Resolver::new(session, ast_map, make_glob_map, arenas); - resolver.callback = callback; - resolver.build_reduced_graph(krate); resolve_imports::resolve_imports(&mut resolver); From 5a4e0b14e39989f327f9f8103cf38ec43cd22131 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 25 Apr 2016 00:12:12 +0000 Subject: [PATCH 22/97] Remove use of `ast_map.span_if_local()` and improve diagnostics --- src/librustc_resolve/lib.rs | 17 ++++++----------- .../compile-fail/const-pattern-irrefutable.rs | 4 ++-- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bca7a6a89e9e9..c0a22151a59b0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -141,7 +141,7 @@ enum ResolutionError<'a> { /// error E0413: declaration shadows an enum variant or unit-like struct in scope DeclarationShadowsEnumVariantOrUnitLikeStruct(Name), /// error E0414: only irrefutable patterns allowed here - OnlyIrrefutablePatternsAllowedHere(DefId, Name), + OnlyIrrefutablePatternsAllowedHere(Name), /// error E0415: identifier is bound more than once in this parameter list IdentifierBoundMoreThanOnceInParameterList(&'a str), /// error E0416: identifier is bound more than once in the same pattern @@ -323,7 +323,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, or unit-like struct in scope", name) } - ResolutionError::OnlyIrrefutablePatternsAllowedHere(did, name) => { + ResolutionError::OnlyIrrefutablePatternsAllowedHere(name) => { let mut err = struct_span_err!(resolver.session, span, E0414, @@ -331,14 +331,10 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, err.span_note(span, "there already is a constant in scope sharing the same \ name as this pattern"); - if let Some(sp) = resolver.ast_map.span_if_local(did) { - err.span_note(sp, "constant defined here"); - } if let Some(binding) = resolver.current_module .resolve_name_in_lexical_scope(name, ValueNS) { - if binding.is_import() { - err.span_note(binding.span, "constant imported here"); - } + let participle = if binding.is_import() { "imported" } else { "defined" }; + err.span_note(binding.span, &format!("constant {} here", participle)); } err } @@ -2248,12 +2244,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { depth: 0, }); } - FoundConst(def, name) => { + FoundConst(_, name) => { resolve_error( self, pattern.span, - ResolutionError::OnlyIrrefutablePatternsAllowedHere(def.def_id(), - name) + ResolutionError::OnlyIrrefutablePatternsAllowedHere(name) ); self.record_def(pattern.id, err_path_resolution()); } diff --git a/src/test/compile-fail/const-pattern-irrefutable.rs b/src/test/compile-fail/const-pattern-irrefutable.rs index bc395af9622c5..825c39011fcc1 100644 --- a/src/test/compile-fail/const-pattern-irrefutable.rs +++ b/src/test/compile-fail/const-pattern-irrefutable.rs @@ -9,8 +9,8 @@ // except according to those terms. mod foo { - pub const b: u8 = 2; //~ NOTE constant defined here - pub const d: u8 = 2; //~ NOTE constant defined here + pub const b: u8 = 2; + pub const d: u8 = 2; } use foo::b as c; //~ NOTE constant imported here From a70e42a953d71e356e170de8b6bd525d4a32dc4d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 24 Apr 2016 21:10:54 +0000 Subject: [PATCH 23/97] Remove use of `ast_map.expect_item()` and improve diagnostics (fixes #33186) --- src/librustc_resolve/lib.rs | 83 +++++++++---------- .../suggest-path-instead-of-mod-dot-item.rs | 12 ++- 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c0a22151a59b0..b83d6e9363e9c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -68,7 +68,7 @@ use rustc::hir::intravisit::{self, FnKind, Visitor}; use rustc::hir; use rustc::hir::{Arm, BindByRef, BindByValue, BindingMode, Block}; use rustc::hir::Crate; -use rustc::hir::{Expr, ExprAgain, ExprBreak, ExprCall, ExprField}; +use rustc::hir::{Expr, ExprAgain, ExprBreak, ExprField}; use rustc::hir::{ExprLoop, ExprWhile, ExprMethodCall}; use rustc::hir::{ExprPath, ExprStruct, FnDecl}; use rustc::hir::{ForeignItemFn, ForeignItemStatic, Generics}; @@ -163,7 +163,7 @@ enum ResolutionError<'a> { /// error E0424: `self` is not available in a static method SelfNotAvailableInStaticMethod, /// error E0425: unresolved name - UnresolvedName(&'a str, &'a str, UnresolvedNameContext), + UnresolvedName(&'a str, &'a str, UnresolvedNameContext<'a>), /// error E0426: use of undeclared label UndeclaredLabel(&'a str), /// error E0427: cannot use `ref` binding mode with ... @@ -186,12 +186,12 @@ enum ResolutionError<'a> { /// Context of where `ResolutionError::UnresolvedName` arose. #[derive(Clone, PartialEq, Eq, Debug)] -enum UnresolvedNameContext { - /// `PathIsMod(id)` indicates that a given path, used in +enum UnresolvedNameContext<'a> { + /// `PathIsMod(parent)` indicates that a given path, used in /// expression context, actually resolved to a module rather than - /// a value. The `id` attached to the variant is the node id of - /// the erroneous path expression. - PathIsMod(ast::NodeId), + /// a value. The optional expression attached to the variant is the + /// the parent of the erroneous path expression. + PathIsMod(Option<&'a Expr>), /// `Other` means we have no extra information about the context /// of the unresolved name error. (Maybe we could eliminate all @@ -419,39 +419,25 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, match context { UnresolvedNameContext::Other => { } // no help available - UnresolvedNameContext::PathIsMod(id) => { - let mut help_msg = String::new(); - let parent_id = resolver.ast_map.get_parent_node(id); - if let Some(hir_map::Node::NodeExpr(e)) = resolver.ast_map.find(parent_id) { - match e.node { - ExprField(_, ident) => { - help_msg = format!("To reference an item from the \ - `{module}` module, use \ - `{module}::{ident}`", - module = path, - ident = ident.node); - } - ExprMethodCall(ident, _, _) => { - help_msg = format!("To call a function from the \ - `{module}` module, use \ - `{module}::{ident}(..)`", - module = path, - ident = ident.node); - } - ExprCall(_, _) => { - help_msg = format!("No function corresponds to `{module}(..)`", - module = path); - } - _ => { } // no help available + UnresolvedNameContext::PathIsMod(parent) => { + err.fileline_help(span, &match parent.map(|parent| &parent.node) { + Some(&ExprField(_, ident)) => { + format!("To reference an item from the `{module}` module, \ + use `{module}::{ident}`", + module = path, + ident = ident.node) } - } else { - help_msg = format!("Module `{module}` cannot be the value of an expression", - module = path); - } - - if !help_msg.is_empty() { - err.fileline_help(span, &help_msg); - } + Some(&ExprMethodCall(ident, _, _)) => { + format!("To call a function from the `{module}` module, \ + use `{module}::{ident}(..)`", + module = path, + ident = ident.node) + } + _ => { + format!("Module `{module}` cannot be used as an expression", + module = path) + } + }); } } err @@ -553,7 +539,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { self.resolve_block(block); } fn visit_expr(&mut self, expr: &Expr) { - self.resolve_expr(expr); + self.resolve_expr(expr, None); } fn visit_local(&mut self, local: &Local) { self.resolve_local(local); @@ -2850,7 +2836,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } SuggestionType::NotFound } - fn resolve_expr(&mut self, expr: &Expr) { + fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) { // First, record candidate traits for this expression if it could // result in the invocation of a method call. @@ -2995,7 +2981,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { UseLexicalScope, expr.span) { Success(_) => { - context = UnresolvedNameContext::PathIsMod(expr.id); + context = UnresolvedNameContext::PathIsMod(parent); }, _ => {}, }; @@ -3069,6 +3055,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } + ExprField(ref subexpression, _) => { + self.resolve_expr(subexpression, Some(expr)); + } + ExprMethodCall(_, ref types, ref arguments) => { + let mut arguments = arguments.iter(); + self.resolve_expr(arguments.next().unwrap(), Some(expr)); + for argument in arguments { + self.resolve_expr(argument, None); + } + for ty in types.iter() { + self.visit_ty(ty); + } + } _ => { intravisit::walk_expr(self, expr); diff --git a/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs b/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs index 1d04679fd11e7..412c90fd214c1 100644 --- a/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs +++ b/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs @@ -47,10 +47,14 @@ fn h4() -> i32 { //~| HELP To reference an item from the `a::b` module, use `a::b::J` } -fn h5() -> i32 { - a.b.f() +fn h5() { + a.b.f(); //~^ ERROR E0425 //~| HELP To reference an item from the `a` module, use `a::b` + let v = Vec::new(); + v.push(a::b); + //~^ ERROR E0425 + //~| HELP Module `a::b` cannot be used as an expression } fn h6() -> i32 { @@ -62,11 +66,11 @@ fn h6() -> i32 { fn h7() { a::b //~^ ERROR E0425 - //~| HELP Module `a::b` cannot be the value of an expression + //~| HELP Module `a::b` cannot be used as an expression } fn h8() -> i32 { a::b() //~^ ERROR E0425 - //~| HELP No function corresponds to `a::b(..)` + //~| HELP Module `a::b` cannot be used as an expression } From 6bc93183183d070bf355bbd5714209fd00631e1e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 29 Apr 2016 19:32:18 +0000 Subject: [PATCH 24/97] configure: Add a sanity check for tarballs without submodules Because GitHub publishes broken tarballs on our behalf that we can't disable, this adds a check that src/liblibc exists, and then complains if not. --- configure | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/configure b/configure index 5273e4c03e722..e96ed327df3a5 100755 --- a/configure +++ b/configure @@ -1453,6 +1453,19 @@ then cd ${CFG_BUILD_DIR} fi +# Do a sanity check that the submodule source exists. Because GitHub +# automatically publishes broken tarballs that can't be disabled, and +# people download them and try to use them. +if [ ! -e "${CFG_SRC_DIR}/src/liblibc" ]; then + err "some submodules are missing. Is this a broken tarball? + +If you downloaded this tarball from the GitHub release pages at +https://github.com/rust-lang/rust/releases, +then please delete it and instead download the source from +https://www.rust-lang.org/downloads.html" + +fi + # Configure llvm, only if necessary step_msg "looking at LLVM" CFG_LLVM_SRC_DIR=${CFG_SRC_DIR}src/llvm/ From 5f956103c8a939e69b1da6f9b8f674802520b229 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 30 Apr 2016 03:30:33 +0300 Subject: [PATCH 25/97] Fix patterns of the constants that are const meth See the regression test for the sample code this fixes --- src/librustc_const_eval/eval.rs | 2 +- src/test/run-pass/const-meth-pattern.rs | 27 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/const-meth-pattern.rs diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c2ac3d838c8d0..132caa010d42f 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -281,7 +281,7 @@ pub fn const_expr_to_pat(tcx: &ty::TyCtxt, expr: &Expr, pat_id: ast::NodeId, spa let path = match def.full_def() { Def::Struct(def_id) => def_to_path(tcx, def_id), Def::Variant(_, variant_did) => def_to_path(tcx, variant_did), - Def::Fn(..) => return Ok(P(hir::Pat { + Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat { id: expr.id, node: PatKind::Lit(P(expr.clone())), span: span, diff --git a/src/test/run-pass/const-meth-pattern.rs b/src/test/run-pass/const-meth-pattern.rs new file mode 100644 index 0000000000000..3b27987f190cd --- /dev/null +++ b/src/test/run-pass/const-meth-pattern.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(const_fn)] + +struct A; + +impl A { + const fn banana() -> bool { + true + } +} + +const ABANANA: bool = A::banana(); + +fn main() { + match true { + ABANANA => {}, + _ => panic!("what?") + } +} From 04f8ba2ece3de0892e826db86f491f044e06d24c Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sat, 30 Apr 2016 03:40:34 +0300 Subject: [PATCH 26/97] Impl int/uint::MIN/MAX in terms of min/max_value --- src/libcore/num/int_macros.rs | 13 +++++++++++++ src/libcore/num/uint_macros.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index 42349257ab71c..fb1a3bbe3b4fb 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -10,6 +10,7 @@ #![doc(hidden)] +#[cfg(stage0)] macro_rules! int_module { ($T:ty, $bits:expr) => ( // FIXME(#11621): Should be deprecated once CTFE is implemented in favour of @@ -25,3 +26,15 @@ pub const MIN: $T = (-1 as $T) << ($bits - 1); pub const MAX: $T = !MIN; ) } + +#[cfg(not(stage0))] +macro_rules! int_module { ($T:ident, $bits:expr) => ( + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] +pub const MIN: $T = $T::min_value(); +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] +pub const MAX: $T = $T::max_value(); + +) } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 6479836cbe117..af6b1b89f96d5 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -10,6 +10,7 @@ #![doc(hidden)] +#[cfg(stage0)] macro_rules! uint_module { ($T:ty, $bits:expr) => ( #[stable(feature = "rust1", since = "1.0.0")] @@ -20,3 +21,15 @@ pub const MIN: $T = 0 as $T; pub const MAX: $T = !0 as $T; ) } + +#[cfg(not(stage0))] +macro_rules! uint_module { ($T:ident, $bits:expr) => ( + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] +pub const MIN: $T = $T::min_value(); +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] +pub const MAX: $T = $T::max_value(); + +) } From 16eaecbe43bc135b5b69cd114c25deb14a09c9e4 Mon Sep 17 00:00:00 2001 From: Brandon Edens Date: Fri, 29 Apr 2016 22:45:24 -0700 Subject: [PATCH 27/97] Emit warning to user when attempting to use optimize for size on non-nightly builds. --- src/librustc/session/config.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index ab7537334509c..b8dd750d3f1c2 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1136,6 +1136,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { (Some("3"), _) => OptLevel::Aggressive, (Some("s"), true) => OptLevel::Size, (Some("z"), true) => OptLevel::SizeMin, + (Some("s"), false) | (Some("z"), false) => { + early_error(error_format, &format!("the optimizations s or z are only \ + accepted on the nightly compiler")); + }, (Some(arg), _) => { early_error(error_format, &format!("optimization level needs to be \ between 0-3 (instead was `{}`)", From e6201cfb5cabc636a1dbfb1e543e5485639497a4 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 30 Apr 2016 11:16:30 +0200 Subject: [PATCH 28/97] Implement find() on Chain iterators This results in a roughly 2x speedup compared to the default impl "inherited" from Iterator. --- src/libcore/iter/mod.rs | 17 +++++++++++++++++ src/libcoretest/iter.rs | 13 +++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index abc199cd1828b..17f7c0a773e68 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -541,6 +541,23 @@ impl Iterator for Chain where } } + #[inline] + fn find

(&mut self, mut predicate: P) -> Option where + P: FnMut(&Self::Item) -> bool, + { + match self.state { + ChainState::Both => match self.a.find(&mut predicate) { + None => { + self.state = ChainState::Back; + self.b.find(predicate) + } + v => v + }, + ChainState::Front => self.a.find(predicate), + ChainState::Back => self.b.find(predicate), + } + } + #[inline] fn last(self) -> Option { match self.state { diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index 6c0cb03b5f775..56b10d0b79b41 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -133,6 +133,19 @@ fn test_iterator_chain_count() { assert_eq!(zs.iter().chain(&ys).count(), 4); } +#[test] +fn test_iterator_chain_find() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let mut iter = xs.iter().chain(&ys); + assert_eq!(iter.find(|&&i| i == 4), Some(&4)); + assert_eq!(iter.next(), Some(&5)); + assert_eq!(iter.find(|&&i| i == 40), Some(&40)); + assert_eq!(iter.next(), Some(&50)); + assert_eq!(iter.find(|&&i| i == 100), None); + assert_eq!(iter.next(), None); +} + #[test] fn test_filter_map() { let it = (0..).step_by(1).take(10) From 08207c9b52120ec8f59f67d747755bb9dd289a7b Mon Sep 17 00:00:00 2001 From: Demetri Obenour Date: Sat, 30 Apr 2016 17:21:18 -0400 Subject: [PATCH 29/97] Note that later versions of G++ are okay G++ 4.7 is the minimum requirement, but later versions are also okay. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1acf5fd1f3df8..4e476b4f357ec 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Read ["Installing Rust"] from [The Book]. 1. Make sure you have installed the dependencies: - * `g++` 4.7 or `clang++` 3.x + * `g++` 4.7 or later or `clang++` 3.x * `python` 2.7 (but not 3.x) * GNU `make` 3.81 or later * `curl` From 0649942a46d29a4782b4bfcce1c6fe006ad63dc6 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 30 Apr 2016 04:08:49 +0000 Subject: [PATCH 30/97] Panic on relowering an AST node with a cached node id --- src/librustc/hir/lowering.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6f30553e26638..ea92cfd9ee075 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -213,6 +213,8 @@ fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut(); if id_cache.contains_key(&expr_id) { + panic!("relowering!!!"); + /* let cached_id = lctx.cached_id.get(); if cached_id == 0 { // We're entering a node where we need to track ids, but are not @@ -224,6 +226,7 @@ fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R assert!(cached_id == id_cache[&expr_id], "id mismatch"); } lctx.gensym_key.set(id_cache[&expr_id]); + */ } else { // We've never lowered this node before, remember it for next time. let next_id = lctx.id_assigner.peek_node_id(); From 3906aef5c6df5a6d71d0a6b0c9c816b9160f9de1 Mon Sep 17 00:00:00 2001 From: James Miller Date: Sun, 1 May 2016 17:56:07 +1200 Subject: [PATCH 31/97] Handle coercion casts properly when building the MIR Coercion casts (`expr as T` where the type of `expr` can be coerced to `T`) are essentially no-ops, as the actual work is done by a coercion. Previously a check for type equality was used to avoid emitting the redundant cast in the MIR, but this failed for coercion casts of function items that had lifetime parameters. The MIR trans code doesn't handle `FnPtr -> FnPtr` casts and produced an error. Also fixes a bug with type ascription expressions not having any adjustments applied. Fixes #33295 --- src/librustc_mir/build/expr/as_rvalue.rs | 9 +- src/librustc_mir/hair/cx/expr.rs | 791 ++++++++++--------- src/test/run-pass/mir_ascription_coercion.rs | 20 + src/test/run-pass/mir_coercion_casts.rs | 22 + 4 files changed, 448 insertions(+), 394 deletions(-) create mode 100644 src/test/run-pass/mir_ascription_coercion.rs create mode 100644 src/test/run-pass/mir_coercion_casts.rs diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 8992381135ea8..88757c6873c5f 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -87,12 +87,9 @@ impl<'a,'tcx> Builder<'a,'tcx> { } ExprKind::Cast { source } => { let source = this.hir.mirror(source); - if source.ty == expr.ty { - this.expr_as_rvalue(block, source) - } else { - let source = unpack!(block = this.as_operand(block, source)); - block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) - } + + let source = unpack!(block = this.as_operand(block, source)); + block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) } ExprKind::ReifyFnPointer { source } => { let source = unpack!(block = this.as_operand(block, source)); diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 7dab8c4c5fb2a..6d527f77800f6 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -21,6 +21,7 @@ use rustc_const_eval as const_eval; use rustc::middle::region::CodeExtent; use rustc::hir::pat_util; use rustc::ty::{self, VariantDef, Ty}; +use rustc::ty::cast::CastKind as TyCastKind; use rustc::mir::repr::*; use rustc::hir; use syntax::ptr::P; @@ -29,398 +30,12 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { type Output = Expr<'tcx>; fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Expr<'tcx> { - debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); - - let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)! let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id); let expr_extent = cx.tcx.region_maps.node_extent(self.id); - let kind = match self.node { - // Here comes the interesting stuff: - hir::ExprMethodCall(_, _, ref args) => { - // Rewrite a.b(c) into UFCS form like Trait::b(a, c) - let expr = method_callee(cx, self, ty::MethodCall::expr(self.id)); - let args = args.iter() - .map(|e| e.to_ref()) - .collect(); - ExprKind::Call { - ty: expr.ty, - fun: expr.to_ref(), - args: args, - } - } - - hir::ExprCall(ref fun, ref args) => { - if cx.tcx.is_method_call(self.id) { - // The callee is something implementing Fn, FnMut, or FnOnce. - // Find the actual method implementation being called and - // build the appropriate UFCS call expression with the - // callee-object as self parameter. - - // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) - - let method = method_callee(cx, self, ty::MethodCall::expr(self.id)); - - let sig = match method.ty.sty { - ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig, - _ => span_bug!(self.span, "type of method is not an fn") - }; - - let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| { - span_bug!(self.span, "method call has late-bound regions") - }); - - assert_eq!(sig.inputs.len(), 2); - - let tupled_args = Expr { - ty: sig.inputs[1], - temp_lifetime: temp_lifetime, - span: self.span, - kind: ExprKind::Tuple { - fields: args.iter().map(ToRef::to_ref).collect() - } - }; - - ExprKind::Call { - ty: method.ty, - fun: method.to_ref(), - args: vec![fun.to_ref(), tupled_args.to_ref()] - } - } else { - let adt_data = if let hir::ExprPath(..) = fun.node { - // Tuple-like ADTs are represented as ExprCall. We convert them here. - expr_ty.ty_adt_def().and_then(|adt_def|{ - match cx.tcx.def_map.borrow()[&fun.id].full_def() { - Def::Variant(_, variant_id) => { - Some((adt_def, adt_def.variant_index_with_id(variant_id))) - }, - Def::Struct(..) => { - Some((adt_def, 0)) - }, - _ => None - } - }) - } else { None }; - if let Some((adt_def, index)) = adt_data { - let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(fun.id).substs); - let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef { - name: Field::new(idx), - expr: e.to_ref() - }).collect(); - ExprKind::Adt { - adt_def: adt_def, - substs: substs, - variant_index: index, - fields: field_refs, - base: None - } - } else { - ExprKind::Call { - ty: cx.tcx.node_id_to_type(fun.id), - fun: fun.to_ref(), - args: args.to_ref(), - } - } - } - } - - hir::ExprAddrOf(mutbl, ref expr) => { - let region = match expr_ty.sty { - ty::TyRef(r, _) => r, - _ => span_bug!(expr.span, "type of & not region"), - }; - ExprKind::Borrow { - region: *region, - borrow_kind: to_borrow_kind(mutbl), - arg: expr.to_ref(), - } - } - - hir::ExprBlock(ref blk) => { - ExprKind::Block { body: &blk } - } - - hir::ExprAssign(ref lhs, ref rhs) => { - ExprKind::Assign { - lhs: lhs.to_ref(), - rhs: rhs.to_ref(), - } - } - - hir::ExprAssignOp(op, ref lhs, ref rhs) => { - if cx.tcx.is_method_call(self.id) { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - overloaded_operator(cx, self, ty::MethodCall::expr(self.id), - pass_args, lhs.to_ref(), vec![rhs]) - } else { - ExprKind::AssignOp { - op: bin_op(op.node), - lhs: lhs.to_ref(), - rhs: rhs.to_ref(), - } - } - } - - hir::ExprLit(..) => ExprKind::Literal { - literal: cx.const_eval_literal(self) - }, - - hir::ExprBinary(op, ref lhs, ref rhs) => { - if cx.tcx.is_method_call(self.id) { - let pass_args = if op.node.is_by_value() { - PassArgs::ByValue - } else { - PassArgs::ByRef - }; - overloaded_operator(cx, self, ty::MethodCall::expr(self.id), - pass_args, lhs.to_ref(), vec![rhs]) - } else { - // FIXME overflow - match op.node { - hir::BinOp_::BiAnd => { - ExprKind::LogicalOp { - op: LogicalOp::And, - lhs: lhs.to_ref(), - rhs: rhs.to_ref(), - } - } - hir::BinOp_::BiOr => { - ExprKind::LogicalOp { - op: LogicalOp::Or, - lhs: lhs.to_ref(), - rhs: rhs.to_ref(), - } - } - _ => { - let op = bin_op(op.node); - ExprKind::Binary { - op: op, - lhs: lhs.to_ref(), - rhs: rhs.to_ref(), - } - } - } - } - } - - hir::ExprIndex(ref lhs, ref index) => { - if cx.tcx.is_method_call(self.id) { - overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id), - PassArgs::ByValue, lhs.to_ref(), vec![index]) - } else { - ExprKind::Index { - lhs: lhs.to_ref(), - index: index.to_ref(), - } - } - } - - hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { - if cx.tcx.is_method_call(self.id) { - overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id), - PassArgs::ByValue, arg.to_ref(), vec![]) - } else { - ExprKind::Deref { arg: arg.to_ref() } - } - } - - hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { - if cx.tcx.is_method_call(self.id) { - overloaded_operator(cx, self, ty::MethodCall::expr(self.id), - PassArgs::ByValue, arg.to_ref(), vec![]) - } else { - ExprKind::Unary { - op: UnOp::Not, - arg: arg.to_ref(), - } - } - } - - hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { - if cx.tcx.is_method_call(self.id) { - overloaded_operator(cx, self, ty::MethodCall::expr(self.id), - PassArgs::ByValue, arg.to_ref(), vec![]) - } else { - // FIXME runtime-overflow - if let hir::ExprLit(_) = arg.node { - ExprKind::Literal { - literal: cx.const_eval_literal(self), - } - } else { - ExprKind::Unary { - op: UnOp::Neg, - arg: arg.to_ref(), - } - } - } - } - - hir::ExprStruct(_, ref fields, ref base) => { - match expr_ty.sty { - ty::TyStruct(adt, substs) => { - let field_refs = field_refs(&adt.variants[0], fields); - ExprKind::Adt { - adt_def: adt, - variant_index: 0, - substs: substs, - fields: field_refs, - base: base.as_ref().map(|base| { - FruInfo { - base: base.to_ref(), - field_types: cx.tcx.tables - .borrow() - .fru_field_types[&self.id] - .clone() - } - }) - } - } - ty::TyEnum(adt, substs) => { - match cx.tcx.def_map.borrow()[&self.id].full_def() { - Def::Variant(enum_id, variant_id) => { - debug_assert!(adt.did == enum_id); - assert!(base.is_none()); - - let index = adt.variant_index_with_id(variant_id); - let field_refs = field_refs(&adt.variants[index], fields); - ExprKind::Adt { - adt_def: adt, - variant_index: index, - substs: substs, - fields: field_refs, - base: None - } - } - ref def => { - span_bug!( - self.span, - "unexpected def: {:?}", - def); - } - } - } - _ => { - span_bug!( - self.span, - "unexpected type for struct literal: {:?}", - expr_ty); - } - } - } - - hir::ExprClosure(..) => { - let closure_ty = cx.tcx.expr_ty(self); - let (def_id, substs) = match closure_ty.sty { - ty::TyClosure(def_id, ref substs) => (def_id, substs), - _ => { - span_bug!(self.span, - "closure expr w/o closure type: {:?}", - closure_ty); - } - }; - let upvars = cx.tcx.with_freevars(self.id, |freevars| { - freevars.iter() - .enumerate() - .map(|(i, fv)| capture_freevar(cx, self, fv, substs.upvar_tys[i])) - .collect() - }); - ExprKind::Closure { - closure_id: def_id, - substs: &substs, - upvars: upvars, - } - } - - hir::ExprPath(..) => { - convert_path_expr(cx, self) - } - - hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => { - ExprKind::InlineAsm { - asm: asm, - outputs: outputs.to_ref(), - inputs: inputs.to_ref() - } - } - - // Now comes the rote stuff: - - hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat { - value: v.to_ref(), - count: TypedConstVal { - ty: cx.tcx.expr_ty(c), - span: c.span, - value: match const_eval::eval_const_expr(cx.tcx, c) { - ConstVal::Integral(ConstInt::Usize(u)) => u, - other => bug!("constant evaluation of repeat count yielded {:?}", other), - }, - } - }, - hir::ExprRet(ref v) => - ExprKind::Return { value: v.to_ref() }, - hir::ExprBreak(label) => - ExprKind::Break { label: label.map(|_| loop_label(cx, self)) }, - hir::ExprAgain(label) => - ExprKind::Continue { label: label.map(|_| loop_label(cx, self)) }, - hir::ExprMatch(ref discr, ref arms, _) => - ExprKind::Match { discriminant: discr.to_ref(), - arms: arms.iter().map(|a| convert_arm(cx, a)).collect() }, - hir::ExprIf(ref cond, ref then, ref otherwise) => - ExprKind::If { condition: cond.to_ref(), - then: block::to_expr_ref(cx, then), - otherwise: otherwise.to_ref() }, - hir::ExprWhile(ref cond, ref body, _) => - ExprKind::Loop { condition: Some(cond.to_ref()), - body: block::to_expr_ref(cx, body) }, - hir::ExprLoop(ref body, _) => - ExprKind::Loop { condition: None, - body: block::to_expr_ref(cx, body) }, - hir::ExprField(ref source, name) => { - let index = match cx.tcx.expr_ty_adjusted(source).sty { - ty::TyStruct(adt_def, _) => - adt_def.variants[0].index_of_field_named(name.node), - ref ty => - span_bug!( - self.span, - "field of non-struct: {:?}", - ty), - }; - let index = index.unwrap_or_else(|| { - span_bug!( - self.span, - "no index found for field `{}`", - name.node) - }); - ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) } - } - hir::ExprTupField(ref source, index) => - ExprKind::Field { lhs: source.to_ref(), - name: Field::new(index.node as usize) }, - hir::ExprCast(ref source, _) => - ExprKind::Cast { source: source.to_ref() }, - hir::ExprType(ref source, _) => - return source.make_mirror(cx), - hir::ExprBox(ref value) => - ExprKind::Box { - value: value.to_ref(), - value_extents: cx.tcx.region_maps.node_extent(value.id) - }, - hir::ExprVec(ref fields) => - ExprKind::Vec { fields: fields.to_ref() }, - hir::ExprTup(ref fields) => - ExprKind::Tuple { fields: fields.to_ref() }, - }; + debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); - let mut expr = Expr { - temp_lifetime: temp_lifetime, - ty: expr_ty, - span: self.span, - kind: kind, - }; + let mut expr = make_mirror_unadjusted(cx, self); debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}", expr, cx.tcx.tables.borrow().adjustments.get(&self.id)); @@ -587,6 +202,406 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } } +fn make_mirror_unadjusted<'a, 'tcx>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> Expr<'tcx> { + let expr_ty = cx.tcx.expr_ty(expr); + let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); + + let kind = match expr.node { + // Here comes the interesting stuff: + hir::ExprMethodCall(_, _, ref args) => { + // Rewrite a.b(c) into UFCS form like Trait::b(a, c) + let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id)); + let args = args.iter() + .map(|e| e.to_ref()) + .collect(); + ExprKind::Call { + ty: expr.ty, + fun: expr.to_ref(), + args: args, + } + } + + hir::ExprCall(ref fun, ref args) => { + if cx.tcx.is_method_call(expr.id) { + // The callee is something implementing Fn, FnMut, or FnOnce. + // Find the actual method implementation being called and + // build the appropriate UFCS call expression with the + // callee-object as expr parameter. + + // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) + + let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id)); + + let sig = match method.ty.sty { + ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig, + _ => span_bug!(expr.span, "type of method is not an fn") + }; + + let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| { + span_bug!(expr.span, "method call has late-bound regions") + }); + + assert_eq!(sig.inputs.len(), 2); + + let tupled_args = Expr { + ty: sig.inputs[1], + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::Tuple { + fields: args.iter().map(ToRef::to_ref).collect() + } + }; + + ExprKind::Call { + ty: method.ty, + fun: method.to_ref(), + args: vec![fun.to_ref(), tupled_args.to_ref()] + } + } else { + let adt_data = if let hir::ExprPath(..) = fun.node { + // Tuple-like ADTs are represented as ExprCall. We convert them here. + expr_ty.ty_adt_def().and_then(|adt_def|{ + match cx.tcx.def_map.borrow()[&fun.id].full_def() { + Def::Variant(_, variant_id) => { + Some((adt_def, adt_def.variant_index_with_id(variant_id))) + }, + Def::Struct(..) => { + Some((adt_def, 0)) + }, + _ => None + } + }) + } else { None }; + if let Some((adt_def, index)) = adt_data { + let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(fun.id).substs); + let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef { + name: Field::new(idx), + expr: e.to_ref() + }).collect(); + ExprKind::Adt { + adt_def: adt_def, + substs: substs, + variant_index: index, + fields: field_refs, + base: None + } + } else { + ExprKind::Call { + ty: cx.tcx.node_id_to_type(fun.id), + fun: fun.to_ref(), + args: args.to_ref(), + } + } + } + } + + hir::ExprAddrOf(mutbl, ref expr) => { + let region = match expr_ty.sty { + ty::TyRef(r, _) => r, + _ => span_bug!(expr.span, "type of & not region"), + }; + ExprKind::Borrow { + region: *region, + borrow_kind: to_borrow_kind(mutbl), + arg: expr.to_ref(), + } + } + + hir::ExprBlock(ref blk) => { + ExprKind::Block { body: &blk } + } + + hir::ExprAssign(ref lhs, ref rhs) => { + ExprKind::Assign { + lhs: lhs.to_ref(), + rhs: rhs.to_ref(), + } + } + + hir::ExprAssignOp(op, ref lhs, ref rhs) => { + if cx.tcx.is_method_call(expr.id) { + let pass_args = if op.node.is_by_value() { + PassArgs::ByValue + } else { + PassArgs::ByRef + }; + overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), + pass_args, lhs.to_ref(), vec![rhs]) + } else { + ExprKind::AssignOp { + op: bin_op(op.node), + lhs: lhs.to_ref(), + rhs: rhs.to_ref(), + } + } + } + + hir::ExprLit(..) => ExprKind::Literal { + literal: cx.const_eval_literal(expr) + }, + + hir::ExprBinary(op, ref lhs, ref rhs) => { + if cx.tcx.is_method_call(expr.id) { + let pass_args = if op.node.is_by_value() { + PassArgs::ByValue + } else { + PassArgs::ByRef + }; + overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), + pass_args, lhs.to_ref(), vec![rhs]) + } else { + // FIXME overflow + match op.node { + hir::BinOp_::BiAnd => { + ExprKind::LogicalOp { + op: LogicalOp::And, + lhs: lhs.to_ref(), + rhs: rhs.to_ref(), + } + } + hir::BinOp_::BiOr => { + ExprKind::LogicalOp { + op: LogicalOp::Or, + lhs: lhs.to_ref(), + rhs: rhs.to_ref(), + } + } + _ => { + let op = bin_op(op.node); + ExprKind::Binary { + op: op, + lhs: lhs.to_ref(), + rhs: rhs.to_ref(), + } + } + } + } + } + + hir::ExprIndex(ref lhs, ref index) => { + if cx.tcx.is_method_call(expr.id) { + overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id), + PassArgs::ByValue, lhs.to_ref(), vec![index]) + } else { + ExprKind::Index { + lhs: lhs.to_ref(), + index: index.to_ref(), + } + } + } + + hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { + if cx.tcx.is_method_call(expr.id) { + overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id), + PassArgs::ByValue, arg.to_ref(), vec![]) + } else { + ExprKind::Deref { arg: arg.to_ref() } + } + } + + hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { + if cx.tcx.is_method_call(expr.id) { + overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), + PassArgs::ByValue, arg.to_ref(), vec![]) + } else { + ExprKind::Unary { + op: UnOp::Not, + arg: arg.to_ref(), + } + } + } + + hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { + if cx.tcx.is_method_call(expr.id) { + overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), + PassArgs::ByValue, arg.to_ref(), vec![]) + } else { + // FIXME runtime-overflow + if let hir::ExprLit(_) = arg.node { + ExprKind::Literal { + literal: cx.const_eval_literal(expr), + } + } else { + ExprKind::Unary { + op: UnOp::Neg, + arg: arg.to_ref(), + } + } + } + } + + hir::ExprStruct(_, ref fields, ref base) => { + match expr_ty.sty { + ty::TyStruct(adt, substs) => { + let field_refs = field_refs(&adt.variants[0], fields); + ExprKind::Adt { + adt_def: adt, + variant_index: 0, + substs: substs, + fields: field_refs, + base: base.as_ref().map(|base| { + FruInfo { + base: base.to_ref(), + field_types: cx.tcx.tables + .borrow() + .fru_field_types[&expr.id] + .clone() + } + }) + } + } + ty::TyEnum(adt, substs) => { + match cx.tcx.def_map.borrow()[&expr.id].full_def() { + Def::Variant(enum_id, variant_id) => { + debug_assert!(adt.did == enum_id); + assert!(base.is_none()); + + let index = adt.variant_index_with_id(variant_id); + let field_refs = field_refs(&adt.variants[index], fields); + ExprKind::Adt { + adt_def: adt, + variant_index: index, + substs: substs, + fields: field_refs, + base: None + } + } + ref def => { + span_bug!( + expr.span, + "unexpected def: {:?}", + def); + } + } + } + _ => { + span_bug!( + expr.span, + "unexpected type for struct literal: {:?}", + expr_ty); + } + } + } + + hir::ExprClosure(..) => { + let closure_ty = cx.tcx.expr_ty(expr); + let (def_id, substs) = match closure_ty.sty { + ty::TyClosure(def_id, ref substs) => (def_id, substs), + _ => { + span_bug!(expr.span, + "closure expr w/o closure type: {:?}", + closure_ty); + } + }; + let upvars = cx.tcx.with_freevars(expr.id, |freevars| { + freevars.iter() + .enumerate() + .map(|(i, fv)| capture_freevar(cx, expr, fv, substs.upvar_tys[i])) + .collect() + }); + ExprKind::Closure { + closure_id: def_id, + substs: &substs, + upvars: upvars, + } + } + + hir::ExprPath(..) => { + convert_path_expr(cx, expr) + } + + hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => { + ExprKind::InlineAsm { + asm: asm, + outputs: outputs.to_ref(), + inputs: inputs.to_ref() + } + } + + // Now comes the rote stuff: + + hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat { + value: v.to_ref(), + count: TypedConstVal { + ty: cx.tcx.expr_ty(c), + span: c.span, + value: match const_eval::eval_const_expr(cx.tcx, c) { + ConstVal::Integral(ConstInt::Usize(u)) => u, + other => bug!("constant evaluation of repeat count yielded {:?}", other), + }, + } + }, + hir::ExprRet(ref v) => + ExprKind::Return { value: v.to_ref() }, + hir::ExprBreak(label) => + ExprKind::Break { label: label.map(|_| loop_label(cx, expr)) }, + hir::ExprAgain(label) => + ExprKind::Continue { label: label.map(|_| loop_label(cx, expr)) }, + hir::ExprMatch(ref discr, ref arms, _) => + ExprKind::Match { discriminant: discr.to_ref(), + arms: arms.iter().map(|a| convert_arm(cx, a)).collect() }, + hir::ExprIf(ref cond, ref then, ref otherwise) => + ExprKind::If { condition: cond.to_ref(), + then: block::to_expr_ref(cx, then), + otherwise: otherwise.to_ref() }, + hir::ExprWhile(ref cond, ref body, _) => + ExprKind::Loop { condition: Some(cond.to_ref()), + body: block::to_expr_ref(cx, body) }, + hir::ExprLoop(ref body, _) => + ExprKind::Loop { condition: None, + body: block::to_expr_ref(cx, body) }, + hir::ExprField(ref source, name) => { + let index = match cx.tcx.expr_ty_adjusted(source).sty { + ty::TyStruct(adt_def, _) => + adt_def.variants[0].index_of_field_named(name.node), + ref ty => + span_bug!( + expr.span, + "field of non-struct: {:?}", + ty), + }; + let index = index.unwrap_or_else(|| { + span_bug!( + expr.span, + "no index found for field `{}`", + name.node) + }); + ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) } + } + hir::ExprTupField(ref source, index) => + ExprKind::Field { lhs: source.to_ref(), + name: Field::new(index.node as usize) }, + hir::ExprCast(ref source, _) => { + // Check to see if this cast is a "coercion cast", where the cast is actually done + // using a coercion (or is a no-op). + if let Some(&TyCastKind::CoercionCast) = cx.tcx.cast_kinds.borrow().get(&source.id) { + // Skip the actual cast itexpr, as it's now a no-op. + return source.make_mirror(cx); + } else { + ExprKind::Cast { source: source.to_ref() } + } + } + hir::ExprType(ref source, _) => + return source.make_mirror(cx), + hir::ExprBox(ref value) => + ExprKind::Box { + value: value.to_ref(), + value_extents: cx.tcx.region_maps.node_extent(value.id) + }, + hir::ExprVec(ref fields) => + ExprKind::Vec { fields: fields.to_ref() }, + hir::ExprTup(ref fields) => + ExprKind::Tuple { fields: fields.to_ref() }, + }; + + Expr { + temp_lifetime: temp_lifetime, + ty: expr_ty, + span: expr.span, + kind: kind, + } +} + fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &hir::Expr, method_call: ty::MethodCall) diff --git a/src/test/run-pass/mir_ascription_coercion.rs b/src/test/run-pass/mir_ascription_coercion.rs new file mode 100644 index 0000000000000..b227be9c543b2 --- /dev/null +++ b/src/test/run-pass/mir_ascription_coercion.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that the result of type ascription has adjustments applied + +#![feature(rustc_attrs, type_ascription)] + +#[rustc_mir] +fn main() { + let x = [1, 2, 3]; + // The RHS should coerce to &[i32] + let _y : &[i32] = &x : &[i32; 3]; +} diff --git a/src/test/run-pass/mir_coercion_casts.rs b/src/test/run-pass/mir_coercion_casts.rs new file mode 100644 index 0000000000000..4d5c59276d750 --- /dev/null +++ b/src/test/run-pass/mir_coercion_casts.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests the coercion casts are handled properly + +#![feature(rustc_attrs)] + +#[rustc_mir] +fn main() { + // This should produce only a reification of f, + // not a fn -> fn cast as well + let _ = f as fn(&()); +} + +fn f<'a>(_: &'a ()) { } From 3eef0831cbb930157d117d5ca5478962ea883373 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 1 May 2016 12:01:12 +0200 Subject: [PATCH 32/97] libsyntax/pp: minor modernizations * implement Display on Token instead of custom tok_str() fn * use expression returns * remove redundant parens in asserts * remove "/* bad */" comments that appear to be related to early changes in memory management * and a few individual idiomatic changes --- src/libsyntax/print/pp.rs | 72 +++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index c381a3a8437de..a1fa126818f6a 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -61,8 +61,8 @@ //! line (which it can't) and so naturally place the content on its own line to //! avoid combining it with other lines and making matters even worse. +use std::fmt; use std::io; -use std::string; #[derive(Clone, Copy, PartialEq)] pub enum Breaks { @@ -112,35 +112,30 @@ impl Token { } } -pub fn tok_str(token: &Token) -> String { - match *token { - Token::String(ref s, len) => format!("STR({},{})", s, len), - Token::Break(_) => "BREAK".to_string(), - Token::Begin(_) => "BEGIN".to_string(), - Token::End => "END".to_string(), - Token::Eof => "EOF".to_string() +impl fmt::Display for Token { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Token::String(ref s, len) => write!(f, "STR({},{})", s, len), + Token::Break(_) => f.write_str("BREAK"), + Token::Begin(_) => f.write_str("BEGIN"), + Token::End => f.write_str("END"), + Token::Eof => f.write_str("EOF"), + } } } -pub fn buf_str(toks: &[Token], - szs: &[isize], - left: usize, - right: usize, - lim: usize) - -> String { +fn buf_str(toks: &[Token], szs: &[isize], left: usize, right: usize, lim: usize) -> String { let n = toks.len(); assert_eq!(n, szs.len()); let mut i = left; let mut l = lim; - let mut s = string::String::from("["); + let mut s = String::from("["); while i != right && l != 0 { l -= 1; if i != left { s.push_str(", "); } - s.push_str(&format!("{}={}", - szs[i], - tok_str(&toks[i]))); + s.push_str(&format!("{}={}", szs[i], &toks[i])); i += 1; i %= n; } @@ -413,38 +408,38 @@ impl<'a> Printer<'a> { } else { self.top += 1; self.top %= self.buf_len; - assert!((self.top != self.bottom)); + assert!(self.top != self.bottom); } self.scan_stack[self.top] = x; } pub fn scan_pop(&mut self) -> usize { - assert!((!self.scan_stack_empty)); + assert!(!self.scan_stack_empty); let x = self.scan_stack[self.top]; if self.top == self.bottom { self.scan_stack_empty = true; } else { self.top += self.buf_len - 1; self.top %= self.buf_len; } - return x; + x } pub fn scan_top(&mut self) -> usize { - assert!((!self.scan_stack_empty)); - return self.scan_stack[self.top]; + assert!(!self.scan_stack_empty); + self.scan_stack[self.top] } pub fn scan_pop_bottom(&mut self) -> usize { - assert!((!self.scan_stack_empty)); + assert!(!self.scan_stack_empty); let x = self.scan_stack[self.bottom]; if self.top == self.bottom { self.scan_stack_empty = true; } else { self.bottom += 1; self.bottom %= self.buf_len; } - return x; + x } pub fn advance_right(&mut self) { self.right += 1; self.right %= self.buf_len; - assert!((self.right != self.left)); + assert!(self.right != self.left); } pub fn advance_left(&mut self) -> io::Result<()> { debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right, @@ -512,19 +507,16 @@ impl<'a> Printer<'a> { let ret = write!(self.out, "\n"); self.pending_indentation = 0; self.indent(amount); - return ret; + ret } pub fn indent(&mut self, amount: isize) { debug!("INDENT {}", amount); self.pending_indentation += amount; } pub fn get_top(&mut self) -> PrintStackElem { - let print_stack = &mut self.print_stack; - let n = print_stack.len(); - if n != 0 { - (*print_stack)[n - 1] - } else { - PrintStackElem { + match self.print_stack.last() { + Some(el) => *el, + None => PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) } @@ -538,7 +530,7 @@ impl<'a> Printer<'a> { write!(self.out, "{}", s) } pub fn print(&mut self, token: Token, l: isize) -> io::Result<()> { - debug!("print {} {} (remaining line space={})", tok_str(&token), l, + debug!("print {} {} (remaining line space={})", token, l, self.space); debug!("{}", buf_str(&self.token, &self.size, @@ -566,7 +558,7 @@ impl<'a> Printer<'a> { Token::End => { debug!("print End -> pop End"); let print_stack = &mut self.print_stack; - assert!((!print_stack.is_empty())); + assert!(!print_stack.is_empty()); print_stack.pop().unwrap(); Ok(()) } @@ -603,12 +595,12 @@ impl<'a> Printer<'a> { } } } - Token::String(s, len) => { + Token::String(ref s, len) => { debug!("print String({})", s); assert_eq!(l, len); // assert!(l <= space); self.space -= len; - self.print_str(&s[..]) + self.print_str(s) } Token::Eof => { // Eof should never get here. @@ -652,15 +644,15 @@ pub fn eof(p: &mut Printer) -> io::Result<()> { } pub fn word(p: &mut Printer, wrd: &str) -> io::Result<()> { - p.pretty_print(Token::String(/* bad */ wrd.to_string(), wrd.len() as isize)) + p.pretty_print(Token::String(wrd.to_string(), wrd.len() as isize)) } pub fn huge_word(p: &mut Printer, wrd: &str) -> io::Result<()> { - p.pretty_print(Token::String(/* bad */ wrd.to_string(), SIZE_INFINITY)) + p.pretty_print(Token::String(wrd.to_string(), SIZE_INFINITY)) } pub fn zero_word(p: &mut Printer, wrd: &str) -> io::Result<()> { - p.pretty_print(Token::String(/* bad */ wrd.to_string(), 0)) + p.pretty_print(Token::String(wrd.to_string(), 0)) } pub fn spaces(p: &mut Printer, n: usize) -> io::Result<()> { From 41861691ebbb736a0f0dfdab142d2302dd7b87ae Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 1 May 2016 12:22:05 +0200 Subject: [PATCH 33/97] libsyntax/pp: replace manual ring buffer with a VecDeque --- src/libsyntax/print/pp.rs | 71 +++++++++++---------------------------- 1 file changed, 19 insertions(+), 52 deletions(-) diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index a1fa126818f6a..4a92ad8ddb26d 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -61,6 +61,7 @@ //! line (which it can't) and so naturally place the content on its own line to //! avoid combining it with other lines and making matters even worse. +use std::collections::VecDeque; use std::fmt; use std::io; @@ -164,7 +165,7 @@ pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { debug!("mk_printer {}", linewidth); let token = vec![Token::Eof; n]; let size = vec![0; n]; - let scan_stack = vec![0; n]; + let scan_stack = VecDeque::with_capacity(n); Printer { out: out, buf_len: n, @@ -177,9 +178,6 @@ pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { left_total: 0, right_total: 0, scan_stack: scan_stack, - scan_stack_empty: true, - top: 0, - bottom: 0, print_stack: Vec::new(), pending_indentation: 0 } @@ -241,9 +239,8 @@ pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { /// approximation for purposes of line breaking). /// /// The "input side" of the printer is managed as an abstract process called -/// SCAN, which uses 'scan_stack', 'scan_stack_empty', 'top' and 'bottom', to -/// manage calculating 'size'. SCAN is, in other words, the process of -/// calculating 'size' entries. +/// SCAN, which uses 'scan_stack', to manage calculating 'size'. SCAN is, in +/// other words, the process of calculating 'size' entries. /// /// The "output side" of the printer is managed by an abstract process called /// PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to @@ -286,13 +283,7 @@ pub struct Printer<'a> { /// Begin (if there is any) on top of it. Stuff is flushed off the /// bottom as it becomes irrelevant due to the primary ring-buffer /// advancing. - scan_stack: Vec , - /// Top==bottom disambiguator - scan_stack_empty: bool, - /// Index of top of scan_stack - top: usize, - /// Index of bottom of scan_stack - bottom: usize, + scan_stack: VecDeque , /// Stack of blocks-in-progress being flushed by print print_stack: Vec , /// Buffered indentation to avoid writing trailing whitespace @@ -311,7 +302,7 @@ impl<'a> Printer<'a> { debug!("pp Vec<{},{}>", self.left, self.right); match token { Token::Eof => { - if !self.scan_stack_empty { + if !self.scan_stack.is_empty() { self.check_stack(0); self.advance_left()?; } @@ -319,7 +310,7 @@ impl<'a> Printer<'a> { Ok(()) } Token::Begin(b) => { - if self.scan_stack_empty { + if self.scan_stack.is_empty() { self.left_total = 1; self.right_total = 1; self.left = 0; @@ -334,7 +325,7 @@ impl<'a> Printer<'a> { Ok(()) } Token::End => { - if self.scan_stack_empty { + if self.scan_stack.is_empty() { debug!("pp End/print Vec<{},{}>", self.left, self.right); self.print(token, 0) } else { @@ -348,7 +339,7 @@ impl<'a> Printer<'a> { } } Token::Break(b) => { - if self.scan_stack_empty { + if self.scan_stack.is_empty() { self.left_total = 1; self.right_total = 1; self.left = 0; @@ -365,7 +356,7 @@ impl<'a> Printer<'a> { Ok(()) } Token::String(s, len) => { - if self.scan_stack_empty { + if self.scan_stack.is_empty() { debug!("pp String('{}')/print Vec<{},{}>", s, self.left, self.right); self.print(Token::String(s, len), len) @@ -387,12 +378,10 @@ impl<'a> Printer<'a> { if self.right_total - self.left_total > self.space { debug!("scan window is {}, longer than space on line ({})", self.right_total - self.left_total, self.space); - if !self.scan_stack_empty { - if self.left == self.scan_stack[self.bottom] { - debug!("setting {} to infinity and popping", self.left); - let scanned = self.scan_pop_bottom(); - self.size[scanned] = SIZE_INFINITY; - } + if Some(&self.left) == self.scan_stack.back() { + debug!("setting {} to infinity and popping", self.left); + let scanned = self.scan_pop_bottom(); + self.size[scanned] = SIZE_INFINITY; } self.advance_left()?; if self.left != self.right { @@ -403,38 +392,16 @@ impl<'a> Printer<'a> { } pub fn scan_push(&mut self, x: usize) { debug!("scan_push {}", x); - if self.scan_stack_empty { - self.scan_stack_empty = false; - } else { - self.top += 1; - self.top %= self.buf_len; - assert!(self.top != self.bottom); - } - self.scan_stack[self.top] = x; + self.scan_stack.push_front(x); } pub fn scan_pop(&mut self) -> usize { - assert!(!self.scan_stack_empty); - let x = self.scan_stack[self.top]; - if self.top == self.bottom { - self.scan_stack_empty = true; - } else { - self.top += self.buf_len - 1; self.top %= self.buf_len; - } - x + self.scan_stack.pop_front().unwrap() } pub fn scan_top(&mut self) -> usize { - assert!(!self.scan_stack_empty); - self.scan_stack[self.top] + *self.scan_stack.front().unwrap() } pub fn scan_pop_bottom(&mut self) -> usize { - assert!(!self.scan_stack_empty); - let x = self.scan_stack[self.bottom]; - if self.top == self.bottom { - self.scan_stack_empty = true; - } else { - self.bottom += 1; self.bottom %= self.buf_len; - } - x + self.scan_stack.pop_back().unwrap() } pub fn advance_right(&mut self) { self.right += 1; @@ -476,7 +443,7 @@ impl<'a> Printer<'a> { Ok(()) } pub fn check_stack(&mut self, k: isize) { - if !self.scan_stack_empty { + if !self.scan_stack.is_empty() { let x = self.scan_top(); match self.token[x] { Token::Begin(_) => { From e8cbcef86e33b7d3ffeda9be8797eebaac3eac28 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sun, 1 May 2016 13:16:06 +0100 Subject: [PATCH 34/97] Fix alloc_jemalloc on windows gnu targets jemalloc prefixes the symbols by default on Windows so we need to account for that to avoid link errors such as: `undefined reference to `mallocx'` when using alloc_jemalloc. --- src/liballoc_jemalloc/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 3a30bebec5478..7651d91c06d6b 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -41,28 +41,28 @@ use libc::{c_int, c_void, size_t}; #[cfg(not(cargobuild))] extern {} -// Note that the symbols here are prefixed by default on OSX (we don't -// explicitly request it), and on Android and DragonFly we explicitly request -// it as unprefixing cause segfaults (mismatches in allocators). +// Note that the symbols here are prefixed by default on OSX and Windows (we +// don't explicitly request it), and on Android and DragonFly we explicitly +// request it as unprefixing cause segfaults (mismatches in allocators). extern { #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly"), + target_os = "dragonfly", target_os = "windows"), link_name = "je_mallocx")] fn mallocx(size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly"), + target_os = "dragonfly", target_os = "windows"), link_name = "je_rallocx")] fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly"), + target_os = "dragonfly", target_os = "windows"), link_name = "je_xallocx")] fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly"), + target_os = "dragonfly", target_os = "windows"), link_name = "je_sdallocx")] fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly"), + target_os = "dragonfly", target_os = "windows"), link_name = "je_nallocx")] fn nallocx(size: size_t, flags: c_int) -> size_t; } From a4128e5950395993b3db1e0db095c07727f55991 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Sun, 1 May 2016 13:53:39 -0400 Subject: [PATCH 35/97] Fix a race condition caused by concurrently executed codegen unit tests. --- src/test/codegen-units/partitioning/extern-drop-glue.rs | 5 ++++- src/test/codegen-units/partitioning/extern-generic.rs | 4 +++- .../codegen-units/partitioning/inlining-from-extern-crate.rs | 4 +++- src/test/codegen-units/partitioning/local-drop-glue.rs | 4 +++- src/test/codegen-units/partitioning/local-generic.rs | 4 +++- src/test/codegen-units/partitioning/local-inlining.rs | 4 +++- .../codegen-units/partitioning/local-transitive-inlining.rs | 4 +++- .../codegen-units/partitioning/methods-are-with-self-type.rs | 4 +++- src/test/codegen-units/partitioning/regular-modules.rs | 4 +++- src/test/codegen-units/partitioning/statics.rs | 4 +++- 10 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index be41232ffbab0..5262d31ae0dca 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -9,7 +9,10 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp + +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/extern-drop-glue #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/extern-generic.rs b/src/test/codegen-units/partitioning/extern-generic.rs index cd6f4619f9c80..6beed231df993 100644 --- a/src/test/codegen-units/partitioning/extern-generic.rs +++ b/src/test/codegen-units/partitioning/extern-generic.rs @@ -9,7 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/extern-generic #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs index 7b92cf3f7cd52..967824f31d045 100644 --- a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -9,7 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/inlining-from-extern-crate #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index f3a973fc47851..1edc3d5d2e238 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -9,7 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-drop-glue #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-generic.rs b/src/test/codegen-units/partitioning/local-generic.rs index dd18874baa32b..4c762ebdc2e54 100644 --- a/src/test/codegen-units/partitioning/local-generic.rs +++ b/src/test/codegen-units/partitioning/local-generic.rs @@ -9,7 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/local-generic #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index f493c8ed63f74..880cc0a4fb47a 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -9,7 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-inlining #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index 31d99e08b6530..f3efa2587d3d5 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -9,7 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/local-transitive-inlining #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs index 6d04545f93d6e..390bade153c58 100644 --- a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs +++ b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs @@ -9,7 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/methods-are-with-self-type #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/regular-modules.rs b/src/test/codegen-units/partitioning/regular-modules.rs index 69c9bd0a12ae4..c3af86f820f18 100644 --- a/src/test/codegen-units/partitioning/regular-modules.rs +++ b/src/test/codegen-units/partitioning/regular-modules.rs @@ -9,7 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=eager -Z incremental=tmp +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/regular-modules #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/statics.rs b/src/test/codegen-units/partitioning/statics.rs index e853ccaff0dd5..9e878b95a369a 100644 --- a/src/test/codegen-units/partitioning/statics.rs +++ b/src/test/codegen-units/partitioning/statics.rs @@ -9,7 +9,9 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp +// We specify -Z incremental here because we want to test the partitioning for +// incremental compilation +// compile-flags:-Zprint-trans-items=lazy -Zincremental=tmp/partitioning-tests/statics #![crate_type="lib"] From b51698ad60ecad793ac745be676d3f059bea4b80 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 1 May 2016 21:54:55 +0200 Subject: [PATCH 36/97] match check: note "catchall" patterns in unreachable error Caught as catchall patterns are: * unconditional name bindings * references to them * tuple bindings with catchall elements Fixes #31221. --- src/librustc_const_eval/check_match.rs | 23 ++++++++++-- src/test/compile-fail/issue-31221.rs | 49 ++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-31221.rs diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 5883013ac72f2..adc158b323c91 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -341,7 +341,15 @@ fn check_arms(cx: &MatchCheckCtxt, }, hir::MatchSource::Normal => { - span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern") + let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001, + "unreachable pattern"); + // if we had a catchall pattern, hint at that + for row in &seen.0 { + if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0]) { + span_note!(err, row[0].span, "this pattern matches any value"); + } + } + err.emit(); }, hir::MatchSource::TryDesugar => { @@ -361,7 +369,18 @@ fn check_arms(cx: &MatchCheckCtxt, } } -fn raw_pat<'a>(p: &'a Pat) -> &'a Pat { +/// Checks for common cases of "catchall" patterns that may not be intended as such. +fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool { + match p.node { + PatKind::Ident(_, _, None) => pat_is_binding(dm, p), + PatKind::Ident(_, _, Some(ref s)) => pat_is_catchall(dm, &s), + PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s), + PatKind::Tup(ref v) => v.iter().all(|p| pat_is_catchall(dm, &p)), + _ => false + } +} + +fn raw_pat(p: &Pat) -> &Pat { match p.node { PatKind::Ident(_, _, Some(ref s)) => raw_pat(&s), _ => p diff --git a/src/test/compile-fail/issue-31221.rs b/src/test/compile-fail/issue-31221.rs new file mode 100644 index 0000000000000..2b3df9ad1d83b --- /dev/null +++ b/src/test/compile-fail/issue-31221.rs @@ -0,0 +1,49 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Enum { + Var1, + Var2, +} + +fn main() { + use Enum::*; + let s = Var1; + match s { + Var1 => (), + Var3 => (), + //~^ NOTE this pattern matches any value + Var2 => (), + //~^ ERROR unreachable pattern + }; + match &s { + &Var1 => (), + &Var3 => (), + //~^ NOTE this pattern matches any value + &Var2 => (), + //~^ ERROR unreachable pattern + }; + let t = (Var1, Var1); + match t { + (Var1, b) => (), + (c, d) => (), + //~^ NOTE this pattern matches any value + anything => () + //~^ ERROR unreachable pattern + }; + // `_` need not emit a note, it is pretty obvious already. + let t = (Var1, Var1); + match t { + (Var1, b) => (), + _ => (), + anything => () + //~^ ERROR unreachable pattern + }; +} From ffba7b7254f9b828cf173ed066ba2d69b8831cd8 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 1 May 2016 22:21:11 +0200 Subject: [PATCH 37/97] typeck: remove confusing suggestion for calling a fn type * It is not clear what a "base function" is. * The suggestion just adds parens, so suggests calling without args. The second point could be fixed with e.g. `(...)` instead of `()`, but the preceding "note: X is a function, perhaps you wish to call it" should already be clear enough. Fixes: #31341 --- src/librustc_typeck/check/method/suggest.rs | 4 ---- src/test/compile-fail/issue-29124.rs | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index c5195cf8787da..31c81170f7a36 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -158,10 +158,6 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if let Some(expr) = rcvr_expr { if let Ok (expr_string) = cx.sess.codemap().span_to_snippet(expr.span) { report_function!(expr.span, expr_string); - err.span_suggestion(expr.span, - "try calling the base function:", - format!("{}()", - expr_string)); } else if let Expr_::ExprPath(_, path) = expr.node.clone() { if let Some(segment) = path.segments.last() { diff --git a/src/test/compile-fail/issue-29124.rs b/src/test/compile-fail/issue-29124.rs index b3dc043f502fc..a72dac0d5dd68 100644 --- a/src/test/compile-fail/issue-29124.rs +++ b/src/test/compile-fail/issue-29124.rs @@ -25,11 +25,7 @@ fn main() { obj::func.x(); //~^ ERROR no method named `x` found for type `fn() -> ret {obj::func}` in the current scope //~^^ NOTE obj::func is a function, perhaps you wish to call it - //~^^^ HELP try calling the base function: - //~| SUGGESTION obj::func().x(); func.x(); //~^ ERROR no method named `x` found for type `fn() -> ret {func}` in the current scope //~^^ NOTE func is a function, perhaps you wish to call it - //~^^^ HELP try calling the base function: - //~| SUGGESTION func().x(); } From 02df9f32b1947fe194e2844a11db454b9763ea92 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 30 Apr 2016 19:37:17 +0000 Subject: [PATCH 38/97] Remove idempotent lowering test --- src/librustc/hir/lowering.rs | 114 ----------------------------------- 1 file changed, 114 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ea92cfd9ee075..6d6186fb93795 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2116,117 +2116,3 @@ fn signal_block_expr(lctx: &LoweringContext, }), attrs) } - - - -#[cfg(test)] -mod test { - use super::*; - use syntax::ast::{self, NodeId, NodeIdAssigner}; - use syntax::{parse, codemap}; - use syntax::fold::Folder; - use std::cell::Cell; - - struct MockAssigner { - next_id: Cell, - } - - impl MockAssigner { - fn new() -> MockAssigner { - MockAssigner { next_id: Cell::new(0) } - } - } - - trait FakeExtCtxt { - fn call_site(&self) -> codemap::Span; - fn cfg(&self) -> ast::CrateConfig; - fn ident_of(&self, st: &str) -> ast::Ident; - fn name_of(&self, st: &str) -> ast::Name; - fn parse_sess(&self) -> &parse::ParseSess; - } - - impl FakeExtCtxt for parse::ParseSess { - fn call_site(&self) -> codemap::Span { - codemap::Span { - lo: codemap::BytePos(0), - hi: codemap::BytePos(0), - expn_id: codemap::NO_EXPANSION, - } - } - fn cfg(&self) -> ast::CrateConfig { - Vec::new() - } - fn ident_of(&self, st: &str) -> ast::Ident { - parse::token::str_to_ident(st) - } - fn name_of(&self, st: &str) -> ast::Name { - parse::token::intern(st) - } - fn parse_sess(&self) -> &parse::ParseSess { - self - } - } - - impl NodeIdAssigner for MockAssigner { - fn next_node_id(&self) -> NodeId { - let result = self.next_id.get(); - self.next_id.set(result + 1); - result - } - - fn peek_node_id(&self) -> NodeId { - self.next_id.get() - } - } - - impl Folder for MockAssigner { - fn new_id(&mut self, old_id: NodeId) -> NodeId { - assert_eq!(old_id, ast::DUMMY_NODE_ID); - self.next_node_id() - } - } - - #[test] - fn test_preserves_ids() { - let cx = parse::ParseSess::new(); - let mut assigner = MockAssigner::new(); - - let ast_if_let = quote_expr!(&cx, - if let Some(foo) = baz { - bar(foo); - }); - let ast_if_let = assigner.fold_expr(ast_if_let); - let ast_while_let = quote_expr!(&cx, - while let Some(foo) = baz { - bar(foo); - }); - let ast_while_let = assigner.fold_expr(ast_while_let); - let ast_for = quote_expr!(&cx, - for i in 0..10 { - for j in 0..10 { - foo(i, j); - } - }); - let ast_for = assigner.fold_expr(ast_for); - let ast_in = quote_expr!(&cx, in HEAP { foo() }); - let ast_in = assigner.fold_expr(ast_in); - - let lctx = LoweringContext::testing_context(&assigner); - - let hir1 = lower_expr(&lctx, &ast_if_let); - let hir2 = lower_expr(&lctx, &ast_if_let); - assert!(hir1 == hir2); - - let hir1 = lower_expr(&lctx, &ast_while_let); - let hir2 = lower_expr(&lctx, &ast_while_let); - assert!(hir1 == hir2); - - let hir1 = lower_expr(&lctx, &ast_for); - let hir2 = lower_expr(&lctx, &ast_for); - assert!(hir1 == hir2); - - let hir1 = lower_expr(&lctx, &ast_in); - let hir2 = lower_expr(&lctx, &ast_in); - assert!(hir1 == hir2); - } -} From ca88c44a9092c22ce39797e9b19ed6f7bb179ada Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 30 Apr 2016 00:48:03 +0000 Subject: [PATCH 39/97] Avoid using the lowering context in `librustc_save_analysis` --- src/librustc_driver/driver.rs | 12 ++---------- src/librustc_driver/lib.rs | 1 - src/librustc_save_analysis/dump_visitor.rs | 6 ++---- src/librustc_save_analysis/lib.rs | 20 +++++++------------- 4 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4dd03fd210654..3f0833cd6700c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -165,8 +165,7 @@ pub fn compile_input(sess: &Session, &hir_map, &expanded_crate, &hir_map.krate(), - &id[..], - &lcx), + &id[..]), Ok(())); } @@ -203,7 +202,6 @@ pub fn compile_input(sess: &Session, &analysis, mir_map.as_ref(), tcx, - &lcx, &id); (control.after_analysis.callback)(state); @@ -345,7 +343,6 @@ pub struct CompileState<'a, 'ast: 'a, 'tcx: 'a> { pub mir_map: Option<&'a MirMap<'tcx>>, pub analysis: Option<&'a ty::CrateAnalysis<'a>>, pub tcx: Option<&'a TyCtxt<'tcx>>, - pub lcx: Option<&'a LoweringContext<'a>>, pub trans: Option<&'a trans::CrateTranslation>, } @@ -368,7 +365,6 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { analysis: None, mir_map: None, tcx: None, - lcx: None, trans: None, } } @@ -400,15 +396,13 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { hir_map: &'a hir_map::Map<'ast>, krate: &'a ast::Crate, hir_crate: &'a hir::Crate, - crate_name: &'a str, - lcx: &'a LoweringContext<'a>) + crate_name: &'a str) -> CompileState<'a, 'ast, 'tcx> { CompileState { crate_name: Some(crate_name), ast_map: Some(hir_map), krate: Some(krate), hir_crate: Some(hir_crate), - lcx: Some(lcx), ..CompileState::empty(input, session, out_dir) } } @@ -421,7 +415,6 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { analysis: &'a ty::CrateAnalysis, mir_map: Option<&'a MirMap<'tcx>>, tcx: &'a TyCtxt<'tcx>, - lcx: &'a LoweringContext<'a>, crate_name: &'a str) -> CompileState<'a, 'ast, 'tcx> { CompileState { @@ -430,7 +423,6 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { tcx: Some(tcx), krate: krate, hir_crate: Some(hir_crate), - lcx: Some(lcx), crate_name: Some(crate_name), ..CompileState::empty(input, session, out_dir) } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 666432819302e..2d3363507d06c 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -499,7 +499,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.after_analysis.callback = box |state| { time(state.session.time_passes(), "save analysis", || { save::process_crate(state.tcx.unwrap(), - state.lcx.unwrap(), state.krate.unwrap(), state.analysis.unwrap(), state.crate_name.unwrap(), diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 724bd7341e312..d12d1c8aae057 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -42,8 +42,6 @@ use syntax::visit::{self, Visitor}; use syntax::print::pprust::{path_to_string, ty_to_string}; use syntax::ptr::P; -use rustc::hir::lowering::lower_expr; - use super::{escape, generated_code, SaveContext, PathCollector}; use super::data::*; use super::dump::Dump; @@ -1222,7 +1220,7 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx, visit::walk_expr(self, ex); } ast::ExprKind::Struct(ref path, ref fields, ref base) => { - let hir_expr = lower_expr(self.save_ctxt.lcx, ex); + let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id); let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap(); let def = self.tcx.resolve_expr(&hir_expr); self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base) @@ -1241,7 +1239,7 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx, ast::ExprKind::TupField(ref sub_ex, idx) => { self.visit_expr(&sub_ex); - let hir_node = lower_expr(self.save_ctxt.lcx, sub_ex); + let hir_node = self.save_ctxt.tcx.map.expect_expr(sub_ex.id); let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; match *ty { ty::TyStruct(def, _) => { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 6830735b0bab4..85c8f1f8ec98c 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -28,7 +28,7 @@ #[macro_use] extern crate syntax; extern crate serialize as rustc_serialize; -use rustc::hir::{self, lowering}; +use rustc::hir; use rustc::hir::map::NodeItem; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; @@ -75,7 +75,6 @@ pub mod recorder { pub struct SaveContext<'l, 'tcx: 'l> { tcx: &'l TyCtxt<'tcx>, - lcx: &'l lowering::LoweringContext<'l>, span_utils: SpanUtils<'tcx>, } @@ -84,20 +83,16 @@ macro_rules! option_try( ); impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { - pub fn new(tcx: &'l TyCtxt<'tcx>, - lcx: &'l lowering::LoweringContext<'l>) - -> SaveContext<'l, 'tcx> { + pub fn new(tcx: &'l TyCtxt<'tcx>) -> SaveContext<'l, 'tcx> { let span_utils = SpanUtils::new(&tcx.sess); - SaveContext::from_span_utils(tcx, lcx, span_utils) + SaveContext::from_span_utils(tcx, span_utils) } pub fn from_span_utils(tcx: &'l TyCtxt<'tcx>, - lcx: &'l lowering::LoweringContext<'l>, span_utils: SpanUtils<'tcx>) -> SaveContext<'l, 'tcx> { SaveContext { tcx: tcx, - lcx: lcx, span_utils: span_utils, } } @@ -378,14 +373,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { - let hir_node = lowering::lower_expr(self.lcx, expr); + let hir_node = self.tcx.map.expect_expr(expr.id); let ty = self.tcx.expr_ty_adjusted_opt(&hir_node); if ty.is_none() || ty.unwrap().sty == ty::TyError { return None; } match expr.node { ast::ExprKind::Field(ref sub_ex, ident) => { - let hir_node = lowering::lower_expr(self.lcx, sub_ex); + let hir_node = self.tcx.map.expect_expr(sub_ex.id); match self.tcx.expr_ty_adjusted(&hir_node).sty { ty::TyStruct(def, _) => { let f = def.struct_variant().field_named(ident.node.name); @@ -405,7 +400,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprKind::Struct(ref path, _, _) => { - let hir_node = lowering::lower_expr(self.lcx, expr); + let hir_node = self.tcx.map.expect_expr(expr.id); match self.tcx.expr_ty_adjusted(&hir_node).sty { ty::TyStruct(def, _) => { let sub_span = self.span_utils.span_for_last_ident(path.span); @@ -704,7 +699,6 @@ impl Format { } pub fn process_crate<'l, 'tcx>(tcx: &'l TyCtxt<'tcx>, - lcx: &'l lowering::LoweringContext<'l>, krate: &ast::Crate, analysis: &'l ty::CrateAnalysis<'l>, cratename: &str, @@ -755,7 +749,7 @@ pub fn process_crate<'l, 'tcx>(tcx: &'l TyCtxt<'tcx>, let output = &mut output_file; let utils: SpanUtils<'tcx> = SpanUtils::new(&tcx.sess); - let save_ctxt = SaveContext::new(tcx, lcx); + let save_ctxt = SaveContext::new(tcx); macro_rules! dump { ($new_dumper: expr) => {{ From b8dc2a7c768eb288b0984a4429a793df6a1213de Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 30 Apr 2016 19:48:46 +0000 Subject: [PATCH 40/97] Remove the lowering context's id caching system --- src/librustc/hir/lowering.rs | 158 ++++++----------------------------- 1 file changed, 27 insertions(+), 131 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6d6186fb93795..90a5eee1f160d 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -29,21 +29,6 @@ // are unique). Every new node must have a unique id. Avoid cloning HIR nodes. // If you do, you must then set the new node's id to a fresh one. // -// Lowering must be reproducable (the compiler only lowers once, but tools and -// custom lints may lower an AST node to a HIR node to interact with the -// compiler). The most interesting bit of this is ids - if you lower an AST node -// and create new HIR nodes with fresh ids, when re-lowering the same node, you -// must ensure you get the same ids! To do this, we keep track of the next id -// when we translate a node which requires new ids. By checking this cache and -// using node ids starting with the cached id, we ensure ids are reproducible. -// To use this system, you just need to hold on to a CachedIdSetter object -// whilst lowering. This is an RAII object that takes care of setting and -// restoring the cached id, etc. -// -// This whole system relies on node ids being incremented one at a time and -// all increments being for lowering. This means that you should not call any -// non-lowering function which will use new node ids. -// // We must also cache gensym'ed Idents to ensure that we get the same Ident // every time we lower a node with gensym'ed names. One consequence of this is // that you can only gensym a name once in a lowering (you don't need to worry @@ -67,7 +52,6 @@ use hir::map::definitions::DefPathData; use hir::def_id::DefIndex; use std::collections::BTreeMap; -use std::collections::HashMap; use std::iter; use syntax::ast::*; use syntax::attr::{ThinAttributes, ThinAttributesExt}; @@ -83,18 +67,8 @@ use std::cell::{Cell, RefCell}; pub struct LoweringContext<'a> { crate_root: Option<&'static str>, - // Map AST ids to ids used for expanded nodes. - id_cache: RefCell>, - // Use if there are no cached ids for the current node. + // Use to assign ids to hir nodes that do not directly correspond to an ast node id_assigner: &'a NodeIdAssigner, - // 0 == no cached id. Must be incremented to align with previous id - // incrementing. - cached_id: Cell, - // Keep track of gensym'ed idents. - gensym_cache: RefCell>, - // A copy of cached_id, but is also set to an id while a node is lowered for - // the first time. - gensym_key: Cell, // We must keep the set of definitions up to date as we add nodes that // weren't in the AST. definitions: Option<&'a RefCell>, @@ -121,11 +95,7 @@ impl<'a, 'hir> LoweringContext<'a> { LoweringContext { crate_root: crate_root, - id_cache: RefCell::new(HashMap::new()), id_assigner: id_assigner, - cached_id: Cell::new(0), - gensym_cache: RefCell::new(HashMap::new()), - gensym_key: Cell::new(0), definitions: Some(defs), parent_def: Cell::new(None), } @@ -136,40 +106,18 @@ impl<'a, 'hir> LoweringContext<'a> { pub fn testing_context(id_assigner: &'a NodeIdAssigner) -> LoweringContext<'a> { LoweringContext { crate_root: None, - id_cache: RefCell::new(HashMap::new()), id_assigner: id_assigner, - cached_id: Cell::new(0), - gensym_cache: RefCell::new(HashMap::new()), - gensym_key: Cell::new(0), definitions: None, parent_def: Cell::new(None), } } fn next_id(&self) -> NodeId { - let cached_id = self.cached_id.get(); - if cached_id == 0 { - return self.id_assigner.next_node_id(); - } - - self.cached_id.set(cached_id + 1); - cached_id + self.id_assigner.next_node_id() } fn str_to_ident(&self, s: &'static str) -> hir::Ident { - let gensym_key = self.gensym_key.get(); - if gensym_key == 0 { - return hir::Ident::from_name(token::gensym(s)); - } - - let cached = self.gensym_cache.borrow().contains_key(&(gensym_key, s)); - if cached { - self.gensym_cache.borrow()[&(gensym_key, s)] - } else { - let result = hir::Ident::from_name(token::gensym(s)); - self.gensym_cache.borrow_mut().insert((gensym_key, s), result); - result - } + hir::Ident::from_name(token::gensym(s)) } // Panics if this LoweringContext's NodeIdAssigner is not able to emit diagnostics. @@ -197,56 +145,6 @@ impl<'a, 'hir> LoweringContext<'a> { } } -// Utility fn for setting and unsetting the cached id. -fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R - where OP: FnOnce(&LoweringContext) -> R -{ - // Only reset the id if it was previously 0, i.e., was not cached. - // If it was cached, we are in a nested node, but our id count will - // still count towards the parent's count. - let reset_cached_id = lctx.cached_id.get() == 0; - // We always reset gensym_key so that if we use the same name in a nested - // node and after that node, they get different values. - let old_gensym_key = lctx.gensym_key.get(); - - { - let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut(); - - if id_cache.contains_key(&expr_id) { - panic!("relowering!!!"); - /* - let cached_id = lctx.cached_id.get(); - if cached_id == 0 { - // We're entering a node where we need to track ids, but are not - // yet tracking. - lctx.cached_id.set(id_cache[&expr_id]); - } else { - // We're already tracking - check that the tracked id is the same - // as the expected id. - assert!(cached_id == id_cache[&expr_id], "id mismatch"); - } - lctx.gensym_key.set(id_cache[&expr_id]); - */ - } else { - // We've never lowered this node before, remember it for next time. - let next_id = lctx.id_assigner.peek_node_id(); - id_cache.insert(expr_id, next_id); - lctx.gensym_key.set(next_id); - // self.cached_id is not set when we lower a node for the first time, - // only on re-lowering. - } - } - - let result = op(lctx); - - if reset_cached_id { - lctx.cached_id.set(0); - } - lctx.gensym_key.set(old_gensym_key); - - result -} - pub fn lower_ident(_lctx: &LoweringContext, ident: Ident) -> hir::Ident { hir::Ident { name: mtwt::resolve(ident), @@ -1080,7 +978,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); // InPlace::finalize(place) // }) - return cache_ids(lctx, e.id, |lctx| { + return { let placer_expr = lower_expr(lctx, placer); let value_expr = lower_expr(lctx, value_expr); @@ -1175,7 +1073,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { e.span, hir::PushUnstableBlock, e.attrs.clone()) - }); + } } ExprKind::Vec(ref exprs) => { @@ -1229,20 +1127,18 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { let else_opt = else_opt.as_ref().map(|els| { match els.node { ExprKind::IfLet(..) => { - cache_ids(lctx, e.id, |lctx| { - // wrap the if-let expr in a block - let span = els.span; - let els = lower_expr(lctx, els); - let id = lctx.next_id(); - let blk = P(hir::Block { - stmts: hir_vec![], - expr: Some(els), - id: id, - rules: hir::DefaultBlock, - span: span, - }); - expr_block(lctx, blk, None) - }) + // wrap the if-let expr in a block + let span = els.span; + let els = lower_expr(lctx, els); + let id = lctx.next_id(); + let blk = P(hir::Block { + stmts: hir_vec![], + expr: Some(els), + id: id, + rules: hir::DefaultBlock, + span: span, + }); + expr_block(lctx, blk, None) } _ => lower_expr(lctx, els), } @@ -1331,7 +1227,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { None) } - return cache_ids(lctx, e.id, |lctx| { + return { use syntax::ast::RangeLimits::*; match (e1, e2, lims) { @@ -1362,7 +1258,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { _ => panic!(lctx.diagnostic().span_fatal(e.span, "inclusive range with no end")) } - }); + } } ExprKind::Path(ref qself, ref path) => { let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| { @@ -1436,7 +1332,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // _ => [ | ()] // } - return cache_ids(lctx, e.id, |lctx| { + return { // ` => ` let pat_arm = { let body = lower_block(lctx, body); @@ -1510,7 +1406,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { contains_else_clause: contains_else_clause, }), e.attrs.clone()) - }); + } } // Desugar ExprWhileLet @@ -1525,7 +1421,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // } // } - return cache_ids(lctx, e.id, |lctx| { + return { // ` => ` let pat_arm = { let body = lower_block(lctx, body); @@ -1556,7 +1452,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { opt_ident.map(|ident| lower_ident(lctx, ident))); // add attributes to the outer returned expr node expr(lctx, e.span, loop_expr, e.attrs.clone()) - }); + } } // Desugar ExprForLoop @@ -1578,7 +1474,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // result // } - return cache_ids(lctx, e.id, |lctx| { + return { // expand let head = lower_expr(lctx, head); @@ -1677,7 +1573,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { let block = block_all(lctx, e.span, hir_vec![let_stmt], Some(result)); // add the attributes to the outer returned expr node expr_block(lctx, block, e.attrs.clone()) - }); + } } // Desugar ExprKind::Try @@ -1694,7 +1590,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // } // } - return cache_ids(lctx, e.id, |lctx| { + return { // expand let sub_expr = lower_expr(lctx, sub_expr); @@ -1735,7 +1631,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { expr_match(lctx, e.span, sub_expr, hir_vec![err_arm, ok_arm], hir::MatchSource::TryDesugar, None) - }) + } } ExprKind::Mac(_) => panic!("Shouldn't exist here"), From 298a1c056fd5a3507939581f0577aeb9f313bae2 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 2 May 2016 00:02:38 +0000 Subject: [PATCH 41/97] Cleanup formatting --- src/librustc/hir/lowering.rs | 654 +++++++++++++++++------------------ 1 file changed, 321 insertions(+), 333 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 90a5eee1f160d..099e13dfa09e8 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -978,102 +978,100 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); // InPlace::finalize(place) // }) - return { - let placer_expr = lower_expr(lctx, placer); - let value_expr = lower_expr(lctx, value_expr); - - let placer_ident = lctx.str_to_ident("placer"); - let place_ident = lctx.str_to_ident("place"); - let p_ptr_ident = lctx.str_to_ident("p_ptr"); - - let make_place = ["ops", "Placer", "make_place"]; - let place_pointer = ["ops", "Place", "pointer"]; - let move_val_init = ["intrinsics", "move_val_init"]; - let inplace_finalize = ["ops", "InPlace", "finalize"]; - - let make_call = |lctx: &LoweringContext, p, args| { - let path = core_path(lctx, e.span, p); - let path = expr_path(lctx, path, None); - expr_call(lctx, e.span, path, args, None) - }; - - let mk_stmt_let = |lctx: &LoweringContext, bind, expr| { - stmt_let(lctx, e.span, false, bind, expr, None) - }; + let placer_expr = lower_expr(lctx, placer); + let value_expr = lower_expr(lctx, value_expr); + + let placer_ident = lctx.str_to_ident("placer"); + let place_ident = lctx.str_to_ident("place"); + let p_ptr_ident = lctx.str_to_ident("p_ptr"); + + let make_place = ["ops", "Placer", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let move_val_init = ["intrinsics", "move_val_init"]; + let inplace_finalize = ["ops", "InPlace", "finalize"]; + + let make_call = |lctx: &LoweringContext, p, args| { + let path = core_path(lctx, e.span, p); + let path = expr_path(lctx, path, None); + expr_call(lctx, e.span, path, args, None) + }; - let mk_stmt_let_mut = |lctx: &LoweringContext, bind, expr| { - stmt_let(lctx, e.span, true, bind, expr, None) - }; + let mk_stmt_let = |lctx: &LoweringContext, bind, expr| { + stmt_let(lctx, e.span, false, bind, expr, None) + }; - // let placer = ; - let s1 = { - let placer_expr = signal_block_expr(lctx, - hir_vec![], - placer_expr, - e.span, - hir::PopUnstableBlock, - None); - mk_stmt_let(lctx, placer_ident, placer_expr) - }; + let mk_stmt_let_mut = |lctx: &LoweringContext, bind, expr| { + stmt_let(lctx, e.span, true, bind, expr, None) + }; - // let mut place = Placer::make_place(placer); - let s2 = { - let placer = expr_ident(lctx, e.span, placer_ident, None); - let call = make_call(lctx, &make_place, hir_vec![placer]); - mk_stmt_let_mut(lctx, place_ident, call) - }; + // let placer = ; + let s1 = { + let placer_expr = signal_block_expr(lctx, + hir_vec![], + placer_expr, + e.span, + hir::PopUnstableBlock, + None); + mk_stmt_let(lctx, placer_ident, placer_expr) + }; - // let p_ptr = Place::pointer(&mut place); - let s3 = { - let agent = expr_ident(lctx, e.span, place_ident, None); - let args = hir_vec![expr_mut_addr_of(lctx, e.span, agent, None)]; - let call = make_call(lctx, &place_pointer, args); - mk_stmt_let(lctx, p_ptr_ident, call) - }; + // let mut place = Placer::make_place(placer); + let s2 = { + let placer = expr_ident(lctx, e.span, placer_ident, None); + let call = make_call(lctx, &make_place, hir_vec![placer]); + mk_stmt_let_mut(lctx, place_ident, call) + }; - // pop_unsafe!(EXPR)); - let pop_unsafe_expr = { - let value_expr = signal_block_expr(lctx, - hir_vec![], - value_expr, - e.span, - hir::PopUnstableBlock, - None); - signal_block_expr(lctx, - hir_vec![], - value_expr, - e.span, - hir::PopUnsafeBlock(hir::CompilerGenerated), None) - }; + // let p_ptr = Place::pointer(&mut place); + let s3 = { + let agent = expr_ident(lctx, e.span, place_ident, None); + let args = hir_vec![expr_mut_addr_of(lctx, e.span, agent, None)]; + let call = make_call(lctx, &place_pointer, args); + mk_stmt_let(lctx, p_ptr_ident, call) + }; - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let expr = { - let ptr = expr_ident(lctx, e.span, p_ptr_ident, None); - let call_move_val_init = - hir::StmtSemi( - make_call(lctx, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), - lctx.next_id()); - let call_move_val_init = respan(e.span, call_move_val_init); - - let place = expr_ident(lctx, e.span, place_ident, None); - let call = make_call(lctx, &inplace_finalize, hir_vec![place]); - signal_block_expr(lctx, - hir_vec![call_move_val_init], - call, - e.span, - hir::PushUnsafeBlock(hir::CompilerGenerated), None) - }; + // pop_unsafe!(EXPR)); + let pop_unsafe_expr = { + let value_expr = signal_block_expr(lctx, + hir_vec![], + value_expr, + e.span, + hir::PopUnstableBlock, + None); + signal_block_expr(lctx, + hir_vec![], + value_expr, + e.span, + hir::PopUnsafeBlock(hir::CompilerGenerated), None) + }; + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let expr = { + let ptr = expr_ident(lctx, e.span, p_ptr_ident, None); + let call_move_val_init = + hir::StmtSemi( + make_call(lctx, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), + lctx.next_id()); + let call_move_val_init = respan(e.span, call_move_val_init); + + let place = expr_ident(lctx, e.span, place_ident, None); + let call = make_call(lctx, &inplace_finalize, hir_vec![place]); signal_block_expr(lctx, - hir_vec![s1, s2, s3], - expr, + hir_vec![call_move_val_init], + call, e.span, - hir::PushUnstableBlock, - e.attrs.clone()) - } + hir::PushUnsafeBlock(hir::CompilerGenerated), None) + }; + + return signal_block_expr(lctx, + hir_vec![s1, s2, s3], + expr, + e.span, + hir::PushUnstableBlock, + e.attrs.clone()); } ExprKind::Vec(ref exprs) => { @@ -1227,38 +1225,36 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { None) } - return { - use syntax::ast::RangeLimits::*; + use syntax::ast::RangeLimits::*; - match (e1, e2, lims) { - (&None, &None, HalfOpen) => - make_struct(lctx, e, &["RangeFull"], - &[]), + return match (e1, e2, lims) { + (&None, &None, HalfOpen) => + make_struct(lctx, e, &["RangeFull"], + &[]), - (&Some(ref e1), &None, HalfOpen) => - make_struct(lctx, e, &["RangeFrom"], - &[("start", e1)]), + (&Some(ref e1), &None, HalfOpen) => + make_struct(lctx, e, &["RangeFrom"], + &[("start", e1)]), - (&None, &Some(ref e2), HalfOpen) => - make_struct(lctx, e, &["RangeTo"], - &[("end", e2)]), + (&None, &Some(ref e2), HalfOpen) => + make_struct(lctx, e, &["RangeTo"], + &[("end", e2)]), - (&Some(ref e1), &Some(ref e2), HalfOpen) => - make_struct(lctx, e, &["Range"], - &[("start", e1), ("end", e2)]), + (&Some(ref e1), &Some(ref e2), HalfOpen) => + make_struct(lctx, e, &["Range"], + &[("start", e1), ("end", e2)]), - (&None, &Some(ref e2), Closed) => - make_struct(lctx, e, &["RangeToInclusive"], - &[("end", e2)]), + (&None, &Some(ref e2), Closed) => + make_struct(lctx, e, &["RangeToInclusive"], + &[("end", e2)]), - (&Some(ref e1), &Some(ref e2), Closed) => - make_struct(lctx, e, &["RangeInclusive", "NonEmpty"], - &[("start", e1), ("end", e2)]), + (&Some(ref e1), &Some(ref e2), Closed) => + make_struct(lctx, e, &["RangeInclusive", "NonEmpty"], + &[("start", e1), ("end", e2)]), - _ => panic!(lctx.diagnostic().span_fatal(e.span, - "inclusive range with no end")) - } - } + _ => panic!(lctx.diagnostic().span_fatal(e.span, + "inclusive range with no end")) + }; } ExprKind::Path(ref qself, ref path) => { let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| { @@ -1332,81 +1328,79 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // _ => [ | ()] // } - return { - // ` => ` - let pat_arm = { - let body = lower_block(lctx, body); - let body_expr = expr_block(lctx, body, None); - arm(hir_vec![lower_pat(lctx, pat)], body_expr) - }; + // ` => ` + let pat_arm = { + let body = lower_block(lctx, body); + let body_expr = expr_block(lctx, body, None); + arm(hir_vec![lower_pat(lctx, pat)], body_expr) + }; - // `[_ if => ,]` - let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e)); - let else_if_arms = { - let mut arms = vec![]; - loop { - let else_opt_continue = else_opt.and_then(|els| { - els.and_then(|els| { - match els.node { - // else if - hir::ExprIf(cond, then, else_opt) => { - let pat_under = pat_wild(lctx, e.span); - arms.push(hir::Arm { - attrs: hir_vec![], - pats: hir_vec![pat_under], - guard: Some(cond), - body: expr_block(lctx, then, None), - }); - else_opt.map(|else_opt| (else_opt, true)) - } - _ => Some((P(els), false)), + // `[_ if => ,]` + let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e)); + let else_if_arms = { + let mut arms = vec![]; + loop { + let else_opt_continue = else_opt.and_then(|els| { + els.and_then(|els| { + match els.node { + // else if + hir::ExprIf(cond, then, else_opt) => { + let pat_under = pat_wild(lctx, e.span); + arms.push(hir::Arm { + attrs: hir_vec![], + pats: hir_vec![pat_under], + guard: Some(cond), + body: expr_block(lctx, then, None), + }); + else_opt.map(|else_opt| (else_opt, true)) } - }) - }); - match else_opt_continue { - Some((e, true)) => { - else_opt = Some(e); - } - Some((e, false)) => { - else_opt = Some(e); - break; - } - None => { - else_opt = None; - break; + _ => Some((P(els), false)), } + }) + }); + match else_opt_continue { + Some((e, true)) => { + else_opt = Some(e); + } + Some((e, false)) => { + else_opt = Some(e); + break; + } + None => { + else_opt = None; + break; } } - arms - }; - - let contains_else_clause = else_opt.is_some(); + } + arms + }; - // `_ => [ | ()]` - let else_arm = { - let pat_under = pat_wild(lctx, e.span); - let else_expr = - else_opt.unwrap_or_else( - || expr_tuple(lctx, e.span, hir_vec![], None)); - arm(hir_vec![pat_under], else_expr) - }; + let contains_else_clause = else_opt.is_some(); - let mut arms = Vec::with_capacity(else_if_arms.len() + 2); - arms.push(pat_arm); - arms.extend(else_if_arms); - arms.push(else_arm); + // `_ => [ | ()]` + let else_arm = { + let pat_under = pat_wild(lctx, e.span); + let else_expr = + else_opt.unwrap_or_else( + || expr_tuple(lctx, e.span, hir_vec![], None)); + arm(hir_vec![pat_under], else_expr) + }; - let sub_expr = lower_expr(lctx, sub_expr); - // add attributes to the outer returned expr node - expr(lctx, - e.span, - hir::ExprMatch(sub_expr, - arms.into(), - hir::MatchSource::IfLetDesugar { - contains_else_clause: contains_else_clause, - }), - e.attrs.clone()) - } + let mut arms = Vec::with_capacity(else_if_arms.len() + 2); + arms.push(pat_arm); + arms.extend(else_if_arms); + arms.push(else_arm); + + let sub_expr = lower_expr(lctx, sub_expr); + // add attributes to the outer returned expr node + return expr(lctx, + e.span, + hir::ExprMatch(sub_expr, + arms.into(), + hir::MatchSource::IfLetDesugar { + contains_else_clause: contains_else_clause, + }), + e.attrs.clone()); } // Desugar ExprWhileLet @@ -1421,38 +1415,36 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // } // } - return { - // ` => ` - let pat_arm = { - let body = lower_block(lctx, body); - let body_expr = expr_block(lctx, body, None); - arm(hir_vec![lower_pat(lctx, pat)], body_expr) - }; + // ` => ` + let pat_arm = { + let body = lower_block(lctx, body); + let body_expr = expr_block(lctx, body, None); + arm(hir_vec![lower_pat(lctx, pat)], body_expr) + }; - // `_ => break` - let break_arm = { - let pat_under = pat_wild(lctx, e.span); - let break_expr = expr_break(lctx, e.span, None); - arm(hir_vec![pat_under], break_expr) - }; + // `_ => break` + let break_arm = { + let pat_under = pat_wild(lctx, e.span); + let break_expr = expr_break(lctx, e.span, None); + arm(hir_vec![pat_under], break_expr) + }; - // `match { ... }` - let arms = hir_vec![pat_arm, break_arm]; - let sub_expr = lower_expr(lctx, sub_expr); - let match_expr = expr(lctx, - e.span, - hir::ExprMatch(sub_expr, - arms, - hir::MatchSource::WhileLetDesugar), - None); - - // `[opt_ident]: loop { ... }` - let loop_block = block_expr(lctx, match_expr); - let loop_expr = hir::ExprLoop(loop_block, - opt_ident.map(|ident| lower_ident(lctx, ident))); - // add attributes to the outer returned expr node - expr(lctx, e.span, loop_expr, e.attrs.clone()) - } + // `match { ... }` + let arms = hir_vec![pat_arm, break_arm]; + let sub_expr = lower_expr(lctx, sub_expr); + let match_expr = expr(lctx, + e.span, + hir::ExprMatch(sub_expr, + arms, + hir::MatchSource::WhileLetDesugar), + None); + + // `[opt_ident]: loop { ... }` + let loop_block = block_expr(lctx, match_expr); + let loop_expr = hir::ExprLoop(loop_block, + opt_ident.map(|ident| lower_ident(lctx, ident))); + // add attributes to the outer returned expr node + return expr(lctx, e.span, loop_expr, e.attrs.clone()); } // Desugar ExprForLoop @@ -1474,106 +1466,104 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // result // } - return { - // expand - let head = lower_expr(lctx, head); - - let iter = lctx.str_to_ident("iter"); - - // `::std::option::Option::Some() => ` - let pat_arm = { - let body_block = lower_block(lctx, body); - let body_span = body_block.span; - let body_expr = P(hir::Expr { - id: lctx.next_id(), - node: hir::ExprBlock(body_block), - span: body_span, - attrs: None, - }); - let pat = lower_pat(lctx, pat); - let some_pat = pat_some(lctx, e.span, pat); + // expand + let head = lower_expr(lctx, head); - arm(hir_vec![some_pat], body_expr) - }; + let iter = lctx.str_to_ident("iter"); - // `::std::option::Option::None => break` - let break_arm = { - let break_expr = expr_break(lctx, e.span, None); + // `::std::option::Option::Some() => ` + let pat_arm = { + let body_block = lower_block(lctx, body); + let body_span = body_block.span; + let body_expr = P(hir::Expr { + id: lctx.next_id(), + node: hir::ExprBlock(body_block), + span: body_span, + attrs: None, + }); + let pat = lower_pat(lctx, pat); + let some_pat = pat_some(lctx, e.span, pat); - arm(hir_vec![pat_none(lctx, e.span)], break_expr) - }; + arm(hir_vec![some_pat], body_expr) + }; - // `match ::std::iter::Iterator::next(&mut iter) { ... }` - let match_expr = { - let next_path = { - let strs = std_path(lctx, &["iter", "Iterator", "next"]); - - path_global(e.span, strs) - }; - let iter = expr_ident(lctx, e.span, iter, None); - let ref_mut_iter = expr_mut_addr_of(lctx, e.span, iter, None); - let next_path = expr_path(lctx, next_path, None); - let next_expr = expr_call(lctx, - e.span, - next_path, - hir_vec![ref_mut_iter], - None); - let arms = hir_vec![pat_arm, break_arm]; - - expr(lctx, - e.span, - hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar), - None) - }; + // `::std::option::Option::None => break` + let break_arm = { + let break_expr = expr_break(lctx, e.span, None); - // `[opt_ident]: loop { ... }` - let loop_block = block_expr(lctx, match_expr); - let loop_expr = hir::ExprLoop(loop_block, - opt_ident.map(|ident| lower_ident(lctx, ident))); - let loop_expr = expr(lctx, e.span, loop_expr, None); - - // `mut iter => { ... }` - let iter_arm = { - let iter_pat = pat_ident_binding_mode(lctx, - e.span, - iter, - hir::BindByValue(hir::MutMutable)); - arm(hir_vec![iter_pat], loop_expr) + arm(hir_vec![pat_none(lctx, e.span)], break_expr) + }; + + // `match ::std::iter::Iterator::next(&mut iter) { ... }` + let match_expr = { + let next_path = { + let strs = std_path(lctx, &["iter", "Iterator", "next"]); + + path_global(e.span, strs) }; + let iter = expr_ident(lctx, e.span, iter, None); + let ref_mut_iter = expr_mut_addr_of(lctx, e.span, iter, None); + let next_path = expr_path(lctx, next_path, None); + let next_expr = expr_call(lctx, + e.span, + next_path, + hir_vec![ref_mut_iter], + None); + let arms = hir_vec![pat_arm, break_arm]; + + expr(lctx, + e.span, + hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar), + None) + }; - // `match ::std::iter::IntoIterator::into_iter() { ... }` - let into_iter_expr = { - let into_iter_path = { - let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]); + // `[opt_ident]: loop { ... }` + let loop_block = block_expr(lctx, match_expr); + let loop_expr = hir::ExprLoop(loop_block, + opt_ident.map(|ident| lower_ident(lctx, ident))); + let loop_expr = expr(lctx, e.span, loop_expr, None); + + // `mut iter => { ... }` + let iter_arm = { + let iter_pat = pat_ident_binding_mode(lctx, + e.span, + iter, + hir::BindByValue(hir::MutMutable)); + arm(hir_vec![iter_pat], loop_expr) + }; - path_global(e.span, strs) - }; + // `match ::std::iter::IntoIterator::into_iter() { ... }` + let into_iter_expr = { + let into_iter_path = { + let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]); - let into_iter = expr_path(lctx, into_iter_path, None); - expr_call(lctx, e.span, into_iter, hir_vec![head], None) + path_global(e.span, strs) }; - let match_expr = expr_match(lctx, - e.span, - into_iter_expr, - hir_vec![iter_arm], - hir::MatchSource::ForLoopDesugar, - None); - - // `{ let _result = ...; _result }` - // underscore prevents an unused_variables lint if the head diverges - let result_ident = lctx.str_to_ident("_result"); - let let_stmt = stmt_let(lctx, + let into_iter = expr_path(lctx, into_iter_path, None); + expr_call(lctx, e.span, into_iter, hir_vec![head], None) + }; + + let match_expr = expr_match(lctx, e.span, - false, - result_ident, - match_expr, + into_iter_expr, + hir_vec![iter_arm], + hir::MatchSource::ForLoopDesugar, None); - let result = expr_ident(lctx, e.span, result_ident, None); - let block = block_all(lctx, e.span, hir_vec![let_stmt], Some(result)); - // add the attributes to the outer returned expr node - expr_block(lctx, block, e.attrs.clone()) - } + + // `{ let _result = ...; _result }` + // underscore prevents an unused_variables lint if the head diverges + let result_ident = lctx.str_to_ident("_result"); + let let_stmt = stmt_let(lctx, + e.span, + false, + result_ident, + match_expr, + None); + let result = expr_ident(lctx, e.span, result_ident, None); + let block = block_all(lctx, e.span, hir_vec![let_stmt], Some(result)); + // add the attributes to the outer returned expr node + return expr_block(lctx, block, e.attrs.clone()); } // Desugar ExprKind::Try @@ -1590,48 +1580,46 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { // } // } - return { - // expand - let sub_expr = lower_expr(lctx, sub_expr); + // expand + let sub_expr = lower_expr(lctx, sub_expr); - // Ok(val) => val - let ok_arm = { - let val_ident = lctx.str_to_ident("val"); - let val_pat = pat_ident(lctx, e.span, val_ident); - let val_expr = expr_ident(lctx, e.span, val_ident, None); - let ok_pat = pat_ok(lctx, e.span, val_pat); + // Ok(val) => val + let ok_arm = { + let val_ident = lctx.str_to_ident("val"); + let val_pat = pat_ident(lctx, e.span, val_ident); + let val_expr = expr_ident(lctx, e.span, val_ident, None); + let ok_pat = pat_ok(lctx, e.span, val_pat); - arm(hir_vec![ok_pat], val_expr) - }; + arm(hir_vec![ok_pat], val_expr) + }; - // Err(err) => return Err(From::from(err)) - let err_arm = { - let err_ident = lctx.str_to_ident("err"); - let from_expr = { - let path = std_path(lctx, &["convert", "From", "from"]); - let path = path_global(e.span, path); - let from = expr_path(lctx, path, None); - let err_expr = expr_ident(lctx, e.span, err_ident, None); - - expr_call(lctx, e.span, from, hir_vec![err_expr], None) - }; - let err_expr = { - let path = std_path(lctx, &["result", "Result", "Err"]); - let path = path_global(e.span, path); - let err_ctor = expr_path(lctx, path, None); - expr_call(lctx, e.span, err_ctor, hir_vec![from_expr], None) - }; - let err_pat = pat_err(lctx, e.span, - pat_ident(lctx, e.span, err_ident)); - let ret_expr = expr(lctx, e.span, - hir::Expr_::ExprRet(Some(err_expr)), None); - - arm(hir_vec![err_pat], ret_expr) + // Err(err) => return Err(From::from(err)) + let err_arm = { + let err_ident = lctx.str_to_ident("err"); + let from_expr = { + let path = std_path(lctx, &["convert", "From", "from"]); + let path = path_global(e.span, path); + let from = expr_path(lctx, path, None); + let err_expr = expr_ident(lctx, e.span, err_ident, None); + + expr_call(lctx, e.span, from, hir_vec![err_expr], None) + }; + let err_expr = { + let path = std_path(lctx, &["result", "Result", "Err"]); + let path = path_global(e.span, path); + let err_ctor = expr_path(lctx, path, None); + expr_call(lctx, e.span, err_ctor, hir_vec![from_expr], None) }; + let err_pat = pat_err(lctx, e.span, + pat_ident(lctx, e.span, err_ident)); + let ret_expr = expr(lctx, e.span, + hir::Expr_::ExprRet(Some(err_expr)), None); - expr_match(lctx, e.span, sub_expr, hir_vec![err_arm, ok_arm], - hir::MatchSource::TryDesugar, None) - } + arm(hir_vec![err_pat], ret_expr) + }; + + return expr_match(lctx, e.span, sub_expr, hir_vec![err_arm, ok_arm], + hir::MatchSource::TryDesugar, None); } ExprKind::Mac(_) => panic!("Shouldn't exist here"), From 522b6ed8a7112064ca6e15ccb49c76fefae8ff71 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 1 May 2016 23:49:26 +0000 Subject: [PATCH 42/97] Avoid keeping MTWT tables for save-analysis --- src/librustc_driver/driver.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 3f0833cd6700c..980ff6c61e426 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -246,9 +246,7 @@ pub fn compile_input(sess: &Session, } fn keep_mtwt_tables(sess: &Session) -> bool { - sess.opts.debugging_opts.keep_mtwt_tables || - sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv + sess.opts.debugging_opts.keep_mtwt_tables } fn keep_ast(sess: &Session) -> bool { From ef69ef81e31b248c0eb5ca6b95ab0f302f49e77c Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 2 May 2016 00:43:02 +0000 Subject: [PATCH 43/97] Remove outdated comment --- src/librustc/hir/lowering.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 099e13dfa09e8..0876e609396c5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -29,12 +29,6 @@ // are unique). Every new node must have a unique id. Avoid cloning HIR nodes. // If you do, you must then set the new node's id to a fresh one. // -// We must also cache gensym'ed Idents to ensure that we get the same Ident -// every time we lower a node with gensym'ed names. One consequence of this is -// that you can only gensym a name once in a lowering (you don't need to worry -// about nested lowering though). That's because we cache based on the name and -// the currently cached node id, which is unique per lowered node. -// // Spans are used for error messages and for tools to map semantics back to // source code. It is therefore not as important with spans as ids to be strict // about use (you can't break the compiler by screwing up a span). Obviously, a From 0e89f55982bea0597b52eee75071caf0e686a449 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 1 May 2016 22:12:48 +0200 Subject: [PATCH 44/97] E0269: add suggestion to check for trailing semicolons In situations where the value of the last expression must be inferred, rustc will not emit the "you might need to remove the semicolon" warning, so at least note this in the extended description. Fixes: #30497 --- src/librustc/diagnostics.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index e230836ef4515..448cdc71af7a5 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -635,7 +635,17 @@ fn foo(x: u8) -> u8 { ``` It is advisable to find out what the unhandled cases are and check for them, -returning an appropriate value or panicking if necessary. +returning an appropriate value or panicking if necessary. Check if you need +to remove a semicolon from the last expression, like in this case: + +```ignore +fn foo(x: u8) -> u8 { + inner(2*x + 1); +} +``` + +The semicolon discards the return value of `inner`, instead of returning +it from `foo`. "##, E0270: r##" From d20b4067fd0e1b641b0c126bd69461b09171519e Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 1 May 2016 20:40:16 +0200 Subject: [PATCH 45/97] diagnostics for E0432: imports are relative to crate root This is curiously missing from both the short message and this long diagnostic. Refs #31573 (not sure if it should be considered "fixed" as the short message still only refers to extern crates). --- src/librustc_resolve/diagnostics.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 0a8fce49ebbaf..56d3b927dc592 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -916,11 +916,14 @@ An import was unresolved. Erroneous code example: use something::Foo; // error: unresolved import `something::Foo`. ``` -Please verify you didn't misspell the import name or the import does exist -in the module from where you tried to import it. Example: +Paths in `use` statements are relative to the crate root. To import items +relative to the current and parent modules, use the `self::` and `super::` +prefixes, respectively. Also verify that you didn't misspell the import +name and that the import exists in the module from where you tried to +import it. Example: ```ignore -use something::Foo; // ok! +use self::something::Foo; // ok! mod something { pub struct Foo; @@ -928,7 +931,7 @@ mod something { ``` Or, if you tried to use a module from an external crate, you may have missed -the `extern crate` declaration: +the `extern crate` declaration (which is usually placed in the crate root): ```ignore extern crate homura; // Required to use the `homura` crate From 9e2300015bc2a88f8f3f81d208f5dfcc1c45d31d Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 2 May 2016 07:44:21 +0200 Subject: [PATCH 46/97] lexer: do not display char confusingly in error message Current code leads to messages like "... use a \xHH escape: \u{e4}" which is confusing. The printed span already points to the offending character, which should be enough to identify the non-ASCII problem. Fixes: #29088 --- src/libsyntax/parse/lexer/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 881663a056c78..da62e5286d4e7 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -931,11 +931,10 @@ impl<'a> StringReader<'a> { _ => { if ascii_only && first_source_char > '\x7F' { let last_pos = self.last_pos; - self.err_span_char(start, - last_pos, - "byte constant must be ASCII. Use a \\xHH escape for a \ - non-ASCII byte", - first_source_char); + self.err_span_(start, + last_pos, + "byte constant must be ASCII. Use a \\xHH escape for a \ + non-ASCII byte"); return false; } } From 38c88360510ac6d9c741d7cbc52608908fd21278 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Sun, 1 May 2016 23:30:12 -0700 Subject: [PATCH 47/97] docs: Changed docs for `size_of` to describe size as a stride offset Current description of `std::mem::size_of` is ambiguous, and the `std::intrinsics::size_of` description incorrectly defines size as the number of bytes necessary to exactly overwrite a value, not including the padding between elements necessary in a vector or structure. --- src/libcore/intrinsics.rs | 7 ++----- src/libcore/mem.rs | 3 +++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 45890cd3d8139..8a9f662bf83aa 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -192,11 +192,8 @@ extern "rust-intrinsic" { /// The size of a type in bytes. /// - /// This is the exact number of bytes in memory taken up by a - /// value of the given type. In other words, a memset of this size - /// would *exactly* overwrite a value. When laid out in vectors - /// and structures there may be additional padding between - /// elements. + /// More specifically, this is the offset in bytes between successive + /// items of the same type, including alignment padding. pub fn size_of() -> usize; /// Moves a value to an uninitialized memory location. diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 2c648d1516bff..56d268bf37c66 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -117,6 +117,9 @@ pub fn forget(t: T) { /// Returns the size of a type in bytes. /// +/// More specifically, this is the offset in bytes between successive +/// items of the same type, including alignment padding. +/// /// # Examples /// /// ``` From 9fe3c065b0e94b1e2ce7f14ab512475e79426ce4 Mon Sep 17 00:00:00 2001 From: Ryman Date: Mon, 2 May 2016 15:54:54 +0100 Subject: [PATCH 48/97] libstd: correct the link to functions in io module documentation Currently the link refers to it's own section of the documentation rather than the list of functions generated by rustdoc. --- src/libstd/io/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index d914d143e7011..ca15aa2d56c49 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -195,7 +195,7 @@ //! //! ## Functions //! -//! There are a number of [functions][functions] that offer access to various +//! There are a number of [functions][functions-list] that offer access to various //! features. For example, we can use three of these functions to copy everything //! from standard input to standard output: //! @@ -208,7 +208,7 @@ //! # } //! ``` //! -//! [functions]: #functions +//! [functions-list]: #functions-1 //! //! ## io::Result //! From a20ee76b56c46a593238ce7ac9b9f70a99c43ff4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:52:31 -0400 Subject: [PATCH 49/97] revamp MultiSpan and introduce new snippet code MultiSpan model is now: - set of primary spans - set of span+label pairs Primary spans render with `^^^`, secondary spans with `---`. Labels are placed next to the `^^^` or `---` marker as appropriate. --- src/libsyntax/codemap.rs | 218 +++---- src/libsyntax/errors/snippet/mod.rs | 821 +++++++++++++++++++++++++++ src/libsyntax/errors/snippet/test.rs | 524 +++++++++++++++++ 3 files changed, 1428 insertions(+), 135 deletions(-) create mode 100644 src/libsyntax/errors/snippet/mod.rs create mode 100644 src/libsyntax/errors/snippet/test.rs diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 35aa827782ddf..228af27f4b10a 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -32,8 +32,6 @@ use serialize::{Encodable, Decodable, Encoder, Decoder}; use ast::Name; -use errors::emitter::MAX_HIGHLIGHT_LINES; - // _____________________________________________________________________________ // Pos, BytePos, CharPos // @@ -51,7 +49,7 @@ pub struct BytePos(pub u32); /// A character offset. Because of multibyte utf8 characters, a byte offset /// is not equivalent to a character offset. The CodeMap will convert BytePos /// values to CharPos values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub struct CharPos(pub usize); // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix @@ -132,13 +130,29 @@ pub struct Span { pub expn_id: ExpnId } -/// Spans are converted to MultiSpans just before error reporting, either automatically, -/// generated by line grouping, or manually constructed. -/// In the latter case care should be taken to ensure that spans are ordered, disjoint, -/// and point into the same FileMap. +/// A collection of spans. Spans have two orthogonal attributes: +/// +/// - they can be *primary spans*. In this case they are the locus of +/// the error, and would be rendered with `^^^`. +/// - they can have a *label*. In this case, the label is written next +/// to the mark in the snippet when we render. #[derive(Clone)] pub struct MultiSpan { - pub spans: Vec + primary_spans: Vec, + span_labels: Vec<(Span, String)>, +} + +#[derive(Clone, Debug)] +pub struct SpanLabel { + /// the span we are going to include in the final snippet + pub span: Span, + + /// is this a primary span? This is the "locus" of the message, + /// and is indicated with a `^^^^` underline, versus `----` + pub is_primary: bool, + + /// what label should we attach to this span (if any)? + pub label: Option, } pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION }; @@ -276,97 +290,76 @@ pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { impl MultiSpan { pub fn new() -> MultiSpan { - MultiSpan { spans: Vec::new() } + MultiSpan { + primary_spans: vec![], + span_labels: vec![] + } } - pub fn to_span_bounds(&self) -> Span { - assert!(!self.spans.is_empty()); - let Span { lo, expn_id, .. } = *self.spans.first().unwrap(); - let Span { hi, .. } = *self.spans.last().unwrap(); - Span { lo: lo, hi: hi, expn_id: expn_id } + pub fn from_span(primary_span: Span) -> MultiSpan { + MultiSpan { + primary_spans: vec![primary_span], + span_labels: vec![] + } } - /// Merges or inserts the given span into itself. - pub fn push_merge(&mut self, mut sp: Span) { - let mut idx_merged = None; - - for idx in 0.. { - let cur = match self.spans.get(idx) { - Some(s) => *s, - None => break, - }; - // Try to merge with a contained Span - if let Some(union) = cur.merge(sp) { - self.spans[idx] = union; - sp = union; - idx_merged = Some(idx); - break; - } - // Or insert into the first sorted position - if sp.hi <= cur.lo { - self.spans.insert(idx, sp); - idx_merged = Some(idx); - break; - } - } - if let Some(idx) = idx_merged { - // Merge with spans trailing the insertion/merging position - while (idx + 1) < self.spans.len() { - if let Some(union) = self.spans[idx + 1].merge(sp) { - self.spans[idx] = union; - self.spans.remove(idx + 1); - } else { - break; - } - } - } else { - self.spans.push(sp); + pub fn from_spans(vec: Vec) -> MultiSpan { + MultiSpan { + primary_spans: vec, + span_labels: vec![] } } - /// Inserts the given span into itself, for use with `end_highlight_lines`. - pub fn push_trim(&mut self, mut sp: Span) { - let mut prev = mk_sp(BytePos(0), BytePos(0)); + pub fn push_primary_span(&mut self, span: Span) { + self.primary_spans.push(span); + } - if let Some(first) = self.spans.get_mut(0) { - if first.lo > sp.lo { - // Prevent us here from spanning fewer lines - // because of trimming the start of the span - // (this should not be visible, because this method ought - // to not be used in conjunction with `highlight_lines`) - first.lo = sp.lo; - } + pub fn push_span_label(&mut self, span: Span, label: String) { + self.span_labels.push((span, label)); + } + + /// Selects the first primary span (if any) + pub fn primary_span(&self) -> Option { + self.primary_spans.first().cloned() + } + + /// Returns all primary spans. + pub fn primary_spans(&self) -> &[Span] { + &self.primary_spans + } + + /// Returns the strings to highlight. If we have an explicit set, + /// return those, otherwise just give back an (unlabeled) version + /// of the primary span. + pub fn span_labels(&self) -> Vec { + let is_primary = |span| self.primary_spans.contains(&span); + let mut span_labels = vec![]; + + for &(span, ref label) in &self.span_labels { + span_labels.push(SpanLabel { + span: span, + is_primary: is_primary(span), + label: Some(label.clone()) + }); } - for idx in 0.. { - if let Some(sp_trim) = sp.trim_start(prev) { - // Implies `sp.hi > prev.hi` - let cur = match self.spans.get(idx) { - Some(s) => *s, - None => { - sp = sp_trim; - break; - } - }; - // `cur` may overlap with `sp_trim` - if let Some(cur_trim) = cur.trim_start(sp_trim) { - // Implies `sp.hi < cur.hi` - self.spans.insert(idx, sp_trim); - self.spans[idx + 1] = cur_trim; - return; - } else if sp.hi == cur.hi { - return; - } - prev = cur; + for &span in &self.primary_spans { + if !span_labels.iter().any(|sl| sl.span == span) { + span_labels.push(SpanLabel { + span: span, + is_primary: true, + label: None + }); } } - self.spans.push(sp); + + span_labels } } impl From for MultiSpan { fn from(span: Span) -> MultiSpan { - MultiSpan { spans: vec![span] } + MultiSpan::from_span(span) } } @@ -929,6 +922,10 @@ impl CodeMap { } pub fn span_to_string(&self, sp: Span) -> String { + if sp == COMMAND_LINE_SP { + return "".to_string(); + } + if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) { return "no-location".to_string(); } @@ -1099,12 +1096,16 @@ impl CodeMap { } pub fn span_to_lines(&self, sp: Span) -> FileLinesResult { + debug!("span_to_lines(sp={:?})", sp); + if sp.lo > sp.hi { return Err(SpanLinesError::IllFormedSpan(sp)); } let lo = self.lookup_char_pos(sp.lo); + debug!("span_to_lines: lo={:?}", lo); let hi = self.lookup_char_pos(sp.hi); + debug!("span_to_lines: hi={:?}", hi); if lo.file.start_pos != hi.file.start_pos { return Err(SpanLinesError::DistinctSources(DistinctSources { @@ -1184,59 +1185,6 @@ impl CodeMap { } } - /// Groups and sorts spans by lines into `MultiSpan`s, where `push` adds them to their group, - /// specifying the unification behaviour for overlapping spans. - /// Spans overflowing a line are put into their own one-element-group. - pub fn custom_group_spans(&self, mut spans: Vec, push: F) -> Vec - where F: Fn(&mut MultiSpan, Span) - { - spans.sort_by(|a, b| a.lo.cmp(&b.lo)); - let mut groups = Vec::::new(); - let mut overflowing = vec![]; - let mut prev_expn = ExpnId(!2u32); - let mut prev_file = !0usize; - let mut prev_line = !0usize; - let mut err_size = 0; - - for sp in spans { - let line = self.lookup_char_pos(sp.lo).line; - let line_hi = self.lookup_char_pos(sp.hi).line; - if line != line_hi { - overflowing.push(sp.into()); - continue - } - let file = self.lookup_filemap_idx(sp.lo); - - if err_size < MAX_HIGHLIGHT_LINES && sp.expn_id == prev_expn && file == prev_file { - // `push` takes care of sorting, trimming, and merging - push(&mut groups.last_mut().unwrap(), sp); - if line != prev_line { - err_size += 1; - } - } else { - groups.push(sp.into()); - err_size = 1; - } - prev_expn = sp.expn_id; - prev_file = file; - prev_line = line; - } - groups.extend(overflowing); - groups - } - - /// Groups and sorts spans by lines into `MultiSpan`s, merging overlapping spans. - /// Spans overflowing a line are put into their own one-element-group. - pub fn group_spans(&self, spans: Vec) -> Vec { - self.custom_group_spans(spans, |msp, sp| msp.push_merge(sp)) - } - - /// Like `group_spans`, but trims overlapping spans instead of - /// merging them (for use with `end_highlight_lines`) - pub fn end_group_spans(&self, spans: Vec) -> Vec { - self.custom_group_spans(spans, |msp, sp| msp.push_trim(sp)) - } - pub fn get_filemap(&self, filename: &str) -> Rc { for fm in self.files.borrow().iter() { if filename == fm.name { diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs new file mode 100644 index 0000000000000..cd8f705ab2e5f --- /dev/null +++ b/src/libsyntax/errors/snippet/mod.rs @@ -0,0 +1,821 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Code for annotating snippets. + +use codemap::{CharPos, CodeMap, FileMap, LineInfo, Span}; +use std::cmp; +use std::rc::Rc; +use std::mem; +use std::ops::Range; + +#[cfg(test)] +mod test; + +pub struct SnippetData { + codemap: Rc, + files: Vec, +} + +pub struct FileInfo { + file: Rc, + + /// The "primary file", if any, gets a `-->` marker instead of + /// `>>>`, and has a line-number/column printed and not just a + /// filename. It appears first in the listing. It is known to + /// contain at least one primary span, though primary spans (which + /// are designated with `^^^`) may also occur in other files. + primary_span: Option, + + lines: Vec, +} + +struct Line { + line_index: usize, + annotations: Vec, +} + +#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)] +struct Annotation { + /// Start column, 0-based indexing -- counting *characters*, not + /// utf-8 bytes. Note that it is important that this field goes + /// first, so that when we sort, we sort orderings by start + /// column. + start_col: usize, + + /// End column within the line. + end_col: usize, + + /// Is this annotation derived from primary span + is_primary: bool, + + /// Optional label to display adjacent to the annotation. + label: Option, +} + +#[derive(Debug)] +pub struct RenderedLine { + pub text: Vec, + pub kind: RenderedLineKind, +} + +#[derive(Debug)] +pub struct StyledString { + pub text: String, + pub style: Style, +} + +#[derive(Debug)] +pub struct StyledBuffer { + text: Vec>, + styles: Vec> +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Style { + FileNameStyle, + LineAndColumn, + LineNumber, + Quotation, + UnderlinePrimary, + UnderlineSecondary, + LabelPrimary, + LabelSecondary, + NoStyle, +} +use self::Style::*; + +#[derive(Debug, Clone)] +pub enum RenderedLineKind { + PrimaryFileName, + OtherFileName, + SourceText { + file: Rc, + line_index: usize, + }, + Annotations, + Elision, +} +use self::RenderedLineKind::*; + +impl SnippetData { + pub fn new(codemap: Rc, + primary_span: Option) // (*) + -> Self { + // (*) The primary span indicates the file that must appear + // first, and which will have a line number etc in its + // name. Outside of tests, this is always `Some`, but for many + // tests it's not relevant to test this portion of the logic, + // and it's tedious to pick a primary span (read: tedious to + // port older tests that predate the existence of a primary + // span). + + debug!("SnippetData::new(primary_span={:?})", primary_span); + + let mut data = SnippetData { + codemap: codemap.clone(), + files: vec![] + }; + if let Some(primary_span) = primary_span { + let lo = codemap.lookup_char_pos(primary_span.lo); + data.files.push( + FileInfo { + file: lo.file, + primary_span: Some(primary_span), + lines: vec![], + }); + } + data + } + + pub fn push(&mut self, span: Span, is_primary: bool, label: Option) { + debug!("SnippetData::push(span={:?}, is_primary={}, label={:?})", + span, is_primary, label); + + let file_lines = match self.codemap.span_to_lines(span) { + Ok(file_lines) => file_lines, + Err(_) => { + // ignore unprintable spans completely. + return; + } + }; + + self.file(&file_lines.file) + .push_lines(&file_lines.lines, is_primary, label); + } + + fn file(&mut self, file_map: &Rc) -> &mut FileInfo { + let index = self.files.iter().position(|f| f.file.name == file_map.name); + if let Some(index) = index { + return &mut self.files[index]; + } + + self.files.push( + FileInfo { + file: file_map.clone(), + lines: vec![], + primary_span: None, + }); + self.files.last_mut().unwrap() + } + + pub fn render_lines(&self) -> Vec { + debug!("SnippetData::render_lines()"); + + let mut rendered_lines: Vec<_> = + self.files.iter() + .flat_map(|f| f.render_file_lines(&self.codemap)) + .collect(); + prepend_prefixes(&mut rendered_lines); + trim_lines(&mut rendered_lines); + rendered_lines + } +} + +pub trait StringSource { + fn make_string(self) -> String; +} + +impl StringSource for String { + fn make_string(self) -> String { + self + } +} + +impl StringSource for Vec { + fn make_string(self) -> String { + self.into_iter().collect() + } +} + +impl From<(S, Style, RenderedLineKind)> for RenderedLine + where S: StringSource +{ + fn from((text, style, kind): (S, Style, RenderedLineKind)) -> Self { + RenderedLine { + text: vec![StyledString { + text: text.make_string(), + style: style, + }], + kind: kind, + } + } +} + +impl From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine + where S1: StringSource, S2: StringSource +{ + fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) + -> Self { + let (text1, style1, text2, style2, kind) = tuple; + RenderedLine { + text: vec![ + StyledString { + text: text1.make_string(), + style: style1, + }, + StyledString { + text: text2.make_string(), + style: style2, + } + ], + kind: kind, + } + } +} + +impl RenderedLine { + fn trim_last(&mut self) { + if !self.text.is_empty() { + let last_text = &mut self.text.last_mut().unwrap().text; + let len = last_text.trim_right().len(); + last_text.truncate(len); + } + } +} + +impl RenderedLineKind { + fn prefix(&self) -> StyledString { + match *self { + SourceText { file: _, line_index } => + StyledString { + text: format!("{}", line_index + 1), + style: LineNumber, + }, + Elision => + StyledString { + text: String::from("..."), + style: LineNumber, + }, + PrimaryFileName | + OtherFileName | + Annotations => + StyledString { + text: String::from(""), + style: LineNumber, + }, + } + } +} + +impl StyledBuffer { + fn new() -> StyledBuffer { + StyledBuffer { text: vec![], styles: vec![] } + } + + fn render(&self, source_kind: RenderedLineKind) -> Vec { + let mut output: Vec = vec![]; + let mut styled_vec: Vec = vec![]; + + for (row, row_style) in self.text.iter().zip(&self.styles) { + let mut current_style = NoStyle; + let mut current_text = String::new(); + + for (&c, &s) in row.iter().zip(row_style) { + if s != current_style { + if !current_text.is_empty() { + styled_vec.push(StyledString { text: current_text, style: current_style }); + } + current_style = s; + current_text = String::new(); + } + current_text.push(c); + } + if !current_text.is_empty() { + styled_vec.push(StyledString { text: current_text, style: current_style }); + } + + if output.is_empty() { + //We know our first output line is source and the rest are highlights and labels + output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() }); + } else { + output.push(RenderedLine { text: styled_vec, kind: Annotations }); + } + styled_vec = vec![]; + } + + output + } + + fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) { + while line >= self.text.len() { + self.text.push(vec![]); + self.styles.push(vec![]); + } + + if col < self.text[line].len() { + self.text[line][col] = chr; + self.styles[line][col] = style; + } else { + while self.text[line].len() < col { + self.text[line].push(' '); + self.styles[line].push(NoStyle); + } + self.text[line].push(chr); + self.styles[line].push(style); + } + } + + fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) { + let mut n = col; + for c in string.chars() { + self.putc(line, n, c, style); + n += 1; + } + } + + fn set_style(&mut self, line: usize, col: usize, style: Style) { + if self.styles.len() > line && self.styles[line].len() > col { + self.styles[line][col] = style; + } + } + + fn append(&mut self, line: usize, string: &str, style: Style) { + if line >= self.text.len() { + self.puts(line, 0, string, style); + } else { + let col = self.text[line].len(); + self.puts(line, col, string, style); + } + } +} + +impl FileInfo { + fn push_lines(&mut self, + lines: &[LineInfo], + is_primary: bool, + label: Option) { + assert!(lines.len() > 0); + + // If a span covers multiple lines, just put the label on the + // first one. This is a sort of arbitrary choice and not + // obviously correct. + let (line0, remaining_lines) = lines.split_first().unwrap(); + let index = self.ensure_source_line(line0.line_index); + self.lines[index].push_annotation(line0.start_col, + line0.end_col, + is_primary, + label); + for line in remaining_lines { + if line.end_col > line.start_col { + let index = self.ensure_source_line(line.line_index); + self.lines[index].push_annotation(line.start_col, + line.end_col, + is_primary, + None); + } + } + } + + /// Ensure that we have a `Line` struct corresponding to + /// `line_index` in the file. If we already have some other lines, + /// then this will add the intervening lines to ensure that we + /// have a complete snippet. (Note that when we finally display, + /// some of those lines may be elided.) + fn ensure_source_line(&mut self, line_index: usize) -> usize { + if self.lines.is_empty() { + self.lines.push(Line::new(line_index)); + return 0; + } + + // Find the range of lines we have thus far. + let first_line_index = self.lines.first().unwrap().line_index; + let last_line_index = self.lines.last().unwrap().line_index; + assert!(first_line_index <= last_line_index); + + // If the new line is lower than all the lines we have thus + // far, then insert the new line and any intervening lines at + // the front. In a silly attempt at micro-optimization, we + // don't just call `insert` repeatedly, but instead make a new + // (empty) vector, pushing the new lines onto it, and then + // appending the old vector. + if line_index < first_line_index { + let lines = mem::replace(&mut self.lines, vec![]); + self.lines.extend( + (line_index .. first_line_index) + .map(|line| Line::new(line)) + .chain(lines)); + return 0; + } + + // If the new line comes after the ones we have so far, insert + // lines for it. + if line_index > last_line_index { + self.lines.extend( + (last_line_index+1 .. line_index+1) + .map(|line| Line::new(line))); + return self.lines.len() - 1; + } + + // Otherwise it should already exist. + return line_index - first_line_index; + } + + fn render_file_lines(&self, codemap: &Rc) -> Vec { + // Group our lines by those with annotations and those without + let mut lines_iter = self.lines.iter().peekable(); + + let mut line_groups = vec![]; + + loop { + match lines_iter.next() { + None => break, + Some(line) if line.annotations.is_empty() => { + // Collect unannotated group + let mut unannotated_group : Vec<&Line> = vec![]; + + unannotated_group.push(line); + + loop { + let next_line = + match lines_iter.peek() { + None => break, + Some(x) if !x.annotations.is_empty() => break, + Some(x) => x.clone() + }; + + unannotated_group.push(next_line); + lines_iter.next(); + } + + line_groups.push((false, unannotated_group)); + } + Some(line) => { + // Collect annotated group + let mut annotated_group : Vec<&Line> = vec![]; + + annotated_group.push(line); + + loop { + let next_line = + match lines_iter.peek() { + None => break, + Some(x) if x.annotations.is_empty() => break, + Some(x) => x.clone() + }; + + annotated_group.push(next_line); + lines_iter.next(); + } + + line_groups.push((true, annotated_group)); + } + } + } + + let mut output = vec![]; + + // First insert the name of the file. + match self.primary_span { + Some(span) => { + let lo = codemap.lookup_char_pos(span.lo); + output.push(RenderedLine { + text: vec![StyledString { + text: lo.file.name.clone(), + style: FileNameStyle, + }, StyledString { + text: format!(":{}:{}", lo.line, lo.col.0 + 1), + style: LineAndColumn, + }], + kind: PrimaryFileName, + }); + } + None => { + output.push(RenderedLine { + text: vec![StyledString { + text: self.file.name.clone(), + style: FileNameStyle, + }], + kind: OtherFileName, + }); + } + } + + for &(is_annotated, ref group) in line_groups.iter() { + if is_annotated { + let mut annotation_ends_at_eol = false; + let mut prev_ends_at_eol = false; + let mut elide_unlabeled_region = false; + + for group_line in group.iter() { + let source_string_len = + self.file.get_line(group_line.line_index) + .map(|s| s.len()) + .unwrap_or(0); + + for annotation in &group_line.annotations { + if annotation.end_col == source_string_len { + annotation_ends_at_eol = true; + } + } + + let is_single_unlabeled_annotated_line = + if group_line.annotations.len() == 1 { + if let Some(annotation) = group_line.annotations.first() { + match annotation.label { + Some(_) => false, + None => annotation.start_col == 0 && + annotation.end_col == source_string_len + } + } else { + false + } + } else { + false + }; + + if prev_ends_at_eol && is_single_unlabeled_annotated_line { + if !elide_unlabeled_region { + output.push(RenderedLine::from((String::new(), + NoStyle, Elision))); + elide_unlabeled_region = true; + prev_ends_at_eol = true; + } + continue; + } + + let mut v = self.render_line(group_line); + output.append(&mut v); + + prev_ends_at_eol = annotation_ends_at_eol; + } + } else { + if group.len() > 1 { + output.push(RenderedLine::from((String::new(), NoStyle, Elision))); + } else { + let mut v: Vec = + group.iter().flat_map(|line| self.render_line(line)).collect(); + output.append(&mut v); + } + } + } + + output + } + + fn render_line(&self, line: &Line) -> Vec { + let source_string = self.file.get_line(line.line_index) + .unwrap_or(""); + let source_kind = SourceText { + file: self.file.clone(), + line_index: line.line_index, + }; + + let mut styled_buffer = StyledBuffer::new(); + + // First create the source line we will highlight. + styled_buffer.append(0, &source_string, Quotation); + + if line.annotations.is_empty() { + return styled_buffer.render(source_kind); + } + + // We want to display like this: + // + // vec.push(vec.pop().unwrap()); + // --- ^^^ _ previous borrow ends here + // | | + // | error occurs here + // previous borrow of `vec` occurs here + // + // But there are some weird edge cases to be aware of: + // + // vec.push(vec.pop().unwrap()); + // -------- - previous borrow ends here + // || + // |this makes no sense + // previous borrow of `vec` occurs here + // + // For this reason, we group the lines into "highlight lines" + // and "annotations lines", where the highlight lines have the `~`. + + //let mut highlight_line = Self::whitespace(&source_string); + + // Sort the annotations by (start, end col) + let mut annotations = line.annotations.clone(); + annotations.sort(); + + // Next, create the highlight line. + for annotation in &annotations { + for p in annotation.start_col .. annotation.end_col { + if annotation.is_primary { + styled_buffer.putc(1, p, '^', UnderlinePrimary); + styled_buffer.set_style(0, p, UnderlinePrimary); + } else { + styled_buffer.putc(1, p, '-', UnderlineSecondary); + } + } + } + + // Now we are going to write labels in. To start, we'll exclude + // the annotations with no labels. + let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) = + annotations.into_iter() + .partition(|a| a.label.is_some()); + + // If there are no annotations that need text, we're done. + if labeled_annotations.is_empty() { + return styled_buffer.render(source_kind); + } + + // Now add the text labels. We try, when possible, to stick the rightmost + // annotation at the end of the highlight line: + // + // vec.push(vec.pop().unwrap()); + // --- --- - previous borrow ends here + // + // But sometimes that's not possible because one of the other + // annotations overlaps it. For example, from the test + // `span_overlap_label`, we have the following annotations + // (written on distinct lines for clarity): + // + // fn foo(x: u32) { + // -------------- + // - + // + // In this case, we can't stick the rightmost-most label on + // the highlight line, or we would get: + // + // fn foo(x: u32) { + // -------- x_span + // | + // fn_span + // + // which is totally weird. Instead we want: + // + // fn foo(x: u32) { + // -------------- + // | | + // | x_span + // fn_span + // + // which is...less weird, at least. In fact, in general, if + // the rightmost span overlaps with any other span, we should + // use the "hang below" version, so we can at least make it + // clear where the span *starts*. + let mut labeled_annotations = &labeled_annotations[..]; + match labeled_annotations.split_last().unwrap() { + (last, previous) => { + if previous.iter() + .chain(&unlabeled_annotations) + .all(|a| !overlaps(a, last)) + { + // append the label afterwards; we keep it in a separate + // string + let highlight_label: String = format!(" {}", last.label.as_ref().unwrap()); + if last.is_primary { + styled_buffer.append(1, &highlight_label, LabelPrimary); + } else { + styled_buffer.append(1, &highlight_label, LabelSecondary); + } + labeled_annotations = previous; + } + } + } + + // If that's the last annotation, we're done + if labeled_annotations.is_empty() { + return styled_buffer.render(source_kind); + } + + for (index, annotation) in labeled_annotations.iter().enumerate() { + // Leave: + // - 1 extra line + // - One line for each thing that comes after + let comes_after = labeled_annotations.len() - index - 1; + let blank_lines = 3 + comes_after; + + // For each blank line, draw a `|` at our column. The + // text ought to be long enough for this. + for index in 2..blank_lines { + if annotation.is_primary { + styled_buffer.putc(index, annotation.start_col, '|', UnderlinePrimary); + } else { + styled_buffer.putc(index, annotation.start_col, '|', UnderlineSecondary); + } + } + + if annotation.is_primary { + styled_buffer.puts(blank_lines, annotation.start_col, + annotation.label.as_ref().unwrap(), LabelPrimary); + } else { + styled_buffer.puts(blank_lines, annotation.start_col, + annotation.label.as_ref().unwrap(), LabelSecondary); + } + } + + styled_buffer.render(source_kind) + } +} + +fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { + let prefixes: Vec<_> = + rendered_lines.iter() + .map(|rl| rl.kind.prefix()) + .collect(); + + // find the max amount of spacing we need; add 1 to + // p.text.len() to leave space between the prefix and the + // source text + let padding_len = + prefixes.iter() + .map(|p| if p.text.len() == 0 { 0 } else { p.text.len() + 1 }) + .max() + .unwrap_or(0); + + // Ensure we insert at least one character of padding, so that the + // `-->` arrows can fit etc. + let padding_len = cmp::max(padding_len, 1); + + for (mut prefix, line) in prefixes.into_iter().zip(rendered_lines) { + let extra_spaces = (prefix.text.len() .. padding_len).map(|_| ' '); + prefix.text.extend(extra_spaces); + match line.kind { + RenderedLineKind::Elision => { + line.text.insert(0, prefix); + } + RenderedLineKind::PrimaryFileName => { + // --> filename + // 22 |> + // ^ + // padding_len + let dashes = (0..padding_len - 1).map(|_| ' ') + .chain(Some('-')) + .chain(Some('-')) + .chain(Some('>')) + .chain(Some(' ')); + line.text.insert(0, StyledString {text: dashes.collect(), + style: LineNumber}) + } + RenderedLineKind::OtherFileName => { + // >>>>> filename + // 22 |> + // ^ + // padding_len + let dashes = (0..padding_len + 2).map(|_| '>') + .chain(Some(' ')); + line.text.insert(0, StyledString {text: dashes.collect(), + style: LineNumber}) + } + _ => { + line.text.insert(0, prefix); + line.text.insert(1, StyledString {text: String::from("|> "), + style: LineNumber}) + } + } + } +} + +fn trim_lines(rendered_lines: &mut [RenderedLine]) { + for line in rendered_lines { + while !line.text.is_empty() { + line.trim_last(); + if line.text.last().unwrap().text.is_empty() { + line.text.pop(); + } else { + break; + } + } + } +} + +impl Line { + fn new(line_index: usize) -> Line { + Line { + line_index: line_index, + annotations: vec![] + } + } + + fn push_annotation(&mut self, + start: CharPos, + end: CharPos, + is_primary: bool, + label: Option) { + self.annotations.push(Annotation { + start_col: start.0, + end_col: end.0, + is_primary: is_primary, + label: label, + }); + } +} + +fn overlaps(a1: &Annotation, + a2: &Annotation) + -> bool +{ + between(a1.start_col, a2.start_col .. a2.end_col) || + between(a2.start_col, a1.start_col .. a1.end_col) +} + +fn between(v: usize, range: Range) -> bool { + v >= range.start && v < range.end +} diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs new file mode 100644 index 0000000000000..44ece285b1b23 --- /dev/null +++ b/src/libsyntax/errors/snippet/test.rs @@ -0,0 +1,524 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Code for testing annotated snippets. + +use codemap::{BytePos, CodeMap, FileMap, NO_EXPANSION, Span}; +use std::rc::Rc; +use super::{RenderedLine, SnippetData}; + +/// Returns the span corresponding to the `n`th occurrence of +/// `substring` in `source_text`. +trait CodeMapExtension { + fn span_substr(&self, + file: &Rc, + source_text: &str, + substring: &str, + n: usize) + -> Span; +} + +impl CodeMapExtension for CodeMap { + fn span_substr(&self, + file: &Rc, + source_text: &str, + substring: &str, + n: usize) + -> Span + { + println!("span_substr(file={:?}/{:?}, substring={:?}, n={})", + file.name, file.start_pos, substring, n); + let mut i = 0; + let mut hi = 0; + loop { + let offset = source_text[hi..].find(substring).unwrap_or_else(|| { + panic!("source_text `{}` does not have {} occurrences of `{}`, only {}", + source_text, n, substring, i); + }); + let lo = hi + offset; + hi = lo + substring.len(); + if i == n { + let span = Span { + lo: BytePos(lo as u32 + file.start_pos.0), + hi: BytePos(hi as u32 + file.start_pos.0), + expn_id: NO_EXPANSION, + }; + assert_eq!(&self.span_to_snippet(span).unwrap()[..], + substring); + return span; + } + i += 1; + } + } +} + +fn splice(start: Span, end: Span) -> Span { + Span { + lo: start.lo, + hi: end.hi, + expn_id: NO_EXPANSION, + } +} + +fn make_string(lines: &[RenderedLine]) -> String { + lines.iter() + .flat_map(|rl| { + rl.text.iter() + .map(|s| &s.text[..]) + .chain(Some("\n")) + }) + .collect() +} + +#[test] +fn one_line() { + let file_text = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); + let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); + let span_semi = cm.span_substr(&foo, file_text, ";", 0); + + let mut snippet = SnippetData::new(cm, None); + snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here"))); + snippet.push(span_vec1, false, Some(format!("error occurs here"))); + snippet.push(span_semi, false, Some(format!("previous borrow ends here"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + + let text: String = make_string(&lines); + + println!("text=\n{}", text); + assert_eq!(&text[..], &r#" +>>>> foo.rs +3 |> vec.push(vec.pop().unwrap()); + |> --- --- - previous borrow ends here + |> | | + |> | error occurs here + |> previous borrow of `vec` occurs here +"#[1..]); +} + +#[test] +fn two_files() { + let file_text_foo = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let file_text_bar = r#" +fn bar() { + // these blank links here + // serve to ensure that the line numbers + // from bar.rs + // require more digits + + + + + + + + + + + vec.push(); + + // this line will get elided + + vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo_map = cm.new_filemap_and_lines("foo.rs", file_text_foo); + let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0); + let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1); + let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0); + + let bar_map = cm.new_filemap_and_lines("bar.rs", file_text_bar); + let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0); + let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1); + let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0); + + let mut snippet = SnippetData::new(cm, Some(span_foo_vec1)); + snippet.push(span_foo_vec0, false, Some(format!("a"))); + snippet.push(span_foo_vec1, true, Some(format!("b"))); + snippet.push(span_foo_semi, false, Some(format!("c"))); + snippet.push(span_bar_vec0, false, Some(format!("d"))); + snippet.push(span_bar_vec1, false, Some(format!("e"))); + snippet.push(span_bar_semi, false, Some(format!("f"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + + let text: String = make_string(&lines); + + println!("text=\n{}", text); + + // Note that the `|>` remain aligned across both files: + assert_eq!(&text[..], &r#" + --> foo.rs:3:14 +3 |> vec.push(vec.pop().unwrap()); + |> --- ^^^ - c + |> | | + |> | b + |> a +>>>>>> bar.rs +17 |> vec.push(); + |> --- - f + |> | + |> d +... +21 |> vec.pop().unwrap()); + |> --- e +"#[1..]); +} + +#[test] +fn multi_line() { + let file_text = r#" +fn foo() { + let name = find_id(&data, 22).unwrap(); + + // Add one more item we forgot to the vector. Silly us. + data.push(Data { name: format!("Hera"), id: 66 }); + + // Print everything out. + println!("Name: {:?}", name); + println!("Data: {:?}", data); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span_data0 = cm.span_substr(&foo, file_text, "data", 0); + let span_data1 = cm.span_substr(&foo, file_text, "data", 1); + let span_rbrace = cm.span_substr(&foo, file_text, "}", 3); + + let mut snippet = SnippetData::new(cm, None); + snippet.push(span_data0, false, Some(format!("immutable borrow begins here"))); + snippet.push(span_data1, false, Some(format!("mutable borrow occurs here"))); + snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + + let text: String = make_string(&lines); + + println!("text=\n{}", text); + assert_eq!(&text[..], &r#" +>>>>>> foo.rs +3 |> let name = find_id(&data, 22).unwrap(); + |> ---- immutable borrow begins here +... +6 |> data.push(Data { name: format!("Hera"), id: 66 }); + |> ---- mutable borrow occurs here +... +11 |> } + |> - immutable borrow ends here +"#[1..]); +} + +#[test] +fn overlapping() { + let file_text = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span0 = cm.span_substr(&foo, file_text, "vec.push", 0); + let span1 = cm.span_substr(&foo, file_text, "vec", 0); + let span2 = cm.span_substr(&foo, file_text, "ec.push", 0); + let span3 = cm.span_substr(&foo, file_text, "unwrap", 0); + + let mut snippet = SnippetData::new(cm, None); + snippet.push(span0, false, Some(format!("A"))); + snippet.push(span1, false, Some(format!("B"))); + snippet.push(span2, false, Some(format!("C"))); + snippet.push(span3, false, Some(format!("D"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + let text: String = make_string(&lines); + + println!("text=r#\"\n{}\".trim_left()", text); + assert_eq!(&text[..], &r#" +>>>> foo.rs +3 |> vec.push(vec.pop().unwrap()); + |> -------- ------ D + |> || + |> |C + |> A + |> B +"#[1..]); +} + +#[test] +fn one_line_out_of_order() { + let file_text = r#" +fn foo() { + vec.push(vec.pop().unwrap()); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0); + let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1); + let span_semi = cm.span_substr(&foo, file_text, ";", 0); + + // intentionally don't push the snippets left to right + let mut snippet = SnippetData::new(cm, None); + snippet.push(span_vec1, false, Some(format!("error occurs here"))); + snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here"))); + snippet.push(span_semi, false, Some(format!("previous borrow ends here"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + let text: String = make_string(&lines); + + println!("text=r#\"\n{}\".trim_left()", text); + assert_eq!(&text[..], &r#" +>>>> foo.rs +3 |> vec.push(vec.pop().unwrap()); + |> --- --- - previous borrow ends here + |> | | + |> | error occurs here + |> previous borrow of `vec` occurs here +"#[1..]); +} + +#[test] +fn elide_unnecessary_lines() { + let file_text = r#" +fn foo() { + let mut vec = vec![0, 1, 2]; + let mut vec2 = vec; + vec2.push(3); + vec2.push(4); + vec2.push(5); + vec2.push(6); + vec.push(7); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3); + let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8); + + let mut snippet = SnippetData::new(cm, None); + snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \ + has type `collections::vec::Vec`"))); + snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`"))); + + let lines = snippet.render_lines(); + println!("{:#?}", lines); + let text: String = make_string(&lines); + println!("text=r#\"\n{}\".trim_left()", text); + assert_eq!(&text[..], &r#" +>>>>>> foo.rs +4 |> let mut vec2 = vec; + |> --- `vec` moved here because it has type `collections::vec::Vec` +... +9 |> vec.push(7); + |> --- use of moved value: `vec` +"#[1..]); +} + +#[test] +fn spans_without_labels() { + let file_text = r#" +fn foo() { + let mut vec = vec![0, 1, 2]; + let mut vec2 = vec; + vec2.push(3); + vec2.push(4); + vec2.push(5); + vec2.push(6); + vec.push(7); +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + for i in 0..4 { + let span_veci = cm.span_substr(&foo, file_text, "vec", i); + snippet.push(span_veci, false, None); + } + + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("text=&r#\"\n{}\n\"#[1..]", text); + assert_eq!(text, &r#" +>>>> foo.rs +3 |> let mut vec = vec![0, 1, 2]; + |> --- --- +4 |> let mut vec2 = vec; + |> --- --- +"#[1..]); +} + +#[test] +fn span_long_selection() { + let file_text = r#" +impl SomeTrait for () { + fn foo(x: u32) { + // impl 1 + // impl 2 + // impl 3 + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + let fn_span = cm.span_substr(&foo, file_text, "fn", 0); + let rbrace_span = cm.span_substr(&foo, file_text, "}", 0); + snippet.push(splice(fn_span, rbrace_span), false, None); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" +>>>>>> foo.rs +3 |> fn foo(x: u32) { + |> ---------------- +... +"#[1..]); +} + +#[test] +fn span_overlap_label() { + // Test that we don't put `x_span` to the right of its highlight, + // since there is another highlight that overlaps it. + + let file_text = r#" + fn foo(x: u32) { + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0); + let x_span = cm.span_substr(&foo, file_text, "x", 0); + snippet.push(fn_span, false, Some(format!("fn_span"))); + snippet.push(x_span, false, Some(format!("x_span"))); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" +>>>> foo.rs +2 |> fn foo(x: u32) { + |> -------------- + |> | | + |> | x_span + |> fn_span +"#[1..]); +} + +#[test] +fn span_overlap_label2() { + // Test that we don't put `x_span` to the right of its highlight, + // since there is another highlight that overlaps it. In this + // case, the overlap is only at the beginning, but it's still + // better to show the beginning more clearly. + + let file_text = r#" + fn foo(x: u32) { + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0); + let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0); + snippet.push(fn_span, false, Some(format!("fn_span"))); + snippet.push(x_span, false, Some(format!("x_span"))); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" +>>>> foo.rs +2 |> fn foo(x: u32) { + |> -------------- + |> | | + |> | x_span + |> fn_span +"#[1..]); +} + +#[test] +fn span_overlap_label3() { + // Test that we don't put `x_span` to the right of its highlight, + // since there is another highlight that overlaps it. In this + // case, the overlap is only at the beginning, but it's still + // better to show the beginning more clearly. + + let file_text = r#" + fn foo() { + let closure = || { + inner + }; + } +} +"#; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut snippet = SnippetData::new(cm.clone(), None); + + let closure_span = { + let closure_start_span = cm.span_substr(&foo, file_text, "||", 0); + let closure_end_span = cm.span_substr(&foo, file_text, "}", 0); + splice(closure_start_span, closure_end_span) + }; + + let inner_span = cm.span_substr(&foo, file_text, "inner", 0); + + snippet.push(closure_span, false, Some(format!("foo"))); + snippet.push(inner_span, false, Some(format!("bar"))); + + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" +>>>> foo.rs +3 |> let closure = || { + |> ---- foo +4 |> inner + |> ---------------- + |> | + |> bar +5 |> }; + |> -------- +"#[1..]); +} From e7c7a18d94cf672d6a031455d091e0bebe1a6b7c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:57:20 -0400 Subject: [PATCH 50/97] adapt JSON to new model Each Span now carries a `is_primary` boolean along with an optional label. If there are multiple labels for a span, it will appear multiple times. --- src/libsyntax/errors/json.rs | 202 ++++++++++++------------------ src/tools/compiletest/src/json.rs | 47 +++++-- 2 files changed, 119 insertions(+), 130 deletions(-) diff --git a/src/libsyntax/errors/json.rs b/src/libsyntax/errors/json.rs index 821617bfe89df..b343c3f3fbbc5 100644 --- a/src/libsyntax/errors/json.rs +++ b/src/libsyntax/errors/json.rs @@ -20,7 +20,7 @@ // FIXME spec the JSON output properly. -use codemap::{self, Span, MacroBacktrace, MultiSpan, CodeMap}; +use codemap::{self, MacroBacktrace, Span, SpanLabel, MultiSpan, CodeMap}; use diagnostics::registry::Registry; use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion}; use errors::emitter::Emitter; @@ -53,20 +53,13 @@ impl JsonEmitter { } impl Emitter for JsonEmitter { - fn emit(&mut self, span: Option<&MultiSpan>, msg: &str, code: Option<&str>, level: Level) { + fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, level: Level) { let data = Diagnostic::new(span, msg, code, level, self); if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) { panic!("failed to print diagnostics: {:?}", e); } } - fn custom_emit(&mut self, sp: &RenderSpan, msg: &str, level: Level) { - let data = Diagnostic::from_render_span(sp, msg, level, self); - if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) { - panic!("failed to print diagnostics: {:?}", e); - } - } - fn emit_struct(&mut self, db: &DiagnosticBuilder) { let data = Diagnostic::from_diagnostic_builder(db, self); if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) { @@ -104,8 +97,13 @@ struct DiagnosticSpan { /// 1-based, character offset. column_start: usize, column_end: usize, + /// Is this a "primary" span -- meaning the point, or one of the points, + /// where the error occurred? + is_primary: bool, /// Source text from the start of line_start to the end of line_end. text: Vec, + /// Label that should be placed at this location (if any) + label: Option, /// If we are suggesting a replacement, this will contain text /// that should be sliced in atop this span. You may prefer to /// load the fully rendered version from the parent `Diagnostic`, @@ -148,7 +146,7 @@ struct DiagnosticCode { } impl<'a> Diagnostic<'a> { - fn new(msp: Option<&MultiSpan>, + fn new(msp: &MultiSpan, msg: &'a str, code: Option<&str>, level: Level, @@ -158,27 +156,12 @@ impl<'a> Diagnostic<'a> { message: msg, code: DiagnosticCode::map_opt_string(code.map(|c| c.to_owned()), je), level: level.to_str(), - spans: msp.map_or(vec![], |msp| DiagnosticSpan::from_multispan(msp, je)), + spans: DiagnosticSpan::from_multispan(msp, je), children: vec![], rendered: None, } } - fn from_render_span(span: &RenderSpan, - msg: &'a str, - level: Level, - je: &JsonEmitter) - -> Diagnostic<'a> { - Diagnostic { - message: msg, - code: None, - level: level.to_str(), - spans: DiagnosticSpan::from_render_span(span, je), - children: vec![], - rendered: je.render(span), - } - } - fn from_diagnostic_builder<'c>(db: &'c DiagnosticBuilder, je: &JsonEmitter) -> Diagnostic<'c> { @@ -186,7 +169,7 @@ impl<'a> Diagnostic<'a> { message: &db.message, code: DiagnosticCode::map_opt_string(db.code.clone(), je), level: db.level.to_str(), - spans: db.span.as_ref().map_or(vec![], |sp| DiagnosticSpan::from_multispan(sp, je)), + spans: DiagnosticSpan::from_multispan(&db.span, je), children: db.children.iter().map(|c| { Diagnostic::from_sub_diagnostic(c, je) }).collect(), @@ -201,8 +184,7 @@ impl<'a> Diagnostic<'a> { level: db.level.to_str(), spans: db.render_span.as_ref() .map(|sp| DiagnosticSpan::from_render_span(sp, je)) - .or_else(|| db.span.as_ref().map(|s| DiagnosticSpan::from_multispan(s, je))) - .unwrap_or(vec![]), + .unwrap_or_else(|| DiagnosticSpan::from_multispan(&db.span, je)), children: vec![], rendered: db.render_span.as_ref() .and_then(|rsp| je.render(rsp)), @@ -211,44 +193,68 @@ impl<'a> Diagnostic<'a> { } impl DiagnosticSpan { - fn from_span(span: Span, suggestion: Option<&String>, je: &JsonEmitter) - -> DiagnosticSpan { + fn from_span_label(span: SpanLabel, + suggestion: Option<&String>, + je: &JsonEmitter) + -> DiagnosticSpan { + Self::from_span_etc(span.span, + span.is_primary, + span.label, + suggestion, + je) + } + + fn from_span_etc(span: Span, + is_primary: bool, + label: Option, + suggestion: Option<&String>, + je: &JsonEmitter) + -> DiagnosticSpan { // obtain the full backtrace from the `macro_backtrace` // helper; in some ways, it'd be better to expand the // backtrace ourselves, but the `macro_backtrace` helper makes // some decision, such as dropping some frames, and I don't // want to duplicate that logic here. let backtrace = je.cm.macro_backtrace(span).into_iter(); - DiagnosticSpan::from_span_and_backtrace(span, suggestion, backtrace, je) + DiagnosticSpan::from_span_full(span, + is_primary, + label, + suggestion, + backtrace, + je) } - fn from_span_and_backtrace(span: Span, - suggestion: Option<&String>, - mut backtrace: vec::IntoIter, - je: &JsonEmitter) - -> DiagnosticSpan { + fn from_span_full(span: Span, + is_primary: bool, + label: Option, + suggestion: Option<&String>, + mut backtrace: vec::IntoIter, + je: &JsonEmitter) + -> DiagnosticSpan { let start = je.cm.lookup_char_pos(span.lo); let end = je.cm.lookup_char_pos(span.hi); - let backtrace_step = - backtrace.next() - .map(|bt| { - let call_site = - Self::from_span_and_backtrace(bt.call_site, - None, - backtrace, - je); - let def_site_span = bt.def_site_span.map(|sp| { - Self::from_span_and_backtrace(sp, - None, - vec![].into_iter(), - je) - }); - Box::new(DiagnosticSpanMacroExpansion { - span: call_site, - macro_decl_name: bt.macro_decl_name, - def_site_span: def_site_span, - }) - }); + let backtrace_step = backtrace.next().map(|bt| { + let call_site = + Self::from_span_full(bt.call_site, + false, + None, + None, + backtrace, + je); + let def_site_span = bt.def_site_span.map(|sp| { + Self::from_span_full(sp, + false, + None, + None, + vec![].into_iter(), + je) + }); + Box::new(DiagnosticSpanMacroExpansion { + span: call_site, + macro_decl_name: bt.macro_decl_name, + def_site_span: def_site_span, + }) + }); DiagnosticSpan { file_name: start.file.name.clone(), byte_start: span.lo.0, @@ -257,53 +263,42 @@ impl DiagnosticSpan { line_end: end.line, column_start: start.col.0 + 1, column_end: end.col.0 + 1, + is_primary: is_primary, text: DiagnosticSpanLine::from_span(span, je), suggested_replacement: suggestion.cloned(), expansion: backtrace_step, + label: label, } } fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec { - msp.spans.iter().map(|&span| Self::from_span(span, None, je)).collect() + msp.span_labels() + .into_iter() + .map(|span_str| Self::from_span_label(span_str, None, je)) + .collect() } fn from_suggestion(suggestion: &CodeSuggestion, je: &JsonEmitter) -> Vec { - assert_eq!(suggestion.msp.spans.len(), suggestion.substitutes.len()); - suggestion.msp.spans.iter() - .zip(&suggestion.substitutes) - .map(|(&span, suggestion)| { - DiagnosticSpan::from_span(span, Some(suggestion), je) - }) - .collect() + assert_eq!(suggestion.msp.span_labels().len(), suggestion.substitutes.len()); + suggestion.msp.span_labels() + .into_iter() + .zip(&suggestion.substitutes) + .map(|(span_label, suggestion)| { + DiagnosticSpan::from_span_label(span_label, + Some(suggestion), + je) + }) + .collect() } fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec { match *rsp { RenderSpan::FileLine(ref msp) | - RenderSpan::FullSpan(ref msp) => { - DiagnosticSpan::from_multispan(msp, je) - } - RenderSpan::Suggestion(ref suggestion) => { - DiagnosticSpan::from_suggestion(suggestion, je) - } - RenderSpan::EndSpan(ref msp) => { - msp.spans.iter().map(|&span| { - let end = je.cm.lookup_char_pos(span.hi); - DiagnosticSpan { - file_name: end.file.name.clone(), - byte_start: span.hi.0, - byte_end: span.hi.0, - line_start: end.line, - line_end: end.line, - column_start: end.col.0 + 1, - column_end: end.col.0 + 1, - text: DiagnosticSpanLine::from_span_end(span, je), - suggested_replacement: None, - expansion: None, - } - }).collect() - } + RenderSpan::FullSpan(ref msp) => + DiagnosticSpan::from_multispan(msp, je), + RenderSpan::Suggestion(ref suggestion) => + DiagnosticSpan::from_suggestion(suggestion, je), } } } @@ -340,34 +335,6 @@ impl DiagnosticSpanLine { }) .unwrap_or(vec![]) } - - /// Create a list of DiagnosticSpanLines from span - the result covers all - /// of `span`, but the highlight is zero-length and at the end of `span`. - fn from_span_end(span: Span, je: &JsonEmitter) -> Vec { - je.cm.span_to_lines(span) - .map(|lines| { - let fm = &*lines.file; - lines.lines.iter() - .enumerate() - .map(|(i, line)| { - // Invariant - CodeMap::span_to_lines - // will not return extra context lines - // - the last line returned is the last - // line of `span`. - let highlight = if i == lines.lines.len() - 1 { - (line.end_col.0 + 1, line.end_col.0 + 1) - } else { - (0, 0) - }; - DiagnosticSpanLine::line_from_filemap(fm, - line.line_index, - highlight.0, - highlight.1) - }) - .collect() - }) - .unwrap_or(vec![]) - } } impl DiagnosticCode { @@ -396,9 +363,6 @@ impl JsonEmitter { RenderSpan::Suggestion(ref suggestion) => { Some(suggestion.splice_lines(&self.cm)) } - RenderSpan::EndSpan(_) => { - None - } } } } diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 073b5e57cc7c5..3501b335205ed 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -33,6 +33,8 @@ struct DiagnosticSpan { line_end: usize, column_start: usize, column_end: usize, + is_primary: bool, + label: Option, expansion: Option>, } @@ -66,7 +68,7 @@ fn parse_line(file_name: &str, line: &str) -> Vec { match json::decode::(line) { Ok(diagnostic) => { let mut expected_errors = vec![]; - push_expected_errors(&mut expected_errors, &diagnostic, file_name); + push_expected_errors(&mut expected_errors, &diagnostic, &[], file_name); expected_errors } Err(error) => { @@ -80,12 +82,24 @@ fn parse_line(file_name: &str, line: &str) -> Vec { fn push_expected_errors(expected_errors: &mut Vec, diagnostic: &Diagnostic, + default_spans: &[&DiagnosticSpan], file_name: &str) { - // We only consider messages pertaining to the current file. - let matching_spans = || { - diagnostic.spans.iter().filter(|span| { - Path::new(&span.file_name) == Path::new(&file_name) - }) + let spans_in_this_file: Vec<_> = + diagnostic.spans.iter() + .filter(|span| Path::new(&span.file_name) == Path::new(&file_name)) + .collect(); + + let primary_spans: Vec<_> = + spans_in_this_file.iter() + .cloned() + .filter(|span| span.is_primary) + .collect(); + let primary_spans = if primary_spans.is_empty() { + // subdiagnostics often don't have a span of their own; + // inherit the span from the parent in that case + default_spans + } else { + &primary_spans }; // We break the output into multiple lines, and then append the @@ -124,7 +138,7 @@ fn push_expected_errors(expected_errors: &mut Vec, // more structured shortly anyhow. let mut message_lines = diagnostic.message.lines(); if let Some(first_line) = message_lines.next() { - for span in matching_spans() { + for span in primary_spans { let msg = with_code(span, first_line); let kind = ErrorKind::from_str(&diagnostic.level).ok(); expected_errors.push( @@ -137,7 +151,7 @@ fn push_expected_errors(expected_errors: &mut Vec, } } for next_line in message_lines { - for span in matching_spans() { + for span in primary_spans { expected_errors.push( Error { line_num: span.line_start, @@ -150,7 +164,7 @@ fn push_expected_errors(expected_errors: &mut Vec, // If the message has a suggestion, register that. if let Some(ref rendered) = diagnostic.rendered { - let start_line = matching_spans().map(|s| s.line_start).min().expect("\ + let start_line = primary_spans.iter().map(|s| s.line_start).min().expect("\ every suggestion should have at least one span"); for (index, line) in rendered.lines().enumerate() { expected_errors.push( @@ -164,7 +178,7 @@ fn push_expected_errors(expected_errors: &mut Vec, } // Add notes for the backtrace - for span in matching_spans() { + for span in primary_spans { for frame in &span.expansion { push_backtrace(expected_errors, frame, @@ -172,9 +186,20 @@ fn push_expected_errors(expected_errors: &mut Vec, } } + // Add notes for any labels that appear in the message. + for span in spans_in_this_file.iter() + .filter(|span| span.label.is_some()) + { + expected_errors.push(Error { + line_num: span.line_start, + kind: Some(ErrorKind::Note), + msg: span.label.clone().unwrap() + }); + } + // Flatten out the children. for child in &diagnostic.children { - push_expected_errors(expected_errors, child, file_name); + push_expected_errors(expected_errors, child, primary_spans, file_name); } } From 5b150cf0ca2145c7d03a2b5ed92d9f65cc0ebcca Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:45:28 -0400 Subject: [PATCH 51/97] add borrowck info inline in main snippet This uses the new `span_label` APIs --- src/librustc/diagnostics.rs | 2 +- src/librustc_borrowck/borrowck/check_loans.rs | 142 +++++++------ src/librustc_borrowck/borrowck/mod.rs | 188 ++++++------------ src/librustc_borrowck/diagnostics.rs | 1 + 4 files changed, 146 insertions(+), 187 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index e230836ef4515..efef259dcad9b 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1569,5 +1569,5 @@ register_diagnostics! { E0490, // a value of type `..` is borrowed for too long E0491, // in type `..`, reference has a longer lifetime than the data it... E0495, // cannot infer an appropriate lifetime due to conflicting requirements - E0524, // expected a closure that implements `..` but this closure only implements `..` + E0525, // expected a closure that implements `..` but this closure only implements `..` } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index d79ba213aca14..bbd9cd4526d95 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -447,22 +447,24 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // borrow ends let common = new_loan.loan_path.common(&old_loan.loan_path); - let (nl, ol, new_loan_msg, old_loan_msg) = + let (nl, ol, new_loan_msg, old_loan_msg) = { if new_loan.loan_path.has_fork(&old_loan.loan_path) && common.is_some() { let nl = self.bccx.loan_path_to_string(&common.unwrap()); let ol = nl.clone(); - let new_loan_msg = format!(" (here through borrowing `{}`)", + let new_loan_msg = format!(" (via `{}`)", self.bccx.loan_path_to_string( &new_loan.loan_path)); - let old_loan_msg = format!(" (through borrowing `{}`)", + let old_loan_msg = format!(" (via `{}`)", self.bccx.loan_path_to_string( &old_loan.loan_path)); (nl, ol, new_loan_msg, old_loan_msg) } else { (self.bccx.loan_path_to_string(&new_loan.loan_path), self.bccx.loan_path_to_string(&old_loan.loan_path), - String::new(), String::new()) - }; + String::new(), + String::new()) + } + }; let ol_pronoun = if new_loan.loan_path == old_loan.loan_path { "it".to_string() @@ -470,12 +472,48 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { format!("`{}`", ol) }; + // We want to assemble all the relevant locations for the error. + // + // 1. Where did the new loan occur. + // - if due to closure creation, where was the variable used in closure? + // 2. Where did old loan occur. + // 3. Where does old loan expire. + + let previous_end_span = + self.tcx().map.span(old_loan.kill_scope.node_id(&self.tcx().region_maps)) + .end_point(); + let mut err = match (new_loan.kind, old_loan.kind) { (ty::MutBorrow, ty::MutBorrow) => { struct_span_err!(self.bccx, new_loan.span, E0499, "cannot borrow `{}`{} as mutable \ more than once at a time", nl, new_loan_msg) + .span_label( + old_loan.span, + &format!("first mutable borrow occurs here{}", old_loan_msg)) + .span_label( + new_loan.span, + &format!("second mutable borrow occurs here{}", new_loan_msg)) + .span_label( + previous_end_span, + &format!("first borrow ends here")) + } + + (ty::UniqueImmBorrow, ty::UniqueImmBorrow) => { + struct_span_err!(self.bccx, new_loan.span, E0524, + "two closures require unique access to `{}` \ + at the same time", + nl) + .span_label( + old_loan.span, + &format!("first closure is constructed here")) + .span_label( + new_loan.span, + &format!("second closure is constructed here")) + .span_label( + previous_end_span, + &format!("borrow from first closure ends here")) } (ty::UniqueImmBorrow, _) => { @@ -483,6 +521,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { "closure requires unique access to `{}` \ but {} is already borrowed{}", nl, ol_pronoun, old_loan_msg) + .span_label( + new_loan.span, + &format!("closure construction occurs here{}", new_loan_msg)) + .span_label( + old_loan.span, + &format!("borrow occurs here{}", old_loan_msg)) + .span_label( + previous_end_span, + &format!("borrow ends here")) } (_, ty::UniqueImmBorrow) => { @@ -490,6 +537,15 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { "cannot borrow `{}`{} as {} because \ previous closure requires unique access", nl, new_loan_msg, new_loan.kind.to_user_str()) + .span_label( + new_loan.span, + &format!("borrow occurs here{}", new_loan_msg)) + .span_label( + old_loan.span, + &format!("closure construction occurs here{}", old_loan_msg)) + .span_label( + previous_end_span, + &format!("borrow from closure ends here")) } (_, _) => { @@ -502,70 +558,42 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { ol_pronoun, old_loan.kind.to_user_str(), old_loan_msg) + .span_label( + new_loan.span, + &format!("{} borrow occurs here{}", + new_loan.kind.to_user_str(), + new_loan_msg)) + .span_label( + old_loan.span, + &format!("{} borrow occurs here{}", + old_loan.kind.to_user_str(), + old_loan_msg)) + .span_label( + previous_end_span, + &format!("{} borrow ends here", + old_loan.kind.to_user_str())) } }; match new_loan.cause { euv::ClosureCapture(span) => { - err.span_note( + err = err.span_label( span, - &format!("borrow occurs due to use of `{}` in closure", - nl)); + &format!("borrow occurs due to use of `{}` in closure", nl)); } _ => { } } - let rule_summary = match old_loan.kind { - ty::MutBorrow => { - format!("the mutable borrow prevents subsequent \ - moves, borrows, or modification of `{0}` \ - until the borrow ends", - ol) - } - - ty::ImmBorrow => { - format!("the immutable borrow prevents subsequent \ - moves or mutable borrows of `{0}` \ - until the borrow ends", - ol) - } - - ty::UniqueImmBorrow => { - format!("the unique capture prevents subsequent \ - moves or borrows of `{0}` \ - until the borrow ends", - ol) - } - }; - - let borrow_summary = match old_loan.cause { - euv::ClosureCapture(_) => { - format!("previous borrow of `{}` occurs here{} due to \ - use in closure", - ol, old_loan_msg) - } - - euv::OverloadedOperator | - euv::AddrOf | - euv::AutoRef | - euv::AutoUnsafe | - euv::ClosureInvocation | - euv::ForLoop | - euv::RefBinding | - euv::MatchDiscriminant => { - format!("previous borrow of `{}` occurs here{}", - ol, old_loan_msg) + match old_loan.cause { + euv::ClosureCapture(span) => { + err = err.span_label( + span, + &format!("previous borrow occurs due to use of `{}` in closure", + ol)); } - }; - - err.span_note( - old_loan.span, - &format!("{}; {}", borrow_summary, rule_summary)); + _ => { } + } - let old_loan_span = self.tcx().map.span( - old_loan.kill_scope.node_id(&self.tcx().region_maps)); - err.span_end_note(old_loan_span, - "previous borrow ends here"); err.emit(); return false; } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 15db356b1ba95..87000749598a7 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -34,14 +34,14 @@ use rustc::middle::free_region::FreeRegionMap; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use std::fmt; use std::mem; use std::rc::Rc; use syntax::ast; use syntax::attr::AttrMetaMethods; -use syntax::codemap::Span; +use syntax::codemap::{MultiSpan, Span}; use syntax::errors::DiagnosticBuilder; use rustc::hir; @@ -633,23 +633,22 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { lp: &LoanPath<'tcx>, the_move: &move_data::Move, moved_lp: &LoanPath<'tcx>, - param_env: &ty::ParameterEnvironment<'b,'tcx>) { - let verb = match use_kind { - MovedInUse => "use", - MovedInCapture => "capture", + _param_env: &ty::ParameterEnvironment<'b,'tcx>) { + let (verb, verb_participle) = match use_kind { + MovedInUse => ("use", "used"), + MovedInCapture => ("capture", "captured"), }; - let (ol, moved_lp_msg, mut err) = match the_move.kind { + let (_ol, _moved_lp_msg, mut err) = match the_move.kind { move_data::Declared => { - let err = struct_span_err!( + // If this is an uninitialized variable, just emit a simple warning + // and return. + struct_span_err!( self.tcx.sess, use_span, E0381, "{} of possibly uninitialized variable: `{}`", verb, - self.loan_path_to_string(lp)); - - (self.loan_path_to_string(moved_lp), - String::new(), - err) + self.loan_path_to_string(lp)).emit(); + return; } _ => { // If moved_lp is something like `x.a`, and lp is something like `x.b`, we would @@ -688,122 +687,52 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess, use_span, E0382, "{} of {}moved value: `{}`", verb, msg, nl); - (ol, moved_lp_msg, err) + (ol, moved_lp_msg, err)} + }; + + // Get type of value and span where it was previously + // moved. + let (move_span, move_note) = match the_move.kind { + move_data::Declared => { + unreachable!(); } + + move_data::MoveExpr | + move_data::MovePat => + (self.tcx.map.span(the_move.id), ""), + + move_data::Captured => + (match self.tcx.map.expect_expr(the_move.id).node { + hir::ExprClosure(_, _, _, fn_decl_span) => fn_decl_span, + ref r => bug!("Captured({}) maps to non-closure: {:?}", + the_move.id, r), + }, " (into closure)"), }; - match the_move.kind { - move_data::Declared => {} + // Annotate the use and the move in the span. Watch out for + // the case where the use and the move are the same. This + // means the use is in a loop. + err = if use_span == move_span { + err.span_label( + use_span, + &format!("value moved{} here in previous iteration of loop", + move_note)) + } else { + err.span_label(use_span, &format!("value {} here after move", verb_participle)) + .span_label(move_span, &format!("value moved{} here", move_note)) + }; - move_data::MoveExpr => { - let (expr_ty, expr_span) = match self.tcx - .map - .find(the_move.id) { - Some(hir_map::NodeExpr(expr)) => { - (self.tcx.expr_ty_adjusted(&expr), expr.span) - } - r => { - bug!("MoveExpr({}) maps to {:?}, not Expr", - the_move.id, - r) - } - }; - let (suggestion, _) = - move_suggestion(param_env, expr_span, expr_ty, ("moved by default", "")); - // If the two spans are the same, it's because the expression will be evaluated - // multiple times. Avoid printing the same span and adjust the wording so it makes - // more sense that it's from multiple evalutations. - if expr_span == use_span { - err.note( - &format!("`{}` was previously moved here{} because it has type `{}`, \ - which is {}", - ol, - moved_lp_msg, - expr_ty, - suggestion)); - } else { - err.span_note( - expr_span, - &format!("`{}` moved here{} because it has type `{}`, which is {}", - ol, - moved_lp_msg, - expr_ty, - suggestion)); - } - } + err.note(&format!("move occurs because `{}` has type `{}`, \ + which does not implement the `Copy` trait", + self.loan_path_to_string(moved_lp), + moved_lp.ty)); - move_data::MovePat => { - let pat_ty = self.tcx.node_id_to_type(the_move.id); - let span = self.tcx.map.span(the_move.id); - err.span_note(span, - &format!("`{}` moved here{} because it has type `{}`, \ - which is moved by default", - ol, - moved_lp_msg, - pat_ty)); - match self.tcx.sess.codemap().span_to_snippet(span) { - Ok(string) => { - err.span_suggestion( - span, - &format!("if you would like to borrow the value instead, \ - use a `ref` binding as shown:"), - format!("ref {}", string)); - }, - Err(_) => { - err.fileline_help(span, - "use `ref` to override"); - }, - } - } + // Note: we used to suggest adding a `ref binding` or calling + // `clone` but those suggestions have been removed because + // they are often not what you actually want to do, and were + // not considered particularly helpful. - move_data::Captured => { - let (expr_ty, expr_span) = match self.tcx - .map - .find(the_move.id) { - Some(hir_map::NodeExpr(expr)) => { - (self.tcx.expr_ty_adjusted(&expr), expr.span) - } - r => { - bug!("Captured({}) maps to {:?}, not Expr", - the_move.id, - r) - } - }; - let (suggestion, help) = - move_suggestion(param_env, - expr_span, - expr_ty, - ("moved by default", - "make a copy and capture that instead to override")); - err.span_note( - expr_span, - &format!("`{}` moved into closure environment here{} because it \ - has type `{}`, which is {}", - ol, - moved_lp_msg, - moved_lp.ty, - suggestion)); - err.fileline_help(expr_span, help); - } - } err.emit(); - - fn move_suggestion<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>, - span: Span, - ty: Ty<'tcx>, - default_msgs: (&'static str, &'static str)) - -> (&'static str, &'static str) { - match ty.sty { - _ => { - if ty.moves_by_default(param_env, span) { - ("non-copyable", - "perhaps you meant to use `clone()`?") - } else { - default_msgs - } - } - } - } } pub fn report_partial_reinitialization_of_uninitialized_structure( @@ -833,19 +762,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err(s, m); } - pub fn struct_span_err(&self, s: Span, m: &str) -> DiagnosticBuilder<'a> { + pub fn struct_span_err>(&self, s: S, m: &str) + -> DiagnosticBuilder<'a> { self.tcx.sess.struct_span_err(s, m) } - pub fn struct_span_err_with_code(&self, - s: Span, - msg: &str, - code: &str) - -> DiagnosticBuilder<'a> { + pub fn struct_span_err_with_code>(&self, + s: S, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { self.tcx.sess.struct_span_err_with_code(s, msg, code) } - pub fn span_err_with_code(&self, s: Span, msg: &str, code: &str) { + pub fn span_err_with_code>(&self, s: S, msg: &str, code: &str) { self.tcx.sess.span_err_with_code(s, msg, code); } diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 7f6fd9de3d294..c7ad0b6a6c606 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -444,4 +444,5 @@ register_diagnostics! { E0506, // cannot assign to `..` because it is borrowed E0508, // cannot move out of type `..`, a non-copy fixed-size array E0509, // cannot move out of type `..`, which defines the `Drop` trait + E0524, // two closures require unique access to `..` at the same time } From 11dc974a38fd533aa692cea213305056cd3a6902 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:56:01 -0400 Subject: [PATCH 52/97] refactor to use new snippet code and model Major changes: - Remove old snippet rendering code and use the new stuff. - Introduce `span_label` method to add a label - Remove EndSpan mode and replace with a fn to get the last character of a span. - Stop using `Option` and just use an empty `MultiSpan` - and probably a bunch of other stuff :) --- src/librustc/session/mod.rs | 4 +- src/librustc_driver/lib.rs | 16 +- src/librustc_driver/test.rs | 4 - src/librustc_trans/back/write.rs | 19 +- src/libsyntax/codemap.rs | 87 +--- src/libsyntax/errors/emitter.rs | 796 +++++++++---------------------- src/libsyntax/errors/mod.rs | 175 ++++--- 7 files changed, 357 insertions(+), 744 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 5b78e4de18b57..edb1c4530c240 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -567,7 +567,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { } config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), }; - emitter.emit(None, msg, None, errors::Level::Fatal); + emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Fatal); panic!(errors::FatalError); } @@ -578,7 +578,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { } config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()), }; - emitter.emit(None, msg, None, errors::Level::Warning); + emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Warning); } // Err(0) means compilation was stopped, but no errors were found. diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 2d3363507d06c..52306e388e235 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -91,8 +91,9 @@ use std::thread; use rustc::session::early_error; -use syntax::{ast, errors, diagnostics}; -use syntax::codemap::{CodeMap, FileLoader, RealFileLoader}; +use syntax::{ast, errors, diagnostic}; +use syntax::codemap::MultiSpan; +use syntax::parse::{self, PResult}; use syntax::errors::emitter::Emitter; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult, token}; @@ -136,7 +137,8 @@ pub fn run(args: Vec) -> isize { None => { let mut emitter = errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto); - emitter.emit(None, &abort_msg(err_count), None, errors::Level::Fatal); + emitter.emit(&MultiSpan::new(), &abort_msg(err_count), None, + errors::Level::Fatal); exit_on_err(); } } @@ -379,7 +381,7 @@ fn check_cfg(sopts: &config::Options, match item.node { ast::MetaItemKind::List(ref pred, _) => { saw_invalid_predicate = true; - emitter.emit(None, + emitter.emit(&MultiSpan::new(), &format!("invalid predicate in --cfg command line argument: `{}`", pred), None, @@ -1028,19 +1030,19 @@ pub fn monitor(f: F) { // a .span_bug or .bug call has already printed what // it wants to print. if !value.is::() { - emitter.emit(None, "unexpected panic", None, errors::Level::Bug); + emitter.emit(&MultiSpan::new(), "unexpected panic", None, errors::Level::Bug); } let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(), format!("we would appreciate a bug report: {}", BUG_REPORT_URL)]; for note in &xs { - emitter.emit(None, ¬e[..], None, errors::Level::Note) + emitter.emit(&MultiSpan::new(), ¬e[..], None, errors::Level::Note) } if match env::var_os("RUST_BACKTRACE") { Some(val) => &val != "0", None => false, } { - emitter.emit(None, + emitter.emit(&MultiSpan::new(), "run with `RUST_BACKTRACE=1` for a backtrace", None, errors::Level::Note); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index ce92dd158c969..60f4ab1c95f2b 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -86,10 +86,6 @@ impl Emitter for ExpectErrorEmitter { lvl: Level) { remove_message(self, msg, lvl); } - - fn custom_emit(&mut self, _sp: &RenderSpan, msg: &str, lvl: Level) { - remove_message(self, msg, lvl); - } } fn errors(msgs: &[&str]) -> (Box, usize) { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 8a915f044053a..50fd039276253 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -19,7 +19,7 @@ use llvm::SMDiagnosticRef; use {CrateTranslation, ModuleTranslation}; use util::common::time; use util::common::path2cstr; -use syntax::codemap; +use syntax::codemap::{self, MultiSpan}; use syntax::errors::{self, Handler, Level}; use syntax::errors::emitter::Emitter; @@ -84,13 +84,13 @@ impl SharedEmitter { for diag in &*buffer { match diag.code { Some(ref code) => { - handler.emit_with_code(None, + handler.emit_with_code(&MultiSpan::new(), &diag.msg, &code[..], diag.lvl); }, None => { - handler.emit(None, + handler.emit(&MultiSpan::new(), &diag.msg, diag.lvl); }, @@ -101,9 +101,12 @@ impl SharedEmitter { } impl Emitter for SharedEmitter { - fn emit(&mut self, sp: Option<&codemap::MultiSpan>, - msg: &str, code: Option<&str>, lvl: Level) { - assert!(sp.is_none(), "SharedEmitter doesn't support spans"); + fn emit(&mut self, + sp: &codemap::MultiSpan, + msg: &str, + code: Option<&str>, + lvl: Level) { + assert!(sp.primary_span().is_none(), "SharedEmitter doesn't support spans"); self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), @@ -112,8 +115,8 @@ impl Emitter for SharedEmitter { }); } - fn custom_emit(&mut self, _sp: &errors::RenderSpan, _msg: &str, _lvl: Level) { - bug!("SharedEmitter doesn't support custom_emit"); + fn emit_struct(&mut self, _db: &errors::DiagnosticBuilder) { + bug!("SharedEmitter doesn't support emit_struct"); } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 228af27f4b10a..5862538de2e04 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -163,6 +163,12 @@ pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0), expn_id: COMMAND_LINE_EXPN }; impl Span { + /// Returns a new span representing just the end-point of this span + pub fn end_point(self) -> Span { + let lo = cmp::max(self.hi.0 - 1, self.lo.0); + Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} + } + /// Returns `self` if `self` is not the dummy span, and `other` otherwise. pub fn substitute_dummy(self, other: Span) -> Span { if self.source_equal(&DUMMY_SP) { other } else { self } @@ -794,7 +800,7 @@ impl CodeMap { /// Creates a new filemap and sets its line information. pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc { let fm = self.new_filemap(filename.to_string(), src.to_owned()); - let mut byte_pos: u32 = 0; + let mut byte_pos: u32 = fm.start_pos.0; for line in src.lines() { // register the start of this line fm.next_line(BytePos(byte_pos)); @@ -1126,7 +1132,9 @@ impl CodeMap { // numbers in Loc are 1-based, so we subtract 1 to get 0-based // lines. for line_index in lo.line-1 .. hi.line-1 { - let line_len = lo.file.get_line(line_index).map(|s| s.len()).unwrap_or(0); + let line_len = lo.file.get_line(line_index) + .map(|s| s.chars().count()) + .unwrap_or(0); lines.push(LineInfo { line_index: line_index, start_col: start_col, end_col: CharPos::from_usize(line_len) }); @@ -1584,13 +1592,13 @@ mod tests { assert_eq!(file_lines.lines[0].line_index, 1); } - /// Given a string like " ^~~~~~~~~~~~ ", produces a span + /// Given a string like " ~~~~~~~~~~~~ ", produces a span /// coverting that range. The idea is that the string has the same /// length as the input, and we uncover the byte positions. Note /// that this can span lines and so on. fn span_from_selection(input: &str, selection: &str) -> Span { assert_eq!(input.len(), selection.len()); - let left_index = selection.find('^').unwrap() as u32; + let left_index = selection.find('~').unwrap() as u32; let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } } @@ -1601,7 +1609,7 @@ mod tests { fn span_to_snippet_and_lines_spanning_multiple_lines() { let cm = CodeMap::new(); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; - let selection = " \n ^~\n~~~\n~~~~~ \n \n"; + let selection = " \n ~~\n~~~\n~~~~~ \n \n"; cm.new_filemap_and_lines("blork.rs", inputtext); let span = span_from_selection(inputtext, selection); @@ -1751,73 +1759,4 @@ r"blork2.rs:2:1: 2:12 "; assert_eq!(sstr, res_str); } - - #[test] - fn t13() { - // Test that collecting multiple spans into line-groups works correctly - let cm = CodeMap::new(); - let inp = "_aaaaa__bbb\nvv\nw\nx\ny\nz\ncccccc__ddddee__"; - let sp1 = " ^~~~~ \n \n \n \n \n \n "; - let sp2 = " \n \n \n \n \n^\n "; - let sp3 = " ^~~\n~~\n \n \n \n \n "; - let sp4 = " \n \n \n \n \n \n^~~~~~ "; - let sp5 = " \n \n \n \n \n \n ^~~~ "; - let sp6 = " \n \n \n \n \n \n ^~~~ "; - let sp_trim = " \n \n \n \n \n \n ^~ "; - let sp_merge = " \n \n \n \n \n \n ^~~~~~ "; - let sp7 = " \n ^\n \n \n \n \n "; - let sp8 = " \n \n^\n \n \n \n "; - let sp9 = " \n \n \n^\n \n \n "; - let sp10 = " \n \n \n \n^\n \n "; - - let span = |sp, expected| { - let sp = span_from_selection(inp, sp); - assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected); - sp - }; - - cm.new_filemap_and_lines("blork.rs", inp); - let sp1 = span(sp1, "aaaaa"); - let sp2 = span(sp2, "z"); - let sp3 = span(sp3, "bbb\nvv"); - let sp4 = span(sp4, "cccccc"); - let sp5 = span(sp5, "dddd"); - let sp6 = span(sp6, "ddee"); - let sp7 = span(sp7, "v"); - let sp8 = span(sp8, "w"); - let sp9 = span(sp9, "x"); - let sp10 = span(sp10, "y"); - let sp_trim = span(sp_trim, "ee"); - let sp_merge = span(sp_merge, "ddddee"); - - let spans = vec![sp5, sp2, sp4, sp9, sp10, sp7, sp3, sp8, sp1, sp6]; - - macro_rules! check_next { - ($groups: expr, $expected: expr) => ({ - let actual = $groups.next().map(|g|&g.spans[..]); - let expected = $expected; - println!("actual:\n{:?}\n", actual); - println!("expected:\n{:?}\n", expected); - assert_eq!(actual, expected.as_ref().map(|x|&x[..])); - }); - } - - let _groups = cm.group_spans(spans.clone()); - let it = &mut _groups.iter(); - - check_next!(it, Some([sp1, sp7, sp8, sp9, sp10, sp2])); - // New group because we're exceeding MAX_HIGHLIGHT_LINES - check_next!(it, Some([sp4, sp_merge])); - check_next!(it, Some([sp3])); - check_next!(it, None::<[Span; 0]>); - - let _groups = cm.end_group_spans(spans); - let it = &mut _groups.iter(); - - check_next!(it, Some([sp1, sp7, sp8, sp9, sp10, sp2])); - // New group because we're exceeding MAX_HIGHLIGHT_LINES - check_next!(it, Some([sp4, sp5, sp_trim])); - check_next!(it, Some([sp3])); - check_next!(it, None::<[Span; 0]>); - } } diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 0b5234769b219..e963a5f794cb6 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -16,6 +16,7 @@ use diagnostics; use errors::{Level, RenderSpan, CodeSuggestion, DiagnosticBuilder}; use errors::RenderSpan::*; use errors::Level::*; +use errors::snippet::{RenderedLineKind, SnippetData, Style}; use std::{cmp, fmt}; use std::io::prelude::*; @@ -24,27 +25,15 @@ use std::rc::Rc; use term; pub trait Emitter { - fn emit(&mut self, span: Option<&MultiSpan>, msg: &str, code: Option<&str>, lvl: Level); - fn custom_emit(&mut self, sp: &RenderSpan, msg: &str, lvl: Level); + fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level); /// Emit a structured diagnostic. - fn emit_struct(&mut self, db: &DiagnosticBuilder) { - self.emit(db.span.as_ref(), &db.message, db.code.as_ref().map(|s| &**s), db.level); - for child in &db.children { - match child.render_span { - Some(ref sp) => self.custom_emit(sp, &child.message, child.level), - None => self.emit(child.span.as_ref(), &child.message, None, child.level), - } - } - } + fn emit_struct(&mut self, db: &DiagnosticBuilder); } /// maximum number of lines we will print for each error; arbitrary. pub const MAX_HIGHLIGHT_LINES: usize = 6; -/// maximum number of lines we will print for each span; arbitrary. -const MAX_SP_LINES: usize = 6; - #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ColorConfig { Auto, @@ -70,19 +59,23 @@ pub struct BasicEmitter { impl Emitter for BasicEmitter { fn emit(&mut self, - msp: Option<&MultiSpan>, + msp: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level) { - assert!(msp.is_none(), "BasicEmitter can't handle spans"); + assert!(msp.primary_span().is_none(), "BasicEmitter can't handle spans"); + if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { panic!("failed to print diagnostics: {:?}", e); } - } - fn custom_emit(&mut self, _: &RenderSpan, _: &str, _: Level) { - panic!("BasicEmitter can't handle custom_emit"); + fn emit_struct(&mut self, db: &DiagnosticBuilder) { + self.emit(&db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); + for child in &db.children { + assert!(child.render_span.is_none(), "BasicEmitter can't handle spans"); + self.emit(&child.span, &child.message, None, child.level); + } } } @@ -101,33 +94,31 @@ pub struct EmitterWriter { dst: Destination, registry: Option, cm: Rc, + first: bool, } impl Emitter for EmitterWriter { fn emit(&mut self, - msp: Option<&MultiSpan>, + msp: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level) { - let error = match msp.map(|s|(s.to_span_bounds(), s)) { - Some((COMMAND_LINE_SP, msp)) => { - self.emit_(&FileLine(msp.clone()), msg, code, lvl) - }, - Some((DUMMY_SP, _)) | None => print_diagnostic(&mut self.dst, "", lvl, msg, code), - Some((_, msp)) => self.emit_(&FullSpan(msp.clone()), msg, code, lvl), - }; - - if let Err(e) = error { - panic!("failed to print diagnostics: {:?}", e); - } + self.emit_multispan(msp, msg, code, lvl, true); } - fn custom_emit(&mut self, - rsp: &RenderSpan, - msg: &str, - lvl: Level) { - if let Err(e) = self.emit_(rsp, msg, None, lvl) { - panic!("failed to print diagnostics: {:?}", e); + fn emit_struct(&mut self, db: &DiagnosticBuilder) { + self.emit_multispan(&db.span, &db.message, + db.code.as_ref().map(|s| &**s), db.level, true); + + for child in &db.children { + match child.render_span { + Some(ref sp) => + self.emit_renderspan(sp, &child.message, + child.level), + None => + self.emit_multispan(&child.span, + &child.message, None, child.level, false), + } } } } @@ -153,9 +144,10 @@ impl EmitterWriter { -> EmitterWriter { if color_config.use_color() { let dst = Destination::from_stderr(); - EmitterWriter { dst: dst, registry: registry, cm: code_map } + EmitterWriter { dst: dst, registry: registry, cm: code_map, first: true } } else { - EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map } + EmitterWriter { dst: Raw(Box::new(io::stderr())), + registry: registry, cm: code_map, first: true } } } @@ -163,7 +155,49 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { - EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map } + EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, first: true } + } + + fn emit_multispan(&mut self, + span: &MultiSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + is_header: bool) { + if is_header { + if self.first { + self.first = false; + } else { + match write!(self.dst, "\n") { + Ok(_) => { } + Err(e) => { + panic!("failed to print diagnostics: {:?}", e) + } + } + } + } + + let error = match span.primary_span() { + Some(COMMAND_LINE_SP) => { + self.emit_(&FileLine(span.clone()), msg, code, lvl) + } + Some(DUMMY_SP) | None => { + print_diagnostic(&mut self.dst, "", lvl, msg, code) + } + Some(_) => { + self.emit_(&FullSpan(span.clone()), msg, code, lvl) + } + }; + + if let Err(e) = error { + panic!("failed to print diagnostics: {:?}", e); + } + } + + fn emit_renderspan(&mut self, sp: &RenderSpan, msg: &str, lvl: Level) { + if let Err(e) = self.emit_(sp, msg, None, lvl) { + panic!("failed to print diagnostics: {:?}", e); + } } fn emit_(&mut self, @@ -173,51 +207,43 @@ impl EmitterWriter { lvl: Level) -> io::Result<()> { let msp = rsp.span(); - let bounds = msp.to_span_bounds(); - - let ss = if bounds == COMMAND_LINE_SP { - "".to_string() - } else if let EndSpan(_) = *rsp { - let span_end = Span { lo: bounds.hi, hi: bounds.hi, expn_id: bounds.expn_id}; - self.cm.span_to_string(span_end) - } else { - self.cm.span_to_string(bounds) - }; - - print_diagnostic(&mut self.dst, &ss[..], lvl, msg, code)?; + let primary_span = msp.primary_span(); + + match code { + Some(code) if self.registry.as_ref() + .and_then(|registry| registry.find_description(code)).is_some() => + { + let code_with_explain = String::from("--explain ") + code; + print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))? + } + _ => print_diagnostic(&mut self.dst, "", lvl, msg, code)? + } match *rsp { FullSpan(_) => { self.highlight_lines(msp, lvl)?; - self.print_macro_backtrace(bounds)?; - } - EndSpan(_) => { - self.end_highlight_lines(msp, lvl)?; - self.print_macro_backtrace(bounds)?; + if let Some(primary_span) = primary_span { + self.print_macro_backtrace(primary_span)?; + } } Suggestion(ref suggestion) => { self.highlight_suggestion(suggestion)?; - self.print_macro_backtrace(bounds)?; + if let Some(primary_span) = primary_span { + self.print_macro_backtrace(primary_span)?; + } } FileLine(..) => { // no source text in this case! } } - if let Some(code) = code { - if let Some(_) = self.registry.as_ref() - .and_then(|registry| registry.find_description(code)) { - print_diagnostic(&mut self.dst, &ss[..], Help, - &format!("run `rustc --explain {}` to see a \ - detailed explanation", code), None)?; - } - } Ok(()) } fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()> { - let lines = self.cm.span_to_lines(suggestion.msp.to_span_bounds()).unwrap(); + let primary_span = suggestion.msp.primary_span().unwrap(); + let lines = self.cm.span_to_lines(primary_span).unwrap(); assert!(!lines.lines.is_empty()); let complete = suggestion.splice_lines(&self.cm); @@ -251,325 +277,21 @@ impl EmitterWriter { lvl: Level) -> io::Result<()> { - let lines = match self.cm.span_to_lines(msp.to_span_bounds()) { - Ok(lines) => lines, - Err(_) => { - write!(&mut self.dst, "(internal compiler error: unprintable span)\n")?; - return Ok(()); - } - }; - - let fm = &*lines.file; - if let None = fm.src { - return Ok(()); - } - - let display_line_infos = &lines.lines[..]; - assert!(display_line_infos.len() > 0); - - // Calculate the widest number to format evenly and fix #11715 - let digits = line_num_max_digits(display_line_infos.last().unwrap()); - let first_line_index = display_line_infos.first().unwrap().line_index; - - let skip = fm.name.chars().count() + digits + 2; - - let mut spans = msp.spans.iter().peekable(); - let mut lines = display_line_infos.iter(); - let mut prev_line_index = first_line_index.wrapping_sub(1); - - // Display at most MAX_HIGHLIGHT_LINES lines. - let mut remaining_err_lines = MAX_HIGHLIGHT_LINES; - - // To emit a overflowed spans code-lines *AFTER* the rendered spans - let mut overflowed_buf = String::new(); - let mut overflowed = false; - - // FIXME (#8706) - 'l: loop { - if remaining_err_lines <= 0 { - break; - } - let line = match lines.next() { - Some(l) => l, - None => break, - }; - - // Skip is the number of characters we need to skip because they are - // part of the 'filename:line ' part of the code line. - let mut s: String = ::std::iter::repeat(' ').take(skip).collect(); - let mut col = skip; - let mut lastc = ' '; - - let cur_line_str = fm.get_line(line.line_index).unwrap(); - let mut line_chars = cur_line_str.chars().enumerate().peekable(); - let mut line_spans = 0; - - // Assemble spans for this line - loop { - // Peek here to preserve the span if it doesn't belong to this line - let sp = match spans.peek() { - Some(sp) => **sp, - None => break, - }; - let lo = self.cm.lookup_char_pos(sp.lo); - let hi = self.cm.lookup_char_pos(sp.hi); - let line_num = line.line_index + 1; - - if !(lo.line <= line_num && hi.line >= line_num) { - // This line is not contained in the span - if overflowed { - // Never elide the final line of an overflowed span - prev_line_index = line.line_index - 1; - overflowed = false; - break; - } - - if line_spans == 0 { - continue 'l; - } else { - // This line is finished, now render the spans we've assembled - break; - } - } - spans.next(); - line_spans += 1; - - if lo.line != hi.line { - // Assemble extra code lines to be emitted after this lines spans - // (substract `2` because the first and last line are rendered normally) - let max_lines = cmp::min(remaining_err_lines, MAX_SP_LINES) - 2; - prev_line_index = line.line_index; - let count = cmp::min((hi.line - lo.line - 1), max_lines); - for _ in 0..count { - let line = match lines.next() { - Some(l) => l, - None => break, - }; - let line_str = fm.get_line(line.line_index).unwrap(); - overflowed_buf.push_str(&format!("{}:{:>width$} {}\n", - fm.name, - line.line_index + 1, - line_str, - width=digits)); - remaining_err_lines -= 1; - prev_line_index += 1 - } - // Remember that the span overflowed to ensure - // that we emit its last line exactly once - // (other spans may, or may not, start on it) - overflowed = true; - break; - } - - for (pos, ch) in line_chars.by_ref() { - lastc = ch; - if pos >= lo.col.to_usize() { break; } - // Whenever a tab occurs on the code line, we insert one on - // the error-point-squiggly-line as well (instead of a space). - // That way the squiggly line will usually appear in the correct - // position. - match ch { - '\t' => { - col += 8 - col%8; - s.push('\t'); - }, - _ => { - col += 1; - s.push(' '); - }, - } - } - - s.push('^'); - let col_ptr = col; - let count = match lastc { - // Most terminals have a tab stop every eight columns by default - '\t' => 8 - col%8, - _ => 1, - }; - col += count; - s.extend(::std::iter::repeat('~').take(count)); - - let hi = self.cm.lookup_char_pos(sp.hi); - if hi.col != lo.col { - let mut chars = line_chars.by_ref(); - loop { - // We peek here to preserve the value for the next span - let (pos, ch) = match chars.peek() { - Some(elem) => *elem, - None => break, - }; - if pos >= hi.col.to_usize() { break; } - let count = match ch { - '\t' => 8 - col%8, - _ => 1, - }; - col += count; - s.extend(::std::iter::repeat('~').take(count)); - - chars.next(); - } - } - if (col - col_ptr) > 0 { - // One extra squiggly is replaced by a "^" - s.pop(); - } - } - - // If we elided something put an ellipsis. - if prev_line_index != line.line_index.wrapping_sub(1) && !overflowed { - write!(&mut self.dst, "{0:1$}...\n", "", skip)?; - } - - // Print offending code-line - remaining_err_lines -= 1; - write!(&mut self.dst, "{}:{:>width$} {}\n", - fm.name, - line.line_index + 1, - cur_line_str, - width=digits)?; - - if s.len() > skip { - // Render the spans we assembled previously (if any). - println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()), - "{}", s)?; - } - - if !overflowed_buf.is_empty() { - // Print code-lines trailing the rendered spans (when a span overflows) - write!(&mut self.dst, "{}", &overflowed_buf)?; - overflowed_buf.clear(); - } else { - prev_line_index = line.line_index; - } - } - - // If we elided something, put an ellipsis. - if lines.next().is_some() { - write!(&mut self.dst, "{0:1$}...\n", "", skip)?; - } - Ok(()) - } - - /// Here are the differences between this and the normal `highlight_lines`: - /// `end_highlight_lines` will always put arrow on the last byte of each - /// span (instead of the first byte). Also, when a span is too long (more - /// than 6 lines), `end_highlight_lines` will print the first line, then - /// dot dot dot, then last line, whereas `highlight_lines` prints the first - /// six lines. - #[allow(deprecated)] - fn end_highlight_lines(&mut self, - msp: &MultiSpan, - lvl: Level) - -> io::Result<()> { - let lines = match self.cm.span_to_lines(msp.to_span_bounds()) { - Ok(lines) => lines, - Err(_) => { - write!(&mut self.dst, "(internal compiler error: unprintable span)\n")?; - return Ok(()); - } - }; - - let fm = &*lines.file; - if let None = fm.src { - return Ok(()); + let mut snippet_data = SnippetData::new(self.cm.clone(), + msp.primary_span()); + for span_label in msp.span_labels() { + snippet_data.push(span_label.span, + span_label.is_primary, + span_label.label); } - - let lines = &lines.lines[..]; - - // Calculate the widest number to format evenly - let first_line = lines.first().unwrap(); - let last_line = lines.last().unwrap(); - let digits = line_num_max_digits(last_line); - - let skip = fm.name.chars().count() + digits + 2; - - let mut spans = msp.spans.iter().peekable(); - let mut lines = lines.iter(); - let mut prev_line_index = first_line.line_index.wrapping_sub(1); - - // Display at most MAX_HIGHLIGHT_LINES lines. - let mut remaining_err_lines = MAX_HIGHLIGHT_LINES; - - 'l: loop { - if remaining_err_lines <= 0 { - break; - } - let line = match lines.next() { - Some(line) => line, - None => break, - }; - - // Skip is the number of characters we need to skip because they are - // part of the 'filename:line ' part of the previous line. - let mut s: String = ::std::iter::repeat(' ').take(skip).collect(); - - let line_str = fm.get_line(line.line_index).unwrap(); - let mut line_chars = line_str.chars().enumerate(); - let mut line_spans = 0; - - loop { - // Peek here to preserve the span if it doesn't belong to this line - let sp = match spans.peek() { - Some(sp) => **sp, - None => break, - }; - let lo = self.cm.lookup_char_pos(sp.lo); - let hi = self.cm.lookup_char_pos(sp.hi); - let elide_sp = (hi.line - lo.line) >= MAX_SP_LINES; - - let line_num = line.line_index + 1; - if !(lo.line <= line_num && hi.line >= line_num) { - // This line is not contained in the span - if line_spans == 0 { - continue 'l; - } else { - // This line is finished, now render the spans we've assembled - break - } - } else if hi.line > line_num { - if elide_sp && lo.line < line_num { - // This line is inbetween the first and last line of the span, - // so we may want to elide it. - continue 'l; - } else { - break - } - } - line_spans += 1; - spans.next(); - - for (pos, ch) in line_chars.by_ref() { - // Span seems to use half-opened interval, so subtract 1 - if pos >= hi.col.to_usize() - 1 { break; } - // Whenever a tab occurs on the previous line, we insert one on - // the error-point-squiggly-line as well (instead of a space). - // That way the squiggly line will usually appear in the correct - // position. - match ch { - '\t' => s.push('\t'), - _ => s.push(' '), - } - } - s.push('^'); + let rendered_lines = snippet_data.render_lines(); + for rendered_line in &rendered_lines { + for styled_string in &rendered_line.text { + self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?; + write!(&mut self.dst, "{}", styled_string.text)?; + self.dst.reset_attrs()?; } - - if prev_line_index != line.line_index.wrapping_sub(1) { - // If we elided something, put an ellipsis. - write!(&mut self.dst, "{0:1$}...\n", "", skip)?; - } - - // Print offending code-lines - write!(&mut self.dst, "{}:{:>width$} {}\n", fm.name, - line.line_index + 1, line_str, width=digits)?; - remaining_err_lines -= 1; - - if s.len() > skip { - // Render the spans we assembled previously (if any) - println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()), - "{}", s)?; - } - prev_line_index = line.line_index; + write!(&mut self.dst, "\n")?; } Ok(()) } @@ -602,6 +324,7 @@ fn line_num_max_digits(line: &codemap::LineInfo) -> usize { digits } + fn print_diagnostic(dst: &mut Destination, topic: &str, lvl: Level, @@ -609,17 +332,22 @@ fn print_diagnostic(dst: &mut Destination, code: Option<&str>) -> io::Result<()> { if !topic.is_empty() { - write!(dst, "{} ", topic)?; - } - - print_maybe_styled!(dst, term::Attr::ForegroundColor(lvl.color()), - "{}: ", lvl.to_string())?; - print_maybe_styled!(dst, term::Attr::Bold, "{}", msg)?; - + dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?; + write!(dst, "{}: ", topic)?; + dst.reset_attrs()?; + } + dst.start_attr(term::Attr::Bold)?; + dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?; + write!(dst, "{}", lvl.to_string())?; + dst.reset_attrs()?; + write!(dst, ": ")?; + dst.start_attr(term::Attr::Bold)?; + write!(dst, "{}", msg)?; if let Some(code) = code { let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA); print_maybe_styled!(dst, style, " [{}]", code.clone())?; } + dst.reset_attrs()?; write!(dst, "\n")?; Ok(()) } @@ -660,6 +388,52 @@ impl Destination { } } + fn apply_style(&mut self, + lvl: Level, + _kind: &RenderedLineKind, + style: Style) + -> io::Result<()> { + match style { + Style::FileNameStyle => { + } + Style::LineAndColumn => { + } + Style::LineNumber => { + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; + } + Style::Quotation => { + } + Style::UnderlinePrimary | Style::LabelPrimary => { + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(lvl.color()))?; + } + Style::UnderlineSecondary | Style::LabelSecondary => { + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; + } + Style::NoStyle => { + } + } + Ok(()) + } + + fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> { + match *self { + Terminal(ref mut t) => { t.attr(attr)?; } + Raw(_) => { } + } + Ok(()) + } + + fn reset_attrs(&mut self) -> io::Result<()> { + match *self { + Terminal(ref mut t) => { t.reset()?; } + Raw(_) => { } + } + Ok(()) + } + fn print_maybe_styled(&mut self, args: fmt::Arguments, color: term::Attr, @@ -741,7 +515,7 @@ mod test { /// that this can span lines and so on. fn span_from_selection(input: &str, selection: &str) -> Span { assert_eq!(input.len(), selection.len()); - let left_index = selection.find('^').unwrap() as u32; + let left_index = selection.find('~').unwrap() as u32; let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } } @@ -777,12 +551,15 @@ mod test { let vec = data.lock().unwrap().clone(); let vec: &[u8] = &vec; let str = from_utf8(vec).unwrap(); - println!("{}", str); - assert_eq!(str, "dummy.txt: 8 line8\n\ - dummy.txt: 9 line9\n\ - dummy.txt:10 line10\n\ - dummy.txt:11 e-lä-vän\n\ - dummy.txt:12 tolv\n"); + println!("r#\"\n{}\"#", str); + assert_eq!(str, &r#" + --> dummy.txt:8:1 +8 |> line8 + |> ^^^^^^^^^^^^^ +... +11 |> e-lä-vän + |> ^^^^^^^^^^^^^^^^ +"#[1..]); } #[test] @@ -790,7 +567,7 @@ mod test { // Test that a `MultiSpan` containing a single span splices a substition correctly let cm = CodeMap::new(); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; - let selection = " \n ^~\n~~~\n~~~~~ \n \n"; + let selection = " \n ~~\n~~~\n~~~~~ \n \n"; cm.new_filemap_and_lines("blork.rs", inputtext); let sp = span_from_selection(inputtext, selection); let msp: MultiSpan = sp.into(); @@ -808,51 +585,25 @@ mod test { } #[test] - fn test_multiple_span_splice() { - // Test that a `MultiSpan` containing multiple spans splices substitions on - // several lines correctly + fn test_multi_span_splice() { + // Test that a `MultiSpan` containing multiple spans splices a substition correctly let cm = CodeMap::new(); - let inp = "aaaaabbbbBB\nZZ\nZZ\nCCCDDDDDdddddeee"; - let sp1 = " ^~~~~~\n \n \n "; - let sp2 = " \n \n \n^~~~~~ "; - let sp3 = " \n \n \n ^~~ "; - let sp4 = " \n \n \n ^~~~ "; - - let span_eq = |sp, eq| assert_eq!(&cm.span_to_snippet(sp).unwrap(), eq); - - cm.new_filemap_and_lines("blork.rs", inp); - let sp1 = span_from_selection(inp, sp1); - let sp2 = span_from_selection(inp, sp2); - let sp3 = span_from_selection(inp, sp3); - let sp4 = span_from_selection(inp, sp4); - span_eq(sp1, "bbbbBB"); - span_eq(sp2, "CCCDDD"); - span_eq(sp3, "ddd"); - span_eq(sp4, "ddee"); - - let substitutes: Vec = ["1", "2", "3", "4"].iter().map(|x|x.to_string()).collect(); - let expected = "aaaaa1\nZZ\nZZ\n2DD34e"; - - let test = |msp| { - let suggest = CodeSuggestion { - msp: msp, - substitutes: substitutes.clone(), - }; - let actual = suggest.splice_lines(&cm); - assert_eq!(actual, expected); + let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; + let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order + let selection2 = " \n ~~\n~~~\n~~~~~ \n \n"; + cm.new_filemap_and_lines("blork.rs", inputtext); + let sp1 = span_from_selection(inputtext, selection1); + let sp2 = span_from_selection(inputtext, selection2); + let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]); + + let expected = "bbbbZZZZZZddddd\neXYZe"; + let suggest = CodeSuggestion { + msp: msp, + substitutes: vec!["ZZZZZZ".to_owned(), + "XYZ".to_owned()] }; - test(MultiSpan { spans: vec![sp1, sp2, sp3, sp4] }); - - // Test ordering and merging by `MultiSpan::push` - let mut msp = MultiSpan::new(); - msp.push_merge(sp2); - msp.push_merge(sp1); - assert_eq!(&msp.spans, &[sp1, sp2]); - msp.push_merge(sp4); - assert_eq!(&msp.spans, &[sp1, sp2, sp4]); - msp.push_merge(sp3); - assert_eq!(&msp.spans, &[sp1, sp2, sp3, sp4]); - test(msp); + + assert_eq!(suggest.splice_lines(&cm), expected); } #[test] @@ -862,17 +613,17 @@ mod test { let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone()); let inp = "_____aaaaaa____bbbbbb__cccccdd_"; - let sp1 = " ^~~~~~ "; - let sp2 = " ^~~~~~ "; - let sp3 = " ^~~~~ "; - let sp4 = " ^~~~ "; - let sp34 = " ^~~~~~~ "; - let sp4_end = " ^~ "; - - let expect_start = "dummy.txt:1 _____aaaaaa____bbbbbb__cccccdd_\n\ - \x20 ^~~~~~ ^~~~~~ ^~~~~~~\n"; - let expect_end = "dummy.txt:1 _____aaaaaa____bbbbbb__cccccdd_\n\ - \x20 ^ ^ ^ ^\n"; + let sp1 = " ~~~~~~ "; + let sp2 = " ~~~~~~ "; + let sp3 = " ~~~~~ "; + let sp4 = " ~~~~ "; + let sp34 = " ~~~~~~~ "; + + let expect_start = &r#" + --> dummy.txt:1:6 +1 |> _____aaaaaa____bbbbbb__cccccdd_ + |> ^^^^^^ ^^^^^^ ^^^^^^^ +"#[1..]; let span = |sp, expected| { let sp = span_from_selection(inp, sp); @@ -885,7 +636,6 @@ mod test { let sp3 = span(sp3, "ccccc"); let sp4 = span(sp4, "ccdd"); let sp34 = span(sp34, "cccccdd"); - let sp4_end = span(sp4_end, "dd"); let spans = vec![sp1, sp2, sp3, sp4]; @@ -894,26 +644,17 @@ mod test { highlight(); let vec = data.lock().unwrap().clone(); let actual = from_utf8(&vec[..]).unwrap(); + println!("actual=\n{}", actual); assert_eq!(actual, expected); }; - let msp = MultiSpan { spans: vec![sp1, sp2, sp34] }; - let msp_end = MultiSpan { spans: vec![sp1, sp2, sp3, sp4_end] }; + let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]); test(expect_start, &mut || { diag.highlight_lines(&msp, Level::Error).unwrap(); }); - test(expect_end, &mut || { - diag.end_highlight_lines(&msp_end, Level::Error).unwrap(); - }); test(expect_start, &mut || { - for msp in cm.group_spans(spans.clone()) { - diag.highlight_lines(&msp, Level::Error).unwrap(); - } - }); - test(expect_end, &mut || { - for msp in cm.end_group_spans(spans.clone()) { - diag.end_highlight_lines(&msp, Level::Error).unwrap(); - } + let msp = MultiSpan::from_spans(spans.clone()); + diag.highlight_lines(&msp, Level::Error).unwrap(); }); } @@ -950,75 +691,31 @@ mod test { let sp4 = span(10, 10, (2, 3)); let sp5 = span(10, 10, (4, 6)); - let expect0 = "dummy.txt: 5 ccccc\n\ - dummy.txt: 6 xxxxx\n\ - dummy.txt: 7 yyyyy\n\ - \x20 ...\n\ - dummy.txt: 9 ddd__eee_\n\ - \x20 ^~~ ^~~\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^~\n"; - - let expect = "dummy.txt: 1 aaaaa\n\ - dummy.txt: 2 aaaaa\n\ - dummy.txt: 3 aaaaa\n\ - dummy.txt: 4 bbbbb\n\ - dummy.txt: 5 ccccc\n\ - dummy.txt: 6 xxxxx\n\ - \x20 ...\n"; - - let expect_g1 = "dummy.txt:1 aaaaa\n\ - dummy.txt:2 aaaaa\n\ - dummy.txt:3 aaaaa\n\ - dummy.txt:4 bbbbb\n\ - dummy.txt:5 ccccc\n\ - dummy.txt:6 xxxxx\n\ - \x20 ...\n"; - - let expect2 = "dummy.txt: 9 ddd__eee_\n\ - \x20 ^~~ ^~~\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^~\n"; - - - let expect_end = "dummy.txt: 1 aaaaa\n\ - \x20 ...\n\ - dummy.txt: 7 yyyyy\n\ - \x20 ^\n\ - \x20 ...\n\ - dummy.txt: 9 ddd__eee_\n\ - \x20 ^ ^\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^\n"; - - let expect0_end = "dummy.txt: 5 ccccc\n\ - dummy.txt: 6 xxxxx\n\ - dummy.txt: 7 yyyyy\n\ - \x20 ^\n\ - \x20 ...\n\ - dummy.txt: 9 ddd__eee_\n\ - \x20 ^ ^\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^\n"; - - let expect_end_g1 = "dummy.txt:1 aaaaa\n\ - \x20 ...\n\ - dummy.txt:7 yyyyy\n\ - \x20 ^\n"; - - let expect2_end = "dummy.txt: 9 ddd__eee_\n\ - \x20 ^ ^\n\ - \x20 ...\n\ - dummy.txt:11 __f_gg\n\ - \x20 ^ ^\n"; - - let expect_groups = [expect2, expect_g1]; - let expect_end_groups = [expect2_end, expect_end_g1]; - let spans = vec![sp3, sp1, sp4, sp2, sp5]; + let expect0 = &r#" + --> dummy.txt:5:1 +5 |> ccccc + |> ^^^^^ +... +8 |> _____ +9 |> ddd__eee_ + |> ^^^ ^^^ +10 |> elided +11 |> __f_gg + |> ^ ^^ +"#[1..]; + + let expect = &r#" + --> dummy.txt:1:1 +1 |> aaaaa + |> ^^^^^ +... +8 |> _____ +9 |> ddd__eee_ + |> ^^^ ^^^ +10 |> elided +11 |> __f_gg + |> ^ ^^ +"#[1..]; macro_rules! test { ($expected: expr, $highlight: expr) => ({ @@ -1034,37 +731,14 @@ mod test { }); } - let msp0 = MultiSpan { spans: vec![sp0, sp2, sp3, sp4, sp5] }; - let msp = MultiSpan { spans: vec![sp1, sp2, sp3, sp4, sp5] }; - let msp2 = MultiSpan { spans: vec![sp2, sp3, sp4, sp5] }; + let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]); + let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]); test!(expect0, || { diag.highlight_lines(&msp0, Level::Error).unwrap(); }); - test!(expect0_end, || { - diag.end_highlight_lines(&msp0, Level::Error).unwrap(); - }); test!(expect, || { diag.highlight_lines(&msp, Level::Error).unwrap(); }); - test!(expect_end, || { - diag.end_highlight_lines(&msp, Level::Error).unwrap(); - }); - test!(expect2, || { - diag.highlight_lines(&msp2, Level::Error).unwrap(); - }); - test!(expect2_end, || { - diag.end_highlight_lines(&msp2, Level::Error).unwrap(); - }); - for (msp, expect) in cm.group_spans(spans.clone()).iter().zip(expect_groups.iter()) { - test!(expect, || { - diag.highlight_lines(&msp, Level::Error).unwrap(); - }); - } - for (msp, expect) in cm.group_spans(spans.clone()).iter().zip(expect_end_groups.iter()) { - test!(expect, || { - diag.end_highlight_lines(&msp, Level::Error).unwrap(); - }); - } } } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 792828b3054e9..abbc4eef7bf81 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -13,7 +13,7 @@ pub use errors::emitter::ColorConfig; use self::Level::*; use self::RenderSpan::*; -use codemap::{self, CodeMap, MultiSpan}; +use codemap::{self, CodeMap, MultiSpan, NO_EXPANSION, Span}; use diagnostics; use errors::emitter::{Emitter, EmitterWriter}; @@ -24,6 +24,7 @@ use term; pub mod emitter; pub mod json; +pub mod snippet; #[derive(Clone)] pub enum RenderSpan { @@ -32,13 +33,6 @@ pub enum RenderSpan { /// the source code covered by the span. FullSpan(MultiSpan), - /// Similar to a FullSpan, but the cited position is the end of - /// the span, instead of the start. Used, at least, for telling - /// compiletest/runtest to look at the last line of the span - /// (since `end_highlight_lines` displays an arrow to the end - /// of the span). - EndSpan(MultiSpan), - /// A suggestion renders with both with an initial line for the /// message, prefixed by file:linenum, followed by a summary /// of hypothetical source code, where each `String` is spliced @@ -61,7 +55,6 @@ impl RenderSpan { match *self { FullSpan(ref msp) | Suggestion(CodeSuggestion { ref msp, .. }) | - EndSpan(ref msp) | FileLine(ref msp) => msp } @@ -88,12 +81,24 @@ impl CodeSuggestion { } } } - let bounds = self.msp.to_span_bounds(); - let lines = cm.span_to_lines(bounds).unwrap(); - assert!(!lines.lines.is_empty()); - // This isn't strictly necessary, but would in all likelyhood be an error - assert_eq!(self.msp.spans.len(), self.substitutes.len()); + let mut primary_spans = self.msp.primary_spans().to_owned(); + + assert_eq!(primary_spans.len(), self.substitutes.len()); + if primary_spans.is_empty() { + return format!(""); + } + + // Assumption: all spans are in the same file, and all spans + // are disjoint. Sort in ascending order. + primary_spans.sort_by_key(|sp| sp.lo); + + // Find the bounding span. + let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap(); + let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap(); + let bounding_span = Span { lo: lo, hi: hi, expn_id: NO_EXPANSION }; + let lines = cm.span_to_lines(bounding_span).unwrap(); + assert!(!lines.lines.is_empty()); // To build up the result, we do this for each span: // - push the line segment trailing the previous span @@ -105,13 +110,13 @@ impl CodeSuggestion { // // Finally push the trailing line segment of the last span let fm = &lines.file; - let mut prev_hi = cm.lookup_char_pos(bounds.lo); + let mut prev_hi = cm.lookup_char_pos(bounding_span.lo); prev_hi.col = CharPos::from_usize(0); let mut prev_line = fm.get_line(lines.lines[0].line_index); let mut buf = String::new(); - for (sp, substitute) in self.msp.spans.iter().zip(self.substitutes.iter()) { + for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) { let cur_lo = cm.lookup_char_pos(sp.lo); if prev_hi.line == cur_lo.line { push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo)); @@ -183,7 +188,7 @@ pub struct DiagnosticBuilder<'a> { level: Level, message: String, code: Option, - span: Option, + span: MultiSpan, children: Vec, } @@ -192,7 +197,7 @@ pub struct DiagnosticBuilder<'a> { struct SubDiagnostic { level: Level, message: String, - span: Option, + span: MultiSpan, render_span: Option, } @@ -228,37 +233,61 @@ impl<'a> DiagnosticBuilder<'a> { self.level == Level::Fatal } - pub fn note(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, None, None); + /// Add a span/label to be included in the resulting snippet. + /// This is pushed onto the `MultiSpan` that was created when the + /// diagnostic was first built. If you don't call this function at + /// all, and you just supplied a `Span` to create the diagnostic, + /// then the snippet will just include that `Span`, which is + /// called the primary span. + pub fn span_label(mut self, span: Span, label: &fmt::Display) + -> DiagnosticBuilder<'a> { + self.span.push_span_label(span, format!("{}", label)); + self + } + + pub fn note_expected_found(mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display) + -> DiagnosticBuilder<'a> + { + // For now, just attach these as notes + self.note(&format!("expected {} `{}`", label, expected)); + self.note(&format!(" found {} `{}`", label, found)); + self + } + + pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, MultiSpan::new(), None); self } pub fn span_note>(&mut self, sp: S, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, Some(sp.into()), None); + self.sub(Level::Note, msg, sp.into(), None); self } pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, None, None); + self.sub(Level::Warning, msg, MultiSpan::new(), None); self } pub fn span_warn>(&mut self, sp: S, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, Some(sp.into()), None); + self.sub(Level::Warning, msg, sp.into(), None); self } pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, None, None); + self.sub(Level::Help, msg, MultiSpan::new(), None); self } pub fn span_help>(&mut self, sp: S, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, Some(sp.into()), None); + self.sub(Level::Help, msg, sp.into(), None); self } /// Prints out a message with a suggested edit of the code. @@ -269,43 +298,15 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, suggestion: String) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, None, Some(Suggestion(CodeSuggestion { + self.sub(Level::Help, msg, MultiSpan::new(), Some(Suggestion(CodeSuggestion { msp: sp.into(), substitutes: vec![suggestion], }))); self } - pub fn span_end_note>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, None, Some(EndSpan(sp.into()))); - self - } - pub fn fileline_warn>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, None, Some(FileLine(sp.into()))); - self - } - pub fn fileline_note>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, None, Some(FileLine(sp.into()))); - self - } - pub fn fileline_help>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, None, Some(FileLine(sp.into()))); - self - } - pub fn span>(&mut self, sp: S) -> &mut Self { - self.span = Some(sp.into()); + pub fn set_span>(&mut self, sp: S) -> &mut Self { + self.span = sp.into(); self } @@ -324,7 +325,7 @@ impl<'a> DiagnosticBuilder<'a> { level: level, message: message.to_owned(), code: None, - span: None, + span: MultiSpan::new(), children: vec![], } } @@ -334,7 +335,7 @@ impl<'a> DiagnosticBuilder<'a> { fn sub(&mut self, level: Level, message: &str, - span: Option, + span: MultiSpan, render_span: Option) { let sub = SubDiagnostic { level: level, @@ -357,7 +358,10 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> { impl<'a> Drop for DiagnosticBuilder<'a> { fn drop(&mut self) { if !self.cancelled() { - self.emitter.borrow_mut().emit(None, "Error constructed but not emitted", None, Bug); + self.emitter.borrow_mut().emit(&MultiSpan::new(), + "Error constructed but not emitted", + None, + Bug); panic!(); } } @@ -412,7 +416,7 @@ impl Handler { msg: &str) -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); - result.span(sp); + result.set_span(sp); if !self.can_emit_warnings { result.cancel(); } @@ -424,7 +428,7 @@ impl Handler { code: &str) -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); - result.span(sp); + result.set_span(sp); result.code(code.to_owned()); if !self.can_emit_warnings { result.cancel(); @@ -444,7 +448,7 @@ impl Handler { -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); - result.span(sp); + result.set_span(sp); result } pub fn struct_span_err_with_code<'a, S: Into>(&'a self, @@ -454,7 +458,7 @@ impl Handler { -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); - result.span(sp); + result.set_span(sp); result.code(code.to_owned()); result } @@ -468,7 +472,7 @@ impl Handler { -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); - result.span(sp); + result.set_span(sp); result } pub fn struct_span_fatal_with_code<'a, S: Into>(&'a self, @@ -478,7 +482,7 @@ impl Handler { -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); - result.span(sp); + result.set_span(sp); result.code(code.to_owned()); result } @@ -499,7 +503,7 @@ impl Handler { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit(Some(&sp.into()), msg, Fatal); + self.emit(&sp.into(), msg, Fatal); self.bump_err_count(); return FatalError; } @@ -508,7 +512,7 @@ impl Handler { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit_with_code(Some(&sp.into()), msg, code, Fatal); + self.emit_with_code(&sp.into(), msg, code, Fatal); self.bump_err_count(); return FatalError; } @@ -516,24 +520,24 @@ impl Handler { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit(Some(&sp.into()), msg, Error); + self.emit(&sp.into(), msg, Error); self.bump_err_count(); } pub fn span_err_with_code>(&self, sp: S, msg: &str, code: &str) { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit_with_code(Some(&sp.into()), msg, code, Error); + self.emit_with_code(&sp.into(), msg, code, Error); self.bump_err_count(); } pub fn span_warn>(&self, sp: S, msg: &str) { - self.emit(Some(&sp.into()), msg, Warning); + self.emit(&sp.into(), msg, Warning); } pub fn span_warn_with_code>(&self, sp: S, msg: &str, code: &str) { - self.emit_with_code(Some(&sp.into()), msg, code, Warning); + self.emit_with_code(&sp.into(), msg, code, Warning); } pub fn span_bug>(&self, sp: S, msg: &str) -> ! { - self.emit(Some(&sp.into()), msg, Bug); + self.emit(&sp.into(), msg, Bug); panic!(ExplicitBug); } pub fn delay_span_bug>(&self, sp: S, msg: &str) { @@ -541,11 +545,11 @@ impl Handler { *delayed = Some((sp.into(), msg.to_string())); } pub fn span_bug_no_panic>(&self, sp: S, msg: &str) { - self.emit(Some(&sp.into()), msg, Bug); + self.emit(&sp.into(), msg, Bug); self.bump_err_count(); } pub fn span_note_without_error>(&self, sp: S, msg: &str) { - self.emit.borrow_mut().emit(Some(&sp.into()), msg, None, Note); + self.emit.borrow_mut().emit(&sp.into(), msg, None, Note); } pub fn span_unimpl>(&self, sp: S, msg: &str) -> ! { self.span_bug(sp, &format!("unimplemented {}", msg)); @@ -554,7 +558,7 @@ impl Handler { if self.treat_err_as_bug { self.bug(msg); } - self.emit.borrow_mut().emit(None, msg, None, Fatal); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Fatal); self.bump_err_count(); FatalError } @@ -562,17 +566,17 @@ impl Handler { if self.treat_err_as_bug { self.bug(msg); } - self.emit.borrow_mut().emit(None, msg, None, Error); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Error); self.bump_err_count(); } pub fn warn(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Warning); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Warning); } pub fn note_without_error(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Note); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Note); } pub fn bug(&self, msg: &str) -> ! { - self.emit.borrow_mut().emit(None, msg, None, Bug); + self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Bug); panic!(ExplicitBug); } pub fn unimpl(&self, msg: &str) -> ! { @@ -614,25 +618,20 @@ impl Handler { panic!(self.fatal(&s)); } pub fn emit(&self, - msp: Option<&MultiSpan>, + msp: &MultiSpan, msg: &str, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(msp, msg, None, lvl); + self.emit.borrow_mut().emit(&msp, msg, None, lvl); if !self.continue_after_error.get() { self.abort_if_errors(); } } pub fn emit_with_code(&self, - msp: Option<&MultiSpan>, + msp: &MultiSpan, msg: &str, code: &str, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(msp, msg, Some(code), lvl); - if !self.continue_after_error.get() { self.abort_if_errors(); } - } - pub fn custom_emit(&self, rsp: RenderSpan, msg: &str, lvl: Level) { - if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().custom_emit(&rsp, msg, lvl); + self.emit.borrow_mut().emit(&msp, msg, Some(code), lvl); if !self.continue_after_error.get() { self.abort_if_errors(); } } } From d9a947ce8fd4f53b7a273b39a84a7af0fe34d2c5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 15:00:05 -0400 Subject: [PATCH 53/97] use new `note_expected_found` API This API pulls the "expected type foo, found type bar" out after the main snippet. There are some other places where it makes sense, but this is a start. --- src/librustc/infer/error_reporting.rs | 38 ++++++++++++------------ src/librustc_typeck/check/_match.rs | 4 +-- src/librustc_typeck/check/intrinsic.rs | 5 +--- src/librustc_typeck/check/wfcheck.rs | 3 +- src/librustc_typeck/collect.rs | 5 ++-- src/librustc_typeck/lib.rs | 40 ++++++++++++++------------ 6 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index abc6ff4a294e3..88972beb31b09 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -249,12 +249,12 @@ pub trait ErrorReporting<'tcx> { terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx>; - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option; + fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)>; fn expected_found_str + TypeFoldable<'tcx>>( &self, exp_found: &ty::error::ExpectedFound) - -> Option; + -> Option<(String, String)>; fn report_concrete_failure(&self, origin: SubregionOrigin<'tcx>, @@ -535,7 +535,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { - let expected_found_str = match self.values_str(&trace.values) { + let (expected, found) = match self.values_str(&trace.values) { Some(v) => v, None => { return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */ @@ -548,18 +548,17 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { false }; - let expected_found_str = if is_simple_error { - expected_found_str - } else { - format!("{} ({})", expected_found_str, terr) - }; - let mut err = struct_span_err!(self.tcx.sess, trace.origin.span(), E0308, - "{}: {}", - trace.origin, - expected_found_str); + "{}", + trace.origin); + + if !is_simple_error { + err = err.note_expected_found(&"type", &expected, &found); + } + + err = err.span_label(trace.origin.span(), &terr); self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span()); @@ -574,6 +573,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { }, _ => () } + err } @@ -631,7 +631,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived /// error. - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option { + fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { match *values { infer::Types(ref exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), @@ -642,7 +642,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn expected_found_str + TypeFoldable<'tcx>>( &self, exp_found: &ty::error::ExpectedFound) - -> Option + -> Option<(String, String)> { let expected = exp_found.expected.resolve(self); if expected.references_error() { @@ -654,9 +654,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { return None; } - Some(format!("expected `{}`, found `{}`", - expected, - found)) + Some((format!("{}", expected), format!("{}", found))) } fn report_generic_bound_failure(&self, @@ -1751,11 +1749,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { }; match self.values_str(&trace.values) { - Some(values_str) => { + Some((expected, found)) => { err.span_note( trace.origin.span(), - &format!("...so that {} ({})", - desc, values_str)); + &format!("...so that {} (expected {}, found {})", + desc, expected, found)); } None => { // Really should avoid printing this error at diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a7a04f4a85fe8..544fb117f3614 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -116,8 +116,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // Check that the types of the end-points can be unified. let types_unify = require_same_types( - tcx, Some(fcx.infcx()), false, pat.span, rhs_ty, lhs_ty, - || "mismatched types in range".to_string() + tcx, Some(fcx.infcx()), false, pat.span, rhs_ty, lhs_ty, + "mismatched types in range", ); // It's ok to return without a message as `require_same_types` prints an error. diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index eae0cfb0f2267..b71ee8722ab60 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -61,10 +61,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &TyCtxt<'tcx>, it: &hir::ForeignItem, it.span, i_ty.ty, fty, - || { - format!("intrinsic has wrong type: expected `{}`", - fty) - }); + "intrinsic has wrong type"); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 3bfd53ceadae8..492dbce9bdf45 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -418,8 +418,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let _ = ::require_same_types( fcx.tcx(), Some(fcx.infcx()), false, span, sig.inputs[0], rcvr_ty, - || "mismatched method receiver".to_owned() - ); + "mismatched method receiver"); } fn check_variances_for_type_defn(&self, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ffcf427715667..51534a46ddac3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1044,8 +1044,9 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>, -> ty::AdtDefMaster<'tcx> { fn print_err(tcx: &TyCtxt, span: Span, ty: ty::Ty, cv: ConstVal) { - span_err!(tcx.sess, span, E0079, "mismatched types: expected `{}` got `{}`", - ty, cv.description()); + struct_span_err!(tcx.sess, span, E0079, "mismatched types") + .note_expected_found(&"type", &ty, &format!("{}", cv.description())) + .emit(); } fn evaluate_disr_expr<'tcx>(tcx: &TyCtxt<'tcx>, repr_ty: attr::IntType, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 7f27d10ce1ec3..c51304120a89c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -185,15 +185,14 @@ fn require_c_abi_if_variadic(tcx: &TyCtxt, } } -fn require_same_types<'a, 'tcx, M>(tcx: &TyCtxt<'tcx>, - maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>, - t1_is_expected: bool, - span: Span, - t1: Ty<'tcx>, - t2: Ty<'tcx>, - msg: M) - -> bool where - M: FnOnce() -> String, +fn require_same_types<'a, 'tcx>(tcx: &TyCtxt<'tcx>, + maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>, + t1_is_expected: bool, + span: Span, + t1: Ty<'tcx>, + t2: Ty<'tcx>, + msg: &str) + -> bool { let result = match maybe_infcx { None => { @@ -208,7 +207,17 @@ fn require_same_types<'a, 'tcx, M>(tcx: &TyCtxt<'tcx>, match result { Ok(_) => true, Err(ref terr) => { - let mut err = struct_span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr); + let mut err = struct_span_err!(tcx.sess, span, E0211, "{}", msg); + err = err.span_label(span, &terr); + let (mut expected_ty, mut found_ty) = + if t1_is_expected {(t1, t2)} else {(t2, t1)}; + if let Some(infcx) = maybe_infcx { + expected_ty = infcx.resolve_type_vars_if_possible(&expected_ty); + found_ty = infcx.resolve_type_vars_if_possible(&found_ty); + } + err = err.note_expected_found(&"type", + &expected_ty, + &found_ty); tcx.note_and_explain_type_err(&mut err, terr, span); err.emit(); false @@ -250,10 +259,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, }); require_same_types(tcx, None, false, main_span, main_t, se_ty, - || { - format!("main function expects type: `{}`", - se_ty) - }); + "main function has wrong type"); } _ => { span_bug!(main_span, @@ -301,11 +307,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, }); require_same_types(tcx, None, false, start_span, start_t, se_ty, - || { - format!("start function expects type: `{}`", - se_ty) - }); - + "start function has wrong type"); } _ => { span_bug!(start_span, From e416518e6862335a9c99f4c9dfe23192bac3cab8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:42:13 -0400 Subject: [PATCH 54/97] update test cases to reflect new messages --- src/test/compile-fail/array-not-vector.rs | 14 +-- .../compile-fail/associated-types-eq-3.rs | 7 +- .../compile-fail/associated-types-path-2.rs | 6 +- .../compile-fail/augmented-assignments.rs | 4 +- src/test/compile-fail/bad-const-type.rs | 7 +- src/test/compile-fail/bad-main.rs | 2 +- src/test/compile-fail/binop-move-semantics.rs | 2 + .../block-must-not-have-result-while.rs | 7 +- .../borrowck/borrowck-box-insensitivity.rs | 46 +++++--- .../borrowck/borrowck-closures-mut-of-imm.rs | 2 +- .../borrowck/borrowck-closures-unique.rs | 2 +- .../borrowck/borrowck-lend-flow-loop.rs | 1 + .../borrowck-mut-borrow-linear-errors.rs | 1 + .../borrowck-report-with-custom-diagnostic.rs | 15 ++- src/test/compile-fail/closure-wrong-kind.rs | 2 +- src/test/compile-fail/coerce-mut.rs | 4 +- src/test/compile-fail/coercion-slice.rs | 7 +- src/test/compile-fail/cross-borrow-trait.rs | 7 +- .../compile-fail/default_ty_param_conflict.rs | 3 + .../default_ty_param_conflict_cross_crate.rs | 6 +- .../compile-fail/destructure-trait-ref.rs | 21 ++-- src/test/compile-fail/dst-bad-assign.rs | 7 +- src/test/compile-fail/dst-bad-coerce4.rs | 7 +- .../explicit-self-lifetime-mismatch.rs | 8 +- src/test/compile-fail/extern-main-fn.rs | 2 +- src/test/compile-fail/fn-item-type.rs | 20 ++-- src/test/compile-fail/fn-trait-formatting.rs | 21 ++-- .../fully-qualified-type-name1.rs | 7 +- .../fully-qualified-type-name2.rs | 7 +- .../fully-qualified-type-name4.rs | 7 +- .../generic-type-params-name-repr.rs | 42 +++---- src/test/compile-fail/if-branch-types.rs | 3 +- src/test/compile-fail/if-let-arm-types.rs | 3 + .../compile-fail/if-without-else-result.rs | 7 +- .../integer-literal-suffix-inference.rs | 108 ++++++------------ .../integral-variable-unification-error.rs | 7 +- src/test/compile-fail/issue-10176.rs | 7 +- src/test/compile-fail/issue-11319.rs | 9 +- src/test/compile-fail/issue-12997-2.rs | 7 +- src/test/compile-fail/issue-13359.rs | 6 +- src/test/compile-fail/issue-13466.rs | 14 +-- src/test/compile-fail/issue-13482-2.rs | 7 +- src/test/compile-fail/issue-13482.rs | 4 +- src/test/compile-fail/issue-13624.rs | 14 +-- src/test/compile-fail/issue-14091.rs | 7 +- src/test/compile-fail/issue-14541.rs | 7 +- src/test/compile-fail/issue-15783.rs | 7 +- src/test/compile-fail/issue-15896.rs | 7 +- src/test/compile-fail/issue-16338.rs | 7 +- src/test/compile-fail/issue-16401.rs | 7 +- src/test/compile-fail/issue-17033.rs | 7 +- src/test/compile-fail/issue-17263.rs | 14 ++- src/test/compile-fail/issue-17283.rs | 21 ++-- src/test/compile-fail/issue-17728.rs | 3 + src/test/compile-fail/issue-17740.rs | 8 +- src/test/compile-fail/issue-19109.rs | 9 +- src/test/compile-fail/issue-19991.rs | 7 +- src/test/compile-fail/issue-24036.rs | 6 + src/test/compile-fail/issue-24357.rs | 4 +- src/test/compile-fail/issue-24446.rs | 2 +- src/test/compile-fail/issue-26480.rs | 1 + src/test/compile-fail/issue-27008.rs | 7 +- src/test/compile-fail/issue-29084.rs | 5 +- src/test/compile-fail/issue-2951.rs | 7 +- src/test/compile-fail/issue-3477.rs | 3 +- src/test/compile-fail/issue-3680.rs | 7 +- src/test/compile-fail/issue-4201.rs | 7 +- src/test/compile-fail/issue-4517.rs | 7 +- src/test/compile-fail/issue-4968.rs | 7 +- src/test/compile-fail/issue-5100.rs | 40 +++---- src/test/compile-fail/issue-5358-1.rs | 7 +- src/test/compile-fail/issue-5500.rs | 7 +- src/test/compile-fail/issue-7061.rs | 7 +- src/test/compile-fail/issue-7092.rs | 9 +- src/test/compile-fail/issue-7867.rs | 21 ++-- src/test/compile-fail/issue-9575.rs | 2 +- src/test/compile-fail/main-wrong-type-2.rs | 2 +- src/test/compile-fail/main-wrong-type.rs | 2 +- src/test/compile-fail/match-range-fail.rs | 3 +- src/test/compile-fail/match-struct.rs | 7 +- src/test/compile-fail/match-vec-mismatch-2.rs | 7 +- src/test/compile-fail/method-self-arg-1.rs | 14 +-- ...ased-on-type-distribute-copy-over-paren.rs | 8 +- .../moves-based-on-type-match-bindings.rs | 2 + .../compile-fail/mut-pattern-mismatched.rs | 8 +- src/test/compile-fail/noexporttypeexe.rs | 7 +- src/test/compile-fail/occurs-check-2.rs | 4 +- src/test/compile-fail/occurs-check.rs | 4 +- .../compile-fail/pattern-error-continue.rs | 10 +- src/test/compile-fail/pptypedef.rs | 6 +- src/test/compile-fail/ptr-coercion.rs | 12 +- src/test/compile-fail/ref-suggestion.rs | 6 - src/test/compile-fail/regions-bounds.rs | 8 +- .../regions-early-bound-error-method.rs | 4 +- .../regions-fn-subtyping-return-static.rs | 7 +- .../compile-fail/regions-infer-not-param.rs | 8 +- .../regions-infer-paramd-indirect.rs | 4 +- .../reject-specialized-drops-8142.rs | 4 +- src/test/compile-fail/repeat_count.rs | 41 +++---- .../compile-fail/shift-various-bad-types.rs | 3 +- src/test/compile-fail/slice-mut.rs | 4 +- .../slightly-nice-generic-literal-messages.rs | 7 +- .../compile-fail/struct-base-wrong-type-2.rs | 14 +-- .../compile-fail/struct-base-wrong-type.rs | 14 +-- .../structure-constructor-type-mismatch.rs | 18 +-- src/test/compile-fail/substs-ppaux.rs | 32 +++--- src/test/compile-fail/suppressed-error.rs | 7 +- .../tag-that-dare-not-speak-its-name.rs | 7 +- src/test/compile-fail/terr-in-field.rs | 7 +- src/test/compile-fail/terr-sorts.rs | 7 +- .../compile-fail/token-error-correct-3.rs | 3 + .../compile-fail/trait-bounds-cant-coerce.rs | 7 +- src/test/compile-fail/tuple-arity-mismatch.rs | 14 +-- .../tutorial-suffix-inference-test.rs | 9 +- .../compile-fail/type-mismatch-multiple.rs | 10 +- .../type-mismatch-same-crate-name.rs | 16 ++- src/test/compile-fail/type-parameter-names.rs | 7 +- .../type-params-in-different-spaces-1.rs | 7 +- .../typeck_type_placeholder_mismatch.rs | 14 +-- .../compile-fail/ufcs-explicit-self-bad.rs | 8 +- src/test/compile-fail/variadic-ffi-3.rs | 14 +-- 121 files changed, 534 insertions(+), 630 deletions(-) diff --git a/src/test/compile-fail/array-not-vector.rs b/src/test/compile-fail/array-not-vector.rs index 6c9b8f81b2faf..1bbccae53a44d 100644 --- a/src/test/compile-fail/array-not-vector.rs +++ b/src/test/compile-fail/array-not-vector.rs @@ -11,16 +11,14 @@ fn main() { let _x: i32 = [1, 2, 3]; //~^ ERROR mismatched types - //~| expected `i32` - //~| found `[_; 3]` - //~| expected i32 - //~| found array of 3 elements + //~| expected type `i32` + //~| found type `[_; 3]` + //~| expected i32, found array of 3 elements let x: &[i32] = &[1, 2, 3]; let _y: &i32 = x; //~^ ERROR mismatched types - //~| expected `&i32` - //~| found `&[i32]` - //~| expected i32 - //~| found slice + //~| expected type `&i32` + //~| found type `&[i32]` + //~| expected i32, found slice } diff --git a/src/test/compile-fail/associated-types-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs index f01f2b111c5c1..8c66160e8a36f 100644 --- a/src/test/compile-fail/associated-types-eq-3.rs +++ b/src/test/compile-fail/associated-types-eq-3.rs @@ -32,10 +32,9 @@ fn foo1>(x: I) { fn foo2(x: I) { let _: Bar = x.boo(); //~^ ERROR mismatched types - //~| expected `Bar` - //~| found `::A` - //~| expected struct `Bar` - //~| found associated type + //~| expected type `Bar` + //~| found type `::A` + //~| expected struct `Bar`, found associated type } diff --git a/src/test/compile-fail/associated-types-path-2.rs b/src/test/compile-fail/associated-types-path-2.rs index 68fba56427cc5..cdb7dff692c14 100644 --- a/src/test/compile-fail/associated-types-path-2.rs +++ b/src/test/compile-fail/associated-types-path-2.rs @@ -28,8 +28,7 @@ pub fn f2(a: T) -> T::A { pub fn f1_int_int() { f1(2i32, 4i32); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `i32` + //~| expected u32, found i32 } pub fn f1_int_uint() { @@ -49,8 +48,7 @@ pub fn f1_uint_int() { pub fn f2_int() { let _: i32 = f2(2i32); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `u32` + //~| expected i32, found u32 } pub fn main() { } diff --git a/src/test/compile-fail/augmented-assignments.rs b/src/test/compile-fail/augmented-assignments.rs index 221015d512062..8ac6b419295ee 100644 --- a/src/test/compile-fail/augmented-assignments.rs +++ b/src/test/compile-fail/augmented-assignments.rs @@ -21,8 +21,10 @@ impl AddAssign for Int { fn main() { let mut x = Int(1); x //~ error: use of moved value: `x` + //~^ value used here after move + //~| note: move occurs because `x` has type `Int` += - x; //~ note: `x` moved here because it has type `Int`, which is non-copyable + x; //~ value moved here let y = Int(2); y //~ error: cannot borrow immutable local variable `y` as mutable diff --git a/src/test/compile-fail/bad-const-type.rs b/src/test/compile-fail/bad-const-type.rs index f05c8c31f1024..ee6ac33072792 100644 --- a/src/test/compile-fail/bad-const-type.rs +++ b/src/test/compile-fail/bad-const-type.rs @@ -10,8 +10,7 @@ static i: String = 10; //~^ ERROR mismatched types -//~| expected `std::string::String` -//~| found `_` -//~| expected struct `std::string::String` -//~| found integral variable +//~| expected type `std::string::String` +//~| found type `_` +//~| expected struct `std::string::String`, found integral variable fn main() { println!("{}", i); } diff --git a/src/test/compile-fail/bad-main.rs b/src/test/compile-fail/bad-main.rs index 321dca8989134..1253f7569e7e8 100644 --- a/src/test/compile-fail/bad-main.rs +++ b/src/test/compile-fail/bad-main.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main(x: isize) { } //~ ERROR: main function expects type +fn main(x: isize) { } //~ ERROR: main function has wrong type diff --git a/src/test/compile-fail/binop-move-semantics.rs b/src/test/compile-fail/binop-move-semantics.rs index cff0064497aff..0cc6ea3e984d9 100644 --- a/src/test/compile-fail/binop-move-semantics.rs +++ b/src/test/compile-fail/binop-move-semantics.rs @@ -62,6 +62,7 @@ fn mut_plus_immut() { &mut f + &f; //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable + //~^ cannot borrow `f` as immutable because it is also borrowed as mutable } fn immut_plus_mut() { @@ -70,6 +71,7 @@ fn immut_plus_mut() { &f + &mut f; //~ ERROR: cannot borrow `f` as mutable because it is also borrowed as immutable + //~^ cannot borrow `f` as mutable because it is also borrowed as immutable } fn main() {} diff --git a/src/test/compile-fail/block-must-not-have-result-while.rs b/src/test/compile-fail/block-must-not-have-result-while.rs index ba6340ed395ee..a0fb470e1e4d0 100644 --- a/src/test/compile-fail/block-must-not-have-result-while.rs +++ b/src/test/compile-fail/block-must-not-have-result-while.rs @@ -11,9 +11,8 @@ fn main() { while true { true //~ ERROR mismatched types - //~| expected `()` - //~| found `bool` - //~| expected () - //~| found bool + //~| expected type `()` + //~| found type `bool` + //~| expected (), found bool } } diff --git a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs index 7c3d632078fe2..bde3212c5bc63 100644 --- a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs +++ b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs @@ -33,22 +33,28 @@ struct D { fn copy_after_move() { let a: Box<_> = box A { x: box 0, y: 1 }; let _x = a.x; + //~^ value moved here let _y = a.y; //~ ERROR use of moved - //~^^ NOTE `a` moved here (through moving `a.x`) + //~^ move occurs because `a.x` has type `Box` + //~| value used here after move } fn move_after_move() { let a: Box<_> = box B { x: box 0, y: box 1 }; let _x = a.x; + //~^ value moved here let _y = a.y; //~ ERROR use of moved - //~^^ NOTE `a` moved here (through moving `a.x`) + //~^ move occurs because `a.x` has type `Box` + //~| value used here after move } fn borrow_after_move() { let a: Box<_> = box A { x: box 0, y: 1 }; let _x = a.x; + //~^ value moved here let _y = &a.y; //~ ERROR use of moved - //~^^ NOTE `a` moved here (through moving `a.x`) + //~^ move occurs because `a.x` has type `Box` + //~| value used here after move } fn move_after_borrow() { @@ -75,44 +81,52 @@ fn move_after_mut_borrow() { fn borrow_after_mut_borrow() { let mut a: Box<_> = box A { x: box 0, y: 1 }; let _x = &mut a.x; - //~^ NOTE previous borrow of `a` occurs here (through borrowing `a.x`); + //~^ NOTE mutable borrow occurs here (via `a.x`) let _y = &a.y; //~ ERROR cannot borrow + //~^ immutable borrow occurs here (via `a.y`) } -//~^ NOTE previous borrow ends here +//~^ NOTE mutable borrow ends here fn mut_borrow_after_borrow() { let mut a: Box<_> = box A { x: box 0, y: 1 }; let _x = &a.x; - //~^ NOTE previous borrow of `a` occurs here (through borrowing `a.x`) + //~^ NOTE immutable borrow occurs here (via `a.x`) let _y = &mut a.y; //~ ERROR cannot borrow + //~^ mutable borrow occurs here (via `a.y`) } -//~^ NOTE previous borrow ends here +//~^ NOTE immutable borrow ends here fn copy_after_move_nested() { let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; let _x = a.x.x; - //~^ NOTE `a.x.x` moved here because it has type `Box`, which is moved by default + //~^ value moved here let _y = a.y; //~ ERROR use of collaterally moved + //~^ NOTE move occurs because `a.x.x` has type `Box` + //~| value used here after move } fn move_after_move_nested() { let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; let _x = a.x.x; - //~^ NOTE `a.x.x` moved here because it has type `Box`, which is moved by default + //~^ value moved here let _y = a.y; //~ ERROR use of collaterally moved + //~^ NOTE move occurs because `a.x.x` has type `Box` + //~| value used here after move } fn borrow_after_move_nested() { let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; let _x = a.x.x; - //~^ NOTE `a.x.x` moved here because it has type `Box`, which is moved by default + //~^ value moved here let _y = &a.y; //~ ERROR use of collaterally moved + //~^ NOTE move occurs because `a.x.x` has type `Box` + //~| value used here after move } fn move_after_borrow_nested() { let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; let _x = &a.x.x; - //~^ NOTE borrow of `a.x.x` occurs here + //~^ borrow of `a.x.x` occurs here let _y = a.y; //~ ERROR cannot move } @@ -133,18 +147,20 @@ fn move_after_mut_borrow_nested() { fn borrow_after_mut_borrow_nested() { let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; let _x = &mut a.x.x; - //~^ NOTE previous borrow of `a.x.x` occurs here; the mutable borrow prevents + //~^ mutable borrow occurs here let _y = &a.y; //~ ERROR cannot borrow + //~^ immutable borrow occurs here } -//~^ NOTE previous borrow ends here +//~^ NOTE mutable borrow ends here fn mut_borrow_after_borrow_nested() { let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; let _x = &a.x.x; - //~^ NOTE previous borrow of `a.x.x` occurs here; the immutable borrow prevents + //~^ immutable borrow occurs here let _y = &mut a.y; //~ ERROR cannot borrow + //~^ mutable borrow occurs here } -//~^ NOTE previous borrow ends here +//~^ NOTE immutable borrow ends here fn main() { copy_after_move(); diff --git a/src/test/compile-fail/borrowck/borrowck-closures-mut-of-imm.rs b/src/test/compile-fail/borrowck/borrowck-closures-mut-of-imm.rs index 40f9be2dd8230..dc2f0e8395f08 100644 --- a/src/test/compile-fail/borrowck/borrowck-closures-mut-of-imm.rs +++ b/src/test/compile-fail/borrowck/borrowck-closures-mut-of-imm.rs @@ -24,7 +24,7 @@ fn a(x: &isize) { //~^ ERROR cannot borrow let c2 = || set(&mut *x); //~^ ERROR cannot borrow - //~| ERROR closure requires unique access + //~| ERROR two closures require unique access to `x` at the same time } fn main() { diff --git a/src/test/compile-fail/borrowck/borrowck-closures-unique.rs b/src/test/compile-fail/borrowck/borrowck-closures-unique.rs index 3646a68f06fd7..1b22dc4d2c6af 100644 --- a/src/test/compile-fail/borrowck/borrowck-closures-unique.rs +++ b/src/test/compile-fail/borrowck/borrowck-closures-unique.rs @@ -39,7 +39,7 @@ fn c(x: &mut isize) { fn d(x: &mut isize) { let c1 = || set(x); - let c2 = || set(x); //~ ERROR closure requires unique access to `x` + let c2 = || set(x); //~ ERROR two closures require unique access to `x` at the same time } fn e(x: &mut isize) { diff --git a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs index f09e7ffd7e4b7..56cbe0b187867 100644 --- a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs +++ b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs @@ -109,6 +109,7 @@ fn while_aliased_mut_cond(cond: bool, cond2: bool) { borrow(&*v); //~ ERROR cannot borrow if cond2 { x = &mut v; //~ ERROR cannot borrow + //~^ ERROR cannot borrow } } } diff --git a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs index 38e0e27a7b98e..f789d44016eb1 100644 --- a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs +++ b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs @@ -19,6 +19,7 @@ fn main() { match 1 { 1 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time + //~| ERROR cannot borrow `x` as mutable more than once at a time 2 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time _ => { addr = &mut x; } diff --git a/src/test/compile-fail/borrowck/borrowck-report-with-custom-diagnostic.rs b/src/test/compile-fail/borrowck/borrowck-report-with-custom-diagnostic.rs index 2b1ff47ee3d94..3ca8cc431e098 100644 --- a/src/test/compile-fail/borrowck/borrowck-report-with-custom-diagnostic.rs +++ b/src/test/compile-fail/borrowck/borrowck-report-with-custom-diagnostic.rs @@ -13,10 +13,11 @@ fn main() { // Original borrow ends at end of function let mut x = 1; let y = &mut x; - //~^ previous borrow of `x` occurs here; the mutable borrow prevents + //~^ mutable borrow occurs here let z = &x; //~ ERROR cannot borrow + //~^ immutable borrow occurs here } -//~^ NOTE previous borrow ends here +//~^ NOTE mutable borrow ends here fn foo() { match true { @@ -24,10 +25,11 @@ fn foo() { // Original borrow ends at end of match arm let mut x = 1; let y = &x; - //~^ previous borrow of `x` occurs here; the immutable borrow prevents + //~^ immutable borrow occurs here let z = &mut x; //~ ERROR cannot borrow + //~^ mutable borrow occurs here } - //~^ NOTE previous borrow ends here + //~^ NOTE immutable borrow ends here false => () } } @@ -37,8 +39,9 @@ fn bar() { || { let mut x = 1; let y = &mut x; - //~^ previous borrow of `x` occurs here; the mutable borrow prevents + //~^ first mutable borrow occurs here let z = &mut x; //~ ERROR cannot borrow + //~^ second mutable borrow occurs here }; - //~^ NOTE previous borrow ends here + //~^ NOTE first borrow ends here } diff --git a/src/test/compile-fail/closure-wrong-kind.rs b/src/test/compile-fail/closure-wrong-kind.rs index 6792414c36790..a387e4c5ece11 100644 --- a/src/test/compile-fail/closure-wrong-kind.rs +++ b/src/test/compile-fail/closure-wrong-kind.rs @@ -17,6 +17,6 @@ fn bar(_: T) {} fn main() { let x = X; - let closure = |_| foo(x); //~ ERROR E0524 + let closure = |_| foo(x); //~ ERROR E0525 bar(closure); } diff --git a/src/test/compile-fail/coerce-mut.rs b/src/test/compile-fail/coerce-mut.rs index 30c1b66a7b81f..634d12441a120 100644 --- a/src/test/compile-fail/coerce-mut.rs +++ b/src/test/compile-fail/coerce-mut.rs @@ -14,7 +14,7 @@ fn main() { let x = 0; f(&x); //~^ ERROR mismatched types - //~| expected `&mut i32` - //~| found `&_` + //~| expected type `&mut i32` + //~| found type `&_` //~| values differ in mutability } diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs index bb4d1693af7e3..bd7e6c2a2131d 100644 --- a/src/test/compile-fail/coercion-slice.rs +++ b/src/test/compile-fail/coercion-slice.rs @@ -13,8 +13,7 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types - //~| expected `&[i32]` - //~| found `[_; 1]` - //~| expected &-ptr - //~| found array of 1 elements + //~| expected type `&[i32]` + //~| found type `[_; 1]` + //~| expected &-ptr, found array of 1 elements } diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index d60fb1d5d1966..ea9a29c0e2ae5 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -19,8 +19,7 @@ pub fn main() { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let x: Box = Box::new(Foo); let _y: &Trait = x; //~ ERROR mismatched types - //~| expected `&Trait` - //~| found `Box` - //~| expected &-ptr - //~| found box + //~| expected type `&Trait` + //~| found type `Box` + //~| expected &-ptr, found box } diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs index 48c5cd1ff7706..4702b504f157d 100644 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ b/src/test/compile-fail/default_ty_param_conflict.rs @@ -23,6 +23,9 @@ fn main() { // Here, F is instantiated with $0=uint let x = foo(); //~^ ERROR: mismatched types + //~| expected type `usize` + //~| found type `isize` + //~| NOTE: conflicting type parameter defaults `usize` and `isize` //~| NOTE: conflicting type parameter defaults `usize` and `isize` //~| NOTE: ...that was applied to an unconstrained type variable here diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs index fc2c49d65affe..b608c6c99be89 100644 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs +++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs @@ -24,7 +24,11 @@ fn main() { //~^ NOTE: ...that also applies to the same type variable here meh(foo); - //~^ ERROR: mismatched types: + //~^ ERROR: mismatched types //~| NOTE: conflicting type parameter defaults `bool` and `char` + //~| NOTE: conflicting type parameter defaults `bool` and `char` + //~| a second default is defined on `default_param_test::bleh` //~| NOTE: ...that was applied to an unconstrained type variable here + //~| expected type `bool` + //~| found type `char` } diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index 68d9795710245..d0a31fbce91ed 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -40,20 +40,17 @@ fn main() { // n > m let &&x = &1isize as &T; //~^ ERROR mismatched types - //~| expected `T` - //~| found `&_` - //~| expected trait T - //~| found &-ptr + //~| expected type `T` + //~| found type `&_` + //~| expected trait T, found &-ptr let &&&x = &(&1isize as &T); //~^ ERROR mismatched types - //~| expected `T` - //~| found `&_` - //~| expected trait T - //~| found &-ptr + //~| expected type `T` + //~| found type `&_` + //~| expected trait T, found &-ptr let box box x = box 1isize as Box; //~^ ERROR mismatched types - //~| expected `T` - //~| found `Box<_>` - //~| expected trait T - //~| found box + //~| expected type `T` + //~| found type `Box<_>` + //~| expected trait T, found box } diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index 2d21d0ebc760b..9e71ad2417792 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -45,9 +45,8 @@ pub fn main() { let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = Bar1 {f: 36}; //~^ ERROR mismatched types - //~| expected `ToBar` - //~| found `Bar1` - //~| expected trait ToBar - //~| found struct `Bar1` + //~| expected type `ToBar` + //~| found type `Bar1` + //~| expected trait ToBar, found struct `Bar1` //~| ERROR `ToBar: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/dst-bad-coerce4.rs b/src/test/compile-fail/dst-bad-coerce4.rs index c1443bdbb309d..9d4d56cf79190 100644 --- a/src/test/compile-fail/dst-bad-coerce4.rs +++ b/src/test/compile-fail/dst-bad-coerce4.rs @@ -19,8 +19,7 @@ pub fn main() { let f1: &Fat<[isize]> = &Fat { ptr: [1, 2, 3] }; let f2: &Fat<[isize; 3]> = f1; //~^ ERROR mismatched types - //~| expected `&Fat<[isize; 3]>` - //~| found `&Fat<[isize]>` - //~| expected array of 3 elements - //~| found slice + //~| expected type `&Fat<[isize; 3]>` + //~| found type `&Fat<[isize]>` + //~| expected array of 3 elements, found slice } diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs index 922e58698dd75..b5432fafb1b85 100644 --- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -16,12 +16,12 @@ struct Foo<'a,'b> { impl<'a,'b> Foo<'a,'b> { fn bar(self: Foo<'b,'a>) {} //~^ ERROR mismatched types - //~| expected `Foo<'a, 'b>` - //~| found `Foo<'b, 'a>` + //~| expected type `Foo<'a, 'b>` + //~| found type `Foo<'b, 'a>` //~| lifetime mismatch //~| ERROR mismatched types - //~| expected `Foo<'a, 'b>` - //~| found `Foo<'b, 'a>` + //~| expected type `Foo<'a, 'b>` + //~| found type `Foo<'b, 'a>` //~| lifetime mismatch } diff --git a/src/test/compile-fail/extern-main-fn.rs b/src/test/compile-fail/extern-main-fn.rs index 05ce3eefda86c..11f299acefa87 100644 --- a/src/test/compile-fail/extern-main-fn.rs +++ b/src/test/compile-fail/extern-main-fn.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern fn main() {} //~ ERROR: main function expects type +extern fn main() {} //~ ERROR: main function has wrong type diff --git a/src/test/compile-fail/fn-item-type.rs b/src/test/compile-fail/fn-item-type.rs index c90a7113f1b41..6217a9f16b935 100644 --- a/src/test/compile-fail/fn-item-type.rs +++ b/src/test/compile-fail/fn-item-type.rs @@ -22,26 +22,22 @@ impl Foo for T { /* `foo` is still default here */ } fn main() { eq(foo::, bar::); //~^ ERROR mismatched types - //~| expected `fn(isize) -> isize {foo::}` - //~| found `fn(isize) -> isize {bar::}` - //~| expected fn item - //~| found a different fn item + //~| expected type `fn(isize) -> isize {foo::}` + //~| found type `fn(isize) -> isize {bar::}` + //~| expected fn item, found a different fn item eq(foo::, foo::); //~^ ERROR mismatched types - //~| expected `fn(isize) -> isize {foo::}` - //~| found `fn(isize) -> isize {foo::}` + //~| expected u8, found i8 eq(bar::, bar::>); //~^ ERROR mismatched types - //~| expected `fn(isize) -> isize {bar::}` - //~| found `fn(isize) -> isize {bar::>}` - //~| expected struct `std::string::String` - //~| found struct `std::vec::Vec` + //~| expected type `fn(isize) -> isize {bar::}` + //~| found type `fn(isize) -> isize {bar::>}` + //~| expected struct `std::string::String`, found struct `std::vec::Vec` // Make sure we distinguish between trait methods correctly. eq(::foo, ::foo); //~^ ERROR mismatched types - //~| expected `fn() {::foo}` - //~| found `fn() {::foo}` + //~| expected u8, found u16 } diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs index 8cbfc520ff449..fd140cd1d391a 100644 --- a/src/test/compile-fail/fn-trait-formatting.rs +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -16,22 +16,19 @@ fn needs_fn(x: F) where F: Fn(isize) -> isize {} fn main() { let _: () = (box |_: isize| {}) as Box; //~^ ERROR mismatched types - //~| expected `()` - //~| found `Box` - //~| expected () - //~| found box + //~| expected type `()` + //~| found type `Box` + //~| expected (), found box let _: () = (box |_: isize, isize| {}) as Box; //~^ ERROR mismatched types - //~| expected `()` - //~| found `Box` - //~| expected () - //~| found box + //~| expected type `()` + //~| found type `Box` + //~| expected (), found box let _: () = (box || -> isize { unimplemented!() }) as Box isize>; //~^ ERROR mismatched types - //~| expected `()` - //~| found `Box isize>` - //~| expected () - //~| found box + //~| expected type `()` + //~| found type `Box isize>` + //~| expected (), found box needs_fn(1); //~^ ERROR : std::ops::Fn<(isize,)>` diff --git a/src/test/compile-fail/fully-qualified-type-name1.rs b/src/test/compile-fail/fully-qualified-type-name1.rs index fb787e8572c20..5ea8ce2264438 100644 --- a/src/test/compile-fail/fully-qualified-type-name1.rs +++ b/src/test/compile-fail/fully-qualified-type-name1.rs @@ -14,8 +14,7 @@ fn main() { let x: Option; x = 5; //~^ ERROR mismatched types - //~| expected `std::option::Option` - //~| found `_` - //~| expected enum `std::option::Option` - //~| found integral variable + //~| expected type `std::option::Option` + //~| found type `_` + //~| expected enum `std::option::Option`, found integral variable } diff --git a/src/test/compile-fail/fully-qualified-type-name2.rs b/src/test/compile-fail/fully-qualified-type-name2.rs index ab542d90800b2..9ba8a11d536be 100644 --- a/src/test/compile-fail/fully-qualified-type-name2.rs +++ b/src/test/compile-fail/fully-qualified-type-name2.rs @@ -21,10 +21,9 @@ mod y { fn bar(x: x::foo) -> y::foo { return x; //~^ ERROR mismatched types - //~| expected `y::foo` - //~| found `x::foo` - //~| expected enum `y::foo` - //~| found enum `x::foo` + //~| expected type `y::foo` + //~| found type `x::foo` + //~| expected enum `y::foo`, found enum `x::foo` } fn main() { diff --git a/src/test/compile-fail/fully-qualified-type-name4.rs b/src/test/compile-fail/fully-qualified-type-name4.rs index 9242849efc746..3c8fde751f123 100644 --- a/src/test/compile-fail/fully-qualified-type-name4.rs +++ b/src/test/compile-fail/fully-qualified-type-name4.rs @@ -15,10 +15,9 @@ use std::option::Option; fn bar(x: usize) -> Option { return x; //~^ ERROR mismatched types - //~| expected `std::option::Option` - //~| found `usize` - //~| expected enum `std::option::Option` - //~| found usize + //~| expected type `std::option::Option` + //~| found type `usize` + //~| expected enum `std::option::Option`, found usize } fn main() { diff --git a/src/test/compile-fail/generic-type-params-name-repr.rs b/src/test/compile-fail/generic-type-params-name-repr.rs index adf9a98a05c2d..71d7cf792e475 100644 --- a/src/test/compile-fail/generic-type-params-name-repr.rs +++ b/src/test/compile-fail/generic-type-params-name-repr.rs @@ -22,46 +22,40 @@ fn main() { // Ensure that the printed type doesn't include the default type params... let _: Foo = (); //~^ ERROR mismatched types - //~| expected `Foo` - //~| found `()` - //~| expected struct `Foo` - //~| found () + //~| expected type `Foo` + //~| found type `()` + //~| expected struct `Foo`, found () // ...even when they're present, but the same types as the defaults. let _: Foo = (); //~^ ERROR mismatched types - //~| expected `Foo` - //~| found `()` - //~| expected struct `Foo` - //~| found () + //~| expected type `Foo` + //~| found type `()` + //~| expected struct `Foo`, found () // Including cases where the default is using previous type params. let _: HashMap = (); //~^ ERROR mismatched types - //~| expected `HashMap` - //~| found `()` - //~| expected struct `HashMap` - //~| found () + //~| expected type `HashMap` + //~| found type `()` + //~| expected struct `HashMap`, found () let _: HashMap> = (); //~^ ERROR mismatched types - //~| expected `HashMap` - //~| found `()` - //~| expected struct `HashMap` - //~| found () + //~| expected type `HashMap` + //~| found type `()` + //~| expected struct `HashMap`, found () // But not when there's a different type in between. let _: Foo = (); //~^ ERROR mismatched types - //~| expected `Foo` - //~| found `()` - //~| expected struct `Foo` - //~| found () + //~| expected type `Foo` + //~| found type `()` + //~| expected struct `Foo`, found () // And don't print <> at all when there's just defaults. let _: Foo = (); //~^ ERROR mismatched types - //~| expected `Foo` - //~| found `()` - //~| expected struct `Foo` - //~| found () + //~| expected type `Foo` + //~| found type `()` + //~| expected struct `Foo`, found () } diff --git a/src/test/compile-fail/if-branch-types.rs b/src/test/compile-fail/if-branch-types.rs index 2c730531b823a..ca9803f66b20d 100644 --- a/src/test/compile-fail/if-branch-types.rs +++ b/src/test/compile-fail/if-branch-types.rs @@ -11,6 +11,5 @@ fn main() { let x = if true { 10i32 } else { 10u32 }; //~^ ERROR if and else have incompatible types - //~| expected `i32` - //~| found `u32` + //~| expected i32, found u32 } diff --git a/src/test/compile-fail/if-let-arm-types.rs b/src/test/compile-fail/if-let-arm-types.rs index d179ec015d231..c7b1e1a62c209 100644 --- a/src/test/compile-fail/if-let-arm-types.rs +++ b/src/test/compile-fail/if-let-arm-types.rs @@ -10,6 +10,9 @@ fn main() { if let Some(b) = None { //~ ERROR: `if let` arms have incompatible types + //~^ expected (), found integral variable + //~| expected type `()` + //~| found type `_` () } else { //~ NOTE: `if let` arm with an incompatible type 1 diff --git a/src/test/compile-fail/if-without-else-result.rs b/src/test/compile-fail/if-without-else-result.rs index a9567f4272f50..e8aa1f70ea1dc 100644 --- a/src/test/compile-fail/if-without-else-result.rs +++ b/src/test/compile-fail/if-without-else-result.rs @@ -11,9 +11,8 @@ fn main() { let a = if true { true }; //~^ ERROR if may be missing an else clause - //~| expected `()` - //~| found `bool` - //~| expected () - //~| found bool + //~| expected type `()` + //~| found type `bool` + //~| expected (), found bool println!("{}", a); } diff --git a/src/test/compile-fail/integer-literal-suffix-inference.rs b/src/test/compile-fail/integer-literal-suffix-inference.rs index a01db18a34a7f..7a850d90a8747 100644 --- a/src/test/compile-fail/integer-literal-suffix-inference.rs +++ b/src/test/compile-fail/integer-literal-suffix-inference.rs @@ -41,168 +41,132 @@ fn main() { id_i8(a8); // ok id_i8(a16); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i16` + //~| expected i8, found i16 id_i8(a32); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i32` + //~| expected i8, found i32 id_i8(a64); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i64` + //~| expected i8, found i64 id_i16(a8); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i8` + //~| expected i16, found i8 id_i16(a16); // ok id_i16(a32); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i32` + //~| expected i16, found i32 id_i16(a64); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i64` + //~| expected i16, found i64 id_i32(a8); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i8` + //~| expected i32, found i8 id_i32(a16); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i16` + //~| expected i32, found i16 id_i32(a32); // ok id_i32(a64); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i64` + //~| expected i32, found i64 id_i64(a8); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i8` + //~| expected i64, found i8 id_i64(a16); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i16` + //~| expected i64, found i16 id_i64(a32); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i32` + //~| expected i64, found i32 id_i64(a64); // ok id_i8(c8); // ok id_i8(c16); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i16` + //~| expected i8, found i16 id_i8(c32); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i32` + //~| expected i8, found i32 id_i8(c64); //~^ ERROR mismatched types - //~| expected `i8` - //~| found `i64` + //~| expected i8, found i64 id_i16(c8); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i8` + //~| expected i16, found i8 id_i16(c16); // ok id_i16(c32); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i32` + //~| expected i16, found i32 id_i16(c64); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `i64` + //~| expected i16, found i64 id_i32(c8); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i8` + //~| expected i32, found i8 id_i32(c16); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i16` + //~| expected i32, found i16 id_i32(c32); // ok id_i32(c64); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i64` + //~| expected i32, found i64 id_i64(a8); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i8` + //~| expected i64, found i8 id_i64(a16); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i16` + //~| expected i64, found i16 id_i64(a32); //~^ ERROR mismatched types - //~| expected `i64` - //~| found `i32` + //~| expected i64, found i32 id_i64(a64); // ok id_u8(b8); // ok id_u8(b16); //~^ ERROR mismatched types - //~| expected `u8` - //~| found `u16` + //~| expected u8, found u16 id_u8(b32); //~^ ERROR mismatched types - //~| expected `u8` - //~| found `u32` + //~| expected u8, found u32 id_u8(b64); //~^ ERROR mismatched types - //~| expected `u8` - //~| found `u64` + //~| expected u8, found u64 id_u16(b8); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `u8` + //~| expected u16, found u8 id_u16(b16); // ok id_u16(b32); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `u32` + //~| expected u16, found u32 id_u16(b64); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `u64` + //~| expected u16, found u64 id_u32(b8); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `u8` + //~| expected u32, found u8 id_u32(b16); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `u16` + //~| expected u32, found u16 id_u32(b32); // ok id_u32(b64); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `u64` + //~| expected u32, found u64 id_u64(b8); //~^ ERROR mismatched types - //~| expected `u64` - //~| found `u8` + //~| expected u64, found u8 id_u64(b16); //~^ ERROR mismatched types - //~| expected `u64` - //~| found `u16` + //~| expected u64, found u16 id_u64(b32); //~^ ERROR mismatched types - //~| expected `u64` - //~| found `u32` + //~| expected u64, found u32 id_u64(b64); // ok } diff --git a/src/test/compile-fail/integral-variable-unification-error.rs b/src/test/compile-fail/integral-variable-unification-error.rs index 3374f715917c2..99f2d25166891 100644 --- a/src/test/compile-fail/integral-variable-unification-error.rs +++ b/src/test/compile-fail/integral-variable-unification-error.rs @@ -12,8 +12,7 @@ fn main() { let mut x = 2; x = 5.0; //~^ ERROR mismatched types - //~| expected `_` - //~| found `_` - //~| expected integral variable - //~| found floating-point variable + //~| expected type `_` + //~| found type `_` + //~| expected integral variable, found floating-point variable } diff --git a/src/test/compile-fail/issue-10176.rs b/src/test/compile-fail/issue-10176.rs index 6e84e777898b6..434b795ff31f5 100644 --- a/src/test/compile-fail/issue-10176.rs +++ b/src/test/compile-fail/issue-10176.rs @@ -11,10 +11,9 @@ fn f() -> isize { (return 1, return 2) //~^ ERROR mismatched types -//~| expected `isize` -//~| found `(_, _)` -//~| expected isize -//~| found tuple +//~| expected type `isize` +//~| found type `(_, _)` +//~| expected isize, found tuple } fn main() {} diff --git a/src/test/compile-fail/issue-11319.rs b/src/test/compile-fail/issue-11319.rs index d3e44b71b1c89..8242fa1c2e979 100644 --- a/src/test/compile-fail/issue-11319.rs +++ b/src/test/compile-fail/issue-11319.rs @@ -10,11 +10,10 @@ fn main() { match Some(10) { - //~^ ERROR match arms have incompatible types: - //~| expected `bool` - //~| found `()` - //~| expected bool - //~| found () + //~^ ERROR match arms have incompatible types + //~| expected type `bool` + //~| found type `()` + //~| expected bool, found () Some(5) => false, Some(2) => true, None => (), //~ NOTE match arm with an incompatible type diff --git a/src/test/compile-fail/issue-12997-2.rs b/src/test/compile-fail/issue-12997-2.rs index 8b467c2ba11f9..436d9e91dc72f 100644 --- a/src/test/compile-fail/issue-12997-2.rs +++ b/src/test/compile-fail/issue-12997-2.rs @@ -15,7 +15,6 @@ #[bench] fn bar(x: isize) { } //~^ ERROR mismatched types -//~| expected `fn(&mut __test::test::Bencher)` -//~| found `fn(isize) {bar}` -//~| expected &-ptr -//~| found isize +//~| expected type `fn(&mut __test::test::Bencher)` +//~| found type `fn(isize) {bar}` +//~| expected &-ptr, found isize diff --git a/src/test/compile-fail/issue-13359.rs b/src/test/compile-fail/issue-13359.rs index 775412a12ca6a..e33859e8c19a3 100644 --- a/src/test/compile-fail/issue-13359.rs +++ b/src/test/compile-fail/issue-13359.rs @@ -15,11 +15,9 @@ fn bar(_s: u32) { } fn main() { foo(1*(1 as isize)); //~^ ERROR mismatched types - //~| expected `i16` - //~| found `isize` + //~| expected i16, found isize bar(1*(1 as usize)); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `usize` + //~| expected u32, found usize } diff --git a/src/test/compile-fail/issue-13466.rs b/src/test/compile-fail/issue-13466.rs index d2c8b679ff69f..17b96411603ef 100644 --- a/src/test/compile-fail/issue-13466.rs +++ b/src/test/compile-fail/issue-13466.rs @@ -17,16 +17,14 @@ pub fn main() { let _x: usize = match Some(1) { Ok(u) => u, //~^ ERROR mismatched types - //~| expected `std::option::Option<_>` - //~| found `std::result::Result<_, _>` - //~| expected enum `std::option::Option` - //~| found enum `std::result::Result` + //~| expected type `std::option::Option<_>` + //~| found type `std::result::Result<_, _>` + //~| expected enum `std::option::Option`, found enum `std::result::Result` Err(e) => panic!(e) //~^ ERROR mismatched types - //~| expected `std::option::Option<_>` - //~| found `std::result::Result<_, _>` - //~| expected enum `std::option::Option` - //~| found enum `std::result::Result` + //~| expected type `std::option::Option<_>` + //~| found type `std::result::Result<_, _>` + //~| expected enum `std::option::Option`, found enum `std::result::Result` }; } diff --git a/src/test/compile-fail/issue-13482-2.rs b/src/test/compile-fail/issue-13482-2.rs index e1fe2d06993d5..fe03373a45d9f 100644 --- a/src/test/compile-fail/issue-13482-2.rs +++ b/src/test/compile-fail/issue-13482-2.rs @@ -17,10 +17,9 @@ fn main() { let y = match x { [] => None, //~^ ERROR mismatched types -//~| expected `[_#1i; 2]` -//~| found `[_#7t; 0]` -//~| expected an array with a fixed size of 2 elements -//~| found one with 0 elements +//~| expected type `[_#1i; 2]` +//~| found type `[_#7t; 0]` +//~| expected an array with a fixed size of 2 elements, found one with 0 elements [a,_] => Some(a) }; } diff --git a/src/test/compile-fail/issue-13482.rs b/src/test/compile-fail/issue-13482.rs index 8d98fe313349b..7ed7f5898b1b7 100644 --- a/src/test/compile-fail/issue-13482.rs +++ b/src/test/compile-fail/issue-13482.rs @@ -15,8 +15,8 @@ fn main() { let y = match x { [] => None, //~^ ERROR mismatched types - //~| expected `[_; 2]` - //~| found `[_; 0]` + //~| expected type `[_; 2]` + //~| found type `[_; 0]` //~| expected an array with a fixed size of 2 elements [a,_] => Some(a) }; diff --git a/src/test/compile-fail/issue-13624.rs b/src/test/compile-fail/issue-13624.rs index 2a5805790a742..e4ed87c3cb0cd 100644 --- a/src/test/compile-fail/issue-13624.rs +++ b/src/test/compile-fail/issue-13624.rs @@ -16,10 +16,9 @@ mod a { pub fn get_enum_struct_variant() -> () { Enum::EnumStructVariant { x: 1, y: 2, z: 3 } //~^ ERROR mismatched types - //~| expected `()` - //~| found `a::Enum` - //~| expected () - //~| found enum `a::Enum` + //~| expected type `()` + //~| found type `a::Enum` + //~| expected (), found enum `a::Enum` } } @@ -32,10 +31,9 @@ mod b { match enum_struct_variant { a::Enum::EnumStructVariant { x, y, z } => { //~^ ERROR mismatched types - //~| expected `()` - //~| found `a::Enum` - //~| expected () - // found enum `a::Enum` + //~| expected type `()` + //~| found type `a::Enum` + //~| expected (), found enum `a::Enum` } } } diff --git a/src/test/compile-fail/issue-14091.rs b/src/test/compile-fail/issue-14091.rs index 3ceb465cb4b23..ccaeeab8b4789 100644 --- a/src/test/compile-fail/issue-14091.rs +++ b/src/test/compile-fail/issue-14091.rs @@ -9,9 +9,8 @@ // except according to those terms. // error-pattern:mismatched types -// error-pattern:expected `bool` -// error-pattern:found `_` -// error-pattern:expected bool -// error-pattern:found integral variable +// error-pattern:expected bool, found integral variable +// error-pattern:expected type `bool` +// error-pattern:found type `_` fn main(){assert!(1,1);} diff --git a/src/test/compile-fail/issue-14541.rs b/src/test/compile-fail/issue-14541.rs index deb8f00cd01c9..84c600d2201e3 100644 --- a/src/test/compile-fail/issue-14541.rs +++ b/src/test/compile-fail/issue-14541.rs @@ -14,10 +14,9 @@ struct vec3 { y: f32, z: f32 } fn make(v: vec2) { let vec3 { y: _, z: _ } = v; //~^ ERROR mismatched types - //~| expected `vec2` - //~| found `vec3` - //~| expected struct `vec2` - //~| found struct `vec3` + //~| expected type `vec2` + //~| found type `vec3` + //~| expected struct `vec2`, found struct `vec3` } fn main() { } diff --git a/src/test/compile-fail/issue-15783.rs b/src/test/compile-fail/issue-15783.rs index 9a139021e4c6d..37a2f1582bf08 100644 --- a/src/test/compile-fail/issue-15783.rs +++ b/src/test/compile-fail/issue-15783.rs @@ -17,9 +17,8 @@ fn main() { let x = Some(&[name]); let msg = foo(x); //~^ ERROR mismatched types -//~| expected `std::option::Option<&[&str]>` -//~| found `std::option::Option<&[&str; 1]>` -//~| expected slice -//~| found array of 1 elements +//~| expected type `std::option::Option<&[&str]>` +//~| found type `std::option::Option<&[&str; 1]>` +//~| expected slice, found array of 1 elements assert_eq!(msg, 3); } diff --git a/src/test/compile-fail/issue-15896.rs b/src/test/compile-fail/issue-15896.rs index 7381ade263b20..35ef9ba2b4bea 100644 --- a/src/test/compile-fail/issue-15896.rs +++ b/src/test/compile-fail/issue-15896.rs @@ -20,10 +20,9 @@ fn main() { E::B( Tau{t: x}, //~^ ERROR mismatched types - //~| expected `main::R` - //~| found `main::Tau` - //~| expected enum `main::R` - //~| found struct `main::Tau` + //~| expected type `main::R` + //~| found type `main::Tau` + //~| expected enum `main::R`, found struct `main::Tau` _) => x, }; } diff --git a/src/test/compile-fail/issue-16338.rs b/src/test/compile-fail/issue-16338.rs index 30775a958b57d..da6d081a7acb5 100644 --- a/src/test/compile-fail/issue-16338.rs +++ b/src/test/compile-fail/issue-16338.rs @@ -13,8 +13,7 @@ use std::raw::Slice; fn main() { let Slice { data: data, len: len } = "foo"; //~^ ERROR mismatched types - //~| expected `&str` - //~| found `std::raw::Slice<_>` - //~| expected &-ptr - //~| found struct `std::raw::Slice` + //~| expected type `&str` + //~| found type `std::raw::Slice<_>` + //~| expected &-ptr, found struct `std::raw::Slice` } diff --git a/src/test/compile-fail/issue-16401.rs b/src/test/compile-fail/issue-16401.rs index a90f9fe26e48c..df272a71cee4f 100644 --- a/src/test/compile-fail/issue-16401.rs +++ b/src/test/compile-fail/issue-16401.rs @@ -14,10 +14,9 @@ fn main() { match () { Slice { data: data, len: len } => (), //~^ ERROR mismatched types - //~| expected `()` - //~| found `std::raw::Slice<_>` - //~| expected () - //~| found struct `std::raw::Slice` + //~| expected type `()` + //~| found type `std::raw::Slice<_>` + //~| expected (), found struct `std::raw::Slice` _ => unreachable!() } } diff --git a/src/test/compile-fail/issue-17033.rs b/src/test/compile-fail/issue-17033.rs index 6010e206920e5..f0fe01b415970 100644 --- a/src/test/compile-fail/issue-17033.rs +++ b/src/test/compile-fail/issue-17033.rs @@ -12,10 +12,9 @@ fn f<'r>(p: &'r mut fn(p: &mut ())) { (*p)(()) //~ ERROR mismatched types - //~| expected `&mut ()` - //~| found `()` - //~| expected &-ptr - //~| found () + //~| expected type `&mut ()` + //~| found type `()` + //~| expected &-ptr, found () } fn main() {} diff --git a/src/test/compile-fail/issue-17263.rs b/src/test/compile-fail/issue-17263.rs index 2320bc02baf5e..063afe285fad3 100644 --- a/src/test/compile-fail/issue-17263.rs +++ b/src/test/compile-fail/issue-17263.rs @@ -15,13 +15,15 @@ struct Foo { a: isize, b: isize } fn main() { let mut x: Box<_> = box Foo { a: 1, b: 2 }; let (a, b) = (&mut x.a, &mut x.b); - //~^ ERROR cannot borrow `x` (here through borrowing `x.b`) as mutable more than once at a time - //~^^ NOTE previous borrow of `x` occurs here (through borrowing `x.a`) + //~^ ERROR cannot borrow `x` (via `x.b`) as mutable more than once at a time + //~| NOTE first mutable borrow occurs here (via `x.a`) + //~| NOTE second mutable borrow occurs here (via `x.b`) let mut foo: Box<_> = box Foo { a: 1, b: 2 }; let (c, d) = (&mut foo.a, &foo.b); - //~^ ERROR cannot borrow `foo` (here through borrowing `foo.b`) as immutable - //~^^ NOTE previous borrow of `foo` occurs here (through borrowing `foo.a`) + //~^ ERROR cannot borrow `foo` (via `foo.b`) as immutable + //~| NOTE mutable borrow occurs here (via `foo.a`) + //~| NOTE immutable borrow occurs here (via `foo.b`) } -//~^ NOTE previous borrow ends here -//~^^ NOTE previous borrow ends here +//~^ NOTE first borrow ends here +//~^^ NOTE mutable borrow ends here diff --git a/src/test/compile-fail/issue-17283.rs b/src/test/compile-fail/issue-17283.rs index c7d6443663241..98208bcfdbdee 100644 --- a/src/test/compile-fail/issue-17283.rs +++ b/src/test/compile-fail/issue-17283.rs @@ -24,28 +24,25 @@ fn main() { // `x { ... }` should not be interpreted as a struct literal here if x = x { //~^ ERROR mismatched types - //~| expected `bool` - //~| found `()` - //~| expected bool - //~| found () + //~| expected type `bool` + //~| found type `()` + //~| expected bool, found () println!("{}", x); } // Explicit parentheses on the left should match behavior of above if (x = x) { //~^ ERROR mismatched types - //~| expected `bool` - //~| found `()` - //~| expected bool - //~| found () + //~| expected type `bool` + //~| found type `()` + //~| expected bool, found () println!("{}", x); } // The struct literal interpretation is fine with explicit parentheses on the right if y = (Foo { foo: x }) { //~^ ERROR mismatched types - //~| expected `bool` - //~| found `()` - //~| expected bool - //~| found () + //~| expected type `bool` + //~| found type `()` + //~| expected bool, found () println!("{}", x); } } diff --git a/src/test/compile-fail/issue-17728.rs b/src/test/compile-fail/issue-17728.rs index 787eb7a3b8878..f508d7123d88f 100644 --- a/src/test/compile-fail/issue-17728.rs +++ b/src/test/compile-fail/issue-17728.rs @@ -108,6 +108,9 @@ impl Debug for Player { fn str_to_direction(to_parse: &str) -> RoomDirection { match to_parse { //~ ERROR match arms have incompatible types + //~^ expected enum `RoomDirection`, found enum `std::option::Option` + //~| expected type `RoomDirection` + //~| found type `std::option::Option<_>` "w" | "west" => RoomDirection::West, "e" | "east" => RoomDirection::East, "n" | "north" => RoomDirection::North, diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs index 4381bf22e2ace..6b9294b2038f1 100644 --- a/src/test/compile-fail/issue-17740.rs +++ b/src/test/compile-fail/issue-17740.rs @@ -15,12 +15,12 @@ struct Foo<'a> { impl <'a> Foo<'a>{ fn bar(self: &mut Foo) { //~^ mismatched types - //~| expected `&mut Foo<'a>` - //~| found `&mut Foo<'_>` + //~| expected type `&mut Foo<'a>` + //~| found type `&mut Foo<'_>` //~| lifetime mismatch //~| mismatched types - //~| expected `&mut Foo<'a>` - //~| found `&mut Foo<'_>` + //~| expected type `&mut Foo<'a>` + //~| found type `&mut Foo<'_>` //~| lifetime mismatch } } diff --git a/src/test/compile-fail/issue-19109.rs b/src/test/compile-fail/issue-19109.rs index 1ffffa9fc748e..580684e2e140b 100644 --- a/src/test/compile-fail/issue-19109.rs +++ b/src/test/compile-fail/issue-19109.rs @@ -12,11 +12,10 @@ trait Trait { } fn function(t: &mut Trait) { t as *mut Trait - //~^ ERROR: mismatched types: - //~| expected `()`, - //~| found `*mut Trait` - //~| (expected (), - //~| found *-ptr) [E0308] + //~^ ERROR: mismatched types + //~| NOTE: expected type `()` + //~| NOTE: found type `*mut Trait` + //~| NOTE: expected (), found *-ptr } fn main() { } diff --git a/src/test/compile-fail/issue-19991.rs b/src/test/compile-fail/issue-19991.rs index 6c9b0004f7754..b368daaaf587c 100644 --- a/src/test/compile-fail/issue-19991.rs +++ b/src/test/compile-fail/issue-19991.rs @@ -13,10 +13,9 @@ fn main() { if let Some(homura) = Some("madoka") { //~ ERROR missing an else clause - //~| expected `()` - //~| found `_` - //~| expected () - //~| found integral variable + //~| expected type `()` + //~| found type `_` + //~| expected (), found integral variable 765 }; } diff --git a/src/test/compile-fail/issue-24036.rs b/src/test/compile-fail/issue-24036.rs index 06b058cbfe179..ac7e0f2e9a867 100644 --- a/src/test/compile-fail/issue-24036.rs +++ b/src/test/compile-fail/issue-24036.rs @@ -14,6 +14,9 @@ fn closure_to_loc() { //~^ ERROR mismatched types //~| NOTE no two closures, even if identical, have the same type //~| HELP consider boxing your closure and/or using it as a trait object + //~| expected closure, found a different closure + //~| expected type `[closure + //~| found type `[closure } fn closure_from_match() { @@ -26,6 +29,9 @@ fn closure_from_match() { //~^^^^^^ ERROR match arms have incompatible types //~| NOTE no two closures, even if identical, have the same type //~| HELP consider boxing your closure and/or using it as a trait object + //~| expected closure, found a different closure + //~| expected type `[closure + //~| found type `[closure } fn main() { } diff --git a/src/test/compile-fail/issue-24357.rs b/src/test/compile-fail/issue-24357.rs index f193a07b85af9..5d6b989fc968a 100644 --- a/src/test/compile-fail/issue-24357.rs +++ b/src/test/compile-fail/issue-24357.rs @@ -12,7 +12,9 @@ struct NoCopy; fn main() { let x = NoCopy; let f = move || { let y = x; }; - //~^ NOTE `x` moved into closure environment here because it has type `NoCopy` + //~^ value moved (into closure) here let z = x; //~^ ERROR use of moved value: `x` + //~| value used here after move + //~| move occurs because `x` has type `NoCopy` } diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index a2831fd2b5ac8..cbeac77479811 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -10,7 +10,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { - //~^ ERROR: mismatched types: + //~^ ERROR: mismatched types 0 }; } diff --git a/src/test/compile-fail/issue-26480.rs b/src/test/compile-fail/issue-26480.rs index 23e4ffb1f3076..adcf8484f7828 100644 --- a/src/test/compile-fail/issue-26480.rs +++ b/src/test/compile-fail/issue-26480.rs @@ -25,6 +25,7 @@ macro_rules! write { write(stdout, $arr.as_ptr() as *const i8, $arr.len() * size_of($arr[0])); //~^ ERROR mismatched types + //~| expected u64, found usize } }} } diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs index 2a4b98563ab9f..bdcbaf09177fe 100644 --- a/src/test/compile-fail/issue-27008.rs +++ b/src/test/compile-fail/issue-27008.rs @@ -13,9 +13,8 @@ struct S; fn main() { let b = [0; S]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `S` - //~| expected usize - //~| found struct `S` + //~| expected type `usize` + //~| found type `S` + //~| expected usize, found struct `S` //~| ERROR expected positive integer for repeat count, found struct } diff --git a/src/test/compile-fail/issue-29084.rs b/src/test/compile-fail/issue-29084.rs index 78913e759a1cc..00d2969a0f67d 100644 --- a/src/test/compile-fail/issue-29084.rs +++ b/src/test/compile-fail/issue-29084.rs @@ -13,10 +13,13 @@ macro_rules! foo { fn bar(d: u8) { } bar(&mut $d); //~^ ERROR mismatched types + //~| expected u8, found &-ptr + //~| expected type `u8` + //~| found type `&mut u8` }} } fn main() { foo!(0u8); - //~^ NOTE in this expansion of foo! + //~^ in this expansion of foo! } diff --git a/src/test/compile-fail/issue-2951.rs b/src/test/compile-fail/issue-2951.rs index d0781b5658087..11ff7ab2476b9 100644 --- a/src/test/compile-fail/issue-2951.rs +++ b/src/test/compile-fail/issue-2951.rs @@ -12,10 +12,9 @@ fn foo(x: T, y: U) { let mut xx = x; xx = y; //~^ ERROR mismatched types - //~| expected `T` - //~| found `U` - //~| expected type parameter - //~| found a different type parameter + //~| expected type `T` + //~| found type `U` + //~| expected type parameter, found a different type parameter } fn main() { diff --git a/src/test/compile-fail/issue-3477.rs b/src/test/compile-fail/issue-3477.rs index 43ef1b59ccf27..0bad7372a12d9 100644 --- a/src/test/compile-fail/issue-3477.rs +++ b/src/test/compile-fail/issue-3477.rs @@ -11,6 +11,5 @@ fn main() { let _p: char = 100; //~^ ERROR mismatched types - //~| expected `char` - //~| found `u8` + //~| expected char, found u8 } diff --git a/src/test/compile-fail/issue-3680.rs b/src/test/compile-fail/issue-3680.rs index fc918c278ef5d..e698e6da5294e 100644 --- a/src/test/compile-fail/issue-3680.rs +++ b/src/test/compile-fail/issue-3680.rs @@ -12,9 +12,8 @@ fn main() { match None { Err(_) => () //~^ ERROR mismatched types - //~| expected `std::option::Option<_>` - //~| found `std::result::Result<_, _>` - //~| expected enum `std::option::Option` - //~| found enum `std::result::Result` + //~| expected type `std::option::Option<_>` + //~| found type `std::result::Result<_, _>` + //~| expected enum `std::option::Option`, found enum `std::result::Result` } } diff --git a/src/test/compile-fail/issue-4201.rs b/src/test/compile-fail/issue-4201.rs index b5af1f03b635b..58423341cc6f0 100644 --- a/src/test/compile-fail/issue-4201.rs +++ b/src/test/compile-fail/issue-4201.rs @@ -13,10 +13,9 @@ fn main() { 0 } else if false { //~^ ERROR if may be missing an else clause -//~| expected `()` -//~| found `_` -//~| expected () -//~| found integral variable +//~| expected type `()` +//~| found type `_` +//~| expected (), found integral variable 1 }; } diff --git a/src/test/compile-fail/issue-4517.rs b/src/test/compile-fail/issue-4517.rs index a1804b5a2689d..fbd8972cbfaa6 100644 --- a/src/test/compile-fail/issue-4517.rs +++ b/src/test/compile-fail/issue-4517.rs @@ -14,8 +14,7 @@ fn main() { let foo: [u8; 4] = [1; 4]; bar(foo); //~^ ERROR mismatched types - //~| expected `usize` - //~| found `[u8; 4]` - //~| expected usize - //~| found array of 4 elements + //~| expected type `usize` + //~| found type `[u8; 4]` + //~| expected usize, found array of 4 elements } diff --git a/src/test/compile-fail/issue-4968.rs b/src/test/compile-fail/issue-4968.rs index e7cd20f38a1d2..7c0905873df89 100644 --- a/src/test/compile-fail/issue-4968.rs +++ b/src/test/compile-fail/issue-4968.rs @@ -14,8 +14,7 @@ const A: (isize,isize) = (4,2); fn main() { match 42 { A => () } //~^ ERROR mismatched types - //~| expected `_` - //~| found `(isize, isize)` - //~| expected integral variable - //~| found tuple + //~| expected type `_` + //~| found type `(isize, isize)` + //~| expected integral variable, found tuple } diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs index 304b6f185fe36..9e78b7b947f98 100644 --- a/src/test/compile-fail/issue-5100.rs +++ b/src/test/compile-fail/issue-5100.rs @@ -16,48 +16,43 @@ enum A { B, C } fn main() { match (true, false) { A::B => (), -//~^ ERROR mismatched types: -//~| expected `(bool, bool)` -//~| found `A` -//~| expected tuple -//~| found enum `A` +//~^ ERROR mismatched types +//~| expected type `(bool, bool)` +//~| found type `A` +//~| expected tuple, found enum `A` _ => () } match (true, false) { (true, false, false) => () //~^ ERROR mismatched types -//~| expected `(bool, bool)` -//~| found `(_, _, _)` -//~| expected a tuple with 2 elements -//~| found one with 3 elements +//~| expected type `(bool, bool)` +//~| found type `(_, _, _)` +//~| expected a tuple with 2 elements, found one with 3 elements } match (true, false) { (true, false, false) => () //~^ ERROR mismatched types -//~| expected `(bool, bool)` -//~| found `(_, _, _)` -//~| expected a tuple with 2 elements -//~| found one with 3 elements +//~| expected type `(bool, bool)` +//~| found type `(_, _, _)` +//~| expected a tuple with 2 elements, found one with 3 elements } match (true, false) { box (true, false) => () //~^ ERROR mismatched types -//~| expected `(bool, bool)` -//~| found `Box<_>` -//~| expected tuple -//~| found box +//~| expected type `(bool, bool)` +//~| found type `Box<_>` +//~| expected tuple, found box } match (true, false) { &(true, false) => () //~^ ERROR mismatched types -//~| expected `(bool, bool)` -//~| found `&_` -//~| expected tuple -//~| found &-ptr +//~| expected type `(bool, bool)` +//~| found type `&_` +//~| expected tuple, found &-ptr } @@ -69,6 +64,5 @@ fn main() { // Make sure none of the errors above were fatal let x: char = true; //~ ERROR mismatched types - //~| expected `char` - //~| found `bool` + //~| expected char, found bool } diff --git a/src/test/compile-fail/issue-5358-1.rs b/src/test/compile-fail/issue-5358-1.rs index 32702d3e2f6fe..d8aad54fd3ee9 100644 --- a/src/test/compile-fail/issue-5358-1.rs +++ b/src/test/compile-fail/issue-5358-1.rs @@ -15,10 +15,9 @@ fn main() { match S(Either::Left(5)) { Either::Right(_) => {} //~^ ERROR mismatched types - //~| expected `S` - //~| found `Either<_, _>` - //~| expected struct `S` - //~| found enum `Either` + //~| expected type `S` + //~| found type `Either<_, _>` + //~| expected struct `S`, found enum `Either` _ => {} } } diff --git a/src/test/compile-fail/issue-5500.rs b/src/test/compile-fail/issue-5500.rs index 565634191be9a..cacbf7656def2 100644 --- a/src/test/compile-fail/issue-5500.rs +++ b/src/test/compile-fail/issue-5500.rs @@ -11,8 +11,7 @@ fn main() { &panic!() //~^ ERROR mismatched types - //~| expected `()` - //~| found `&_` - //~| expected () - //~| found &-ptr + //~| expected type `()` + //~| found type `&_` + //~| expected (), found &-ptr } diff --git a/src/test/compile-fail/issue-7061.rs b/src/test/compile-fail/issue-7061.rs index e261249bc998e..1519d71dd3be2 100644 --- a/src/test/compile-fail/issue-7061.rs +++ b/src/test/compile-fail/issue-7061.rs @@ -13,10 +13,9 @@ struct BarStruct; impl<'a> BarStruct { fn foo(&'a mut self) -> Box { self } //~^ ERROR mismatched types - //~| expected `Box` - //~| found `&'a mut BarStruct` - //~| expected box - //~| found &-ptr + //~| expected type `Box` + //~| found type `&'a mut BarStruct` + //~| expected box, found &-ptr } fn main() {} diff --git a/src/test/compile-fail/issue-7092.rs b/src/test/compile-fail/issue-7092.rs index 4acbcb165ff08..638f45cd35776 100644 --- a/src/test/compile-fail/issue-7092.rs +++ b/src/test/compile-fail/issue-7092.rs @@ -15,11 +15,10 @@ fn foo(x: Whatever) { match x { Some(field) => //~^ ERROR mismatched types -//~| expected `Whatever` -//~| found `std::option::Option<_>` -//~| expected enum `Whatever` -//~| found enum `std::option::Option` - field.access(), +//~| expected type `Whatever` +//~| found type `std::option::Option<_>` +//~| expected enum `Whatever`, found enum `std::option::Option` + field.access(), } } diff --git a/src/test/compile-fail/issue-7867.rs b/src/test/compile-fail/issue-7867.rs index 95513860b084f..e0de860b0eac3 100644 --- a/src/test/compile-fail/issue-7867.rs +++ b/src/test/compile-fail/issue-7867.rs @@ -16,25 +16,22 @@ fn main() { match (true, false) { A::B => (), //~^ ERROR mismatched types - //~| expected `(bool, bool)` - //~| found `A` - //~| expected tuple - //~| found enum `A` + //~| expected type `(bool, bool)` + //~| found type `A` + //~| expected tuple, found enum `A` _ => () } match &Some(42) { Some(x) => (), //~^ ERROR mismatched types - //~| expected `&std::option::Option<_>` - //~| found `std::option::Option<_>` - //~| expected &-ptr - //~| found enum `std::option::Option` + //~| expected type `&std::option::Option<_>` + //~| found type `std::option::Option<_>` + //~| expected &-ptr, found enum `std::option::Option` None => () //~^ ERROR mismatched types - //~| expected `&std::option::Option<_>` - //~| found `std::option::Option<_>` - //~| expected &-ptr - //~| found enum `std::option::Option` + //~| expected type `&std::option::Option<_>` + //~| found type `std::option::Option<_>` + //~| expected &-ptr, found enum `std::option::Option` } } diff --git a/src/test/compile-fail/issue-9575.rs b/src/test/compile-fail/issue-9575.rs index 94dd787f08635..9295eeb1779b0 100644 --- a/src/test/compile-fail/issue-9575.rs +++ b/src/test/compile-fail/issue-9575.rs @@ -12,6 +12,6 @@ #[start] fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize { - //~^ ERROR incorrect number of function parameters + //~^ start function has wrong type 0 } diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs index 09d5765a80f3f..7434a6c960b2d 100644 --- a/src/test/compile-fail/main-wrong-type-2.rs +++ b/src/test/compile-fail/main-wrong-type-2.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() -> char { -//~^ ERROR: main function expects type +//~^ ERROR: main function has wrong type } diff --git a/src/test/compile-fail/main-wrong-type.rs b/src/test/compile-fail/main-wrong-type.rs index d9c617a71720e..431b855d51773 100644 --- a/src/test/compile-fail/main-wrong-type.rs +++ b/src/test/compile-fail/main-wrong-type.rs @@ -14,5 +14,5 @@ struct S { } fn main(foo: S) { -//~^ ERROR: main function expects type +//~^ ERROR: main function has wrong type } diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 05b870b8f41cc..526aa83dec7fd 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -28,6 +28,5 @@ fn main() { _ => { } }; //~^^^ ERROR mismatched types in range - //~| expected char - //~| found integral variable + //~| expected char, found integral variable } diff --git a/src/test/compile-fail/match-struct.rs b/src/test/compile-fail/match-struct.rs index 5bda37896879b..0dbdda1f9ba1e 100644 --- a/src/test/compile-fail/match-struct.rs +++ b/src/test/compile-fail/match-struct.rs @@ -16,10 +16,9 @@ fn main() { match (S { a: 1 }) { E::C(_) => (), //~^ ERROR mismatched types - //~| expected `S` - //~| found `E` - //~| expected struct `S` - //~| found enum `E` + //~| expected type `S` + //~| found type `E` + //~| expected struct `S`, found enum `E` _ => () } } diff --git a/src/test/compile-fail/match-vec-mismatch-2.rs b/src/test/compile-fail/match-vec-mismatch-2.rs index 0bbba8861217d..2831499c73d87 100644 --- a/src/test/compile-fail/match-vec-mismatch-2.rs +++ b/src/test/compile-fail/match-vec-mismatch-2.rs @@ -14,9 +14,8 @@ fn main() { match () { [()] => { } //~^ ERROR mismatched types - //~| expected `()` - //~| found `&[_]` - //~| expected () - //~| found &-ptr + //~| expected type `()` + //~| found type `&[_]` + //~| expected (), found &-ptr } } diff --git a/src/test/compile-fail/method-self-arg-1.rs b/src/test/compile-fail/method-self-arg-1.rs index 57a96bb9a26ea..ffa5287d4b2c3 100644 --- a/src/test/compile-fail/method-self-arg-1.rs +++ b/src/test/compile-fail/method-self-arg-1.rs @@ -19,13 +19,11 @@ impl Foo { fn main() { let x = Foo; Foo::bar(x); //~ ERROR mismatched types - //~| expected `&Foo` - //~| found `Foo` - //~| expected &-ptr - //~| found struct `Foo` + //~| expected type `&Foo` + //~| found type `Foo` + //~| expected &-ptr, found struct `Foo` Foo::bar(&42); //~ ERROR mismatched types - //~| expected `&Foo` - //~| found `&_` - //~| expected struct `Foo` - //~| found integral variable + //~| expected type `&Foo` + //~| found type `&_` + //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs b/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs index f30360af46eb4..02c09aa7d69a2 100644 --- a/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs +++ b/src/test/compile-fail/moves-based-on-type-distribute-copy-over-paren.rs @@ -16,13 +16,17 @@ fn touch(_a: &A) {} fn f00() { let x = "hi".to_string(); - let _y = Foo { f:x }; //~ NOTE `x` moved here + let _y = Foo { f:x }; + //~^ value moved here touch(&x); //~ ERROR use of moved value: `x` + //~^ value used here after move + //~| move occurs because `x` has type `std::string::String` } fn f05() { let x = "hi".to_string(); - let _y = Foo { f:(((x))) }; //~ NOTE `x` moved here + let _y = Foo { f:(((x))) }; + //~^ value moved here touch(&x); //~ ERROR use of moved value: `x` } diff --git a/src/test/compile-fail/moves-based-on-type-match-bindings.rs b/src/test/compile-fail/moves-based-on-type-match-bindings.rs index 7d209467caf2a..bcbb8dbfad121 100644 --- a/src/test/compile-fail/moves-based-on-type-match-bindings.rs +++ b/src/test/compile-fail/moves-based-on-type-match-bindings.rs @@ -24,6 +24,8 @@ fn f10() { }; touch(&x); //~ ERROR use of partially moved value: `x` + //~^ value used here after move + //~| move occurs because `x.f` has type `std::string::String` } fn main() {} diff --git a/src/test/compile-fail/mut-pattern-mismatched.rs b/src/test/compile-fail/mut-pattern-mismatched.rs index 9eb24c81960ca..63e7dbd30def2 100644 --- a/src/test/compile-fail/mut-pattern-mismatched.rs +++ b/src/test/compile-fail/mut-pattern-mismatched.rs @@ -14,8 +14,8 @@ fn main() { // (separate lines to ensure the spans are accurate) let &_ //~ ERROR mismatched types - //~| expected `&mut _` - //~| found `&_` + //~| expected type `&mut _` + //~| found type `&_` //~| values differ in mutability = foo; let &mut _ = foo; @@ -23,8 +23,8 @@ fn main() { let bar = &1; let &_ = bar; let &mut _ //~ ERROR mismatched types - //~| expected `&_` - //~| found `&mut _` + //~| expected type `&_` + //~| found type `&mut _` //~| values differ in mutability = bar; } diff --git a/src/test/compile-fail/noexporttypeexe.rs b/src/test/compile-fail/noexporttypeexe.rs index 687e1e49ee844..c950ef5b68002 100644 --- a/src/test/compile-fail/noexporttypeexe.rs +++ b/src/test/compile-fail/noexporttypeexe.rs @@ -19,8 +19,7 @@ fn main() { // not convertible to a path. let x: isize = noexporttypelib::foo(); //~^ ERROR mismatched types - //~| expected `isize` - //~| found `std::option::Option` - //~| expected isize - //~| found enum `std::option::Option` + //~| expected type `isize` + //~| found type `std::option::Option` + //~| expected isize, found enum `std::option::Option` } diff --git a/src/test/compile-fail/occurs-check-2.rs b/src/test/compile-fail/occurs-check-2.rs index fd2903a85ddb0..5cb60079fa4b8 100644 --- a/src/test/compile-fail/occurs-check-2.rs +++ b/src/test/compile-fail/occurs-check-2.rs @@ -16,7 +16,7 @@ fn main() { g = f; f = box g; //~^ ERROR mismatched types - //~| expected `_` - //~| found `Box<_>` + //~| expected type `_` + //~| found type `Box<_>` //~| cyclic type of infinite size } diff --git a/src/test/compile-fail/occurs-check.rs b/src/test/compile-fail/occurs-check.rs index 036fcc1b9d779..499124cb0573b 100644 --- a/src/test/compile-fail/occurs-check.rs +++ b/src/test/compile-fail/occurs-check.rs @@ -14,7 +14,7 @@ fn main() { let f; f = box f; //~^ ERROR mismatched types - //~| expected `_` - //~| found `Box<_>` + //~| expected type `_` + //~| found type `Box<_>` //~| cyclic type of infinite size } diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs index 9b67595800320..d9f3bb3c40f8d 100644 --- a/src/test/compile-fail/pattern-error-continue.rs +++ b/src/test/compile-fail/pattern-error-continue.rs @@ -31,17 +31,15 @@ fn main() { match 'c' { S { .. } => (), //~^ ERROR mismatched types - //~| expected `char` - //~| found `S` - //~| expected char - //~| found struct `S` + //~| expected type `char` + //~| found type `S` + //~| expected char, found struct `S` _ => () } f(true); //~^ ERROR mismatched types - //~| expected `char` - //~| found `bool` + //~| expected char, found bool match () { E::V => {} //~ ERROR failed to resolve. Use of undeclared type or module `E` diff --git a/src/test/compile-fail/pptypedef.rs b/src/test/compile-fail/pptypedef.rs index 1a1c87ff47d46..7ece52e753786 100644 --- a/src/test/compile-fail/pptypedef.rs +++ b/src/test/compile-fail/pptypedef.rs @@ -13,11 +13,9 @@ fn let_in(x: T, f: F) where F: FnOnce(T) {} fn main() { let_in(3u32, |i| { assert!(i == 3i32); }); //~^ ERROR mismatched types - //~| expected `u32` - //~| found `i32` + //~| expected u32, found i32 let_in(3i32, |i| { assert!(i == 3u32); }); //~^ ERROR mismatched types - //~| expected `i32` - //~| found `u32` + //~| expected i32, found u32 } diff --git a/src/test/compile-fail/ptr-coercion.rs b/src/test/compile-fail/ptr-coercion.rs index 18e210076cb55..ff627e69d4c58 100644 --- a/src/test/compile-fail/ptr-coercion.rs +++ b/src/test/compile-fail/ptr-coercion.rs @@ -15,19 +15,19 @@ pub fn main() { // *const -> *mut let x: *const isize = &42; let x: *mut isize = x; //~ ERROR mismatched types - //~| expected `*mut isize` - //~| found `*const isize` + //~| expected type `*mut isize` + //~| found type `*const isize` //~| values differ in mutability // & -> *mut let x: *mut isize = &42; //~ ERROR mismatched types - //~| expected `*mut isize` - //~| found `&isize` + //~| expected type `*mut isize` + //~| found type `&isize` //~| values differ in mutability let x: *const isize = &42; let x: *mut isize = x; //~ ERROR mismatched types - //~| expected `*mut isize` - //~| found `*const isize` + //~| expected type `*mut isize` + //~| found type `*const isize` //~| values differ in mutability } diff --git a/src/test/compile-fail/ref-suggestion.rs b/src/test/compile-fail/ref-suggestion.rs index 815f752663223..0a0867195d976 100644 --- a/src/test/compile-fail/ref-suggestion.rs +++ b/src/test/compile-fail/ref-suggestion.rs @@ -11,22 +11,16 @@ fn main() { let x = vec![1]; let y = x; - //~^ HELP use a `ref` binding as shown - //~| SUGGESTION let ref y = x; x; //~ ERROR use of moved value let x = vec![1]; let mut y = x; - //~^ HELP use a `ref` binding as shown - //~| SUGGESTION let ref mut y = x; x; //~ ERROR use of moved value let x = (Some(vec![1]), ()); match x { (Some(y), ()) => {}, - //~^ HELP use a `ref` binding as shown - //~| SUGGESTION (Some(ref y), ()) => {}, _ => {}, } x; //~ ERROR use of partially moved value diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index 7f2889a327be0..64dbf27b78e48 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -17,15 +17,15 @@ struct a_class<'a> { x:&'a isize } fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> { return e; //~ ERROR mismatched types - //~| expected `an_enum<'b>` - //~| found `an_enum<'a>` + //~| expected type `an_enum<'b>` + //~| found type `an_enum<'a>` //~| lifetime mismatch } fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { return e; //~ ERROR mismatched types - //~| expected `a_class<'b>` - //~| found `a_class<'a>` + //~| expected type `a_class<'b>` + //~| found type `a_class<'a>` //~| lifetime mismatch } diff --git a/src/test/compile-fail/regions-early-bound-error-method.rs b/src/test/compile-fail/regions-early-bound-error-method.rs index 8cc35272282c4..f6a0c86de6626 100644 --- a/src/test/compile-fail/regions-early-bound-error-method.rs +++ b/src/test/compile-fail/regions-early-bound-error-method.rs @@ -29,8 +29,8 @@ impl<'a> Box<'a> { fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize { g2.get() //~^ ERROR mismatched types - //~| expected `&'a isize` - //~| found `&'b isize` + //~| expected type `&'a isize` + //~| found type `&'b isize` //~| lifetime mismatch } diff --git a/src/test/compile-fail/regions-fn-subtyping-return-static.rs b/src/test/compile-fail/regions-fn-subtyping-return-static.rs index ebf7ca289f889..c0116b21166e0 100644 --- a/src/test/compile-fail/regions-fn-subtyping-return-static.rs +++ b/src/test/compile-fail/regions-fn-subtyping-return-static.rs @@ -55,10 +55,9 @@ fn supply_G() { want_G(bar); want_G(baz); //~^ ERROR mismatched types - //~| expected `fn(&'cx S) -> &'static S` - //~| found `fn(&S) -> &S {baz}` - //~| expected concrete lifetime - //~| found bound lifetime parameter 'cx + //~| expected type `fn(&'cx S) -> &'static S` + //~| found type `fn(&S) -> &S {baz}` + //~| expected concrete lifetime, found bound lifetime parameter 'cx } pub fn main() { diff --git a/src/test/compile-fail/regions-infer-not-param.rs b/src/test/compile-fail/regions-infer-not-param.rs index 83b9d4633dcf3..131b7170951f6 100644 --- a/src/test/compile-fail/regions-infer-not-param.rs +++ b/src/test/compile-fail/regions-infer-not-param.rs @@ -27,10 +27,10 @@ fn take_direct<'a,'b>(p: direct<'a>) -> direct<'b> { p } //~ ERROR mismatched ty fn take_indirect1(p: indirect1) -> indirect1 { p } fn take_indirect2<'a,'b>(p: indirect2<'a>) -> indirect2<'b> { p } //~ ERROR mismatched types -//~| expected `indirect2<'b>` -//~| found `indirect2<'a>` +//~| expected type `indirect2<'b>` +//~| found type `indirect2<'a>` //~| ERROR mismatched types -//~| expected `indirect2<'b>` -//~| found `indirect2<'a>` +//~| expected type `indirect2<'b>` +//~| found type `indirect2<'a>` fn main() {} diff --git a/src/test/compile-fail/regions-infer-paramd-indirect.rs b/src/test/compile-fail/regions-infer-paramd-indirect.rs index 1d32e8fe7b250..fad115c2aedf8 100644 --- a/src/test/compile-fail/regions-infer-paramd-indirect.rs +++ b/src/test/compile-fail/regions-infer-paramd-indirect.rs @@ -32,8 +32,8 @@ impl<'a> set_f<'a> for c<'a> { fn set_f_bad(&mut self, b: Box) { self.f = b; //~^ ERROR mismatched types - //~| expected `Box>` - //~| found `Box>` + //~| expected type `Box>` + //~| found type `Box>` //~| lifetime mismatch } } diff --git a/src/test/compile-fail/reject-specialized-drops-8142.rs b/src/test/compile-fail/reject-specialized-drops-8142.rs index adc8702240378..1ea956bbd5489 100644 --- a/src/test/compile-fail/reject-specialized-drops-8142.rs +++ b/src/test/compile-fail/reject-specialized-drops-8142.rs @@ -38,8 +38,8 @@ impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // AC impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT //~^ ERROR mismatched types -//~| expected `N<'n>` -//~| found `N<'static>` +//~| expected type `N<'n>` +//~| found type `N<'static>` impl Drop for O { fn drop(&mut self) { } } // ACCEPT diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index 10b722946a8a8..ab5af64d95c13 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -16,52 +16,45 @@ fn main() { //~^ ERROR expected constant integer for repeat count, found variable [E0307] let b = [0; ()]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `()` - //~| expected usize - //~| found ()) [E0308] + //~| expected type `usize` + //~| found type `()` + //~| expected usize, found () //~| ERROR expected positive integer for repeat count, found tuple [E0306] let c = [0; true]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `bool` + //~| expected usize, found bool //~| ERROR expected positive integer for repeat count, found boolean [E0306] let d = [0; 0.5]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `_` - //~| expected usize - //~| found floating-point variable) [E0308] + //~| expected type `usize` + //~| found type `_` + //~| expected usize, found floating-point variable //~| ERROR expected positive integer for repeat count, found float [E0306] let e = [0; "foo"]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `&'static str` - //~| expected usize - //~| found &-ptr) [E0308] + //~| expected type `usize` + //~| found type `&'static str` + //~| expected usize, found &-ptr //~| ERROR expected positive integer for repeat count, found string literal [E0306] let f = [0; -4_isize]; //~^ ERROR mismatched types //~| expected `usize` - //~| found `isize` [E0308] + //~| found `isize` //~| ERROR mismatched types: - //~| expected `usize`, - //~| found `isize` [E0307] + //~| expected usize, found isize let f = [0_usize; -1_isize]; //~^ ERROR mismatched types //~| expected `usize` - //~| found `isize` [E0308] + //~| found `isize` //~| ERROR mismatched types - //~| expected `usize` - //~| found `isize` [E0307] + //~| expected usize, found isize struct G { g: (), } let g = [0; G { g: () }]; //~^ ERROR mismatched types - //~| expected `usize` - //~| found `main::G` - //~| expected usize - //~| found struct `main::G`) [E0308] + //~| expected type `usize` + //~| found type `main::G` + //~| expected usize, found struct `main::G` //~| ERROR expected positive integer for repeat count, found struct [E0306] } diff --git a/src/test/compile-fail/shift-various-bad-types.rs b/src/test/compile-fail/shift-various-bad-types.rs index 560af9193b35e..2d06161111ef1 100644 --- a/src/test/compile-fail/shift-various-bad-types.rs +++ b/src/test/compile-fail/shift-various-bad-types.rs @@ -34,8 +34,7 @@ fn foo(p: &Panolpy) { // Type of the result follows the LHS, not the RHS: let _: i32 = 22_i64 >> 1_i32; //~^ ERROR mismatched types - //~| expected `i32` - //~| found `i64` + //~| expected i32, found i64 } fn main() { diff --git a/src/test/compile-fail/slice-mut.rs b/src/test/compile-fail/slice-mut.rs index e6acc32545178..874cca8cb3fd0 100644 --- a/src/test/compile-fail/slice-mut.rs +++ b/src/test/compile-fail/slice-mut.rs @@ -16,7 +16,7 @@ fn main() { let y: &mut[_] = &x[2..4]; //~^ ERROR mismatched types - //~| expected `&mut [_]` - //~| found `&[isize]` + //~| expected type `&mut [_]` + //~| found type `&[isize]` //~| values differ in mutability } diff --git a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs index 3c1c3796a246f..3140bb6e5731d 100644 --- a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs +++ b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs @@ -16,10 +16,9 @@ fn main() { match Foo(1.1, marker::PhantomData) { 1 => {} //~^ ERROR mismatched types - //~| expected `Foo<_, _>` - //~| found `_` - //~| expected struct `Foo` - //~| found integral variable + //~| expected type `Foo<_, _>` + //~| found type `_` + //~| expected struct `Foo`, found integral variable } } diff --git a/src/test/compile-fail/struct-base-wrong-type-2.rs b/src/test/compile-fail/struct-base-wrong-type-2.rs index 83e73b6bc3ef4..1250d0dabcd9a 100644 --- a/src/test/compile-fail/struct-base-wrong-type-2.rs +++ b/src/test/compile-fail/struct-base-wrong-type-2.rs @@ -19,13 +19,11 @@ struct Bar { x: isize } fn main() { let b = Bar { x: 5 }; let f = Foo { a: 2, ..b }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `Bar` - //~| expected struct `Foo` - //~| found struct `Bar` + //~| expected type `Foo` + //~| found type `Bar` + //~| expected struct `Foo`, found struct `Bar` let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `_` - //~| expected struct `Foo` - //~| found integral variable + //~| expected type `Foo` + //~| found type `_` + //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/struct-base-wrong-type.rs b/src/test/compile-fail/struct-base-wrong-type.rs index c98131560d486..4503e465840fe 100644 --- a/src/test/compile-fail/struct-base-wrong-type.rs +++ b/src/test/compile-fail/struct-base-wrong-type.rs @@ -18,15 +18,13 @@ struct Bar { x: isize } static bar: Bar = Bar { x: 5 }; static foo: Foo = Foo { a: 2, ..bar }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `Bar` - //~| expected struct `Foo` - //~| found struct `Bar` + //~| expected type `Foo` + //~| found type `Bar` + //~| expected struct `Foo`, found struct `Bar` static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `_` - //~| expected struct `Foo` - //~| found integral variable + //~| expected type `Foo` + //~| found type `_` + //~| expected struct `Foo`, found integral variable fn main() { let b = Bar { x: 5 }; diff --git a/src/test/compile-fail/structure-constructor-type-mismatch.rs b/src/test/compile-fail/structure-constructor-type-mismatch.rs index 7a6b8ff662240..87fc5ba93aeb3 100644 --- a/src/test/compile-fail/structure-constructor-type-mismatch.rs +++ b/src/test/compile-fail/structure-constructor-type-mismatch.rs @@ -26,38 +26,32 @@ fn main() { let pt = PointF { x: 1, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable y: 2, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable }; let pt2 = Point:: { x: 3, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable y: 4, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable }; let pair = PairF { x: 5, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable y: 6, }; let pair2 = PairF:: { x: 7, //~^ ERROR mismatched types - //~| expected f32 - //~| found integral variable + //~| expected f32, found integral variable y: 8, }; diff --git a/src/test/compile-fail/substs-ppaux.rs b/src/test/compile-fail/substs-ppaux.rs index 8dd9994b234ba..c857790e342d0 100644 --- a/src/test/compile-fail/substs-ppaux.rs +++ b/src/test/compile-fail/substs-ppaux.rs @@ -24,36 +24,36 @@ fn main() {} fn foo<'z>() where &'z (): Sized { let x: () = >::bar::<'static, char>; //[verbose]~^ ERROR mismatched types - //[verbose]~| expected `()` - //[verbose]~| found `fn() {>::bar::}` + //[verbose]~| expected type `()` + //[verbose]~| found type `fn() {>::bar::}` //[normal]~^^^^ ERROR mismatched types - //[normal]~| expected `()` - //[normal]~| found `fn() {>::bar::<'static, char>}` + //[normal]~| expected type `()` + //[normal]~| found type `fn() {>::bar::<'static, char>}` let x: () = >::bar::<'static, char>; //[verbose]~^ ERROR mismatched types - //[verbose]~| expected `()` - //[verbose]~| found `fn() {>::bar::}` + //[verbose]~| expected type `()` + //[verbose]~| found type `fn() {>::bar::}` //[normal]~^^^^ ERROR mismatched types - //[normal]~| expected `()` - //[normal]~| found `fn() {>::bar::<'static, char>}` + //[normal]~| expected type `()` + //[normal]~| found type `fn() {>::bar::<'static, char>}` let x: () = >::baz; //[verbose]~^ ERROR mismatched types - //[verbose]~| expected `()` - //[verbose]~| found `fn() {>::baz}` + //[verbose]~| expected type `()` + //[verbose]~| found type `fn() {>::baz}` //[normal]~^^^^ ERROR mismatched types - //[normal]~| expected `()` - //[normal]~| found `fn() {>::baz}` + //[normal]~| expected type `()` + //[normal]~| found type `fn() {>::baz}` let x: () = foo::<'static>; //[verbose]~^ ERROR mismatched types - //[verbose]~| expected `()` - //[verbose]~| found `fn() {foo::}` + //[verbose]~| expected type `()` + //[verbose]~| found type `fn() {foo::}` //[normal]~^^^^ ERROR mismatched types - //[normal]~| expected `()` - //[normal]~| found `fn() {foo::<'static>}` + //[normal]~| expected type `()` + //[normal]~| found type `fn() {foo::<'static>}` >::bar; //[verbose]~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/suppressed-error.rs b/src/test/compile-fail/suppressed-error.rs index 44de5d8cfe353..9a4a52ced2008 100644 --- a/src/test/compile-fail/suppressed-error.rs +++ b/src/test/compile-fail/suppressed-error.rs @@ -11,9 +11,8 @@ fn main() { let (x, y) = (); //~^ ERROR mismatched types -//~| expected `()` -//~| found `(_, _)` -//~| expected () -//~| found tuple +//~| expected type `()` +//~| found type `(_, _)` +//~| expected (), found tuple return x; } diff --git a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs index 725234dfeab56..8f420f1ce4b0d 100644 --- a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs +++ b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs @@ -21,8 +21,7 @@ fn main() { let y; let x : char = last(y); //~^ ERROR mismatched types - //~| expected `char` - //~| found `std::option::Option<_>` - //~| expected char - //~| found enum `std::option::Option` + //~| expected type `char` + //~| found type `std::option::Option<_>` + //~| expected char, found enum `std::option::Option` } diff --git a/src/test/compile-fail/terr-in-field.rs b/src/test/compile-fail/terr-in-field.rs index 60db35b879f57..4a21e1339811e 100644 --- a/src/test/compile-fail/terr-in-field.rs +++ b/src/test/compile-fail/terr-in-field.rs @@ -21,10 +21,9 @@ struct bar { fn want_foo(f: foo) {} fn have_bar(b: bar) { want_foo(b); //~ ERROR mismatched types - //~| expected `foo` - //~| found `bar` - //~| expected struct `foo` - //~| found struct `bar` + //~| expected type `foo` + //~| found type `bar` + //~| expected struct `foo`, found struct `bar` } fn main() {} diff --git a/src/test/compile-fail/terr-sorts.rs b/src/test/compile-fail/terr-sorts.rs index 231d2366b48a8..592d7b3929bfc 100644 --- a/src/test/compile-fail/terr-sorts.rs +++ b/src/test/compile-fail/terr-sorts.rs @@ -19,10 +19,9 @@ type bar = Box; fn want_foo(f: foo) {} fn have_bar(b: bar) { want_foo(b); //~ ERROR mismatched types - //~| expected `foo` - //~| found `Box` - //~| expected struct `foo` - //~| found box + //~| expected type `foo` + //~| found type `Box` + //~| expected struct `foo`, found box } fn main() {} diff --git a/src/test/compile-fail/token-error-correct-3.rs b/src/test/compile-fail/token-error-correct-3.rs index f42c8d09a9c09..24627e9420874 100644 --- a/src/test/compile-fail/token-error-correct-3.rs +++ b/src/test/compile-fail/token-error-correct-3.rs @@ -22,6 +22,9 @@ pub mod raw { callback(path.as_ref(); //~ NOTE: unclosed delimiter //~^ ERROR: expected one of fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types + //~^ expected (), found enum `std::result::Result` + //~| expected type `()` + //~| found type `std::result::Result` } else { //~ ERROR: incorrect close delimiter: `}` //~^ ERROR: expected one of Ok(false); diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs index 836f08d0e78bb..1fff812af5b8d 100644 --- a/src/test/compile-fail/trait-bounds-cant-coerce.rs +++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs @@ -22,10 +22,9 @@ fn c(x: Box) { fn d(x: Box) { a(x); //~ ERROR mismatched types - //~| expected `Box` - //~| found `Box` - //~| expected bounds `Send` - //~| found no bounds + //~| expected type `Box` + //~| found type `Box` + //~| expected bounds `Send`, found no bounds } fn main() { } diff --git a/src/test/compile-fail/tuple-arity-mismatch.rs b/src/test/compile-fail/tuple-arity-mismatch.rs index 8ad9ca50e3042..e62255a4e77d4 100644 --- a/src/test/compile-fail/tuple-arity-mismatch.rs +++ b/src/test/compile-fail/tuple-arity-mismatch.rs @@ -15,15 +15,13 @@ fn first((value, _): (isize, f64)) -> isize { value } fn main() { let y = first ((1,2.0,3)); //~^ ERROR mismatched types - //~| expected `(isize, f64)` - //~| found `(isize, f64, _)` - //~| expected a tuple with 2 elements - //~| found one with 3 elements + //~| expected type `(isize, f64)` + //~| found type `(isize, f64, _)` + //~| expected a tuple with 2 elements, found one with 3 elements let y = first ((1,)); //~^ ERROR mismatched types - //~| expected `(isize, f64)` - //~| found `(isize,)` - //~| expected a tuple with 2 elements - //~| found one with 1 elements + //~| expected type `(isize, f64)` + //~| found type `(isize,)` + //~| expected a tuple with 2 elements, found one with 1 elements } diff --git a/src/test/compile-fail/tutorial-suffix-inference-test.rs b/src/test/compile-fail/tutorial-suffix-inference-test.rs index 99d6437c02ed4..dadf7eb91d8f4 100644 --- a/src/test/compile-fail/tutorial-suffix-inference-test.rs +++ b/src/test/compile-fail/tutorial-suffix-inference-test.rs @@ -18,12 +18,10 @@ fn main() { identity_u8(x); // after this, `x` is assumed to have type `u8` identity_u16(x); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `u8` + //~| expected u16, found u8 identity_u16(y); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `i32` + //~| expected u16, found i32 let a = 3; @@ -32,6 +30,5 @@ fn main() { identity_i(a); // ok identity_u16(a); //~^ ERROR mismatched types - //~| expected `u16` - //~| found `isize` + //~| expected u16, found isize } diff --git a/src/test/compile-fail/type-mismatch-multiple.rs b/src/test/compile-fail/type-mismatch-multiple.rs index dd8f54cdabb8f..0f174d99fefcb 100644 --- a/src/test/compile-fail/type-mismatch-multiple.rs +++ b/src/test/compile-fail/type-mismatch-multiple.rs @@ -12,11 +12,9 @@ fn main() { let a: bool = 1; let b: i32 = true; } //~^ ERROR mismatched types -//~| expected `bool` -//~| found `_` -//~| expected bool -//~| found integral variable +//~| expected type `bool` +//~| found type `_` +//~| expected bool, found integral variable //~| ERROR mismatched types -//~| expected `i32` -//~| found `bool` +//~| expected i32, found bool diff --git a/src/test/compile-fail/type-mismatch-same-crate-name.rs b/src/test/compile-fail/type-mismatch-same-crate-name.rs index e81ae5d743939..e74acaa71b0f3 100644 --- a/src/test/compile-fail/type-mismatch-same-crate-name.rs +++ b/src/test/compile-fail/type-mismatch-same-crate-name.rs @@ -23,9 +23,17 @@ fn main() { let bar2 = {extern crate crate_a2 as a; a::bar()}; { extern crate crate_a1 as a; - a::try_foo(foo2); //~ ERROR mismatched types - //~^ NOTE Perhaps two different versions of crate `crate_a1` - a::try_bar(bar2); //~ ERROR mismatched types - //~^ NOTE Perhaps two different versions of crate `crate_a1` + a::try_foo(foo2); + //~^ ERROR mismatched types + //~| Perhaps two different versions of crate `crate_a1` + //~| expected struct `main::a::Foo` + //~| expected type `main::a::Foo` + //~| found type `main::a::Foo` + a::try_bar(bar2); + //~^ ERROR mismatched types + //~| Perhaps two different versions of crate `crate_a1` + //~| expected trait `main::a::Bar` + //~| expected type `Box` + //~| found type `Box` } } diff --git a/src/test/compile-fail/type-parameter-names.rs b/src/test/compile-fail/type-parameter-names.rs index 408bf72e97c87..11a2fc2665ca4 100644 --- a/src/test/compile-fail/type-parameter-names.rs +++ b/src/test/compile-fail/type-parameter-names.rs @@ -14,10 +14,9 @@ fn foo(x: Foo) -> Bar { x //~^ ERROR mismatched types -//~| expected `Bar` -//~| found `Foo` -//~| expected type parameter -//~| found a different type parameter +//~| expected type `Bar` +//~| found type `Foo` +//~| expected type parameter, found a different type parameter } fn main() {} diff --git a/src/test/compile-fail/type-params-in-different-spaces-1.rs b/src/test/compile-fail/type-params-in-different-spaces-1.rs index 155b835bbc6e0..26eac6adde221 100644 --- a/src/test/compile-fail/type-params-in-different-spaces-1.rs +++ b/src/test/compile-fail/type-params-in-different-spaces-1.rs @@ -13,10 +13,9 @@ use std::ops::Add; trait BrokenAdd: Copy + Add { fn broken_add(&self, rhs: T) -> Self { *self + rhs //~ ERROR mismatched types - //~| expected `Self` - //~| found `T` - //~| expected Self - //~| found type parameter + //~| expected type `Self` + //~| found type `T` + //~| expected Self, found type parameter } } diff --git a/src/test/compile-fail/typeck_type_placeholder_mismatch.rs b/src/test/compile-fail/typeck_type_placeholder_mismatch.rs index 1daea8f915b3f..91e3c38322e47 100644 --- a/src/test/compile-fail/typeck_type_placeholder_mismatch.rs +++ b/src/test/compile-fail/typeck_type_placeholder_mismatch.rs @@ -22,18 +22,16 @@ pub fn main() { fn test1() { let x: Foo<_> = Bar::(PhantomData); //~^ ERROR mismatched types - //~| expected `Foo<_>` - //~| found `Bar` - //~| expected struct `Foo` - //~| found struct `Bar` + //~| expected type `Foo<_>` + //~| found type `Bar` + //~| expected struct `Foo`, found struct `Bar` let y: Foo = x; } fn test2() { let x: Foo<_> = Bar::(PhantomData); //~^ ERROR mismatched types - //~| expected `Foo<_>` - //~| found `Bar` - //~| expected struct `Foo` - //~| found struct `Bar` + //~| expected type `Foo<_>` + //~| found type `Bar` + //~| expected struct `Foo`, found struct `Bar` } diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index e54a7623cb0c3..f14a3505cdeb4 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -45,12 +45,12 @@ impl<'a, T> SomeTrait for &'a Bar { //~^ ERROR mismatched types fn dummy3(self: &&Bar) {} //~^ ERROR mismatched types - //~| expected `&&'a Bar` - //~| found `&&Bar` + //~| expected type `&&'a Bar` + //~| found type `&&Bar` //~| lifetime mismatch //~| ERROR mismatched types - //~| expected `&&'a Bar` - //~| found `&&Bar` + //~| expected type `&&'a Bar` + //~| found type `&&Bar` //~| lifetime mismatch } diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs index 6e60562da6749..b43159b0d96b0 100644 --- a/src/test/compile-fail/variadic-ffi-3.rs +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -21,17 +21,15 @@ fn main() { let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~^ ERROR: mismatched types - //~| expected `unsafe extern "C" fn(isize, u8)` - //~| found `unsafe extern "C" fn(isize, u8, ...) {foo}` - //~| expected non-variadic fn - //~| found variadic function + //~| expected type `unsafe extern "C" fn(isize, u8)` + //~| found type `unsafe extern "C" fn(isize, u8, ...) {foo}` + //~| NOTE: expected non-variadic fn, found variadic function let y: extern "C" fn(f: isize, x: u8, ...) = bar; //~^ ERROR: mismatched types - //~| expected `extern "C" fn(isize, u8, ...)` - //~| found `extern "C" fn(isize, u8) {bar}` - //~| expected variadic fn - //~| found non-variadic function + //~| expected type `extern "C" fn(isize, u8, ...)` + //~| found type `extern "C" fn(isize, u8) {bar}` + //~| NOTE: expected variadic fn, found non-variadic function foo(1, 2, 3f32); //~ ERROR: can't pass an `f32` to variadic function, cast to `c_double` foo(1, 2, true); //~ ERROR: can't pass `bool` to variadic function, cast to `c_int` From 1ff1887cc9537cf45c2bc405ce0b026ef9a2246a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:44:07 -0400 Subject: [PATCH 55/97] thread tighter span for closures around Track the span corresponding to the `|...|` part of the closure. --- src/libsyntax/ext/expand.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 63d9a699944ea..65df379781ecd 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -222,7 +222,7 @@ fn expand_mac_invoc(mac: ast::Mac, pth.span, &format!("macro undefined: '{}!'", &extname)); - fld.cx.suggest_macro_name(&extname.as_str(), pth.span, &mut err); + fld.cx.suggest_macro_name(&extname.as_str(), &mut err); err.emit(); // let compilation continue @@ -355,8 +355,8 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool "macro_escape is a deprecated synonym for macro_use"); is_use = true; if let ast::AttrStyle::Inner = attr.node.style { - err.fileline_help(attr.span, "consider an outer attribute, \ - #[macro_use] mod ...").emit(); + err.help("consider an outer attribute, \ + #[macro_use] mod ...").emit(); } else { err.emit(); } From 489a6c95bf747059b28472efc17d39795c6adcad Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 14:49:16 -0400 Subject: [PATCH 56/97] replace fileline_{help,note} with {help,note} The extra filename and line was mainly there to keep the indentation relative to the main snippet; now that this doesn't include filename/line-number as a prefix, it is distracted. --- src/librustc/infer/error_reporting.rs | 19 +- src/librustc/lint/context.rs | 14 +- src/librustc/traits/error_reporting.rs | 165 ++++++------------ .../borrowck/gather_loans/move_error.rs | 3 +- src/librustc_borrowck/borrowck/mod.rs | 3 +- src/librustc_const_eval/check_match.rs | 2 +- src/librustc_lint/builtin.rs | 4 +- src/librustc_metadata/creader.rs | 4 +- src/librustc_metadata/loader.rs | 26 ++- src/librustc_passes/consts.rs | 3 +- src/librustc_resolve/lib.rs | 29 ++- src/librustc_typeck/astconv.rs | 45 +++-- src/librustc_typeck/check/callee.rs | 4 +- src/librustc_typeck/check/cast.rs | 7 +- src/librustc_typeck/check/method/suggest.rs | 28 ++- src/librustc_typeck/check/mod.rs | 6 +- src/librustc_typeck/check/wfcheck.rs | 3 +- src/librustc_typeck/coherence/mod.rs | 3 +- src/librustc_typeck/collect.rs | 9 +- src/libsyntax/diagnostics/macros.rs | 6 +- src/libsyntax/ext/base.rs | 7 +- src/libsyntax/feature_gate.rs | 6 +- src/libsyntax/parse/attr.rs | 5 +- src/libsyntax/parse/mod.rs | 10 +- src/libsyntax/parse/parser.rs | 21 ++- 25 files changed, 172 insertions(+), 260 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 88972beb31b09..11d92f8585489 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -682,10 +682,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { E0309, "{} may not live long enough", labeled_user_string); - err.fileline_help(origin.span(), - &format!("consider adding an explicit lifetime bound `{}: {}`...", - bound_kind, - sub)); + err.help(&format!("consider adding an explicit lifetime bound `{}: {}`...", + bound_kind, + sub)); err } @@ -696,10 +695,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { E0310, "{} may not live long enough", labeled_user_string); - err.fileline_help(origin.span(), - &format!("consider adding an explicit lifetime \ - bound `{}: 'static`...", - bound_kind)); + err.help(&format!("consider adding an explicit lifetime \ + bound `{}: 'static`...", + bound_kind)); err } @@ -710,9 +708,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { E0311, "{} may not live long enough", labeled_user_string); - err.fileline_help(origin.span(), - &format!("consider adding an explicit lifetime bound for `{}`", - bound_kind)); + err.help(&format!("consider adding an explicit lifetime bound for `{}`", + bound_kind)); self.tcx.note_and_explain_region( &mut err, &format!("{} must be valid for ", labeled_user_string), diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 684cfbea3f5da..4ea6845b3c4f4 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -456,17 +456,13 @@ pub fn raw_struct_lint<'a>(sess: &'a Session, it will become a hard error in a future release!"); let citation = format!("for more information, see {}", future_incompatible.reference); - if let Some(sp) = span { - err.fileline_warn(sp, &explanation); - err.fileline_note(sp, &citation); - } else { - err.warn(&explanation); - err.note(&citation); - } + err.warn(&explanation); + err.note(&citation); } if let Some(span) = def { - err.span_note(span, "lint level defined here"); + let explanation = "lint level defined here"; + err = err.span_label(span, &explanation); } err @@ -542,7 +538,7 @@ pub trait LintContext: Sized { let mut err = self.lookup(lint, Some(span), msg); if self.current_level(lint) != Level::Allow { if note_span == span { - err.fileline_note(note_span, note); + err.note(note); } else { err.span_note(note_span, note); } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d7ddfc9f1a6d0..531a4fbf8beba 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -206,18 +206,17 @@ fn find_similar_impl_candidates<'a, 'tcx>( impl_candidates } -fn report_similar_impl_candidates(span: Span, - err: &mut DiagnosticBuilder, +fn report_similar_impl_candidates(err: &mut DiagnosticBuilder, impl_candidates: &[ty::TraitRef]) { - err.fileline_help(span, &format!("the following implementations were found:")); + err.help(&format!("the following implementations were found:")); let end = cmp::min(4, impl_candidates.len()); for candidate in &impl_candidates[0..end] { - err.fileline_help(span, &format!(" {:?}", candidate)); + err.help(&format!(" {:?}", candidate)); } if impl_candidates.len() > 4 { - err.fileline_help(span, &format!("and {} others", impl_candidates.len()-4)); + err.help(&format!("and {} others", impl_candidates.len()-4)); } } @@ -240,7 +239,7 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, predicate); if suggest_increasing_limit { - suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span); + suggest_new_overflow_limit(infcx.tcx, &mut err); } note_obligation_cause(infcx, &mut err, obligation); @@ -353,19 +352,15 @@ pub fn try_report_overflow_error_type_of_infinite_size<'a, 'tcx>( let mut err = recursive_type_with_infinite_size_error(tcx, main_def_id); let len = struct_enum_tys.len(); if len > 2 { - let span = tcx.map.span_if_local(main_def_id).unwrap(); - err.fileline_note(span, - &format!("type `{}` is embedded within `{}`...", - struct_enum_tys[0], - struct_enum_tys[1])); + err.note(&format!("type `{}` is embedded within `{}`...", + struct_enum_tys[0], + struct_enum_tys[1])); for &next_ty in &struct_enum_tys[1..len-1] { - err.fileline_note(span, - &format!("...which in turn is embedded within `{}`...", next_ty)); + err.note(&format!("...which in turn is embedded within `{}`...", next_ty)); } - err.fileline_note(span, - &format!("...which in turn is embedded within `{}`, \ - completing the cycle.", - struct_enum_tys[len-1])); + err.note(&format!("...which in turn is embedded within `{}`, \ + completing the cycle.", + struct_enum_tys[len-1])); } err.emit(); infcx.tcx.sess.abort_if_errors(); @@ -380,9 +375,9 @@ pub fn recursive_type_with_infinite_size_error<'tcx>(tcx: &TyCtxt<'tcx>, let span = tcx.map.span_if_local(type_def_id).unwrap(); let mut err = struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", tcx.item_path_str(type_def_id)); - err.fileline_help(span, &format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \ - at some point to make `{}` representable", - tcx.item_path_str(type_def_id))); + err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \ + at some point to make `{}` representable", + tcx.item_path_str(type_def_id))); err } @@ -423,15 +418,14 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, // these notes will often be of the form // "the type `T` can't be frobnicated" // which is somewhat confusing. - err.fileline_help(obligation.cause.span, &format!( - "consider adding a `where {}` bound", + err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate() )); } else if let Some(s) = on_unimplemented_note(infcx, trait_ref, obligation.cause.span) { // Otherwise, if there is an on-unimplemented note, // display it. - err.fileline_note(obligation.cause.span, &s); + err.note(&s); } else { // If we can't show anything useful, try to find // similar impls. @@ -439,8 +433,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, let impl_candidates = find_similar_impl_candidates(infcx, trait_ref); if impl_candidates.len() > 0 { - report_similar_impl_candidates(obligation.cause.span, - &mut err, &impl_candidates); + report_similar_impl_candidates(&mut err, &impl_candidates); } } note_obligation_cause(infcx, &mut err, obligation); @@ -499,7 +492,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, let found_kind = infcx.closure_kind(closure_def_id).unwrap(); let closure_span = infcx.tcx.map.span_if_local(closure_def_id).unwrap(); let mut err = struct_span_err!( - infcx.tcx.sess, closure_span, E0524, + infcx.tcx.sess, closure_span, E0525, "expected a closure that implements the `{}` trait, but this closure \ only implements `{}`", kind, @@ -570,41 +563,31 @@ pub fn report_object_safety_error<'tcx>(tcx: &TyCtxt<'tcx>, } match violation { ObjectSafetyViolation::SizedSelf => { - err.fileline_note( - span, - "the trait cannot require that `Self : Sized`"); + err.note("the trait cannot require that `Self : Sized`"); } ObjectSafetyViolation::SupertraitSelf => { - err.fileline_note( - span, - "the trait cannot use `Self` as a type parameter \ - in the supertrait listing"); + err.note("the trait cannot use `Self` as a type parameter \ + in the supertrait listing"); } ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => { - err.fileline_note( - span, - &format!("method `{}` has no receiver", - method.name)); + err.note(&format!("method `{}` has no receiver", + method.name)); } ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => { - err.fileline_note( - span, - &format!("method `{}` references the `Self` type \ - in its arguments or return type", - method.name)); + err.note(&format!("method `{}` references the `Self` type \ + in its arguments or return type", + method.name)); } ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => { - err.fileline_note( - span, - &format!("method `{}` has generic type parameters", - method.name)); + err.note(&format!("method `{}` has generic type parameters", + method.name)); } } } @@ -766,14 +749,12 @@ fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, note_obligation_cause_code(infcx, err, &obligation.predicate, - obligation.cause.span, &obligation.cause.code); } fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, err: &mut DiagnosticBuilder, predicate: &T, - cause_span: Span, cause_code: &ObligationCauseCode<'tcx>) where T: fmt::Display { @@ -781,101 +762,71 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, match *cause_code { ObligationCauseCode::MiscObligation => { } ObligationCauseCode::SliceOrArrayElem => { - err.fileline_note( - cause_span, - "slice and array elements must have `Sized` type"); + err.note("slice and array elements must have `Sized` type"); } ObligationCauseCode::ProjectionWf(data) => { - err.fileline_note( - cause_span, - &format!("required so that the projection `{}` is well-formed", - data)); + err.note(&format!("required so that the projection `{}` is well-formed", + data)); } ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.fileline_note( - cause_span, - &format!("required so that reference `{}` does not outlive its referent", - ref_ty)); + err.note(&format!("required so that reference `{}` does not outlive its referent", + ref_ty)); } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.item_path_str(item_def_id); - err.fileline_note( - cause_span, - &format!("required by `{}`", item_name)); + err.note(&format!("required by `{}`", item_name)); } ObligationCauseCode::ObjectCastObligation(object_ty) => { - err.fileline_note( - cause_span, - &format!( - "required for the cast to the object type `{}`", - infcx.ty_to_string(object_ty))); + err.note(&format!("required for the cast to the object type `{}`", + infcx.ty_to_string(object_ty))); } ObligationCauseCode::RepeatVec => { - err.fileline_note( - cause_span, - "the `Copy` trait is required because the \ - repeated element will be copied"); + err.note("the `Copy` trait is required because the \ + repeated element will be copied"); } ObligationCauseCode::VariableType(_) => { - err.fileline_note( - cause_span, - "all local variables must have a statically known size"); + err.note("all local variables must have a statically known size"); } ObligationCauseCode::ReturnType => { - err.fileline_note( - cause_span, - "the return type of a function must have a \ - statically known size"); + err.note("the return type of a function must have a \ + statically known size"); } ObligationCauseCode::AssignmentLhsSized => { - err.fileline_note( - cause_span, - "the left-hand-side of an assignment must have a statically known size"); + err.note("the left-hand-side of an assignment must have a statically known size"); } ObligationCauseCode::StructInitializerSized => { - err.fileline_note( - cause_span, - "structs must have a statically known size to be initialized"); + err.note("structs must have a statically known size to be initialized"); } ObligationCauseCode::ClosureCapture(var_id, _, builtin_bound) => { let def_id = tcx.lang_items.from_builtin_kind(builtin_bound).unwrap(); let trait_name = tcx.item_path_str(def_id); let name = tcx.local_var_name_str(var_id); - err.fileline_note( - cause_span, + err.note( &format!("the closure that captures `{}` requires that all captured variables \ implement the trait `{}`", name, trait_name)); } ObligationCauseCode::FieldSized => { - err.fileline_note( - cause_span, - "only the last field of a struct or enum variant \ - may have a dynamically sized type"); + err.note("only the last field of a struct or enum variant \ + may have a dynamically sized type"); } ObligationCauseCode::SharedStatic => { - err.fileline_note( - cause_span, - "shared static variables must have a type that implements `Sync`"); + err.note("shared static variables must have a type that implements `Sync`"); } ObligationCauseCode::BuiltinDerivedObligation(ref data) => { let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); - err.fileline_note( - cause_span, - &format!("required because it appears within the type `{}`", - parent_trait_ref.0.self_ty())); + err.note(&format!("required because it appears within the type `{}`", + parent_trait_ref.0.self_ty())); let parent_predicate = parent_trait_ref.to_predicate(); note_obligation_cause_code(infcx, err, &parent_predicate, - cause_span, &data.parent_code); } ObligationCauseCode::ImplDerivedObligation(ref data) => { let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref); - err.fileline_note( - cause_span, + err.note( &format!("required because of the requirements on the impl of `{}` for `{}`", parent_trait_ref, parent_trait_ref.0.self_ty())); @@ -883,12 +834,10 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, note_obligation_cause_code(infcx, err, &parent_predicate, - cause_span, &data.parent_code); } ObligationCauseCode::CompareImplMethodObligation => { - err.fileline_note( - cause_span, + err.note( &format!("the requirement `{}` appears on the impl method \ but not on the corresponding trait method", predicate)); @@ -896,12 +845,10 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, } } -fn suggest_new_overflow_limit(tcx: &TyCtxt, err:&mut DiagnosticBuilder, span: Span) { +fn suggest_new_overflow_limit(tcx: &TyCtxt, err:&mut DiagnosticBuilder) { let current_limit = tcx.sess.recursion_limit.get(); let suggested_limit = current_limit * 2; - err.fileline_note( - span, - &format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)); + err.note(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)); } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 3d94f5b186f0f..5768a441c51b7 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -167,8 +167,7 @@ fn note_move_destination(err: &mut DiagnosticBuilder, err.span_note( move_to_span, "attempting to move value to here"); - err.fileline_help( - move_to_span, + err.help( &format!("to prevent the move, \ use `ref {0}` or `ref mut {0}` to capture value by \ reference", diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 87000749598a7..f65e694939bfc 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -912,8 +912,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }; if is_closure { - err.fileline_help(span, - "closures behind references must be called via `&mut`"); + err.help("closures behind references must be called via `&mut`"); } err.emit(); } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 5883013ac72f2..ead6ab099a88b 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -255,7 +255,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) "pattern binding `{}` is named the same as one \ of the variants of the type `{}`", ident.node, ty_path); - fileline_help!(err, p.span, + help!(err, "if you meant to match on a variant, \ consider making the path in the pattern qualified: `{}::{}`", ty_path, ident.node); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 5e3a47701ebbf..4bdd926869a5a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -764,8 +764,8 @@ impl LateLintPass for UnconditionalRecursion { for call in &self_call_spans { db.span_note(*call, "recursive call site"); } - db.fileline_help(sp, "a `loop` may express intention \ - better if this is on purpose"); + db.help("a `loop` may express intention \ + better if this is on purpose"); } db.emit(); } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 635ef4ab35836..de0de219db2f1 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -241,8 +241,8 @@ impl<'a> CrateReader<'a> { crate_rustc_version .as_ref().map(|s| &**s) .unwrap_or("an old version of rustc")); - err.fileline_help(span, "consider removing the compiled binaries and recompiling \ - with your current version of rustc"); + err.help("consider removing the compiled binaries and recompiling \ + with your current version of rustc"); err.emit(); } } diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 28e0e5746a3ee..2316a67d9d3e3 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -346,39 +346,33 @@ impl<'a> Context<'a> { if !self.rejected_via_triple.is_empty() { let mismatches = self.rejected_via_triple.iter(); for (i, &CrateMismatch{ ref path, ref got }) in mismatches.enumerate() { - err.fileline_note(self.span, - &format!("crate `{}`, path #{}, triple {}: {}", - self.ident, i+1, got, path.display())); + err.note(&format!("crate `{}`, path #{}, triple {}: {}", + self.ident, i+1, got, path.display())); } } if !self.rejected_via_hash.is_empty() { - err.span_note(self.span, "perhaps this crate needs \ - to be recompiled?"); + err.note("perhaps this crate needs to be recompiled?"); let mismatches = self.rejected_via_hash.iter(); for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() { - err.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - self.ident, i+1, path.display())); + err.note(&format!("crate `{}` path #{}: {}", + self.ident, i+1, path.display())); } match self.root { &None => {} &Some(ref r) => { for (i, path) in r.paths().iter().enumerate() { - err.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - r.ident, i+1, path.display())); + err.note(&format!("crate `{}` path #{}: {}", + r.ident, i+1, path.display())); } } } } if !self.rejected_via_kind.is_empty() { - err.fileline_help(self.span, "please recompile this crate using \ - --crate-type lib"); + err.help("please recompile this crate using --crate-type lib"); let mismatches = self.rejected_via_kind.iter(); for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { - err.fileline_note(self.span, - &format!("crate `{}` path #{}: {}", - self.ident, i+1, path.display())); + err.note(&format!("crate `{}` path #{}: {}", + self.ident, i+1, path.display())); } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 1f9c40856fd19..dede4d2a42a53 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -198,9 +198,8 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { let mut err = self.tcx.sess.struct_span_err( expr.span, "const fns are an unstable feature"); - fileline_help!( + help!( &mut err, - expr.span, "in Nightly builds, add `#![feature(const_fn)]` to the crate \ attributes to enable"); err.emit(); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b83d6e9363e9c..1bb99eb1a5e0e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -244,7 +244,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, E0405, "trait `{}` is not in scope", name); - show_candidates(&mut err, span, &candidates); + show_candidates(&mut err, &candidates); err } ResolutionError::UndeclaredAssociatedType => { @@ -312,7 +312,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, "{} `{}` is undefined or not in scope", kind, name); - show_candidates(&mut err, span, &candidates); + show_candidates(&mut err, &candidates); err } ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(name) => { @@ -420,7 +420,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, match context { UnresolvedNameContext::Other => { } // no help available UnresolvedNameContext::PathIsMod(parent) => { - err.fileline_help(span, &match parent.map(|parent| &parent.node) { + err.help(&match parent.map(|parent| &parent.node) { Some(&ExprField(_, ident)) => { format!("To reference an item from the `{module}` module, \ use `{module}::{ident}`", @@ -1784,8 +1784,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If it's a typedef, give a note if let Def::TyAlias(..) = path_res.base_def { - err.fileline_note(trait_path.span, - "`type` aliases cannot be used for traits"); + err.note(trait_path.span, + "`type` aliases cannot be used for traits"); let definition_site = { let segments = &trait_path.segments; @@ -2880,7 +2880,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", path_name); if self.emit_errors { - err.fileline_help(expr.span, &msg); + err.help(&msg); } else { err.span_help(expr.span, &msg); } @@ -2922,7 +2922,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { path_name); if self.emit_errors { - err.fileline_help(expr.span, &msg); + err.help(&msg); } else { err.span_help(expr.span, &msg); } @@ -3420,7 +3420,6 @@ fn path_names_to_string(path: &Path, depth: usize) -> String { /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way fn show_candidates(session: &mut DiagnosticBuilder, - span: syntax::codemap::Span, candidates: &SuggestedCandidates) { let paths = &candidates.candidates; @@ -3440,26 +3439,23 @@ fn show_candidates(session: &mut DiagnosticBuilder, // behave differently based on how many candidates we have: if !paths.is_empty() { if paths.len() == 1 { - session.fileline_help( - span, + session.help( &format!("you can import it into scope: `use {};`.", &path_strings[0]), ); } else { - session.fileline_help(span, "you can import several candidates \ + session.help("you can import several candidates \ into scope (`use ...;`):"); let count = path_strings.len() as isize - MAX_CANDIDATES as isize + 1; for (idx, path_string) in path_strings.iter().enumerate() { if idx == MAX_CANDIDATES - 1 && count > 1 { - session.fileline_help( - span, + session.help( &format!(" and {} other candidates", count).to_string(), ); break; } else { - session.fileline_help( - span, + session.help( &format!(" `{}`", path_string).to_string(), ); } @@ -3468,8 +3464,7 @@ fn show_candidates(session: &mut DiagnosticBuilder, } } else { // nothing found: - session.fileline_help( - span, + session.help( &format!("no candidates by the name of `{}` found in your \ project; maybe you misspelled the name or forgot to import \ an external crate?", candidates.name.to_string()), diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1110e193e579b..ac7745985e6af 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -206,7 +206,6 @@ pub fn ast_region_to_region(tcx: &TyCtxt, lifetime: &hir::Lifetime) fn report_elision_failure( db: &mut DiagnosticBuilder, - default_span: Span, params: Vec) { let mut m = String::new(); @@ -243,29 +242,29 @@ fn report_elision_failure( } if len == 0 { - fileline_help!(db, default_span, - "this function's return type contains a borrowed value, but \ - there is no value for it to be borrowed from"); - fileline_help!(db, default_span, - "consider giving it a 'static lifetime"); + help!(db, + "this function's return type contains a borrowed value, but \ + there is no value for it to be borrowed from"); + help!(db, + "consider giving it a 'static lifetime"); } else if !any_lifetimes { - fileline_help!(db, default_span, - "this function's return type contains a borrowed value with \ - an elided lifetime, but the lifetime cannot be derived from \ - the arguments"); - fileline_help!(db, default_span, - "consider giving it an explicit bounded or 'static \ - lifetime"); + help!(db, + "this function's return type contains a borrowed value with \ + an elided lifetime, but the lifetime cannot be derived from \ + the arguments"); + help!(db, + "consider giving it an explicit bounded or 'static \ + lifetime"); } else if len == 1 { - fileline_help!(db, default_span, - "this function's return type contains a borrowed value, but \ - the signature does not say which {} it is borrowed from", - m); + help!(db, + "this function's return type contains a borrowed value, but \ + the signature does not say which {} it is borrowed from", + m); } else { - fileline_help!(db, default_span, - "this function's return type contains a borrowed value, but \ - the signature does not say whether it is borrowed from {}", - m); + help!(db, + "this function's return type contains a borrowed value, but \ + the signature does not say whether it is borrowed from {}", + m); } } @@ -286,7 +285,7 @@ pub fn opt_ast_region_to_region<'tcx>( let mut err = struct_span_err!(this.tcx().sess, default_span, E0106, "missing lifetime specifier"); if let Some(params) = params { - report_elision_failure(&mut err, default_span, params); + report_elision_failure(&mut err, params); } err.emit(); ty::ReStatic @@ -1087,7 +1086,7 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>, } _ => { - fileline_help!(&mut err, ty.span, + help!(&mut err, "perhaps you forgot parentheses? (per RFC 438)"); } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 21800d91d9458..a96b739ebcf99 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -64,8 +64,8 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: struct_span_err!(tcx.sess, span, E0174, "explicit use of unboxed closure method `{}` is experimental", method) - .fileline_help(span, "add `#![feature(unboxed_closures)]` to the crate \ - attributes to enable") + .help("add `#![feature(unboxed_closures)]` to the crate \ + attributes to enable") .emit(); } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 922c411ce8cd8..249ab27ec5956 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -155,8 +155,7 @@ impl<'tcx> CastCheck<'tcx> { actual, fcx.infcx().ty_to_string(self.cast_ty)) }, self.expr_ty, None) - .fileline_help(self.span, - &format!("cast through {} first", match e { + .help(&format!("cast through {} first", match e { CastError::NeedViaPtr => "a raw pointer", CastError::NeedViaThinPtr => "a thin pointer", CastError::NeedViaInt => "an integer", @@ -167,7 +166,7 @@ impl<'tcx> CastCheck<'tcx> { } CastError::CastToBool => { struct_span_err!(fcx.tcx().sess, self.span, E0054, "cannot cast as `bool`") - .fileline_help(self.span, "compare with zero instead") + .help("compare with zero instead") .emit(); } CastError::CastToChar => { @@ -202,7 +201,7 @@ impl<'tcx> CastCheck<'tcx> { actual, fcx.infcx().ty_to_string(self.cast_ty)) }, self.expr_ty, None) - .fileline_note(self.span, "vtable kinds may not match") + .note("vtable kinds may not match") .emit(); } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index c5195cf8787da..b541ca151c856 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -148,9 +148,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if is_fn_ty(&rcvr_ty, &fcx, span) { macro_rules! report_function { ($span:expr, $name:expr) => { - err.fileline_note( - $span, - &format!("{} is a function, perhaps you wish to call it", + err.note(&format!("{} is a function, perhaps you wish to call it", $name)); } } @@ -172,8 +170,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } if !static_sources.is_empty() { - err.fileline_note( - span, + err.note( "found the following associated functions; to be used as \ methods, functions must have a `self` parameter"); @@ -187,8 +184,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, p)) .collect::>() .join(", "); - err.fileline_note( - span, + err.note( &format!("the method `{}` exists but the \ following trait bounds were not satisfied: {}", item_name, @@ -306,13 +302,12 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"}, one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}); - err.fileline_help(span, &msg[..]); + err.help(&msg[..]); for (i, trait_did) in candidates.iter().enumerate() { - err.fileline_help(span, - &format!("candidate #{}: `use {}`", - i + 1, - fcx.tcx().item_path_str(*trait_did))); + err.help(&format!("candidate #{}: `use {}`", + i + 1, + fcx.tcx().item_path_str(*trait_did))); } return } @@ -351,13 +346,12 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}, name = item_name); - err.fileline_help(span, &msg[..]); + err.help(&msg[..]); for (i, trait_info) in candidates.iter().enumerate() { - err.fileline_help(span, - &format!("candidate #{}: `{}`", - i + 1, - fcx.tcx().item_path_str(trait_info.def_id))); + err.help(&format!("candidate #{}: `{}`", + i + 1, + fcx.tcx().item_path_str(trait_info.def_id))); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2d0505d9347d5..385f04b8564f5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2955,9 +2955,9 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, `{}`", field.node, actual) }, expr_t, None) - .fileline_help(field.span, - "maybe a `()` to call it is missing? \ - If not, try an anonymous function") + .help( + "maybe a `()` to call it is missing? \ + If not, try an anonymous function") .emit(); fcx.write_error(expr.id); } else { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 492dbce9bdf45..25a37b6810e44 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -501,8 +501,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let suggested_marker_id = self.tcx().lang_items.phantom_data(); match suggested_marker_id { Some(def_id) => { - err.fileline_help( - span, + err.help( &format!("consider removing `{}` or using a marker such as `{}`", param_name, self.tcx().item_path_str(def_id))); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 859fbd974fedc..bfb371be663b5 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -510,8 +510,7 @@ fn enforce_trait_manually_implementable(tcx: &TyCtxt, sp: Span, trait_def_id: De E0183, "manual implementations of `{}` are experimental", trait_name); - fileline_help!(&mut err, sp, - "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); + help!(&mut err, "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); err.emit(); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 51534a46ddac3..c10488a03ef68 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1258,9 +1258,9 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ which traits can use parenthetical notation"); - fileline_help!(&mut err, it.span, - "add `#![feature(unboxed_closures)]` to \ - the crate attributes to use it"); + help!(&mut err, + "add `#![feature(unboxed_closures)]` to \ + the crate attributes to use it"); err.emit(); } @@ -2196,8 +2196,7 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( &format!("use of SIMD type `{}` in FFI is highly experimental and \ may result in invalid code", pprust::ty_to_string(ast_ty))) - .fileline_help(ast_ty.span, - "add #![feature(simd_ffi)] to the crate attributes to enable") + .help("add #![feature(simd_ffi)] to the crate attributes to enable") .emit(); } }; diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 95a74d875545f..25e0428248df4 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -101,9 +101,9 @@ macro_rules! span_help { } #[macro_export] -macro_rules! fileline_help { - ($err:expr, $span:expr, $($message:tt)*) => ({ - ($err).fileline_help($span, &format!($($message)*)); +macro_rules! help { + ($err:expr, $($message:tt)*) => ({ + ($err).help(&format!($($message)*)); }) } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index c0306b8494be2..303187aeba87d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -764,15 +764,14 @@ impl<'a> ExtCtxt<'a> { pub fn suggest_macro_name(&mut self, name: &str, - span: Span, err: &mut DiagnosticBuilder<'a>) { let names = &self.syntax_env.names; if let Some(suggestion) = find_best_match_for_name(names.iter(), name, None) { if suggestion != name { - err.fileline_help(span, &format!("did you mean `{}!`?", suggestion)); + err.help(&format!("did you mean `{}!`?", suggestion)); } else { - err.fileline_help(span, &format!("have you added the `#[macro_use]` on the \ - module/import?")); + err.help(&format!("have you added the `#[macro_use]` on the \ + module/import?")); } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ed2371fc34823..e269475d1e2c5 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -770,9 +770,9 @@ pub fn emit_feature_err(diag: &Handler, feature: &str, span: Span, issue: GateIs err.emit(); return; } - err.fileline_help(span, &format!("add #![feature({})] to the \ - crate attributes to enable", - feature)); + err.help(&format!("add #![feature({})] to the \ + crate attributes to enable", + feature)); err.emit(); } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index b8e320e36e9b4..3aac12d76ffdf 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -69,9 +69,8 @@ impl<'a> Parser<'a> { self.diagnostic() .struct_span_err(span, "an inner attribute is not permitted in this context") - .fileline_help(span, - "place inner attribute at the top of the module or \ - block") + .help("place inner attribute at the top of the module or \ + block") .emit() } ast::AttrStyle::Inner diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c2050d2a8f48b..2a9bcfd658c18 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -445,11 +445,11 @@ fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>, if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { // if it looks like a width, lets try to be helpful. sd.struct_span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..])) - .fileline_help(sp, "valid widths are 32 and 64") + .help("valid widths are 32 and 64") .emit(); } else { sd.struct_span_err(sp, &format!("invalid suffix `{}` for float literal", suf)) - .fileline_help(sp, "valid suffixes are `f32` and `f64`") + .help("valid suffixes are `f32` and `f64`") .emit(); } @@ -621,12 +621,12 @@ pub fn integer_lit(s: &str, if looks_like_width_suffix(&['i', 'u'], suf) { sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal", &suf[1..])) - .fileline_help(sp, "valid widths are 8, 16, 32 and 64") + .help("valid widths are 8, 16, 32 and 64") .emit(); } else { sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)) - .fileline_help(sp, "the suffix must be one of the integral types \ - (`u32`, `isize`, etc)") + .help("the suffix must be one of the integral types \ + (`u32`, `isize`, etc)") .emit(); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 671a11b57dec1..b9188f5101d3f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -583,7 +583,7 @@ impl<'a> Parser<'a> { let mut err = self.fatal(&format!("expected identifier, found `{}`", self.this_token_to_string())); if self.token == token::Underscore { - err.fileline_note(self.span, "`_` is a wildcard pattern, not an identifier"); + err.note("`_` is a wildcard pattern, not an identifier"); } Err(err) } @@ -1082,7 +1082,7 @@ impl<'a> Parser<'a> { } pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> DiagnosticBuilder<'a> { let mut err = self.sess.span_diagnostic.struct_span_fatal(sp, m); - err.fileline_help(sp, help); + err.help(help); err } pub fn bug(&self, m: &str) -> ! { @@ -2622,10 +2622,9 @@ impl<'a> Parser<'a> { Some(f) => f, None => continue, }; - err.fileline_help(last_span, - &format!("try parenthesizing the first index; e.g., `(foo.{}){}`", - float.trunc() as usize, - format!(".{}", fstr.splitn(2, ".").last().unwrap()))); + err.help(&format!("try parenthesizing the first index; e.g., `(foo.{}){}`", + float.trunc() as usize, + format!(".{}", fstr.splitn(2, ".").last().unwrap()))); } return Err(err); @@ -3134,7 +3133,7 @@ impl<'a> Parser<'a> { let mut err = self.diagnostic().struct_span_err(op_span, "chained comparison operators require parentheses"); if op.node == BinOpKind::Lt && *outer_op == AssocOp::Greater { - err.fileline_help(op_span, + err.help( "use `::<...>` instead of `<...>` if you meant to specify type arguments"); } err.emit(); @@ -4951,13 +4950,13 @@ impl<'a> Parser<'a> { if is_macro_rules { self.diagnostic().struct_span_err(span, "can't qualify macro_rules \ invocation with `pub`") - .fileline_help(span, "did you mean #[macro_export]?") + .help("did you mean #[macro_export]?") .emit(); } else { self.diagnostic().struct_span_err(span, "can't qualify macro \ invocation with `pub`") - .fileline_help(span, "try adjusting the macro to put `pub` \ - inside the invocation") + .help("try adjusting the macro to put `pub` \ + inside the invocation") .emit(); } } @@ -5857,7 +5856,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Mut) { let last_span = self.last_span; self.diagnostic().struct_span_err(last_span, "const globals cannot be mutable") - .fileline_help(last_span, "did you mean to declare a static?") + .help("did you mean to declare a static?") .emit(); } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; From 41a652e0948d6cbcffa89a219b37a1e39ae619d4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 15:52:52 -0400 Subject: [PATCH 57/97] WIP factor out RudimentaryEmitter --- src/librustc_trans/back/write.rs | 21 +++++--------- src/libsyntax/errors/emitter.rs | 47 +++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 50fd039276253..ffd8c261b6055 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -19,9 +19,9 @@ use llvm::SMDiagnosticRef; use {CrateTranslation, ModuleTranslation}; use util::common::time; use util::common::path2cstr; -use syntax::codemap::{self, MultiSpan}; +use syntax::codemap::MultiSpan; use syntax::errors::{self, Handler, Level}; -use syntax::errors::emitter::Emitter; +use syntax::errors::emitter::RudimentaryEmitter; use std::collections::HashMap; use std::ffi::{CStr, CString}; @@ -100,24 +100,17 @@ impl SharedEmitter { } } -impl Emitter for SharedEmitter { - fn emit(&mut self, - sp: &codemap::MultiSpan, - msg: &str, - code: Option<&str>, - lvl: Level) { - assert!(sp.primary_span().is_none(), "SharedEmitter doesn't support spans"); - +impl RudimentaryEmitter for SharedEmitter { + fn emit_rudimentary(&mut self, + msg: &str, + code: Option<&str>, + lvl: Level) { self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), code: code.map(|s| s.to_string()), lvl: lvl, }); } - - fn emit_struct(&mut self, _db: &errors::DiagnosticBuilder) { - bug!("SharedEmitter doesn't support emit_struct"); - } } diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index e963a5f794cb6..f851937d82bc0 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -25,12 +25,38 @@ use std::rc::Rc; use term; pub trait Emitter { + /// Emit a standalone diagnostic message. fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level); /// Emit a structured diagnostic. fn emit_struct(&mut self, db: &DiagnosticBuilder); } +/// A core trait that can only handle very simple messages: those +/// without spans or any real structure. Used only in specific contexts. +pub trait RudimentaryEmitter { + fn emit_rudimentary(&mut self, msg: &str, code: Option<&str>, lvl: Level); +} + +impl Emitter for T { + fn emit(&mut self, + msp: &MultiSpan, + msg: &str, + code: Option<&str>, + lvl: Level) { + assert!(msp.primary_span().is_none(), "Rudimenatry emitters can't handle spans"); + self.emit_rudimentary(msg, code, lvl); + } + + fn emit_struct(&mut self, db: &DiagnosticBuilder) { + self.emit(&db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); + for child in &db.children { + assert!(child.render_span.is_none(), "Rudimentary emitters can't handle render spans"); + self.emit(&child.span, &child.message, None, child.level); + } + } +} + /// maximum number of lines we will print for each error; arbitrary. pub const MAX_HIGHLIGHT_LINES: usize = 6; @@ -57,26 +83,15 @@ pub struct BasicEmitter { dst: Destination, } -impl Emitter for BasicEmitter { - fn emit(&mut self, - msp: &MultiSpan, - msg: &str, - code: Option<&str>, - lvl: Level) { - assert!(msp.primary_span().is_none(), "BasicEmitter can't handle spans"); - +impl RudimentaryEmitter for BasicEmitter { + fn emit_rudimentary(&mut self, + msg: &str, + code: Option<&str>, + lvl: Level) { if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { panic!("failed to print diagnostics: {:?}", e); } } - - fn emit_struct(&mut self, db: &DiagnosticBuilder) { - self.emit(&db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); - for child in &db.children { - assert!(child.render_span.is_none(), "BasicEmitter can't handle spans"); - self.emit(&child.span, &child.message, None, child.level); - } - } } impl BasicEmitter { From 71c6f813098a4e51344b7968022bbd946bad37be Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 16:08:51 -0400 Subject: [PATCH 58/97] change errors from Yellow to Magenta The Yellow text is very hard to read with a white background. --- src/libsyntax/errors/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index abbc4eef7bf81..0de2e067802e2 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -661,7 +661,7 @@ impl Level { fn color(self) -> term::color::Color { match self { Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, - Warning => term::color::BRIGHT_YELLOW, + Warning => term::color::BRIGHT_MAGENTA, Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, Cancelled => unreachable!(), From 47143945cc3bc8ec67f67609df13ccd4bb1a3bf5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 17:35:32 -0400 Subject: [PATCH 59/97] delete the json-errors test It's primary purpose was to check that json worked at all, but compiletest does that now. --- src/test/run-make/json-errors/Makefile | 9 --------- src/test/run-make/json-errors/foo.json | 4 ---- src/test/run-make/json-errors/foo.rs | 15 --------------- 3 files changed, 28 deletions(-) delete mode 100644 src/test/run-make/json-errors/Makefile delete mode 100644 src/test/run-make/json-errors/foo.json delete mode 100644 src/test/run-make/json-errors/foo.rs diff --git a/src/test/run-make/json-errors/Makefile b/src/test/run-make/json-errors/Makefile deleted file mode 100644 index 30bcafd104945..0000000000000 --- a/src/test/run-make/json-errors/Makefile +++ /dev/null @@ -1,9 +0,0 @@ --include ../tools.mk - -LOG := $(TMPDIR)/foo.log - -all: - cp foo.rs $(TMPDIR) - cd $(TMPDIR) - -$(RUSTC) -Z unstable-options --error-format=json foo.rs 2>$(LOG) - diff foo.json $(LOG) diff --git a/src/test/run-make/json-errors/foo.json b/src/test/run-make/json-errors/foo.json deleted file mode 100644 index bde669ab0f7f9..0000000000000 --- a/src/test/run-make/json-errors/foo.json +++ /dev/null @@ -1,4 +0,0 @@ -{"message":"unresolved name `y`","code":{"code":"E0425","explanation":"\nAn unresolved name was used. Example of erroneous codes:\n\n```compile_fail\nsomething_that_doesnt_exist::foo;\n// error: unresolved name `something_that_doesnt_exist::foo`\n\n// or:\n\ntrait Foo {\n fn bar() {\n Self; // error: unresolved name `Self`\n }\n}\n\n// or:\n\nlet x = unknown_variable; // error: unresolved name `unknown_variable`\n```\n\nPlease verify that the name wasn't misspelled and ensure that the\nidentifier being referred to is valid for the given situation. Example:\n\n```\nenum something_that_does_exist {\n Foo,\n}\n```\n\nOr:\n\n```\nmod something_that_does_exist {\n pub static foo : i32 = 0i32;\n}\n\nsomething_that_does_exist::foo; // ok!\n```\n\nOr:\n\n```\nlet unknown_variable = 12u32;\nlet x = unknown_variable; // ok!\n```\n"},"level":"error","spans":[{"file_name":"foo.rs","byte_start":496,"byte_end":497,"line_start":12,"line_end":12,"column_start":18,"column_end":19,"text":[{"text":" let x = 42 + y;","highlight_start":18,"highlight_end":19}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null} -{"message":"mismatched types:\n expected `u8`,\n found `i32`","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n\nAnother situation in which this occurs is when you attempt to use the `try!`\nmacro inside a function that does not return a `Result`:\n\n```compile_fail\nuse std::fs::File;\n\nfn main() {\n let mut f = try!(File::create(\"foo.txt\"));\n}\n```\n\nThis code gives an error like this:\n\n```text\n:5:8: 6:42 error: mismatched types:\n expected `()`,\n found `core::result::Result<_, _>`\n (expected (),\n found enum `core::result::Result`) [E0308]\n```\n\n`try!` returns a `Result`, and so the function must. But `main()` has\n`()` as its return type, hence the error.\n"},"level":"error","spans":[{"file_name":"foo.rs","byte_start":511,"byte_end":516,"line_start":14,"line_end":14,"column_start":12,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":12,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null} -{"message":"the trait bound `u8: std::ops::Add` is not satisfied","code":{"code":"E0277","explanation":"\nYou tried to use a type which doesn't implement some trait in a place which\nexpected that trait. Erroneous code example:\n\n```compile_fail\n// here we declare the Foo trait with a bar method\ntrait Foo {\n fn bar(&self);\n}\n\n// we now declare a function which takes an object implementing the Foo trait\nfn some_func(foo: T) {\n foo.bar();\n}\n\nfn main() {\n // we now call the method with the i32 type, which doesn't implement\n // the Foo trait\n some_func(5i32); // error: the trait bound `i32 : Foo` is not satisfied\n}\n```\n\nIn order to fix this error, verify that the type you're using does implement\nthe trait. Example:\n\n```\ntrait Foo {\n fn bar(&self);\n}\n\nfn some_func(foo: T) {\n foo.bar(); // we can now use this method since i32 implements the\n // Foo trait\n}\n\n// we implement the trait on the i32 type\nimpl Foo for i32 {\n fn bar(&self) {}\n}\n\nfn main() {\n some_func(5i32); // ok!\n}\n```\n\nOr in a generic context, an erroneous code example would look like:\n```compile_fail\nfn some_func(foo: T) {\n println!(\"{:?}\", foo); // error: the trait `core::fmt::Debug` is not\n // implemented for the type `T`\n}\n\nfn main() {\n // We now call the method with the i32 type,\n // which *does* implement the Debug trait.\n some_func(5i32);\n}\n```\n\nNote that the error here is in the definition of the generic function: Although\nwe only call it with a parameter that does implement `Debug`, the compiler\nstill rejects the function: It must work with all possible input types. In\norder to make this example compile, we need to restrict the generic type we're\naccepting:\n```\nuse std::fmt;\n\n// Restrict the input type to types that implement Debug.\nfn some_func(foo: T) {\n println!(\"{:?}\", foo);\n}\n\nfn main() {\n // Calling the method is still fine, as i32 implements Debug.\n some_func(5i32);\n\n // This would fail to compile now:\n // struct WithoutDebug;\n // some_func(WithoutDebug);\n}\n\nRust only looks at the signature of the called function, as such it must\nalready specify all requirements that will be used for every type parameter.\n```\n\n"},"level":"error","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[{"message":"the following implementations were found:","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" ","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" <&'a u8 as std::ops::Add>","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" >","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null},{"message":" <&'b u8 as std::ops::Add<&'a u8>>","code":null,"level":"help","spans":[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":5,"column_end":17,"text":[{"text":" 42u8 + 42i32;","highlight_start":5,"highlight_end":17}],"suggested_replacement":null,"expansion":null}],"children":[],"rendered":null}],"rendered":null} -{"message":"aborting due to 2 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":null} diff --git a/src/test/run-make/json-errors/foo.rs b/src/test/run-make/json-errors/foo.rs deleted file mode 100644 index 4db33940d8843..0000000000000 --- a/src/test/run-make/json-errors/foo.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn main() { - let x = 42 + y; - - 42u8 + 42i32; -} From 9d022f299359c341d2f57ab5425855556fc83937 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 17:47:42 -0400 Subject: [PATCH 60/97] rewrite span-length to include strings It is way easier to copy-and-paste strings from the output than to figure out how to reproduce them from first principles. --- .../run-make/unicode-input/span_length.rs | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index 3963d20df8873..f3bfe083016e7 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -65,8 +65,8 @@ fn main() { let err = String::from_utf8_lossy(&result.stderr); - // the span should end the line (e.g no extra ~'s) - let expected_span = format!("^{}\n", repeat("~").take(n - 1) + // the span should end the line (e.g no extra ^'s) + let expected_span = format!("^{}\n", repeat("^").take(n - 1) .collect::()); assert!(err.contains(&expected_span)); } @@ -91,17 +91,19 @@ fn main() { // Test both the length of the snake and the leading spaces up to it - // First snake is 8 ~s long, with 7 preceding spaces (excluding file name/line offset) - let expected_span = format!("\n{}^{}\n", - repeat(" ").take(offset + 7).collect::(), - repeat("~").take(8).collect::()); - assert!(err.contains(&expected_span)); - // Second snake is only 7 ~s long, with 36 preceding spaces, - // because rustc counts chars() now rather than width(). This - // is because width() functions are to be removed from - // librustc_unicode - let expected_span = format!("\n{}^{}\n", - repeat(" ").take(offset + 36).collect::(), - repeat("~").take(7).collect::()); - assert!(err.contains(&expected_span)); + // First snake is 9 ^s long. + let expected_1 = r#" +1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {} + |> ^^^^^^^^^ +"#; + assert!(err.contains(&expected_1)); + + // Second snake is only 8 ^s long, because rustc counts chars() + // now rather than width(). This is because width() functions are + // to be removed from librustc_unicode + let expected_2 = r#" +1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {} + |> ^^^^^^^^ +"#; + assert!(err.contains(&expected_2)); } From 1067850e6a8664eaabd59c3893aa5a762bdf2339 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 20 Apr 2016 20:00:25 -0400 Subject: [PATCH 61/97] refactor the Emitter trait There is now a CoreEmitter that everything desugars to, but without losing any information. Also remove RenderSpan::FileLine. This lets the rustc_driver tests build. --- src/librustc_driver/test.rs | 17 ++-- src/librustc_trans/back/write.rs | 16 +-- src/libsyntax/errors/emitter.rs | 163 ++++++++++++++----------------- src/libsyntax/errors/json.rs | 2 - src/libsyntax/errors/mod.rs | 7 +- 5 files changed, 92 insertions(+), 113 deletions(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 60f4ab1c95f2b..f2448d50b22bc 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -34,9 +34,9 @@ use std::cell::RefCell; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; -use syntax::codemap::{MultiSpan, CodeMap, DUMMY_SP}; +use syntax::codemap::{CodeMap, DUMMY_SP}; use syntax::errors; -use syntax::errors::emitter::Emitter; +use syntax::errors::emitter::{CoreEmitter, Emitter}; use syntax::errors::{Level, RenderSpan}; use syntax::parse::token; use syntax::feature_gate::UnstableFeatures; @@ -78,12 +78,13 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { } } -impl Emitter for ExpectErrorEmitter { - fn emit(&mut self, - _sp: Option<&MultiSpan>, - msg: &str, - _: Option<&str>, - lvl: Level) { +impl CoreEmitter for ExpectErrorEmitter { + fn emit_message(&mut self, + _sp: &RenderSpan, + msg: &str, + _: Option<&str>, + lvl: Level, + _is_header: bool) { remove_message(self, msg, lvl); } } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index ffd8c261b6055..a35048f89c114 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -20,8 +20,8 @@ use {CrateTranslation, ModuleTranslation}; use util::common::time; use util::common::path2cstr; use syntax::codemap::MultiSpan; -use syntax::errors::{self, Handler, Level}; -use syntax::errors::emitter::RudimentaryEmitter; +use syntax::errors::{self, Handler, Level, RenderSpan}; +use syntax::errors::emitter::CoreEmitter; use std::collections::HashMap; use std::ffi::{CStr, CString}; @@ -100,11 +100,13 @@ impl SharedEmitter { } } -impl RudimentaryEmitter for SharedEmitter { - fn emit_rudimentary(&mut self, - msg: &str, - code: Option<&str>, - lvl: Level) { +impl CoreEmitter for SharedEmitter { + fn emit_message(&mut self, + _rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + _is_header: bool) { self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), code: code.map(|s| s.to_string()), diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index f851937d82bc0..2b29de7fd7135 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -24,6 +24,8 @@ use std::io; use std::rc::Rc; use term; +/// Emitter trait for emitting errors. Do not implement this directly: +/// implement `CoreEmitter` instead. pub trait Emitter { /// Emit a standalone diagnostic message. fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level); @@ -32,27 +34,44 @@ pub trait Emitter { fn emit_struct(&mut self, db: &DiagnosticBuilder); } -/// A core trait that can only handle very simple messages: those -/// without spans or any real structure. Used only in specific contexts. -pub trait RudimentaryEmitter { - fn emit_rudimentary(&mut self, msg: &str, code: Option<&str>, lvl: Level); +pub trait CoreEmitter { + fn emit_message(&mut self, + rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + is_header: bool); } -impl Emitter for T { +impl Emitter for T { fn emit(&mut self, msp: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level) { - assert!(msp.primary_span().is_none(), "Rudimenatry emitters can't handle spans"); - self.emit_rudimentary(msg, code, lvl); + self.emit_message(&FullSpan(msp.clone()), + msg, + code, + lvl, + true); } fn emit_struct(&mut self, db: &DiagnosticBuilder) { - self.emit(&db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); + self.emit_message(&FullSpan(db.span.clone()), + &db.message, + db.code.as_ref().map(|s| &**s), + db.level, + true); for child in &db.children { - assert!(child.render_span.is_none(), "Rudimentary emitters can't handle render spans"); - self.emit(&child.span, &child.message, None, child.level); + let render_span = child.render_span + .clone() + .unwrap_or_else( + || FullSpan(child.span.clone())); + self.emit_message(&render_span, + &child.message, + None, + child.level, + false); } } } @@ -83,11 +102,14 @@ pub struct BasicEmitter { dst: Destination, } -impl RudimentaryEmitter for BasicEmitter { - fn emit_rudimentary(&mut self, - msg: &str, - code: Option<&str>, - lvl: Level) { +impl CoreEmitter for BasicEmitter { + fn emit_message(&mut self, + _rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + _is_header: bool) { + // we ignore the span as we have no access to a codemap at this point if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { panic!("failed to print diagnostics: {:?}", e); } @@ -112,28 +134,16 @@ pub struct EmitterWriter { first: bool, } -impl Emitter for EmitterWriter { - fn emit(&mut self, - msp: &MultiSpan, - msg: &str, - code: Option<&str>, - lvl: Level) { - self.emit_multispan(msp, msg, code, lvl, true); - } - - fn emit_struct(&mut self, db: &DiagnosticBuilder) { - self.emit_multispan(&db.span, &db.message, - db.code.as_ref().map(|s| &**s), db.level, true); - - for child in &db.children { - match child.render_span { - Some(ref sp) => - self.emit_renderspan(sp, &child.message, - child.level), - None => - self.emit_multispan(&child.span, - &child.message, None, child.level, false), - } +impl CoreEmitter for EmitterWriter { + fn emit_message(&mut self, + rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + is_header: bool) { + match self.emit_message_(rsp, msg, code, lvl, is_header) { + Ok(()) => { } + Err(e) => panic!("failed to emit error: {}", e) } } } @@ -173,83 +183,56 @@ impl EmitterWriter { EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, first: true } } - fn emit_multispan(&mut self, - span: &MultiSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - is_header: bool) { + fn emit_message_(&mut self, + rsp: &RenderSpan, + msg: &str, + code: Option<&str>, + lvl: Level, + is_header: bool) + -> io::Result<()> { if is_header { if self.first { self.first = false; } else { - match write!(self.dst, "\n") { - Ok(_) => { } - Err(e) => { - panic!("failed to print diagnostics: {:?}", e) - } - } + write!(self.dst, "\n")?; } } - let error = match span.primary_span() { - Some(COMMAND_LINE_SP) => { - self.emit_(&FileLine(span.clone()), msg, code, lvl) - } - Some(DUMMY_SP) | None => { - print_diagnostic(&mut self.dst, "", lvl, msg, code) - } - Some(_) => { - self.emit_(&FullSpan(span.clone()), msg, code, lvl) - } - }; - - if let Err(e) = error { - panic!("failed to print diagnostics: {:?}", e); - } - } - - fn emit_renderspan(&mut self, sp: &RenderSpan, msg: &str, lvl: Level) { - if let Err(e) = self.emit_(sp, msg, None, lvl) { - panic!("failed to print diagnostics: {:?}", e); - } - } - - fn emit_(&mut self, - rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level) - -> io::Result<()> { - let msp = rsp.span(); - let primary_span = msp.primary_span(); - match code { Some(code) if self.registry.as_ref() - .and_then(|registry| registry.find_description(code)).is_some() => - { + .and_then(|registry| registry.find_description(code)) + .is_some() => { let code_with_explain = String::from("--explain ") + code; print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))? } - _ => print_diagnostic(&mut self.dst, "", lvl, msg, code)? + _ => { + print_diagnostic(&mut self.dst, "", lvl, msg, code)? + } } + // Watch out for various nasty special spans; don't try to + // print any filename or anything for those. + match rsp.span().primary_span() { + Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => { + return Ok(()); + } + _ => { } + } + + // Otherwise, print out the snippet etc as needed. match *rsp { - FullSpan(_) => { + FullSpan(ref msp) => { self.highlight_lines(msp, lvl)?; - if let Some(primary_span) = primary_span { + if let Some(primary_span) = msp.primary_span() { self.print_macro_backtrace(primary_span)?; } } Suggestion(ref suggestion) => { self.highlight_suggestion(suggestion)?; - if let Some(primary_span) = primary_span { + if let Some(primary_span) = rsp.span().primary_span() { self.print_macro_backtrace(primary_span)?; } } - FileLine(..) => { - // no source text in this case! - } } Ok(()) diff --git a/src/libsyntax/errors/json.rs b/src/libsyntax/errors/json.rs index b343c3f3fbbc5..93c6268ccaea1 100644 --- a/src/libsyntax/errors/json.rs +++ b/src/libsyntax/errors/json.rs @@ -294,7 +294,6 @@ impl DiagnosticSpan { fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec { match *rsp { - RenderSpan::FileLine(ref msp) | RenderSpan::FullSpan(ref msp) => DiagnosticSpan::from_multispan(msp, je), RenderSpan::Suggestion(ref suggestion) => @@ -356,7 +355,6 @@ impl DiagnosticCode { impl JsonEmitter { fn render(&self, render_span: &RenderSpan) -> Option { match *render_span { - RenderSpan::FileLine(_) | RenderSpan::FullSpan(_) => { None } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 0de2e067802e2..d533ffb981a6b 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -38,10 +38,6 @@ pub enum RenderSpan { /// of hypothetical source code, where each `String` is spliced /// into the lines in place of the code covered by each span. Suggestion(CodeSuggestion), - - /// A FileLine renders with just a line for the message prefixed - /// by file:linenum. - FileLine(MultiSpan), } #[derive(Clone)] @@ -54,8 +50,7 @@ impl RenderSpan { fn span(&self) -> &MultiSpan { match *self { FullSpan(ref msp) | - Suggestion(CodeSuggestion { ref msp, .. }) | - FileLine(ref msp) => + Suggestion(CodeSuggestion { ref msp, .. }) => msp } } From 8013eebf2c77b7756b6a99aee2c38ef417c60e19 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Apr 2016 04:47:01 -0400 Subject: [PATCH 62/97] fix error message in librustc_driver tests --- src/librustc_driver/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index f2448d50b22bc..c6a0e0feff12a 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -73,6 +73,7 @@ fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { e.messages.remove(i); } None => { + debug!("Unexpected error: {} Expected: {:?}", msg, e.messages); panic!("Unexpected error: {} Expected: {:?}", msg, e.messages); } } @@ -446,7 +447,7 @@ fn contravariant_region_ptr_ok() { #[test] fn contravariant_region_ptr_err() { - test_env(EMPTY_SOURCE_STR, errors(&["lifetime mismatch"]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&["mismatched types"]), |env| { env.create_simple_region_hierarchy(); let t_rptr1 = env.t_rptr_scope(1); let t_rptr10 = env.t_rptr_scope(10); From 5adfe5bffedf0e98864d93381ca2ff2213d8fc88 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:48:54 -0400 Subject: [PATCH 63/97] Nit: comments should be uppercase letter --- src/libsyntax/codemap.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 5862538de2e04..93025c5833294 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -144,14 +144,14 @@ pub struct MultiSpan { #[derive(Clone, Debug)] pub struct SpanLabel { - /// the span we are going to include in the final snippet + /// The span we are going to include in the final snippet. pub span: Span, - /// is this a primary span? This is the "locus" of the message, - /// and is indicated with a `^^^^` underline, versus `----` + /// Is this a primary span? This is the "locus" of the message, + /// and is indicated with a `^^^^` underline, versus `----`. pub is_primary: bool, - /// what label should we attach to this span (if any)? + /// What label should we attach to this span (if any)? pub label: Option, } From 9a9c9afbe265b1fc9dbb1ed8bdb9b82523badf9c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:49:05 -0400 Subject: [PATCH 64/97] Fix whitespace --- src/test/compile-fail/issue-7092.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/issue-7092.rs b/src/test/compile-fail/issue-7092.rs index 638f45cd35776..26e1597b1db4b 100644 --- a/src/test/compile-fail/issue-7092.rs +++ b/src/test/compile-fail/issue-7092.rs @@ -18,7 +18,7 @@ fn foo(x: Whatever) { //~| expected type `Whatever` //~| found type `std::option::Option<_>` //~| expected enum `Whatever`, found enum `std::option::Option` - field.access(), + field.access(), } } From e56121c584893d8b46af5e4cd5d580d30f221d9f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:49:10 -0400 Subject: [PATCH 65/97] Do not import variants from RenderedLineKind --- src/libsyntax/errors/snippet/mod.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index cd8f705ab2e5f..0018667e67b65 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -103,7 +103,7 @@ pub enum RenderedLineKind { Annotations, Elision, } -use self::RenderedLineKind::*; +use self::RenderedLineKind as RLK; impl SnippetData { pub fn new(codemap: Rc, @@ -244,19 +244,19 @@ impl RenderedLine { impl RenderedLineKind { fn prefix(&self) -> StyledString { match *self { - SourceText { file: _, line_index } => + RLK::SourceText { file: _, line_index } => StyledString { text: format!("{}", line_index + 1), style: LineNumber, }, - Elision => + RLK::Elision => StyledString { text: String::from("..."), style: LineNumber, }, - PrimaryFileName | - OtherFileName | - Annotations => + RLK::PrimaryFileName | + RLK::OtherFileName | + RLK::Annotations => StyledString { text: String::from(""), style: LineNumber, @@ -296,7 +296,7 @@ impl StyledBuffer { //We know our first output line is source and the rest are highlights and labels output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() }); } else { - output.push(RenderedLine { text: styled_vec, kind: Annotations }); + output.push(RenderedLine { text: styled_vec, kind: RLK::Annotations }); } styled_vec = vec![]; } @@ -484,7 +484,7 @@ impl FileInfo { text: format!(":{}:{}", lo.line, lo.col.0 + 1), style: LineAndColumn, }], - kind: PrimaryFileName, + kind: RLK::PrimaryFileName, }); } None => { @@ -493,7 +493,7 @@ impl FileInfo { text: self.file.name.clone(), style: FileNameStyle, }], - kind: OtherFileName, + kind: RLK::OtherFileName, }); } } @@ -534,7 +534,7 @@ impl FileInfo { if prev_ends_at_eol && is_single_unlabeled_annotated_line { if !elide_unlabeled_region { output.push(RenderedLine::from((String::new(), - NoStyle, Elision))); + NoStyle, RLK::Elision))); elide_unlabeled_region = true; prev_ends_at_eol = true; } @@ -548,7 +548,7 @@ impl FileInfo { } } else { if group.len() > 1 { - output.push(RenderedLine::from((String::new(), NoStyle, Elision))); + output.push(RenderedLine::from((String::new(), NoStyle, RLK::Elision))); } else { let mut v: Vec = group.iter().flat_map(|line| self.render_line(line)).collect(); @@ -563,7 +563,7 @@ impl FileInfo { fn render_line(&self, line: &Line) -> Vec { let source_string = self.file.get_line(line.line_index) .unwrap_or(""); - let source_kind = SourceText { + let source_kind = RLK::SourceText { file: self.file.clone(), line_index: line.line_index, }; From d58a4becf3943c02b9815f3d3875fe8817e41c7b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:52:28 -0400 Subject: [PATCH 66/97] Nit: do not import variants from Style --- src/libsyntax/errors/snippet/mod.rs | 47 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 0018667e67b65..f86d4bdb147a6 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -90,7 +90,6 @@ pub enum Style { LabelSecondary, NoStyle, } -use self::Style::*; #[derive(Debug, Clone)] pub enum RenderedLineKind { @@ -247,19 +246,19 @@ impl RenderedLineKind { RLK::SourceText { file: _, line_index } => StyledString { text: format!("{}", line_index + 1), - style: LineNumber, + style: Style::LineNumber, }, RLK::Elision => StyledString { text: String::from("..."), - style: LineNumber, + style: Style::LineNumber, }, RLK::PrimaryFileName | RLK::OtherFileName | RLK::Annotations => StyledString { text: String::from(""), - style: LineNumber, + style: Style::LineNumber, }, } } @@ -275,7 +274,7 @@ impl StyledBuffer { let mut styled_vec: Vec = vec![]; for (row, row_style) in self.text.iter().zip(&self.styles) { - let mut current_style = NoStyle; + let mut current_style = Style::NoStyle; let mut current_text = String::new(); for (&c, &s) in row.iter().zip(row_style) { @@ -316,7 +315,7 @@ impl StyledBuffer { } else { while self.text[line].len() < col { self.text[line].push(' '); - self.styles[line].push(NoStyle); + self.styles[line].push(Style::NoStyle); } self.text[line].push(chr); self.styles[line].push(style); @@ -479,10 +478,10 @@ impl FileInfo { output.push(RenderedLine { text: vec![StyledString { text: lo.file.name.clone(), - style: FileNameStyle, + style: Style::FileNameStyle, }, StyledString { text: format!(":{}:{}", lo.line, lo.col.0 + 1), - style: LineAndColumn, + style: Style::LineAndColumn, }], kind: RLK::PrimaryFileName, }); @@ -491,7 +490,7 @@ impl FileInfo { output.push(RenderedLine { text: vec![StyledString { text: self.file.name.clone(), - style: FileNameStyle, + style: Style::FileNameStyle, }], kind: RLK::OtherFileName, }); @@ -534,7 +533,7 @@ impl FileInfo { if prev_ends_at_eol && is_single_unlabeled_annotated_line { if !elide_unlabeled_region { output.push(RenderedLine::from((String::new(), - NoStyle, RLK::Elision))); + Style::NoStyle, RLK::Elision))); elide_unlabeled_region = true; prev_ends_at_eol = true; } @@ -548,7 +547,7 @@ impl FileInfo { } } else { if group.len() > 1 { - output.push(RenderedLine::from((String::new(), NoStyle, RLK::Elision))); + output.push(RenderedLine::from((String::new(), Style::NoStyle, RLK::Elision))); } else { let mut v: Vec = group.iter().flat_map(|line| self.render_line(line)).collect(); @@ -571,7 +570,7 @@ impl FileInfo { let mut styled_buffer = StyledBuffer::new(); // First create the source line we will highlight. - styled_buffer.append(0, &source_string, Quotation); + styled_buffer.append(0, &source_string, Style::Quotation); if line.annotations.is_empty() { return styled_buffer.render(source_kind); @@ -606,10 +605,10 @@ impl FileInfo { for annotation in &annotations { for p in annotation.start_col .. annotation.end_col { if annotation.is_primary { - styled_buffer.putc(1, p, '^', UnderlinePrimary); - styled_buffer.set_style(0, p, UnderlinePrimary); + styled_buffer.putc(1, p, '^', Style::UnderlinePrimary); + styled_buffer.set_style(0, p, Style::UnderlinePrimary); } else { - styled_buffer.putc(1, p, '-', UnderlineSecondary); + styled_buffer.putc(1, p, '-', Style::UnderlineSecondary); } } } @@ -671,9 +670,9 @@ impl FileInfo { // string let highlight_label: String = format!(" {}", last.label.as_ref().unwrap()); if last.is_primary { - styled_buffer.append(1, &highlight_label, LabelPrimary); + styled_buffer.append(1, &highlight_label, Style::LabelPrimary); } else { - styled_buffer.append(1, &highlight_label, LabelSecondary); + styled_buffer.append(1, &highlight_label, Style::LabelSecondary); } labeled_annotations = previous; } @@ -696,18 +695,18 @@ impl FileInfo { // text ought to be long enough for this. for index in 2..blank_lines { if annotation.is_primary { - styled_buffer.putc(index, annotation.start_col, '|', UnderlinePrimary); + styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlinePrimary); } else { - styled_buffer.putc(index, annotation.start_col, '|', UnderlineSecondary); + styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlineSecondary); } } if annotation.is_primary { styled_buffer.puts(blank_lines, annotation.start_col, - annotation.label.as_ref().unwrap(), LabelPrimary); + annotation.label.as_ref().unwrap(), Style::LabelPrimary); } else { styled_buffer.puts(blank_lines, annotation.start_col, - annotation.label.as_ref().unwrap(), LabelSecondary); + annotation.label.as_ref().unwrap(), Style::LabelSecondary); } } @@ -752,7 +751,7 @@ fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { .chain(Some('>')) .chain(Some(' ')); line.text.insert(0, StyledString {text: dashes.collect(), - style: LineNumber}) + style: Style::LineNumber}) } RenderedLineKind::OtherFileName => { // >>>>> filename @@ -762,12 +761,12 @@ fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { let dashes = (0..padding_len + 2).map(|_| '>') .chain(Some(' ')); line.text.insert(0, StyledString {text: dashes.collect(), - style: LineNumber}) + style: Style::LineNumber}) } _ => { line.text.insert(0, prefix); line.text.insert(1, StyledString {text: String::from("|> "), - style: LineNumber}) + style: Style::LineNumber}) } } } From d5529f000da43fe2e9f2aad03f747b0144da9354 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 12:53:20 -0400 Subject: [PATCH 67/97] Nit: do not use RLK --- src/libsyntax/errors/snippet/mod.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index f86d4bdb147a6..4d9a3eb24860d 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -102,7 +102,6 @@ pub enum RenderedLineKind { Annotations, Elision, } -use self::RenderedLineKind as RLK; impl SnippetData { pub fn new(codemap: Rc, @@ -243,19 +242,19 @@ impl RenderedLine { impl RenderedLineKind { fn prefix(&self) -> StyledString { match *self { - RLK::SourceText { file: _, line_index } => + RenderedLineKind::SourceText { file: _, line_index } => StyledString { text: format!("{}", line_index + 1), style: Style::LineNumber, }, - RLK::Elision => + RenderedLineKind::Elision => StyledString { text: String::from("..."), style: Style::LineNumber, }, - RLK::PrimaryFileName | - RLK::OtherFileName | - RLK::Annotations => + RenderedLineKind::PrimaryFileName | + RenderedLineKind::OtherFileName | + RenderedLineKind::Annotations => StyledString { text: String::from(""), style: Style::LineNumber, @@ -295,7 +294,7 @@ impl StyledBuffer { //We know our first output line is source and the rest are highlights and labels output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() }); } else { - output.push(RenderedLine { text: styled_vec, kind: RLK::Annotations }); + output.push(RenderedLine { text: styled_vec, kind: RenderedLineKind::Annotations }); } styled_vec = vec![]; } @@ -483,7 +482,7 @@ impl FileInfo { text: format!(":{}:{}", lo.line, lo.col.0 + 1), style: Style::LineAndColumn, }], - kind: RLK::PrimaryFileName, + kind: RenderedLineKind::PrimaryFileName, }); } None => { @@ -492,7 +491,7 @@ impl FileInfo { text: self.file.name.clone(), style: Style::FileNameStyle, }], - kind: RLK::OtherFileName, + kind: RenderedLineKind::OtherFileName, }); } } @@ -533,7 +532,8 @@ impl FileInfo { if prev_ends_at_eol && is_single_unlabeled_annotated_line { if !elide_unlabeled_region { output.push(RenderedLine::from((String::new(), - Style::NoStyle, RLK::Elision))); + Style::NoStyle, + RenderedLineKind::Elision))); elide_unlabeled_region = true; prev_ends_at_eol = true; } @@ -547,7 +547,9 @@ impl FileInfo { } } else { if group.len() > 1 { - output.push(RenderedLine::from((String::new(), Style::NoStyle, RLK::Elision))); + output.push(RenderedLine::from((String::new(), + Style::NoStyle, + RenderedLineKind::Elision))); } else { let mut v: Vec = group.iter().flat_map(|line| self.render_line(line)).collect(); @@ -562,7 +564,7 @@ impl FileInfo { fn render_line(&self, line: &Line) -> Vec { let source_string = self.file.get_line(line.line_index) .unwrap_or(""); - let source_kind = RLK::SourceText { + let source_kind = RenderedLineKind::SourceText { file: self.file.clone(), line_index: line.line_index, }; From f6496cd3700a9a4e3dc1a6d3245287066f4b99e4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 13:06:28 -0400 Subject: [PATCH 68/97] Nit: address various style nits --- src/libsyntax/errors/emitter.rs | 7 ++++++- src/libsyntax/errors/snippet/mod.rs | 4 +--- src/libsyntax/errors/snippet/test.rs | 4 +++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 2b29de7fd7135..7cad1714625bb 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -131,6 +131,9 @@ pub struct EmitterWriter { dst: Destination, registry: Option, cm: Rc, + + /// Is this the first error emitted thus far? If not, we emit a + /// `\n` before the top-level errors. first: bool, } @@ -172,7 +175,9 @@ impl EmitterWriter { EmitterWriter { dst: dst, registry: registry, cm: code_map, first: true } } else { EmitterWriter { dst: Raw(Box::new(io::stderr())), - registry: registry, cm: code_map, first: true } + registry: registry, + cm: code_map, + first: true } } } diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 4d9a3eb24860d..ada336b29a48a 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -16,7 +16,6 @@ use std::rc::Rc; use std::mem; use std::ops::Range; -#[cfg(test)] mod test; pub struct SnippetData { @@ -210,8 +209,7 @@ impl From<(S, Style, RenderedLineKind)> for RenderedLine impl From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine where S1: StringSource, S2: StringSource { - fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) - -> Self { + fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) -> Self { let (text1, style1, text2, style2, kind) = tuple; RenderedLine { text: vec![ diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 44ece285b1b23..ccf50536adbab 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,6 +10,8 @@ // Code for testing annotated snippets. +#![cfg(test)] + use codemap::{BytePos, CodeMap, FileMap, NO_EXPANSION, Span}; use std::rc::Rc; use super::{RenderedLine, SnippetData}; From 94841bea7b5753ba29655ce60a99f329e8eb8f24 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 13:36:19 -0400 Subject: [PATCH 69/97] Nit: in emitter.rs --- src/libsyntax/errors/emitter.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 7cad1714625bb..07dafb0b7dff0 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -397,8 +397,7 @@ impl Destination { style: Style) -> io::Result<()> { match style { - Style::FileNameStyle => { - } + Style::FileNameStyle | Style::LineAndColumn => { } Style::LineNumber => { From 24f4b151b11b22b66ac0128f76c1e12cca45b178 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 13:36:30 -0400 Subject: [PATCH 70/97] Nit: use last_mut better --- src/libsyntax/errors/snippet/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index ada336b29a48a..0c8b4f2046a49 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -229,10 +229,9 @@ impl From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine impl RenderedLine { fn trim_last(&mut self) { - if !self.text.is_empty() { - let last_text = &mut self.text.last_mut().unwrap().text; - let len = last_text.trim_right().len(); - last_text.truncate(len); + if let Some(last_text) = self.text.last_mut() { + let len = last_text.text.trim_right().len(); + last_text.text.truncate(len); } } } From 1fdbfcdbd0a6a63317872fef24222533bbc8cfaf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 09:33:38 -0700 Subject: [PATCH 71/97] only emit `^` at the start of a multi-line error as a result, simplify elision code --- src/libsyntax/errors/emitter.rs | 15 +-- src/libsyntax/errors/snippet/mod.rs | 184 +++++++++------------------ src/libsyntax/errors/snippet/test.rs | 11 +- 3 files changed, 67 insertions(+), 143 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 07dafb0b7dff0..eaa973db2b8c7 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -543,7 +543,7 @@ mod test { dreizehn "; let file = cm.new_filemap_and_lines("dummy.txt", content); - let start = file.lines.borrow()[7]; + let start = file.lines.borrow()[10]; let end = file.lines.borrow()[11]; let sp = mk_sp(start, end); let lvl = Level::Error; @@ -555,12 +555,9 @@ mod test { let str = from_utf8(vec).unwrap(); println!("r#\"\n{}\"#", str); assert_eq!(str, &r#" - --> dummy.txt:8:1 -8 |> line8 - |> ^^^^^^^^^^^^^ -... + --> dummy.txt:11:1 11 |> e-lä-vän - |> ^^^^^^^^^^^^^^^^ + |> ^ "#[1..]); } @@ -696,9 +693,8 @@ mod test { let expect0 = &r#" --> dummy.txt:5:1 5 |> ccccc - |> ^^^^^ + |> ^ ... -8 |> _____ 9 |> ddd__eee_ |> ^^^ ^^^ 10 |> elided @@ -709,9 +705,8 @@ mod test { let expect = &r#" --> dummy.txt:1:1 1 |> aaaaa - |> ^^^^^ + |> ^ ... -8 |> _____ 9 |> ddd__eee_ |> ^^^ ^^^ 10 |> elided diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 0c8b4f2046a49..643b5c3c5f236 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -49,7 +49,7 @@ struct Annotation { /// column. start_col: usize, - /// End column within the line. + /// End column within the line (exclusive) end_col: usize, /// Is this annotation derived from primary span @@ -349,24 +349,40 @@ impl FileInfo { label: Option) { assert!(lines.len() > 0); - // If a span covers multiple lines, just put the label on the - // first one. This is a sort of arbitrary choice and not - // obviously correct. - let (line0, remaining_lines) = lines.split_first().unwrap(); - let index = self.ensure_source_line(line0.line_index); - self.lines[index].push_annotation(line0.start_col, - line0.end_col, + // If a span covers multiple lines, we reduce it to a single + // point at the start of the span. This means that instead + // of producing output like this: + // + // ``` + // --> foo.rs:2:1 + // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>) + // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // 3 |> -> Set> + // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // (and so on) + // ``` + // + // we produce: + // + // ``` + // --> foo.rs:2:1 + // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>) + // ^ + // ``` + // + // Basically, although this loses information, multi-line spans just + // never look good. + + let (line, start_col, end_col) = if lines.len() == 1 { + (lines[0].line_index, lines[0].start_col, lines[0].end_col) + } else { + (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1)) + }; + let index = self.ensure_source_line(line); + self.lines[index].push_annotation(start_col, + end_col, is_primary, label); - for line in remaining_lines { - if line.end_col > line.start_col { - let index = self.ensure_source_line(line.line_index); - self.lines[index].push_annotation(line.start_col, - line.end_col, - is_primary, - None); - } - } } /// Ensure that we have a `Line` struct corresponding to @@ -414,57 +430,10 @@ impl FileInfo { } fn render_file_lines(&self, codemap: &Rc) -> Vec { - // Group our lines by those with annotations and those without - let mut lines_iter = self.lines.iter().peekable(); - - let mut line_groups = vec![]; - - loop { - match lines_iter.next() { - None => break, - Some(line) if line.annotations.is_empty() => { - // Collect unannotated group - let mut unannotated_group : Vec<&Line> = vec![]; - - unannotated_group.push(line); - - loop { - let next_line = - match lines_iter.peek() { - None => break, - Some(x) if !x.annotations.is_empty() => break, - Some(x) => x.clone() - }; - - unannotated_group.push(next_line); - lines_iter.next(); - } - - line_groups.push((false, unannotated_group)); - } - Some(line) => { - // Collect annotated group - let mut annotated_group : Vec<&Line> = vec![]; - - annotated_group.push(line); - - loop { - let next_line = - match lines_iter.peek() { - None => break, - Some(x) if x.annotations.is_empty() => break, - Some(x) => x.clone() - }; - - annotated_group.push(next_line); - lines_iter.next(); - } - - line_groups.push((true, annotated_group)); - } - } - } + // As a first step, we elide any instance of more than one + // continuous unannotated line. + let mut lines_iter = self.lines.iter(); let mut output = vec![]; // First insert the name of the file. @@ -493,65 +462,30 @@ impl FileInfo { } } - for &(is_annotated, ref group) in line_groups.iter() { - if is_annotated { - let mut annotation_ends_at_eol = false; - let mut prev_ends_at_eol = false; - let mut elide_unlabeled_region = false; - - for group_line in group.iter() { - let source_string_len = - self.file.get_line(group_line.line_index) - .map(|s| s.len()) - .unwrap_or(0); - - for annotation in &group_line.annotations { - if annotation.end_col == source_string_len { - annotation_ends_at_eol = true; - } - } - - let is_single_unlabeled_annotated_line = - if group_line.annotations.len() == 1 { - if let Some(annotation) = group_line.annotations.first() { - match annotation.label { - Some(_) => false, - None => annotation.start_col == 0 && - annotation.end_col == source_string_len - } - } else { - false - } - } else { - false - }; - - if prev_ends_at_eol && is_single_unlabeled_annotated_line { - if !elide_unlabeled_region { - output.push(RenderedLine::from((String::new(), - Style::NoStyle, - RenderedLineKind::Elision))); - elide_unlabeled_region = true; - prev_ends_at_eol = true; - } - continue; - } - - let mut v = self.render_line(group_line); - output.append(&mut v); + let mut next_line = lines_iter.next(); + while next_line.is_some() { + // Consume lines with annotations. + while let Some(line) = next_line { + if line.annotations.is_empty() { break; } + output.append(&mut self.render_line(line)); + next_line = lines_iter.next(); + } - prev_ends_at_eol = annotation_ends_at_eol; - } - } else { - if group.len() > 1 { - output.push(RenderedLine::from((String::new(), - Style::NoStyle, - RenderedLineKind::Elision))); - } else { - let mut v: Vec = - group.iter().flat_map(|line| self.render_line(line)).collect(); - output.append(&mut v); - } + // Emit lines without annotations, but only if they are + // followed by a line with an annotation. + let unannotated_line = next_line; + let mut unannotated_lines = 0; + while let Some(line) = next_line { + if !line.annotations.is_empty() { break; } + unannotated_lines += 1; + next_line = lines_iter.next(); + } + if unannotated_lines > 1 { + output.push(RenderedLine::from((String::new(), + Style::NoStyle, + RenderedLineKind::Elision))); + } else if let Some(line) = unannotated_line { + output.append(&mut self.render_line(line)); } } diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index ccf50536adbab..d995d828bc727 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -406,8 +406,7 @@ impl SomeTrait for () { assert_eq!(text, &r#" >>>>>> foo.rs 3 |> fn foo(x: u32) { - |> ---------------- -... + |> - "#[1..]); } @@ -515,12 +514,8 @@ fn span_overlap_label3() { assert_eq!(text, &r#" >>>> foo.rs 3 |> let closure = || { - |> ---- foo + |> - foo 4 |> inner - |> ---------------- - |> | - |> bar -5 |> }; - |> -------- + |> ---- bar "#[1..]); } From 883b9699098e43453c0f4b9c3fd2a6fa16afcb35 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 21:06:53 -0400 Subject: [PATCH 72/97] Nit: add comment --- src/libsyntax/codemap.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 93025c5833294..1efd415685cc6 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -334,9 +334,11 @@ impl MultiSpan { &self.primary_spans } - /// Returns the strings to highlight. If we have an explicit set, - /// return those, otherwise just give back an (unlabeled) version - /// of the primary span. + /// Returns the strings to highlight. We always ensure that there + /// is an entry for each of the primary spans -- for each primary + /// span P, if there is at least one label with span P, we return + /// those labels (marked as primary). But otherwise we return + /// `SpanLabel` instances with empty labels. pub fn span_labels(&self) -> Vec { let is_primary = |span| self.primary_spans.contains(&span); let mut span_labels = vec![]; From 5db4d620f2727113dfd5dd16fdb9417b9afda9d2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 21:08:54 -0400 Subject: [PATCH 73/97] Nit: remove push_primary_span, which was never called --- src/libsyntax/codemap.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 1efd415685cc6..ca8708fdc8326 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -316,10 +316,6 @@ impl MultiSpan { } } - pub fn push_primary_span(&mut self, span: Span) { - self.primary_spans.push(span); - } - pub fn push_span_label(&mut self, span: Span, label: String) { self.span_labels.push((span, label)); } From ba12ed06edf119c1d543158b8d0ac7d7ec503d82 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 22:52:56 -0400 Subject: [PATCH 74/97] fix tests better --- src/libsyntax/errors/emitter.rs | 4 ++-- src/libsyntax/errors/snippet/test.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index eaa973db2b8c7..cea6dbb75d981 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -556,8 +556,8 @@ mod test { println!("r#\"\n{}\"#", str); assert_eq!(str, &r#" --> dummy.txt:11:1 -11 |> e-lä-vän - |> ^ +11 |> e-lä-vän + |> ^ "#[1..]); } diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index d995d828bc727..286a3e3d40715 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -405,8 +405,8 @@ impl SomeTrait for () { println!("r#\"\n{}\"", text); assert_eq!(text, &r#" >>>>>> foo.rs -3 |> fn foo(x: u32) { - |> - +3 |> fn foo(x: u32) { + |> - "#[1..]); } @@ -516,6 +516,6 @@ fn span_overlap_label3() { 3 |> let closure = || { |> - foo 4 |> inner - |> ---- bar + |> ----- bar "#[1..]); } From 8a9ad72c1d67261049aac1d067529da48adcc644 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 26 Apr 2016 22:59:15 -0400 Subject: [PATCH 75/97] Nit: use Range::contains --- src/libsyntax/errors/snippet/mod.rs | 9 ++------- src/libsyntax/lib.rs | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 643b5c3c5f236..feaf48352db86 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -14,7 +14,6 @@ use codemap::{CharPos, CodeMap, FileMap, LineInfo, Span}; use std::cmp; use std::rc::Rc; use std::mem; -use std::ops::Range; mod test; @@ -744,10 +743,6 @@ fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { - between(a1.start_col, a2.start_col .. a2.end_col) || - between(a2.start_col, a1.start_col .. a1.end_col) -} - -fn between(v: usize, range: Range) -> bool { - v >= range.start && v < range.end + (a2.start_col .. a2.end_col).contains(a1.start_col) || + (a1.start_col .. a1.end_col).contains(a2.start_col) } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 6cfa1e9847b88..420a41e03b914 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -33,6 +33,7 @@ #![feature(str_escape)] #![feature(unicode)] #![feature(question_mark)] +#![feature(range_contains)] extern crate serialize; extern crate term; From 790043b44e0c078c0f80b16cd03d1aeac6ef242b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 27 Apr 2016 10:45:35 -0400 Subject: [PATCH 76/97] fix snippet tests MORE! --- src/libsyntax/errors/emitter.rs | 2 +- src/libsyntax/errors/snippet/test.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index cea6dbb75d981..b5be0fa16dd45 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -555,7 +555,7 @@ mod test { let str = from_utf8(vec).unwrap(); println!("r#\"\n{}\"#", str); assert_eq!(str, &r#" - --> dummy.txt:11:1 + --> dummy.txt:11:1 11 |> e-lä-vän |> ^ "#[1..]); diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 286a3e3d40715..56c891daa12fb 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -404,7 +404,7 @@ impl SomeTrait for () { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>>>> foo.rs +>>>> foo.rs 3 |> fn foo(x: u32) { |> - "#[1..]); From 89d086be74d5ddf21d67f2a3c27a29cca2631bba Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 27 Apr 2016 19:51:12 -0400 Subject: [PATCH 77/97] change color of warning to YELLOW --- src/libsyntax/errors/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index d533ffb981a6b..feac8aadc1e05 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -656,7 +656,7 @@ impl Level { fn color(self) -> term::color::Color { match self { Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, - Warning => term::color::BRIGHT_MAGENTA, + Warning => term::color::YELLOW, Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, Cancelled => unreachable!(), From 49dfac487267b574c802e0bdf5a66c5ff0624340 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 27 Apr 2016 19:59:57 -0400 Subject: [PATCH 78/97] move "lint level defined here" into secondary note It does not help you to understand the error, just explains why you are seeing it, so it is clearly secondary. --- src/librustc/lint/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 4ea6845b3c4f4..43c0e197e16bc 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -462,7 +462,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session, if let Some(span) = def { let explanation = "lint level defined here"; - err = err.span_label(span, &explanation); + err.span_note(span, &explanation); } err From 84cb56f8ee11ba89914462e478f06e9c1e8e7971 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 28 Apr 2016 16:39:59 -0700 Subject: [PATCH 79/97] Add back in a 'old school' error format --- src/libsyntax/errors/emitter.rs | 116 ++++++++++++++++++++---- src/libsyntax/errors/snippet/mod.rs | 135 +++++++++++++++++++++------- 2 files changed, 201 insertions(+), 50 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index b5be0fa16dd45..7f4d1a9dc349a 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -135,6 +135,9 @@ pub struct EmitterWriter { /// Is this the first error emitted thus far? If not, we emit a /// `\n` before the top-level errors. first: bool, + + // For now, allow an old-school mode while we transition + old_school: bool, } impl CoreEmitter for EmitterWriter { @@ -170,14 +173,23 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; if color_config.use_color() { let dst = Destination::from_stderr(); - EmitterWriter { dst: dst, registry: registry, cm: code_map, first: true } + EmitterWriter { dst: dst, + registry: registry, + cm: code_map, + first: true, + old_school: old_school } } else { EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map, - first: true } + first: true, + old_school: old_school } } } @@ -185,7 +197,15 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { - EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, first: true } + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; + EmitterWriter { dst: Raw(dst), + registry: registry, + cm: code_map, + first: true, + old_school: old_school } } fn emit_message_(&mut self, @@ -199,7 +219,9 @@ impl EmitterWriter { if self.first { self.first = false; } else { - write!(self.dst, "\n")?; + if !self.old_school { + write!(self.dst, "\n")?; + } } } @@ -208,7 +230,17 @@ impl EmitterWriter { .and_then(|registry| registry.find_description(code)) .is_some() => { let code_with_explain = String::from("--explain ") + code; - print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))? + if self.old_school { + let loc = match rsp.span().primary_span() { + Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), + Some(ps) => self.cm.span_to_string(ps), + None => "".to_string() + }; + print_diagnostic(&mut self.dst, &loc, lvl, msg, Some(code))? + } + else { + print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))? + } } _ => { print_diagnostic(&mut self.dst, "", lvl, msg, code)? @@ -239,7 +271,24 @@ impl EmitterWriter { } } } - + if self.old_school { + match code { + Some(code) if self.registry.as_ref() + .and_then(|registry| registry.find_description(code)) + .is_some() => { + let loc = match rsp.span().primary_span() { + Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), + Some(ps) => self.cm.span_to_string(ps), + None => "".to_string() + }; + let msg = "run `rustc --explain ".to_string() + &code.to_string() + + "` to see a detailed explanation"; + print_diagnostic(&mut self.dst, &loc, Level::Help, &msg, + None)? + } + _ => () + } + } Ok(()) } @@ -282,19 +331,48 @@ impl EmitterWriter { { let mut snippet_data = SnippetData::new(self.cm.clone(), msp.primary_span()); - for span_label in msp.span_labels() { - snippet_data.push(span_label.span, - span_label.is_primary, - span_label.label); + if self.old_school { + let mut output_vec = vec![]; + for span_label in msp.span_labels() { + let mut snippet_data = snippet_data.clone(); + snippet_data.push(span_label.span, + span_label.is_primary, + span_label.label); + if span_label.is_primary { + output_vec.insert(0, snippet_data); + } + else { + output_vec.push(snippet_data); + } + } + + for snippet_data in output_vec.iter() { + let rendered_lines = snippet_data.render_lines(); + for rendered_line in &rendered_lines { + for styled_string in &rendered_line.text { + self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?; + write!(&mut self.dst, "{}", styled_string.text)?; + self.dst.reset_attrs()?; + } + write!(&mut self.dst, "\n")?; + } + } } - let rendered_lines = snippet_data.render_lines(); - for rendered_line in &rendered_lines { - for styled_string in &rendered_line.text { - self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?; - write!(&mut self.dst, "{}", styled_string.text)?; - self.dst.reset_attrs()?; + else { + for span_label in msp.span_labels() { + snippet_data.push(span_label.span, + span_label.is_primary, + span_label.label); + } + let rendered_lines = snippet_data.render_lines(); + for rendered_line in &rendered_lines { + for styled_string in &rendered_line.text { + self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?; + write!(&mut self.dst, "{}", styled_string.text)?; + self.dst.reset_attrs()?; + } + write!(&mut self.dst, "\n")?; } - write!(&mut self.dst, "\n")?; } Ok(()) } @@ -327,7 +405,6 @@ fn line_num_max_digits(line: &codemap::LineInfo) -> usize { digits } - fn print_diagnostic(dst: &mut Destination, topic: &str, lvl: Level, @@ -335,7 +412,6 @@ fn print_diagnostic(dst: &mut Destination, code: Option<&str>) -> io::Result<()> { if !topic.is_empty() { - dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?; write!(dst, "{}: ", topic)?; dst.reset_attrs()?; } @@ -346,10 +422,12 @@ fn print_diagnostic(dst: &mut Destination, write!(dst, ": ")?; dst.start_attr(term::Attr::Bold)?; write!(dst, "{}", msg)?; + if let Some(code) = code { let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA); print_maybe_styled!(dst, style, " [{}]", code.clone())?; } + dst.reset_attrs()?; write!(dst, "\n")?; Ok(()) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index feaf48352db86..18a64cc399c42 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -17,11 +17,13 @@ use std::mem; mod test; +#[derive(Clone)] pub struct SnippetData { codemap: Rc, files: Vec, } +#[derive(Clone)] pub struct FileInfo { file: Rc, @@ -35,6 +37,7 @@ pub struct FileInfo { lines: Vec, } +#[derive(Clone)] struct Line { line_index: usize, annotations: Vec, @@ -429,6 +432,10 @@ impl FileInfo { } fn render_file_lines(&self, codemap: &Rc) -> Vec { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; // As a first step, we elide any instance of more than one // continuous unannotated line. @@ -436,28 +443,30 @@ impl FileInfo { let mut output = vec![]; // First insert the name of the file. - match self.primary_span { - Some(span) => { - let lo = codemap.lookup_char_pos(span.lo); - output.push(RenderedLine { - text: vec![StyledString { - text: lo.file.name.clone(), - style: Style::FileNameStyle, - }, StyledString { - text: format!(":{}:{}", lo.line, lo.col.0 + 1), - style: Style::LineAndColumn, - }], - kind: RenderedLineKind::PrimaryFileName, - }); - } - None => { - output.push(RenderedLine { - text: vec![StyledString { - text: self.file.name.clone(), - style: Style::FileNameStyle, - }], - kind: RenderedLineKind::OtherFileName, - }); + if !old_school { + match self.primary_span { + Some(span) => { + let lo = codemap.lookup_char_pos(span.lo); + output.push(RenderedLine { + text: vec![StyledString { + text: lo.file.name.clone(), + style: Style::FileNameStyle, + }, StyledString { + text: format!(":{}:{}", lo.line, lo.col.0 + 1), + style: Style::LineAndColumn, + }], + kind: RenderedLineKind::PrimaryFileName, + }); + } + None => { + output.push(RenderedLine { + text: vec![StyledString { + text: self.file.name.clone(), + style: Style::FileNameStyle, + }], + kind: RenderedLineKind::OtherFileName, + }); + } } } @@ -466,7 +475,31 @@ impl FileInfo { // Consume lines with annotations. while let Some(line) = next_line { if line.annotations.is_empty() { break; } - output.append(&mut self.render_line(line)); + + let mut rendered_line = self.render_line(line); + if old_school { + match self.primary_span { + Some(span) => { + let lo = codemap.lookup_char_pos(span.lo); + rendered_line[0].text.insert(0, StyledString { + text: format!(":{} ", lo.line), + style: Style::LineAndColumn, + }); + rendered_line[0].text.insert(0, StyledString { + text: lo.file.name.clone(), + style: Style::FileNameStyle, + }); + let gap_amount = rendered_line[0].text[0].text.len() + + rendered_line[0].text[1].text.len(); + rendered_line[1].text.insert(0, StyledString { + text: vec![" "; gap_amount].join(""), + style: Style::NoStyle + }); + } + _ =>() + } + } + output.append(&mut rendered_line); next_line = lines_iter.next(); } @@ -492,6 +525,10 @@ impl FileInfo { } fn render_line(&self, line: &Line) -> Vec { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; let source_string = self.file.get_line(line.line_index) .unwrap_or(""); let source_kind = RenderedLineKind::SourceText { @@ -535,12 +572,34 @@ impl FileInfo { // Next, create the highlight line. for annotation in &annotations { - for p in annotation.start_col .. annotation.end_col { - if annotation.is_primary { - styled_buffer.putc(1, p, '^', Style::UnderlinePrimary); - styled_buffer.set_style(0, p, Style::UnderlinePrimary); - } else { - styled_buffer.putc(1, p, '-', Style::UnderlineSecondary); + if old_school { + for p in annotation.start_col .. annotation.end_col { + if p == annotation.start_col { + styled_buffer.putc(1, p, '^', + if annotation.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }); + } + else { + styled_buffer.putc(1, p, '~', + if annotation.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }); + } + } + } + else { + for p in annotation.start_col .. annotation.end_col { + if annotation.is_primary { + styled_buffer.putc(1, p, '^', Style::UnderlinePrimary); + styled_buffer.set_style(0, p, Style::UnderlinePrimary); + } else { + styled_buffer.putc(1, p, '-', Style::UnderlineSecondary); + } } } } @@ -555,6 +614,9 @@ impl FileInfo { if labeled_annotations.is_empty() { return styled_buffer.render(source_kind); } + if old_school { + return styled_buffer.render(source_kind); + } // Now add the text labels. We try, when possible, to stick the rightmost // annotation at the end of the highlight line: @@ -647,6 +709,14 @@ impl FileInfo { } fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; + if old_school { + return; + } + let prefixes: Vec<_> = rendered_lines.iter() .map(|rl| rl.kind.prefix()) @@ -686,11 +756,14 @@ fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { style: Style::LineNumber}) } RenderedLineKind::OtherFileName => { - // >>>>> filename + // ::: filename // 22 |> // ^ // padding_len - let dashes = (0..padding_len + 2).map(|_| '>') + let dashes = (0..padding_len - 1).map(|_| ' ') + .chain(Some(':')) + .chain(Some(':')) + .chain(Some(':')) .chain(Some(' ')); line.text.insert(0, StyledString {text: dashes.collect(), style: Style::LineNumber}) From 79f61a45328e534e52cf705452b33ae4b8ae474d Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 29 Apr 2016 13:27:40 -0700 Subject: [PATCH 80/97] Finish up with 'old school' error mode --- src/librustc_trans/back/write.rs | 3 +- src/libsyntax/errors/emitter.rs | 75 +++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index a35048f89c114..10bcf83d7556f 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -106,7 +106,8 @@ impl CoreEmitter for SharedEmitter { msg: &str, code: Option<&str>, lvl: Level, - _is_header: bool) { + _is_header: bool, + _show_snippet: bool) { self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), code: code.map(|s| s.to_string()), diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 7f4d1a9dc349a..769f6b0539706 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -40,7 +40,8 @@ pub trait CoreEmitter { msg: &str, code: Option<&str>, lvl: Level, - is_header: bool); + is_header: bool, + show_snippet: bool); } impl Emitter for T { @@ -53,25 +54,47 @@ impl Emitter for T { msg, code, lvl, + true, true); } fn emit_struct(&mut self, db: &DiagnosticBuilder) { + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; + let db_span = FullSpan(db.span.clone()); self.emit_message(&FullSpan(db.span.clone()), &db.message, db.code.as_ref().map(|s| &**s), db.level, + true, true); for child in &db.children { let render_span = child.render_span .clone() .unwrap_or_else( || FullSpan(child.span.clone())); - self.emit_message(&render_span, - &child.message, - None, - child.level, - false); + + if !old_school { + self.emit_message(&render_span, + &child.message, + None, + child.level, + false, + true); + } else { + let (render_span, show_snippet) = match render_span.span().primary_span() { + None => (db_span.clone(), false), + _ => (render_span, true) + }; + self.emit_message(&render_span, + &child.message, + None, + child.level, + false, + show_snippet); + } } } } @@ -108,7 +131,8 @@ impl CoreEmitter for BasicEmitter { msg: &str, code: Option<&str>, lvl: Level, - _is_header: bool) { + _is_header: bool, + _show_snippet: bool) { // we ignore the span as we have no access to a codemap at this point if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) { panic!("failed to print diagnostics: {:?}", e); @@ -146,8 +170,9 @@ impl CoreEmitter for EmitterWriter { msg: &str, code: Option<&str>, lvl: Level, - is_header: bool) { - match self.emit_message_(rsp, msg, code, lvl, is_header) { + is_header: bool, + show_snippet: bool) { + match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) { Ok(()) => { } Err(e) => panic!("failed to emit error: {}", e) } @@ -213,7 +238,8 @@ impl EmitterWriter { msg: &str, code: Option<&str>, lvl: Level, - is_header: bool) + is_header: bool, + show_snippet: bool) -> io::Result<()> { if is_header { if self.first { @@ -243,10 +269,24 @@ impl EmitterWriter { } } _ => { - print_diagnostic(&mut self.dst, "", lvl, msg, code)? + if self.old_school { + let loc = match rsp.span().primary_span() { + Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), + Some(ps) => self.cm.span_to_string(ps), + None => "".to_string() + }; + print_diagnostic(&mut self.dst, &loc, lvl, msg, code)? + } + else { + print_diagnostic(&mut self.dst, "", lvl, msg, code)? + } } } + if !show_snippet { + return Ok(()); + } + // Watch out for various nasty special spans; don't try to // print any filename or anything for those. match rsp.span().primary_span() { @@ -333,8 +373,10 @@ impl EmitterWriter { msp.primary_span()); if self.old_school { let mut output_vec = vec![]; + for span_label in msp.span_labels() { let mut snippet_data = snippet_data.clone(); + snippet_data.push(span_label.span, span_label.is_primary, span_label.label); @@ -412,7 +454,16 @@ fn print_diagnostic(dst: &mut Destination, code: Option<&str>) -> io::Result<()> { if !topic.is_empty() { - write!(dst, "{}: ", topic)?; + let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { + Ok(_) => false, + Err(_) => true, + }; + if !old_school { + write!(dst, "{}: ", topic)?; + } + else { + write!(dst, "{} ", topic)?; + } dst.reset_attrs()?; } dst.start_attr(term::Attr::Bold)?; From 5974e5b294ee3b67054a31eae2a4b9bab950a119 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Fri, 29 Apr 2016 14:06:20 -0700 Subject: [PATCH 81/97] Fix up error-pattern style test --- src/test/compile-fail/issue-14091.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/compile-fail/issue-14091.rs b/src/test/compile-fail/issue-14091.rs index ccaeeab8b4789..9c594ef485fd7 100644 --- a/src/test/compile-fail/issue-14091.rs +++ b/src/test/compile-fail/issue-14091.rs @@ -9,8 +9,5 @@ // except according to those terms. // error-pattern:mismatched types -// error-pattern:expected bool, found integral variable -// error-pattern:expected type `bool` -// error-pattern:found type `_` fn main(){assert!(1,1);} From 2ba5fac1a460de9936b85f9459668b0992f21f06 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 29 Apr 2016 18:08:02 -0400 Subject: [PATCH 82/97] fix rebase flaws --- src/librustc_driver/lib.rs | 5 ++--- src/librustc_resolve/lib.rs | 3 +-- src/libsyntax_ext/deriving/mod.rs | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 52306e388e235..d03ae45e83fe8 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -91,9 +91,8 @@ use std::thread; use rustc::session::early_error; -use syntax::{ast, errors, diagnostic}; -use syntax::codemap::MultiSpan; -use syntax::parse::{self, PResult}; +use syntax::{ast, errors, diagnostics}; +use syntax::codemap::{CodeMap, FileLoader, RealFileLoader, MultiSpan}; use syntax::errors::emitter::Emitter; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult, token}; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1bb99eb1a5e0e..e747ed1526061 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1784,8 +1784,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If it's a typedef, give a note if let Def::TyAlias(..) = path_res.base_def { - err.note(trait_path.span, - "`type` aliases cannot be used for traits"); + err.note("`type` aliases cannot be used for traits"); let definition_site = { let segments = &trait_path.segments; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 4ca3196b9c5ec..91c272c59c4a6 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -204,9 +204,9 @@ macro_rules! derive_traits { sp, feature_gate::EXPLAIN_DERIVE_UNDERSCORE, ); if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_none() { - w.fileline_help( - sp, &format!("add #![feature(custom_derive)] to \ - the crate attributes to enable") + w.help( + &format!("add #![feature(custom_derive)] to \ + the crate attributes to enable") ); } w.emit(); From 95576b8ec40538fc311029dd838d2a22c0e9af7f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 29 Apr 2016 21:13:42 -0400 Subject: [PATCH 83/97] update unit tests --- src/libsyntax/errors/emitter.rs | 21 +++++---------------- src/libsyntax/errors/mod.rs | 17 +++++++++++++++++ src/libsyntax/errors/snippet/mod.rs | 17 +++++------------ src/libsyntax/errors/snippet/test.rs | 22 +++++++++++----------- 4 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 769f6b0539706..486e2ace0876a 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -13,6 +13,7 @@ use self::Destination::*; use codemap::{self, COMMAND_LINE_SP, DUMMY_SP, Pos, Span, MultiSpan}; use diagnostics; +use errors::check_old_skool; use errors::{Level, RenderSpan, CodeSuggestion, DiagnosticBuilder}; use errors::RenderSpan::*; use errors::Level::*; @@ -59,10 +60,7 @@ impl Emitter for T { } fn emit_struct(&mut self, db: &DiagnosticBuilder) { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); let db_span = FullSpan(db.span.clone()); self.emit_message(&FullSpan(db.span.clone()), &db.message, @@ -198,10 +196,7 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); if color_config.use_color() { let dst = Destination::from_stderr(); EmitterWriter { dst: dst, @@ -222,10 +217,7 @@ impl EmitterWriter { registry: Option, code_map: Rc) -> EmitterWriter { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, @@ -454,10 +446,7 @@ fn print_diagnostic(dst: &mut Destination, code: Option<&str>) -> io::Result<()> { if !topic.is_empty() { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); if !old_school { write!(dst, "{}: ", topic)?; } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index feac8aadc1e05..4ade537c8ce04 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -683,3 +683,20 @@ pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where None => diag.bug(&msg()), } } + +/// True if we should use the old-skool error format style. This is +/// the default setting until the new errors are deemed stable enough +/// for general use. +/// +/// FIXME(#33240) +#[cfg(not(test))] +fn check_old_skool() -> bool { + use std::env; + env::var("RUST_NEW_ERROR_FORMAT").is_err() +} + +/// For unit tests, use the new format. +#[cfg(test)] +fn check_old_skool() -> bool { + false +} diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 18a64cc399c42..6c90bfd08186b 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -11,6 +11,7 @@ // Code for annotating snippets. use codemap::{CharPos, CodeMap, FileMap, LineInfo, Span}; +use errors::check_old_skool; use std::cmp; use std::rc::Rc; use std::mem; @@ -432,10 +433,8 @@ impl FileInfo { } fn render_file_lines(&self, codemap: &Rc) -> Vec { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); + // As a first step, we elide any instance of more than one // continuous unannotated line. @@ -525,10 +524,7 @@ impl FileInfo { } fn render_line(&self, line: &Line) -> Vec { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); let source_string = self.file.get_line(line.line_index) .unwrap_or(""); let source_kind = RenderedLineKind::SourceText { @@ -709,10 +705,7 @@ impl FileInfo { } fn prepend_prefixes(rendered_lines: &mut [RenderedLine]) { - let old_school = match ::std::env::var("RUST_NEW_ERROR_FORMAT") { - Ok(_) => false, - Err(_) => true, - }; + let old_school = check_old_skool(); if old_school { return; } diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 56c891daa12fb..569d11199190c 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -105,7 +105,7 @@ fn foo() { println!("text=\n{}", text); assert_eq!(&text[..], &r#" ->>>> foo.rs + ::: foo.rs 3 |> vec.push(vec.pop().unwrap()); |> --- --- - previous borrow ends here |> | | @@ -180,7 +180,7 @@ fn bar() { |> | | |> | b |> a ->>>>>> bar.rs + ::: bar.rs 17 |> vec.push(); |> --- - f |> | @@ -224,7 +224,7 @@ fn foo() { println!("text=\n{}", text); assert_eq!(&text[..], &r#" ->>>>>> foo.rs + ::: foo.rs 3 |> let name = find_id(&data, 22).unwrap(); |> ---- immutable borrow begins here ... @@ -263,7 +263,7 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ->>>> foo.rs + ::: foo.rs 3 |> vec.push(vec.pop().unwrap()); |> -------- ------ D |> || @@ -299,7 +299,7 @@ fn foo() { println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ->>>> foo.rs + ::: foo.rs 3 |> vec.push(vec.pop().unwrap()); |> --- --- - previous borrow ends here |> | | @@ -337,7 +337,7 @@ fn foo() { let text: String = make_string(&lines); println!("text=r#\"\n{}\".trim_left()", text); assert_eq!(&text[..], &r#" ->>>>>> foo.rs + ::: foo.rs 4 |> let mut vec2 = vec; |> --- `vec` moved here because it has type `collections::vec::Vec` ... @@ -373,7 +373,7 @@ fn foo() { let text: String = make_string(&lines); println!("text=&r#\"\n{}\n\"#[1..]", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 3 |> let mut vec = vec![0, 1, 2]; |> --- --- 4 |> let mut vec2 = vec; @@ -404,7 +404,7 @@ impl SomeTrait for () { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 3 |> fn foo(x: u32) { |> - "#[1..]); @@ -433,7 +433,7 @@ fn span_overlap_label() { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 2 |> fn foo(x: u32) { |> -------------- |> | | @@ -467,7 +467,7 @@ fn span_overlap_label2() { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 2 |> fn foo(x: u32) { |> -------------- |> | | @@ -512,7 +512,7 @@ fn span_overlap_label3() { let text: String = make_string(&lines); println!("r#\"\n{}\"", text); assert_eq!(text, &r#" ->>>> foo.rs + ::: foo.rs 3 |> let closure = || { |> - foo 4 |> inner From 64e0819fc2681be7d3f0e61f8b0f61eca67ad3fb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 30 Apr 2016 09:54:48 -0400 Subject: [PATCH 84/97] patch travis failure --- src/librustc_driver/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index c6a0e0feff12a..37f7b31b69cf2 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -85,7 +85,8 @@ impl CoreEmitter for ExpectErrorEmitter { msg: &str, _: Option<&str>, lvl: Level, - _is_header: bool) { + _is_header: bool, + _show_snippet: bool) { remove_message(self, msg, lvl); } } From f359aa276216aa74868b4ead5fea9a83a8397b27 Mon Sep 17 00:00:00 2001 From: jonathandturner Date: Sat, 30 Apr 2016 09:06:01 -0700 Subject: [PATCH 85/97] Fix unicode test to use original error format --- .../run-make/unicode-input/span_length.rs | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index f3bfe083016e7..3963d20df8873 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -65,8 +65,8 @@ fn main() { let err = String::from_utf8_lossy(&result.stderr); - // the span should end the line (e.g no extra ^'s) - let expected_span = format!("^{}\n", repeat("^").take(n - 1) + // the span should end the line (e.g no extra ~'s) + let expected_span = format!("^{}\n", repeat("~").take(n - 1) .collect::()); assert!(err.contains(&expected_span)); } @@ -91,19 +91,17 @@ fn main() { // Test both the length of the snake and the leading spaces up to it - // First snake is 9 ^s long. - let expected_1 = r#" -1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {} - |> ^^^^^^^^^ -"#; - assert!(err.contains(&expected_1)); - - // Second snake is only 8 ^s long, because rustc counts chars() - // now rather than width(). This is because width() functions are - // to be removed from librustc_unicode - let expected_2 = r#" -1 |> extern "路濫狼á́́" fn foo() {} extern "路濫狼á́" fn bar() {} - |> ^^^^^^^^ -"#; - assert!(err.contains(&expected_2)); + // First snake is 8 ~s long, with 7 preceding spaces (excluding file name/line offset) + let expected_span = format!("\n{}^{}\n", + repeat(" ").take(offset + 7).collect::(), + repeat("~").take(8).collect::()); + assert!(err.contains(&expected_span)); + // Second snake is only 7 ~s long, with 36 preceding spaces, + // because rustc counts chars() now rather than width(). This + // is because width() functions are to be removed from + // librustc_unicode + let expected_span = format!("\n{}^{}\n", + repeat(" ").take(offset + 36).collect::(), + repeat("~").take(7).collect::()); + assert!(err.contains(&expected_span)); } From 9d151a71c032b655ca457521730044237c9e130e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 May 2016 11:37:59 -0400 Subject: [PATCH 86/97] do not fail if len(rendered_lines) is == 1 also handle more rendered-lines --- src/libsyntax/errors/snippet/mod.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 6c90bfd08186b..1ec4a0157426a 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -475,30 +475,34 @@ impl FileInfo { while let Some(line) = next_line { if line.annotations.is_empty() { break; } - let mut rendered_line = self.render_line(line); + let mut rendered_lines = self.render_line(line); + assert!(!rendered_lines.is_empty()); if old_school { match self.primary_span { Some(span) => { let lo = codemap.lookup_char_pos(span.lo); - rendered_line[0].text.insert(0, StyledString { + rendered_lines[0].text.insert(0, StyledString { text: format!(":{} ", lo.line), style: Style::LineAndColumn, }); - rendered_line[0].text.insert(0, StyledString { + rendered_lines[0].text.insert(0, StyledString { text: lo.file.name.clone(), style: Style::FileNameStyle, }); - let gap_amount = rendered_line[0].text[0].text.len() + - rendered_line[0].text[1].text.len(); - rendered_line[1].text.insert(0, StyledString { - text: vec![" "; gap_amount].join(""), - style: Style::NoStyle - }); + let gap_amount = + rendered_lines[0].text[0].text.len() + + rendered_lines[0].text[1].text.len(); + for i in 1..rendered_lines.len() { + rendered_lines[i].text.insert(0, StyledString { + text: vec![" "; gap_amount].join(""), + style: Style::NoStyle + }); + } } _ =>() } } - output.append(&mut rendered_line); + output.append(&mut rendered_lines); next_line = lines_iter.next(); } From db8a9a92b3dafcd5a8d7207096c8cbb90db0b013 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 May 2016 11:44:25 -0400 Subject: [PATCH 87/97] avoid double panic --- src/libsyntax/errors/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 4ade537c8ce04..f0c665bcb3cdb 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -20,6 +20,7 @@ use errors::emitter::{Emitter, EmitterWriter}; use std::cell::{RefCell, Cell}; use std::{error, fmt}; use std::rc::Rc; +use std::thread::panicking; use term; pub mod emitter; @@ -352,7 +353,7 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> { /// we emit a bug. impl<'a> Drop for DiagnosticBuilder<'a> { fn drop(&mut self) { - if !self.cancelled() { + if !panicking() && !self.cancelled() { self.emitter.borrow_mut().emit(&MultiSpan::new(), "Error constructed but not emitted", None, From 71e63296a202a7da5eea2d0227517f66069cfa63 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 1 May 2016 22:33:22 -0700 Subject: [PATCH 88/97] rustc: Handle concurrent `create_dir` requests The compiler created a directory as part of `-Z incremental` but that may be hierarchically used concurrently so we need to protect ourselves against that. --- src/librustc_incremental/persist/util.rs | 26 ++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs index 9b4e5997efe42..5b4e88def018b 100644 --- a/src/librustc_incremental/persist/util.rs +++ b/src/librustc_incremental/persist/util.rs @@ -9,14 +9,16 @@ // except according to those terms. use rustc::ty; + use std::fs; -use std::path::PathBuf; +use std::io; +use std::path::{PathBuf, Path}; pub fn dep_graph_path<'tcx>(tcx: &ty::TyCtxt<'tcx>) -> Option { // For now, just save/load dep-graph from // directory/dep_graph.rbml tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| { - match fs::create_dir_all(&incr_dir){ + match create_dir_racy(&incr_dir) { Ok(()) => {} Err(err) => { tcx.sess.err( @@ -30,3 +32,23 @@ pub fn dep_graph_path<'tcx>(tcx: &ty::TyCtxt<'tcx>) -> Option { }) } +// Like std::fs::create_dir_all, except handles concurrent calls among multiple +// threads or processes. +fn create_dir_racy(path: &Path) -> io::Result<()> { + match fs::create_dir(path) { + Ok(()) => return Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::NotFound => {} + Err(e) => return Err(e), + } + match path.parent() { + Some(p) => try!(create_dir_racy(p)), + None => return Err(io::Error::new(io::ErrorKind::Other, + "failed to create whole tree")), + } + match fs::create_dir(path) { + Ok(()) => Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()), + Err(e) => Err(e), + } +} From 9355a91224a6f715b94342c074e5bac1f9e820f3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 May 2016 13:05:14 -0400 Subject: [PATCH 89/97] assert we get at least two rendered lines back --- src/libsyntax/errors/snippet/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 1ec4a0157426a..e213f623ab85d 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -38,13 +38,13 @@ pub struct FileInfo { lines: Vec, } -#[derive(Clone)] +#[derive(Clone, Debug)] struct Line { line_index: usize, annotations: Vec, } -#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)] +#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] struct Annotation { /// Start column, 0-based indexing -- counting *characters*, not /// utf-8 bytes. Note that it is important that this field goes @@ -492,6 +492,9 @@ impl FileInfo { let gap_amount = rendered_lines[0].text[0].text.len() + rendered_lines[0].text[1].text.len(); + assert!(rendered_lines.len() >= 2, + "no annotations resulted from: {:?}", + line); for i in 1..rendered_lines.len() { rendered_lines[i].text.insert(0, StyledString { text: vec![" "; gap_amount].join(""), From a4000cbbf8be9f21884077bee1361b5221e1f78f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 20 Apr 2016 11:48:52 +1200 Subject: [PATCH 90/97] Make pretty printer take Session by ref --- src/librustc_driver/lib.rs | 5 ++--- src/librustc_driver/pretty.rs | 37 ++++++++++++++++++----------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 2d3363507d06c..dc96884e47bbf 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -208,11 +208,10 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile), Some(sess)); - // It is somewhat unfortunate that this is hardwired in - this is forced by - // the fact that pretty_print_input requires the session by value. + // It is somewhat unfortunate that this is hardwired in. let pretty = callbacks.parse_pretty(&sess, &matches); if let Some((ppm, opt_uii)) = pretty { - pretty::pretty_print_input(sess, &cstore, cfg, &input, ppm, opt_uii, ofile); + pretty::pretty_print_input(&sess, &cstore, cfg, &input, ppm, opt_uii, ofile); return (Ok(()), None); } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index b1143fd3e8454..0591b0493cfb6 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -700,14 +700,14 @@ impl fold::Folder for ReplaceBodyWithLoop { } } -pub fn pretty_print_input(sess: Session, +pub fn pretty_print_input(sess: &Session, cstore: &CStore, cfg: ast::CrateConfig, input: &Input, ppm: PpMode, opt_uii: Option, ofile: Option) { - let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, input)); + let krate = panictry!(driver::phase_1_parse_input(sess, cfg, input)); let krate = if let PpmSource(PpmEveryBodyLoops) = ppm { let mut fold = ReplaceBodyWithLoop::new(); @@ -716,14 +716,14 @@ pub fn pretty_print_input(sess: Session, krate }; - let id = link::find_crate_name(Some(&sess), &krate.attrs, input); + let id = link::find_crate_name(Some(sess), &krate.attrs, input); let is_expanded = needs_expansion(&ppm); let compute_ast_map = needs_ast_map(&ppm, &opt_uii); let krate = if compute_ast_map { - match driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None) { + match driver::phase_2_configure_and_expand(sess, &cstore, krate, &id, None) { Err(_) => return, - Ok(k) => driver::assign_node_ids(&sess, k), + Ok(k) => driver::assign_node_ids(sess, k), } } else { krate @@ -739,11 +739,12 @@ pub fn pretty_print_input(sess: Session, let ast_map = if compute_ast_map { _defs = Some(RefCell::new(hir_map::collect_definitions(&krate))); let defs = _defs.as_ref().unwrap(); - LocalCrateReader::new(&sess, &cstore, defs, &krate, &id).read_crates(&dep_graph); - let lcx = LoweringContext::new(&sess, Some(&krate), defs); + LocalCrateReader::new(sess, &cstore, defs, &krate, &id).read_crates(&dep_graph); + let lcx = LoweringContext::new(sess, Some(&krate), defs); hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph.clone()); - Some(hir_map::map_crate(&mut hir_forest, defs)) + let map = hir_map::map_crate(&mut hir_forest, defs); + Some(map) } else { None }; @@ -764,7 +765,7 @@ pub fn pretty_print_input(sess: Session, (PpmSource(s), _) => { // Silently ignores an identified node. let out: &mut Write = &mut out; - s.call_with_pp_support(&sess, ast_map, box out, |annotation, out| { + s.call_with_pp_support(sess, ast_map, box out, |annotation, out| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); pprust::print_crate(sess.codemap(), @@ -780,7 +781,7 @@ pub fn pretty_print_input(sess: Session, (PpmHir(s), None) => { let out: &mut Write = &mut out; - s.call_with_pp_support_hir(&sess, + s.call_with_pp_support_hir(sess, &ast_map.unwrap(), &arenas, &id, @@ -801,7 +802,7 @@ pub fn pretty_print_input(sess: Session, (PpmHir(s), Some(uii)) => { let out: &mut Write = &mut out; - s.call_with_pp_support_hir(&sess, + s.call_with_pp_support_hir(sess, &ast_map.unwrap(), &arenas, &id, @@ -836,12 +837,12 @@ pub fn pretty_print_input(sess: Session, let ast_map = ast_map.expect("--unpretty missing ast_map"); let nodeid = if let Some(uii) = uii { debug!("pretty printing MIR for {:?}", uii); - Some(uii.to_one_node_id("--unpretty", &sess, &ast_map)) + Some(uii.to_one_node_id("--unpretty", sess, &ast_map)) } else { debug!("pretty printing MIR for whole crate"); None }; - abort_on_err(driver::phase_3_run_analysis_passes(&sess, + abort_on_err(driver::phase_3_run_analysis_passes(sess, ast_map, &arenas, &id, @@ -864,7 +865,7 @@ pub fn pretty_print_input(sess: Session, } } Ok(()) - }), &sess) + }), sess) } (PpmFlowGraph(mode), opt_uii) => { @@ -876,7 +877,7 @@ pub fn pretty_print_input(sess: Session, }); let ast_map = ast_map.expect("--pretty flowgraph missing ast_map"); - let nodeid = uii.to_one_node_id("--pretty", &sess, &ast_map); + let nodeid = uii.to_one_node_id("--pretty", sess, &ast_map); let node = ast_map.find(nodeid).unwrap_or_else(|| { sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) @@ -886,8 +887,8 @@ pub fn pretty_print_input(sess: Session, let out: &mut Write = &mut out; match code { Some(code) => { - let variants = gather_flowgraph_variants(&sess); - abort_on_err(driver::phase_3_run_analysis_passes(&sess, + let variants = gather_flowgraph_variants(sess); + abort_on_err(driver::phase_3_run_analysis_passes(sess, ast_map, &arenas, &id, @@ -899,7 +900,7 @@ pub fn pretty_print_input(sess: Session, code, mode, out) - }), &sess) + }), sess) } None => { let message = format!("--pretty=flowgraph needs block, fn, or method; got \ From 7ee02d9f4d94f6a826d10529419b64a4ccd2a405 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 20 Apr 2016 16:24:14 +1200 Subject: [PATCH 91/97] Use the compiler API to run pretty printing. This commit still does a lot of building in pretty because we always run after parsing. --- src/librustc_driver/driver.rs | 56 +++++++----- src/librustc_driver/lib.rs | 92 +++++++++----------- src/librustc_driver/pretty.rs | 10 +-- src/test/run-pass-fulldeps/compiler-calls.rs | 2 +- 4 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 6e47ee8101d31..bf1457c576eba 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -70,7 +70,7 @@ pub fn compile_input(sess: &Session, control: &CompileController) -> CompileResult { macro_rules! controller_entry_point { ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{ - let state = $make_state; + let state = &mut $make_state; let phase_result: &CompileResult = &$phase_result; if phase_result.is_ok() || control.$point.run_callback_on_error { (control.$point.callback)(state); @@ -95,10 +95,17 @@ pub fn compile_input(sess: &Session, } }; + let mut compile_state = CompileState::state_after_parse(input, + sess, + outdir, + output, + krate, + &cstore); controller_entry_point!(after_parse, sess, - CompileState::state_after_parse(input, sess, outdir, &krate), + compile_state, Ok(())); + let krate = compile_state.krate.unwrap(); let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess); let id = link::find_crate_name(Some(sess), &krate.attrs, input); @@ -194,16 +201,16 @@ pub fn compile_input(sess: &Session, // Eventually, we will want to track plugins. let _ignore = tcx.dep_graph.in_ignore(); - let state = CompileState::state_after_analysis(input, - &tcx.sess, - outdir, - opt_crate, - tcx.map.krate(), - &analysis, - mir_map.as_ref(), - tcx, - &id); - (control.after_analysis.callback)(state); + let mut state = CompileState::state_after_analysis(input, + &tcx.sess, + outdir, + opt_crate, + tcx.map.krate(), + &analysis, + mir_map.as_ref(), + tcx, + &id); + (control.after_analysis.callback)(&mut state); if control.after_analysis.stop == Compilation::Stop { return result.and_then(|_| Err(0usize)); @@ -311,7 +318,7 @@ pub struct PhaseController<'a> { // If true then the compiler will try to run the callback even if the phase // ends with an error. Note that this is not always possible. pub run_callback_on_error: bool, - pub callback: Box () + 'a>, + pub callback: Box, } impl<'a> PhaseController<'a> { @@ -330,11 +337,12 @@ impl<'a> PhaseController<'a> { pub struct CompileState<'a, 'ast: 'a, 'tcx: 'a> { pub input: &'a Input, pub session: &'a Session, - pub cfg: Option<&'a ast::CrateConfig>, - pub krate: Option<&'a ast::Crate>, + pub krate: Option, + pub cstore: Option<&'a CStore>, pub crate_name: Option<&'a str>, pub output_filenames: Option<&'a OutputFilenames>, pub out_dir: Option<&'a Path>, + pub out_file: Option<&'a Path>, pub expanded_crate: Option<&'a ast::Crate>, pub hir_crate: Option<&'a hir::Crate>, pub ast_map: Option<&'a hir_map::Map<'ast>>, @@ -353,8 +361,9 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { input: input, session: session, out_dir: out_dir.as_ref().map(|s| &**s), - cfg: None, + out_file: None, krate: None, + cstore: None, crate_name: None, output_filenames: None, expanded_crate: None, @@ -370,9 +379,16 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { fn state_after_parse(input: &'a Input, session: &'a Session, out_dir: &'a Option, - krate: &'a ast::Crate) + out_file: &'a Option, + krate: ast::Crate, + cstore: &'a CStore) -> CompileState<'a, 'ast, 'tcx> { - CompileState { krate: Some(krate), ..CompileState::empty(input, session, out_dir) } + CompileState { + krate: Some(krate), + cstore: Some(cstore), + out_file: out_file.as_ref().map(|s| &**s), + ..CompileState::empty(input, session, out_dir) + } } fn state_after_expand(input: &'a Input, @@ -399,7 +415,7 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { CompileState { crate_name: Some(crate_name), ast_map: Some(hir_map), - krate: Some(krate), + expanded_crate: Some(krate), hir_crate: Some(hir_crate), ..CompileState::empty(input, session, out_dir) } @@ -419,7 +435,7 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { analysis: Some(analysis), mir_map: mir_map, tcx: Some(tcx), - krate: krate, + expanded_crate: krate, hir_crate: Some(hir_crate), crate_name: Some(crate_name), ..CompileState::empty(input, session, out_dir) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index dc96884e47bbf..8ffdf6843e75a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -31,6 +31,7 @@ #![feature(set_stdio)] #![feature(staged_api)] #![feature(question_mark)] +#![feature(unboxed_closures)] extern crate arena; extern crate flate; @@ -208,15 +209,8 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile), Some(sess)); - // It is somewhat unfortunate that this is hardwired in. - let pretty = callbacks.parse_pretty(&sess, &matches); - if let Some((ppm, opt_uii)) = pretty { - pretty::pretty_print_input(&sess, &cstore, cfg, &input, ppm, opt_uii, ofile); - return (Ok(()), None); - } - let plugins = sess.opts.debugging_opts.extra_plugins.clone(); - let control = callbacks.build_controller(&sess); + let control = callbacks.build_controller(&sess, &matches); (driver::compile_input(&sess, &cstore, cfg, &input, &odir, &ofile, Some(plugins), &control), Some(sess)) @@ -247,6 +241,27 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option)> { } } +fn parse_pretty(sess: &Session, + matches: &getopts::Matches) + -> Option<(PpMode, Option)> { + let pretty = if sess.opts.debugging_opts.unstable_options { + matches.opt_default("pretty", "normal").map(|a| { + // stable pretty-print variants only + pretty::parse_pretty(sess, &a, false) + }) + } else { + None + }; + if pretty.is_none() && sess.unstable_options() { + matches.opt_str("unpretty").map(|a| { + // extended with unstable pretty-print variants + pretty::parse_pretty(sess, &a, true) + }) + } else { + pretty + } +} + // Whether to stop or continue compilation. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Compilation { @@ -316,29 +331,9 @@ pub trait CompilerCalls<'a> { None } - // Parse pretty printing information from the arguments. The implementer can - // choose to ignore this (the default will return None) which will skip pretty - // printing. If you do want to pretty print, it is recommended to use the - // implementation of this method from RustcDefaultCalls. - // FIXME, this is a terrible bit of API. Parsing of pretty printing stuff - // should be done as part of the framework and the implementor should customise - // handling of it. However, that is not possible atm because pretty printing - // essentially goes off and takes another path through the compiler which - // means the session is either moved or not depending on what parse_pretty - // returns (we could fix this by cloning, but it's another hack). The proper - // solution is to handle pretty printing as if it were a compiler extension, - // extending CompileController to make this work (see for example the treatment - // of save-analysis in RustcDefaultCalls::build_controller). - fn parse_pretty(&mut self, - _sess: &Session, - _matches: &getopts::Matches) - -> Option<(PpMode, Option)> { - None - } - // Create a CompilController struct for controlling the behaviour of // compilation. - fn build_controller(&mut self, &Session) -> CompileController<'a>; + fn build_controller(&mut self, &Session, &getopts::Matches) -> CompileController<'a>; } // CompilerCalls instance for a regular rustc build. @@ -441,28 +436,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { None } - fn parse_pretty(&mut self, - sess: &Session, - matches: &getopts::Matches) - -> Option<(PpMode, Option)> { - let pretty = if sess.opts.debugging_opts.unstable_options { - matches.opt_default("pretty", "normal").map(|a| { - // stable pretty-print variants only - pretty::parse_pretty(sess, &a, false) - }) - } else { - None - }; - if pretty.is_none() && sess.unstable_options() { - matches.opt_str("unpretty").map(|a| { - // extended with unstable pretty-print variants - pretty::parse_pretty(sess, &a, true) - }) - } else { - pretty - } - } - fn late_callback(&mut self, matches: &getopts::Matches, sess: &Session, @@ -474,9 +447,22 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { .and_then(|| RustcDefaultCalls::list_metadata(sess, matches, input)) } - fn build_controller(&mut self, sess: &Session) -> CompileController<'a> { + fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { let mut control = CompileController::basic(); + if let Some((ppm, opt_uii)) = parse_pretty(&sess, &matches) { + control.after_parse.stop = Compilation::Stop; + control.after_parse.callback = box move |state| { + pretty::pretty_print_input(state.session, + state.cstore.unwrap(), + state.input, + state.krate.take().unwrap(), + ppm, + opt_uii.clone(), + state.out_file); + }; + } + if sess.opts.parse_only || sess.opts.debugging_opts.show_span.is_some() || sess.opts.debugging_opts.ast_json_noexpand { control.after_parse.stop = Compilation::Stop; @@ -498,7 +484,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.after_analysis.callback = box |state| { time(state.session.time_passes(), "save analysis", || { save::process_crate(state.tcx.unwrap(), - state.krate.unwrap(), + state.expanded_crate.unwrap(), state.analysis.unwrap(), state.crate_name.unwrap(), state.out_dir, diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 0591b0493cfb6..80d8a40b4e914 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -49,7 +49,7 @@ use std::fs::File; use std::io::{self, Write}; use std::iter; use std::option; -use std::path::PathBuf; +use std::path::Path; use std::str::FromStr; use rustc::hir::map as hir_map; @@ -702,13 +702,11 @@ impl fold::Folder for ReplaceBodyWithLoop { pub fn pretty_print_input(sess: &Session, cstore: &CStore, - cfg: ast::CrateConfig, input: &Input, + krate: ast::Crate, ppm: PpMode, opt_uii: Option, - ofile: Option) { - let krate = panictry!(driver::phase_1_parse_input(sess, cfg, input)); - + ofile: Option<&Path>) { let krate = if let PpmSource(PpmEveryBodyLoops) = ppm { let mut fold = ReplaceBodyWithLoop::new(); fold.fold_crate(krate) @@ -922,7 +920,7 @@ pub fn pretty_print_input(sess: &Session, match ofile { None => print!("{}", String::from_utf8(out).unwrap()), Some(p) => { - match File::create(&p) { + match File::create(p) { Ok(mut w) => w.write_all(&out).unwrap(), Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e), } diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs index 42784e009ee44..837215c3cac4e 100644 --- a/src/test/run-pass-fulldeps/compiler-calls.rs +++ b/src/test/run-pass-fulldeps/compiler-calls.rs @@ -69,7 +69,7 @@ impl<'a> CompilerCalls<'a> for TestCalls { panic!("This shouldn't happen"); } - fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> { + fn build_controller(&mut self, _: &Session, _: &getopts::Matches) -> driver::CompileController<'a> { panic!("This shouldn't be called"); } } From 52a2b33a4b1c9f10e7034a758d4dff4f53129a49 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 21 Apr 2016 10:29:49 +1200 Subject: [PATCH 92/97] Refactor pretty printing to use more of the driver --- src/librustc_driver/driver.rs | 97 +++++--- src/librustc_driver/lib.rs | 44 +++- src/librustc_driver/pretty.rs | 452 ++++++++++++++++++---------------- 3 files changed, 330 insertions(+), 263 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bf1457c576eba..2b56366f1c697 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -112,7 +112,7 @@ pub fn compile_input(sess: &Session, let expanded_crate = phase_2_configure_and_expand(sess, &cstore, krate, - &id[..], + &id, addl_plugins)?; (outputs, expanded_crate, id) @@ -123,8 +123,10 @@ pub fn compile_input(sess: &Session, CompileState::state_after_expand(input, sess, outdir, + output, + &cstore, &expanded_crate, - &id[..]), + &id), Ok(())); let expanded_crate = assign_node_ids(sess, expanded_crate); @@ -169,10 +171,13 @@ pub fn compile_input(sess: &Session, CompileState::state_after_write_deps(input, sess, outdir, + output, + &arenas, + &cstore, &hir_map, &expanded_crate, &hir_map.krate(), - &id[..]), + &id), Ok(())); } @@ -202,8 +207,9 @@ pub fn compile_input(sess: &Session, let _ignore = tcx.dep_graph.in_ignore(); let mut state = CompileState::state_after_analysis(input, - &tcx.sess, + sess, outdir, + output, opt_crate, tcx.map.krate(), &analysis, @@ -243,7 +249,7 @@ pub fn compile_input(sess: &Session, controller_entry_point!(after_llvm, sess, - CompileState::state_after_llvm(input, sess, outdir, &trans), + CompileState::state_after_llvm(input, sess, outdir, output, &trans), phase5_result); phase5_result?; @@ -334,34 +340,36 @@ impl<'a> PhaseController<'a> { /// State that is passed to a callback. What state is available depends on when /// during compilation the callback is made. See the various constructor methods /// (`state_*`) in the impl to see which data is provided for any given entry point. -pub struct CompileState<'a, 'ast: 'a, 'tcx: 'a> { +pub struct CompileState<'a, 'b, 'ast: 'a, 'tcx: 'b> where 'ast: 'tcx { pub input: &'a Input, - pub session: &'a Session, + pub session: &'ast Session, pub krate: Option, pub cstore: Option<&'a CStore>, pub crate_name: Option<&'a str>, pub output_filenames: Option<&'a OutputFilenames>, pub out_dir: Option<&'a Path>, pub out_file: Option<&'a Path>, + pub arenas: Option<&'ast ty::CtxtArenas<'ast>>, pub expanded_crate: Option<&'a ast::Crate>, pub hir_crate: Option<&'a hir::Crate>, pub ast_map: Option<&'a hir_map::Map<'ast>>, - pub mir_map: Option<&'a MirMap<'tcx>>, + pub mir_map: Option<&'b MirMap<'tcx>>, pub analysis: Option<&'a ty::CrateAnalysis<'a>>, - pub tcx: Option<&'a TyCtxt<'tcx>>, + pub tcx: Option<&'b TyCtxt<'tcx>>, pub trans: Option<&'a trans::CrateTranslation>, } -impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { +impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> { fn empty(input: &'a Input, - session: &'a Session, + session: &'ast Session, out_dir: &'a Option) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'b, 'ast, 'tcx> { CompileState { input: input, session: session, out_dir: out_dir.as_ref().map(|s| &**s), out_file: None, + arenas: None, krate: None, cstore: None, crate_name: None, @@ -377,12 +385,12 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { } fn state_after_parse(input: &'a Input, - session: &'a Session, + session: &'ast Session, out_dir: &'a Option, out_file: &'a Option, krate: ast::Crate, cstore: &'a CStore) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'b, 'ast, 'tcx> { CompileState { krate: Some(krate), cstore: Some(cstore), @@ -392,45 +400,56 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { } fn state_after_expand(input: &'a Input, - session: &'a Session, + session: &'ast Session, out_dir: &'a Option, + out_file: &'a Option, + cstore: &'a CStore, expanded_crate: &'a ast::Crate, crate_name: &'a str) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'b, 'ast, 'tcx> { CompileState { crate_name: Some(crate_name), + cstore: Some(cstore), expanded_crate: Some(expanded_crate), + out_file: out_file.as_ref().map(|s| &**s), ..CompileState::empty(input, session, out_dir) } } fn state_after_write_deps(input: &'a Input, - session: &'a Session, + session: &'ast Session, out_dir: &'a Option, + out_file: &'a Option, + arenas: &'ast ty::CtxtArenas<'ast>, + cstore: &'a CStore, hir_map: &'a hir_map::Map<'ast>, krate: &'a ast::Crate, hir_crate: &'a hir::Crate, crate_name: &'a str) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'b, 'ast, 'tcx> { CompileState { crate_name: Some(crate_name), + arenas: Some(arenas), + cstore: Some(cstore), ast_map: Some(hir_map), expanded_crate: Some(krate), hir_crate: Some(hir_crate), + out_file: out_file.as_ref().map(|s| &**s), ..CompileState::empty(input, session, out_dir) } } fn state_after_analysis(input: &'a Input, - session: &'a Session, + session: &'ast Session, out_dir: &'a Option, + out_file: &'a Option, krate: Option<&'a ast::Crate>, hir_crate: &'a hir::Crate, - analysis: &'a ty::CrateAnalysis, - mir_map: Option<&'a MirMap<'tcx>>, - tcx: &'a TyCtxt<'tcx>, + analysis: &'a ty::CrateAnalysis<'a>, + mir_map: Option<&'b MirMap<'tcx>>, + tcx: &'b TyCtxt<'tcx>, crate_name: &'a str) - -> CompileState<'a, 'ast, 'tcx> { + -> CompileState<'a, 'b, 'ast, 'tcx> { CompileState { analysis: Some(analysis), mir_map: mir_map, @@ -438,17 +457,23 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> { expanded_crate: krate, hir_crate: Some(hir_crate), crate_name: Some(crate_name), + out_file: out_file.as_ref().map(|s| &**s), ..CompileState::empty(input, session, out_dir) } } fn state_after_llvm(input: &'a Input, - session: &'a Session, + session: &'ast Session, out_dir: &'a Option, + out_file: &'a Option, trans: &'a trans::CrateTranslation) - -> CompileState<'a, 'ast, 'tcx> { - CompileState { trans: Some(trans), ..CompileState::empty(input, session, out_dir) } + -> CompileState<'a, 'b, 'ast, 'tcx> { + CompileState { + trans: Some(trans), + out_file: out_file.as_ref().map(|s| &**s), + ..CompileState::empty(input, session, out_dir) + } } } @@ -814,16 +839,16 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let index = stability::Index::new(&hir_map); TyCtxt::create_and_enter(sess, - arenas, - def_map, - named_region_map, - hir_map, - freevars, - region_map, - lang_items, - index, - name, - |tcx| { + arenas, + def_map, + named_region_map, + hir_map, + freevars, + region_map, + lang_items, + index, + name, + |tcx| { time(time_passes, "load_dep_graph", || rustc_incremental::load_dep_graph(tcx)); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 8ffdf6843e75a..74f6d3f25157b 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -450,17 +450,39 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { let mut control = CompileController::basic(); - if let Some((ppm, opt_uii)) = parse_pretty(&sess, &matches) { - control.after_parse.stop = Compilation::Stop; - control.after_parse.callback = box move |state| { - pretty::pretty_print_input(state.session, - state.cstore.unwrap(), - state.input, - state.krate.take().unwrap(), - ppm, - opt_uii.clone(), - state.out_file); - }; + if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) { + if ppm.needs_ast_map(&opt_uii) { + control.after_write_deps.stop = Compilation::Stop; + + control.after_parse.callback = box move |state| { + state.krate = Some(pretty::fold_crate(state.krate.take().unwrap(), ppm)); + }; + control.after_write_deps.callback = box move |state| { + pretty::print_after_write_deps(state.session, + state.cstore.unwrap(), + state.ast_map.unwrap(), + state.input, + &state.expanded_crate.take().unwrap(), + state.crate_name.unwrap(), + ppm, + state.arenas.unwrap(), + opt_uii.clone(), + state.out_file); + }; + } else { + control.after_parse.stop = Compilation::Stop; + + control.after_parse.callback = box move |state| { + let krate = pretty::fold_crate(state.krate.take().unwrap(), ppm); + pretty::print_after_parsing(state.session, + state.input, + &krate, + ppm, + state.out_file); + }; + } + + return control; } if sess.opts.parse_only || sess.opts.debugging_opts.show_span.is_some() || diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 80d8a40b4e914..223b6629a8814 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -15,8 +15,6 @@ pub use self::PpSourceMode::*; pub use self::PpMode::*; use self::NodesMatchingUII::*; -use rustc_trans::back::link; - use {driver, abort_on_err}; use rustc::dep_graph::DepGraph; @@ -55,7 +53,6 @@ use std::str::FromStr; use rustc::hir::map as hir_map; use rustc::hir::map::{blocks, NodePrinter}; use rustc::hir; -use rustc::hir::lowering::{lower_crate, LoweringContext}; use rustc::hir::print as pprust_hir; use rustc::mir::mir_map::MirMap; @@ -89,6 +86,32 @@ pub enum PpMode { PpmMirCFG, } +impl PpMode { + pub fn needs_ast_map(&self, opt_uii: &Option) -> bool { + match *self { + PpmSource(PpmNormal) | + PpmSource(PpmEveryBodyLoops) | + PpmSource(PpmIdentified) => opt_uii.is_some(), + + PpmSource(PpmExpanded) | + PpmSource(PpmExpandedIdentified) | + PpmSource(PpmExpandedHygiene) | + PpmHir(_) | + PpmMir | + PpmMirCFG | + PpmFlowGraph(_) => true, + PpmSource(PpmTyped) => panic!("invalid state"), + } + } + + pub fn needs_analysis(&self) -> bool { + match *self { + PpmMir | PpmMirCFG | PpmFlowGraph(_) => true, + _ => false, + } + } +} + pub fn parse_pretty(sess: &Session, name: &str, extended: bool) @@ -147,7 +170,7 @@ impl PpSourceMode { /// Constructs a `PrinterSupport` object and passes it to `f`. fn call_with_pp_support<'tcx, A, B, F>(&self, sess: &'tcx Session, - ast_map: Option>, + ast_map: Option<&hir_map::Map<'tcx>>, payload: B, f: F) -> A @@ -157,7 +180,7 @@ impl PpSourceMode { PpmNormal | PpmEveryBodyLoops | PpmExpanded => { let annotation = NoAnn { sess: sess, - ast_map: ast_map, + ast_map: ast_map.map(|m| m.clone()), }; f(&annotation, payload) } @@ -165,14 +188,14 @@ impl PpSourceMode { PpmIdentified | PpmExpandedIdentified => { let annotation = IdentifiedAnnotation { sess: sess, - ast_map: ast_map, + ast_map: ast_map.map(|m| m.clone()), }; f(&annotation, payload) } PpmExpandedHygiene => { let annotation = HygieneAnnotation { sess: sess, - ast_map: ast_map, + ast_map: ast_map.map(|m| m.clone()), }; f(&annotation, payload) } @@ -582,40 +605,6 @@ impl UserIdentifiedItem { } } -fn needs_ast_map(ppm: &PpMode, opt_uii: &Option) -> bool { - match *ppm { - PpmSource(PpmNormal) | - PpmSource(PpmEveryBodyLoops) | - PpmSource(PpmIdentified) => opt_uii.is_some(), - - PpmSource(PpmExpanded) | - PpmSource(PpmExpandedIdentified) | - PpmSource(PpmExpandedHygiene) | - PpmHir(_) | - PpmMir | - PpmMirCFG | - PpmFlowGraph(_) => true, - PpmSource(PpmTyped) => panic!("invalid state"), - } -} - -fn needs_expansion(ppm: &PpMode) -> bool { - match *ppm { - PpmSource(PpmNormal) | - PpmSource(PpmEveryBodyLoops) | - PpmSource(PpmIdentified) => false, - - PpmSource(PpmExpanded) | - PpmSource(PpmExpandedIdentified) | - PpmSource(PpmExpandedHygiene) | - PpmHir(_) | - PpmMir | - PpmMirCFG | - PpmFlowGraph(_) => true, - PpmSource(PpmTyped) => panic!("invalid state"), - } -} - struct ReplaceBodyWithLoop { within_static_or_const: bool, } @@ -700,89 +689,176 @@ impl fold::Folder for ReplaceBodyWithLoop { } } -pub fn pretty_print_input(sess: &Session, - cstore: &CStore, - input: &Input, - krate: ast::Crate, - ppm: PpMode, - opt_uii: Option, - ofile: Option<&Path>) { - let krate = if let PpmSource(PpmEveryBodyLoops) = ppm { - let mut fold = ReplaceBodyWithLoop::new(); - fold.fold_crate(krate) - } else { - krate +fn print_flowgraph<'tcx, W: Write>(variants: Vec, + tcx: &TyCtxt<'tcx>, + mir_map: Option<&MirMap<'tcx>>, + code: blocks::Code, + mode: PpFlowGraphMode, + 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()), + }; + let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; + let lcfg = LabelledCFG { + ast_map: &tcx.map, + cfg: &cfg, + name: format!("node_{}", code.id()), + labelled_edges: labelled_edges, }; - let id = link::find_crate_name(Some(sess), &krate.attrs, input); + match code { + _ if variants.is_empty() => { + let r = dot::render(&lcfg, &mut out); + return expand_err_details(r); + } + blocks::BlockCode(_) => { + tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \ + fn-like node id."); + return Ok(()); + } + blocks::FnLikeCode(fn_like) => { + let (bccx, analysis_data) = + borrowck::build_borrowck_dataflow_data_for_fn(tcx, + mir_map, + fn_like.to_fn_parts(), + &cfg); - let is_expanded = needs_expansion(&ppm); - let compute_ast_map = needs_ast_map(&ppm, &opt_uii); - let krate = if compute_ast_map { - match driver::phase_2_configure_and_expand(sess, &cstore, krate, &id, None) { - Err(_) => return, - Ok(k) => driver::assign_node_ids(sess, k), + let lcfg = borrowck_dot::DataflowLabeller { + inner: lcfg, + variants: variants, + borrowck_ctxt: &bccx, + analysis_data: &analysis_data, + }; + let r = dot::render(&lcfg, &mut out); + return expand_err_details(r); } - } else { - krate - }; + } - // There is some twisted, god-forsaken tangle of lifetimes here which makes - // the ordering of stuff super-finicky. - let mut hir_forest; - let mut _defs = None; - let dep_graph = DepGraph::new(false); - let arenas = ty::CtxtArenas::new(); - let _ignore = dep_graph.in_ignore(); - let ast_map = if compute_ast_map { - _defs = Some(RefCell::new(hir_map::collect_definitions(&krate))); - let defs = _defs.as_ref().unwrap(); - LocalCrateReader::new(sess, &cstore, defs, &krate, &id).read_crates(&dep_graph); - let lcx = LoweringContext::new(sess, Some(&krate), defs); - - hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph.clone()); - let map = hir_map::map_crate(&mut hir_forest, defs); - Some(map) + fn expand_err_details(r: io::Result<()>) -> io::Result<()> { + r.map_err(|ioerr| { + io::Error::new(io::ErrorKind::Other, + &format!("graphviz::render failed: {}", ioerr)[..]) + }) + } +} + +pub fn fold_crate(krate: ast::Crate, ppm: PpMode) -> ast::Crate { + if let PpmSource(PpmEveryBodyLoops) = ppm { + let mut fold = ReplaceBodyWithLoop::new(); + fold.fold_crate(krate) } else { - None - }; + krate + } +} +fn get_source(input: &Input, sess: &Session) -> (Vec, String) { let src_name = driver::source_name(input); let src = sess.codemap() - .get_filemap(&src_name[..]) + .get_filemap(&src_name) .src .as_ref() .unwrap() .as_bytes() .to_vec(); + (src, src_name) +} + +fn write_output(out: Vec, ofile: Option<&Path>) { + match ofile { + None => print!("{}", String::from_utf8(out).unwrap()), + Some(p) => { + match File::create(p) { + Ok(mut w) => w.write_all(&out).unwrap(), + Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e), + } + } + } +} + +pub fn print_after_parsing(sess: &Session, + input: &Input, + krate: &ast::Crate, + ppm: PpMode, + ofile: Option<&Path>) { + let dep_graph = DepGraph::new(false); + let _ignore = dep_graph.in_ignore(); + + let (src, src_name) = get_source(input, sess); + let mut rdr = &*src; + let mut out = Vec::new(); + + if let PpmSource(s) = ppm { + // Silently ignores an identified node. + let out: &mut Write = &mut out; + s.call_with_pp_support(sess, None, box out, |annotation, out| { + debug!("pretty printing source code {:?}", s); + let sess = annotation.sess(); + pprust::print_crate(sess.codemap(), + sess.diagnostic(), + krate, + src_name.to_string(), + &mut rdr, + out, + annotation.pp_ann(), + false) + }).unwrap() + } else { + unreachable!(); + }; + + write_output(out, ofile); +} + +pub fn print_after_write_deps<'tcx, 'a: 'tcx>(sess: &'a Session, + cstore: &CStore, + ast_map: &hir_map::Map<'tcx>, + input: &Input, + krate: &ast::Crate, + crate_name: &str, + ppm: PpMode, + arenas: &'tcx ty::CtxtArenas<'tcx>, + opt_uii: Option, + ofile: Option<&Path>) { + let dep_graph = DepGraph::new(false); + let _ignore = dep_graph.in_ignore(); + if ppm.needs_analysis() { + print_with_analysis(sess, cstore, ast_map, crate_name, arenas, ppm, opt_uii, ofile); + return; + } + + let (src, src_name) = get_source(input, sess); + + let mut rdr = &src[..]; let mut out = Vec::new(); match (ppm, opt_uii) { (PpmSource(s), _) => { // Silently ignores an identified node. let out: &mut Write = &mut out; - s.call_with_pp_support(sess, ast_map, box out, |annotation, out| { + s.call_with_pp_support(sess, Some(ast_map), box out, |annotation, out| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); pprust::print_crate(sess.codemap(), sess.diagnostic(), - &krate, + krate, src_name.to_string(), &mut rdr, out, annotation.pp_ann(), - is_expanded) + true) }) } (PpmHir(s), None) => { let out: &mut Write = &mut out; s.call_with_pp_support_hir(sess, - &ast_map.unwrap(), - &arenas, - &id, + ast_map, + arenas, + crate_name, box out, |annotation, out, krate| { debug!("pretty printing source code {:?}", s); @@ -794,16 +870,16 @@ pub fn pretty_print_input(sess: &Session, &mut rdr, out, annotation.pp_ann(), - is_expanded) + true) }) } (PpmHir(s), Some(uii)) => { let out: &mut Write = &mut out; s.call_with_pp_support_hir(sess, - &ast_map.unwrap(), - &arenas, - &id, + ast_map, + arenas, + crate_name, (out,uii), |annotation, (out,uii), _| { debug!("pretty printing source code {:?}", s); @@ -829,156 +905,100 @@ pub fn pretty_print_input(sess: &Session, } pp::eof(&mut pp_state.s) }) - } + } + _ => unreachable!(), + }.unwrap(); + + write_output(out, ofile); +} + +// In an ideal world, this would be a public function called by the driver after +// analsysis is performed. However, we want to call `phase_3_run_analysis_passes` +// with a different callback than the standard driver, so that isn't easy. +// Instead, we call that function ourselves. +fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, + cstore: &CStore, + ast_map: &hir_map::Map<'tcx>, + crate_name: &str, + arenas: &'tcx ty::CtxtArenas<'tcx>, + ppm: PpMode, + uii: Option, + ofile: Option<&Path>) { + let nodeid = if let Some(uii) = uii { + debug!("pretty printing for {:?}", uii); + Some(uii.to_one_node_id("--unpretty", sess, &ast_map)) + } else { + debug!("pretty printing for whole crate"); + None + }; - (pp_type@PpmMir, uii) | (pp_type@PpmMirCFG, uii) => { - let ast_map = ast_map.expect("--unpretty missing ast_map"); - let nodeid = if let Some(uii) = uii { - debug!("pretty printing MIR for {:?}", uii); - Some(uii.to_one_node_id("--unpretty", sess, &ast_map)) - } else { - debug!("pretty printing MIR for whole crate"); - None - }; - abort_on_err(driver::phase_3_run_analysis_passes(sess, - ast_map, - &arenas, - &id, - resolve::MakeGlobMap::No, - |tcx, mir_map, _, _| { + let mut out = Vec::new(); + + abort_on_err(driver::phase_3_run_analysis_passes(sess, + ast_map.clone(), + arenas, + crate_name, + resolve::MakeGlobMap::No, + |tcx, mir_map, _, _| { + match ppm { + PpmMir | PpmMirCFG => { if let Some(mir_map) = mir_map { if let Some(nodeid) = nodeid { let mir = mir_map.map.get(&nodeid).unwrap_or_else(|| { sess.fatal(&format!("no MIR map entry for node {}", nodeid)) }); - match pp_type { + match ppm { PpmMir => write_mir_pretty(tcx, iter::once((&nodeid, mir)), &mut out), - _ => write_mir_graphviz(tcx, iter::once((&nodeid, mir)), &mut out) + PpmMirCFG => write_mir_graphviz(tcx, iter::once((&nodeid, mir)), &mut out), + _ => unreachable!(), }?; } else { - match pp_type { + match ppm { PpmMir => write_mir_pretty(tcx, mir_map.map.iter(), &mut out), - _ => write_mir_graphviz(tcx, mir_map.map.iter(), &mut out) + PpmMirCFG => write_mir_graphviz(tcx, mir_map.map.iter(), &mut out), + _ => unreachable!(), }?; } } Ok(()) - }), sess) - } - - (PpmFlowGraph(mode), opt_uii) => { - debug!("pretty printing flow graph for {:?}", opt_uii); - let uii = opt_uii.unwrap_or_else(|| { - sess.fatal(&format!("`pretty flowgraph=..` needs NodeId (int) or - \ - unique path suffix (b::c::d)")) + } + PpmFlowGraph(mode) => { + let nodeid = nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or \ + unique path suffix (b::c::d)"); + let node = tcx.map.find(nodeid).unwrap_or_else(|| { + tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) + }); - }); - let ast_map = ast_map.expect("--pretty flowgraph missing ast_map"); - let nodeid = uii.to_one_node_id("--pretty", sess, &ast_map); + let code = blocks::Code::from_node(node); + match code { + Some(code) => { + let variants = gather_flowgraph_variants(tcx.sess); - let node = ast_map.find(nodeid).unwrap_or_else(|| { - sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) - }); + let out: &mut Write = &mut out; - let code = blocks::Code::from_node(node); - let out: &mut Write = &mut out; - match code { - Some(code) => { - let variants = gather_flowgraph_variants(sess); - abort_on_err(driver::phase_3_run_analysis_passes(sess, - ast_map, - &arenas, - &id, - resolve::MakeGlobMap::No, - |tcx, mir_map, _, _| { print_flowgraph(variants, tcx, mir_map.as_ref(), code, mode, out) - }), sess) - } - None => { - let message = format!("--pretty=flowgraph needs block, fn, or method; got \ - {:?}", - node); - - // point to what was found, if there's an - // accessible span. - match ast_map.opt_span(nodeid) { - Some(sp) => sess.span_fatal(sp, &message[..]), - None => sess.fatal(&message[..]), + } + None => { + let message = format!("--pretty=flowgraph needs block, fn, or method; got \ + {:?}", + node); + + // Point to what was found, if there's an accessible span. + match tcx.map.opt_span(nodeid) { + Some(sp) => tcx.sess.span_fatal(sp, &message), + None => tcx.sess.fatal(&message), + } } } } + _ => unreachable!(), } - } - .unwrap(); - - match ofile { - None => print!("{}", String::from_utf8(out).unwrap()), - Some(p) => { - match File::create(p) { - Ok(mut w) => w.write_all(&out).unwrap(), - Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e), - } - } - } -} + }), sess).unwrap(); -fn print_flowgraph<'tcx, W: Write>(variants: Vec, - tcx: &TyCtxt<'tcx>, - mir_map: Option<&MirMap<'tcx>>, - code: blocks::Code, - mode: PpFlowGraphMode, - 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()), - }; - let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; - let lcfg = LabelledCFG { - ast_map: &tcx.map, - cfg: &cfg, - name: format!("node_{}", code.id()), - labelled_edges: labelled_edges, - }; - - match code { - _ if variants.is_empty() => { - let r = dot::render(&lcfg, &mut out); - return expand_err_details(r); - } - blocks::BlockCode(_) => { - tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \ - fn-like node id."); - return Ok(()); - } - blocks::FnLikeCode(fn_like) => { - let (bccx, analysis_data) = - borrowck::build_borrowck_dataflow_data_for_fn(tcx, - mir_map, - fn_like.to_fn_parts(), - &cfg); - - let lcfg = borrowck_dot::DataflowLabeller { - inner: lcfg, - variants: variants, - borrowck_ctxt: &bccx, - analysis_data: &analysis_data, - }; - let r = dot::render(&lcfg, &mut out); - return expand_err_details(r); - } - } - - fn expand_err_details(r: io::Result<()>) -> io::Result<()> { - r.map_err(|ioerr| { - io::Error::new(io::ErrorKind::Other, - &format!("graphviz::render failed: {}", ioerr)[..]) - }) - } + write_output(out, ofile); } From aaf56d7086e6dc5e436ec7064898f90295908312 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 21 Apr 2016 17:28:25 +1200 Subject: [PATCH 93/97] Fix tests --- src/librustc_driver/lib.rs | 5 ++++- src/librustc_driver/pretty.rs | 4 +++- src/test/run-pass-fulldeps/compiler-calls.rs | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 74f6d3f25157b..dc181d106f488 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -447,7 +447,10 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { .and_then(|| RustcDefaultCalls::list_metadata(sess, matches, input)) } - fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { + fn build_controller(&mut self, + sess: &Session, + matches: &getopts::Matches) + -> CompileController<'a> { let mut control = CompileController::basic(); if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 223b6629a8814..4e07728807643 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -949,7 +949,9 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, }); match ppm { PpmMir => write_mir_pretty(tcx, iter::once((&nodeid, mir)), &mut out), - PpmMirCFG => write_mir_graphviz(tcx, iter::once((&nodeid, mir)), &mut out), + PpmMirCFG => { + write_mir_graphviz(tcx, iter::once((&nodeid, mir)), &mut out) + } _ => unreachable!(), }?; } else { diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs index 837215c3cac4e..af641d717edd9 100644 --- a/src/test/run-pass-fulldeps/compiler-calls.rs +++ b/src/test/run-pass-fulldeps/compiler-calls.rs @@ -69,7 +69,10 @@ impl<'a> CompilerCalls<'a> for TestCalls { panic!("This shouldn't happen"); } - fn build_controller(&mut self, _: &Session, _: &getopts::Matches) -> driver::CompileController<'a> { + fn build_controller(&mut self, + _: &Session, + _: &getopts::Matches) + -> driver::CompileController<'a> { panic!("This shouldn't be called"); } } From c1c6e99bfd3296954a192d9fe3151a222dd9045c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 26 Apr 2016 14:06:24 +1200 Subject: [PATCH 94/97] rebasing Note that this whole PR is a [breaking-change] for clients of the Compiler API. --- src/librustc_driver/lib.rs | 1 - src/librustc_driver/pretty.rs | 7 +------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index dc181d106f488..ceb851da530ac 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -462,7 +462,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { }; control.after_write_deps.callback = box move |state| { pretty::print_after_write_deps(state.session, - state.cstore.unwrap(), state.ast_map.unwrap(), state.input, &state.expanded_crate.take().unwrap(), diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 4e07728807643..30f943bd9a444 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -26,8 +26,6 @@ use rustc::session::config::Input; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; use rustc_resolve as resolve; -use rustc_metadata::cstore::CStore; -use rustc_metadata::creader::LocalCrateReader; use rustc_mir::pretty::write_mir_pretty; use rustc_mir::graphviz::write_mir_graphviz; @@ -42,7 +40,6 @@ use syntax::util::small_vector::SmallVector; use graphviz as dot; -use std::cell::RefCell; use std::fs::File; use std::io::{self, Write}; use std::iter; @@ -813,7 +810,6 @@ pub fn print_after_parsing(sess: &Session, } pub fn print_after_write_deps<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &CStore, ast_map: &hir_map::Map<'tcx>, input: &Input, krate: &ast::Crate, @@ -826,7 +822,7 @@ pub fn print_after_write_deps<'tcx, 'a: 'tcx>(sess: &'a Session, let _ignore = dep_graph.in_ignore(); if ppm.needs_analysis() { - print_with_analysis(sess, cstore, ast_map, crate_name, arenas, ppm, opt_uii, ofile); + print_with_analysis(sess, ast_map, crate_name, arenas, ppm, opt_uii, ofile); return; } @@ -917,7 +913,6 @@ pub fn print_after_write_deps<'tcx, 'a: 'tcx>(sess: &'a Session, // with a different callback than the standard driver, so that isn't easy. // Instead, we call that function ourselves. fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &CStore, ast_map: &hir_map::Map<'tcx>, crate_name: &str, arenas: &'tcx ty::CtxtArenas<'tcx>, From 780f725176e0fb8f37ef67564dd9ff1ee01f29c2 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 2 May 2016 07:23:56 +0200 Subject: [PATCH 95/97] typeck: when suggesting associated fns, do not show call site as fallback In case we cannot produce a span for the location of the definition, just do not show a span at all. cc: #29121 --- src/librustc_typeck/check/method/suggest.rs | 23 ++++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b541ca151c856..adc1972735a47 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -237,7 +237,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match *source { 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 the call site. + // the impl, if local to crate (item may be defaulted), else nothing. let item = impl_item(fcx.tcx(), impl_did, item_name) .or_else(|| { trait_item( @@ -246,8 +246,9 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, item_name ) }).unwrap(); - let impl_span = fcx.tcx().map.def_id_span(impl_did, span); - let item_span = fcx.tcx().map.def_id_span(item.def_id(), impl_span); + let note_span = fcx.tcx().map.span_if_local(item.def_id()).or_else(|| { + fcx.tcx().map.span_if_local(impl_did) + }); let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty; @@ -259,11 +260,17 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } }; - span_note!(err, item_span, - "candidate #{} is defined in an impl{} for the type `{}`", - idx + 1, - insertion, - impl_ty); + let note_str = format!("candidate #{} is defined in an impl{} \ + for the type `{}`", + idx + 1, + insertion, + impl_ty); + if let Some(note_span) = note_span { + // We have a span pointing to the method. Show note with snippet. + err.span_note(note_span, ¬e_str); + } else { + err.note(¬e_str); + } } CandidateSource::TraitSource(trait_did) => { let item = trait_item(fcx.tcx(), trait_did, item_name).unwrap(); From daf367c8fcfe1d42dfa618f4f1689e282da925c2 Mon Sep 17 00:00:00 2001 From: Garrett Squire Date: Mon, 25 Apr 2016 16:59:54 -0700 Subject: [PATCH 96/97] add Cargo.lock check to ensure it is synced --- src/tools/tidy/src/cargo_lock.rs | 43 ++++++++++++++++++++++++++++++++ src/tools/tidy/src/main.rs | 2 ++ 2 files changed, 45 insertions(+) create mode 100644 src/tools/tidy/src/cargo_lock.rs diff --git a/src/tools/tidy/src/cargo_lock.rs b/src/tools/tidy/src/cargo_lock.rs new file mode 100644 index 0000000000000..4324db489b7f8 --- /dev/null +++ b/src/tools/tidy/src/cargo_lock.rs @@ -0,0 +1,43 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::path::Path; + +const CARGO_LOCK: &'static str = "Cargo.lock"; + +pub fn check(path: &Path, bad: &mut bool) { + use std::process::Command; + + super::walk(path, + &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), + &mut |file| { + let name = file.file_name().unwrap().to_string_lossy(); + if name == CARGO_LOCK { + let rel_path = file.strip_prefix(path).unwrap(); + let ret_code = Command::new("git") + .arg("diff-index") + .arg("--quiet") + .arg("HEAD") + .arg(rel_path) + .current_dir(path) + .status() + .unwrap_or_else(|e| { + panic!("could not run git diff-index: {}", e); + }); + if !ret_code.success() { + let parent_path = file.parent().unwrap().join("Cargo.toml"); + print!("dirty lock file found at {} ", rel_path.display()); + println!("please commit your changes or update the lock file by running:"); + println!("\n\tcargo update --manifest-path {}", parent_path.display()); + *bad = true; + } + } + }); +} diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index e9e2508aba9bd..2839bbded1a5f 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,6 +35,7 @@ mod style; mod errors; mod features; mod cargo; +mod cargo_lock; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -46,6 +47,7 @@ fn main() { errors::check(&path, &mut bad); cargo::check(&path, &mut bad); features::check(&path, &mut bad); + cargo_lock::check(&path, &mut bad); if bad { panic!("some tidy checks failed"); From 1afb8b1b22ca6aaa5a2a5e2e0a39828190ab0204 Mon Sep 17 00:00:00 2001 From: Garrett Squire Date: Wed, 4 May 2016 10:09:09 -0700 Subject: [PATCH 97/97] update the Cargo lock file --- src/rustc/Cargo.lock | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 1fa4d5398f489..b4c2e21651edb 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -7,15 +7,6 @@ dependencies = [ "rustdoc 0.0.0", ] -[[package]] -name = "advapi32-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "arena" version = "0.0.0" @@ -29,7 +20,7 @@ name = "flate" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -38,12 +29,8 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.17" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "graphviz" @@ -192,7 +179,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", ] @@ -233,6 +220,7 @@ dependencies = [ "log 0.0.0", "rustc 0.0.0", "rustc_const_eval 0.0.0", + "rustc_const_math 0.0.0", "syntax 0.0.0", ] @@ -278,6 +266,7 @@ version = "0.0.0" dependencies = [ "log 0.0.0", "rustc 0.0.0", + "serialize 0.0.0", "syntax 0.0.0", ] @@ -323,7 +312,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", - "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -362,13 +351,3 @@ dependencies = [ "syntax 0.0.0", ] -[[package]] -name = "winapi" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -