Inherit generics for impl-trait.
This commit is contained in:
parent
b95650930b
commit
5fc261e9a0
6 changed files with 144 additions and 72 deletions
|
@ -2767,35 +2767,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
|
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
|
||||||
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
|
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
|
||||||
// Our own parameters are the resolved lifetimes.
|
// Our own parameters are the resolved lifetimes.
|
||||||
if let GenericParamDefKind::Lifetime = param.kind {
|
let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() };
|
||||||
if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
|
let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() };
|
||||||
self.ast_region_to_region(lifetime, None).into()
|
self.ast_region_to_region(lifetime, None).into()
|
||||||
} else {
|
} else {
|
||||||
bug!()
|
tcx.mk_param_from_def(param)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bug!()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match param.kind {
|
|
||||||
// For RPIT (return position impl trait), only lifetimes
|
|
||||||
// mentioned in the impl Trait predicate are captured by
|
|
||||||
// the opaque type, so the lifetime parameters from the
|
|
||||||
// parent item need to be replaced with `'static`.
|
|
||||||
//
|
|
||||||
// For `impl Trait` in the types of statics, constants,
|
|
||||||
// locals and type aliases. These capture all parent
|
|
||||||
// lifetimes, so they can use their identity subst.
|
|
||||||
GenericParamDefKind::Lifetime
|
|
||||||
if matches!(
|
|
||||||
origin,
|
|
||||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..)
|
|
||||||
) =>
|
|
||||||
{
|
|
||||||
tcx.lifetimes.re_static.into()
|
|
||||||
}
|
|
||||||
_ => tcx.mk_param_from_def(param),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
|
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
|
||||||
|
@ -2972,6 +2948,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
|
Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self, generate_err))]
|
||||||
fn validate_late_bound_regions(
|
fn validate_late_bound_regions(
|
||||||
&self,
|
&self,
|
||||||
constrained_regions: FxHashSet<ty::BoundRegionKind>,
|
constrained_regions: FxHashSet<ty::BoundRegionKind>,
|
||||||
|
|
|
@ -240,6 +240,7 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
|
||||||
}
|
}
|
||||||
check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
|
check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
|
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
|
||||||
/// in "inheriting lifetimes".
|
/// in "inheriting lifetimes".
|
||||||
#[instrument(level = "debug", skip(tcx, span))]
|
#[instrument(level = "debug", skip(tcx, span))]
|
||||||
|
@ -251,15 +252,19 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
|
||||||
let item = tcx.hir().expect_item(def_id);
|
let item = tcx.hir().expect_item(def_id);
|
||||||
debug!(?item, ?span);
|
debug!(?item, ?span);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct FoundParentLifetime;
|
struct FoundParentLifetime;
|
||||||
struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
|
struct FindParentLifetimeVisitor<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
parent_count: u32,
|
||||||
|
}
|
||||||
impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
|
impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
|
||||||
type BreakTy = FoundParentLifetime;
|
type BreakTy = FoundParentLifetime;
|
||||||
|
|
||||||
|
#[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> {
|
||||||
debug!("FindParentLifetimeVisitor: r={:?}", r);
|
|
||||||
if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r {
|
if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r {
|
||||||
if index < self.0.parent_count as u32 {
|
if index < self.parent_count {
|
||||||
return ControlFlow::Break(FoundParentLifetime);
|
return ControlFlow::Break(FoundParentLifetime);
|
||||||
} else {
|
} else {
|
||||||
return ControlFlow::CONTINUE;
|
return ControlFlow::CONTINUE;
|
||||||
|
@ -269,6 +274,63 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
|
||||||
r.super_visit_with(self)
|
r.super_visit_with(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self), ret)]
|
||||||
|
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
// We're only interested in types involving regions
|
||||||
|
if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
|
||||||
|
return ControlFlow::CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
match ty.kind() {
|
||||||
|
ty::Closure(_, ref substs) => {
|
||||||
|
// Skip lifetime parameters of the enclosing item(s)
|
||||||
|
|
||||||
|
substs.as_closure().tupled_upvars_ty().visit_with(self)?;
|
||||||
|
substs.as_closure().sig_as_fn_ptr_ty().visit_with(self)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Generator(_, ref substs, _) => {
|
||||||
|
// Skip lifetime parameters of the enclosing item(s)
|
||||||
|
// Also skip the witness type, because that has no free regions.
|
||||||
|
|
||||||
|
substs.as_generator().tupled_upvars_ty().visit_with(self)?;
|
||||||
|
substs.as_generator().return_ty().visit_with(self)?;
|
||||||
|
substs.as_generator().yield_ty().visit_with(self)?;
|
||||||
|
substs.as_generator().resume_ty().visit_with(self)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Opaque(def_id, ref substs) => {
|
||||||
|
// Skip lifetime paramters that are not captures.
|
||||||
|
let variances = self.tcx.variances_of(*def_id);
|
||||||
|
|
||||||
|
for (v, s) in std::iter::zip(variances, substs.iter()) {
|
||||||
|
if *v != ty::Variance::Bivariant {
|
||||||
|
s.visit_with(self)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Projection(proj)
|
||||||
|
if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
|
||||||
|
{
|
||||||
|
// Skip lifetime paramters that are not captures.
|
||||||
|
let variances = self.tcx.variances_of(proj.item_def_id);
|
||||||
|
|
||||||
|
for (v, s) in std::iter::zip(variances, proj.substs.iter()) {
|
||||||
|
if *v != ty::Variance::Bivariant {
|
||||||
|
s.visit_with(self)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
ty.super_visit_with(self)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlFlow::CONTINUE
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
if let ty::ConstKind::Unevaluated(..) = c.kind() {
|
if let ty::ConstKind::Unevaluated(..) = c.kind() {
|
||||||
// FIXME(#72219) We currently don't detect lifetimes within substs
|
// FIXME(#72219) We currently don't detect lifetimes within substs
|
||||||
|
@ -291,11 +353,14 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
|
||||||
type BreakTy = Ty<'tcx>;
|
type BreakTy = Ty<'tcx>;
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
|
debug!(?t, "root_visit_ty");
|
||||||
if t == self.opaque_identity_ty {
|
if t == self.opaque_identity_ty {
|
||||||
ControlFlow::CONTINUE
|
ControlFlow::CONTINUE
|
||||||
} else {
|
} else {
|
||||||
t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
|
t.visit_with(&mut FindParentLifetimeVisitor {
|
||||||
|
tcx: self.tcx,
|
||||||
|
parent_count: self.generics.parent_count as u32,
|
||||||
|
})
|
||||||
.map_break(|FoundParentLifetime| t)
|
.map_break(|FoundParentLifetime| t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,14 +394,18 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
|
||||||
|
|
||||||
if let ItemKind::OpaqueTy(hir::OpaqueTy {
|
if let ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
|
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
|
||||||
|
in_trait,
|
||||||
..
|
..
|
||||||
}) = item.kind
|
}) = item.kind
|
||||||
{
|
{
|
||||||
|
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
||||||
|
let opaque_identity_ty = if in_trait {
|
||||||
|
tcx.mk_projection(def_id.to_def_id(), substs)
|
||||||
|
} else {
|
||||||
|
tcx.mk_opaque(def_id.to_def_id(), substs)
|
||||||
|
};
|
||||||
let mut visitor = ProhibitOpaqueVisitor {
|
let mut visitor = ProhibitOpaqueVisitor {
|
||||||
opaque_identity_ty: tcx.mk_opaque(
|
opaque_identity_ty,
|
||||||
def_id.to_def_id(),
|
|
||||||
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
|
|
||||||
),
|
|
||||||
generics: tcx.generics_of(def_id),
|
generics: tcx.generics_of(def_id),
|
||||||
tcx,
|
tcx,
|
||||||
selftys: vec![],
|
selftys: vec![],
|
||||||
|
@ -345,10 +414,6 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
|
||||||
.explicit_item_bounds(def_id)
|
.explicit_item_bounds(def_id)
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
|
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
|
||||||
debug!(
|
|
||||||
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}",
|
|
||||||
prohibit_opaque, visitor.opaque_identity_ty, visitor.generics
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(ty) = prohibit_opaque.break_value() {
|
if let Some(ty) = prohibit_opaque.break_value() {
|
||||||
visitor.visit_item(&item);
|
visitor.visit_item(&item);
|
||||||
|
|
|
@ -261,6 +261,7 @@ fn label_msg_span(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(tcx))]
|
||||||
pub fn unexpected_hidden_region_diagnostic<'tcx>(
|
pub fn unexpected_hidden_region_diagnostic<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
|
@ -332,32 +332,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
concrete_ty: Ty<'tcx>,
|
concrete_ty: Ty<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
let def_id = opaque_type_key.def_id;
|
|
||||||
|
|
||||||
let tcx = self.tcx;
|
|
||||||
|
|
||||||
let concrete_ty = self.resolve_vars_if_possible(concrete_ty);
|
let concrete_ty = self.resolve_vars_if_possible(concrete_ty);
|
||||||
|
|
||||||
debug!(?concrete_ty);
|
debug!(?concrete_ty);
|
||||||
|
|
||||||
let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) {
|
let variances = self.tcx.variances_of(opaque_type_key.def_id);
|
||||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
|
debug!(?variances);
|
||||||
// We lower
|
|
||||||
//
|
|
||||||
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
|
|
||||||
//
|
|
||||||
// into
|
|
||||||
//
|
|
||||||
// type foo::<'p0..'pn>::Foo<'q0..'qm>
|
|
||||||
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
|
|
||||||
//
|
|
||||||
// For these types we only iterate over `'l0..lm` below.
|
|
||||||
tcx.generics_of(def_id).parent_count
|
|
||||||
}
|
|
||||||
// These opaque type inherit all lifetime parameters from their
|
|
||||||
// parent, so we have to check them all.
|
|
||||||
hir::OpaqueTyOrigin::TyAlias => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// For a case like `impl Foo<'a, 'b>`, we would generate a constraint
|
// For a case like `impl Foo<'a, 'b>`, we would generate a constraint
|
||||||
// `'r in ['a, 'b, 'static]` for each region `'r` that appears in the
|
// `'r in ['a, 'b, 'static]` for each region `'r` that appears in the
|
||||||
|
@ -370,9 +349,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
// type can be equal to any of the region parameters of the
|
// type can be equal to any of the region parameters of the
|
||||||
// opaque type definition.
|
// opaque type definition.
|
||||||
let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
|
let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
|
||||||
opaque_type_key.substs[first_own_region..]
|
opaque_type_key
|
||||||
|
.substs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|arg| match arg.unpack() {
|
.enumerate()
|
||||||
|
.filter(|(i, _)| variances[*i] == ty::Variance::Invariant)
|
||||||
|
.filter_map(|(_, arg)| match arg.unpack() {
|
||||||
GenericArgKind::Lifetime(r) => Some(r),
|
GenericArgKind::Lifetime(r) => Some(r),
|
||||||
GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
|
GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
|
||||||
})
|
})
|
||||||
|
@ -381,6 +363,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
);
|
);
|
||||||
|
|
||||||
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
|
||||||
|
tcx: self.tcx,
|
||||||
op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
|
op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -440,11 +423,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
//
|
//
|
||||||
// We ignore any type parameters because impl trait values are assumed to
|
// We ignore any type parameters because impl trait values are assumed to
|
||||||
// capture all the in-scope type parameters.
|
// capture all the in-scope type parameters.
|
||||||
struct ConstrainOpaqueTypeRegionVisitor<OP> {
|
struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
op: OP,
|
op: OP,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
|
impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
|
||||||
where
|
where
|
||||||
OP: FnMut(ty::Region<'tcx>),
|
OP: FnMut(ty::Region<'tcx>),
|
||||||
{
|
{
|
||||||
|
@ -490,6 +474,31 @@ where
|
||||||
substs.as_generator().yield_ty().visit_with(self);
|
substs.as_generator().yield_ty().visit_with(self);
|
||||||
substs.as_generator().resume_ty().visit_with(self);
|
substs.as_generator().resume_ty().visit_with(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ty::Opaque(def_id, ref substs) => {
|
||||||
|
// Skip lifetime paramters that are not captures.
|
||||||
|
let variances = self.tcx.variances_of(*def_id);
|
||||||
|
|
||||||
|
for (v, s) in std::iter::zip(variances, substs.iter()) {
|
||||||
|
if *v != ty::Variance::Bivariant {
|
||||||
|
s.visit_with(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Projection(proj)
|
||||||
|
if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
|
||||||
|
{
|
||||||
|
// Skip lifetime paramters that are not captures.
|
||||||
|
let variances = self.tcx.variances_of(proj.item_def_id);
|
||||||
|
|
||||||
|
for (v, s) in std::iter::zip(variances, proj.substs.iter()) {
|
||||||
|
if *v != ty::Variance::Bivariant {
|
||||||
|
s.visit_with(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
ty.super_visit_with(self);
|
ty.super_visit_with(self);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1338,8 +1338,8 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
|
||||||
// HACK: The HIR lowering for async fn does not generate
|
// HACK: The HIR lowering for async fn does not generate
|
||||||
// any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes
|
// any `+ Captures<'x>` bounds for the `impl Future<...>`, so all async fns with lifetimes
|
||||||
// would now fail to compile. We should probably just make hir lowering fill this in properly.
|
// would now fail to compile. We should probably just make hir lowering fill this in properly.
|
||||||
OpaqueTyOrigin::AsyncFn(_) => map.collect(),
|
OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::AsyncFn(_) => map.collect(),
|
||||||
OpaqueTyOrigin::FnReturn(_) | OpaqueTyOrigin::TyAlias => {
|
OpaqueTyOrigin::TyAlias => {
|
||||||
// Opaque types may only use regions that are bound. So for
|
// Opaque types may only use regions that are bound. So for
|
||||||
// ```rust
|
// ```rust
|
||||||
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
|
// type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
|
||||||
|
|
|
@ -170,6 +170,26 @@ pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
|
||||||
tcx.mk_substs(params)
|
tcx.mk_substs(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(relation), ret)]
|
||||||
|
fn relate_opaque_item_substs<'tcx, R: TypeRelation<'tcx>>(
|
||||||
|
relation: &mut R,
|
||||||
|
def_id: DefId,
|
||||||
|
a_subst: SubstsRef<'tcx>,
|
||||||
|
b_subst: SubstsRef<'tcx>,
|
||||||
|
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
|
||||||
|
let tcx = relation.tcx();
|
||||||
|
let variances = tcx.variances_of(def_id);
|
||||||
|
debug!(?variances);
|
||||||
|
|
||||||
|
let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
|
||||||
|
let variance = variances[i];
|
||||||
|
let variance_info = ty::VarianceDiagInfo::default();
|
||||||
|
relation.relate_with_variance(variance, variance_info, a, b)
|
||||||
|
});
|
||||||
|
|
||||||
|
tcx.mk_substs(params)
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
|
impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
|
||||||
fn relate<R: TypeRelation<'tcx>>(
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
relation: &mut R,
|
relation: &mut R,
|
||||||
|
@ -561,7 +581,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
||||||
(&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
|
(&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
|
||||||
if a_def_id == b_def_id =>
|
if a_def_id == b_def_id =>
|
||||||
{
|
{
|
||||||
let substs = relate_substs(relation, a_substs, b_substs)?;
|
let substs = relate_opaque_item_substs(relation, a_def_id, a_substs, b_substs)?;
|
||||||
Ok(tcx.mk_opaque(a_def_id, substs))
|
Ok(tcx.mk_opaque(a_def_id, substs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue