From fab7020bd95c695be4f3c06dce236fada0dabb8e Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Fri, 9 Feb 2018 19:04:12 +0100 Subject: [PATCH 01/12] Add span_suggestion while removing TyRefs based on the snippet String. --- src/librustc/traits/error_reporting.rs | 87 ++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7e5dc02798dff..c90a6d0709db6 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -575,6 +575,44 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { = self.on_unimplemented_note(trait_ref, obligation); let have_alt_message = message.is_some() || label.is_some(); + // { + // let ty::Binder(trait_ref) = trait_ref; + // println!("TraitRef: {:?}", trait_ref); + // println!("TraitRef: id:{:?}; subst:{:?}", trait_ref.def_id, trait_ref.substs); + + // if let ty::Predicate::Trait(trait_predicate_binder) = + // trait_ref.to_predicate() { + // let trait_predicate = trait_predicate_binder.skip_binder(); + // println!("TraitPredicateBinder: {:?}", trait_predicate_binder); + // println!("TraitPredicate: {:?}", trait_predicate); + + // let trait_ty = trait_ref.self_ty(); + // println!("TraitPredicateTy: {:?}", trait_ty); + // println!("TraitPredicateTy: sty:{:?}; flags{:?}", trait_ty.sty, trait_ty.flags); + // } + + // for in_ty in trait_ref.input_types() { + // println!("\t- {:?}", in_ty); + // println!("\t\t- sty:{:?}; flags:{:?}", in_ty.sty, in_ty.flags); + // } + + // println!("Message: {:?}", message); + // println!("Label: {:?}", label); + // println!("Obligation: {:?}", obligation); + // println!("Span: {:?}", self.tcx.sess.codemap().span_to_string(span)); + + // let body_id = obligation.cause.body_id; + // println!("BodyId: {:?}", body_id); + // println!("BodyIdSpan: {:?}", self.tcx.hir.span(body_id)); + + // match self.tcx.hir.find(body_id) { + // Some(node) => println!("Node: {:?}", node), + // None => println!("Node not found."), + // } + + // println!("=------------------------------="); + // } + let mut err = struct_span_err!( self.tcx.sess, span, @@ -606,6 +644,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); + self.suggest_remove_reference(&obligation, &mut err, &trait_ref); // Try to report a help message if !trait_ref.has_infer_types() && @@ -844,6 +883,54 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + fn suggest_remove_reference(&self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::Binder>) { + let ty::Binder(trait_ref) = trait_ref; + + let span = obligation.cause.span; + let mut snippet = match self.tcx.sess.codemap().span_to_snippet(span) { + Ok(s) => s, + Err(_) => String::from(""), + }; + + let mut refs_number = 0; + + for c in snippet.chars() { + if c == '&' { + refs_number += 1; + } + } + + let mut refs_remaining = refs_number; + let mut trait_type = trait_ref.self_ty(); + let mut selcx = SelectionContext::new(self); + + while refs_remaining > 0 { + if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) = + trait_type.sty { + trait_type = t_type; + refs_remaining -= 1; + + let substs = self.tcx.mk_substs_trait(trait_type, &[]); + let new_trait_ref = ty::TraitRef::new(trait_ref.def_id, substs); + let new_obligation = Obligation::new(ObligationCause::dummy(), + obligation.param_env, + new_trait_ref.to_predicate()); + + if selcx.evaluate_obligation(&new_obligation) { + for i in 0..refs_number { + snippet.remove(i); + } + err.span_suggestion(span, "consider removing `&`s like", format!("{}", snippet)); + } + } else { + break; + } + } + } + /// Given some node representing a fn-like thing in the HIR map, /// returns a span and `ArgKind` information that describes the /// arguments it expects. This can be supplied to From 4dd45069feda95e06cf8287629caea9c64d9d481 Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Sun, 11 Mar 2018 02:21:38 -0300 Subject: [PATCH 02/12] Refactored with high-order functions. --- src/librustc/traits/error_reporting.rs | 42 +++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index c90a6d0709db6..5bfeff89e355a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -888,28 +888,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err: &mut DiagnosticBuilder<'tcx>, trait_ref: &ty::Binder>) { let ty::Binder(trait_ref) = trait_ref; - let span = obligation.cause.span; - let mut snippet = match self.tcx.sess.codemap().span_to_snippet(span) { - Ok(s) => s, - Err(_) => String::from(""), - }; - let mut refs_number = 0; + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { + let refs_number = snippet.chars() + .filter(|c| !c.is_whitespace()) + .take_while(|c| *c == '&') + .count(); - for c in snippet.chars() { - if c == '&' { - refs_number += 1; - } - } + let mut refs_remaining = refs_number; + let mut trait_type = trait_ref.self_ty(); + let mut selcx = SelectionContext::new(self); - let mut refs_remaining = refs_number; - let mut trait_type = trait_ref.self_ty(); - let mut selcx = SelectionContext::new(self); + while refs_remaining > 0 { + if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) = + trait_type.sty { - while refs_remaining > 0 { - if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) = - trait_type.sty { trait_type = t_type; refs_remaining -= 1; @@ -920,14 +914,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { new_trait_ref.to_predicate()); if selcx.evaluate_obligation(&new_obligation) { - for i in 0..refs_number { - snippet.remove(i); - } - err.span_suggestion(span, "consider removing `&`s like", format!("{}", snippet)); + let suggest_snippet = snippet.chars() + .skip(refs_number) + .collect::(); + + err.span_suggestion(span, + "consider removing `&`s like", + format!("{}", suggest_snippet)); + + break; } } else { break; } + } } } From e0fb0132c12cc291a866c0ca72334751d3b5a677 Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Mon, 12 Mar 2018 23:40:55 -0300 Subject: [PATCH 03/12] Test added. --- src/test/ui/suggest-remove-refs.rs | 18 ++++++++++++++++++ src/test/ui/suggest-remove-refs.stderr | 15 +++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/test/ui/suggest-remove-refs.rs create mode 100644 src/test/ui/suggest-remove-refs.stderr diff --git a/src/test/ui/suggest-remove-refs.rs b/src/test/ui/suggest-remove-refs.rs new file mode 100644 index 0000000000000..0f19c48337b1e --- /dev/null +++ b/src/test/ui/suggest-remove-refs.rs @@ -0,0 +1,18 @@ +// Copyright 2014 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 v = vec![0, 1, 2, 3]; + + for (i, n) in &v.iter().enumerate() { + //~^ ERROR the trait bound + println!("{}", i); + } +} diff --git a/src/test/ui/suggest-remove-refs.stderr b/src/test/ui/suggest-remove-refs.stderr new file mode 100644 index 0000000000000..d81166e55797a --- /dev/null +++ b/src/test/ui/suggest-remove-refs.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&std::iter::Enumerate>: std::iter::Iterator` is not satisfied + --> $DIR/suggest-remove-refs.rs:14:19 + | +LL | for (i, n) in &v.iter().enumerate() { + | ^^^^^^^^^^^^^^^^^^^^^ + | | + | `&std::iter::Enumerate>` is not an iterator; maybe try calling `.iter()` or a similar method + | help: consider removing `&`s like: `v.iter().enumerate()` + | + = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Enumerate>` + = note: required by `std::iter::IntoIterator::into_iter` + +error: aborting due to previous error + +If you want more information on this error, try using "rustc --explain E0277" From f44b945e0ed73c6d108a40655d3bed14133ec7db Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Tue, 13 Mar 2018 01:05:46 -0300 Subject: [PATCH 04/12] New test added. --- ...remove-refs.rs => suggest-remove-refs-1.rs} | 0 ...efs.stderr => suggest-remove-refs-1.stderr} | 4 ++-- src/test/ui/suggest-remove-refs-2.rs | 18 ++++++++++++++++++ src/test/ui/suggest-remove-refs-2.stderr | 15 +++++++++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) rename src/test/ui/{suggest-remove-refs.rs => suggest-remove-refs-1.rs} (100%) rename src/test/ui/{suggest-remove-refs.stderr => suggest-remove-refs-1.stderr} (84%) create mode 100644 src/test/ui/suggest-remove-refs-2.rs create mode 100644 src/test/ui/suggest-remove-refs-2.stderr diff --git a/src/test/ui/suggest-remove-refs.rs b/src/test/ui/suggest-remove-refs-1.rs similarity index 100% rename from src/test/ui/suggest-remove-refs.rs rename to src/test/ui/suggest-remove-refs-1.rs diff --git a/src/test/ui/suggest-remove-refs.stderr b/src/test/ui/suggest-remove-refs-1.stderr similarity index 84% rename from src/test/ui/suggest-remove-refs.stderr rename to src/test/ui/suggest-remove-refs-1.stderr index d81166e55797a..154b67219f679 100644 --- a/src/test/ui/suggest-remove-refs.stderr +++ b/src/test/ui/suggest-remove-refs-1.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `&std::iter::Enumerate>: std::iter::Iterator` is not satisfied - --> $DIR/suggest-remove-refs.rs:14:19 + --> $DIR/suggest-remove-refs-1.rs:14:19 | LL | for (i, n) in &v.iter().enumerate() { | ^^^^^^^^^^^^^^^^^^^^^ | | | `&std::iter::Enumerate>` is not an iterator; maybe try calling `.iter()` or a similar method - | help: consider removing `&`s like: `v.iter().enumerate()` + | help: consider removing 1 references `&`: `v.iter().enumerate()` | = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Enumerate>` = note: required by `std::iter::IntoIterator::into_iter` diff --git a/src/test/ui/suggest-remove-refs-2.rs b/src/test/ui/suggest-remove-refs-2.rs new file mode 100644 index 0000000000000..c427f697ae1ef --- /dev/null +++ b/src/test/ui/suggest-remove-refs-2.rs @@ -0,0 +1,18 @@ +// Copyright 2014 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 v = vec![0, 1, 2, 3]; + + for (i, n) in & & & & &v.iter().enumerate() { + //~^ ERROR the trait bound + println!("{}", i); + } +} diff --git a/src/test/ui/suggest-remove-refs-2.stderr b/src/test/ui/suggest-remove-refs-2.stderr new file mode 100644 index 0000000000000..f394344275aaf --- /dev/null +++ b/src/test/ui/suggest-remove-refs-2.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&&&&&std::iter::Enumerate>: std::iter::Iterator` is not satisfied + --> $DIR/suggest-remove-refs-2.rs:14:19 + | +LL | for (i, n) in & & & & &v.iter().enumerate() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `&&&&&std::iter::Enumerate>` is not an iterator; maybe try calling `.iter()` or a similar method + | help: consider removing 5 references `&`: `v.iter().enumerate()` + | + = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate>` + = note: required by `std::iter::IntoIterator::into_iter` + +error: aborting due to previous error + +If you want more information on this error, try using "rustc --explain E0277" From 97b66d2987522d28bb69994e8908a5bb789bff37 Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Tue, 13 Mar 2018 01:06:04 -0300 Subject: [PATCH 05/12] Review fixes. - `suggest_snippet` handling space between refs; - Suggest message changing according to the number of refs that should be removed. --- src/librustc/traits/error_reporting.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 5bfeff89e355a..31c8cb25c521a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -883,6 +883,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, + /// suggest removing these references until we reach a type that implements the trait. fn suggest_remove_reference(&self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, @@ -896,16 +898,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .take_while(|c| *c == '&') .count(); - let mut refs_remaining = refs_number; let mut trait_type = trait_ref.self_ty(); let mut selcx = SelectionContext::new(self); - while refs_remaining > 0 { + for refs_remaining in 0..refs_number { if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) = trait_type.sty { trait_type = t_type; - refs_remaining -= 1; let substs = self.tcx.mk_substs_trait(trait_type, &[]); let new_trait_ref = ty::TraitRef::new(trait_ref.def_id, substs); @@ -914,12 +914,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { new_trait_ref.to_predicate()); if selcx.evaluate_obligation(&new_obligation) { + let remove_refs = refs_remaining + 1; + let suggest_snippet = snippet.chars() - .skip(refs_number) + .filter(|c| !c.is_whitespace()) + .skip(remove_refs) .collect::(); err.span_suggestion(span, - "consider removing `&`s like", + &format!("consider removing {} references `&`", + remove_refs), format!("{}", suggest_snippet)); break; From f41dc775a3ae1f002c24fdff6b2f7c4b68ceca66 Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Wed, 14 Mar 2018 06:41:05 -0300 Subject: [PATCH 06/12] Keeping code formatting. Suggesting snippet without changing the original formatting of the code. --- src/librustc/traits/error_reporting.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 31c8cb25c521a..1bbd24de6ae46 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -914,11 +914,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { new_trait_ref.to_predicate()); if selcx.evaluate_obligation(&new_obligation) { - let remove_refs = refs_remaining + 1; + let mut remove_refs = refs_remaining + 1; let suggest_snippet = snippet.chars() - .filter(|c| !c.is_whitespace()) - .skip(remove_refs) + .skip_while(|c| c.is_whitespace() || { + if *c == '&' && remove_refs > 0 { + true + } else { + false + } + }) .collect::(); err.span_suggestion(span, From 52cd07aef79223b89109fe392addb905d491de18 Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Wed, 14 Mar 2018 06:42:27 -0300 Subject: [PATCH 07/12] Created multiple line test. --- src/test/ui/suggest-remove-refs-3.rs | 21 +++++++++++++++++++++ src/test/ui/suggest-remove-refs-3.stderr | 22 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/test/ui/suggest-remove-refs-3.rs create mode 100644 src/test/ui/suggest-remove-refs-3.stderr diff --git a/src/test/ui/suggest-remove-refs-3.rs b/src/test/ui/suggest-remove-refs-3.rs new file mode 100644 index 0000000000000..f54ae30caebca --- /dev/null +++ b/src/test/ui/suggest-remove-refs-3.rs @@ -0,0 +1,21 @@ +// Copyright 2014 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 v = vec![0, 1, 2, 3]; + + for (i, n) in & & & + & &v + .iter() + .enumerate() { + //~^^^^ ERROR the trait bound + println!("{}", i); + } +} diff --git a/src/test/ui/suggest-remove-refs-3.stderr b/src/test/ui/suggest-remove-refs-3.stderr new file mode 100644 index 0000000000000..7add72adf4d3d --- /dev/null +++ b/src/test/ui/suggest-remove-refs-3.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `&&&&&std::iter::Enumerate>: std::iter::Iterator` is not satisfied + --> $DIR/suggest-remove-refs-3.rs:14:19 + | +LL | for (i, n) in & & & + | ___________________^ +LL | | & &v +LL | | .iter() +LL | | .enumerate() { + | |____________________^ `&&&&&std::iter::Enumerate>` is not an iterator; maybe try calling `.iter()` or a similar method + | + = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate>` + = note: required by `std::iter::IntoIterator::into_iter` +help: consider removing 5 references `&` + | +LL | for (i, n) in v +LL | .iter() +LL | .enumerate() { + | + +error: aborting due to previous error + +If you want more information on this error, try using "rustc --explain E0277" From f6bffd16d15672557e7d9c32b0cca08639a32251 Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Wed, 14 Mar 2018 12:49:06 -0300 Subject: [PATCH 08/12] Rebased with master. --- src/librustc_traits/normalize_projection_ty.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- src/test/ui/suggest-remove-refs-1.stderr | 2 +- src/test/ui/suggest-remove-refs-2.stderr | 2 +- src/test/ui/suggest-remove-refs-3.stderr | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs index 55785d9586cc3..171bc1bd2d6d4 100644 --- a/src/librustc_traits/normalize_projection_ty.rs +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -36,7 +36,7 @@ crate fn normalize_projection_ty<'tcx>( ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal); let fulfill_cx = &mut FulfillmentContext::new(); let selcx = &mut SelectionContext::new(infcx); - let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID); + let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID, DUMMY_NODE_ID); let Normalized { value: answer, obligations, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 596381d7ea676..4943560d68be0 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -298,7 +298,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( }; let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope)); let origin = || infer::SubregionOrigin::SafeDestructor(span); - let cause = &ObligationCause::misc(span, body_id); + let cause = &ObligationCause::misc(span, body_id, body_id); let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty); debug!("dropck_outlives = {:#?}", infer_ok); let kinds = rcx.fcx.register_infer_ok_obligations(infer_ok); diff --git a/src/test/ui/suggest-remove-refs-1.stderr b/src/test/ui/suggest-remove-refs-1.stderr index 154b67219f679..fe4ab2c4ee052 100644 --- a/src/test/ui/suggest-remove-refs-1.stderr +++ b/src/test/ui/suggest-remove-refs-1.stderr @@ -12,4 +12,4 @@ LL | for (i, n) in &v.iter().enumerate() { error: aborting due to previous error -If you want more information on this error, try using "rustc --explain E0277" +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggest-remove-refs-2.stderr b/src/test/ui/suggest-remove-refs-2.stderr index f394344275aaf..243ddcfe125e2 100644 --- a/src/test/ui/suggest-remove-refs-2.stderr +++ b/src/test/ui/suggest-remove-refs-2.stderr @@ -12,4 +12,4 @@ LL | for (i, n) in & & & & &v.iter().enumerate() { error: aborting due to previous error -If you want more information on this error, try using "rustc --explain E0277" +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggest-remove-refs-3.stderr b/src/test/ui/suggest-remove-refs-3.stderr index 7add72adf4d3d..83f3826642b2b 100644 --- a/src/test/ui/suggest-remove-refs-3.stderr +++ b/src/test/ui/suggest-remove-refs-3.stderr @@ -19,4 +19,4 @@ LL | .enumerate() { error: aborting due to previous error -If you want more information on this error, try using "rustc --explain E0277" +For more information about this error, try `rustc --explain E0277`. From c1ba5ac62c14ab5e231edcce914fd33f0e32c2d1 Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Fri, 16 Mar 2018 17:58:11 -0300 Subject: [PATCH 09/12] Reporting with `span_suggestion_short`. --- src/librustc/traits/error_reporting.rs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 1bbd24de6ae46..267d84cc53141 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -914,22 +914,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { new_trait_ref.to_predicate()); if selcx.evaluate_obligation(&new_obligation) { - let mut remove_refs = refs_remaining + 1; - - let suggest_snippet = snippet.chars() - .skip_while(|c| c.is_whitespace() || { - if *c == '&' && remove_refs > 0 { - true - } else { - false - } - }) - .collect::(); + let remove_refs = refs_remaining + 1; - err.span_suggestion(span, - &format!("consider removing {} references `&`", - remove_refs), - format!("{}", suggest_snippet)); + err.span_suggestion_short(span, + &format!("consider removing {} leading `&`-references", + remove_refs), + String::from("")); break; } From 74a4928ed49d000dee9827c21f68148ad3aa271e Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Sat, 17 Mar 2018 15:41:46 -0300 Subject: [PATCH 10/12] Review fixes. - `span_suggestion` changed to `span_suggestion_short`; - `Span` used changed to contain only `&` refs; - Tests passing. --- src/librustc/traits/error_reporting.rs | 11 ++++++----- src/libsyntax/codemap.rs | 16 ++++++++++++++++ src/test/ui/suggest-remove-refs-1.stderr | 4 ++-- src/test/ui/suggest-remove-refs-2.stderr | 4 ++-- src/test/ui/suggest-remove-refs-3.stderr | 21 +++++++++------------ 5 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 267d84cc53141..9b01f8899b52b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -914,13 +914,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { new_trait_ref.to_predicate()); if selcx.evaluate_obligation(&new_obligation) { - let remove_refs = refs_remaining + 1; + let sp = self.tcx.sess.codemap() + .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - err.span_suggestion_short(span, - &format!("consider removing {} leading `&`-references", - remove_refs), - String::from("")); + let remove_refs = refs_remaining + 1; + let format_str = format!("consider removing {} leading `&`-references", + remove_refs); + err.span_suggestion_short(sp, &format_str, String::from("")); break; } } else { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index a1aec05208859..324d57c119452 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -697,6 +697,22 @@ impl CodeMap { sp } + /// Given a `Span`, get a shorter one until `predicate` yields false. + pub fn span_take_while

(&self, sp: Span, predicate: P) -> Span + where P: for <'r> FnMut(&'r char) -> bool + { + if let Ok(snippet) = self.span_to_snippet(sp) { + let offset = snippet.chars() + .take_while(predicate) + .map(|c| c.len_utf8()) + .sum::(); + + sp.with_hi(BytePos(sp.lo().0 + (offset as u32))) + } else { + sp + } + } + pub fn def_span(&self, sp: Span) -> Span { self.span_until_char(sp, '{') } diff --git a/src/test/ui/suggest-remove-refs-1.stderr b/src/test/ui/suggest-remove-refs-1.stderr index fe4ab2c4ee052..c47b4d283d7cd 100644 --- a/src/test/ui/suggest-remove-refs-1.stderr +++ b/src/test/ui/suggest-remove-refs-1.stderr @@ -2,10 +2,10 @@ error[E0277]: the trait bound `&std::iter::Enumerate $DIR/suggest-remove-refs-1.rs:14:19 | LL | for (i, n) in &v.iter().enumerate() { - | ^^^^^^^^^^^^^^^^^^^^^ + | -^^^^^^^^^^^^^^^^^^^^ | | | `&std::iter::Enumerate>` is not an iterator; maybe try calling `.iter()` or a similar method - | help: consider removing 1 references `&`: `v.iter().enumerate()` + | help: consider removing 1 leading `&`-references | = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Enumerate>` = note: required by `std::iter::IntoIterator::into_iter` diff --git a/src/test/ui/suggest-remove-refs-2.stderr b/src/test/ui/suggest-remove-refs-2.stderr index 243ddcfe125e2..fdd654ea3923f 100644 --- a/src/test/ui/suggest-remove-refs-2.stderr +++ b/src/test/ui/suggest-remove-refs-2.stderr @@ -2,10 +2,10 @@ error[E0277]: the trait bound `&&&&&std::iter::Enumerate $DIR/suggest-remove-refs-2.rs:14:19 | LL | for (i, n) in & & & & &v.iter().enumerate() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ---------^^^^^^^^^^^^^^^^^^^^ | | | `&&&&&std::iter::Enumerate>` is not an iterator; maybe try calling `.iter()` or a similar method - | help: consider removing 5 references `&`: `v.iter().enumerate()` + | help: consider removing 5 leading `&`-references | = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate>` = note: required by `std::iter::IntoIterator::into_iter` diff --git a/src/test/ui/suggest-remove-refs-3.stderr b/src/test/ui/suggest-remove-refs-3.stderr index 83f3826642b2b..b0920a0fa523e 100644 --- a/src/test/ui/suggest-remove-refs-3.stderr +++ b/src/test/ui/suggest-remove-refs-3.stderr @@ -1,21 +1,18 @@ error[E0277]: the trait bound `&&&&&std::iter::Enumerate>: std::iter::Iterator` is not satisfied --> $DIR/suggest-remove-refs-3.rs:14:19 | -LL | for (i, n) in & & & - | ___________________^ -LL | | & &v -LL | | .iter() -LL | | .enumerate() { - | |____________________^ `&&&&&std::iter::Enumerate>` is not an iterator; maybe try calling `.iter()` or a similar method +LL | for (i, n) in & & & + | ___________________^ + | |___________________| + | || +LL | || & &v + | ||___________- help: consider removing 5 leading `&`-references +LL | | .iter() +LL | | .enumerate() { + | |_____________________^ `&&&&&std::iter::Enumerate>` is not an iterator; maybe try calling `.iter()` or a similar method | = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate>` = note: required by `std::iter::IntoIterator::into_iter` -help: consider removing 5 references `&` - | -LL | for (i, n) in v -LL | .iter() -LL | .enumerate() { - | error: aborting due to previous error From 0b36b20651704cf7051f468aeb3b84babf940e63 Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Sun, 18 Mar 2018 10:05:20 -0300 Subject: [PATCH 11/12] CodeMap functions refactored. - Using `span_take_while` to implement others. --- src/libsyntax/codemap.rs | 88 +++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 50 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 324d57c119452..73924c4270e66 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -597,21 +597,6 @@ impl CodeMap { self.span_to_source(sp, |src, start_index, _| src[..start_index].to_string()) } - /// Given a `Span`, try to get a shorter span ending before the first occurrence of `c` `char` - pub fn span_until_char(&self, sp: Span, c: char) -> Span { - match self.span_to_snippet(sp) { - Ok(snippet) => { - let snippet = snippet.split(c).nth(0).unwrap_or("").trim_right(); - if !snippet.is_empty() && !snippet.contains('\n') { - sp.with_hi(BytePos(sp.lo().0 + snippet.len() as u32)) - } else { - sp - } - } - _ => sp, - } - } - /// Extend the given `Span` to just after the previous occurrence of `c`. Return the same span /// if no character could be found or if an error occurred while retrieving the code snippet. pub fn span_extend_to_prev_char(&self, sp: Span, c: char) -> Span { @@ -646,26 +631,50 @@ impl CodeMap { sp } + /// Given a `Span`, try to get a shorter span ending before the first occurrence of `c` `char` + pub fn span_until_char(&self, sp: Span, c: char) -> Span { + match self.span_to_snippet(sp) { + Ok(snippet) => { + let snippet = snippet.split(c).nth(0).unwrap_or("").trim_right(); + if !snippet.is_empty() && !snippet.contains('\n') { + sp.with_hi(BytePos(sp.lo().0 + snippet.len() as u32)) + } else { + sp + } + } + _ => sp, + } + } + + /// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char` + /// `c`. + pub fn span_through_char(&self, sp: Span, c: char) -> Span { + if let Ok(snippet) = self.span_to_snippet(sp) { + if let Some(offset) = snippet.find(c) { + return sp.with_hi(BytePos(sp.lo().0 + (offset + c.len_utf8()) as u32)); + } + } + sp + } + /// Given a `Span`, get a new `Span` covering the first token and all its trailing whitespace or /// the original `Span`. /// /// If `sp` points to `"let mut x"`, then a span pointing at `"let "` will be returned. pub fn span_until_non_whitespace(&self, sp: Span) -> Span { - if let Ok(snippet) = self.span_to_snippet(sp) { - let mut offset = 0; - // get the bytes width of all the non-whitespace characters - for c in snippet.chars().take_while(|c| !c.is_whitespace()) { - offset += c.len_utf8(); - } - // get the bytes width of all the whitespace characters after that - for c in snippet[offset..].chars().take_while(|c| c.is_whitespace()) { - offset += c.len_utf8(); + let mut whitespace_found = false; + + self.span_take_while(sp, |c| { + if !whitespace_found && c.is_whitespace() { + whitespace_found = true; } - if offset > 1 { - return sp.with_hi(BytePos(sp.lo().0 + offset as u32)); + + if whitespace_found && !c.is_whitespace() { + false + } else { + true } - } - sp + }) } /// Given a `Span`, get a new `Span` covering the first token without its trailing whitespace or @@ -673,28 +682,7 @@ impl CodeMap { /// /// If `sp` points to `"let mut x"`, then a span pointing at `"let"` will be returned. pub fn span_until_whitespace(&self, sp: Span) -> Span { - if let Ok(snippet) = self.span_to_snippet(sp) { - let mut offset = 0; - // Get the bytes width of all the non-whitespace characters - for c in snippet.chars().take_while(|c| !c.is_whitespace()) { - offset += c.len_utf8(); - } - if offset > 1 { - return sp.with_hi(BytePos(sp.lo().0 + offset as u32)); - } - } - sp - } - - /// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char` - /// `c`. - pub fn span_through_char(&self, sp: Span, c: char) -> Span { - if let Ok(snippet) = self.span_to_snippet(sp) { - if let Some(offset) = snippet.find(c) { - return sp.with_hi(BytePos(sp.lo().0 + (offset + c.len_utf8()) as u32)); - } - } - sp + self.span_take_while(sp, |c| !c.is_whitespace()) } /// Given a `Span`, get a shorter one until `predicate` yields false. From 736ba433ac2f0d2f6604a64f744f86a311a56be4 Mon Sep 17 00:00:00 2001 From: Yukio Siraichi Date: Sun, 18 Mar 2018 20:58:56 -0300 Subject: [PATCH 12/12] Cleaned comments and extras s. --- src/librustc/traits/error_reporting.rs | 38 ------------------- .../normalize_projection_ty.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- 3 files changed, 2 insertions(+), 40 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 9b01f8899b52b..ab3c619dcdcd0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -575,44 +575,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { = self.on_unimplemented_note(trait_ref, obligation); let have_alt_message = message.is_some() || label.is_some(); - // { - // let ty::Binder(trait_ref) = trait_ref; - // println!("TraitRef: {:?}", trait_ref); - // println!("TraitRef: id:{:?}; subst:{:?}", trait_ref.def_id, trait_ref.substs); - - // if let ty::Predicate::Trait(trait_predicate_binder) = - // trait_ref.to_predicate() { - // let trait_predicate = trait_predicate_binder.skip_binder(); - // println!("TraitPredicateBinder: {:?}", trait_predicate_binder); - // println!("TraitPredicate: {:?}", trait_predicate); - - // let trait_ty = trait_ref.self_ty(); - // println!("TraitPredicateTy: {:?}", trait_ty); - // println!("TraitPredicateTy: sty:{:?}; flags{:?}", trait_ty.sty, trait_ty.flags); - // } - - // for in_ty in trait_ref.input_types() { - // println!("\t- {:?}", in_ty); - // println!("\t\t- sty:{:?}; flags:{:?}", in_ty.sty, in_ty.flags); - // } - - // println!("Message: {:?}", message); - // println!("Label: {:?}", label); - // println!("Obligation: {:?}", obligation); - // println!("Span: {:?}", self.tcx.sess.codemap().span_to_string(span)); - - // let body_id = obligation.cause.body_id; - // println!("BodyId: {:?}", body_id); - // println!("BodyIdSpan: {:?}", self.tcx.hir.span(body_id)); - - // match self.tcx.hir.find(body_id) { - // Some(node) => println!("Node: {:?}", node), - // None => println!("Node not found."), - // } - - // println!("=------------------------------="); - // } - let mut err = struct_span_err!( self.tcx.sess, span, diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs index 171bc1bd2d6d4..55785d9586cc3 100644 --- a/src/librustc_traits/normalize_projection_ty.rs +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -36,7 +36,7 @@ crate fn normalize_projection_ty<'tcx>( ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal); let fulfill_cx = &mut FulfillmentContext::new(); let selcx = &mut SelectionContext::new(infcx); - let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID, DUMMY_NODE_ID); + let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID); let Normalized { value: answer, obligations, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 4943560d68be0..596381d7ea676 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -298,7 +298,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( }; let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope)); let origin = || infer::SubregionOrigin::SafeDestructor(span); - let cause = &ObligationCause::misc(span, body_id, body_id); + let cause = &ObligationCause::misc(span, body_id); let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty); debug!("dropck_outlives = {:#?}", infer_ok); let kinds = rcx.fcx.register_infer_ok_obligations(infer_ok);