From 71f8fd5c5859fa09587486351f849277a910e4d9 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 19 Sep 2022 14:59:52 +0200 Subject: [PATCH 1/8] improve infer var handling for implied bounds --- .../rustc_infer/src/infer/outlives/env.rs | 2 + .../src/traits/outlives_bounds.rs | 3 +- .../src/implied_outlives_bounds.rs | 69 ++++++++++--------- .../rustc_typeck/src/check/compare_method.rs | 1 + 4 files changed, 41 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 872886da36261..9922b156ebf96 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -53,6 +53,7 @@ pub struct OutlivesEnvironment<'tcx> { } /// Builder of OutlivesEnvironment. +#[derive(Debug)] struct OutlivesEnvironmentBuilder<'tcx> { param_env: ty::ParamEnv<'tcx>, region_relation: TransitiveRelationBuilder>, @@ -109,6 +110,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> { #[inline] + #[instrument(level = "debug")] fn build(self) -> OutlivesEnvironment<'tcx> { OutlivesEnvironment { param_env: self.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index a4b540182280b..3008dfcadde9e 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -46,7 +46,7 @@ impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> { /// Note that this may cause outlives obligations to be injected /// into the inference context with this body-id. /// - `ty`, the type that we are supposed to assume is WF. - #[instrument(level = "debug", skip(self, param_env, body_id))] + #[instrument(level = "debug", skip(self, param_env, body_id), ret)] fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, @@ -71,6 +71,7 @@ impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> { let TypeOpOutput { output, constraints, .. } = result; if let Some(constraints) = constraints { + debug!(?constraints); // Instantiation may have produced new inference variables and constraints on those // variables. Process these constraints. let mut fulfill_cx = >::new(self.tcx); diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index e3e78f70b15ef..691b79f10533d 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -49,7 +49,8 @@ fn compute_implied_outlives_bounds<'tcx>( let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); let mut wf_args = vec![ty.into()]; - let mut implied_bounds = vec![]; + let mut outlives_bounds: Vec, ty::Region<'tcx>>> = + vec![]; let mut fulfill_cx = >::new(tcx); @@ -65,30 +66,17 @@ fn compute_implied_outlives_bounds<'tcx>( // than the ultimate set. (Note: normally there won't be // unresolved inference variables here anyway, but there might be // during typeck under some circumstances.) + // + // FIXME(@lcnr): It's not really "always fine", having fewer implied + // bounds can be backward incompatible, e.g. #101951 was caused by + // us not dealing with inference vars in `TypeOutlives` predicates. let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) .unwrap_or_default(); - // N.B., all of these predicates *ought* to be easily proven - // true. In fact, their correctness is (mostly) implied by - // other parts of the program. However, in #42552, we had - // an annoying scenario where: - // - // - Some `T::Foo` gets normalized, resulting in a - // variable `_1` and a `T: Trait` constraint - // (not sure why it couldn't immediately get - // solved). This result of `_1` got cached. - // - These obligations were dropped on the floor here, - // rather than being registered. - // - Then later we would get a request to normalize - // `T::Foo` which would result in `_1` being used from - // the cache, but hence without the `T: Trait` - // constraint. As a result, `_1` never gets resolved, - // and we get an ICE (in dropck). - // - // Therefore, we register any predicates involving - // inference variables. We restrict ourselves to those - // involving inference variables both for efficiency and - // to avoids duplicate errors that otherwise show up. + // While these predicates should all be implied by other parts of + // the program, they are still relevant as they may constrain + // inference variables, which is necessary to add the correct + // implied bounds in some cases, mostly when dealing with projections. fulfill_cx.register_predicate_obligations( infcx, obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(), @@ -96,10 +84,10 @@ fn compute_implied_outlives_bounds<'tcx>( // From the full set of obligations, just filter down to the // region relationships. - implied_bounds.extend(obligations.into_iter().flat_map(|obligation| { + outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| { assert!(!obligation.has_escaping_bound_vars()); match obligation.predicate.kind().no_bound_vars() { - None => vec![], + None => None, Some(pred) => match pred { ty::PredicateKind::Trait(..) | ty::PredicateKind::Subtype(..) @@ -109,21 +97,18 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![], + | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::WellFormed(arg) => { wf_args.push(arg); - vec![] + None } ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { - vec![OutlivesBound::RegionSubRegion(r_b, r_a)] + Some(ty::OutlivesPredicate(r_a.into(), r_b)) } ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = infcx.resolve_vars_if_possible(ty_a); - let mut components = smallvec![]; - push_outlives_components(tcx, ty_a, &mut components); - implied_bounds_from_components(r_b, components) + Some(ty::OutlivesPredicate(ty_a.into(), r_b)) } }, } @@ -133,9 +118,27 @@ fn compute_implied_outlives_bounds<'tcx>( // Ensure that those obligations that we had to solve // get solved *here*. match fulfill_cx.select_all_or_error(infcx).as_slice() { - [] => Ok(implied_bounds), - _ => Err(NoSolution), + [] => (), + _ => return Err(NoSolution), } + + // We lazily compute the outlives components as + // `select_all_or_error` constrains inference variables. + let implied_bounds = outlives_bounds + .into_iter() + .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { + ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], + ty::GenericArgKind::Type(ty_a) => { + let ty_a = infcx.resolve_vars_if_possible(ty_a); + let mut components = smallvec![]; + push_outlives_components(tcx, ty_a, &mut components); + implied_bounds_from_components(r_b, components) + } + ty::GenericArgKind::Const(_) => unreachable!(), + }) + .collect(); + + Ok(implied_bounds) } /// When we have an implied bound that `T: 'a`, we can further break diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 0c6d8f26f1d63..59d591acdc445 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -140,6 +140,7 @@ pub(crate) fn compare_impl_method<'tcx>( /// /// Finally we register each of these predicates as an obligation and check that /// they hold. +#[instrument(level = "debug", skip(tcx, impl_m_span, impl_trait_ref))] fn compare_predicate_entailment<'tcx>( tcx: TyCtxt<'tcx>, impl_m: &AssocItem, From 72a21027f5bee367bd9ccbeecc2528986f85d90b Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 19 Sep 2022 15:07:01 +0200 Subject: [PATCH 2/8] add test --- src/test/ui/implied-bounds/issue-101951.rs | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/test/ui/implied-bounds/issue-101951.rs diff --git a/src/test/ui/implied-bounds/issue-101951.rs b/src/test/ui/implied-bounds/issue-101951.rs new file mode 100644 index 0000000000000..108fef8a15fb3 --- /dev/null +++ b/src/test/ui/implied-bounds/issue-101951.rs @@ -0,0 +1,50 @@ +// Taken directly from that issue. +// +// This test detected that we didn't correctly resolve +// inference variables when computing implied bounds. +// +// check-pass +pub trait BuilderFn<'a> { + type Output; +} + +impl<'a, F, Out> BuilderFn<'a> for F +where + F: FnOnce(&'a mut ()) -> Out, +{ + type Output = Out; +} + +pub trait ConstructionFirm { + type Builder: for<'a> BuilderFn<'a>; +} + +pub trait Campus +where + T: ConstructionFirm, +{ + fn add_building( + &mut self, + building: &mut <::Builder as BuilderFn<'_>>::Output, + ); +} + +struct ArchitectsInc {} + +impl ConstructionFirm for ArchitectsInc { + type Builder = fn(&mut ()) -> PrettyCondo<'_>; +} + +struct PrettyCondo<'a> { + _marker: &'a mut (), +} + +struct CondoEstate {} + +impl Campus for CondoEstate { + fn add_building(&mut self, _building: &mut PrettyCondo<'_>) { + todo!() + } +} + +fn main() {} From 3d01d43d488553d5fe8391564de36eed8659ca4c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 23 Sep 2022 18:04:15 -0700 Subject: [PATCH 3/8] rustdoc: Stabilize --diagnostic-width --- src/librustdoc/lib.rs | 2 +- src/test/rustdoc-ui/diagnostic-width.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 14d695582b0f8..23ad0c30f21ed 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -461,7 +461,7 @@ fn opts() -> Vec { "human|json|short", ) }), - unstable("diagnostic-width", |o| { + stable("diagnostic-width", |o| { o.optopt( "", "diagnostic-width", diff --git a/src/test/rustdoc-ui/diagnostic-width.rs b/src/test/rustdoc-ui/diagnostic-width.rs index 61961d5ec710e..290d9db775b73 100644 --- a/src/test/rustdoc-ui/diagnostic-width.rs +++ b/src/test/rustdoc-ui/diagnostic-width.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zunstable-options --diagnostic-width=10 +// compile-flags: --diagnostic-width=10 #![deny(rustdoc::bare_urls)] /// This is a long line that contains a http://link.com From a0be6c49c89556c9d596c9f430ced9d61c16e6d2 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 24 Sep 2022 10:03:59 -0700 Subject: [PATCH 4/8] rustdoc: remove unused CSS `#main-content > .line-numbers` This selector was added in 10b937028660e079cf15735cfb5c4d58892fb10e. It became unreachable when 09150f81930e035254e58ee56f5905c2eb421617 made it so that `.line-numbers` are always nested below `.example-wrap`, even on source pages. --- src/librustdoc/html/static/css/rustdoc.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4136cb6cab33a..8691d60821504 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1917,10 +1917,6 @@ in storage.js plus the media query with (min-width: 701px) border-bottom: 1px solid; } - #main-content > .line-numbers { - margin-top: 0; - } - .notable-traits .notable-traits-tooltiptext { left: 0; top: 100%; From 55b11cf15cfac6798bf87191c30406486f20d642 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 24 Sep 2022 10:51:37 -0700 Subject: [PATCH 5/8] rustdoc: remove unused CSS `.summary` It was added in 4d16de01d0beb84dc4a351022ea5cb587b4ab557 as part of a stability dashboard that was removed in 0a46933c4d81573e78ce16cd215ba155a3114fce. --- src/librustdoc/html/static/css/rustdoc.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4136cb6cab33a..645f0454aa27d 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1130,10 +1130,6 @@ so that we can apply CSS-filters to change the arrow color in themes */ font-size: 1rem; } -.summary { - padding-right: 0px; -} - pre.rust .question-mark { font-weight: bold; } From 59c4a92bafaf19e2d9039436294aa805d748ce0f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 22 Sep 2022 22:53:32 +0000 Subject: [PATCH 6/8] 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 0aea90bb5aaf3..d38eca23ade10 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 0000000000000..f61b34ed99e00 --- /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 0000000000000..91a14523c63b2 --- /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 c377ecea94d0c..4ec4472cc9aea 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 109409d2731c5..c53028e9b2ad7 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 7/8] 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 d38eca23ade10..558db003867d2 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 91a14523c63b2..0000000000000 --- 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 4ec4472cc9aea..c377ecea94d0c 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 c53028e9b2ad7..109409d2731c5 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 8/8] 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 0000000000000..fba4ffa1c6ed2 --- /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); +}