diff --git a/Cargo.lock b/Cargo.lock index 06a2a36f4552b..683331d472468 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1956,9 +1956,9 @@ dependencies = [ [[package]] name = "libffi-sys" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc65067b78c0fc069771e8b9a9e02df71e08858bec92c1f101377c67b9dca7c7" +checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c" dependencies = [ "cc", ] diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 179453238f2cc..01b69966ca92c 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -27,6 +27,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use proc_macro::bridge::client::ProcMacro; +use std::error::Error; use std::ops::Fn; use std::path::Path; use std::time::Duration; @@ -1094,5 +1095,12 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result MirPass<'tcx> for ElaborateDrops { let reachable = traversal::reachable_as_bitset(body); + let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths); ElaborateDropsCtxt { tcx, body, env: &env, init_data: InitializationData { inits, uninits }, - drop_flags: Default::default(), + drop_flags, patch: MirPatch::new(body), un_derefer: un_derefer, reachable, @@ -293,7 +294,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> { body: &'a Body<'tcx>, env: &'a MoveDataParamEnv<'tcx>, init_data: InitializationData<'a, 'tcx>, - drop_flags: FxHashMap, + drop_flags: IndexVec>, patch: MirPatch<'tcx>, un_derefer: UnDerefer<'tcx>, reachable: BitSet, @@ -312,11 +313,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let tcx = self.tcx; let patch = &mut self.patch; debug!("create_drop_flag({:?})", self.body.span); - self.drop_flags.entry(index).or_insert_with(|| patch.new_internal(tcx.types.bool, span)); + self.drop_flags[index].get_or_insert_with(|| patch.new_internal(tcx.types.bool, span)); } fn drop_flag(&mut self, index: MovePathIndex) -> Option> { - self.drop_flags.get(&index).map(|t| Place::from(*t)) + self.drop_flags[index].map(Place::from) } /// create a patch that elaborates all drops in the input @@ -463,7 +464,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) { - if let Some(&flag) = self.drop_flags.get(&path) { + if let Some(flag) = self.drop_flags[path] { let span = self.patch.source_info_for_location(self.body, loc).span; let val = self.constant_bool(span, val.value()); self.patch.add_assign(loc, Place::from(flag), val); @@ -474,7 +475,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let loc = Location::START; let span = self.patch.source_info_for_location(self.body, loc).span; let false_ = self.constant_bool(span, false); - for flag in self.drop_flags.values() { + for flag in self.drop_flags.iter().flatten() { self.patch.add_assign(loc, Place::from(*flag), false_.clone()); } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a97857e05e2e9..5c02e7193a216 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -859,13 +859,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, 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(), - ); }, ); + self.record_lifetime_params_for_async(fn_id, sig.header.asyncness.opt_return_id()); return; } FnKind::Fn(..) => { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index bd52957d162f2..63a73f8d50d93 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -3,7 +3,8 @@ use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ - DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt, + DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, RegionVariableOrigin, + TyCtxtInferExt, }; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; @@ -223,18 +224,20 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { { debug!("rerunning goal to check result is stable"); let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); - let canonical_response = + let new_canonical_response = EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; - if !canonical_response.value.var_values.is_identity() { + if !new_canonical_response.value.var_values.is_identity() { bug!( "unstable result: re-canonicalized goal={canonical_goal:#?} \ - response={canonical_response:#?}" + first_response={canonical_response:#?} \ + second_response={new_canonical_response:#?}" ); } - if certainty != canonical_response.value.certainty { + if certainty != new_canonical_response.value.certainty { bug!( "unstable certainty: {certainty:#?} re-canonicalized goal={canonical_goal:#?} \ - response={canonical_response:#?}" + first_response={canonical_response:#?} \ + second_response={new_canonical_response:#?}" ); } } @@ -434,6 +437,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } + pub(super) fn next_region_infer(&self) -> ty::Region<'tcx> { + self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) + } + pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> { self.infcx.next_const_var( ty, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 226d29687e3a8..67ad7fb4bd21d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -16,7 +16,7 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData}; +use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData, MaybeCause}; use rustc_middle::ty::{self, BoundVar, GenericArgKind}; use rustc_span::DUMMY_SP; use std::iter; @@ -60,9 +60,27 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let certainty = certainty.unify_with(goals_certainty); - let external_constraints = self.compute_external_query_constraints()?; + let response = match certainty { + Certainty::Yes | Certainty::Maybe(MaybeCause::Ambiguity) => { + let external_constraints = self.compute_external_query_constraints()?; + Response { var_values: self.var_values, external_constraints, certainty } + } + Certainty::Maybe(MaybeCause::Overflow) => { + // If we have overflow, it's probable that we're substituting a type + // into itself infinitely and any partial substitutions in the query + // response are probably not useful anyways, so just return an empty + // query response. + // + // This may prevent us from potentially useful inference, e.g. + // 2 candidates, one ambiguous and one overflow, which both + // have the same inference constraints. + // + // Changing this to retain some constraints in the future + // won't be a breaking change, so this is good enough for now. + return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow)); + } + }; - let response = Response { var_values: self.var_values, external_constraints, certainty }; let canonical = Canonicalizer::canonicalize( self.infcx, CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, @@ -72,6 +90,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok(canonical) } + /// Constructs a totally unconstrained, ambiguous response to a goal. + /// + /// Take care when using this, since often it's useful to respond with + /// ambiguity but return constrained variables to guide inference. + pub(in crate::solve) fn make_ambiguous_response_no_constraints( + &self, + maybe_cause: MaybeCause, + ) -> CanonicalResponse<'tcx> { + let unconstrained_response = Response { + var_values: CanonicalVarValues { + var_values: self.tcx().mk_substs_from_iter(self.var_values.var_values.iter().map( + |arg| -> ty::GenericArg<'tcx> { + match arg.unpack() { + GenericArgKind::Lifetime(_) => self.next_region_infer().into(), + GenericArgKind::Type(_) => self.next_ty_infer().into(), + GenericArgKind::Const(ct) => self.next_const_infer(ct.ty()).into(), + } + }, + )), + }, + external_constraints: self + .tcx() + .mk_external_constraints(ExternalConstraintsData::default()), + certainty: Certainty::Maybe(maybe_cause), + }; + + Canonicalizer::canonicalize( + self.infcx, + CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, + &mut Default::default(), + unconstrained_response, + ) + } + #[instrument(level = "debug", skip(self), ret)] fn compute_external_query_constraints(&self) -> Result, NoSolution> { // Cannot use `take_registered_region_obligations` as we may compute the response diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 19bcbd461447d..d94679fef2833 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -340,17 +340,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { if responses.is_empty() { return Err(NoSolution); } - let certainty = responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| { - certainty.unify_with(response.value.certainty) - }); - - let response = self.evaluate_added_goals_and_make_canonical_response(certainty); - if let Ok(response) = response { - assert!(response.has_no_inference_or_external_constraints()); - Ok(response) - } else { - bug!("failed to make floundered response: {responses:?}"); - } + + let Certainty::Maybe(maybe_cause) = responses.iter().fold( + Certainty::AMBIGUOUS, + |certainty, response| { + certainty.unify_with(response.value.certainty) + }, + ) else { + bug!("expected flounder response to be ambiguous") + }; + + Ok(self.make_ambiguous_response_no_constraints(maybe_cause)) } } diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index afdc998172d35..efbbc1c2331cf 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1543,11 +1543,17 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { self.next_back() } - fn min(mut self) -> Option<(&'a K, &'a V)> { + fn min(mut self) -> Option<(&'a K, &'a V)> + where + (&'a K, &'a V): Ord, + { self.next() } - fn max(mut self) -> Option<(&'a K, &'a V)> { + fn max(mut self) -> Option<(&'a K, &'a V)> + where + (&'a K, &'a V): Ord, + { self.next_back() } } @@ -1612,11 +1618,17 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { self.next_back() } - fn min(mut self) -> Option<(&'a K, &'a mut V)> { + fn min(mut self) -> Option<(&'a K, &'a mut V)> + where + (&'a K, &'a mut V): Ord, + { self.next() } - fn max(mut self) -> Option<(&'a K, &'a mut V)> { + fn max(mut self) -> Option<(&'a K, &'a mut V)> + where + (&'a K, &'a mut V): Ord, + { self.next_back() } } @@ -1779,11 +1791,17 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { self.next_back() } - fn min(mut self) -> Option<&'a K> { + fn min(mut self) -> Option<&'a K> + where + &'a K: Ord, + { self.next() } - fn max(mut self) -> Option<&'a K> { + fn max(mut self) -> Option<&'a K> + where + &'a K: Ord, + { self.next_back() } } @@ -2008,11 +2026,17 @@ impl<'a, K, V> Iterator for Range<'a, K, V> { self.next_back() } - fn min(mut self) -> Option<(&'a K, &'a V)> { + fn min(mut self) -> Option<(&'a K, &'a V)> + where + (&'a K, &'a V): Ord, + { self.next() } - fn max(mut self) -> Option<(&'a K, &'a V)> { + fn max(mut self) -> Option<(&'a K, &'a V)> + where + (&'a K, &'a V): Ord, + { self.next_back() } } @@ -2081,11 +2105,17 @@ impl Iterator for IntoKeys { self.next_back() } - fn min(mut self) -> Option { + fn min(mut self) -> Option + where + K: Ord, + { self.next() } - fn max(mut self) -> Option { + fn max(mut self) -> Option + where + K: Ord, + { self.next_back() } } @@ -2204,11 +2234,17 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> { self.next_back() } - fn min(mut self) -> Option<(&'a K, &'a mut V)> { + fn min(mut self) -> Option<(&'a K, &'a mut V)> + where + (&'a K, &'a mut V): Ord, + { self.next() } - fn max(mut self) -> Option<(&'a K, &'a mut V)> { + fn max(mut self) -> Option<(&'a K, &'a mut V)> + where + (&'a K, &'a mut V): Ord, + { self.next_back() } } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index da952a13f1e91..940fa30afb80f 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1501,11 +1501,17 @@ impl<'a, T> Iterator for Iter<'a, T> { self.next_back() } - fn min(mut self) -> Option<&'a T> { + fn min(mut self) -> Option<&'a T> + where + &'a T: Ord, + { self.next() } - fn max(mut self) -> Option<&'a T> { + fn max(mut self) -> Option<&'a T> + where + &'a T: Ord, + { self.next_back() } } @@ -1604,11 +1610,17 @@ impl<'a, T> Iterator for Range<'a, T> { self.next_back() } - fn min(mut self) -> Option<&'a T> { + fn min(mut self) -> Option<&'a T> + where + &'a T: Ord, + { self.next() } - fn max(mut self) -> Option<&'a T> { + fn max(mut self) -> Option<&'a T> + where + &'a T: Ord, + { self.next_back() } } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 8916b42eda05e..896da37f94c02 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2815,7 +2815,7 @@ impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque { } #[inline] - fn extend_one(&mut self, &elem: &T) { + fn extend_one(&mut self, &elem: &'a T) { self.push_back(elem); } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 98c87b2c393ea..940558974e69b 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -248,7 +248,7 @@ where impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { type Error = TryFromSliceError; - fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> { + fn try_from(slice: &'a [T]) -> Result<&'a [T; N], TryFromSliceError> { if slice.len() == N { let ptr = slice.as_ptr() as *const [T; N]; // SAFETY: ok because we just checked that the length fits @@ -275,7 +275,7 @@ impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] { impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { type Error = TryFromSliceError; - fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> { + fn try_from(slice: &'a mut [T]) -> Result<&'a mut [T; N], TryFromSliceError> { if slice.len() == N { let ptr = slice.as_mut_ptr() as *mut [T; N]; // SAFETY: ok because we just checked that the length fits diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 37db074293d8c..0171d89812feb 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -732,12 +732,18 @@ impl Iterator for ops::Range { } #[inline] - fn min(mut self) -> Option { + fn min(mut self) -> Option + where + A: Ord, + { self.next() } #[inline] - fn max(mut self) -> Option { + fn max(mut self) -> Option + where + A: Ord, + { self.next_back() } @@ -1158,12 +1164,18 @@ impl Iterator for ops::RangeInclusive { } #[inline] - fn min(mut self) -> Option { + fn min(mut self) -> Option + where + A: Ord, + { self.next() } #[inline] - fn max(mut self) -> Option { + fn max(mut self) -> Option + where + A: Ord, + { self.next_back() } diff --git a/library/portable-simd/crates/core_simd/src/ops/deref.rs b/library/portable-simd/crates/core_simd/src/ops/deref.rs index 9883a74c92d67..302bf148bd3ef 100644 --- a/library/portable-simd/crates/core_simd/src/ops/deref.rs +++ b/library/portable-simd/crates/core_simd/src/ops/deref.rs @@ -71,7 +71,7 @@ macro_rules! deref_ops { #[inline] #[must_use = "operator returns a new vector without mutating the inputs"] - fn $call(self, rhs: &$simd) -> Self::Output { + fn $call(self, rhs: &'rhs $simd) -> Self::Output { (*self).$call(*rhs) } } diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff index d98f75e7502d4..46b450a4e47f7 100644 --- a/tests/mir-opt/issue_41888.main.ElaborateDrops.diff +++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff @@ -22,9 +22,9 @@ } bb0: { -+ _9 = const false; // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10 + _7 = const false; // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10 + _8 = const false; // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10 ++ _9 = const false; // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10 StorageLive(_1); // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10 StorageLive(_2); // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14 _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14 diff --git a/tests/ui/async-await/in-trait/nested-rpit.rs b/tests/ui/async-await/in-trait/nested-rpit.rs index 41d72ebb4d4c5..9cdc23bbc7809 100644 --- a/tests/ui/async-await/in-trait/nested-rpit.rs +++ b/tests/ui/async-await/in-trait/nested-rpit.rs @@ -1,7 +1,5 @@ // edition: 2021 -// known-bug: #105197 -// failure-status:101 -// dont-check-compiler-stderr +// check-pass #![feature(async_fn_in_trait)] #![feature(return_position_impl_trait_in_trait)] diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs new file mode 100644 index 0000000000000..0ecbca5c13bdd --- /dev/null +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs @@ -0,0 +1,48 @@ +// edition: 2021 +// known-bug: #110963 + +#![feature(return_type_notation)] +#![feature(async_fn_in_trait)] + +trait HealthCheck { + async fn check<'a: 'a>(&'a mut self) -> bool; +} + +async fn do_health_check_par(hc: HC) +where + HC: HealthCheck + Send + 'static, +{ + spawn(async move { + let mut hc = hc; + if !hc.check().await { + log_health_check_failure().await; + } + }); +} + +async fn log_health_check_failure() {} + +fn main() {} + +// Fake tokio spawn + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +fn spawn(future: F) -> JoinHandle +where + F: Future + Send + 'static, + F::Output: Send + 'static, +{ + loop {} +} + +struct JoinHandle; + +impl Future for JoinHandle { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + loop {} + } +} diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr new file mode 100644 index 0000000000000..b4a3924d8dab9 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr @@ -0,0 +1,45 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-110963-early.rs:4:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-110963-early.rs:5:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + +error: higher-ranked lifetime error + --> $DIR/issue-110963-early.rs:15:5 + | +LL | / spawn(async move { +LL | | let mut hc = hc; +LL | | if !hc.check().await { +LL | | log_health_check_failure().await; +LL | | } +LL | | }); + | |______^ + | + = note: could not prove `[async block@$DIR/issue-110963-early.rs:15:11: 20:6]: Send` + +error: higher-ranked lifetime error + --> $DIR/issue-110963-early.rs:15:5 + | +LL | / spawn(async move { +LL | | let mut hc = hc; +LL | | if !hc.check().await { +LL | | log_health_check_failure().await; +LL | | } +LL | | }); + | |______^ + | + = note: could not prove `[async block@$DIR/issue-110963-early.rs:15:11: 20:6]: Send` + +error: aborting due to 2 previous errors; 2 warnings emitted + diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.rs b/tests/ui/async-await/return-type-notation/issue-110963-late.rs new file mode 100644 index 0000000000000..2a35922eaa1b5 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.rs @@ -0,0 +1,50 @@ +// edition: 2021 +// check-pass + +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete +#![feature(async_fn_in_trait)] +//~^ WARN the feature `async_fn_in_trait` is incomplete + +trait HealthCheck { + async fn check(&mut self) -> bool; +} + +async fn do_health_check_par(hc: HC) +where + HC: HealthCheck + Send + 'static, +{ + spawn(async move { + let mut hc = hc; + if !hc.check().await { + log_health_check_failure().await; + } + }); +} + +async fn log_health_check_failure() {} + +fn main() {} + +// Fake tokio spawn + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +fn spawn(future: F) -> JoinHandle +where + F: Future + Send + 'static, + F::Output: Send + 'static, +{ + loop {} +} + +struct JoinHandle; + +impl Future for JoinHandle { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + loop {} + } +} diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.stderr b/tests/ui/async-await/return-type-notation/issue-110963-late.stderr new file mode 100644 index 0000000000000..36ef3ad0a4c82 --- /dev/null +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.stderr @@ -0,0 +1,19 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-110963-late.rs:4:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-110963-late.rs:6:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + +warning: 2 warnings emitted + diff --git a/tests/ui/traits/new-solver/exponential-trait-goals.rs b/tests/ui/traits/new-solver/exponential-trait-goals.rs new file mode 100644 index 0000000000000..b37f09ee185e9 --- /dev/null +++ b/tests/ui/traits/new-solver/exponential-trait-goals.rs @@ -0,0 +1,20 @@ +// compile-flags: -Ztrait-solver=next + +trait Trait {} + +struct W(T); + +impl Trait for W<(W, W)> +where + W: Trait, + W: Trait, +{ +} + +fn impls() {} + +fn main() { + impls::>(); + //~^ ERROR type annotations needed + //~| ERROR overflow evaluating the requirement `W<_>: Trait` +} diff --git a/tests/ui/traits/new-solver/exponential-trait-goals.stderr b/tests/ui/traits/new-solver/exponential-trait-goals.stderr new file mode 100644 index 0000000000000..28a99cbbca6a1 --- /dev/null +++ b/tests/ui/traits/new-solver/exponential-trait-goals.stderr @@ -0,0 +1,23 @@ +error[E0282]: type annotations needed + --> $DIR/exponential-trait-goals.rs:17:5 + | +LL | impls::>(); + | ^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls` + +error[E0275]: overflow evaluating the requirement `W<_>: Trait` + --> $DIR/exponential-trait-goals.rs:17:5 + | +LL | impls::>(); + | ^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`exponential_trait_goals`) +note: required by a bound in `impls` + --> $DIR/exponential-trait-goals.rs:14:13 + | +LL | fn impls() {} + | ^^^^^ required by this bound in `impls` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0275, E0282. +For more information about an error, try `rustc --explain E0275`.