diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4f7c1fc96f13f..ca6b01d8a8a7a 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer /// may not have an address. /// - /// If `ptr` does have a known address, then we return `CONTINUE` and the function call should + /// If `ptr` does have a known address, then we return `Continue(())` and the function call should /// proceed as normal. /// /// If `ptr` doesn't have an address, but its underlying allocation's alignment is at most @@ -273,18 +273,18 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> { ret, StackPopUnwind::NotAllowed, )?; - Ok(ControlFlow::BREAK) + Ok(ControlFlow::Break(())) } else { // Not alignable in const, return `usize::MAX`. let usize_max = Scalar::from_machine_usize(self.machine_usize_max(), self); self.write_scalar(usize_max, dest)?; self.return_to_block(ret)?; - Ok(ControlFlow::BREAK) + Ok(ControlFlow::Break(())) } } Err(_addr) => { // The pointer has an address, continue with function call. - Ok(ControlFlow::CONTINUE) + Ok(ControlFlow::Continue(())) } } } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index a61d3ab40a5ca..cabc65e2c077e 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -26,7 +26,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.needs_subst() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match *ty.kind() { @@ -48,7 +48,7 @@ where return subst.visit_with(self); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => ty.super_visit_with(self), } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 46e7b09a55e10..57b91df2d0708 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -6,7 +6,6 @@ Rust MIR: a lowered representation of Rust. #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(decl_macro)] #![feature(exact_size_is_empty)] #![feature(let_chains)] diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 57007611a76c3..8a9af300c066e 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -317,12 +317,12 @@ where _node: G::Node, _prior_status: Option, ) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } /// Called after all nodes reachable from this one have been examined. fn node_settled(&mut self, _node: G::Node) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } /// Behave as if no edges exist from `source` to `target`. @@ -346,8 +346,8 @@ where prior_status: Option, ) -> ControlFlow { match prior_status { - Some(NodeStatus::Visited) => ControlFlow::BREAK, - _ => ControlFlow::CONTINUE, + Some(NodeStatus::Visited) => ControlFlow::Break(()), + _ => ControlFlow::Continue(()), } } } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 3a2000233c5d1..954e84c303b83 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -11,7 +11,6 @@ #![feature(associated_type_bounds)] #![feature(auto_traits)] #![feature(cell_leak)] -#![feature(control_flow_enum)] #![feature(extend_one)] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3474fab34f00b..54fa5702fbca4 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -291,6 +291,7 @@ language_item_table! { IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None; GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None; + Context, sym::Context, context, Target::Struct, GenericRequirement::None; FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e58669433e218..d5e4b4cb9e728 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -267,7 +267,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { debug!(?t, "root_visit_ty"); if t == self.opaque_identity_ty { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { t.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { tcx: self.tcx, @@ -282,7 +282,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( if self.references_parent_regions { ControlFlow::Break(t) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -1439,7 +1439,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E match *t.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { self.0.push(def); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 49dd1eb22f7fe..8739228e207b0 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1428,7 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow { - ControlFlow::BREAK + ControlFlow::Break(()) } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 0aadc9f311b03..0d070f3d118e0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -416,13 +416,13 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: if t != self.self_ty_root { for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) { match tcx.impl_polarity(impl_def_id) { - ImplPolarity::Negative => return ControlFlow::BREAK, + ImplPolarity::Negative => return ControlFlow::Break(()), ImplPolarity::Reservation => {} // FIXME(@lcnr): That's probably not good enough, idk // // We might just want to take the rustdoc code and somehow avoid // explicit impls for `Self`. - ImplPolarity::Positive => return ControlFlow::CONTINUE, + ImplPolarity::Positive => return ControlFlow::Continue(()), } } } @@ -440,7 +440,7 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 95c971c0d7845..56cc1d8fadc00 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -61,7 +61,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { match *t.kind() { ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => { // projections are not injective - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::Param(data) => { self.parameters.push(Parameter::from(data)); @@ -76,7 +76,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { if let ty::ReEarlyBound(data) = *r { self.parameters.push(Parameter::from(data)); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 24008f8881433..079070be27983 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -92,7 +92,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc a.visit_with(self)?; } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { substs.visit_with(self) } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 26e8dd654c13f..12a2abfa76a92 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -236,7 +236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if t == self.expected_ty { - ControlFlow::BREAK + ControlFlow::Break(()) } else { t.super_visit_with(self) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index fb0f09198ccc1..49ad3ce50b8f5 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -543,7 +543,7 @@ impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { if let Some(def_id) = preds.principal_def_id() { self.0.insert(def_id); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 985cb6463a064..f235cb5ab4503 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -849,7 +849,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { t.super_visit_with(self); self.target_index.shift_out(1); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { @@ -863,7 +863,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { _ => {} } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 6b54ee9576f67..e22ba9785e1fd 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -440,16 +440,16 @@ where t: &ty::Binder<'tcx, T>, ) -> ControlFlow { t.super_visit_with(self); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { // ignore bound regions, keep visiting - ty::ReLateBound(_, _) => ControlFlow::CONTINUE, + ty::ReLateBound(_, _) => ControlFlow::Continue(()), _ => { (self.op)(r); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -457,7 +457,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { // We're only interested in types involving regions if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match ty.kind() { @@ -507,7 +507,7 @@ where } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 8671f8d45a917..65b90aa3d79d3 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { } else if !t.has_non_region_infer() { // All const/type variables in inference types must already be resolved, // no need to visit the contents. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { // Otherwise, keep visiting. t.super_visit_with(self) @@ -178,7 +178,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeOrConstFinder<'a, 'tcx> { } else if !ct.has_non_region_infer() { // All const/type variables in inference types must already be resolved, // no need to visit the contents. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { // Otherwise, keep visiting. ct.super_visit_with(self) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f2ab44ac97c83..be47a3e238c1c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1147,7 +1147,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.has_opaque_types() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } if let ty::Alias(ty::Opaque, ..) = ty.kind() { diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs index 14e6aa6e0c17b..1f95661ce9d5f 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -26,7 +26,7 @@ pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2: __visitor: &mut __V ) -> ::std::ops::ControlFlow<__V::BreakTy> { match *self { #body_visit } - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } }, ) diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 5ca4d260179ce..250f3d0797eb5 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -93,7 +93,7 @@ macro_rules! TrivialTypeTraversalImpls { _: &mut F) -> ::std::ops::ControlFlow { - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } } )+ @@ -219,7 +219,7 @@ macro_rules! EnumTypeTraversalImpl { $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } $($output)* ) @@ -237,7 +237,7 @@ macro_rules! EnumTypeTraversalImpl { $($crate::ty::visit::TypeVisitable::visit_with( $variant_arg, $visitor )?;)* - ::std::ops::ControlFlow::CONTINUE + ::std::ops::ControlFlow::Continue(()) } $($output)* ) @@ -251,7 +251,7 @@ macro_rules! EnumTypeTraversalImpl { @VisitVariants($this, $visitor) input($($input)*) output( - $variant => { ::std::ops::ControlFlow::CONTINUE } + $variant => { ::std::ops::ControlFlow::Continue(()) } $($output)* ) ) diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs index e7cd497b206a9..d44c6809bd830 100644 --- a/compiler/rustc_middle/src/mir/type_visitable.rs +++ b/compiler/rustc_middle/src/mir/type_visitable.rs @@ -4,6 +4,6 @@ use super::*; impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix { fn visit_with>(&self, _: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0c66443555fa4..ce04d8d21f4cd 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1952,6 +1952,15 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty(GeneratorWitness(types)) } + /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes. + pub fn mk_task_context(self) -> Ty<'tcx> { + let context_did = self.require_lang_item(LangItem::Context, None); + let context_adt_ref = self.adt_def(context_did); + let context_substs = self.intern_substs(&[self.lifetimes.re_erased.into()]); + let context_ty = self.mk_adt(context_adt_ref, context_substs); + self.mk_mut_ref(self.lifetimes.re_erased, context_ty) + } + #[inline] pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> { self.mk_ty_infer(TyVar(v)) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 771b63f59c124..4b4518f61e8d3 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -4,12 +4,13 @@ use std::ops::ControlFlow; use crate::ty::{ visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque, - PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, + PolyTraitPredicate, Projection, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::WherePredicate; use rustc_span::Span; @@ -443,7 +444,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - match t.kind() { + match *t.kind() { Infer(InferTy::TyVar(_)) if self.infer_suggestable => {} FnDef(..) @@ -458,9 +459,9 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } Alias(Opaque, AliasTy { def_id, .. }) => { - let parent = self.tcx.parent(*def_id); - if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent) - && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = self.tcx.type_of(parent).kind() + let parent = self.tcx.parent(def_id); + if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent) + && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *self.tcx.type_of(parent).kind() && parent_opaque_def_id == def_id { // Okay @@ -469,6 +470,12 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } } + Alias(Projection, AliasTy { def_id, .. }) => { + if self.tcx.def_kind(def_id) != DefKind::AssocTy { + return ControlFlow::Break(()); + } + } + Param(param) => { // FIXME: It would be nice to make this not use string manipulation, // but it's pretty hard to do this, since `ty::ParamTy` is missing diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ccac6e8f77a65..d681df14af10a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2357,6 +2357,11 @@ impl<'tcx> TyCtxt<'tcx> { self.trait_def(trait_def_id).has_auto_impl } + /// Returns `true` if this is a trait alias. + pub fn trait_is_alias(self, trait_def_id: DefId) -> bool { + self.def_kind(trait_def_id) == DefKind::TraitAlias + } + pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool { self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index aed7051bb993d..5576e53e6a74d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2468,7 +2468,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if not_previously_inserted { ty.super_visit_with(self) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 81ec18684fd85..7d4d35b7fdf94 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -367,7 +367,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> { impl<'tcx> TypeVisitable<'tcx> for ty::AdtDef<'tcx> { fn visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -714,7 +714,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { | ty::Placeholder(..) | ty::Param(..) | ty::Never - | ty::Foreign(..) => ControlFlow::CONTINUE, + | ty::Foreign(..) => ControlFlow::Continue(()), } } } @@ -742,7 +742,7 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> { impl<'tcx> TypeSuperVisitable<'tcx> for ty::Region<'tcx> { fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -844,7 +844,7 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> { fn visit_with>(&self, _visitor: &mut V) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 00225a60d8308..a128e9025fd69 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2011,7 +2011,7 @@ impl<'tcx> Ty<'tcx> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) } + if self.0 == t { ControlFlow::Break(()) } else { t.super_visit_with(self) } } } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index ca44555813138..bee3cc4d7cb9b 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -294,13 +294,13 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => { if (self.callback)(r) { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -311,7 +311,7 @@ impl<'tcx> TyCtxt<'tcx> { if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -394,7 +394,7 @@ impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { if t.outer_exclusive_binder() < self.binder_index || !self.visited.insert((self.binder_index, t)) { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { @@ -512,7 +512,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { if t.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -524,7 +524,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { if r.bound_at_or_above_binder(self.outer_index) { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -547,7 +547,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { if predicate.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -575,7 +575,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -585,7 +585,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -596,7 +596,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -605,7 +605,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { if predicate.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -653,7 +653,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // in the normalized form if self.just_constrained { if let ty::Alias(..) = t.kind() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } } @@ -666,7 +666,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // in the normalized form if self.just_constrained { if let ty::ConstKind::Unevaluated(..) = c.kind() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } } @@ -679,7 +679,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { self.regions.insert(br.kind); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -726,6 +726,6 @@ impl<'tcx> TypeVisitor<'tcx> for MaxUniverse { ); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index fb7ae6f1d2424..a428180a4fa82 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -5,7 +5,6 @@ #![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(box_patterns)] -#![feature(control_flow_enum)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(min_specialization)] diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index fac4997fcbf6d..f67f24b43c4d7 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -118,7 +118,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { // A diverging InlineAsm is treated as non-recursing TerminatorKind::InlineAsm { destination, .. } => { if destination.is_some() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ControlFlow::Break(NonRecursive) } @@ -132,7 +132,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE, + | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue(()), } } @@ -145,7 +145,7 @@ impl<'mir, 'tcx> TriColorVisitor> for Search<'mir, 'tcx> { } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index c097af6161159..39c61a34afcbd 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -460,6 +460,104 @@ fn replace_local<'tcx>( new_local } +/// Transforms the `body` of the generator applying the following transforms: +/// +/// - Eliminates all the `get_context` calls that async lowering created. +/// - Replace all `Local` `ResumeTy` types with `&mut Context<'_>` (`context_mut_ref`). +/// +/// The `Local`s that have their types replaced are: +/// - The `resume` argument itself. +/// - The argument to `get_context`. +/// - The yielded value of a `yield`. +/// +/// The `ResumeTy` hides a `&mut Context<'_>` behind an unsafe raw pointer, and the +/// `get_context` function is being used to convert that back to a `&mut Context<'_>`. +/// +/// Ideally the async lowering would not use the `ResumeTy`/`get_context` indirection, +/// but rather directly use `&mut Context<'_>`, however that would currently +/// lead to higher-kinded lifetime errors. +/// See . +/// +/// The async lowering step and the type / lifetime inference / checking are +/// still using the `ResumeTy` indirection for the time being, and that indirection +/// is removed here. After this transform, the generator body only knows about `&mut Context<'_>`. +fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let context_mut_ref = tcx.mk_task_context(); + + // replace the type of the `resume` argument + replace_resume_ty_local(tcx, body, Local::new(2), context_mut_ref); + + let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None); + + for bb in BasicBlock::new(0)..body.basic_blocks.next_index() { + let bb_data = &body[bb]; + if bb_data.is_cleanup { + continue; + } + + match &bb_data.terminator().kind { + TerminatorKind::Call { func, .. } => { + let func_ty = func.ty(body, tcx); + if let ty::FnDef(def_id, _) = *func_ty.kind() { + if def_id == get_context_def_id { + let local = eliminate_get_context_call(&mut body[bb]); + replace_resume_ty_local(tcx, body, local, context_mut_ref); + } + } else { + continue; + } + } + TerminatorKind::Yield { resume_arg, .. } => { + replace_resume_ty_local(tcx, body, resume_arg.local, context_mut_ref); + } + _ => {} + } + } +} + +fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local { + let terminator = bb_data.terminator.take().unwrap(); + if let TerminatorKind::Call { mut args, destination, target, .. } = terminator.kind { + let arg = args.pop().unwrap(); + let local = arg.place().unwrap().local; + + let arg = Rvalue::Use(arg); + let assign = Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new((destination, arg))), + }; + bb_data.statements.push(assign); + bb_data.terminator = Some(Terminator { + source_info: terminator.source_info, + kind: TerminatorKind::Goto { target: target.unwrap() }, + }); + local + } else { + bug!(); + } +} + +#[cfg_attr(not(debug_assertions), allow(unused))] +fn replace_resume_ty_local<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + local: Local, + context_mut_ref: Ty<'tcx>, +) { + let local_ty = std::mem::replace(&mut body.local_decls[local].ty, context_mut_ref); + // We have to replace the `ResumeTy` that is used for type and borrow checking + // with `&mut Context<'_>` in MIR. + #[cfg(debug_assertions)] + { + if let ty::Adt(resume_ty_adt, _) = local_ty.kind() { + let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + assert_eq!(*resume_ty_adt, expected_adt); + } else { + panic!("expected `ResumeTy`, found `{:?}`", local_ty); + }; + } +} + struct LivenessInfo { /// Which locals are live across any suspension point. saved_locals: GeneratorSavedLocals, @@ -1283,13 +1381,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform { } }; - let is_async_kind = body.generator_kind().unwrap() != GeneratorKind::Gen; + let is_async_kind = matches!(body.generator_kind(), Some(GeneratorKind::Async(_))); let (state_adt_ref, state_substs) = if is_async_kind { // Compute Poll - let state_did = tcx.require_lang_item(LangItem::Poll, None); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[body.return_ty().into()]); - (state_adt_ref, state_substs) + let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_adt_ref = tcx.adt_def(poll_did); + let poll_substs = tcx.intern_substs(&[body.return_ty().into()]); + (poll_adt_ref, poll_substs) } else { // Compute GeneratorState let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); @@ -1303,13 +1401,19 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // RETURN_PLACE then is a fresh unused local with type ret_ty. let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx); + // Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies. + if is_async_kind { + transform_async_context(tcx, body); + } + // We also replace the resume argument and insert an `Assign`. // This is needed because the resume argument `_2` might be live across a `yield`, in which // case there is no `Assign` to it that the transform can turn into a store to the generator // state. After the yield the slot in the generator state would then be uninitialized. let resume_local = Local::new(2); - let new_resume_local = - replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx); + let resume_ty = + if is_async_kind { tcx.mk_task_context() } else { body.local_decls[resume_local].ty }; + let new_resume_local = replace_local(resume_local, resume_ty, body, tcx); // When first entering the generator, move the resume argument into its new local. let source_info = SourceInfo::outermost(body.span); diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index b616ed35d99d7..f88155e4fc792 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,5 +1,4 @@ #![feature(array_windows)] -#![feature(control_flow_enum)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index c8fc69eb856ab..cf13d4584a124 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -300,20 +300,20 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow { if !c.has_non_region_param() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match c.kind() { ty::ConstKind::Param(param) => { debug!(?param); self.unused_parameters.mark_used(param.index); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) => { self.visit_child_body(def.did, substs); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => c.super_visit_with(self), } @@ -322,7 +322,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { if !ty.has_non_region_param() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } match *ty.kind() { @@ -330,18 +330,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { debug!(?def_id); // Avoid cycle errors with generators. if def_id == self.def_id { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } // Consider any generic parameters used by any closures/generators as used in the // parent. self.visit_child_body(def_id, substs); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } ty::Param(param) => { debug!(?param); self.unused_parameters.mark_used(param.index); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => ty.super_visit_with(self), } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index fb55bb4afaac3..9a5d3cceb914e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,6 +1,5 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(associated_type_defaults)] -#![feature(control_flow_enum)] #![feature(rustc_private)] #![feature(try_blocks)] #![feature(let_chains)] @@ -112,7 +111,11 @@ where fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow { let TraitRef { def_id, substs, .. } = trait_ref; self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?; - if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } + if self.def_id_visitor.shallow() { + ControlFlow::Continue(()) + } else { + substs.visit_with(self) + } } fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow { @@ -131,7 +134,7 @@ where }; self.visit_trait(trait_ref)?; if self.def_id_visitor.shallow() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { assoc_substs.iter().try_for_each(|subst| subst.visit_with(self)) } @@ -155,7 +158,7 @@ where ty, _region, ))) => ty.visit_with(self), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::CONTINUE, + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::Continue(()), ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::PredicateKind::WellFormed(arg) => arg.visit_with(self), _ => bug!("unexpected predicate: {:?}", predicate), @@ -189,7 +192,7 @@ where | ty::Generator(def_id, ..) => { self.def_id_visitor.visit_def_id(def_id, "type", &ty)?; if self.def_id_visitor.shallow() { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } // Default type visitor doesn't visit signatures of fn types. // Something like `fn() -> Priv {my_func}` is considered a private type even if @@ -214,7 +217,7 @@ where // as visible/reachable even if both `Type` and `Trait` are private. // Ideally, associated types should be substituted in the same way as // free type aliases, but this isn't done yet. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } // This will also visit substs if necessary, so we don't need to recurse. return self.visit_projection_ty(proj); @@ -274,7 +277,7 @@ where } if self.def_id_visitor.shallow() { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ty.super_visit_with(self) } @@ -319,7 +322,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> if let Some(def_id) = def_id.as_local() { self.min = VL::new_min(self, def_id); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -881,7 +884,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> self.ev.update(def_id, self.level); } } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } @@ -1368,9 +1371,9 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { descr: &dyn fmt::Display, ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } @@ -1865,9 +1868,9 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { descr: &dyn fmt::Display, ) -> ControlFlow { if self.check_def_id(def_id, kind, descr) { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 706002f79b1fb..7597b8d126a9c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -164,6 +164,7 @@ symbols! { Capture, Center, Clone, + Context, Continue, Copy, Count, diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index cd6e4d2bccd5c..2336fb53aec28 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,9 +1,10 @@ //! Code shared by trait and projection goals for candidate assembly. use super::infcx_ext::InferCtxtExt; -use super::{CanonicalResponse, Certainty, EvalCtxt, Goal}; +use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::util::elaborate_predicates; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use std::fmt::Debug; @@ -89,19 +90,35 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, impl_def_id: DefId, - ) -> Result; + ) -> QueryResult<'tcx>; + + fn consider_assumption( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> QueryResult<'tcx>; + + fn consider_auto_trait_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + + fn consider_trait_alias_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; fn consider_builtin_sized_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> Result; + ) -> QueryResult<'tcx>; - fn consider_assumption( + fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - assumption: ty::Predicate<'tcx>, - ) -> Result; + ) -> QueryResult<'tcx>; } + impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn assemble_and_evaluate_candidates>( &mut self, @@ -119,6 +136,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_alias_bound_candidates(goal, &mut candidates); + self.assemble_object_bound_candidates(goal, &mut candidates); + candidates } @@ -180,9 +199,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { tcx.for_each_relevant_impl( goal.predicate.trait_def_id(tcx), goal.predicate.self_ty(), - |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) - .and_then(|certainty| self.make_canonical_response(certainty)) - { + |impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) { Ok(result) => candidates .push(Candidate { source: CandidateSource::Impl(impl_def_id), result }), Err(NoSolution) => (), @@ -197,13 +214,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) { let lang_items = self.tcx().lang_items(); let trait_def_id = goal.predicate.trait_def_id(self.tcx()); - let result = if lang_items.sized_trait() == Some(trait_def_id) { + let result = if self.tcx().trait_is_auto(trait_def_id) { + G::consider_auto_trait_candidate(self, goal) + } else if self.tcx().trait_is_alias(trait_def_id) { + G::consider_trait_alias_candidate(self, goal) + } else if lang_items.sized_trait() == Some(trait_def_id) { G::consider_builtin_sized_candidate(self, goal) + } else if lang_items.copy_trait() == Some(trait_def_id) + || lang_items.clone_trait() == Some(trait_def_id) + { + G::consider_builtin_copy_clone_candidate(self, goal) } else { Err(NoSolution) }; - match result.and_then(|certainty| self.make_canonical_response(certainty)) { + match result { Ok(result) => { candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) } @@ -217,9 +242,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates: &mut Vec>, ) { for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { - match G::consider_assumption(self, goal, assumption) - .and_then(|certainty| self.make_canonical_response(certainty)) - { + match G::consider_assumption(self, goal, assumption) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result }) } @@ -268,9 +291,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { .subst_iter_copied(self.tcx(), alias_ty.substs) .enumerate() { - match G::consider_assumption(self, goal, assumption) - .and_then(|certainty| self.make_canonical_response(certainty)) - { + match G::consider_assumption(self, goal, assumption) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::AliasBound(i), result }) } @@ -278,4 +299,52 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } } + + fn assemble_object_bound_candidates>( + &mut self, + goal: Goal<'tcx, G>, + candidates: &mut Vec>, + ) { + let self_ty = goal.predicate.self_ty(); + let bounds = match *self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Alias(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(_) + | ty::Never + | ty::Tuple(_) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(_) + | ty::Error(_) => return, + ty::Bound(..) => bug!("unexpected bound type: {goal:?}"), + ty::Dynamic(bounds, ..) => bounds, + }; + + let tcx = self.tcx(); + for assumption in + elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty))) + { + match G::consider_assumption(self, goal, assumption.predicate) { + Ok(result) => { + candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) + } + Err(NoSolution) => (), + } + } + } } diff --git a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs index 9b7feb5053787..42f597c781d25 100644 --- a/compiler/rustc_trait_selection/src/solve/infcx_ext.rs +++ b/compiler/rustc_trait_selection/src/solve/infcx_ext.rs @@ -1,10 +1,10 @@ use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_span::DUMMY_SP; use super::Goal; @@ -25,6 +25,11 @@ pub(super) trait InferCtxtExt<'tcx> { lhs: T, rhs: T, ) -> Result>>, NoSolution>; + + fn instantiate_bound_vars_with_infer + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T; } impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { @@ -59,4 +64,15 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { NoSolution }) } + + fn instantiate_bound_vars_with_infer + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::HigherRankedType, + value, + ) + } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 579cd6a2d59cd..32eb84635b536 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -313,6 +313,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } }) } + + fn evaluate_all_and_make_canonical_response( + &mut self, + goals: Vec>>, + ) -> QueryResult<'tcx> { + self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty)) + } } #[instrument(level = "debug", skip(infcx), ret)] diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 0658836fb9cd3..ffc1c70e0cb81 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -23,7 +23,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, ) -> QueryResult<'tcx> { - // To only compute normalization ones for each projection we only + // To only compute normalization once for each projection we only // normalize if the expected term is an unconstrained inference variable. // // E.g. for `::Assoc = u32` we recursively compute the goal @@ -191,7 +191,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, impl_def_id: DefId, - ) -> Result { + ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx); @@ -229,7 +229,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { impl_def_id )? else { let certainty = Certainty::Maybe(MaybeCause::Ambiguity); - return Ok(trait_ref_certainty.unify_and(certainty)); + return ecx.make_canonical_response(trait_ref_certainty.unify_and(certainty)); }; if !assoc_def.item.defaultness(tcx).has_value() { @@ -286,27 +286,70 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let rhs_certainty = ecx.evaluate_all(nested_goals).expect("failed to unify with unconstrained term"); - Ok(trait_ref_certainty.unify_and(rhs_certainty)) + ecx.make_canonical_response(trait_ref_certainty.unify_and(rhs_certainty)) }) } + fn consider_assumption( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> QueryResult<'tcx> { + if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() { + ecx.infcx.probe(|_| { + let assumption_projection_pred = + ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred); + let nested_goals = ecx.infcx.eq( + goal.param_env, + goal.predicate.projection_ty, + assumption_projection_pred.projection_ty, + )?; + let subst_certainty = ecx.evaluate_all(nested_goals)?; + + // The term of our goal should be fully unconstrained, so this should never fail. + // + // It can however be ambiguous when the resolved type is a projection. + let nested_goals = ecx + .infcx + .eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term) + .expect("failed to unify with unconstrained term"); + let rhs_certainty = ecx + .evaluate_all(nested_goals) + .expect("failed to unify with unconstrained term"); + + ecx.make_canonical_response(subst_certainty.unify_and(rhs_certainty)) + }) + } else { + Err(NoSolution) + } + } + + fn consider_auto_trait_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("auto traits do not have associated types: {:?}", goal); + } + + fn consider_trait_alias_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("trait aliases do not have associated types: {:?}", goal); + } + fn consider_builtin_sized_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, - ) -> Result { + ) -> QueryResult<'tcx> { bug!("`Sized` does not have an associated type: {:?}", goal); } - fn consider_assumption( + fn consider_builtin_copy_clone_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, - assumption: ty::Predicate<'tcx>, - ) -> Result { - if let Some(_poly_projection_pred) = assumption.to_opt_poly_projection_pred() { - unimplemented!() - } else { - Err(NoSolution) - } + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index bbe175d5cc853..1ebcfd03c14ea 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -4,14 +4,17 @@ use std::iter; use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; -use super::{Certainty, EvalCtxt, Goal, QueryResult}; +use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; +mod structural_traits; + impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn self_ty(self) -> Ty<'tcx> { self.self_ty() @@ -29,7 +32,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, TraitPredicate<'tcx>>, impl_def_id: DefId, - ) -> Result { + ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); @@ -53,31 +56,104 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { .into_iter() .map(|pred| goal.with(tcx, pred)); nested_goals.extend(where_clause_bounds); - ecx.evaluate_all(nested_goals) + ecx.evaluate_all_and_make_canonical_response(nested_goals) }) } - fn consider_builtin_sized_candidate( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, - ) -> Result { - unimplemented!(); - } - fn consider_assumption( - _ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, - ) -> Result { - if let Some(_poly_trait_pred) = assumption.to_opt_poly_trait_pred() { - unimplemented!() + ) -> QueryResult<'tcx> { + if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() { + // FIXME: Constness and polarity + ecx.infcx.probe(|_| { + let assumption_trait_pred = + ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred); + let nested_goals = ecx.infcx.eq( + goal.param_env, + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, + )?; + ecx.evaluate_all_and_make_canonical_response(nested_goals) + }) } else { Err(NoSolution) } } + + fn consider_auto_trait_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_auto_trait, + ) + } + + fn consider_trait_alias_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + let tcx = ecx.tcx(); + + ecx.infcx.probe(|_| { + let nested_obligations = tcx + .predicates_of(goal.predicate.def_id()) + .instantiate(tcx, goal.predicate.trait_ref.substs); + ecx.evaluate_all_and_make_canonical_response( + nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)).collect(), + ) + }) + } + + fn consider_builtin_sized_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_sized_trait, + ) + } + + fn consider_builtin_copy_clone_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_copy_clone_trait, + ) + } } impl<'tcx> EvalCtxt<'_, 'tcx> { + /// Convenience function for traits that are structural, i.e. that only + /// have nested subgoals that only change the self type. Unlike other + /// evaluate-like helpers, this does a probe, so it doesn't need to be + /// wrapped in one. + fn probe_and_evaluate_goal_for_constituent_tys( + &mut self, + goal: Goal<'tcx, TraitPredicate<'tcx>>, + constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result>, NoSolution>, + ) -> QueryResult<'tcx> { + self.infcx.probe(|_| { + self.evaluate_all_and_make_canonical_response( + constituent_tys(self.infcx, goal.predicate.self_ty())? + .into_iter() + .map(|ty| { + goal.with( + self.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), + ) + }) + .collect(), + ) + }) + } + pub(super) fn compute_trait_goal( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs new file mode 100644 index 0000000000000..bbc0c77253278 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -0,0 +1,179 @@ +use rustc_hir::{Movability, Mutability}; +use rustc_infer::{infer::InferCtxt, traits::query::NoSolution}; +use rustc_middle::ty::{self, Ty}; + +// Calculates the constituent types of a type for `auto trait` purposes. +// +// For types with an "existential" binder, i.e. generator witnesses, we also +// instantiate the binder with placeholders eagerly. +pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + let tcx = infcx.tcx; + match *ty.kind() { + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Str + | ty::Error(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Never + | ty::Char => Ok(vec![]), + + ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Alias(ty::Projection, ..) + | ty::Bound(..) + | ty::Infer(ty::TyVar(_)) => { + // FIXME: Do we need to mark anything as ambiguous here? Yeah? + Err(NoSolution) + } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + Ok(vec![element_ty]) + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + Ok(tys.iter().collect()) + } + + ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, ref substs, _) => { + let generator_substs = substs.as_generator(); + Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + + // For `PhantomData`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), + + ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()), + + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) + } + } +} + +pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::RawPtr(..) + | ty::Char + | ty::Ref(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Array(..) + | ty::Closure(..) + | ty::Never + | ty::Dynamic(_, _, ty::DynStar) + | ty::Error(_) => Ok(vec![]), + + ty::Str + | ty::Slice(_) + | ty::Dynamic(..) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(infcx.tcx); + Ok(sized_crit + .0 + .iter() + .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) + .collect()) + } + } +} + +pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Error(_) => Ok(vec![]), + + // Implementations are provided in core + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, Mutability::Not) + | ty::Array(..) => Err(NoSolution), + + ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Generator(_, _, Movability::Static) + | ty::Foreign(..) + | ty::Ref(_, _, Mutability::Mut) + | ty::Adt(_, _) + | ty::Alias(_, _) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, substs, Movability::Movable) => { + if infcx.tcx.features().generator_clone { + let generator = substs.as_generator(); + Ok(vec![generator.tupled_upvars_ty(), generator.witness()]) + } else { + Err(NoSolution) + } + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 0edae34190c30..5f649852d0bbd 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -614,12 +614,12 @@ impl<'tcx> OrphanChecker<'tcx> { fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { self.non_local_tys.push((t, self.in_self_ty)); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow> { if self.search_first_local_ty { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } else { ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t)) } @@ -641,7 +641,7 @@ enum OrphanCheckEarlyExit<'tcx> { impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { type BreakTy = OrphanCheckEarlyExit<'tcx>; fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { @@ -756,6 +756,6 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { /// parameters, allowing uncovered const parameters in impls seems more useful /// than allowing `impl Trait for i32` to compile. fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 71fb6058cd2c5..f779d9dd8d935 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -198,7 +198,7 @@ fn satisfied_from_param_env<'tcx>( // If we start allowing directly writing `ConstKind::Expr` without an intermediate anon const // this will be incorrect. It might be worth investigating making `predicates_of` elaborate // all of the `ConstEvaluatable` bounds rather than having a visitor here. - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 32b0f65176c18..434f75de02bff 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2932,7 +2932,7 @@ impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor { if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 531aa23d6eac5..f036a311d464c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -493,7 +493,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI && let param_def_id = self.generics.type_param(param, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } t.super_visit_with(self) } @@ -502,7 +502,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } r.super_visit_with(self) } @@ -511,7 +511,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { - return ControlFlow::BREAK; + return ControlFlow::Break(()); } ct.super_visit_with(self) } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 9a0e3d298eda1..c9121212cd8f1 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -783,16 +783,16 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( match t.kind() { ty::Param(_) => { if t == self.tcx.types.self_param { - ControlFlow::BREAK + ControlFlow::Break(()) } else { - ControlFlow::CONTINUE + ControlFlow::Continue(()) } } ty::Alias(ty::Projection, ref data) if self.tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder => { // We'll deny these later in their own pass - ControlFlow::CONTINUE + ControlFlow::Continue(()) } ty::Alias(ty::Projection, ref data) => { // This is a projected type `::X`. @@ -820,7 +820,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>( .contains(&data.trait_ref(self.tcx).def_id); if is_supertrait_of_current_trait { - ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200 + ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200 } else { t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index c6ef13e185b2d..1531c50760d53 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -133,7 +133,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { .escaping .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize()); } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } #[inline] @@ -145,7 +145,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { } _ => {} } - ControlFlow::CONTINUE + ControlFlow::Continue(()) } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { @@ -153,7 +153,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { self.escaping = self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); - ControlFlow::CONTINUE + ControlFlow::Continue(()) } _ => ct.super_visit_with(self), } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 892a7afd799c7..f398fb06c187a 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -107,25 +107,25 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::FnDef(..) => { // Types of formals and return in `fn(_) -> _` are also irrelevant; // so we do not recur into them via `super_visit_with` - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::Array(_, n) if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } => { // rust-lang/rust#62336: ignore type of contents // for empty array. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } ty::FnPtr(..) => { if !self.adt_const_param { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -147,7 +147,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { // Even though `NonStructural` does not implement `PartialEq`, // structural equality on `T` does not recur into the raw // pointer. Therefore, one can still use `C` in a pattern. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -155,7 +155,7 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { ty::Float(_) => { if !self.adt_const_param { - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } else { return ControlFlow::Break(ty); } @@ -172,13 +172,13 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> { self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } }; if !self.seen.insert(adt_def.did()) { debug!("Search already seen adt_def: {:?}", adt_def); - return ControlFlow::CONTINUE; + return ControlFlow::Continue(()); } if !self.type_marked_structural(ty) { diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 384d03106b1e8..b3b9a67b26e3d 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(alloc_layout_extra, control_flow_enum, decl_macro, iterator_try_reduce, never_type)] +#![feature(alloc_layout_extra, decl_macro, iterator_try_reduce, never_type)] #![allow(dead_code, unused_variables)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 669f84ae1b472..91a505a72fae7 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -108,21 +108,41 @@ fn fn_sig_for_fn_abi<'tcx>( // `Generator::resume(...) -> GeneratorState` function in case we // have an ordinary generator, or the `Future::poll(...) -> Poll` // function in case this is a special generator backing an async construct. - let ret_ty = if tcx.generator_is_async(did) { - let state_did = tcx.require_lang_item(LangItem::Poll, None); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[sig.return_ty.into()]); - tcx.mk_adt(state_adt_ref, state_substs) + let (resume_ty, ret_ty) = if tcx.generator_is_async(did) { + // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll` + let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_adt_ref = tcx.adt_def(poll_did); + let poll_substs = tcx.intern_substs(&[sig.return_ty.into()]); + let ret_ty = tcx.mk_adt(poll_adt_ref, poll_substs); + + // We have to replace the `ResumeTy` that is used for type and borrow checking + // with `&mut Context<'_>` which is used in codegen. + #[cfg(debug_assertions)] + { + if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() { + let expected_adt = + tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + assert_eq!(*resume_ty_adt, expected_adt); + } else { + panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty); + }; + } + let context_mut_ref = tcx.mk_task_context(); + + (context_mut_ref, ret_ty) } else { + // The signature should be `Generator::resume(_, Resume) -> GeneratorState` let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); let state_adt_ref = tcx.adt_def(state_did); let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]); - tcx.mk_adt(state_adt_ref, state_substs) + let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + + (sig.resume_ty, ret_ty) }; ty::Binder::bind_with_vars( tcx.mk_fn_sig( - [env_ty, sig.resume_ty].iter(), + [env_ty, resume_ty].iter(), &ret_ty, false, hir::Unsafety::Normal, diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 7ad5cbc01ccf2..0853de601b040 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,7 +6,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(let_chains)] -#![feature(control_flow_enum)] #![feature(never_type)] #![feature(box_patterns)] #![recursion_limit = "256"] diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 5bfe001de46e3..c4fb362094664 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -112,6 +112,10 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> { unsafe { &mut *cx.0.as_ptr().cast() } } +// FIXME(swatinem): This fn is currently needed to work around shortcomings +// in type and lifetime inference. +// See the comment at the bottom of `LoweringContext::make_async_expr` and +// . #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[inline] diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index a4425fd234a4e..89adfccd90135 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -174,6 +174,7 @@ impl RawWakerVTable { /// Currently, `Context` only serves to provide access to a [`&Waker`](Waker) /// which can be used to wake the current task. #[stable(feature = "futures_api", since = "1.36.0")] +#[cfg_attr(not(bootstrap), lang = "Context")] pub struct Context<'a> { waker: &'a Waker, // Ensure we future-proof against variance changes by forcing diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 9ceeeb5ae8fd8..604ab147f6a16 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -390,7 +390,8 @@ function loadCss(cssUrl) { } if (document.activeElement.tagName === "INPUT" && - document.activeElement.type !== "checkbox") { + document.activeElement.type !== "checkbox" && + document.activeElement.type !== "radio") { switch (getVirtualKey(ev)) { case "Escape": handleEscape(ev); @@ -1082,6 +1083,9 @@ function loadCss(cssUrl) { * Show the help popup menu. */ function showHelp() { + // Prevent `blur` events from being dispatched as a result of closing + // other modals. + getHelpButton().querySelector("a").focus(); const menu = getHelpMenu(true); if (menu.style.display === "none") { window.hideAllModals(); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 1b8822b0b2b7d..88592fa0c84c1 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -781,7 +781,29 @@ function initSearch(rawSearchIndex) { return a - b; } - // Sort by non levenshtein results and then levenshtein results by the distance + // sort by index of keyword in item name (no literal occurrence goes later) + a = (aaa.index < 0); + b = (bbb.index < 0); + if (a !== b) { + return a - b; + } + + // Sort by distance in the path part, if specified + // (less changes required to match means higher rankings) + a = aaa.path_lev; + b = bbb.path_lev; + if (a !== b) { + return a - b; + } + + // (later literal occurrence, if any, goes later) + a = aaa.index; + b = bbb.index; + if (a !== b) { + return a - b; + } + + // Sort by distance in the name part, the last part of the path // (less changes required to match means higher rankings) a = (aaa.lev); b = (bbb.lev); @@ -810,19 +832,6 @@ function initSearch(rawSearchIndex) { return (a > b ? +1 : -1); } - // sort by index of keyword in item name (no literal occurrence goes later) - a = (aaa.index < 0); - b = (bbb.index < 0); - if (a !== b) { - return a - b; - } - // (later literal occurrence, if any, goes later) - a = aaa.index; - b = bbb.index; - if (a !== b) { - return a - b; - } - // special precedence for primitive and keyword pages if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) || (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) { @@ -1230,15 +1239,19 @@ function initSearch(rawSearchIndex) { * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element. * * `index` is an `integer`` used to sort by the position of the word in the item's name. * * `lev` is the main metric used to sort the search results. + * * `path_lev` is zero if a single-component search query is used, otherwise it's the + * distance computed for everything other than the last path component. * * @param {Results} results * @param {string} fullId * @param {integer} id * @param {integer} index * @param {integer} lev + * @param {integer} path_lev */ - function addIntoResults(results, fullId, id, index, lev) { - if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) { + function addIntoResults(results, fullId, id, index, lev, path_lev) { + const inBounds = lev <= MAX_LEV_DISTANCE || index !== -1; + if (lev === 0 || (!parsedQuery.literalSearch && inBounds)) { if (results[fullId] !== undefined) { const result = results[fullId]; if (result.dontValidate || result.lev <= lev) { @@ -1250,6 +1263,7 @@ function initSearch(rawSearchIndex) { index: index, dontValidate: parsedQuery.literalSearch, lev: lev, + path_lev: path_lev, }; } } @@ -1280,68 +1294,68 @@ function initSearch(rawSearchIndex) { if (!row || (filterCrates !== null && row.crate !== filterCrates)) { return; } - let lev, lev_add = 0, index = -1; + let lev, index = -1, path_lev = 0; const fullId = row.id; + const searchWord = searchWords[pos]; const in_args = findArg(row, elem, parsedQuery.typeFilter); const returned = checkReturned(row, elem, parsedQuery.typeFilter); - addIntoResults(results_in_args, fullId, pos, index, in_args); - addIntoResults(results_returned, fullId, pos, index, returned); + // path_lev is 0 because no parent path information is currently stored + // in the search index + addIntoResults(results_in_args, fullId, pos, -1, in_args, 0); + addIntoResults(results_returned, fullId, pos, -1, returned, 0); if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) { return; } - const searchWord = searchWords[pos]; - if (parsedQuery.literalSearch) { - if (searchWord === elem.name) { - addIntoResults(results_others, fullId, pos, -1, 0); - } - return; + const row_index = row.normalizedName.indexOf(elem.pathLast); + const word_index = searchWord.indexOf(elem.pathLast); + + // lower indexes are "better" matches + // rank based on the "best" match + if (row_index === -1) { + index = word_index; + } else if (word_index === -1) { + index = row_index; + } else if (word_index < row_index) { + index = word_index; + } else { + index = row_index; } // No need to check anything else if it's a "pure" generics search. if (elem.name.length === 0) { if (row.type !== null) { lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1); - addIntoResults(results_others, fullId, pos, index, lev); + // path_lev is 0 because we know it's empty + addIntoResults(results_others, fullId, pos, index, lev, 0); } return; } if (elem.fullPath.length > 1) { - lev = checkPath(elem.pathWithoutLast, row); - if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) { + path_lev = checkPath(elem.pathWithoutLast, row); + if (path_lev > MAX_LEV_DISTANCE) { return; - } else if (lev > 0) { - lev_add = lev / 10; } } - if (searchWord.indexOf(elem.pathLast) > -1 || - row.normalizedName.indexOf(elem.pathLast) > -1 - ) { - index = row.normalizedName.indexOf(elem.pathLast); - } - lev = levenshtein(searchWord, elem.pathLast); - if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1) { - if (elem.pathLast.length < 6) { - lev = 1; - } else { - lev = 0; + if (parsedQuery.literalSearch) { + if (searchWord === elem.name) { + addIntoResults(results_others, fullId, pos, index, 0, path_lev); } - } - lev += lev_add; - if (lev > MAX_LEV_DISTANCE) { return; - } else if (index !== -1 && elem.fullPath.length < 2) { - lev -= 1; } - if (lev < 0) { - lev = 0; + + lev = levenshtein(searchWord, elem.pathLast); + + if (index === -1 && lev + path_lev > MAX_LEV_DISTANCE) { + return; } - addIntoResults(results_others, fullId, pos, index, lev); + + addIntoResults(results_others, fullId, pos, index, lev, path_lev); } /** @@ -1386,7 +1400,7 @@ function initSearch(rawSearchIndex) { return; } const lev = Math.round(totalLev / nbLev); - addIntoResults(results, row.id, pos, 0, lev); + addIntoResults(results, row.id, pos, 0, lev, 0); } function innerRunQuery() { diff --git a/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir new file mode 100644 index 0000000000000..e62183ac932e5 --- /dev/null +++ b/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir @@ -0,0 +1,41 @@ +// MIR for `a::{closure#0}` 0 generator_resume +/* generator_layout = GeneratorLayout { + field_tys: {}, + variant_fields: { + Unresumed(0): [], + Returned (1): [], + Panicked (2): [], + }, + storage_conflicts: BitMatrix(0x0) {}, +} */ + +fn a::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:10:14: 10:16]>, _2: &mut Context<'_>) -> Poll<()> { + debug _task_context => _4; // in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + let mut _0: std::task::Poll<()>; // return place in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + let mut _3: (); // in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + let mut _4: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + let mut _5: u32; // in scope 0 at $DIR/async_await.rs:+0:14: +0:16 + + bb0: { + _5 = discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:10:14: 10:16]))); // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + switchInt(move _5) -> [0: bb1, 1: bb2, otherwise: bb3]; // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + } + + bb1: { + _4 = move _2; // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + _3 = const (); // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + Deinit(_0); // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + ((_0 as Ready).0: ()) = move _3; // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + discriminant(_0) = 0; // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:10:14: 10:16]))) = 1; // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + return; // scope 0 at $DIR/async_await.rs:+0:16: +0:16 + } + + bb2: { + assert(const false, "`async fn` resumed after completion") -> bb2; // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + } + + bb3: { + unreachable; // scope 0 at $DIR/async_await.rs:+0:14: +0:16 + } +} diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir new file mode 100644 index 0000000000000..85fef5b900291 --- /dev/null +++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir @@ -0,0 +1,433 @@ +// MIR for `b::{closure#0}` 0 generator_resume +/* generator_layout = GeneratorLayout { + field_tys: { + _0: impl std::future::Future, + _1: impl std::future::Future, + }, + variant_fields: { + Unresumed(0): [], + Returned (1): [], + Panicked (2): [], + Suspend0 (3): [_0], + Suspend1 (4): [_1], + }, + storage_conflicts: BitMatrix(2x2) { + (_0, _0), + (_1, _1), + }, +} */ + +fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:13:18: 16:2]>, _2: &mut Context<'_>) -> Poll<()> { + debug _task_context => _38; // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let mut _0: std::task::Poll<()>; // return place in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let _3: (); // in scope 0 at $DIR/async_await.rs:+1:5: +1:14 + let mut _4: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _5: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:5: +1:8 + let mut _6: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _7: (); // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let _8: (); // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _9: std::task::Poll<()>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _10: std::pin::Pin<&mut impl std::future::Future>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _11: &mut impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _12: &mut impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _13: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:5: +1:14 + let mut _14: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:5: +1:14 + let mut _15: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _16: isize; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _18: !; // in scope 0 at $DIR/async_await.rs:+1:5: +1:14 + let mut _19: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _20: (); // in scope 0 at $DIR/async_await.rs:+1:8: +1:14 + let mut _21: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _22: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:5: +2:8 + let mut _23: impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let _24: (); // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _25: std::task::Poll<()>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _26: std::pin::Pin<&mut impl std::future::Future>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _27: &mut impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _28: &mut impl std::future::Future; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _29: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:5: +2:14 + let mut _30: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:5: +2:14 + let mut _31: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _32: isize; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _34: !; // in scope 0 at $DIR/async_await.rs:+2:5: +2:14 + let mut _35: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _36: (); // in scope 0 at $DIR/async_await.rs:+2:8: +2:14 + let mut _37: (); // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let mut _38: &mut std::task::Context<'_>; // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + let mut _39: u32; // in scope 0 at $DIR/async_await.rs:+0:18: +3:2 + scope 1 { + debug __awaitee => (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2])) as variant#3).0: impl std::future::Future); // in scope 1 at $DIR/async_await.rs:+1:8: +1:14 + let _17: (); // in scope 1 at $DIR/async_await.rs:+1:5: +1:14 + scope 2 { + } + scope 3 { + debug result => _17; // in scope 3 at $DIR/async_await.rs:+1:5: +1:14 + } + } + scope 4 { + debug __awaitee => (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2])) as variant#4).0: impl std::future::Future); // in scope 4 at $DIR/async_await.rs:+2:8: +2:14 + let _33: (); // in scope 4 at $DIR/async_await.rs:+2:5: +2:14 + scope 5 { + } + scope 6 { + debug result => _33; // in scope 6 at $DIR/async_await.rs:+2:5: +2:14 + } + } + + bb0: { + _39 = discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2]))); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + switchInt(move _39) -> [0: bb1, 1: bb47, 2: bb46, 3: bb44, 4: bb45, otherwise: bb48]; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb1: { + _38 = move _2; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_3); // scope 0 at $DIR/async_await.rs:+1:5: +1:14 + StorageLive(_4); // scope 0 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_5); // scope 0 at $DIR/async_await.rs:+1:5: +1:8 + _5 = a() -> [return: bb2, unwind: bb39]; // scope 0 at $DIR/async_await.rs:+1:5: +1:8 + // mir::Constant + // + span: $DIR/async_await.rs:14:5: 14:6 + // + literal: Const { ty: fn() -> impl Future {a}, val: Value() } + } + + bb2: { + _4 = as IntoFuture>::into_future(move _5) -> [return: bb3, unwind: bb38]; // scope 0 at $DIR/async_await.rs:+1:8: +1:14 + // mir::Constant + // + span: $DIR/async_await.rs:14:8: 14:14 + // + literal: Const { ty: fn(impl Future) -> as IntoFuture>::IntoFuture { as IntoFuture>::into_future}, val: Value() } + } + + bb3: { + StorageDead(_5); // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + nop; // scope 0 at $DIR/async_await.rs:+1:8: +1:14 + (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2])) as variant#3).0: impl std::future::Future) = move _4; // scope 0 at $DIR/async_await.rs:+1:8: +1:14 + goto -> bb4; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb4: { + StorageLive(_8); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_9); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_10); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_11); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_12); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _12 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2])) as variant#3).0: impl std::future::Future); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _11 = &mut (*_12); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _10 = Pin::<&mut impl Future>::new_unchecked(move _11) -> [return: bb5, unwind: bb35]; // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + // mir::Constant + // + span: $DIR/async_await.rs:14:8: 14:14 + // + literal: Const { ty: unsafe fn(&mut impl Future) -> Pin<&mut impl Future> {Pin::<&mut impl Future>::new_unchecked}, val: Value() } + } + + bb5: { + StorageDead(_11); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + StorageLive(_13); // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + StorageLive(_14); // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + StorageLive(_15); // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _15 = _38; // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + _14 = move _15; // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + goto -> bb6; // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + } + + bb6: { + _13 = &mut (*_14); // scope 2 at $DIR/async_await.rs:+1:5: +1:14 + StorageDead(_15); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + _9 = as Future>::poll(move _10, move _13) -> [return: bb7, unwind: bb34]; // scope 2 at $DIR/async_await.rs:+1:8: +1:14 + // mir::Constant + // + span: $DIR/async_await.rs:14:8: 14:14 + // + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future>, &'b mut Context<'c>) -> Poll< as Future>::Output> { as Future>::poll}, val: Value() } + } + + bb7: { + StorageDead(_13); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_10); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + _16 = discriminant(_9); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + switchInt(move _16) -> [0: bb10, 1: bb8, otherwise: bb9]; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb8: { + _8 = const (); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageDead(_14); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_12); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_9); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_8); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageLive(_19); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageLive(_20); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + _20 = (); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + Deinit(_0); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + discriminant(_0) = 1; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2]))) = 3; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + return; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb9: { + unreachable; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb10: { + StorageLive(_17); // scope 1 at $DIR/async_await.rs:+1:5: +1:14 + _17 = ((_9 as Ready).0: ()); // scope 1 at $DIR/async_await.rs:+1:5: +1:14 + _3 = _17; // scope 3 at $DIR/async_await.rs:+1:5: +1:14 + StorageDead(_17); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_14); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_12); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_9); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_8); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + goto -> bb12; // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + } + + bb11: { + StorageDead(_20); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + _38 = move _19; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + StorageDead(_19); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + _7 = const (); // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + goto -> bb4; // scope 1 at $DIR/async_await.rs:+1:8: +1:14 + } + + bb12: { + nop; // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + goto -> bb13; // scope 0 at $DIR/async_await.rs:+1:14: +1:15 + } + + bb13: { + StorageDead(_4); // scope 0 at $DIR/async_await.rs:+1:14: +1:15 + StorageDead(_3); // scope 0 at $DIR/async_await.rs:+1:14: +1:15 + StorageLive(_21); // scope 0 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_22); // scope 0 at $DIR/async_await.rs:+2:5: +2:8 + _22 = a() -> [return: bb14, unwind: bb32]; // scope 0 at $DIR/async_await.rs:+2:5: +2:8 + // mir::Constant + // + span: $DIR/async_await.rs:15:5: 15:6 + // + literal: Const { ty: fn() -> impl Future {a}, val: Value() } + } + + bb14: { + _21 = as IntoFuture>::into_future(move _22) -> [return: bb15, unwind: bb31]; // scope 0 at $DIR/async_await.rs:+2:8: +2:14 + // mir::Constant + // + span: $DIR/async_await.rs:15:8: 15:14 + // + literal: Const { ty: fn(impl Future) -> as IntoFuture>::IntoFuture { as IntoFuture>::into_future}, val: Value() } + } + + bb15: { + StorageDead(_22); // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + nop; // scope 0 at $DIR/async_await.rs:+2:8: +2:14 + (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2])) as variant#4).0: impl std::future::Future) = move _21; // scope 0 at $DIR/async_await.rs:+2:8: +2:14 + goto -> bb16; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb16: { + StorageLive(_24); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_25); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_26); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_27); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_28); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _28 = &mut (((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2])) as variant#4).0: impl std::future::Future); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _27 = &mut (*_28); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _26 = Pin::<&mut impl Future>::new_unchecked(move _27) -> [return: bb17, unwind: bb28]; // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + // mir::Constant + // + span: $DIR/async_await.rs:15:8: 15:14 + // + literal: Const { ty: unsafe fn(&mut impl Future) -> Pin<&mut impl Future> {Pin::<&mut impl Future>::new_unchecked}, val: Value() } + } + + bb17: { + StorageDead(_27); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + StorageLive(_29); // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + StorageLive(_30); // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + StorageLive(_31); // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _31 = _38; // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + _30 = move _31; // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + goto -> bb18; // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + } + + bb18: { + _29 = &mut (*_30); // scope 5 at $DIR/async_await.rs:+2:5: +2:14 + StorageDead(_31); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + _25 = as Future>::poll(move _26, move _29) -> [return: bb19, unwind: bb27]; // scope 5 at $DIR/async_await.rs:+2:8: +2:14 + // mir::Constant + // + span: $DIR/async_await.rs:15:8: 15:14 + // + literal: Const { ty: for<'a, 'b, 'c> fn(Pin<&'a mut impl Future>, &'b mut Context<'c>) -> Poll< as Future>::Output> { as Future>::poll}, val: Value() } + } + + bb19: { + StorageDead(_29); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_26); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + _32 = discriminant(_25); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + switchInt(move _32) -> [0: bb22, 1: bb20, otherwise: bb21]; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb20: { + _24 = const (); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageDead(_30); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_28); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_25); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_24); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageLive(_35); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageLive(_36); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + _36 = (); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + Deinit(_0); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + discriminant(_0) = 1; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2]))) = 4; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + return; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb21: { + unreachable; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb22: { + StorageLive(_33); // scope 4 at $DIR/async_await.rs:+2:5: +2:14 + _33 = ((_25 as Ready).0: ()); // scope 4 at $DIR/async_await.rs:+2:5: +2:14 + _37 = _33; // scope 6 at $DIR/async_await.rs:+2:5: +2:14 + StorageDead(_33); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_30); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_28); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_25); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_24); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + goto -> bb24; // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + } + + bb23: { + StorageDead(_36); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + _38 = move _35; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + StorageDead(_35); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + _7 = const (); // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + goto -> bb16; // scope 4 at $DIR/async_await.rs:+2:8: +2:14 + } + + bb24: { + nop; // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + goto -> bb25; // scope 0 at $DIR/async_await.rs:+3:1: +3:2 + } + + bb25: { + StorageDead(_21); // scope 0 at $DIR/async_await.rs:+3:1: +3:2 + goto -> bb26; // scope 0 at $DIR/async_await.rs:+3:1: +3:2 + } + + bb26: { + Deinit(_0); // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + ((_0 as Ready).0: ()) = move _37; // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + discriminant(_0) = 0; // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2]))) = 1; // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + return; // scope 0 at $DIR/async_await.rs:+3:2: +3:2 + } + + bb27 (cleanup): { + StorageDead(_29); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_26); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_30); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + goto -> bb29; // scope 4 at no-location + } + + bb28 (cleanup): { + StorageDead(_27); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_26); // scope 5 at $DIR/async_await.rs:+2:13: +2:14 + goto -> bb29; // scope 5 at no-location + } + + bb29 (cleanup): { + StorageDead(_28); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_25); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + StorageDead(_24); // scope 4 at $DIR/async_await.rs:+2:13: +2:14 + goto -> bb30; // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + } + + bb30 (cleanup): { + nop; // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + goto -> bb33; // scope 0 at $DIR/async_await.rs:+3:1: +3:2 + } + + bb31 (cleanup): { + goto -> bb32; // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + } + + bb32 (cleanup): { + StorageDead(_22); // scope 0 at $DIR/async_await.rs:+2:13: +2:14 + goto -> bb33; // scope 0 at no-location + } + + bb33 (cleanup): { + StorageDead(_21); // scope 0 at $DIR/async_await.rs:+3:1: +3:2 + goto -> bb41; // scope 0 at no-location + } + + bb34 (cleanup): { + StorageDead(_13); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_10); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_14); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + goto -> bb36; // scope 1 at no-location + } + + bb35 (cleanup): { + StorageDead(_11); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_10); // scope 2 at $DIR/async_await.rs:+1:13: +1:14 + goto -> bb36; // scope 2 at no-location + } + + bb36 (cleanup): { + StorageDead(_12); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_9); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + StorageDead(_8); // scope 1 at $DIR/async_await.rs:+1:13: +1:14 + goto -> bb37; // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + } + + bb37 (cleanup): { + nop; // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + goto -> bb40; // scope 0 at $DIR/async_await.rs:+1:14: +1:15 + } + + bb38 (cleanup): { + goto -> bb39; // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + } + + bb39 (cleanup): { + StorageDead(_5); // scope 0 at $DIR/async_await.rs:+1:13: +1:14 + goto -> bb40; // scope 0 at no-location + } + + bb40 (cleanup): { + StorageDead(_4); // scope 0 at $DIR/async_await.rs:+1:14: +1:15 + StorageDead(_3); // scope 0 at $DIR/async_await.rs:+1:14: +1:15 + goto -> bb41; // scope 0 at no-location + } + + bb41 (cleanup): { + goto -> bb42; // scope 0 at $DIR/async_await.rs:+3:1: +3:2 + } + + bb42 (cleanup): { + goto -> bb43; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb43 (cleanup): { + discriminant((*(_1.0: &mut [async fn body@$DIR/async_await.rs:13:18: 16:2]))) = 2; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + resume; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb44: { + StorageLive(_3); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_4); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_19); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_20); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + _19 = move _2; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + goto -> bb11; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb45: { + StorageLive(_21); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_35); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + StorageLive(_36); // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + _35 = move _2; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + goto -> bb23; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb46: { + assert(const false, "`async fn` resumed after panicking") -> bb46; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb47: { + assert(const false, "`async fn` resumed after completion") -> bb47; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } + + bb48: { + unreachable; // scope 0 at $DIR/async_await.rs:+0:18: +3:2 + } +} diff --git a/tests/mir-opt/building/async_await.rs b/tests/mir-opt/building/async_await.rs new file mode 100644 index 0000000000000..b6442d63007fe --- /dev/null +++ b/tests/mir-opt/building/async_await.rs @@ -0,0 +1,16 @@ +// This test makes sure that the generator MIR pass eliminates all calls to +// `get_context`, and that the MIR argument type for an async fn and all locals +// related to `yield` are `&mut Context`, and its return type is `Poll`. + +// edition:2018 + +#![crate_type = "lib"] + +// EMIT_MIR async_await.a-{closure#0}.generator_resume.0.mir +async fn a() {} + +// EMIT_MIR async_await.b-{closure#0}.generator_resume.0.mir +pub async fn b() { + a().await; + a().await +} diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 72de41e41bae1..4c72ed51a4979 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -203,6 +203,25 @@ press-key: "?" wait-for-css: ("#help-button .popover", {"display": "block"}) assert-css: ("#settings-menu .popover", {"display": "none"}) +// Now switch back to the settings popover, and make sure the keyboard +// shortcut works when a check box is selected. +click: "#settings-menu > a" +wait-for-css: ("#settings-menu .popover", {"display": "block"}) +focus: "#auto-hide-large-items" +press-key: "?" +wait-for-css: ("#settings-menu .popover", {"display": "none"}) +wait-for-css: ("#help-button .popover", {"display": "block"}) + +// Now switch back to the settings popover, and make sure the keyboard +// shortcut works when a check box is selected. +click: "#settings-menu > a" +wait-for-css: ("#settings-menu .popover", {"display": "block"}) +wait-for-css: ("#help-button .popover", {"display": "none"}) +focus: "#theme-system-preference" +press-key: "?" +wait-for-css: ("#settings-menu .popover", {"display": "none"}) +wait-for-css: ("#help-button .popover", {"display": "block"}) + // Now we go to the settings page to check that the CSS is loaded as expected. goto: "file://" + |DOC_PATH| + "/settings.html" wait-for: "#settings" diff --git a/tests/rustdoc-js-std/macro-print.js b/tests/rustdoc-js-std/macro-print.js index 858046e72e9a4..1b4c7b4057020 100644 --- a/tests/rustdoc-js-std/macro-print.js +++ b/tests/rustdoc-js-std/macro-print.js @@ -3,8 +3,8 @@ const QUERY = 'macro:print'; const EXPECTED = { 'others': [ { 'path': 'std', 'name': 'print' }, - { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'println' }, + { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'eprintln' }, ], }; diff --git a/tests/rustdoc-js-std/typed-query.js b/tests/rustdoc-js-std/typed-query.js index 25efbad269540..fd5c5489d79cf 100644 --- a/tests/rustdoc-js-std/typed-query.js +++ b/tests/rustdoc-js-std/typed-query.js @@ -6,8 +6,8 @@ const FILTER_CRATE = 'std'; const EXPECTED = { 'others': [ { 'path': 'std', 'name': 'print' }, - { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'println' }, + { 'path': 'std', 'name': 'eprint' }, { 'path': 'std', 'name': 'eprintln' }, { 'path': 'std::pin', 'name': 'pin' }, { 'path': 'std::future', 'name': 'join' }, diff --git a/tests/rustdoc-js-std/vec-new.js b/tests/rustdoc-js-std/vec-new.js index cd0e8e7b4a9eb..fc44a566af21f 100644 --- a/tests/rustdoc-js-std/vec-new.js +++ b/tests/rustdoc-js-std/vec-new.js @@ -3,7 +3,8 @@ const QUERY = 'Vec::new'; const EXPECTED = { 'others': [ { 'path': 'std::vec::Vec', 'name': 'new' }, - { 'path': 'std::vec::Vec', 'name': 'ne' }, - { 'path': 'alloc::vec::Vec', 'name': 'ne' }, + { 'path': 'alloc::vec::Vec', 'name': 'new' }, + { 'path': 'std::vec::Vec', 'name': 'new_in' }, + { 'path': 'alloc::vec::Vec', 'name': 'new_in' }, ], }; diff --git a/tests/rustdoc-js/search-short-types.js b/tests/rustdoc-js/search-short-types.js index d14672af71fd6..3b2f15a40bf87 100644 --- a/tests/rustdoc-js/search-short-types.js +++ b/tests/rustdoc-js/search-short-types.js @@ -4,7 +4,6 @@ const EXPECTED = { 'others': [ { 'path': 'search_short_types', 'name': 'P' }, { 'path': 'search_short_types::VeryLongTypeName', 'name': 'p' }, - { 'path': 'search_short_types', 'name': 'Ap' }, - { 'path': 'search_short_types::VeryLongTypeName', 'name': 'ap' }, + { 'path': 'search_short_types', 'name': 'Pa' }, ], }; diff --git a/tests/ui/async-await/in-trait/missing-send-bound.rs b/tests/ui/async-await/in-trait/missing-send-bound.rs new file mode 100644 index 0000000000000..78922b59b27b7 --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-send-bound.rs @@ -0,0 +1,21 @@ +// edition:2021 + +#![feature(async_fn_in_trait)] +//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + +trait Foo { + async fn bar(); +} + +async fn test() { + T::bar().await; +} + +fn test2() { + assert_is_send(test::()); + //~^ ERROR future cannot be sent between threads safely +} + +fn assert_is_send(_: impl Send) {} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr new file mode 100644 index 0000000000000..5cedf3ddb0f68 --- /dev/null +++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr @@ -0,0 +1,29 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/missing-send-bound.rs:3:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: future cannot be sent between threads safely + --> $DIR/missing-send-bound.rs:15:20 + | +LL | assert_is_send(test::()); + | ^^^^^^^^^^^ future returned by `test` is not `Send` + | + = help: within `impl Future`, the trait `Send` is not implemented for `impl Future` +note: future is not `Send` as it awaits another future which is not `Send` + --> $DIR/missing-send-bound.rs:11:5 + | +LL | T::bar().await; + | ^^^^^^^^ await occurs here on type `impl Future`, which is not `Send` +note: required by a bound in `assert_is_send` + --> $DIR/missing-send-bound.rs:19:27 + | +LL | fn assert_is_send(_: impl Send) {} + | ^^^^ required by this bound in `assert_is_send` + +error: aborting due to previous error; 1 warning emitted +