diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index c9d57706d55ea..4c5b160d140bc 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -58,7 +58,7 @@ use crate::middle::region; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, }; -use crate::ty::error::TypeError; +use crate::ty::error::{TypeError, ExpectedFound}; use crate::ty::{self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable}; use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; @@ -1810,10 +1810,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sub_region, "...", ); - err.span_note(sup_trace.cause.span, &format!( - "...so that the {}", - sup_trace.cause.as_requirement_str() - )); + + if self.try_note_static_dyn_trait_impl( + &mut err, &sub_region, sub_trace, + ).is_none() { + err.span_note(sup_trace.cause.span, &format!( + "...so that the {}", + sup_trace.cause.as_requirement_str() + )); + } err.note_expected_found( &"", @@ -1839,9 +1844,162 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "...", ); + if let infer::Subtype(ref sub_trace) = sub_origin { + if self.try_note_static_dyn_trait_impl(&mut err, &sub_region, sub_trace).is_some() { + err.emit(); + return; + } + } + self.note_region_origin(&mut err, &sub_origin); + err.emit(); } + + fn try_note_static_dyn_trait_impl( + &self, + err: &mut DiagnosticBuilder<'_>, + region: Region<'tcx>, + trace: &TypeTrace<'tcx>, + ) -> Option<()> { + debug!( + "try_note_static_dyn_trait_impl: err={:?} trace={:?} region={:?}", err, trace, region, + ); + + if let TypeTrace { + cause, + values: ValuePairs::Types(ExpectedFound { expected, found }), + } = trace { + let expected = self.resolve_vars_if_possible(expected); + + debug!( + "try_note_static_dyn_trait_impl: expected={:?} expected.kind={:?} found={:?}", + expected, expected.kind, found, + ); + + let dyn_static_ty = expected.walk().find(|ty| + if let ty::Dynamic(_, _) = ty.kind { true } else { false }); + + debug!( + "try_note_static_dyn_trait_impl: dyn_static_ty={:?} dyn_static_ty.kind={:?}", + dyn_static_ty, dyn_static_ty.map(|dyn_static_ty| &dyn_static_ty.kind), + ); + + let dyn_trait_name = if let Some(dyn_static_ty) = dyn_static_ty { + if let ty::Dynamic(binder, _) = dyn_static_ty.kind { + binder.skip_binder().to_string() + } else { + return None; + } + } else { + return None; + }; + + if let ObligationCauseCode::ExprAssignable { expr_hir_id } = cause.code { + debug!( + "try_note_static_dyn_trait_impl: expr_hir_id={:?}", expr_hir_id + ); + + let expr_node = self.tcx.hir().get(expr_hir_id); + let parent_node = self.tcx.hir().get( + self.tcx.hir().get_parent_node(expr_hir_id)); + + debug!( + "try_note_static_dyn_trait_impl: expr_node={:?} parent_node={:?}", + expr_node, parent_node, + ); + + let call_expr = match (expr_node, parent_node) { + // The original expression is a param to a method call. Return the call expr. + (_, hir::Node::Expr(parent_expr)) => parent_expr, + // A return expr, which should be assignable to the return type. + // In that case, return the original expr. + (hir::Node::Expr(expr), hir::Node::Block(_)) => expr, + _ => { + return None; + } + }; + + debug!( + "try_note_static_dyn_trait_impl: call_expr={:?} call_expr.kind={:?}", + call_expr, call_expr.kind, + ); + + let tables = self.in_progress_tables.unwrap().borrow(); + + if let hir::ExprKind::MethodCall(_, _, args) = &call_expr.kind { + let method_def_id = tables.type_dependent_def_id(call_expr.hir_id).unwrap(); + let trait_def_id = self.tcx.trait_of_item(method_def_id); + + debug!("try_note_static_dyn_trait_impl: trait_def_id={:?}", trait_def_id); + + // As this is a method call expression, we have at least one argument. + let receiver_arg = &args[0]; + + debug!( + "try_note_static_dyn_trait_impl: receiver_arg.kind={:?}", + tables.expr_ty(receiver_arg).kind + ); + + if let ty::Ref(_, arg_ty, _) = tables.expr_ty(receiver_arg).kind { + let mut trait_impl = None; + + self.tcx.for_each_relevant_impl( + trait_def_id.unwrap(), + arg_ty, + |impl_def_id| { + trait_impl = Some(impl_def_id); + }); + + if let Some(impl_def_id) = trait_impl { + self.note_dyn_impl_and_suggest_anon_lifetime( + err, + impl_def_id, + &dyn_trait_name + ); + return Some(()); + } + } + } + } + } + + None + } + + pub fn note_dyn_impl_and_suggest_anon_lifetime( + &self, + err: &mut DiagnosticBuilder<'_>, + impl_def_id: DefId, + dyn_trait_name: &str, + ) { + let impl_span = self.tcx.sess.source_map() + .def_span(self.tcx.def_span(impl_def_id)); + debug!( + "try_report_static_dyn_trait: impl_span={:?}", impl_span, + ); + + err.span_note( + impl_span, + &format!("...because this implementation requires it"), + ); + + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(impl_span) { + err.span_suggestion( + impl_span, + &format!( + "you can add an explicit constraint to the implementation so that it applies \ + to types with less than `'static` lifetime", + ), + snippet.replace(dyn_trait_name, &format!("{} + '_", &dyn_trait_name)), + Applicability::Unspecified, + ); + } else { + debug!( + "try_report_static_dyn_trait: oh noes impl_span={:?}", impl_span, + ); + } + } } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -1948,7 +2106,7 @@ impl<'tcx> ObligationCause<'tcx> { use crate::traits::ObligationCauseCode::*; match self.code { CompareImplMethodObligation { .. } => "method type is compatible with trait", - ExprAssignable => "expression is assignable", + ExprAssignable { .. } => "expression is assignable", MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source { hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types", _ => "match arms have compatible types", diff --git a/src/librustc/infer/error_reporting/nice_region_error/mod.rs b/src/librustc/infer/error_reporting/nice_region_error/mod.rs index 09cfbf850a57d..e1cd8ed1f902b 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/mod.rs @@ -12,6 +12,7 @@ mod named_anon_conflict; mod placeholder_error; mod outlives_closure; mod static_impl_trait; +mod static_dyn_trait; mod trait_impl_difference; mod util; @@ -73,6 +74,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { .map(|mut diag| { diag.emit(); ErrorReported }) .or_else(|| self.try_report_anon_anon_conflict()) .or_else(|| self.try_report_outlives_closure()) + .or_else(|| self.try_report_static_dyn_trait()) .or_else(|| self.try_report_static_impl_trait()) .or_else(|| self.try_report_impl_not_conforming_to_trait()) } diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 0abdeb7199344..18f4854221ea9 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -82,6 +82,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { return None; } + let dyn_static_ty = new_ty.walk().find(|ty| + if let ty::Dynamic(_, ty::RegionKind::ReStatic) = ty.kind { true } else { false }); + + debug!( + "try_report_named_anon_conflict: dyn_static_ty={:?} dyn_static_ty.kind={:?}", + dyn_static_ty, dyn_static_ty.map(|dyn_static_ty| &dyn_static_ty.kind), + ); + + if dyn_static_ty.is_some() { + return None; + } + if let Some((_, fndecl)) = self.find_anon_type(anon, &br) { if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() || self.is_self_anon(is_first, scope_def_id) diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_dyn_trait.rs b/src/librustc/infer/error_reporting/nice_region_error/static_dyn_trait.rs new file mode 100644 index 0000000000000..c737f8d5415d6 --- /dev/null +++ b/src/librustc/infer/error_reporting/nice_region_error/static_dyn_trait.rs @@ -0,0 +1,140 @@ +#![allow(unused)] +//! Error Reporting for dyn Traits. +use crate::infer::error_reporting::nice_region_error::NiceRegionError; +use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::ty::{self, BoundRegion, FreeRegion, RegionKind, DefIdTree, ParamEnv}; +use crate::util::common::ErrorReported; +use errors::Applicability; +use crate::infer::{SubregionOrigin, ValuePairs, TypeTrace}; +use crate::ty::error::ExpectedFound; +use crate::hir; +use crate::hir::def_id::DefId; +use crate::traits::ObligationCauseCode::ExprAssignable; +use crate::traits::ObligationCause; +use crate::ty::{TyCtxt, TypeFoldable}; +use crate::ty::subst::{Subst, InternalSubsts, SubstsRef}; +use syntax_pos::Span; + +impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { + /// Print the error message for lifetime errors when a static ref to a trait object is required + /// because of a `dyn Trait` impl. + pub(super) fn try_report_static_dyn_trait(&self) -> Option { + let (span, sub, sup) = self.regions(); + + debug!( + "try_report_static_dyn_trait: sub={:?}, sup={:?}, error={:?}", + sub, + sup, + self.error, + ); + + if let Some(ref error) = self.error { + let (found, origin_span) = match error { + RegionResolutionError::ConcreteFailure(SubregionOrigin::Subtype(box TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), _, _) => { + (found, cause.span) + }, + // FIXME there is also the other region origin! + RegionResolutionError::SubSupConflict(_, _, SubregionOrigin::Subtype(box TypeTrace { + cause, + values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), + }), _, _, _) => { + (found, cause.span) + } + _ => { + return None; + } + }; + + debug!( + "try_report_static_dyn_trait: found={:?} origin_span={:?}", + found, origin_span, + ); + + let found = self.infcx.resolve_vars_if_possible(found); + let dyn_static_ty = found.self_ty().walk().find(|ty| + if let ty::Dynamic(_, _) = ty.kind { true } else { false }); + + debug!( + "try_report_static_dyn_trait: dyn_static_ty={:?} dyn_static_ty.kind={:?}", + dyn_static_ty, dyn_static_ty.map(|dyn_static_ty| &dyn_static_ty.kind), + ); + + let dyn_trait_name = if let Some(dyn_static_ty) = dyn_static_ty { + if let ty::Dynamic(binder, _) = dyn_static_ty.kind { + binder.skip_binder().to_string() + } else { + return None; + } + } else { + return None; + }; + + let mut trait_impl = None; + + self.tcx().for_each_relevant_impl( + found.def_id, + found.self_ty(), + |impl_def_id| { + debug!( + "try_report_static_dyn_trait: for_each_relevant_impl impl_def_id={:?}", + impl_def_id, + ); + + trait_impl = Some(impl_def_id); + }); + + debug!( + "try_report_static_dyn_trait: trait_impl={:?}", trait_impl, + ); + + if let Some(impl_def_id) = trait_impl { + self.emit_dyn_trait_err(origin_span, &dyn_trait_name, impl_def_id); + return Some(ErrorReported); + } + } + None + } + + fn emit_dyn_trait_err(&self, + expr_span: Span, + dyn_trait_name: &String, + impl_def_id: DefId, + ) { + let (_, sub, sup) = self.regions(); + + debug!( + "emit_dyn_trait_err: sup={:?} sub={:?} expr_span={:?} dyn_trait_name={:?}", + sup, sub, expr_span, dyn_trait_name, + ); + + let item_span = self.tcx().sess.source_map() + .def_span(self.tcx().def_span(impl_def_id)); + + let (lifetime_description, lt_sp_opt) = self.tcx().msg_span_from_free_region(sup); + + let impl_span = item_span; + + let mut err = self.tcx().sess.struct_span_err( + expr_span, + "cannot infer an appropriate lifetime", + ); + + if let Some(lt_sp_opt) = lt_sp_opt { + err.span_note( + lt_sp_opt, + &format!("first, the lifetime cannot outlive {}...", lifetime_description), + ); + } + + err.span_note(expr_span, + &format!("but, the lifetime must be valid for the {} lifetime...", sub)); + + + self.infcx.note_dyn_impl_and_suggest_anon_lifetime(&mut err, impl_def_id, dyn_trait_name); + + err.emit(); + } +} diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 4b933735fc75f..d8c1676161568 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -150,10 +150,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { match origin { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); - let mut err = self.report_and_explain_type_error(trace, &terr); + let mut err = self.report_and_explain_type_error(trace.clone(), &terr); self.tcx.note_and_explain_region(region_scope_tree, &mut err, "", sup, "..."); self.tcx.note_and_explain_region(region_scope_tree, &mut err, "...does not necessarily outlive ", sub, ""); + self.try_note_static_dyn_trait_impl(&mut err, sub, &trace); err } infer::Reborrow(span) => { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 701c19085bec5..03708ccd59ed1 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2462,7 +2462,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { let tcx = self.tcx; match *cause_code { - ObligationCauseCode::ExprAssignable | + ObligationCauseCode::ExprAssignable { .. } | ObligationCauseCode::MatchExpressionArm { .. } | ObligationCauseCode::MatchExpressionArmPattern { .. } | ObligationCauseCode::IfExpression { .. } | diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index d94e004db2978..1f610e7cfb251 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -231,8 +231,9 @@ pub enum ObligationCauseCode<'tcx> { }, /// Checking that this expression can be assigned where it needs to be - // FIXME(eddyb) #11161 is the original Expr required? - ExprAssignable, + ExprAssignable { + expr_hir_id: hir::HirId, + }, /// Computing common supertype in the arms of a match expression MatchExpressionArm(Box>), diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 8c300da11fcbf..8e8dfeb0a51ed 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -514,7 +514,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { impl_item_def_id, trait_item_def_id, }), - super::ExprAssignable => Some(super::ExprAssignable), + super::ExprAssignable { expr_hir_id } => Some(super::ExprAssignable { expr_hir_id }), super::MatchExpressionArm(box super::MatchExpressionArmCause { arm_span, source, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 726b3ba985778..53a81ab1a9048 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -829,9 +829,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { allow_two_phase: AllowTwoPhase, ) -> RelateResult<'tcx, Ty<'tcx>> { let source = self.resolve_vars_with_obligations(expr_ty); - debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); + debug!("coercion::try {:?}: {:?} -> {:?} ", expr, source, target); + + let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable { + expr_hir_id: expr.hir_id, + }); + - let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause, allow_two_phase); let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; @@ -849,7 +853,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let source = self.resolve_vars_with_obligations(expr_ty); debug!("coercion::can({:?} -> {:?})", source, target); - let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable); + let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::MiscObligation); // We don't ever need two-phase here since we throw out the result of the coercion let coerce = Coerce::new(self, cause, AllowTwoPhase::No); self.probe(|_| coerce.coerce(source, target)).is_ok() diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index 3300293bb36ca..a631c8994a029 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -1,30 +1,28 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/dyn-trait.rs:20:16 +error: cannot infer an appropriate lifetime + --> $DIR/dyn-trait.rs:20:5 | LL | static_val(x); - | ^ + | ^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 19:26... --> $DIR/dyn-trait.rs:19:26 | LL | fn with_dyn_debug_static<'a>(x: Box) { | ^^ -note: ...so that the expression is assignable - --> $DIR/dyn-trait.rs:20:16 - | -LL | static_val(x); - | ^ - = note: expected `std::boxed::Box` - found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>` - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the types are compatible +note: but, the lifetime must be valid for the 'static lifetime... --> $DIR/dyn-trait.rs:20:5 | LL | static_val(x); | ^^^^^^^^^^ - = note: expected `StaticTrait` - found `StaticTrait` +note: ...because this implementation requires it + --> $DIR/dyn-trait.rs:10:1 + | +LL | impl StaticTrait for Box { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: you can add an explicit constraint to the implementation so that it applies to types with less than `'static` lifetime + | +LL | impl StaticTrait for Box { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/traits/trait-object-suggest-lifetime-in-type-param.rs b/src/test/ui/traits/trait-object-suggest-lifetime-in-type-param.rs new file mode 100644 index 0000000000000..a39dac30d0caf --- /dev/null +++ b/src/test/ui/traits/trait-object-suggest-lifetime-in-type-param.rs @@ -0,0 +1,39 @@ +// compile-fail + +trait DebugWith { + fn fmt_with(&self, cx: &Cx); + fn debug_with(&self, cx: &Cx) {} + fn debug_with_box(&self, cx: Box<&Cx>) {} +} + + +trait DebugContext {} + +struct Foo { + bar: Bar +} + +impl DebugWith for Foo { + fn fmt_with(&self, cx: &dyn DebugContext) { + let Foo { bar } = self; + bar.fmt_with(cx); + //~^ ERROR cannot infer an appropriate lifetime + bar.debug_with(cx); + //~^ ERROR cannot infer an appropriate lifetime + } + + fn debug_with_box(&self, cx: Box<&dyn DebugContext>) { + let Foo { bar } = self; + + bar.debug_with_box(cx); + //~^ ERROR mismatched types + } +} + +struct Bar {} + +impl DebugWith for Bar { + fn fmt_with(&self, cx: &dyn DebugContext) {} +} + +fn main() {} diff --git a/src/test/ui/traits/trait-object-suggest-lifetime-in-type-param.stderr b/src/test/ui/traits/trait-object-suggest-lifetime-in-type-param.stderr new file mode 100644 index 0000000000000..ebb023f9f725d --- /dev/null +++ b/src/test/ui/traits/trait-object-suggest-lifetime-in-type-param.stderr @@ -0,0 +1,99 @@ +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:19:22 + | +LL | bar.fmt_with(cx); + | ^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 17:5... + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:17:5 + | +LL | / fn fmt_with(&self, cx: &dyn DebugContext) { +LL | | let Foo { bar } = self; +LL | | bar.fmt_with(cx); +LL | | +LL | | bar.debug_with(cx); +LL | | +LL | | } + | |_____^ +note: ...so that the declared lifetime parameter bounds are satisfied + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:19:22 + | +LL | bar.fmt_with(cx); + | ^^ + = note: but, the lifetime must be valid for the static lifetime... +note: ...because this implementation requires it + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:35:1 + | +LL | impl DebugWith for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: you can add an explicit constraint to the implementation so that it applies to types with less than `'static` lifetime + | +LL | impl DebugWith for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:21:24 + | +LL | bar.debug_with(cx); + | ^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 17:5... + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:17:5 + | +LL | / fn fmt_with(&self, cx: &dyn DebugContext) { +LL | | let Foo { bar } = self; +LL | | bar.fmt_with(cx); +LL | | +LL | | bar.debug_with(cx); +LL | | +LL | | } + | |_____^ +note: ...so that the declared lifetime parameter bounds are satisfied + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:21:24 + | +LL | bar.debug_with(cx); + | ^^ + = note: but, the lifetime must be valid for the static lifetime... +note: ...because this implementation requires it + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:35:1 + | +LL | impl DebugWith for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: you can add an explicit constraint to the implementation so that it applies to types with less than `'static` lifetime + | +LL | impl DebugWith for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:28:28 + | +LL | bar.debug_with_box(cx); + | ^^ lifetime mismatch + | + = note: expected struct `std::boxed::Box<&(dyn DebugContext + 'static)>` + found struct `std::boxed::Box<&dyn DebugContext>` +note: the anonymous lifetime #2 defined on the method body at 25:5... + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:25:5 + | +LL | / fn debug_with_box(&self, cx: Box<&dyn DebugContext>) { +LL | | let Foo { bar } = self; +LL | | +LL | | bar.debug_with_box(cx); +LL | | +LL | | } + | |_____^ + = note: ...does not necessarily outlive the static lifetime +note: ...because this implementation requires it + --> $DIR/trait-object-suggest-lifetime-in-type-param.rs:35:1 + | +LL | impl DebugWith for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: you can add an explicit constraint to the implementation so that it applies to types with less than `'static` lifetime + | +LL | impl DebugWith for Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0308, E0495. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/traits/trait-object-suggest-lifetime.rs b/src/test/ui/traits/trait-object-suggest-lifetime.rs new file mode 100644 index 0000000000000..4532d85c103f1 --- /dev/null +++ b/src/test/ui/traits/trait-object-suggest-lifetime.rs @@ -0,0 +1,35 @@ +// compile-fail + +trait MyIterator { + fn my_next(&mut self) -> Option; +} + +impl Iterator for dyn MyIterator { + type Item = i32; + + fn next(&mut self) -> Option { + self.my_next() + } +} + +fn use_my_iter(my_iter: &mut dyn MyIterator) { + let v: Vec<_> = my_iter.map(|i| i*i).collect(); + //~^ ERROR cannot infer an appropriate lifetime +} + +struct Wrapper(T); + +impl Iterator for Wrapper<&mut dyn MyIterator> { + type Item = i32; + + fn next(&mut self) -> Option { + self.0.my_next() + } +} + +fn use_my_wrapper(wrapper: Wrapper<&mut (dyn MyIterator + '_)>) { + let v: Vec<_> = wrapper.map(|i| i*i).collect(); + //~^ ERROR cannot infer an appropriate lifetime +} + +fn main() {} diff --git a/src/test/ui/traits/trait-object-suggest-lifetime.stderr b/src/test/ui/traits/trait-object-suggest-lifetime.stderr new file mode 100644 index 0000000000000..6a064c5b321d4 --- /dev/null +++ b/src/test/ui/traits/trait-object-suggest-lifetime.stderr @@ -0,0 +1,60 @@ +error: cannot infer an appropriate lifetime + --> $DIR/trait-object-suggest-lifetime.rs:16:29 + | +LL | let v: Vec<_> = my_iter.map(|i| i*i).collect(); + | ^^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 15:1... + --> $DIR/trait-object-suggest-lifetime.rs:15:1 + | +LL | / fn use_my_iter(my_iter: &mut dyn MyIterator) { +LL | | let v: Vec<_> = my_iter.map(|i| i*i).collect(); +LL | | +LL | | } + | |_^ +note: but, the lifetime must be valid for the 'static lifetime... + --> $DIR/trait-object-suggest-lifetime.rs:16:29 + | +LL | let v: Vec<_> = my_iter.map(|i| i*i).collect(); + | ^^^ +note: ...because this implementation requires it + --> $DIR/trait-object-suggest-lifetime.rs:7:1 + | +LL | impl Iterator for dyn MyIterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: you can add an explicit constraint to the implementation so that it applies to types with less than `'static` lifetime + | +LL | impl Iterator for dyn MyIterator + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: cannot infer an appropriate lifetime + --> $DIR/trait-object-suggest-lifetime.rs:31:29 + | +LL | let v: Vec<_> = wrapper.map(|i| i*i).collect(); + | ^^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 30:1... + --> $DIR/trait-object-suggest-lifetime.rs:30:1 + | +LL | / fn use_my_wrapper(wrapper: Wrapper<&mut (dyn MyIterator + '_)>) { +LL | | let v: Vec<_> = wrapper.map(|i| i*i).collect(); +LL | | +LL | | } + | |_^ +note: but, the lifetime must be valid for the '_ lifetime... + --> $DIR/trait-object-suggest-lifetime.rs:31:29 + | +LL | let v: Vec<_> = wrapper.map(|i| i*i).collect(); + | ^^^ +note: ...because this implementation requires it + --> $DIR/trait-object-suggest-lifetime.rs:22:1 + | +LL | impl Iterator for Wrapper<&mut dyn MyIterator> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: you can add an explicit constraint to the implementation so that it applies to types with less than `'static` lifetime + | +LL | impl Iterator for Wrapper<&mut dyn MyIterator + '_> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +