diff --git a/src/librustc_error_codes/error_codes/E0515.md b/src/librustc_error_codes/error_codes/E0515.md index 9580b6f92acd1..0f4fbf672239c 100644 --- a/src/librustc_error_codes/error_codes/E0515.md +++ b/src/librustc_error_codes/error_codes/E0515.md @@ -1,7 +1,4 @@ -Cannot return value that references local variable - -Local variables, function parameters and temporaries are all dropped before the -end of the function body. So a reference to them cannot be returned. +A reference to a local variable was returned. Erroneous code example: @@ -20,6 +17,9 @@ fn get_dangling_iterator<'a>() -> Iter<'a, i32> { } ``` +Local variables, function parameters and temporaries are all dropped before the +end of the function body. So a reference to them cannot be returned. + Consider returning an owned value instead: ``` diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 758a0b39d43ee..2210c663d1469 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -1,6 +1,6 @@ -//! Trait Resolution. See the [rustc guide] for more information on how this works. +//! Trait Resolution. See the [rustc-dev-guide] for more information on how this works. //! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html +//! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html mod engine; pub mod error_reporting; diff --git a/src/librustc_middle/mir/visit.rs b/src/librustc_middle/mir/visit.rs index 400d15cdc144b..5c33db299ae85 100644 --- a/src/librustc_middle/mir/visit.rs +++ b/src/librustc_middle/mir/visit.rs @@ -838,7 +838,7 @@ macro_rules! make_mir_visitor { } macro_rules! visit_place_fns { - (mut) => ( + (mut) => { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; fn super_place( @@ -849,7 +849,7 @@ macro_rules! visit_place_fns { ) { self.visit_place_base(&mut place.local, context, location); - if let Some(new_projection) = self.process_projection(&place.projection) { + if let Some(new_projection) = self.process_projection(&place.projection, location) { place.projection = self.tcx().intern_place_elems(&new_projection); } } @@ -857,12 +857,13 @@ macro_rules! visit_place_fns { fn process_projection( &mut self, projection: &'a [PlaceElem<'tcx>], + location: Location, ) -> Option>> { let mut projection = Cow::Borrowed(projection); for i in 0..projection.len() { if let Some(elem) = projection.get(i) { - if let Some(elem) = self.process_projection_elem(elem) { + if let Some(elem) = self.process_projection_elem(elem, location) { // This converts the borrowed projection into `Cow::Owned(_)` and returns a // clone of the projection so we can mutate and reintern later. let vec = projection.to_mut(); @@ -879,13 +880,30 @@ macro_rules! visit_place_fns { fn process_projection_elem( &mut self, - _elem: &PlaceElem<'tcx>, + elem: &PlaceElem<'tcx>, + location: Location, ) -> Option> { - None + match elem { + PlaceElem::Index(local) => { + let mut new_local = *local; + self.visit_local( + &mut new_local, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), + location, + ); + + if new_local == *local { None } else { Some(PlaceElem::Index(new_local)) } + } + PlaceElem::Deref + | PlaceElem::Field(..) + | PlaceElem::ConstantIndex { .. } + | PlaceElem::Subslice { .. } + | PlaceElem::Downcast(..) => None, + } } - ); + }; - () => ( + () => { fn visit_projection( &mut self, local: Local, @@ -907,12 +925,7 @@ macro_rules! visit_place_fns { self.super_projection_elem(local, proj_base, elem, context, location); } - fn super_place( - &mut self, - place: &Place<'tcx>, - context: PlaceContext, - location: Location, - ) { + fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { let mut context = context; if !place.projection.is_empty() { @@ -925,10 +938,7 @@ macro_rules! visit_place_fns { self.visit_place_base(&place.local, context, location); - self.visit_projection(place.local, - &place.projection, - context, - location); + self.visit_projection(place.local, &place.projection, context, location); } fn super_projection( @@ -961,19 +971,16 @@ macro_rules! visit_place_fns { self.visit_local( local, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), - location + location, ); } - ProjectionElem::Deref | - ProjectionElem::Subslice { from: _, to: _, from_end: _ } | - ProjectionElem::ConstantIndex { offset: _, - min_length: _, - from_end: _ } | - ProjectionElem::Downcast(_, _) => { - } + ProjectionElem::Deref + | ProjectionElem::Subslice { from: _, to: _, from_end: _ } + | ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } + | ProjectionElem::Downcast(_, _) => {} } } - ); + }; } make_mir_visitor!(Visitor,); diff --git a/src/librustc_mir/borrow_check/renumber.rs b/src/librustc_mir/borrow_check/renumber.rs index a1d7bc1462f95..a6b4aa7497722 100644 --- a/src/librustc_mir/borrow_check/renumber.rs +++ b/src/librustc_mir/borrow_check/renumber.rs @@ -64,7 +64,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { debug!("visit_ty: ty={:?}", ty); } - fn process_projection_elem(&mut self, elem: &PlaceElem<'tcx>) -> Option> { + fn process_projection_elem( + &mut self, + elem: &PlaceElem<'tcx>, + _: Location, + ) -> Option> { if let PlaceElem::Field(field, ty) = elem { let new_ty = self.renumber_regions(ty); diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 033ba17f65855..4492895104526 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -89,13 +89,6 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> { *local = self.to; } } - - fn process_projection_elem(&mut self, elem: &PlaceElem<'tcx>) -> Option> { - match elem { - PlaceElem::Index(local) if *local == self.from => Some(PlaceElem::Index(self.to)), - _ => None, - } - } } struct DerefArgVisitor<'tcx> { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 157dada831a2e..8121d4ead1394 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -706,18 +706,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { self.super_place(place, context, location) } - fn process_projection_elem(&mut self, elem: &PlaceElem<'tcx>) -> Option> { - if let PlaceElem::Index(local) = elem { - let new_local = self.make_integrate_local(*local); - - if new_local != *local { - return Some(PlaceElem::Index(new_local)); - } - } - - None - } - fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { self.in_cleanup_block = data.is_cleanup; self.super_basic_block_data(block, data); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index ec0b89ebb4d0a..9579fe1f405ba 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -1036,15 +1036,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { *local = self.promote_temp(*local); } } - - fn process_projection_elem(&mut self, elem: &PlaceElem<'tcx>) -> Option> { - match elem { - PlaceElem::Index(local) if self.is_temp_kind(*local) => { - Some(PlaceElem::Index(self.promote_temp(*local))) - } - _ => None, - } - } } pub fn promote_candidates<'tcx>( diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index c2029a223b941..c0da2c446d65f 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -417,11 +417,4 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } - - fn process_projection_elem(&mut self, elem: &PlaceElem<'tcx>) -> Option> { - match elem { - PlaceElem::Index(local) => Some(PlaceElem::Index(self.map[*local].unwrap())), - _ => None, - } - } } diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index 6b5f6aa991c1e..0ac743359be96 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -2,9 +2,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; -use rustc_middle::mir::{ - Body, BodyAndCache, Local, Location, PlaceElem, ReadOnlyBodyAndCache, VarDebugInfo, -}; +use rustc_middle::mir::{Body, BodyAndCache, Local, Location, ReadOnlyBodyAndCache, VarDebugInfo}; use rustc_middle::ty::TyCtxt; use std::mem; @@ -157,13 +155,4 @@ impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> { *local = self.new_local; } } - - fn process_projection_elem(&mut self, elem: &PlaceElem<'tcx>) -> Option> { - match elem { - PlaceElem::Index(local) if *local == self.query => { - Some(PlaceElem::Index(self.new_local)) - } - _ => None, - } - } } diff --git a/src/librustc_trait_selection/lib.rs b/src/librustc_trait_selection/lib.rs index 21315cc89ca5c..4796b431d8dca 100644 --- a/src/librustc_trait_selection/lib.rs +++ b/src/librustc_trait_selection/lib.rs @@ -2,9 +2,9 @@ //! //! - **Traits.** Trait resolution is implemented in the `traits` module. //! -//! For more information about how rustc works, see the [rustc guide]. +//! For more information about how rustc works, see the [rustc-dev-guide]. //! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/ +//! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/ //! //! # Note //! @@ -16,6 +16,8 @@ #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(or_patterns)] +#![feature(str_strip)] +#![feature(option_zip)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f2640cec7106b..fef7adf02246b 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -388,7 +388,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // which is somewhat confusing. self.suggest_restricting_param_bound( &mut err, - &trait_ref, + trait_ref, obligation.cause.body_id, ); } else { diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 3edc066d49a60..14029f2915141 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::TypeckTables; use rustc_middle::ty::{ self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use std::fmt; @@ -27,7 +27,7 @@ pub trait InferCtxtExt<'tcx> { fn suggest_restricting_param_bound( &self, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::PolyTraitRef<'_>, + trait_ref: ty::PolyTraitRef<'_>, body_id: hir::HirId, ); @@ -148,11 +148,128 @@ pub trait InferCtxtExt<'tcx> { fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>); } +fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { + ( + generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), + format!( + "{} {} ", + if !generics.where_clause.predicates.is_empty() { "," } else { " where" }, + pred, + ), + ) +} + +/// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but +/// it can also be an `impl Trait` param that needs to be decomposed to a type +/// param for cleaner code. +fn suggest_restriction( + generics: &hir::Generics<'_>, + msg: &str, + err: &mut DiagnosticBuilder<'_>, + fn_sig: Option<&hir::FnSig<'_>>, + projection: Option<&ty::ProjectionTy<'_>>, + trait_ref: ty::PolyTraitRef<'_>, +) { + let span = generics.where_clause.span_for_predicates_or_empty_place(); + if span.from_expansion() || span.desugaring_kind().is_some() { + return; + } + // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... + if let Some((bound_str, fn_sig)) = + fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind { + // Shenanigans to get the `Trait` from the `impl Trait`. + ty::Param(param) => { + // `fn foo(t: impl Trait)` + // ^^^^^ get this string + param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig)) + } + _ => None, + }) + { + // We know we have an `impl Trait` that doesn't satisfy a required projection. + + // Find all of the ocurrences of `impl Trait` for `Trait` in the function arguments' + // types. There should be at least one, but there might be *more* than one. In that + // case we could just ignore it and try to identify which one needs the restriction, + // but instead we choose to suggest replacing all instances of `impl Trait` with `T` + // where `T: Trait`. + let mut ty_spans = vec![]; + let impl_trait_str = format!("impl {}", bound_str); + for input in fn_sig.decl.inputs { + if let hir::TyKind::Path(hir::QPath::Resolved( + None, + hir::Path { segments: [segment], .. }, + )) = input.kind + { + if segment.ident.as_str() == impl_trait_str.as_str() { + // `fn foo(t: impl Trait)` + // ^^^^^^^^^^ get this to suggest `T` instead + + // There might be more than one `impl Trait`. + ty_spans.push(input.span); + } + } + } + + let type_param_name = generics.params.next_type_param_name(Some(&bound_str)); + // The type param `T: Trait` we will suggest to introduce. + let type_param = format!("{}: {}", type_param_name, bound_str); + + // FIXME: modify the `trait_ref` instead of string shenanigans. + // Turn `::Bar: Qux` into `::Bar: Qux`. + let pred = trait_ref.without_const().to_predicate().to_string(); + let pred = pred.replace(&impl_trait_str, &type_param_name); + let mut sugg = vec![ + match generics + .params + .iter() + .filter(|p| match p.kind { + hir::GenericParamKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), + .. + } => false, + _ => true, + }) + .last() + { + // `fn foo(t: impl Trait)` + // ^ suggest `` here + None => (generics.span, format!("<{}>", type_param)), + // `fn foo(t: impl Trait)` + // ^^^ suggest `` here + Some(param) => ( + param.bounds_span().unwrap_or(param.span).shrink_to_hi(), + format!(", {}", type_param), + ), + }, + // `fn foo(t: impl Trait)` + // ^ suggest `where ::A: Bound` + predicate_constraint(generics, pred), + ]; + sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string()))); + + // Suggest `fn foo(t: T) where ::A: Bound`. + // FIXME: once `#![feature(associated_type_bounds)]` is stabilized, we should suggest + // `fn foo(t: impl Trait)` instead. + err.multipart_suggestion( + "introduce a type parameter with a trait bound instead of using `impl Trait`", + sugg, + Applicability::MaybeIncorrect, + ); + } else { + // Trivial case: `T` needs an extra bound: `T: Bound`. + let (sp, sugg) = + predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string()); + let appl = Applicability::MachineApplicable; + err.span_suggestion(sp, &format!("consider further restricting {}", msg), sugg, appl); + } +} + impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_restricting_param_bound( &self, mut err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::PolyTraitRef<'_>, + trait_ref: ty::PolyTraitRef<'_>, body_id: hir::HirId, ) { let self_ty = trait_ref.self_ty(); @@ -162,27 +279,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => return, }; - let suggest_restriction = - |generics: &hir::Generics<'_>, msg, err: &mut DiagnosticBuilder<'_>| { - let span = generics.where_clause.span_for_predicates_or_empty_place(); - if !span.from_expansion() && span.desugaring_kind().is_none() { - err.span_suggestion( - generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), - &format!("consider further restricting {}", msg), - format!( - "{} {} ", - if !generics.where_clause.predicates.is_empty() { - "," - } else { - " where" - }, - trait_ref.without_const().to_predicate(), - ), - Applicability::MachineApplicable, - ); - } - }; - // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we // don't suggest `T: Sized + ?Sized`. let mut hir_id = body_id; @@ -194,27 +290,47 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .. }) if param_ty && self_ty == self.tcx.types.self_param => { // Restricting `Self` for a single method. - suggest_restriction(&generics, "`Self`", err); + suggest_restriction(&generics, "`Self`", err, None, projection, trait_ref); return; } hir::Node::TraitItem(hir::TraitItem { generics, - kind: hir::TraitItemKind::Fn(..), + kind: hir::TraitItemKind::Fn(fn_sig, ..), .. }) | hir::Node::ImplItem(hir::ImplItem { generics, - kind: hir::ImplItemKind::Fn(..), + kind: hir::ImplItemKind::Fn(fn_sig, ..), .. }) - | hir::Node::Item( - hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. } - | hir::Item { kind: hir::ItemKind::Trait(_, _, generics, _, _), .. } + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(fn_sig, generics, _), .. + }) if projection.is_some() => { + // Missing restriction on associated type of type parameter (unmet projection). + suggest_restriction( + &generics, + "the associated type", + err, + Some(fn_sig), + projection, + trait_ref, + ); + return; + } + hir::Node::Item( + hir::Item { kind: hir::ItemKind::Trait(_, _, generics, _, _), .. } | hir::Item { kind: hir::ItemKind::Impl { generics, .. }, .. }, ) if projection.is_some() => { - // Missing associated type bound. - suggest_restriction(&generics, "the associated type", err); + // Missing restriction on associated type of type parameter (unmet projection). + suggest_restriction( + &generics, + "the associated type", + err, + None, + projection, + trait_ref, + ); return; } @@ -1588,3 +1704,29 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> { hir::intravisit::walk_body(self, body); } } + +pub trait NextTypeParamName { + fn next_type_param_name(&self, name: Option<&str>) -> String; +} + +impl NextTypeParamName for &[hir::GenericParam<'_>] { + fn next_type_param_name(&self, name: Option<&str>) -> String { + // This is the whitelist of possible parameter names that we might suggest. + let name = name.and_then(|n| n.chars().next()).map(|c| c.to_string().to_uppercase()); + let name = name.as_ref().map(|s| s.as_str()); + let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"]; + let used_names = self + .iter() + .filter_map(|p| match p.name { + hir::ParamName::Plain(ident) => Some(ident.name), + _ => None, + }) + .collect::>(); + + possible_names + .iter() + .find(|n| !used_names.contains(&Symbol::intern(n))) + .unwrap_or(&"ParamName") + .to_string() + } +} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 23bee8e7aad41..8ae779a4783bb 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -45,6 +45,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; +use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; mod type_of; @@ -135,20 +136,7 @@ crate fn placeholder_type_error( if placeholder_types.is_empty() { return; } - // This is the whitelist of possible parameter names that we might suggest. - let possible_names = ["T", "K", "L", "A", "B", "C"]; - let used_names = generics - .iter() - .filter_map(|p| match p.name { - hir::ParamName::Plain(ident) => Some(ident.name), - _ => None, - }) - .collect::>(); - - let type_name = possible_names - .iter() - .find(|n| !used_names.contains(&Symbol::intern(n))) - .unwrap_or(&"ParamName"); + let type_name = generics.next_type_param_name(None); let mut sugg: Vec<_> = placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect(); diff --git a/src/test/run-make-fulldeps/windows-binary-no-external-deps/Makefile b/src/test/run-make-fulldeps/windows-binary-no-external-deps/Makefile new file mode 100644 index 0000000000000..f6adb6d76279d --- /dev/null +++ b/src/test/run-make-fulldeps/windows-binary-no-external-deps/Makefile @@ -0,0 +1,9 @@ +-include ../tools.mk + +# only-windows + +PATH=$(SYSTEMROOT)/system32 + +all: + $(RUSTC) hello.rs + $(TMPDIR)/hello.exe diff --git a/src/test/run-make-fulldeps/windows-binary-no-external-deps/hello.rs b/src/test/run-make-fulldeps/windows-binary-no-external-deps/hello.rs new file mode 100644 index 0000000000000..47ad8c634112b --- /dev/null +++ b/src/test/run-make-fulldeps/windows-binary-no-external-deps/hello.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello World!"); +} diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs new file mode 100644 index 0000000000000..6e9e8821cfea7 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs @@ -0,0 +1,44 @@ +// The double space in `impl Iterator` is load bearing! We want to make sure we don't regress by +// accident if the internal string representation changes. +#[rustfmt::skip] +fn foo(constraints: impl Iterator) { + for constraint in constraints { + qux(constraint); +//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` + } +} + +fn bar(t: T, constraints: impl Iterator) where T: std::fmt::Debug { + for constraint in constraints { + qux(t); + qux(constraint); +//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` + } +} + +fn baz(t: impl std::fmt::Debug, constraints: impl Iterator) { + for constraint in constraints { + qux(t); + qux(constraint); +//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` + } +} + +fn bat(t: T, constraints: impl Iterator, _: I) { + for constraint in constraints { + qux(t); + qux(constraint); +//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` + } +} + +fn bak(constraints: impl Iterator + std::fmt::Debug) { + for constraint in constraints { + qux(constraint); +//~^ ERROR `::Item` doesn't implement + } +} + +fn qux(_: impl std::fmt::Debug) {} + +fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr new file mode 100644 index 0000000000000..6fc629b33a21e --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -0,0 +1,78 @@ +error[E0277]: `::Item` doesn't implement `std::fmt::Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:6:13 + | +LL | qux(constraint); + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` +... +LL | fn qux(_: impl std::fmt::Debug) {} + | --------------- required by this bound in `qux` + | + = help: the trait `std::fmt::Debug` is not implemented for `::Item` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn foo(constraints: I) where ::Item: std::fmt::Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `::Item` doesn't implement `std::fmt::Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:14:13 + | +LL | qux(constraint); + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` +... +LL | fn qux(_: impl std::fmt::Debug) {} + | --------------- required by this bound in `qux` + | + = help: the trait `std::fmt::Debug` is not implemented for `::Item` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn bar(t: T, constraints: I) where T: std::fmt::Debug, ::Item: std::fmt::Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `::Item` doesn't implement `std::fmt::Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:22:13 + | +LL | qux(constraint); + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` +... +LL | fn qux(_: impl std::fmt::Debug) {} + | --------------- required by this bound in `qux` + | + = help: the trait `std::fmt::Debug` is not implemented for `::Item` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn baz(t: impl std::fmt::Debug, constraints: I) where ::Item: std::fmt::Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `::Item` doesn't implement `std::fmt::Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:30:13 + | +LL | qux(constraint); + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` +... +LL | fn qux(_: impl std::fmt::Debug) {} + | --------------- required by this bound in `qux` + | + = help: the trait `std::fmt::Debug` is not implemented for `::Item` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn bat(t: T, constraints: U, _: I) where ::Item: std::fmt::Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `::Item` doesn't implement `std::fmt::Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:37:13 + | +LL | qux(constraint); + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` +... +LL | fn qux(_: impl std::fmt::Debug) {} + | --------------- required by this bound in `qux` + | + = help: the trait `std::fmt::Debug` is not implemented for `::Item` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn bak(constraints: I) where ::Item: std::fmt::Debug { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index db67e0c9b7d98..6c0653d5fcb7c 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -106,7 +106,7 @@ LL | fn test6_b(_: _, _: T) { } | help: use type parameters instead | -LL | fn test6_b(_: K, _: T) { } +LL | fn test6_b(_: U, _: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures @@ -117,7 +117,7 @@ LL | fn test6_c(_: _, _: (T, K, L, A, B)) { } | help: use type parameters instead | -LL | fn test6_c(_: C, _: (T, K, L, A, B)) { } +LL | fn test6_c(_: U, _: (T, K, L, A, B)) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures @@ -377,7 +377,7 @@ LL | struct BadStruct2<_, T>(_, T); | help: use type parameters instead | -LL | struct BadStruct2(K, T); +LL | struct BadStruct2(U, T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures