diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 20ccad26e891..a86471affaa1 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -502,7 +502,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let opaque = self.tcx.mk_opaque(key.def_id, substs); for &ty in tys { let ty = substitute_value(self.tcx, &result_subst, ty); - obligations.extend(self.handle_opaque_type(opaque, ty, cause, param_env)?); + obligations + .extend(self.handle_opaque_type(opaque, ty, cause, param_env)?.obligations); } } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index ff636616db49..cf57270df292 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,5 +1,5 @@ use crate::infer::{InferCtxt, InferOk}; -use crate::traits::{self, PredicateObligation, PredicateObligations}; +use crate::traits::{self, PredicateObligation}; use hir::def_id::{DefId, LocalDefId}; use hir::OpaqueTyOrigin; use rustc_data_structures::sync::Lrc; @@ -20,6 +20,8 @@ mod table; pub use table::{OpaqueTypeStorage, OpaqueTypeTable}; +use super::InferResult; + /// Information about the opaque types whose values we /// are inferring in this function (these are the `impl Trait` that /// appear in the return type). @@ -152,11 +154,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { opaque: Ty<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - ) -> Option>> { - let mut obligations = vec![]; - let value = Instantiator { infcx: self, cause, param_env, obligations: &mut obligations } - .fold_opaque_ty_new(opaque, |_, _| ty)?; - Some(InferOk { value, obligations }) + ) -> Option> { + Instantiator { infcx: self, cause, param_env }.fold_opaque_ty_new(opaque, |_, _| ty) } pub fn handle_opaque_type( @@ -165,9 +164,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { b: Ty<'tcx>, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - ) -> Result, TypeError<'tcx>> { + ) -> InferResult<'tcx, ()> { if a.references_error() || b.references_error() { - return Ok(vec![]); + return Ok(InferOk { value: (), obligations: vec![] }); } if self.defining_use_anchor.is_some() { let process = |a: Ty<'tcx>, b: Ty<'tcx>| { @@ -175,12 +174,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return None; } self.instantiate_opaque_types(b, a, cause.clone(), param_env) - .map(|res| res.obligations) }; if let Some(res) = process(a, b) { - Ok(res) + res } else if let Some(res) = process(b, a) { - Ok(res) + res } else { // Rerun equality check, but this time error out due to // different types. @@ -205,13 +203,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let key = opaque_type.expect_opaque_type(); let origin = self.opaque_ty_origin_unchecked(key.def_id, cause.span); - self.inner.borrow_mut().opaque_types().register( + let prev = self.inner.borrow_mut().opaque_types().register( key, opaque_type, OpaqueHiddenType { ty: hidden_ty, span: cause.span }, origin, ); - Ok(vec![]) + match prev { + Some(prev) => self.at(cause, param_env).eq(prev, hidden_ty), + None => Ok(InferOk { value: (), obligations: vec![] }), + } } } @@ -599,7 +600,6 @@ struct Instantiator<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - obligations: &'a mut PredicateObligations<'tcx>, } impl<'a, 'tcx> Instantiator<'a, 'tcx> { @@ -607,7 +607,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { &mut self, ty: Ty<'tcx>, mk_ty: impl FnOnce(&InferCtxt<'_, 'tcx>, Span) -> Ty<'tcx>, - ) -> Option> { + ) -> Option> { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose // value we are inferring. At present, this is @@ -659,7 +659,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { opaque_type_key: OpaqueTypeKey<'tcx>, origin: hir::OpaqueTyOrigin, mk_ty: impl FnOnce(&InferCtxt<'_, 'tcx>, Span) -> Ty<'tcx>, - ) -> Ty<'tcx> { + ) -> InferResult<'tcx, ()> { let infcx = self.infcx; let tcx = infcx.tcx; let OpaqueTypeKey { def_id, substs } = opaque_type_key; @@ -673,12 +673,16 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { // Foo, impl Bar)`. let span = self.cause.span; - self.infcx.inner.borrow_mut().opaque_types().register( + let mut obligations = vec![]; + let prev = self.infcx.inner.borrow_mut().opaque_types().register( OpaqueTypeKey { def_id, substs }, ty, OpaqueHiddenType { ty: ty_var, span }, origin, ); + if let Some(prev) = prev { + obligations = self.infcx.at(&self.cause, self.param_env).eq(prev, ty_var)?.obligations; + } debug!("generated new type inference var {:?}", ty_var.kind()); @@ -698,7 +702,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { projection_ty, self.cause.clone(), 0, - &mut self.obligations, + &mut obligations, ), // Replace all other mentions of the same opaque type with the hidden type, // as the bounds must hold on the hidden type after all. @@ -714,19 +718,19 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() { if projection.term.references_error() { // No point on adding these obligations since there's a type error involved. - return tcx.ty_error(); + return Ok(InferOk { value: (), obligations: vec![] }); } trace!("{:#?}", projection.term); } // Require that the predicate holds for the concrete type. debug!(?predicate); - self.obligations.push(traits::Obligation::new( + obligations.push(traits::Obligation::new( self.cause.clone(), self.param_env, predicate, )); } - ty_var + Ok(InferOk { value: (), obligations }) } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index dc47272c4fe0..1895c1a85c7c 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -18,14 +18,14 @@ pub struct OpaqueTypeStorage<'tcx> { impl<'tcx> OpaqueTypeStorage<'tcx> { #[instrument(level = "debug")] - pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: usize) { - if idx == 0 { + pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: Option>) { + if let Some(idx) = idx { + self.opaque_types.get_mut(&key).unwrap().hidden_types[0] = idx; + } else { match self.opaque_types.remove(&key) { None => bug!("reverted opaque type inference that was never registered: {:?}", key), Some(_) => {} } - } else { - self.opaque_types.get_mut(&key).unwrap().hidden_types.drain(idx..); } } @@ -75,14 +75,17 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { opaque_type: Ty<'tcx>, ty: OpaqueHiddenType<'tcx>, origin: OpaqueTyOrigin, - ) { + ) -> Option> { if let Some(decl) = self.storage.opaque_types.get_mut(&key) { - decl.hidden_types.push(ty); - self.undo_log.push(UndoLog::OpaqueTypes(key, decl.hidden_types.len())); - return; + assert_eq!(decl.hidden_types.len(), 1); + let prev = decl.hidden_types[0]; + decl.hidden_types = vec![ty]; + self.undo_log.push(UndoLog::OpaqueTypes(key, Some(prev))); + return Some(prev.ty); } let decl = OpaqueTypeDecl { opaque_type, hidden_types: vec![ty], origin }; self.storage.opaque_types.insert(key, decl); - self.undo_log.push(UndoLog::OpaqueTypes(key, 0)); + self.undo_log.push(UndoLog::OpaqueTypes(key, None)); + None } } diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 8f4abfde3010..02b15baf8fb2 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -11,6 +11,8 @@ use crate::{ traits, }; +use super::opaque_types::OpaqueHiddenType; + pub struct Snapshot<'tcx> { pub(crate) undo_len: usize, _marker: PhantomData<&'tcx ()>, @@ -18,7 +20,7 @@ pub struct Snapshot<'tcx> { /// Records the "undo" data for a single operation that affects some form of inference variable. pub(crate) enum UndoLog<'tcx> { - OpaqueTypes(OpaqueTypeKey<'tcx>, usize), + OpaqueTypes(OpaqueTypeKey<'tcx>, Option>), TypeVariables(type_variable::UndoLog<'tcx>), ConstUnificationTable(sv::UndoLog>>), IntUnificationTable(sv::UndoLog>), diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 68dd1cd26168..274f8a3ef79f 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -652,7 +652,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { &obligation.cause, obligation.param_env, ) { - Ok(value) => ProcessResult::Changed(mk_pending(value)), + Ok(value) => ProcessResult::Changed(mk_pending(value.obligations)), Err(err) => ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( ExpectedFound::new(true, a, b), err, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3b99183d8eb1..35818786cbbf 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -705,8 +705,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &obligation.cause, obligation.param_env, ) { - Ok(obligations) => { - self.evaluate_predicates_recursively(previous_stack, obligations) + Ok(res) => { + self.evaluate_predicates_recursively(previous_stack, res.obligations) } Err(_) => Ok(EvaluatedToErr), } diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index f79411c1003e..4032fbbceba4 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -11,11 +11,14 @@ LL | #![feature(specialization)] error[E0308]: mismatched types --> $DIR/equality.rs:15:5 | -LL | return 1_i32; - | ----- type expected due to this -LL | } +LL | fn two(x: bool) -> impl Foo { + | -------- the expected opaque type +... LL | 0_u32 | ^^^^^ expected `i32`, found `u32` + | + = note: expected opaque type `impl Foo` + found type `u32` error[E0277]: cannot add `impl Foo` to `u32` --> $DIR/equality.rs:24:11 diff --git a/src/test/ui/impl-trait/issue-72911.rs b/src/test/ui/impl-trait/issue-72911.rs index d556e968f34e..cf2c8b7e4154 100644 --- a/src/test/ui/impl-trait/issue-72911.rs +++ b/src/test/ui/impl-trait/issue-72911.rs @@ -16,7 +16,6 @@ fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator fn lint_files() -> impl Iterator { //~^ ERROR: failed to resolve - //~| ERROR `()` is not an iterator unimplemented!() } diff --git a/src/test/ui/impl-trait/issue-72911.stderr b/src/test/ui/impl-trait/issue-72911.stderr index 51648e6154dc..4a990286d966 100644 --- a/src/test/ui/impl-trait/issue-72911.stderr +++ b/src/test/ui/impl-trait/issue-72911.stderr @@ -18,15 +18,7 @@ LL | pub fn gather_all() -> impl Iterator { | = help: the trait `Iterator` is not implemented for `()` -error[E0277]: `()` is not an iterator - --> $DIR/issue-72911.rs:17:20 - | -LL | fn lint_files() -> impl Iterator { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator - | - = help: the trait `Iterator` is not implemented for `()` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0433. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr index 0e195558badb..15476c706a7f 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr @@ -1,11 +1,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ordinary-bounds-unrelated.rs:28:22 + --> $DIR/ordinary-bounds-unrelated.rs:28:33 | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here ... LL | if condition() { a } else { b } - | ^ + | ^ | help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound | diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr index 032e88c6d9c1..7315aa8e9d47 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr @@ -1,11 +1,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ordinary-bounds-unsuited.rs:31:22 + --> $DIR/ordinary-bounds-unsuited.rs:31:33 | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here ... LL | if condition() { a } else { b } - | ^ + | ^ | help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound | diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr index 4b4116887dc2..b2f7166f0ae3 100644 --- a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr +++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr @@ -1,20 +1,26 @@ error[E0308]: mismatched types --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5 | -LL | return A; - | - type expected due to this -LL | } +LL | fn can() -> impl NotObjectSafe { + | ------------------ the expected opaque type +... LL | B | ^ expected struct `A`, found struct `B` + | + = note: expected opaque type `impl NotObjectSafe` + found struct `B` error[E0308]: mismatched types --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5 | -LL | return A; - | - type expected due to this -LL | } +LL | fn cat() -> impl ObjectSafe { + | --------------- the expected opaque type +... LL | B | ^ expected struct `A`, found struct `B` + | + = note: expected opaque type `impl ObjectSafe` + found struct `B` error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr index eb0d3a52a4eb..db0d446e559a 100644 --- a/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr @@ -1,31 +1,41 @@ error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5 | -LL | return 0i32; - | ---- type expected due to this -LL | } +LL | fn foo() -> impl std::fmt::Display { + | ---------------------- the expected opaque type +... LL | 1u32 | ^^^^ expected `i32`, found `u32` + | + = note: expected opaque type `impl std::fmt::Display` + found type `u32` error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16 | -LL | return 0i32; - | ---- type expected due to this -LL | } else { +LL | fn bar() -> impl std::fmt::Display { + | ---------------------- the expected opaque type +... LL | return 1u32; | ^^^^ expected `i32`, found `u32` + | + = note: expected opaque type `impl std::fmt::Display` + found type `u32` error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:17:5 | +LL | fn baz() -> impl std::fmt::Display { + | ---------------------- the expected opaque type LL | / if false { LL | | return 0i32; - | | ---- type expected due to this LL | | } else { LL | | 1u32 LL | | } | |_____^ expected `i32`, found `u32` + | + = note: expected opaque type `impl std::fmt::Display` + found type `u32` error[E0308]: `if` and `else` have incompatible types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9 @@ -53,36 +63,48 @@ LL ~ Box::new(1u32) error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:33:5 | +LL | fn bat() -> impl std::fmt::Display { + | ---------------------- the expected opaque type LL | / match 13 { LL | | 0 => return 0i32, - | | ---- type expected due to this LL | | _ => 1u32, LL | | } | |_____^ expected `i32`, found `u32` + | + = note: expected opaque type `impl std::fmt::Display` + found type `u32` error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5 | +LL | fn can() -> impl std::fmt::Display { + | ---------------------- the expected opaque type LL | / match 13 { LL | | 0 => return 0i32, - | | ---- type expected due to this LL | | 1 => 1u32, LL | | _ => 2u32, LL | | } | |_____^ expected `i32`, found `u32` + | + = note: expected opaque type `impl std::fmt::Display` + found type `u32` error[E0308]: mismatched types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:48:5 | +LL | fn cat() -> impl std::fmt::Display { + | ---------------------- the expected opaque type LL | / match 13 { LL | | 0 => { LL | | return 0i32; - | | ---- type expected due to this LL | | } ... | LL | | } LL | | } | |_____^ expected `i32`, found `u32` + | + = note: expected opaque type `impl std::fmt::Display` + found type `u32` error[E0308]: `match` arms have incompatible types --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14 diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.rs b/src/test/ui/type-alias-impl-trait/issue-63279.rs index 3d20b7e37190..e09e1a3afed6 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.rs +++ b/src/test/ui/type-alias-impl-trait/issue-63279.rs @@ -8,6 +8,7 @@ type Closure = impl FnOnce(); fn c() -> Closure { || -> Closure { || () } //~^ ERROR: mismatched types + //~| ERROR: mismatched types //~| ERROR: expected a `FnOnce<()>` closure, found `()` } diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr index 385e816eebf5..810c99c84bc4 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr @@ -15,10 +15,18 @@ LL | || -> Closure { || () } | = note: expected unit type `()` found closure `[closure@$DIR/issue-63279.rs:9:21: 9:26]` -help: you might have meant to return this value + +error[E0308]: mismatched types + --> $DIR/issue-63279.rs:9:5 | -LL | || -> Closure { return || (); } - | ++++++ + +LL | type Closure = impl FnOnce(); + | ------------- the expected opaque type +... +LL | || -> Closure { || () } + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found closure + | + = note: expected opaque type `impl FnOnce()` + found closure `[closure@$DIR/issue-63279.rs:9:5: 9:28]` error: could not find defining uses --> $DIR/issue-63279.rs:5:16 @@ -26,7 +34,7 @@ error: could not find defining uses LL | type Closure = impl FnOnce(); | ^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-74280.stderr b/src/test/ui/type-alias-impl-trait/issue-74280.stderr index 475a00522342..db8c5b7a72be 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74280.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-74280.stderr @@ -1,10 +1,14 @@ error[E0308]: mismatched types --> $DIR/issue-74280.rs:10:5 | -LL | let y = || -> Test { () }; - | -- type expected due to this +LL | type Test = impl Copy; + | --------- the expected opaque type +... LL | 7 | ^ expected `()`, found integer + | + = note: expected opaque type `impl Copy` + found type `{integer}` error: could not find defining uses --> $DIR/issue-74280.rs:5:13 diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr index 65bd12d9a9ab..20da37ec9a18 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr @@ -1,17 +1,18 @@ error[E0308]: mismatched types --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9 | +LL | type X = impl ToString; + | ------------- the expected opaque type +... LL | fn g(a: A, b: B) -> (X, X) { | - - found type parameter | | | expected type parameter LL | (a, b) - | - ^ expected type parameter `A`, found type parameter `B` - | | - | type expected due to this + | ^ expected type parameter `A`, found type parameter `B` | - = note: expected type parameter `A` - found type parameter `B` + = note: expected opaque type `impl ToString` + found type parameter `B` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters