Rollup merge of #105254 - cjgillot:issue-105251, r=oli-obk
Recurse into nested impl-trait when computing variance. Fixes https://github.com/rust-lang/rust/issues/105251
This commit is contained in:
commit
ddb98e0aac
3 changed files with 66 additions and 4 deletions
|
@ -7,7 +7,8 @@ use rustc_arena::DroplessArena;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt, TypeSuperVisitable, TypeVisitable};
|
use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
|
||||||
|
use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable};
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
/// Defines the `TermsContext` basically houses an arena where we can
|
/// Defines the `TermsContext` basically houses an arena where we can
|
||||||
|
@ -75,11 +76,30 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||||
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
|
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
|
||||||
// ```
|
// ```
|
||||||
// we may not use `'c` in the hidden type.
|
// we may not use `'c` in the hidden type.
|
||||||
struct OpaqueTypeLifetimeCollector {
|
struct OpaqueTypeLifetimeCollector<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
root_def_id: DefId,
|
||||||
variances: Vec<ty::Variance>,
|
variances: Vec<ty::Variance>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector {
|
impl<'tcx> OpaqueTypeLifetimeCollector<'tcx> {
|
||||||
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
|
fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlow<!> {
|
||||||
|
if def_id != self.root_def_id && self.tcx.is_descendant_of(def_id, self.root_def_id) {
|
||||||
|
let child_variances = self.tcx.variances_of(def_id);
|
||||||
|
for (a, v) in substs.iter().zip(child_variances) {
|
||||||
|
if *v != ty::Bivariant {
|
||||||
|
a.visit_with(self)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlFlow::CONTINUE
|
||||||
|
} else {
|
||||||
|
substs.visit_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> {
|
||||||
#[instrument(level = "trace", skip(self), ret)]
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
|
if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
|
||||||
|
@ -87,6 +107,19 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||||
}
|
}
|
||||||
r.super_visit_with(self)
|
r.super_visit_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
match t.kind() {
|
||||||
|
ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs),
|
||||||
|
ty::Projection(proj)
|
||||||
|
if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
|
||||||
|
{
|
||||||
|
self.visit_opaque(proj.item_def_id, proj.substs)
|
||||||
|
}
|
||||||
|
_ => t.super_visit_with(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
|
// By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
|
||||||
|
@ -111,7 +144,8 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut collector = OpaqueTypeLifetimeCollector { variances };
|
let mut collector =
|
||||||
|
OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances };
|
||||||
let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id());
|
let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id());
|
||||||
for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
|
for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
|
||||||
let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
|
let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
|
||||||
|
|
8
src/test/ui/impl-trait/nested-return-type4.rs
Normal file
8
src/test/ui/impl-trait/nested-return-type4.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// edition: 2021
|
||||||
|
|
||||||
|
fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
|
||||||
|
async move { let _s = s; }
|
||||||
|
//~^ ERROR hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
20
src/test/ui/impl-trait/nested-return-type4.stderr
Normal file
20
src/test/ui/impl-trait/nested-return-type4.stderr
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifetime that does not appear in bounds
|
||||||
|
--> $DIR/nested-return-type4.rs:4:5
|
||||||
|
|
|
||||||
|
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> {
|
||||||
|
| -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here
|
||||||
|
LL | async move { let _s = s; }
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to declare that `impl Future<Output = impl Sized>` captures `'s`, you can add an explicit `'s` lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + 's {
|
||||||
|
| ++++
|
||||||
|
help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound
|
||||||
|
|
|
||||||
|
LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized + 's> {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0700`.
|
Loading…
Add table
Add a link
Reference in a new issue