From 59c4a92bafaf19e2d9039436294aa805d748ce0f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 22 Sep 2022 22:53:32 +0000 Subject: [PATCH 1/3] Resolve async fn signature even without body (in trait) --- compiler/rustc_resolve/src/late.rs | 5 +- .../ui/async-await/in-trait/issue-102138.rs | 46 +++++++++++++++++++ src/test/ui/async-await/issue-102138.rs | 46 +++++++++++++++++++ .../issue-69401-trait-fn-no-body-ty-local.rs | 2 +- ...sue-69401-trait-fn-no-body-ty-local.stderr | 6 +-- 5 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/async-await/in-trait/issue-102138.rs create mode 100644 src/test/ui/async-await/issue-102138.rs diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0aea90bb5aa..d38eca23ade 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -789,9 +789,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let previous_value = self.diagnostic_metadata.current_function; match fn_kind { // Bail if the function is foreign, and thus cannot validly have - // a body, or if there's no body for some other reason. - FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) - | FnKind::Fn(_, _, sig, _, generics, None) => { + // a body. + FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) => { self.visit_fn_header(&sig.header); self.visit_generics(generics); self.with_lifetime_rib( diff --git a/src/test/ui/async-await/in-trait/issue-102138.rs b/src/test/ui/async-await/in-trait/issue-102138.rs new file mode 100644 index 00000000000..f61b34ed99e --- /dev/null +++ b/src/test/ui/async-await/in-trait/issue-102138.rs @@ -0,0 +1,46 @@ +// check-pass +// edition:2021 + +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + +use std::future::Future; + +async fn yield_now() {} + +trait AsyncIterator { + type Item; + async fn next(&mut self) -> Option; +} + +struct YieldingRange { + counter: u32, + stop: u32, +} + +impl AsyncIterator for YieldingRange { + type Item = u32; + + async fn next(&mut self) -> Option { + if self.counter == self.stop { + None + } else { + let c = self.counter; + self.counter += 1; + yield_now().await; + Some(c) + } + } +} + +async fn async_main() { + let mut x = YieldingRange { counter: 0, stop: 10 }; + + while let Some(v) = x.next().await { + println!("Hi: {v}"); + } +} + +fn main() { + let _ = async_main(); +} diff --git a/src/test/ui/async-await/issue-102138.rs b/src/test/ui/async-await/issue-102138.rs new file mode 100644 index 00000000000..91a14523c63 --- /dev/null +++ b/src/test/ui/async-await/issue-102138.rs @@ -0,0 +1,46 @@ +// check-pass +// edition:2021 + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +use std::future::Future; + +async fn yield_now() {} + +trait AsyncIterator { + type Item; + async fn next(&mut self) -> Option; +} + +struct YieldingRange { + counter: u32, + stop: u32, +} + +impl AsyncIterator for YieldingRange { + type Item = u32; + + async fn next(&mut self) -> Option { + if self.counter == self.stop { + None + } else { + let c = self.counter; + self.counter += 1; + yield_now().await; + Some(c) + } + } +} + +async fn async_main() { + let mut x = YieldingRange { counter: 0, stop: 10 }; + + while let Some(v) = x.next().await { + println!("Hi: {v}"); + } +} + +fn main() { + let _ = async_main(); +} diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs index c377ecea94d..4ec4472cc9a 100644 --- a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs +++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs @@ -2,5 +2,5 @@ fn main() {} trait Foo { fn fn_with_type_named_same_as_local_in_param(b: b); - //~^ ERROR cannot find type `b` in this scope [E0412] + //~^ ERROR expected type, found local variable `b` } diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr index 109409d2731..c53028e9b2a 100644 --- a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr +++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr @@ -1,9 +1,9 @@ -error[E0412]: cannot find type `b` in this scope +error[E0573]: expected type, found local variable `b` --> $DIR/issue-69401-trait-fn-no-body-ty-local.rs:4:53 | LL | fn fn_with_type_named_same_as_local_in_param(b: b); - | ^ not found in this scope + | ^ not a type error: aborting due to previous error -For more information about this error, try `rustc --explain E0412`. +For more information about this error, try `rustc --explain E0573`. From 3d7e9a7b27c735a8eb2fe05781bb7b4331572983 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 Sep 2022 00:49:25 +0000 Subject: [PATCH 2/3] Only record extra lifetime params for async trait fn with no body --- compiler/rustc_resolve/src/late.rs | 78 ++++++++++--------- src/test/ui/async-await/issue-102138.rs | 46 ----------- .../issue-69401-trait-fn-no-body-ty-local.rs | 2 +- ...sue-69401-trait-fn-no-body-ty-local.stderr | 6 +- 4 files changed, 44 insertions(+), 88 deletions(-) delete mode 100644 src/test/ui/async-await/issue-102138.rs diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index d38eca23ade..558db003867 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -789,8 +789,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let previous_value = self.diagnostic_metadata.current_function; match fn_kind { // Bail if the function is foreign, and thus cannot validly have - // a body. - FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) => { + // a body, or if there's no body for some other reason. + FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) + | FnKind::Fn(_, _, sig, _, generics, None) => { self.visit_fn_header(&sig.header); self.visit_generics(generics); self.with_lifetime_rib( @@ -804,7 +805,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { sig.decl.has_self(), sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), &sig.decl.output, - ) + ); + + this.record_lifetime_params_for_async( + fn_id, + sig.header.asyncness.opt_return_id(), + ); }, ); return; @@ -846,41 +852,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { }, ); - // Construct the list of in-scope lifetime parameters for async lowering. - // We include all lifetime parameters, either named or "Fresh". - // The order of those parameters does not matter, as long as it is - // deterministic. - if let Some((async_node_id, _)) = async_node_id { - let mut extra_lifetime_params = this - .r - .extra_lifetime_params_map - .get(&fn_id) - .cloned() - .unwrap_or_default(); - for rib in this.lifetime_ribs.iter().rev() { - extra_lifetime_params.extend( - rib.bindings - .iter() - .map(|(&ident, &(node_id, res))| (ident, node_id, res)), - ); - match rib.kind { - LifetimeRibKind::Item => break, - LifetimeRibKind::AnonymousCreateParameter { - binder, .. - } => { - if let Some(earlier_fresh) = - this.r.extra_lifetime_params_map.get(&binder) - { - extra_lifetime_params.extend(earlier_fresh); - } - } - _ => {} - } - } - this.r - .extra_lifetime_params_map - .insert(async_node_id, extra_lifetime_params); - } + this.record_lifetime_params_for_async(fn_id, async_node_id); if let Some(body) = body { // Ignore errors in function bodies if this is rustdoc @@ -3925,6 +3897,36 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Some((ident.name, ns)), ) } + + /// Construct the list of in-scope lifetime parameters for async lowering. + /// We include all lifetime parameters, either named or "Fresh". + /// The order of those parameters does not matter, as long as it is + /// deterministic. + fn record_lifetime_params_for_async( + &mut self, + fn_id: NodeId, + async_node_id: Option<(NodeId, Span)>, + ) { + if let Some((async_node_id, _)) = async_node_id { + let mut extra_lifetime_params = + self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default(); + for rib in self.lifetime_ribs.iter().rev() { + extra_lifetime_params.extend( + rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)), + ); + match rib.kind { + LifetimeRibKind::Item => break, + LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { + if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { + extra_lifetime_params.extend(earlier_fresh); + } + } + _ => {} + } + } + self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params); + } + } } struct LifetimeCountVisitor<'a, 'b> { diff --git a/src/test/ui/async-await/issue-102138.rs b/src/test/ui/async-await/issue-102138.rs deleted file mode 100644 index 91a14523c63..00000000000 --- a/src/test/ui/async-await/issue-102138.rs +++ /dev/null @@ -1,46 +0,0 @@ -// check-pass -// edition:2021 - -#![feature(return_position_impl_trait_in_trait)] -#![allow(incomplete_features)] - -use std::future::Future; - -async fn yield_now() {} - -trait AsyncIterator { - type Item; - async fn next(&mut self) -> Option; -} - -struct YieldingRange { - counter: u32, - stop: u32, -} - -impl AsyncIterator for YieldingRange { - type Item = u32; - - async fn next(&mut self) -> Option { - if self.counter == self.stop { - None - } else { - let c = self.counter; - self.counter += 1; - yield_now().await; - Some(c) - } - } -} - -async fn async_main() { - let mut x = YieldingRange { counter: 0, stop: 10 }; - - while let Some(v) = x.next().await { - println!("Hi: {v}"); - } -} - -fn main() { - let _ = async_main(); -} diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs index 4ec4472cc9a..c377ecea94d 100644 --- a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs +++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs @@ -2,5 +2,5 @@ fn main() {} trait Foo { fn fn_with_type_named_same_as_local_in_param(b: b); - //~^ ERROR expected type, found local variable `b` + //~^ ERROR cannot find type `b` in this scope [E0412] } diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr index c53028e9b2a..109409d2731 100644 --- a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr +++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr @@ -1,9 +1,9 @@ -error[E0573]: expected type, found local variable `b` +error[E0412]: cannot find type `b` in this scope --> $DIR/issue-69401-trait-fn-no-body-ty-local.rs:4:53 | LL | fn fn_with_type_named_same_as_local_in_param(b: b); - | ^ not a type + | ^ not found in this scope error: aborting due to previous error -For more information about this error, try `rustc --explain E0573`. +For more information about this error, try `rustc --explain E0412`. From e87fcc026b4e31ffd352a035e58d78142c577dea Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 24 Sep 2022 19:04:25 +0000 Subject: [PATCH 3/3] Add test --- src/test/ui/resolve/name-collision-in-trait-fn-sig.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/ui/resolve/name-collision-in-trait-fn-sig.rs diff --git a/src/test/ui/resolve/name-collision-in-trait-fn-sig.rs b/src/test/ui/resolve/name-collision-in-trait-fn-sig.rs new file mode 100644 index 00000000000..fba4ffa1c6e --- /dev/null +++ b/src/test/ui/resolve/name-collision-in-trait-fn-sig.rs @@ -0,0 +1,11 @@ +// check-pass +// This is currently stable behavior, which was almost accidentally made an +// error in #102161 since there is no test exercising it. I am not sure if +// this _should_ be the desired behavior, but at least we should know if it +// changes. + +fn main() {} + +trait Foo { + fn fn_with_type_named_same_as_local_in_param(b: i32, b: i32); +}