Suggest using precise capturing for hidden type that captures region
This commit is contained in:
parent
0c81f94b9a
commit
03bee1e1e5
4 changed files with 212 additions and 15 deletions
|
@ -1,5 +1,6 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
struct_span_code_err, Applicability, Diag, Subdiagnostic, E0309, E0310, E0311, E0495,
|
struct_span_code_err, Applicability, Diag, Subdiagnostic, E0309, E0310, E0311, E0495,
|
||||||
};
|
};
|
||||||
|
@ -12,7 +13,7 @@ use rustc_middle::traits::ObligationCauseCode;
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::{self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _};
|
use rustc_middle::ty::{self, IsSuggestable, Region, Ty, TyCtxt, TypeVisitableExt as _};
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::symbol::kw;
|
||||||
use rustc_span::{ErrorGuaranteed, Span};
|
use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol};
|
||||||
use rustc_type_ir::Upcast as _;
|
use rustc_type_ir::Upcast as _;
|
||||||
|
|
||||||
use super::nice_region_error::find_anon_type;
|
use super::nice_region_error::find_anon_type;
|
||||||
|
@ -1201,6 +1202,9 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
|
||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
|
if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) {
|
||||||
|
if infcx.tcx.features().precise_capturing {
|
||||||
|
suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err);
|
||||||
|
} else {
|
||||||
let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
|
let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id);
|
||||||
nice_region_error::suggest_new_region_bound(
|
nice_region_error::suggest_new_region_bound(
|
||||||
tcx,
|
tcx,
|
||||||
|
@ -1214,6 +1218,7 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ty::RePlaceholder(_) => {
|
ty::RePlaceholder(_) => {
|
||||||
explain_free_region(
|
explain_free_region(
|
||||||
tcx,
|
tcx,
|
||||||
|
@ -1257,3 +1262,98 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
|
||||||
|
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn suggest_precise_capturing<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
opaque_def_id: LocalDefId,
|
||||||
|
captured_lifetime: ty::Region<'tcx>,
|
||||||
|
diag: &mut Diag<'_>,
|
||||||
|
) {
|
||||||
|
let hir::OpaqueTy { bounds, .. } =
|
||||||
|
tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
|
||||||
|
|
||||||
|
let new_lifetime = Symbol::intern(&captured_lifetime.to_string());
|
||||||
|
|
||||||
|
if let Some((args, span)) = bounds.iter().find_map(|bound| match bound {
|
||||||
|
hir::GenericBound::Use(args, span) => Some((args, span)),
|
||||||
|
_ => None,
|
||||||
|
}) {
|
||||||
|
let last_lifetime_span = args.iter().rev().find_map(|arg| match arg {
|
||||||
|
hir::PreciseCapturingArg::Lifetime(lt) => Some(lt.ident.span),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let first_param_span = args.iter().find_map(|arg| match arg {
|
||||||
|
hir::PreciseCapturingArg::Param(p) => Some(p.ident.span),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let (insertion_span, pre, post) = if let Some(last_lifetime_span) = last_lifetime_span {
|
||||||
|
(last_lifetime_span.shrink_to_hi(), ", ", "")
|
||||||
|
} else if let Some(first_param_span) = first_param_span {
|
||||||
|
(first_param_span.shrink_to_lo(), "", ", ")
|
||||||
|
} else {
|
||||||
|
(span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), "", "")
|
||||||
|
};
|
||||||
|
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
insertion_span,
|
||||||
|
format!("add `{new_lifetime}` to the `use<...>` bound to explicitly capture it",),
|
||||||
|
format!("{pre}{new_lifetime}{post}"),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let mut captured_lifetimes = FxIndexSet::default();
|
||||||
|
let mut captured_non_lifetimes = FxIndexSet::default();
|
||||||
|
|
||||||
|
let variances = tcx.variances_of(opaque_def_id);
|
||||||
|
let mut generics = tcx.generics_of(opaque_def_id);
|
||||||
|
loop {
|
||||||
|
for param in &generics.own_params {
|
||||||
|
if variances[param.index as usize] == ty::Bivariant {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match param.kind {
|
||||||
|
ty::GenericParamDefKind::Lifetime => {
|
||||||
|
captured_lifetimes.insert(param.name);
|
||||||
|
}
|
||||||
|
ty::GenericParamDefKind::Type { synthetic: true, .. } => {
|
||||||
|
// FIXME: We can't provide a good suggestion for
|
||||||
|
// `use<...>` if we have an APIT. Bail for now.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ty::GenericParamDefKind::Type { .. }
|
||||||
|
| ty::GenericParamDefKind::Const { .. } => {
|
||||||
|
captured_non_lifetimes.insert(param.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(parent) = generics.parent {
|
||||||
|
generics = tcx.generics_of(parent);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !captured_lifetimes.insert(new_lifetime) {
|
||||||
|
// Uh, strange. This lifetime appears to already be captured...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let concatenated_bounds = captured_lifetimes
|
||||||
|
.into_iter()
|
||||||
|
.chain(captured_non_lifetimes)
|
||||||
|
.map(|sym| sym.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
diag.span_suggestion_verbose(
|
||||||
|
tcx.def_span(opaque_def_id).shrink_to_hi(),
|
||||||
|
format!("add a `use<...>` bound to explicitly capture `{new_lifetime}`",),
|
||||||
|
format!(" + use<{concatenated_bounds}>"),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,10 +16,10 @@ LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x }
|
||||||
| | opaque type defined here
|
| | opaque type defined here
|
||||||
| hidden type `&'a ()` captures the lifetime `'a` as defined here
|
| hidden type `&'a ()` captures the lifetime `'a` as defined here
|
||||||
|
|
|
|
||||||
help: to declare that `impl Sized` captures `'a`, you can add an explicit `'a` lifetime bound
|
help: add `'a` to the `use<...>` bound to explicitly capture it
|
||||||
|
|
|
|
||||||
LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> + 'a { x }
|
LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<'a> { x }
|
||||||
| ++++
|
| ++
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#![feature(precise_capturing)]
|
||||||
|
|
||||||
|
fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> {
|
||||||
|
//~^ HELP add `'a` to the `use<...>` bound
|
||||||
|
x
|
||||||
|
//~^ ERROR hidden type for
|
||||||
|
}
|
||||||
|
|
||||||
|
fn param<'a, T>(x: &'a ()) -> impl Sized + use<T> {
|
||||||
|
//~^ HELP add `'a` to the `use<...>` bound
|
||||||
|
x
|
||||||
|
//~^ ERROR hidden type for
|
||||||
|
}
|
||||||
|
|
||||||
|
fn empty<'a>(x: &'a ()) -> impl Sized + use<> {
|
||||||
|
//~^ HELP add `'a` to the `use<...>` bound
|
||||||
|
x
|
||||||
|
//~^ ERROR hidden type for
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Captures<'a> {}
|
||||||
|
impl<T> Captures<'_> for T {}
|
||||||
|
|
||||||
|
fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> {
|
||||||
|
//~^ HELP add a `use<...>` bound
|
||||||
|
x
|
||||||
|
//~^ ERROR hidden type for
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,67 @@
|
||||||
|
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
|
||||||
|
--> $DIR/hidden-type-suggestion.rs:5:5
|
||||||
|
|
|
||||||
|
LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> {
|
||||||
|
| -- -------------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `&'a ()` captures the lifetime `'a` as defined here
|
||||||
|
LL |
|
||||||
|
LL | x
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
help: add `'a` to the `use<...>` bound to explicitly capture it
|
||||||
|
|
|
||||||
|
LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b, 'a> {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
|
||||||
|
--> $DIR/hidden-type-suggestion.rs:11:5
|
||||||
|
|
|
||||||
|
LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use<T> {
|
||||||
|
| -- ------------------- opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `&'a ()` captures the lifetime `'a` as defined here
|
||||||
|
LL |
|
||||||
|
LL | x
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
help: add `'a` to the `use<...>` bound to explicitly capture it
|
||||||
|
|
|
||||||
|
LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use<'a, T> {
|
||||||
|
| +++
|
||||||
|
|
||||||
|
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
|
||||||
|
--> $DIR/hidden-type-suggestion.rs:17:5
|
||||||
|
|
|
||||||
|
LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<> {
|
||||||
|
| -- ------------------ opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `&'a ()` captures the lifetime `'a` as defined here
|
||||||
|
LL |
|
||||||
|
LL | x
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
help: add `'a` to the `use<...>` bound to explicitly capture it
|
||||||
|
|
|
||||||
|
LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<'a> {
|
||||||
|
| ++
|
||||||
|
|
||||||
|
error[E0700]: hidden type for `impl Captures<'captured>` captures lifetime that does not appear in bounds
|
||||||
|
--> $DIR/hidden-type-suggestion.rs:26:5
|
||||||
|
|
|
||||||
|
LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> {
|
||||||
|
| -- ------------------------ opaque type defined here
|
||||||
|
| |
|
||||||
|
| hidden type `&'a ()` captures the lifetime `'a` as defined here
|
||||||
|
LL |
|
||||||
|
LL | x
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
help: add a `use<...>` bound to explicitly capture `'a`
|
||||||
|
|
|
||||||
|
LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> + use<'captured, 'a, Captured> {
|
||||||
|
| ++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0700`.
|
Loading…
Add table
Add a link
Reference in a new issue