Re-use logic for adding a suggestion when a lifetime bound is missing on an impl trait
This commit is contained in:
parent
be399635a2
commit
888ba509ea
6 changed files with 150 additions and 91 deletions
|
@ -2235,8 +2235,7 @@ pub enum TyKind<'hir> {
|
||||||
///
|
///
|
||||||
/// Type parameters may be stored in each `PathSegment`.
|
/// Type parameters may be stored in each `PathSegment`.
|
||||||
Path(QPath<'hir>),
|
Path(QPath<'hir>),
|
||||||
/// An opaque type definition itself. This is currently only used for the
|
/// An opaque type definition itself. This is only used for `impl Trait`.
|
||||||
/// `opaque type Foo: Trait` item that `impl Trait` in desugars to.
|
|
||||||
///
|
///
|
||||||
/// The generic argument list contains the lifetimes (and in the future
|
/// The generic argument list contains the lifetimes (and in the future
|
||||||
/// possibly parameters) that are actually bound on the `impl Trait`.
|
/// possibly parameters) that are actually bound on the `impl Trait`.
|
||||||
|
|
|
@ -267,6 +267,18 @@ pub fn unexpected_hidden_region_diagnostic(
|
||||||
hidden_region,
|
hidden_region,
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
|
if let Some(reg_info) = tcx.is_suitable_region(hidden_region) {
|
||||||
|
let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
|
||||||
|
nice_region_error::suggest_new_region_bound(
|
||||||
|
tcx,
|
||||||
|
&mut err,
|
||||||
|
fn_returns,
|
||||||
|
hidden_region.to_string(),
|
||||||
|
None,
|
||||||
|
format!("captures {}", hidden_region),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Ugh. This is a painful case: the hidden region is not one
|
// Ugh. This is a painful case: the hidden region is not one
|
||||||
|
|
|
@ -14,6 +14,8 @@ mod static_impl_trait;
|
||||||
mod trait_impl_difference;
|
mod trait_impl_difference;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
pub use static_impl_trait::suggest_new_region_bound;
|
||||||
|
|
||||||
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
|
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
|
||||||
NiceRegionError::new(self, error.clone()).try_report().is_some()
|
NiceRegionError::new(self, error.clone()).try_report().is_some()
|
||||||
|
|
|
@ -217,17 +217,42 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
|
|
||||||
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
|
|
||||||
let consider = "consider changing the";
|
|
||||||
let declare = "to declare that the";
|
|
||||||
let arg = match param.param.pat.simple_ident() {
|
let arg = match param.param.pat.simple_ident() {
|
||||||
Some(simple_ident) => format!("argument `{}`", simple_ident),
|
Some(simple_ident) => format!("argument `{}`", simple_ident),
|
||||||
None => "the argument".to_string(),
|
None => "the argument".to_string(),
|
||||||
};
|
};
|
||||||
let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
|
|
||||||
let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);
|
|
||||||
let captures = format!("captures data from {}", arg);
|
let captures = format!("captures data from {}", arg);
|
||||||
|
suggest_new_region_bound(
|
||||||
|
tcx,
|
||||||
|
&mut err,
|
||||||
|
fn_returns,
|
||||||
|
lifetime_name,
|
||||||
|
Some(arg),
|
||||||
|
captures,
|
||||||
|
Some((param.param_ty_span, param.param_ty.to_string())),
|
||||||
|
);
|
||||||
|
|
||||||
|
err.emit();
|
||||||
|
Some(ErrorReported)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn suggest_new_region_bound(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
|
fn_returns: Vec<&rustc_hir::Ty<'_>>,
|
||||||
|
lifetime_name: String,
|
||||||
|
arg: Option<String>,
|
||||||
|
captures: String,
|
||||||
|
param: Option<(Span, String)>,
|
||||||
|
) {
|
||||||
|
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
|
||||||
|
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
|
||||||
|
let consider = "consider changing the";
|
||||||
|
let declare = "to declare that the";
|
||||||
|
let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
|
||||||
|
let explicit_static =
|
||||||
|
arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg));
|
||||||
let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";
|
let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";
|
||||||
let plus_lt = format!(" + {}", lifetime_name);
|
let plus_lt = format!(" + {}", lifetime_name);
|
||||||
for fn_return in fn_returns {
|
for fn_return in fn_returns {
|
||||||
|
@ -241,8 +266,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
|
let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
|
||||||
opaque
|
opaque
|
||||||
} else {
|
} else {
|
||||||
err.emit();
|
return;
|
||||||
return Some(ErrorReported);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(span) = opaque
|
if let Some(span) = opaque
|
||||||
|
@ -258,18 +282,22 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
{
|
{
|
||||||
|
if let Some(explicit_static) = &explicit_static {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span,
|
span,
|
||||||
&format!("{} `impl Trait`'s {}", consider, explicit_static),
|
&format!("{} `impl Trait`'s {}", consider, explicit_static),
|
||||||
lifetime_name.clone(),
|
lifetime_name.clone(),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
if let Some((param_span, param_ty)) = param.clone() {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
param.param_ty_span,
|
param_span,
|
||||||
add_static_bound,
|
add_static_bound,
|
||||||
param.param_ty.to_string(),
|
param_ty,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
} else if opaque
|
} else if opaque
|
||||||
.bounds
|
.bounds
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -317,28 +345,31 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
// would happen if there are nested impl/dyn traits and only
|
// would happen if there are nested impl/dyn traits and only
|
||||||
// one of them has the bound we'd suggest already there, like
|
// one of them has the bound we'd suggest already there, like
|
||||||
// in `impl Foo<X = dyn Bar> + '_`.
|
// in `impl Foo<X = dyn Bar> + '_`.
|
||||||
|
if let Some(explicit_static) = &explicit_static {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
lt.span,
|
lt.span,
|
||||||
&format!("{} trait object's {}", consider, explicit_static),
|
&format!("{} trait object's {}", consider, explicit_static),
|
||||||
lifetime_name.clone(),
|
lifetime_name.clone(),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
if let Some((param_span, param_ty)) = param.clone() {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
param.param_ty_span,
|
param_span,
|
||||||
add_static_bound,
|
add_static_bound,
|
||||||
param.param_ty.to_string(),
|
param_ty,
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err.emit();
|
|
||||||
Some(ErrorReported)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
fn get_impl_ident_and_self_ty_from_trait(
|
fn get_impl_ident_and_self_ty_from_trait(
|
||||||
&self,
|
&self,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
|
|
|
@ -5,6 +5,11 @@ LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
|
||||||
| -- ^^^^^^^^^^^^^^
|
| -- ^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
|
| hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
|
||||||
|
|
|
||||||
|
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b {
|
||||||
|
| ++++
|
||||||
|
|
||||||
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
|
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
|
||||||
--> $DIR/hidden-lifetimes.rs:45:70
|
--> $DIR/hidden-lifetimes.rs:45:70
|
||||||
|
@ -13,6 +18,11 @@ LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl S
|
||||||
| -- ^^^^^^^^^^^^^^
|
| -- ^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
|
| hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
|
||||||
|
|
|
||||||
|
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b {
|
||||||
|
| ++++
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,11 @@ LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y>
|
||||||
LL |
|
LL |
|
||||||
LL | where 'x: 'y
|
LL | where 'x: 'y
|
||||||
| -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here
|
| -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here
|
||||||
|
|
|
||||||
|
help: to declare that the `impl Trait` captures 'x, you can add an explicit `'x` lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> + 'x
|
||||||
|
| ++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue