diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index bab4f3e9e36..324aef9c01f 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -396,6 +396,32 @@ where generalizer.relate(value, value) } + + fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; + let mut generalize = |ty, ty_is_expected| { + let var = self.infcx.next_ty_var_id_in_universe( + TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: self.delegate.span(), + }, + ty::UniverseIndex::ROOT, + ); + if ty_is_expected { + self.relate_ty_var((ty, var)) + } else { + self.relate_ty_var((var, ty)) + } + }; + let (a, b) = match (a.kind(), b.kind()) { + (&ty::Opaque(..), _) => (a, generalize(b, false)?), + (_, &ty::Opaque(..)) => (generalize(a, true)?, b), + _ => unreachable!(), + }; + self.delegate.register_opaque_type(a, b, true)?; + trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); + Ok(a) + } } /// When we instantiate an inference variable with a value in @@ -572,32 +598,12 @@ where (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)), (&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => { - self.infcx.super_combine_tys(self, a, b) + infcx.commit_if_ok(|_| infcx.super_combine_tys(self, a, b)).or_else(|err| { + if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } + }) } (&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => { - let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) }; - let mut generalize = |ty, ty_is_expected| { - let var = infcx.next_ty_var_id_in_universe( - TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: self.delegate.span(), - }, - ty::UniverseIndex::ROOT, - ); - if ty_is_expected { - self.relate_ty_var((ty, var)) - } else { - self.relate_ty_var((var, ty)) - } - }; - let (a, b) = match (a.kind(), b.kind()) { - (&ty::Opaque(..), _) => (a, generalize(b, false)?), - (_, &ty::Opaque(..)) => (generalize(a, true)?, b), - _ => unreachable!(), - }; - self.delegate.register_opaque_type(a, b, true)?; - trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated"); - Ok(a) + self.relate_opaques(a, b) } (&ty::Projection(projection_ty), _) diff --git a/src/test/ui/impl-trait/issue-100075-2.rs b/src/test/ui/impl-trait/issue-100075-2.rs new file mode 100644 index 00000000000..cf059af1925 --- /dev/null +++ b/src/test/ui/impl-trait/issue-100075-2.rs @@ -0,0 +1,8 @@ +fn opaque(t: T) -> impl Sized { + //~^ ERROR cannot resolve opaque type + //~| WARNING function cannot return without recursing + opaque(Some(t)) +} + +#[allow(dead_code)] +fn main() {} diff --git a/src/test/ui/impl-trait/issue-100075-2.stderr b/src/test/ui/impl-trait/issue-100075-2.stderr new file mode 100644 index 00000000000..5a1f1a97d04 --- /dev/null +++ b/src/test/ui/impl-trait/issue-100075-2.stderr @@ -0,0 +1,24 @@ +warning: function cannot return without recursing + --> $DIR/issue-100075-2.rs:1:1 + | +LL | fn opaque(t: T) -> impl Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +... +LL | opaque(Some(t)) + | --------------- recursive call site + | + = note: `#[warn(unconditional_recursion)]` on by default + = help: a `loop` may express intention better if this is on purpose + +error[E0720]: cannot resolve opaque type + --> $DIR/issue-100075-2.rs:1:23 + | +LL | fn opaque(t: T) -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | opaque(Some(t)) + | --------------- returning here with type `impl Sized` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0720`. diff --git a/src/test/ui/impl-trait/issue-100075.rs b/src/test/ui/impl-trait/issue-100075.rs new file mode 100644 index 00000000000..ea30abb4855 --- /dev/null +++ b/src/test/ui/impl-trait/issue-100075.rs @@ -0,0 +1,21 @@ +trait Marker {} +impl Marker for T {} + +fn maybe( + _t: T, +) -> Option< + //removing the line below makes it compile + &'static T, +> { + None +} + +fn _g(t: &'static T) -> &'static impl Marker { + //~^ ERROR cannot resolve opaque type + if let Some(t) = maybe(t) { + return _g(t); + } + todo!() +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-100075.stderr b/src/test/ui/impl-trait/issue-100075.stderr new file mode 100644 index 00000000000..267ecfdaed1 --- /dev/null +++ b/src/test/ui/impl-trait/issue-100075.stderr @@ -0,0 +1,12 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/issue-100075.rs:13:37 + | +LL | fn _g(t: &'static T) -> &'static impl Marker { + | ^^^^^^^^^^^ recursive opaque type +... +LL | return _g(t); + | ----- returning here with type `&impl Marker` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`.