diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 5920d12a93c..59aea2b2030 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -95,6 +95,45 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let (a, b) = if a_is_expected { (a, b) } else { (b, a) }; let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { ty::Opaque(def_id, substs) => { + let origin = if self.defining_use_anchor.is_some() { + // Check that this is `impl Trait` type is + // declared by `parent_def_id` -- i.e., one whose + // value we are inferring. At present, this is + // always true during the first phase of + // type-check, but not always true later on during + // NLL. Once we support named opaque types more fully, + // this same scenario will be able to arise during all phases. + // + // Here is an example using type alias `impl Trait` + // that indicates the distinction we are checking for: + // + // ```rust + // mod a { + // pub type Foo = impl Iterator; + // pub fn make_foo() -> Foo { .. } + // } + // + // mod b { + // fn foo() -> a::Foo { a::make_foo() } + // } + // ``` + // + // Here, the return type of `foo` references an + // `Opaque` indeed, but not one whose value is + // presently being inferred. You can get into a + // similar situation with closure return types + // today: + // + // ```rust + // fn foo() -> impl Iterator { .. } + // fn bar() { + // let x = || foo(); // returns the Opaque assoc with `foo` + // } + // ``` + self.opaque_type_origin(def_id, cause.span)? + } else { + self.opaque_ty_origin_unchecked(def_id, cause.span) + }; if let ty::Opaque(did2, _) = *b.kind() { // We could accept this, but there are various ways to handle this situation, and we don't // want to make a decision on it right now. Likely this case is so super rare anyway, that @@ -126,45 +165,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { cause.clone(), param_env, b, - if self.defining_use_anchor.is_some() { - // Check that this is `impl Trait` type is - // declared by `parent_def_id` -- i.e., one whose - // value we are inferring. At present, this is - // always true during the first phase of - // type-check, but not always true later on during - // NLL. Once we support named opaque types more fully, - // this same scenario will be able to arise during all phases. - // - // Here is an example using type alias `impl Trait` - // that indicates the distinction we are checking for: - // - // ```rust - // mod a { - // pub type Foo = impl Iterator; - // pub fn make_foo() -> Foo { .. } - // } - // - // mod b { - // fn foo() -> a::Foo { a::make_foo() } - // } - // ``` - // - // Here, the return type of `foo` references an - // `Opaque` indeed, but not one whose value is - // presently being inferred. You can get into a - // similar situation with closure return types - // today: - // - // ```rust - // fn foo() -> impl Iterator { .. } - // fn bar() { - // let x = || foo(); // returns the Opaque assoc with `foo` - // } - // ``` - self.opaque_type_origin(def_id, cause.span)? - } else { - self.opaque_ty_origin_unchecked(def_id, cause.span) - }, + origin, )) } _ => None, diff --git a/src/test/ui/impl-trait/async_scope_creep.rs b/src/test/ui/impl-trait/async_scope_creep.rs new file mode 100644 index 00000000000..7a9d64d339f --- /dev/null +++ b/src/test/ui/impl-trait/async_scope_creep.rs @@ -0,0 +1,28 @@ +#![feature(type_alias_impl_trait)] +// edition:2021 +// check-pass + +struct Pending {} + +struct CantOpen {} + +trait AsyncRead {} + +impl AsyncRead for i32 {} + +type PendingReader<'a> = impl AsyncRead + 'a; + +type OpeningReadFuture<'a> = + impl std::future::Future, CantOpen>>; + +impl Pending { + async fn read(&mut self) -> Result { + Ok(42) + } + + fn read_fut(&mut self) -> OpeningReadFuture<'_> { + self.read() + } +} + +fn main() {}