From a5d931050e69df1bc07117a2891154a71a06a73e Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Tue, 24 Sep 2019 17:49:25 +0800 Subject: [PATCH 01/18] remove 'as_str' when it's already a str type. fix #62642 --- src/librustc_typeck/check/method/suggest.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 2d4d2e32f23db..e68e3211cade1 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -518,7 +518,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if let Some(lev_candidate) = lev_candidate { + fn is_str_ref<'tcx>(ty: Ty<'tcx>) -> bool { + match ty.sty { + ty::Str => true, + ty::Ref(_, ty, _) => is_str_ref(&ty), + _ => false, + } + } + if item_name.as_str() == "as_str" && is_str_ref(&actual) { + err.span_suggestion( + span, + "try to remove `as_str`", + String::new(), + Applicability::MaybeIncorrect, + ); + } else if let Some(lev_candidate) = lev_candidate { let def_kind = lev_candidate.def_kind(); err.span_suggestion( span, From bb3c03049dbef28d18a7ca17b5b9d25f7c276b8e Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Tue, 24 Sep 2019 23:02:21 +0800 Subject: [PATCH 02/18] add test files --- src/librustc_typeck/check/method/suggest.rs | 2 +- src/test/ui/suggestions/remove-as_str.rs | 21 +++++++++++++++ src/test/ui/suggestions/remove-as_str.stderr | 27 ++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/suggestions/remove-as_str.rs create mode 100644 src/test/ui/suggestions/remove-as_str.stderr diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index e68e3211cade1..6efa304559210 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -518,7 +518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn is_str_ref<'tcx>(ty: Ty<'tcx>) -> bool { + fn is_str_ref(ty: Ty<'_>) -> bool { match ty.sty { ty::Str => true, ty::Ref(_, ty, _) => is_str_ref(&ty), diff --git a/src/test/ui/suggestions/remove-as_str.rs b/src/test/ui/suggestions/remove-as_str.rs new file mode 100644 index 0000000000000..d10300b48ba1e --- /dev/null +++ b/src/test/ui/suggestions/remove-as_str.rs @@ -0,0 +1,21 @@ +fn foo1(s: &str) { + s.as_str(); + //~^ ERROR no method named `as_str` found for type `&str` in the current scope +} + +fn foo2<'a>(s: &'a str) { + s.as_str(); + //~^ ERROR no method named `as_str` found for type `&'a str` in the current scope +} + +fn foo3(s: &mut str) { + s.as_str(); + //~^ ERROR no method named `as_str` found for type `&mut str` in the current scope +} + +fn foo4(s: &&str) { + s.as_str(); + //~^ ERROR no method named `as_str` found for type `&&str` in the current scope +} + +fn main() {} diff --git a/src/test/ui/suggestions/remove-as_str.stderr b/src/test/ui/suggestions/remove-as_str.stderr new file mode 100644 index 0000000000000..090a359fa68de --- /dev/null +++ b/src/test/ui/suggestions/remove-as_str.stderr @@ -0,0 +1,27 @@ +error[E0599]: no method named `as_str` found for type `&str` in the current scope + --> $DIR/remove-as_str.rs:2:7 + | +LL | s.as_str(); + | ^^^^^^ help: try to remove `as_str` + +error[E0599]: no method named `as_str` found for type `&'a str` in the current scope + --> $DIR/remove-as_str.rs:7:7 + | +LL | s.as_str(); + | ^^^^^^ help: try to remove `as_str` + +error[E0599]: no method named `as_str` found for type `&mut str` in the current scope + --> $DIR/remove-as_str.rs:12:7 + | +LL | s.as_str(); + | ^^^^^^ help: try to remove `as_str` + +error[E0599]: no method named `as_str` found for type `&&str` in the current scope + --> $DIR/remove-as_str.rs:17:7 + | +LL | s.as_str(); + | ^^^^^^ help: try to remove `as_str` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. From 4cb86c908989087dca7d3ad2b5c9029c62aaf852 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Wed, 25 Sep 2019 12:31:52 +0800 Subject: [PATCH 03/18] comment fixes --- src/librustc/ty/sty.rs | 4 ++++ src/librustc_typeck/check/method/suggest.rs | 11 ++--------- src/test/ui/suggestions/remove-as_str.stderr | 8 ++++---- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index e105c44d09ae5..dfd8168985c02 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1776,6 +1776,10 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_bool(&self) -> bool { self.kind == Bool } + /// Returns `true` if this type is a `str`. + #[inline] + pub fn is_str(&self) -> bool { self.sty == Str } + #[inline] pub fn is_param(&self, index: u32) -> bool { match self.kind { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 6efa304559210..89055628342b1 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -518,17 +518,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn is_str_ref(ty: Ty<'_>) -> bool { - match ty.sty { - ty::Str => true, - ty::Ref(_, ty, _) => is_str_ref(&ty), - _ => false, - } - } - if item_name.as_str() == "as_str" && is_str_ref(&actual) { + if item_name.as_str() == "as_str" && actual.peel_refs().is_str() { err.span_suggestion( span, - "try to remove `as_str`", + "try removing `as_str`", String::new(), Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/suggestions/remove-as_str.stderr b/src/test/ui/suggestions/remove-as_str.stderr index 090a359fa68de..47196aa2c8ea0 100644 --- a/src/test/ui/suggestions/remove-as_str.stderr +++ b/src/test/ui/suggestions/remove-as_str.stderr @@ -2,25 +2,25 @@ error[E0599]: no method named `as_str` found for type `&str` in the current scop --> $DIR/remove-as_str.rs:2:7 | LL | s.as_str(); - | ^^^^^^ help: try to remove `as_str` + | ^^^^^^ help: try removing `as_str` error[E0599]: no method named `as_str` found for type `&'a str` in the current scope --> $DIR/remove-as_str.rs:7:7 | LL | s.as_str(); - | ^^^^^^ help: try to remove `as_str` + | ^^^^^^ help: try removing `as_str` error[E0599]: no method named `as_str` found for type `&mut str` in the current scope --> $DIR/remove-as_str.rs:12:7 | LL | s.as_str(); - | ^^^^^^ help: try to remove `as_str` + | ^^^^^^ help: try removing `as_str` error[E0599]: no method named `as_str` found for type `&&str` in the current scope --> $DIR/remove-as_str.rs:17:7 | LL | s.as_str(); - | ^^^^^^ help: try to remove `as_str` + | ^^^^^^ help: try removing `as_str` error: aborting due to 4 previous errors From 5abc5e9b3df85ec6fa22e67e0ea624cd225d2007 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Tue, 1 Oct 2019 15:22:52 +0800 Subject: [PATCH 04/18] add FIXME and use 'span_label' --- src/librustc_typeck/check/method/suggest.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 89055628342b1..e9a8a52857ab3 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -519,11 +519,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if item_name.as_str() == "as_str" && actual.peel_refs().is_str() { - err.span_suggestion( + // FIXME: the span is not quite correct, it should point to ".as_str()" instead + // of just "as_str". + err.span_label( span, - "try removing `as_str`", - String::new(), - Applicability::MaybeIncorrect, + "try removing `as_str`" ); } else if let Some(lev_candidate) = lev_candidate { let def_kind = lev_candidate.def_kind(); From 51482d0b75de535243032265269562ffa7538c46 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Tue, 1 Oct 2019 15:29:09 +0800 Subject: [PATCH 05/18] fix unit tests --- src/test/ui/suggestions/remove-as_str.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/suggestions/remove-as_str.stderr b/src/test/ui/suggestions/remove-as_str.stderr index 47196aa2c8ea0..2e8b72ebd4f6d 100644 --- a/src/test/ui/suggestions/remove-as_str.stderr +++ b/src/test/ui/suggestions/remove-as_str.stderr @@ -2,25 +2,25 @@ error[E0599]: no method named `as_str` found for type `&str` in the current scop --> $DIR/remove-as_str.rs:2:7 | LL | s.as_str(); - | ^^^^^^ help: try removing `as_str` + | ^^^^^^ try removing `as_str` error[E0599]: no method named `as_str` found for type `&'a str` in the current scope --> $DIR/remove-as_str.rs:7:7 | LL | s.as_str(); - | ^^^^^^ help: try removing `as_str` + | ^^^^^^ try removing `as_str` error[E0599]: no method named `as_str` found for type `&mut str` in the current scope --> $DIR/remove-as_str.rs:12:7 | LL | s.as_str(); - | ^^^^^^ help: try removing `as_str` + | ^^^^^^ try removing `as_str` error[E0599]: no method named `as_str` found for type `&&str` in the current scope --> $DIR/remove-as_str.rs:17:7 | LL | s.as_str(); - | ^^^^^^ help: try removing `as_str` + | ^^^^^^ try removing `as_str` error: aborting due to 4 previous errors From 11c2d43485e92a00d86b3a5bc1655165b6b8371b Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Wed, 2 Oct 2019 12:09:30 +0800 Subject: [PATCH 06/18] typo fix in the code --- src/librustc/ty/sty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index dfd8168985c02..ebeb26be23df6 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1778,7 +1778,7 @@ impl<'tcx> TyS<'tcx> { /// Returns `true` if this type is a `str`. #[inline] - pub fn is_str(&self) -> bool { self.sty == Str } + pub fn is_str(&self) -> bool { self.kind == Str } #[inline] pub fn is_param(&self, index: u32) -> bool { From 55ecb79123a3e9e91444a07e2e42d417e88c0b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 3 Oct 2019 17:10:37 -0700 Subject: [PATCH 07/18] Note when a mutable trait object is needed --- src/librustc/traits/error_reporting.rs | 111 ++++++++++++++---- src/librustc_typeck/check/method/mod.rs | 64 ++++++---- src/librustc_typeck/check/method/suggest.rs | 11 +- src/test/ui/not-panic/not-panic-safe.stderr | 1 + .../ui/parser/lex-bad-char-literals-6.stderr | 2 + .../imm-ref-trait-object-literal.rs | 14 +++ .../imm-ref-trait-object-literal.stderr | 30 +++++ .../ui/suggestions/imm-ref-trait-object.rs | 8 ++ .../suggestions/imm-ref-trait-object.stderr | 10 ++ src/test/ui/suggestions/into-str.stderr | 1 + .../suggestions/mut-borrow-needed-by-trait.rs | 23 ++++ .../mut-borrow-needed-by-trait.stderr | 41 +++++++ .../suggestions/suggest-remove-refs-1.stderr | 1 + 13 files changed, 271 insertions(+), 46 deletions(-) create mode 100644 src/test/ui/suggestions/imm-ref-trait-object-literal.rs create mode 100644 src/test/ui/suggestions/imm-ref-trait-object-literal.stderr create mode 100644 src/test/ui/suggestions/imm-ref-trait-object.rs create mode 100644 src/test/ui/suggestions/imm-ref-trait-object.stderr create mode 100644 src/test/ui/suggestions/mut-borrow-needed-by-trait.rs create mode 100644 src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a1c97d6c68790..f85ba1459f5f2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -453,21 +453,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - fn find_similar_impl_candidates(&self, - trait_ref: ty::PolyTraitRef<'tcx>) - -> Vec> - { - let simp = fast_reject::simplify_type(self.tcx, - trait_ref.skip_binder().self_ty(), - true); + fn find_similar_impl_candidates( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Vec> { + let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true); let all_impls = self.tcx.all_impls(trait_ref.def_id()); match simp { Some(simp) => all_impls.iter().filter_map(|&def_id| { let imp = self.tcx.impl_trait_ref(def_id).unwrap(); - let imp_simp = fast_reject::simplify_type(self.tcx, - imp.self_ty(), - true); + let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true); if let Some(imp_simp) = imp_simp { if simp != imp_simp { return None @@ -482,10 +478,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - fn report_similar_impl_candidates(&self, - impl_candidates: Vec>, - err: &mut DiagnosticBuilder<'_>) - { + fn report_similar_impl_candidates( + &self, + impl_candidates: Vec>, + err: &mut DiagnosticBuilder<'_>, + ) { if impl_candidates.is_empty() { return; } @@ -720,10 +717,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // which is somewhat confusing. err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); - } else if !have_alt_message { - // Can't show anything else useful, try to find similar impls. - let impl_candidates = self.find_similar_impl_candidates(trait_ref); - self.report_similar_impl_candidates(impl_candidates, &mut err); + } else { + if !have_alt_message { + // Can't show anything else useful, try to find similar impls. + let impl_candidates = self.find_similar_impl_candidates(trait_ref); + self.report_similar_impl_candidates(impl_candidates, &mut err); + } + self.suggest_change_mut( + &obligation, + &mut err, + &trait_ref, + points_at_arg, + ); } // If this error is due to `!: Trait` not implemented but `(): Trait` is @@ -1081,9 +1086,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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()); + let new_obligation = Obligation::new( + ObligationCause::dummy(), + obligation.param_env, + new_trait_ref.to_predicate(), + ); if self.predicate_may_hold(&new_obligation) { let sp = self.tcx.sess.source_map() @@ -1105,6 +1112,68 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + /// Check if the trait bound is implemented for a different mutability and note it in the + /// final error. + fn suggest_change_mut( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::Binder>, + points_at_arg: bool, + ) { + let span = obligation.cause.span; + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + let refs_number = snippet.chars() + .filter(|c| !c.is_whitespace()) + .take_while(|c| *c == '&') + .count(); + if let Some('\'') = snippet.chars() + .filter(|c| !c.is_whitespace()) + .skip(refs_number) + .next() + { // Do not suggest removal of borrow from type arguments. + return; + } + + if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind { + let trait_type = match mutability { + hir::Mutability::MutMutable => self.tcx.mk_imm_ref(region, t_type), + hir::Mutability::MutImmutable => self.tcx.mk_mut_ref(region, t_type), + }; + + let substs = self.tcx.mk_substs_trait(&trait_type, &[]); + let new_trait_ref = ty::TraitRef::new(trait_ref.skip_binder().def_id, substs); + let new_obligation = Obligation::new( + ObligationCause::dummy(), + obligation.param_env, + new_trait_ref.to_predicate(), + ); + + if self.predicate_may_hold(&new_obligation) { + let sp = self.tcx.sess.source_map() + .span_take_while(span, |c| c.is_whitespace() || *c == '&'); + if points_at_arg && + mutability == hir::Mutability::MutImmutable && + refs_number > 0 + { + err.span_suggestion( + sp, + "consider changing this borrow's mutability", + "&mut ".to_string(), + Applicability::MachineApplicable, + ); + } else { + err.note(&format!( + "`{}` is implemented for `{:?}`", + trait_ref, + trait_type, + )); + } + } + } + } + } + fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 2be311127214d..4522be21cab50 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -58,7 +58,7 @@ pub enum MethodError<'tcx> { // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have // forgotten to import a trait. - IllegalSizedBound(Vec), + IllegalSizedBound(Vec, bool), // Found a match, but the return type is wrong BadReturnType, @@ -213,33 +213,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { segment, ); + let mut needs_mut = false; + if let ty::Ref(region, t_type, mutability) = self_ty.kind { + let trait_type = match mutability { + hir::Mutability::MutMutable => self.tcx.mk_imm_ref(region, t_type), + hir::Mutability::MutImmutable => self.tcx.mk_mut_ref(region, t_type), + }; + match self.lookup_probe( + span, + segment.ident, + trait_type, + call_expr, + ProbeScope::TraitsInScope + ) { + Ok(ref new_pick) if *new_pick != pick => { + needs_mut = true; + } + _ => {} + } + } + if result.illegal_sized_bound { // We probe again, taking all traits into account (not only those in scope). - let candidates = - match self.lookup_probe(span, - segment.ident, - self_ty, - call_expr, - ProbeScope::AllTraits) { - - // If we find a different result the caller probably forgot to import a trait. - Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()], - Err(Ambiguity(ref sources)) => { - sources.iter() - .filter_map(|source| { - match *source { - // Note: this cannot come from an inherent impl, - // because the first probing succeeded. - ImplSource(def) => self.tcx.trait_id_of_impl(def), - TraitSource(_) => None, - } - }) - .collect() + let candidates = match self.lookup_probe( + span, + segment.ident, + self_ty, + call_expr, + ProbeScope::AllTraits, + ) { + // If we find a different result the caller probably forgot to import a trait. + Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()], + Err(Ambiguity(ref sources)) => sources.iter().filter_map(|source| { + match *source { + // Note: this cannot come from an inherent impl, + // because the first probing succeeded. + ImplSource(def) => self.tcx.trait_id_of_impl(def), + TraitSource(_) => None, } - _ => Vec::new(), - }; + }).collect(), + _ => Vec::new(), + }; - return Err(IllegalSizedBound(candidates)); + return Err(IllegalSizedBound(candidates, needs_mut)); } Ok(result.callee) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 2b34c24b266d0..37bc4b63f4bc9 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -553,7 +553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } - MethodError::IllegalSizedBound(candidates) => { + MethodError::IllegalSizedBound(candidates, needs_mut) => { let msg = format!("the `{}` method cannot be invoked on a trait object", item_name); let mut err = self.sess().struct_span_err(span, &msg); if !candidates.is_empty() { @@ -569,6 +569,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); self.suggest_use_candidates(&mut err, help, candidates); } + if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind { + let trait_type = match mutability { + hir::Mutability::MutMutable => self.tcx.mk_imm_ref(region, t_type), + hir::Mutability::MutImmutable => self.tcx.mk_mut_ref(region, t_type), + }; + if needs_mut { + err.note(&format!("you need `{}` instead", trait_type)); + } + } err.emit(); } diff --git a/src/test/ui/not-panic/not-panic-safe.stderr b/src/test/ui/not-panic/not-panic-safe.stderr index aa18b923044c6..2ae5ba523a70f 100644 --- a/src/test/ui/not-panic/not-panic-safe.stderr +++ b/src/test/ui/not-panic/not-panic-safe.stderr @@ -8,6 +8,7 @@ LL | assert::<&mut i32>(); | ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary | = help: the trait `std::panic::UnwindSafe` is not implemented for `&mut i32` + = note: `std::panic::UnwindSafe` is implemented for `&i32` error: aborting due to previous error diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/parser/lex-bad-char-literals-6.stderr index a7bbe05e94b7b..4792aacefe5e9 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -35,6 +35,7 @@ LL | if x == y {} | ^^ no implementation for `&str == char` | = help: the trait `std::cmp::PartialEq` is not implemented for `&str` + = note: `std::cmp::PartialEq` is implemented for `&mut str` error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:15:20 @@ -52,6 +53,7 @@ LL | if x == z {} | ^^ no implementation for `&str == char` | = help: the trait `std::cmp::PartialEq` is not implemented for `&str` + = note: `std::cmp::PartialEq` is implemented for `&mut str` error: aborting due to 6 previous errors diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal.rs b/src/test/ui/suggestions/imm-ref-trait-object-literal.rs new file mode 100644 index 0000000000000..22ca6dde45eee --- /dev/null +++ b/src/test/ui/suggestions/imm-ref-trait-object-literal.rs @@ -0,0 +1,14 @@ +trait Trait {} + +struct S; + +impl<'a> Trait for &'a mut S {} + +fn foo(_: X) {} + + +fn main() { + let s = S; + foo(&s); //~ ERROR the trait bound `&S: Trait` is not satisfied + foo(s); //~ ERROR the trait bound `S: Trait` is not satisfied +} diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr new file mode 100644 index 0000000000000..ccaceefacd739 --- /dev/null +++ b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr @@ -0,0 +1,30 @@ +error[E0277]: the trait bound `&S: Trait` is not satisfied + --> $DIR/imm-ref-trait-object-literal.rs:12:7 + | +LL | fn foo(_: X) {} + | --- ----- required by this bound in `foo` +... +LL | foo(&s); + | -^ + | | + | the trait `Trait` is not implemented for `&S` + | help: consider changing this borrow's mutability: `&mut` + | + = help: the following implementations were found: + <&'a mut S as Trait> + +error[E0277]: the trait bound `S: Trait` is not satisfied + --> $DIR/imm-ref-trait-object-literal.rs:13:7 + | +LL | fn foo(_: X) {} + | --- ----- required by this bound in `foo` +... +LL | foo(s); + | ^ the trait `Trait` is not implemented for `S` + | + = help: the following implementations were found: + <&'a mut S as Trait> + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/imm-ref-trait-object.rs b/src/test/ui/suggestions/imm-ref-trait-object.rs new file mode 100644 index 0000000000000..288d6c699f59a --- /dev/null +++ b/src/test/ui/suggestions/imm-ref-trait-object.rs @@ -0,0 +1,8 @@ +fn test(t: &dyn Iterator) -> u64 { + t.min().unwrap() //~ ERROR the `min` method cannot be invoked on a trait object +} + +fn main() { + let array = [0u64]; + test(&mut array.iter()); +} diff --git a/src/test/ui/suggestions/imm-ref-trait-object.stderr b/src/test/ui/suggestions/imm-ref-trait-object.stderr new file mode 100644 index 0000000000000..e272d2a73f52c --- /dev/null +++ b/src/test/ui/suggestions/imm-ref-trait-object.stderr @@ -0,0 +1,10 @@ +error: the `min` method cannot be invoked on a trait object + --> $DIR/imm-ref-trait-object.rs:2:8 + | +LL | t.min().unwrap() + | ^^^ + | + = note: you need `&mut dyn std::iter::Iterator` instead + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr index fb3e1096ad54c..6af1267f26faf 100644 --- a/src/test/ui/suggestions/into-str.stderr +++ b/src/test/ui/suggestions/into-str.stderr @@ -8,6 +8,7 @@ LL | foo(String::new()); | ^^^ the trait `std::convert::From` is not implemented for `&str` | = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix + = note: `std::convert::From` is implemented for `&mut str` = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String` error: aborting due to previous error diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs new file mode 100644 index 0000000000000..dcef2ada63bea --- /dev/null +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs @@ -0,0 +1,23 @@ +use std::env::args; +use std::fs::File; +use std::io::{stdout, Write, BufWriter}; + +fn main() { + let mut args = args(); + let _ = args.next(); + let dest = args.next(); + + let h1; let h2; let h3; + + let fp: &dyn Write = match dest { + Some(path) => { h1 = File::create(path).unwrap(); &h1 }, + None => { h2 = stdout(); h3 = h2.lock(); &h3 } + }; + + let fp = BufWriter::new(fp); + //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + + writeln!(fp, "hello world").unwrap(); //~ ERROR no method named `write_fmt` found for type +} diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr new file mode 100644 index 0000000000000..66dc5b66744bd --- /dev/null +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -0,0 +1,41 @@ +error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + --> $DIR/mut-borrow-needed-by-trait.rs:17:29 + | +LL | let fp = BufWriter::new(fp); + | ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` + | + = note: `std::io::Write` is implemented for `&mut dyn std::io::Write` + = note: required by `std::io::BufWriter::::new` + +error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + --> $DIR/mut-borrow-needed-by-trait.rs:17:14 + | +LL | let fp = BufWriter::new(fp); + | ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` + | + = note: `std::io::Write` is implemented for `&mut dyn std::io::Write` + = note: required by `std::io::BufWriter` + +error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + --> $DIR/mut-borrow-needed-by-trait.rs:17:14 + | +LL | let fp = BufWriter::new(fp); + | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` + | + = note: `std::io::Write` is implemented for `&mut dyn std::io::Write` + = note: required by `std::io::BufWriter` + +error[E0599]: no method named `write_fmt` found for type `std::io::BufWriter<&dyn std::io::Write>` in the current scope + --> $DIR/mut-borrow-needed-by-trait.rs:22:5 + | +LL | writeln!(fp, "hello world").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>` + | + = note: the method `write_fmt` exists but the following trait bounds were not satisfied: + `std::io::BufWriter<&dyn std::io::Write> : std::io::Write` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/suggest-remove-refs-1.stderr b/src/test/ui/suggestions/suggest-remove-refs-1.stderr index bfc313cabdc44..069b0a4db6c6f 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-1.stderr +++ b/src/test/ui/suggestions/suggest-remove-refs-1.stderr @@ -8,6 +8,7 @@ LL | for (i, n) in &v.iter().enumerate() { | help: consider removing 1 leading `&`-references | = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Enumerate>` + = note: `std::iter::Iterator` is implemented for `&mut std::iter::Enumerate>` = note: required by `std::iter::IntoIterator::into_iter` error: aborting due to previous error From f5e372ae5de9809368db831f1dc7f7d846c3531b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 3 Oct 2019 17:39:58 -0700 Subject: [PATCH 08/18] Tweak wording --- src/librustc/traits/error_reporting.rs | 3 ++- src/librustc_typeck/check/method/suggest.rs | 2 +- src/test/ui/not-panic/not-panic-safe.stderr | 2 +- src/test/ui/parser/lex-bad-char-literals-6.stderr | 4 ++-- src/test/ui/suggestions/imm-ref-trait-object.stderr | 2 +- src/test/ui/suggestions/into-str.stderr | 2 +- src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr | 6 +++--- src/test/ui/suggestions/suggest-remove-refs-1.stderr | 2 +- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index f85ba1459f5f2..ecd27fa99676d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1164,9 +1164,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } else { err.note(&format!( - "`{}` is implemented for `{:?}`", + "`{}` is implemented for `{:?}`, but not for `{:?}`", trait_ref, trait_type, + trait_ref.skip_binder().self_ty(), )); } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 37bc4b63f4bc9..d7648ec03ab40 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -575,7 +575,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Mutability::MutImmutable => self.tcx.mk_mut_ref(region, t_type), }; if needs_mut { - err.note(&format!("you need `{}` instead", trait_type)); + err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty)); } } err.emit(); diff --git a/src/test/ui/not-panic/not-panic-safe.stderr b/src/test/ui/not-panic/not-panic-safe.stderr index 2ae5ba523a70f..2362ccd32de99 100644 --- a/src/test/ui/not-panic/not-panic-safe.stderr +++ b/src/test/ui/not-panic/not-panic-safe.stderr @@ -8,7 +8,7 @@ LL | assert::<&mut i32>(); | ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary | = help: the trait `std::panic::UnwindSafe` is not implemented for `&mut i32` - = note: `std::panic::UnwindSafe` is implemented for `&i32` + = note: `std::panic::UnwindSafe` is implemented for `&i32`, but not for `&mut i32` error: aborting due to previous error diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/parser/lex-bad-char-literals-6.stderr index 4792aacefe5e9..dc6e1e6e972cc 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -35,7 +35,7 @@ LL | if x == y {} | ^^ no implementation for `&str == char` | = help: the trait `std::cmp::PartialEq` is not implemented for `&str` - = note: `std::cmp::PartialEq` is implemented for `&mut str` + = note: `std::cmp::PartialEq` is implemented for `&mut str`, but not for `&str` error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:15:20 @@ -53,7 +53,7 @@ LL | if x == z {} | ^^ no implementation for `&str == char` | = help: the trait `std::cmp::PartialEq` is not implemented for `&str` - = note: `std::cmp::PartialEq` is implemented for `&mut str` + = note: `std::cmp::PartialEq` is implemented for `&mut str`, but not for `&str` error: aborting due to 6 previous errors diff --git a/src/test/ui/suggestions/imm-ref-trait-object.stderr b/src/test/ui/suggestions/imm-ref-trait-object.stderr index e272d2a73f52c..9185eaa65c06d 100644 --- a/src/test/ui/suggestions/imm-ref-trait-object.stderr +++ b/src/test/ui/suggestions/imm-ref-trait-object.stderr @@ -4,7 +4,7 @@ error: the `min` method cannot be invoked on a trait object LL | t.min().unwrap() | ^^^ | - = note: you need `&mut dyn std::iter::Iterator` instead + = note: you need `&mut dyn std::iter::Iterator` instead of `&dyn std::iter::Iterator` error: aborting due to previous error diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr index 6af1267f26faf..a1e1f4d13572a 100644 --- a/src/test/ui/suggestions/into-str.stderr +++ b/src/test/ui/suggestions/into-str.stderr @@ -8,7 +8,7 @@ LL | foo(String::new()); | ^^^ the trait `std::convert::From` is not implemented for `&str` | = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix - = note: `std::convert::From` is implemented for `&mut str` + = note: `std::convert::From` is implemented for `&mut str`, but not for `&str` = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String` error: aborting due to previous error diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index 66dc5b66744bd..daa8e1162d197 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis LL | let fp = BufWriter::new(fp); | ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | - = note: `std::io::Write` is implemented for `&mut dyn std::io::Write` + = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` = note: required by `std::io::BufWriter::::new` error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied @@ -13,7 +13,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | - = note: `std::io::Write` is implemented for `&mut dyn std::io::Write` + = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` = note: required by `std::io::BufWriter` error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied @@ -22,7 +22,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | - = note: `std::io::Write` is implemented for `&mut dyn std::io::Write` + = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` = note: required by `std::io::BufWriter` error[E0599]: no method named `write_fmt` found for type `std::io::BufWriter<&dyn std::io::Write>` in the current scope diff --git a/src/test/ui/suggestions/suggest-remove-refs-1.stderr b/src/test/ui/suggestions/suggest-remove-refs-1.stderr index 069b0a4db6c6f..04d17a16cc356 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-1.stderr +++ b/src/test/ui/suggestions/suggest-remove-refs-1.stderr @@ -8,7 +8,7 @@ LL | for (i, n) in &v.iter().enumerate() { | help: consider removing 1 leading `&`-references | = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Enumerate>` - = note: `std::iter::Iterator` is implemented for `&mut std::iter::Enumerate>` + = note: `std::iter::Iterator` is implemented for `&mut std::iter::Enumerate>`, but not for `&std::iter::Enumerate>` = note: required by `std::iter::IntoIterator::into_iter` error: aborting due to previous error From 4414068cc49803b0dacba133b7788b8b95b0b473 Mon Sep 17 00:00:00 2001 From: AnthonyMikh Date: Sat, 5 Oct 2019 03:08:05 +0300 Subject: [PATCH 09/18] Correctly estimate required space for string `.len()` returns length in bytes so it overestimates the required space --- src/librustc_errors/styled_buffer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_errors/styled_buffer.rs b/src/librustc_errors/styled_buffer.rs index 6e03618d2b0b5..b12ab9e457602 100644 --- a/src/librustc_errors/styled_buffer.rs +++ b/src/librustc_errors/styled_buffer.rs @@ -111,7 +111,7 @@ impl StyledBuffer { pub fn prepend(&mut self, line: usize, string: &str, style: Style) { self.ensure_lines(line); - let string_len = string.len(); + let string_len = string.chars().count(); // Push the old content over to make room for new content for _ in 0..string_len { From 35a3b58a0836af059971c13b76f32c6b6c3926cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 5 Oct 2019 10:41:24 -0700 Subject: [PATCH 10/18] Obligation must apply modulo regions --- src/librustc/traits/error_reporting.rs | 4 +++- src/librustc/traits/query/evaluate_obligation.rs | 2 +- src/test/ui/parser/lex-bad-char-literals-6.stderr | 2 -- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ecd27fa99676d..1e8f699b520f9 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1149,7 +1149,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { new_trait_ref.to_predicate(), ); - if self.predicate_may_hold(&new_obligation) { + if self.evaluate_obligation_no_overflow( + &new_obligation, + ).must_apply_modulo_regions() { let sp = self.tcx.sess.source_map() .span_take_while(span, |c| c.is_whitespace() || *c == '&'); if points_at_arg && diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs index 17684df7e9b8e..0d426cab9b751 100644 --- a/src/librustc/traits/query/evaluate_obligation.rs +++ b/src/librustc/traits/query/evaluate_obligation.rs @@ -56,7 +56,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // Helper function that canonicalizes and runs the query. If an // overflow results, we re-run it in the local context so we can // report a nice error. - fn evaluate_obligation_no_overflow( + crate fn evaluate_obligation_no_overflow( &self, obligation: &PredicateObligation<'tcx>, ) -> EvaluationResult { diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/parser/lex-bad-char-literals-6.stderr index dc6e1e6e972cc..a7bbe05e94b7b 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -35,7 +35,6 @@ LL | if x == y {} | ^^ no implementation for `&str == char` | = help: the trait `std::cmp::PartialEq` is not implemented for `&str` - = note: `std::cmp::PartialEq` is implemented for `&mut str`, but not for `&str` error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:15:20 @@ -53,7 +52,6 @@ LL | if x == z {} | ^^ no implementation for `&str == char` | = help: the trait `std::cmp::PartialEq` is not implemented for `&str` - = note: `std::cmp::PartialEq` is implemented for `&mut str`, but not for `&str` error: aborting due to 6 previous errors From 169b040a25543274b7cc5fc2d2f15159ef325f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 5 Oct 2019 11:37:21 -0700 Subject: [PATCH 11/18] review comments --- src/librustc/hir/mod.rs | 7 +++++ src/librustc_typeck/check/method/mod.rs | 8 +++--- src/librustc_typeck/check/method/suggest.rs | 30 +++++++++++---------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 9ae661f0952a4..6b9949e8432e1 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1053,6 +1053,13 @@ impl Mutability { MutImmutable => MutImmutable, } } + + pub fn not(self) -> Self { + match self { + MutMutable => MutImmutable, + MutImmutable => MutMutable, + } + } } #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Hash, HashStable)] diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 4522be21cab50..5851a074fa3f1 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -215,10 +215,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut needs_mut = false; if let ty::Ref(region, t_type, mutability) = self_ty.kind { - let trait_type = match mutability { - hir::Mutability::MutMutable => self.tcx.mk_imm_ref(region, t_type), - hir::Mutability::MutImmutable => self.tcx.mk_mut_ref(region, t_type), - }; + let trait_type = self.tcx.mk_ref(region, ty::TypeAndMut { + ty: t_type, + mutbl: mutability.not(), + }); match self.lookup_probe( span, segment.ident, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index d7648ec03ab40..8d08d829283f6 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -557,24 +557,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = format!("the `{}` method cannot be invoked on a trait object", item_name); let mut err = self.sess().struct_span_err(span, &msg); if !candidates.is_empty() { - let help = format!("{an}other candidate{s} {were} found in the following \ - trait{s}, perhaps add a `use` for {one_of_them}:", - an = if candidates.len() == 1 {"an" } else { "" }, - s = pluralise!(candidates.len()), - were = if candidates.len() == 1 { "was" } else { "were" }, - one_of_them = if candidates.len() == 1 { - "it" - } else { - "one_of_them" - }); + let help = format!( + "{an}other candidate{s} {were} found in the following trait{s}, perhaps \ + add a `use` for {one_of_them}:", + an = if candidates.len() == 1 {"an" } else { "" }, + s = pluralise!(candidates.len()), + were = if candidates.len() == 1 { "was" } else { "were" }, + one_of_them = if candidates.len() == 1 { + "it" + } else { + "one_of_them" + }, + ); self.suggest_use_candidates(&mut err, help, candidates); } if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind { - let trait_type = match mutability { - hir::Mutability::MutMutable => self.tcx.mk_imm_ref(region, t_type), - hir::Mutability::MutImmutable => self.tcx.mk_mut_ref(region, t_type), - }; if needs_mut { + let trait_type = self.tcx.mk_ref(region, ty::TypeAndMut { + ty: t_type, + mutbl: mutability.not(), + }); err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty)); } } From 0b0aeaca43bc457db2be70114fa7c6ab7925fd78 Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Sun, 6 Oct 2019 12:03:53 +0800 Subject: [PATCH 12/18] Suggest dereferencing boolean reference when used in 'if' or 'while' Change-Id: I0c5c4d767be2647e6f017ae7bf83558c56dbca97 --- src/librustc_typeck/check/demand.rs | 6 +++++- src/librustc_typeck/check/expr.rs | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 2ea0afb179356..78bd4508e21a4 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -349,7 +349,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the span is from a macro, then it's hard to extract the text // and make a good suggestion, so don't bother. - let is_macro = sp.from_expansion(); + let is_desugaring = match sp.desugaring_kind() { + Some(k) => sp.is_desugaring(k), + None => false + }; + let is_macro = sp.from_expansion() && !is_desugaring; match (&expr.kind, &expected.kind, &checked_ty.kind) { (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) { diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 7a6fe9560fbff..aa26c74967a1e 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -87,6 +87,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { + self.suggest_ref_or_into(&mut err, expr, expected_ty, ty); + let expr = match &expr.kind { ExprKind::DropTemps(expr) => expr, _ => expr, From 8a164acf5879aec3389180f7102ea32dce5eb07a Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Sun, 6 Oct 2019 12:03:53 +0800 Subject: [PATCH 13/18] Suggest dereferencing boolean reference when used in 'if' or 'while' Change-Id: I0c5c4d767be2647e6f017ae7bf83558c56dbca97 --- src/test/ui/if/if-no-match-bindings.stderr | 44 +++++++++++++---- .../disallowed-positions.stderr | 48 ++++++++++++++++++- 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/src/test/ui/if/if-no-match-bindings.stderr b/src/test/ui/if/if-no-match-bindings.stderr index cbf52476ae37f..694b59897c5a9 100644 --- a/src/test/ui/if/if-no-match-bindings.stderr +++ b/src/test/ui/if/if-no-match-bindings.stderr @@ -2,7 +2,10 @@ error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:18:8 | LL | if b_ref() {} - | ^^^^^^^ expected bool, found &bool + | ^^^^^^^ + | | + | expected bool, found &bool + | help: consider dereferencing the borrow: `*b_ref()` | = note: expected type `bool` found type `&bool` @@ -11,7 +14,10 @@ error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:19:8 | LL | if b_mut_ref() {} - | ^^^^^^^^^^^ expected bool, found &mut bool + | ^^^^^^^^^^^ + | | + | expected bool, found &mut bool + | help: consider dereferencing the borrow: `*b_mut_ref()` | = note: expected type `bool` found type `&mut bool` @@ -20,7 +26,10 @@ error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:20:8 | LL | if &true {} - | ^^^^^ expected bool, found &bool + | ^^^^^ + | | + | expected bool, found &bool + | help: consider dereferencing the borrow: `*&true` | = note: expected type `bool` found type `&bool` @@ -29,7 +38,10 @@ error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:21:8 | LL | if &mut true {} - | ^^^^^^^^^ expected bool, found &mut bool + | ^^^^^^^^^ + | | + | expected bool, found &mut bool + | help: consider dereferencing the borrow: `*&mut true` | = note: expected type `bool` found type `&mut bool` @@ -38,7 +50,10 @@ error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:24:11 | LL | while b_ref() {} - | ^^^^^^^ expected bool, found &bool + | ^^^^^^^ + | | + | expected bool, found &bool + | help: consider dereferencing the borrow: `*b_ref()` | = note: expected type `bool` found type `&bool` @@ -47,7 +62,10 @@ error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:25:11 | LL | while b_mut_ref() {} - | ^^^^^^^^^^^ expected bool, found &mut bool + | ^^^^^^^^^^^ + | | + | expected bool, found &mut bool + | help: consider dereferencing the borrow: `*b_mut_ref()` | = note: expected type `bool` found type `&mut bool` @@ -55,8 +73,11 @@ LL | while b_mut_ref() {} error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:26:11 | -LL | while &true {} - | ^^^^^ expected bool, found &bool +26 | while &true {} + | ^^^^^ + | | + | expected bool, found &bool + | help: consider dereferencing the borrow: `*&true` | = note: expected type `bool` found type `&bool` @@ -64,8 +85,11 @@ LL | while &true {} error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:27:11 | -LL | while &mut true {} - | ^^^^^^^^^ expected bool, found &mut bool +27 | while &mut true {} + | ^^^^^^^^^ + | | + | expected bool, found &mut bool + | help: consider dereferencing the borrow: `*&mut true` | = note: expected type `bool` found type `&mut bool` diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 4edc00efc7e72..ab1b405e5c21f 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -513,11 +513,52 @@ warning: the feature `let_chains` is incomplete and may cause the compiler to cr LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. | ^^^^^^^^^^ +warning: unnecessary parentheses around `if` condition + --> $DIR/disallowed-positions.rs:51:8 + | +LL | if (true || let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^^^ help: remove these parentheses + | + = note: `#[warn(unused_parens)]` on by default + +warning: unnecessary parentheses around `while` condition + --> $DIR/disallowed-positions.rs:115:11 + | +LL | while (true || let 0 = 0) {} + | ^^^^^^^^^^^^^^^^^^^ help: remove these parentheses + +wrning: unnecessary parentheses around `let` head expression + --> $DIR/disallowed-positions.rs:160:41 + | +LL | if let Range { start: _, end: _ } = (true..true || false) { } + | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses + +warning: unnecessary parentheses around `let` head expression + --> $DIR/disallowed-positions.rs:162:41 + | +LL | if let Range { start: _, end: _ } = (true..true && false) { } + | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses + +warning: unnecessary parentheses around `let` head expression + --> $DIR/disallowed-positions.rs:164:44 + | +LL | while let Range { start: _, end: _ } = (true..true || false) { } + | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses + +warning: unnecessary parentheses around `let` head expression + --> $DIR/disallowed-positions.rs:166:44 + | +LL | while let Range { start: _, end: _ } = (true..true && false) { } + | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses + error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:32:8 | LL | if &let 0 = 0 {} - | ^^^^^^^^^^ expected bool, found &bool + | ^^^^^^^^^^ + | | + | expected bool, found &bool + | help: consider dereferencing the borrow: `*&let 0 = 0` | = note: expected type `bool` found type `&bool` @@ -702,7 +743,10 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:96:11 | LL | while &let 0 = 0 {} - | ^^^^^^^^^^ expected bool, found &bool + | ^^^^^^^^^^ + | | + | expected bool, found &bool + | help: consider dereferencing the borrow: `*&let 0 = 0` | = note: expected type `bool` found type `&bool` From bbb69d14552b7258ba0b1d56d6558bd32b647b9a Mon Sep 17 00:00:00 2001 From: wangxiangqing Date: Sun, 6 Oct 2019 12:03:53 +0800 Subject: [PATCH 14/18] Suggest dereferencing boolean reference when used in 'if' or 'while' Change-Id: I0c5c4d767be2647e6f017ae7bf83558c56dbca97 --- src/test/ui/if/if-no-match-bindings.stderr | 4 +- .../disallowed-positions.stderr | 38 ------------------- 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/src/test/ui/if/if-no-match-bindings.stderr b/src/test/ui/if/if-no-match-bindings.stderr index 694b59897c5a9..53b7aafc430a2 100644 --- a/src/test/ui/if/if-no-match-bindings.stderr +++ b/src/test/ui/if/if-no-match-bindings.stderr @@ -73,7 +73,7 @@ LL | while b_mut_ref() {} error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:26:11 | -26 | while &true {} +LL | while &true {} | ^^^^^ | | | expected bool, found &bool @@ -85,7 +85,7 @@ error[E0308]: mismatched types error[E0308]: mismatched types --> $DIR/if-no-match-bindings.rs:27:11 | -27 | while &mut true {} +LL | while &mut true {} | ^^^^^^^^^ | | | expected bool, found &mut bool diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index ab1b405e5c21f..619f9c85b24db 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -513,44 +513,6 @@ warning: the feature `let_chains` is incomplete and may cause the compiler to cr LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test. | ^^^^^^^^^^ -warning: unnecessary parentheses around `if` condition - --> $DIR/disallowed-positions.rs:51:8 - | -LL | if (true || let 0 = 0) {} - | ^^^^^^^^^^^^^^^^^^^ help: remove these parentheses - | - = note: `#[warn(unused_parens)]` on by default - -warning: unnecessary parentheses around `while` condition - --> $DIR/disallowed-positions.rs:115:11 - | -LL | while (true || let 0 = 0) {} - | ^^^^^^^^^^^^^^^^^^^ help: remove these parentheses - -wrning: unnecessary parentheses around `let` head expression - --> $DIR/disallowed-positions.rs:160:41 - | -LL | if let Range { start: _, end: _ } = (true..true || false) { } - | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses - -warning: unnecessary parentheses around `let` head expression - --> $DIR/disallowed-positions.rs:162:41 - | -LL | if let Range { start: _, end: _ } = (true..true && false) { } - | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses - -warning: unnecessary parentheses around `let` head expression - --> $DIR/disallowed-positions.rs:164:44 - | -LL | while let Range { start: _, end: _ } = (true..true || false) { } - | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses - -warning: unnecessary parentheses around `let` head expression - --> $DIR/disallowed-positions.rs:166:44 - | -LL | while let Range { start: _, end: _ } = (true..true && false) { } - | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses - error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:32:8 | From c5e0d6e4d43f228687c75ab7406f64b318752d7b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 6 Oct 2019 15:23:33 +0200 Subject: [PATCH 15/18] Add long error explanation for E0566 --- src/librustc/error_codes.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 66c51000066b2..9a5e1ea6f3338 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -1700,6 +1700,30 @@ To understand better how closures work in Rust, read: https://doc.rust-lang.org/book/ch13-01-closures.html "##, +E0566: r##" +Conflicting representation hints have been used on a same item. + +Erroneous code example: + +```compile_fail,E0566 +# #![deny(warnings)] +# fn main() { +#[repr(u32, u64)] // error! +enum Repr { A } +# } +``` + +In most cases (if not all), using just one representation hint is more than +enough. If you want to have a representation hint depending on the current +architecture, use `cfg_attr`. Example: + +``` +#[cfg_attr(linux, repr(u32))] +#[cfg_attr(not(linux), repr(u64))] +enum Repr { A } +``` +"##, + E0580: r##" The `main` function was incorrectly declared. @@ -2097,7 +2121,6 @@ rejected in your own crates. E0490, // a value of type `..` is borrowed for too long E0495, // cannot infer an appropriate lifetime due to conflicting // requirements - E0566, // conflicting representation hints E0623, // lifetime mismatch where both parameters are anonymous regions E0628, // generators cannot have explicit parameters E0631, // type mismatch in closure arguments From 57cb8819ee78f2debf24d2e123c78796204db8c9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 6 Oct 2019 17:02:01 +0200 Subject: [PATCH 16/18] Update ui tests --- src/librustc/error_codes.rs | 7 ++----- src/test/ui/conflicting-repr-hints.stderr | 1 + src/test/ui/feature-gates/feature-gate-repr-simd.stderr | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index 9a5e1ea6f3338..502172db91c9b 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -1705,12 +1705,9 @@ Conflicting representation hints have been used on a same item. Erroneous code example: -```compile_fail,E0566 -# #![deny(warnings)] -# fn main() { -#[repr(u32, u64)] // error! +``` +#[repr(u32, u64)] // warning! enum Repr { A } -# } ``` In most cases (if not all), using just one representation hint is more than diff --git a/src/test/ui/conflicting-repr-hints.stderr b/src/test/ui/conflicting-repr-hints.stderr index 6b15b7ebbe9ee..832f5c3ac2bb7 100644 --- a/src/test/ui/conflicting-repr-hints.stderr +++ b/src/test/ui/conflicting-repr-hints.stderr @@ -66,3 +66,4 @@ LL | | } error: aborting due to 8 previous errors +For more information about this error, try `rustc --explain E0566`. diff --git a/src/test/ui/feature-gates/feature-gate-repr-simd.stderr b/src/test/ui/feature-gates/feature-gate-repr-simd.stderr index dfaa85bc5f014..02c8400e03e82 100644 --- a/src/test/ui/feature-gates/feature-gate-repr-simd.stderr +++ b/src/test/ui/feature-gates/feature-gate-repr-simd.stderr @@ -26,4 +26,5 @@ LL | #[repr(simd)] error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0566, E0658. +For more information about an error, try `rustc --explain E0566`. From 8baf7bf33d060ca6661c03a47d30ecfc2210743a Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Sun, 6 Oct 2019 14:40:08 -0700 Subject: [PATCH 17/18] Update reference - 771c5d10cf944bf7d221f5d6cb7abd2a06c400e4 Add macros in extern blocks and new proc-macro support. - 8caabd62ef5fbe99e6be6aa9e76f55bbb8433d95 Update for "modern" `meta` matcher. - 1b44947d36ccf7eba2b3bd245769eff68abf6d4d Update await desugaring after rust-lang/rust#64292 --- src/doc/reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/reference b/src/doc/reference index 320d232b206ed..5b9d2fcefadfc 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 320d232b206edecb67489316f71a14e31dbc6c08 +Subproject commit 5b9d2fcefadfc32fceafacfc0dd9441d9b57dd94 From 6efcb022bc047cb4aeab59fe400cf341f471ba0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 6 Oct 2019 18:38:15 -0700 Subject: [PATCH 18/18] review comments --- src/librustc/hir/mod.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/suggest.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 6b9949e8432e1..e631ac2ff12d3 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1054,7 +1054,7 @@ impl Mutability { } } - pub fn not(self) -> Self { + pub fn invert(self) -> Self { match self { MutMutable => MutImmutable, MutImmutable => MutMutable, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 5851a074fa3f1..434ead50e0423 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -217,7 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Ref(region, t_type, mutability) = self_ty.kind { let trait_type = self.tcx.mk_ref(region, ty::TypeAndMut { ty: t_type, - mutbl: mutability.not(), + mutbl: mutability.invert(), }); match self.lookup_probe( span, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 8d08d829283f6..90e1c70ece8fd 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -575,7 +575,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if needs_mut { let trait_type = self.tcx.mk_ref(region, ty::TypeAndMut { ty: t_type, - mutbl: mutability.not(), + mutbl: mutability.invert(), }); err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty)); }