Skip to content

Commit

Permalink
Rollup merge of #102161 - compiler-errors:issue-102138, r=tmandry
Browse files Browse the repository at this point in the history
Resolve async fn signature even without body (e.g., in trait)

Fixes #102138

This "bail if no body" behavior was introduced in #69539 to fix #69401, but that ICE does not reproduce any more. The error message changes a bit, but that's all, and I don't think it's a particularly diagnostic bad regression.
  • Loading branch information
matthiaskrgr authored Sep 25, 2022
2 parents 16de1fd + e87fcc0 commit 11b4510
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 36 deletions.
73 changes: 37 additions & 36 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,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;
Expand Down Expand Up @@ -847,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
Expand Down Expand Up @@ -3926,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> {
Expand Down
46 changes: 46 additions & 0 deletions src/test/ui/async-await/in-trait/issue-102138.rs
Original file line number Diff line number Diff line change
@@ -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<Self::Item>;
}

struct YieldingRange {
counter: u32,
stop: u32,
}

impl AsyncIterator for YieldingRange {
type Item = u32;

async fn next(&mut self) -> Option<Self::Item> {
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();
}
11 changes: 11 additions & 0 deletions src/test/ui/resolve/name-collision-in-trait-fn-sig.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 11b4510

Please sign in to comment.