diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 485be4c9987..9ba85e58018 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -540,6 +540,7 @@ impl<'tcx> TyCtxt<'tcx> { expanded_cache: FxHashMap::default(), primary_def_id: Some(def_id), found_recursion: false, + found_any_recursion: false, check_recursion: true, tcx: self, }; @@ -560,6 +561,7 @@ struct OpaqueTypeExpander<'tcx> { expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>, primary_def_id: Option, found_recursion: bool, + found_any_recursion: bool, /// Whether or not to check for recursive opaque types. /// This is `true` when we're explicitly checking for opaque type /// recursion, and 'false' otherwise to avoid unnecessary work. @@ -569,7 +571,7 @@ struct OpaqueTypeExpander<'tcx> { impl<'tcx> OpaqueTypeExpander<'tcx> { fn expand_opaque_ty(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option> { - if self.found_recursion { + if self.found_any_recursion { return None; } let substs = substs.fold_with(self); @@ -591,6 +593,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { } else { // If another opaque type that we contain is recursive, then it // will report the error, so we don't have to. + self.found_any_recursion = true; self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap(); None } @@ -1078,6 +1081,7 @@ pub fn normalize_opaque_types( expanded_cache: FxHashMap::default(), primary_def_id: None, found_recursion: false, + found_any_recursion: false, check_recursion: false, tcx, }; diff --git a/src/test/ui/impl-trait/issue-87450.rs b/src/test/ui/impl-trait/issue-87450.rs new file mode 100644 index 00000000000..983ef7cfbe0 --- /dev/null +++ b/src/test/ui/impl-trait/issue-87450.rs @@ -0,0 +1,16 @@ +fn bar() -> impl Fn() { + wrap(wrap(wrap(wrap(foo())))) +} + +fn foo() -> impl Fn() { + //~^ WARNING 5:1: 5:22: function cannot return without recursing [unconditional_recursion] + //~| ERROR 5:13: 5:22: cannot resolve opaque type [E0720] + wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) +} + +fn wrap(f: impl Fn()) -> impl Fn() { + move || f() +} + +fn main() { +} diff --git a/src/test/ui/impl-trait/issue-87450.stderr b/src/test/ui/impl-trait/issue-87450.stderr new file mode 100644 index 00000000000..83eb33efc6b --- /dev/null +++ b/src/test/ui/impl-trait/issue-87450.stderr @@ -0,0 +1,27 @@ +warning: function cannot return without recursing + --> $DIR/issue-87450.rs:5:1 + | +LL | fn foo() -> impl Fn() { + | ^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +... +LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) + | ----- 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-87450.rs:5:13 + | +LL | fn foo() -> impl Fn() { + | ^^^^^^^^^ recursive opaque type +... +LL | wrap(wrap(wrap(wrap(wrap(wrap(wrap(foo()))))))) + | ----------------------------------------------- returning here with type `impl Fn<()>` +... +LL | fn wrap(f: impl Fn()) -> impl Fn() { + | --------- returning this opaque type `impl Fn<()>` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0720`.