From 68a58f255ac7b7487769667fdd5fe2536f952c15 Mon Sep 17 00:00:00 2001 From: Ross Smyth Date: Thu, 15 Feb 2024 19:54:35 -0500 Subject: Add postfix-match experimental feature Co-authored-by: Josh Stone --- compiler/rustc_span/src/symbol.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'compiler/rustc_span/src') diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3784a08b1b7..2474189fef6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1319,6 +1319,7 @@ symbols! { poll, poll_next, post_dash_lto: "post-lto", + postfix_match, powerpc_target_feature, powf128, powf16, -- cgit 1.4.1-3-g733a5 From 05116c5c30dea6895fb65fe31b6f2dd0f1198b51 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 13 Feb 2024 15:29:50 +0000 Subject: Only split by-ref/by-move futures for async closures --- .../rustc_borrowck/src/type_check/input_output.rs | 2 +- compiler/rustc_hir_typeck/src/callee.rs | 14 ++-- compiler/rustc_hir_typeck/src/closure.rs | 6 +- compiler/rustc_hir_typeck/src/upvar.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 12 --- compiler/rustc_middle/src/mir/visit.rs | 6 +- compiler/rustc_middle/src/ty/instance.rs | 18 ++-- compiler/rustc_middle/src/ty/sty.rs | 17 +++- .../src/coroutine/by_move_body.rs | 35 -------- compiler/rustc_mir_transform/src/pass_manager.rs | 3 - compiler/rustc_mir_transform/src/shim.rs | 98 +++------------------- compiler/rustc_span/src/symbol.rs | 3 +- compiler/rustc_symbol_mangling/src/legacy.rs | 14 +--- compiler/rustc_symbol_mangling/src/v0.rs | 8 +- .../src/solve/normalizes_to/mod.rs | 2 +- .../rustc_trait_selection/src/traits/project.rs | 12 +-- compiler/rustc_ty_utils/src/abi.rs | 18 ++-- compiler/rustc_ty_utils/src/instance.rs | 33 +++----- library/alloc/src/boxed.rs | 8 +- library/core/src/ops/async_function.rs | 30 +++---- .../src/library-features/async-fn-traits.md | 2 +- ...{closure#0}.coroutine_by_move.0.panic-abort.mir | 2 +- ...closure#0}.coroutine_by_move.0.panic-unwind.mir | 2 +- ...-{closure#0}.coroutine_by_mut.0.panic-abort.mir | 47 ----------- ...{closure#0}.coroutine_by_mut.0.panic-unwind.mir | 47 ----------- ...#0}.coroutine_closure_by_move.0.panic-abort.mir | 6 +- ...0}.coroutine_closure_by_move.0.panic-unwind.mir | 6 +- ...e#0}.coroutine_closure_by_mut.0.panic-abort.mir | 16 ---- ...#0}.coroutine_closure_by_mut.0.panic-unwind.mir | 16 ---- tests/mir-opt/async_closure_shims.rs | 2 - .../ui/async-await/async-closures/def-path.stderr | 4 +- tests/ui/async-await/async-fn/dyn-pos.rs | 3 - tests/ui/async-await/async-fn/dyn-pos.stderr | 57 ++----------- 33 files changed, 119 insertions(+), 432 deletions(-) delete mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir delete mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir delete mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir delete mode 100644 tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir (limited to 'compiler/rustc_span/src') diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 575aab47ac7..a4c1066ee8e 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -87,7 +87,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.tcx(), ty::CoroutineArgsParts { parent_args: args.parent_args(), - kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()), + kind_ty: Ty::from_coroutine_closure_kind(self.tcx(), args.kind()), return_ty: user_provided_sig.output(), tupled_upvars_ty, // For async closures, none of these can be annotated, so just fill diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9a500fa712b..0e75a47683d 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -184,16 +184,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: TypeVariableOriginKind::TypeInference, span: callee_expr.span, }); + // We may actually receive a coroutine back whose kind is different + // from the closure that this dispatched from. This is because when + // we have no captures, we automatically implement `FnOnce`. This + // impl forces the closure kind to `FnOnce` i.e. `u8`. + let kind_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: callee_expr.span, + }); let call_sig = self.tcx.mk_fn_sig( [coroutine_closure_sig.tupled_inputs_ty], coroutine_closure_sig.to_coroutine( self.tcx, closure_args.parent_args(), - // Inherit the kind ty of the closure, since we're calling this - // coroutine with the most relaxed `AsyncFn*` trait that we can. - // We don't necessarily need to do this here, but it saves us - // computing one more infer var that will get constrained later. - closure_args.kind_ty(), + kind_ty, self.tcx.coroutine_for_closure(def_id), tupled_upvars_ty, ), diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 4bea4bb3e82..6e30cb02245 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -262,6 +262,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ); + let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: expr_span, + }); let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::ClosureSynthetic, span: expr_span, @@ -279,7 +283,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sig.to_coroutine( tcx, parent_args, - closure_kind_ty, + coroutine_kind_ty, tcx.coroutine_for_closure(expr_def_id), coroutine_upvars_ty, ) diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index be14f5bf0d8..b71e88a1579 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -410,7 +410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype( span, coroutine_args.as_coroutine().kind_ty(), - Ty::from_closure_kind(self.tcx, closure_kind), + Ty::from_coroutine_closure_kind(self.tcx, closure_kind), ); } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d57ffc0f8b5..984d4687ef8 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -278,13 +278,6 @@ pub struct CoroutineInfo<'tcx> { /// using `run_passes`. pub by_move_body: Option>, - /// The body of the coroutine, modified to take its upvars by mutable ref rather than by - /// immutable ref. - /// - /// FIXME(async_closures): This is literally the same body as the parent body. Find a better - /// way to represent the by-mut signature (or cap the closure-kind of the coroutine). - pub by_mut_body: Option>, - /// The layout of a coroutine. This field is populated after the state transform pass. pub coroutine_layout: Option>, @@ -305,7 +298,6 @@ impl<'tcx> CoroutineInfo<'tcx> { yield_ty: Some(yield_ty), resume_ty: Some(resume_ty), by_move_body: None, - by_mut_body: None, coroutine_drop: None, coroutine_layout: None, } @@ -628,10 +620,6 @@ impl<'tcx> Body<'tcx> { self.coroutine.as_ref()?.by_move_body.as_ref() } - pub fn coroutine_by_mut_body(&self) -> Option<&Body<'tcx>> { - self.coroutine.as_ref()?.by_mut_body.as_ref() - } - #[inline] pub fn coroutine_kind(&self) -> Option { self.coroutine.as_ref().map(|coroutine| coroutine.coroutine_kind) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 845b1717550..562aed5a643 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -345,8 +345,10 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | - ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } | - ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id, target_kind: _ } | + ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id: _def_id, + } | + ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 814c3629b08..bbe0915baa2 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -90,16 +90,12 @@ pub enum InstanceDef<'tcx> { /// and dispatch to the `FnMut::call_mut` instance for the closure. ClosureOnceShim { call_once: DefId, track_caller: bool }, - /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` or - /// `<[Fn coroutine-closure] as FnMut>::call_mut`. + /// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` /// /// The body generated here differs significantly from the `ClosureOnceShim`, /// since we need to generate a distinct coroutine type that will move the /// closure's upvars *out* of the closure. - ConstructCoroutineInClosureShim { - coroutine_closure_def_id: DefId, - target_kind: ty::ClosureKind, - }, + ConstructCoroutineInClosureShim { coroutine_closure_def_id: DefId }, /// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce` /// is called on a coroutine-closure whose closure kind greater than `FnOnce`, or @@ -107,7 +103,7 @@ pub enum InstanceDef<'tcx> { /// /// This will select the body that is produced by the `ByMoveBody` transform, and thus /// take and use all of its upvars by-move rather than by-ref. - CoroutineKindShim { coroutine_def_id: DefId, target_kind: ty::ClosureKind }, + CoroutineKindShim { coroutine_def_id: DefId }, /// Compiler-generated accessor for thread locals which returns a reference to the thread local /// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking @@ -192,9 +188,8 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: def_id, - target_kind: _, } - | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id, target_kind: _ } + | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) | InstanceDef::FnPtrAddrShim(def_id, _) => def_id, @@ -651,10 +646,7 @@ impl<'tcx> Instance<'tcx> { Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) } else { Some(Instance { - def: ty::InstanceDef::CoroutineKindShim { - coroutine_def_id, - target_kind: args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(), - }, + def: ty::InstanceDef::CoroutineKindShim { coroutine_def_id }, args, }) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 540936d7d8a..67908013041 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -483,7 +483,7 @@ impl<'tcx> CoroutineClosureSignature<'tcx> { self.to_coroutine( tcx, parent_args, - Ty::from_closure_kind(tcx, goal_kind), + Ty::from_coroutine_closure_kind(tcx, goal_kind), coroutine_def_id, tupled_upvars_ty, ) @@ -2456,6 +2456,21 @@ impl<'tcx> Ty<'tcx> { } } + /// Like [`Ty::to_opt_closure_kind`], but it caps the "maximum" closure kind + /// to `FnMut`. This is because although we have three capability states, + /// `AsyncFn`/`AsyncFnMut`/`AsyncFnOnce`, we only need to distinguish two coroutine + /// bodies: by-ref and by-value. + /// + /// This method should be used when constructing a `Coroutine` out of a + /// `CoroutineClosure`, when the `Coroutine`'s `kind` field is being populated + /// directly from the `CoroutineClosure`'s `kind`. + pub fn from_coroutine_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> { + match kind { + ty::ClosureKind::Fn | ty::ClosureKind::FnMut => tcx.types.i16, + ty::ClosureKind::FnOnce => tcx.types.i32, + } + } + /// Fast path helper for testing if a type is `Sized`. /// /// Returning true means the type is known to be sized. Returning diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index e40f4520671..000b96ee801 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -67,45 +67,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { by_move_body.source = mir::MirSource { instance: InstanceDef::CoroutineKindShim { coroutine_def_id: coroutine_def_id.to_def_id(), - target_kind: ty::ClosureKind::FnOnce, }, promoted: None, }; body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body); - - // If this is coming from an `AsyncFn` coroutine-closure, we must also create a by-mut body. - // This is actually just a copy of the by-ref body, but with a different self type. - // FIXME(async_closures): We could probably unify this with the by-ref body somehow. - if coroutine_kind == ty::ClosureKind::Fn { - let by_mut_coroutine_ty = Ty::new_coroutine( - tcx, - coroutine_def_id.to_def_id(), - ty::CoroutineArgs::new( - tcx, - ty::CoroutineArgsParts { - parent_args: args.as_coroutine().parent_args(), - kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnMut), - resume_ty: args.as_coroutine().resume_ty(), - yield_ty: args.as_coroutine().yield_ty(), - return_ty: args.as_coroutine().return_ty(), - witness: args.as_coroutine().witness(), - tupled_upvars_ty: args.as_coroutine().tupled_upvars_ty(), - }, - ) - .args, - ); - let mut by_mut_body = body.clone(); - by_mut_body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty = by_mut_coroutine_ty; - dump_mir(tcx, false, "coroutine_by_mut", &0, &by_mut_body, |_, _| Ok(())); - by_mut_body.source = mir::MirSource { - instance: InstanceDef::CoroutineKindShim { - coroutine_def_id: coroutine_def_id.to_def_id(), - target_kind: ty::ClosureKind::FnMut, - }, - promoted: None, - }; - body.coroutine.as_mut().unwrap().by_mut_body = Some(by_mut_body); - } } } diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 77478cc741d..17a1c3c7157 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -186,9 +186,6 @@ fn run_passes_inner<'tcx>( if let Some(by_move_body) = coroutine.by_move_body.as_mut() { run_passes_inner(tcx, by_move_body, passes, phase_change, validate_each); } - if let Some(by_mut_body) = coroutine.by_mut_body.as_mut() { - run_passes_inner(tcx, by_mut_body, passes, phase_change, validate_each); - } } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 733e2f93b25..3efaa69a7e7 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -3,8 +3,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::query::Providers; +use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, CoroutineArgs, EarlyBinder, Ty, TyCtxt}; -use rustc_middle::ty::{GenericArgs, CAPTURE_STRUCT_LOCAL}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_index::{Idx, IndexVec}; @@ -70,39 +70,13 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) } - ty::InstanceDef::ConstructCoroutineInClosureShim { - coroutine_closure_def_id, - target_kind, - } => match target_kind { - ty::ClosureKind::Fn => unreachable!("shouldn't be building shim for Fn"), - ty::ClosureKind::FnMut => { - // No need to optimize the body, it has already been optimized - // since we steal it from the `AsyncFn::call` body and just fix - // the return type. - return build_construct_coroutine_by_mut_shim(tcx, coroutine_closure_def_id); - } - ty::ClosureKind::FnOnce => { - build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id) - } - }, + ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id } => { + build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id) + } - ty::InstanceDef::CoroutineKindShim { coroutine_def_id, target_kind } => match target_kind { - ty::ClosureKind::Fn => unreachable!(), - ty::ClosureKind::FnMut => { - return tcx - .optimized_mir(coroutine_def_id) - .coroutine_by_mut_body() - .unwrap() - .clone(); - } - ty::ClosureKind::FnOnce => { - return tcx - .optimized_mir(coroutine_def_id) - .coroutine_by_move_body() - .unwrap() - .clone(); - } - }, + ty::InstanceDef::CoroutineKindShim { coroutine_def_id } => { + return tcx.optimized_mir(coroutine_def_id).coroutine_by_move_body().unwrap().clone(); + } ty::InstanceDef::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end @@ -123,21 +97,11 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let body = if id_args.as_coroutine().kind_ty() == args.as_coroutine().kind_ty() { coroutine_body.coroutine_drop().unwrap() } else { - match args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() { - ty::ClosureKind::Fn => { - unreachable!() - } - ty::ClosureKind::FnMut => coroutine_body - .coroutine_by_mut_body() - .unwrap() - .coroutine_drop() - .unwrap(), - ty::ClosureKind::FnOnce => coroutine_body - .coroutine_by_move_body() - .unwrap() - .coroutine_drop() - .unwrap(), - } + assert_eq!( + args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(), + ty::ClosureKind::FnOnce + ); + coroutine_body.coroutine_by_move_body().unwrap().coroutine_drop().unwrap() }; let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args); @@ -1112,7 +1076,6 @@ fn build_construct_coroutine_by_move_shim<'tcx>( let source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id, - target_kind: ty::ClosureKind::FnOnce, }); let body = @@ -1121,40 +1084,3 @@ fn build_construct_coroutine_by_move_shim<'tcx>( body } - -fn build_construct_coroutine_by_mut_shim<'tcx>( - tcx: TyCtxt<'tcx>, - coroutine_closure_def_id: DefId, -) -> Body<'tcx> { - let mut body = tcx.optimized_mir(coroutine_closure_def_id).clone(); - let coroutine_closure_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity(); - let ty::CoroutineClosure(_, args) = *coroutine_closure_ty.kind() else { - bug!(); - }; - let args = args.as_coroutine_closure(); - - body.local_decls[RETURN_PLACE].ty = - tcx.instantiate_bound_regions_with_erased(args.coroutine_closure_sig().map_bound(|sig| { - sig.to_coroutine_given_kind_and_upvars( - tcx, - args.parent_args(), - tcx.coroutine_for_closure(coroutine_closure_def_id), - ty::ClosureKind::FnMut, - tcx.lifetimes.re_erased, - args.tupled_upvars_ty(), - args.coroutine_captures_by_ref_ty(), - ) - })); - body.local_decls[CAPTURE_STRUCT_LOCAL].ty = - Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_closure_ty); - - body.source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { - coroutine_closure_def_id, - target_kind: ty::ClosureKind::FnMut, - }); - - body.pass_count = 0; - dump_mir(tcx, false, "coroutine_closure_by_mut", &0, &body, |_, _| Ok(())); - - body -} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 63b950a2803..8b911a41a11 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -166,9 +166,8 @@ symbols! { Break, C, CStr, - CallFuture, - CallMutFuture, CallOnceFuture, + CallRefFuture, Capture, Center, Cleanup, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 83e920e2f8e..1c62ce2d214 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -76,16 +76,10 @@ pub(super) fn mangle<'tcx>( } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. - ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } - | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind { - ty::ClosureKind::Fn => unreachable!(), - ty::ClosureKind::FnMut => { - printer.write_str("{{fn-mut-shim}}").unwrap(); - } - ty::ClosureKind::FnOnce => { - printer.write_str("{{fn-once-shim}}").unwrap(); - } - }, + ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } => { + printer.write_str("{{fn-once-shim}}").unwrap(); + } _ => {} } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f1b1b4ed2bb..6bc375512ac 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -46,12 +46,8 @@ pub(super) fn mangle<'tcx>( ty::InstanceDef::VTableShim(_) => Some("vtable"), ty::InstanceDef::ReifyShim(_) => Some("reify"), - ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } - | ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind { - ty::ClosureKind::Fn => unreachable!(), - ty::ClosureKind::FnMut => Some("fn_mut"), - ty::ClosureKind::FnOnce => Some("fn_once"), - }, + ty::InstanceDef::ConstructCoroutineInClosureShim { .. } + | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"), _ => None, }; diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index d24bec5a766..85bb6338daf 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -414,7 +414,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ), output_coroutine_ty.into(), ), - sym::CallMutFuture | sym::CallFuture => ( + sym::CallRefFuture => ( ty::AliasTy::new( tcx, goal.predicate.def_id(), diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6756b5dec23..12371155303 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1726,7 +1726,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let sig = args.coroutine_closure_sig().skip_binder(); let term = match item_name { - sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => { + sym::CallOnceFuture | sym::CallRefFuture => { if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { if !closure_kind.extends(goal_kind) { bug!("we should not be confirming if the closure kind is not met"); @@ -1787,7 +1787,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty], ), - sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new( + sym::CallRefFuture => ty::AliasTy::new( tcx, obligation.predicate.def_id, [ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()], @@ -1803,7 +1803,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let sig = bound_sig.skip_binder(); let term = match item_name { - sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(), + sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); let future_output_def_id = tcx @@ -1822,7 +1822,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( obligation.predicate.def_id, [self_ty, Ty::new_tup(tcx, sig.inputs())], ), - sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new( + sym::CallRefFuture => ty::AliasTy::new( tcx, obligation.predicate.def_id, [ @@ -1842,7 +1842,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let sig = bound_sig.skip_binder(); let term = match item_name { - sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(), + sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); let future_output_def_id = tcx @@ -1859,7 +1859,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( sym::CallOnceFuture | sym::Output => { ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.inputs()[0]]) } - sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new( + sym::CallRefFuture => ty::AliasTy::new( tcx, obligation.predicate.def_id, [ty::GenericArg::from(self_ty), sig.inputs()[0].into(), env_region.into()], diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index a5328baadb5..7d54083fbd5 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -102,6 +102,7 @@ fn fn_sig_for_fn_abi<'tcx>( ) } ty::CoroutineClosure(def_id, args) => { + let coroutine_ty = Ty::new_coroutine_closure(tcx, def_id, args); let sig = args.as_coroutine_closure().coroutine_closure_sig(); let bound_vars = tcx.mk_bound_variable_kinds_from_iter( sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), @@ -111,18 +112,17 @@ fn fn_sig_for_fn_abi<'tcx>( kind: ty::BoundRegionKind::BrEnv, }; let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); - // When this `CoroutineClosure` comes from a `ConstructCoroutineInClosureShim`, // make sure we respect the `target_kind` in that shim. // FIXME(async_closures): This shouldn't be needed, and we should be populating // a separate def-id for these bodies. - let mut kind = args.as_coroutine_closure().kind(); - if let InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } = instance.def { - kind = target_kind; + let mut coroutine_kind = args.as_coroutine_closure().kind(); + + if let InstanceDef::ConstructCoroutineInClosureShim { .. } = instance.def { + coroutine_kind = ty::ClosureKind::FnOnce; } - let env_ty = - tcx.closure_env_ty(Ty::new_coroutine_closure(tcx, def_id, args), kind, env_region); + let env_ty = tcx.closure_env_ty(coroutine_ty, coroutine_kind, env_region); let sig = sig.skip_binder(); ty::Binder::bind_with_vars( @@ -132,7 +132,7 @@ fn fn_sig_for_fn_abi<'tcx>( tcx, args.as_coroutine_closure().parent_args(), tcx.coroutine_for_closure(def_id), - kind, + coroutine_kind, env_region, args.as_coroutine_closure().tupled_upvars_ty(), args.as_coroutine_closure().coroutine_captures_by_ref_ty(), @@ -161,7 +161,7 @@ fn fn_sig_for_fn_abi<'tcx>( // make sure we respect the `target_kind` in that shim. // FIXME(async_closures): This shouldn't be needed, and we should be populating // a separate def-id for these bodies. - if let InstanceDef::CoroutineKindShim { target_kind, .. } = instance.def { + if let InstanceDef::CoroutineKindShim { .. } = instance.def { // Grab the parent coroutine-closure. It has the same args for the purposes // of instantiation, so this will be okay to do. let ty::CoroutineClosure(_, coroutine_closure_args) = *tcx @@ -181,7 +181,7 @@ fn fn_sig_for_fn_abi<'tcx>( tcx, coroutine_closure_args.parent_args(), did, - target_kind, + ty::ClosureKind::FnOnce, tcx.lifetimes.re_erased, coroutine_closure_args.tupled_upvars_ty(), coroutine_closure_args.coroutine_captures_by_ref_ty(), diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 2816bcc888b..c2ea89f4c29 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -282,7 +282,6 @@ fn resolve_associated_item<'tcx>( Some(Instance { def: ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id, - target_kind: ty::ClosureKind::FnOnce, }, args, }) @@ -297,25 +296,19 @@ fn resolve_associated_item<'tcx>( { match *rcvr_args.type_at(0).kind() { ty::CoroutineClosure(coroutine_closure_def_id, args) => { - match (target_kind, args.as_coroutine_closure().kind()) { - (ClosureKind::FnOnce | ClosureKind::FnMut, ClosureKind::Fn) - | (ClosureKind::FnOnce, ClosureKind::FnMut) => { - // If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure, - // or `AsyncFnOnce` for a by-mut closure, then construct a new body that - // has the right return types. - // - // Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs - // to have its input and output types fixed (`&mut self` and returning - // `i16` coroutine kind). - Some(Instance { - def: ty::InstanceDef::ConstructCoroutineInClosureShim { - coroutine_closure_def_id, - target_kind, - }, - args, - }) - } - _ => Some(Instance::new(coroutine_closure_def_id, args)), + if target_kind == ClosureKind::FnOnce + && args.as_coroutine_closure().kind() != ClosureKind::FnOnce + { + // If we're computing `AsyncFnOnce` for a by-ref closure then + // construct a new body that has the right return types. + Some(Instance { + def: ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + }, + args, + }) + } else { + Some(Instance::new(coroutine_closure_def_id, args)) } } ty::Closure(closure_def_id, args) => { diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index f47fe560b07..cfaf533088a 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -2042,18 +2042,16 @@ impl + ?Sized, A: Allocator> AsyncFnOnce #[unstable(feature = "async_fn_traits", issue = "none")] impl + ?Sized, A: Allocator> AsyncFnMut for Box { - type CallMutFuture<'a> = F::CallMutFuture<'a> where Self: 'a; + type CallRefFuture<'a> = F::CallRefFuture<'a> where Self: 'a; - extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_> { + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_> { F::async_call_mut(self, args) } } #[unstable(feature = "async_fn_traits", issue = "none")] impl + ?Sized, A: Allocator> AsyncFn for Box { - type CallFuture<'a> = F::CallFuture<'a> where Self: 'a; - - extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_> { + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> { F::async_call(self, args) } } diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index d6b06ffb7fc..6c8a0daf6f3 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -10,15 +10,9 @@ use crate::marker::Tuple; #[must_use = "async closures are lazy and do nothing unless called"] #[lang = "async_fn"] pub trait AsyncFn: AsyncFnMut { - /// Future returned by [`AsyncFn::async_call`]. - #[unstable(feature = "async_fn_traits", issue = "none")] - type CallFuture<'a>: Future - where - Self: 'a; - /// Call the [`AsyncFn`], returning a future which may borrow from the called closure. #[unstable(feature = "async_fn_traits", issue = "none")] - extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_>; + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_>; } /// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait. @@ -30,15 +24,15 @@ pub trait AsyncFn: AsyncFnMut { #[must_use = "async closures are lazy and do nothing unless called"] #[lang = "async_fn_mut"] pub trait AsyncFnMut: AsyncFnOnce { - /// Future returned by [`AsyncFnMut::async_call_mut`]. + /// Future returned by [`AsyncFnMut::async_call_mut`] and [`AsyncFn::async_call`]. #[unstable(feature = "async_fn_traits", issue = "none")] - type CallMutFuture<'a>: Future + type CallRefFuture<'a>: Future where Self: 'a; /// Call the [`AsyncFnMut`], returning a future which may borrow from the called closure. #[unstable(feature = "async_fn_traits", issue = "none")] - extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_>; + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_>; } /// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait. @@ -72,9 +66,7 @@ mod impls { where F: AsyncFn, { - type CallFuture<'a> = F::CallFuture<'a> where Self: 'a; - - extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> { + extern "rust-call" fn async_call(&self, args: A) -> Self::CallRefFuture<'_> { F::async_call(*self, args) } } @@ -84,9 +76,9 @@ mod impls { where F: AsyncFn, { - type CallMutFuture<'a> = F::CallFuture<'a> where Self: 'a; + type CallRefFuture<'a> = F::CallRefFuture<'a> where Self: 'a; - extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> { + extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallRefFuture<'_> { F::async_call(*self, args) } } @@ -97,7 +89,7 @@ mod impls { F: AsyncFn, { type Output = F::Output; - type CallOnceFuture = F::CallFuture<'a>; + type CallOnceFuture = F::CallRefFuture<'a>; extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { F::async_call(self, args) @@ -109,9 +101,9 @@ mod impls { where F: AsyncFnMut, { - type CallMutFuture<'a> = F::CallMutFuture<'a> where Self: 'a; + type CallRefFuture<'a> = F::CallRefFuture<'a> where Self: 'a; - extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> { + extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallRefFuture<'_> { F::async_call_mut(*self, args) } } @@ -122,7 +114,7 @@ mod impls { F: AsyncFnMut, { type Output = F::Output; - type CallOnceFuture = F::CallMutFuture<'a>; + type CallOnceFuture = F::CallRefFuture<'a>; extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { F::async_call_mut(self, args) diff --git a/src/doc/unstable-book/src/library-features/async-fn-traits.md b/src/doc/unstable-book/src/library-features/async-fn-traits.md index e1c3f067e5b..a0edb3c7dd2 100644 --- a/src/doc/unstable-book/src/library-features/async-fn-traits.md +++ b/src/doc/unstable-book/src/library-features/async-fn-traits.md @@ -10,4 +10,4 @@ for creating custom closure-like types that return futures. [`AsyncFn*`]: ../../std/ops/trait.AsyncFn.html The main difference to the `Fn*` family of traits is that `AsyncFn` can return a future -that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFn::CallFuture` does). +that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFnMut::CallRefFuture` does). diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir index 1fae40c5f40..6ca3dd61005 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-abort.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move -fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:37:53: 40:10}, _2: ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir index 1fae40c5f40..6ca3dd61005 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.panic-unwind.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move -fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () +fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:37:53: 40:10}, _2: ResumeTy) -> () yields () { debug _task_context => _2; diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir deleted file mode 100644 index 9886d6f68a4..00000000000 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-abort.mir +++ /dev/null @@ -1,47 +0,0 @@ -// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut - -fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () -yields () - { - debug _task_context => _2; - debug a => (_1.0: i32); - debug b => (*(_1.1: &i32)); - let mut _0: (); - let _3: i32; - scope 1 { - debug a => _3; - let _4: &i32; - scope 2 { - debug a => _4; - let _5: &i32; - scope 3 { - debug b => _5; - } - } - } - - bb0: { - StorageLive(_3); - _3 = (_1.0: i32); - FakeRead(ForLet(None), _3); - StorageLive(_4); - _4 = &_3; - FakeRead(ForLet(None), _4); - StorageLive(_5); - _5 = &(*(_1.1: &i32)); - FakeRead(ForLet(None), _5); - _0 = const (); - StorageDead(_5); - StorageDead(_4); - StorageDead(_3); - drop(_1) -> [return: bb1, unwind: bb2]; - } - - bb1: { - return; - } - - bb2 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir deleted file mode 100644 index 9886d6f68a4..00000000000 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.panic-unwind.mir +++ /dev/null @@ -1,47 +0,0 @@ -// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut - -fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> () -yields () - { - debug _task_context => _2; - debug a => (_1.0: i32); - debug b => (*(_1.1: &i32)); - let mut _0: (); - let _3: i32; - scope 1 { - debug a => _3; - let _4: &i32; - scope 2 { - debug a => _4; - let _5: &i32; - scope 3 { - debug b => _5; - } - } - } - - bb0: { - StorageLive(_3); - _3 = (_1.0: i32); - FakeRead(ForLet(None), _3); - StorageLive(_4); - _4 = &_3; - FakeRead(ForLet(None), _4); - StorageLive(_5); - _5 = &(*(_1.1: &i32)); - FakeRead(ForLet(None), _5); - _0 = const (); - StorageDead(_5); - StorageDead(_4); - StorageDead(_3); - drop(_1) -> [return: bb1, unwind: bb2]; - } - - bb1: { - return; - } - - bb2 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir index 21a9f6f8721..b5768e14452 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir @@ -1,10 +1,10 @@ // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move -fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { - let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; +fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:37:33: 37:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:37:53: 40:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:37:53: 40:10}; bb0: { - _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) }; + _0 = {coroutine@$DIR/async_closure_shims.rs:37:53: 40:10 (#0)} { a: move _2, b: move (_1.0: i32) }; return; } } diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir index 21a9f6f8721..b5768e14452 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir @@ -1,10 +1,10 @@ // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move -fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { - let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; +fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:37:33: 37:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:37:53: 40:10} { + let mut _0: {async closure body@$DIR/async_closure_shims.rs:37:53: 40:10}; bb0: { - _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) }; + _0 = {coroutine@$DIR/async_closure_shims.rs:37:53: 40:10 (#0)} { a: move _2, b: move (_1.0: i32) }; return; } } diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir deleted file mode 100644 index 1cfb6c2f3ea..00000000000 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir +++ /dev/null @@ -1,16 +0,0 @@ -// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut - -fn main::{closure#0}::{closure#0}(_1: &mut {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { - debug a => _2; - debug b => ((*_1).0: i32); - let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; - let mut _3: &i32; - - bb0: { - StorageLive(_3); - _3 = &((*_1).0: i32); - _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 }; - StorageDead(_3); - return; - } -} diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir deleted file mode 100644 index 1cfb6c2f3ea..00000000000 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir +++ /dev/null @@ -1,16 +0,0 @@ -// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut - -fn main::{closure#0}::{closure#0}(_1: &mut {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} { - debug a => _2; - debug b => ((*_1).0: i32); - let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}; - let mut _3: &i32; - - bb0: { - StorageLive(_3); - _3 = &((*_1).0: i32); - _0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 }; - StorageDead(_3); - return; - } -} diff --git a/tests/mir-opt/async_closure_shims.rs b/tests/mir-opt/async_closure_shims.rs index 5e875321400..47c41ed0500 100644 --- a/tests/mir-opt/async_closure_shims.rs +++ b/tests/mir-opt/async_closure_shims.rs @@ -30,8 +30,6 @@ async fn call_once(f: impl AsyncFnOnce(i32)) { } // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir -// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.mir -// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.mir // EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.mir pub fn main() { block_on(async { diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr index dae45825f37..0a1e30c1253 100644 --- a/tests/ui/async-await/async-closures/def-path.stderr +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -5,11 +5,11 @@ LL | let x = async || {}; | -- the expected `async` closure body LL | LL | let () = x(); - | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?15t witness=?6t}` + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?16t witness=?6t}` | | | expected `async` closure body, found `()` | - = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?15t witness=?6t}` + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?16t witness=?6t}` found unit type `()` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/async-fn/dyn-pos.rs b/tests/ui/async-await/async-fn/dyn-pos.rs index e817a1b518f..772c7d15cfd 100644 --- a/tests/ui/async-await/async-fn/dyn-pos.rs +++ b/tests/ui/async-await/async-fn/dyn-pos.rs @@ -4,9 +4,6 @@ fn foo(x: &dyn async Fn()) {} //~^ ERROR the trait `AsyncFn` cannot be made into an object -//~| ERROR the trait `AsyncFn` cannot be made into an object -//~| ERROR the trait `AsyncFn` cannot be made into an object -//~| ERROR the trait `AsyncFn` cannot be made into an object //~| ERROR the trait `AsyncFnMut` cannot be made into an object //~| ERROR the trait `AsyncFnMut` cannot be made into an object //~| ERROR the trait `AsyncFnMut` cannot be made into an object diff --git a/tests/ui/async-await/async-fn/dyn-pos.stderr b/tests/ui/async-await/async-fn/dyn-pos.stderr index 488c5d06938..3bef5a27897 100644 --- a/tests/ui/async-await/async-fn/dyn-pos.stderr +++ b/tests/ui/async-await/async-fn/dyn-pos.stderr @@ -1,17 +1,3 @@ -error[E0038]: the trait `AsyncFn` cannot be made into an object - --> $DIR/dyn-pos.rs:5:16 - | -LL | fn foo(x: &dyn async Fn()) {} - | ^^^^^^^^^^ `AsyncFn` cannot be made into an object - | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL - | - = note: the trait cannot be made into an object because it contains the generic associated type `CallFuture` - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead: - &F - std::boxed::Box - error[E0038]: the trait `AsyncFnMut` cannot be made into an object --> $DIR/dyn-pos.rs:5:16 | @@ -21,27 +7,12 @@ LL | fn foo(x: &dyn async Fn()) {} note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | - = note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture` + = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture` = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead: &F &mut F std::boxed::Box -error[E0038]: the trait `AsyncFn` cannot be made into an object - --> $DIR/dyn-pos.rs:5:16 - | -LL | fn foo(x: &dyn async Fn()) {} - | ^^^^^^^^^^ `AsyncFn` cannot be made into an object - | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL - | - = note: the trait cannot be made into an object because it contains the generic associated type `CallFuture` - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead: - &F - std::boxed::Box - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0038]: the trait `AsyncFnMut` cannot be made into an object --> $DIR/dyn-pos.rs:5:16 | @@ -51,28 +22,13 @@ LL | fn foo(x: &dyn async Fn()) {} note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | - = note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture` + = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture` = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead: &F &mut F std::boxed::Box = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0038]: the trait `AsyncFn` cannot be made into an object - --> $DIR/dyn-pos.rs:5:16 - | -LL | fn foo(x: &dyn async Fn()) {} - | ^^^^^^^^^^ `AsyncFn` cannot be made into an object - | -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL - | - = note: the trait cannot be made into an object because it contains the generic associated type `CallFuture` - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead: - &F - std::boxed::Box - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0038]: the trait `AsyncFnMut` cannot be made into an object --> $DIR/dyn-pos.rs:5:16 | @@ -82,7 +38,7 @@ LL | fn foo(x: &dyn async Fn()) {} note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | - = note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture` + = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture` = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead: &F &mut F @@ -98,14 +54,11 @@ LL | fn foo(x: &dyn async Fn()) {} note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | - = note: the trait cannot be made into an object because it contains the generic associated type `CallFuture` - ::: $SRC_DIR/core/src/ops/async_function.rs:LL:COL - | - = note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture` + = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture` = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead: &F std::boxed::Box -error: aborting due to 7 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0038`. -- cgit 1.4.1-3-g733a5 From 120d3570aa467c287814fe3edb9003920d8232aa Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 8 Mar 2024 19:17:23 +0100 Subject: Add barest-bones deref patterns Co-authored-by: Deadbeef --- compiler/rustc_ast_passes/src/feature_gate.rs | 10 +++++-- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_hir_typeck/src/pat.rs | 28 +++++++++++++++++-- compiler/rustc_middle/src/thir.rs | 9 +++++++ compiler/rustc_middle/src/thir/visit.rs | 1 + compiler/rustc_mir_build/src/build/matches/mod.rs | 4 +++ compiler/rustc_mir_build/src/build/matches/util.rs | 6 +++++ compiler/rustc_mir_build/src/check_unsafety.rs | 3 ++- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 3 +++ compiler/rustc_mir_build/src/thir/print.rs | 6 +++++ compiler/rustc_pattern_analysis/src/rustc.rs | 6 +++++ compiler/rustc_span/src/symbol.rs | 1 + tests/ui/cfg/cfg-false-feature.stderr | 24 ++++++++--------- .../feature-gates/feature-gate-deref_patterns.rs | 9 +++++++ .../feature-gate-deref_patterns.stderr | 13 +++++++++ tests/ui/pattern/deref-patterns/typeck.rs | 31 ++++++++++++++++++++++ 16 files changed, 139 insertions(+), 17 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-deref_patterns.rs create mode 100644 tests/ui/feature-gates/feature-gate-deref_patterns.stderr create mode 100644 tests/ui/pattern/deref-patterns/typeck.rs (limited to 'compiler/rustc_span/src') diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2c396a64789..277e82b4e53 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -413,7 +413,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } PatKind::Box(..) => { - gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental"); + if !self.features.deref_patterns { + // Allow box patterns under `deref_patterns`. + gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental"); + } } PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => { gate!( @@ -607,13 +610,16 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { }; } + if !visitor.features.deref_patterns { + // Allow box patterns under `deref_patterns`. + gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental"); + } gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental"); // Despite being a new feature, `where T: Trait`, which is RTN syntax now, // used to be gated under associated_type_bounds, which are right above, so RTN needs to // be too. gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental"); gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental"); - gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental"); gate_all_legacy_dont_use!( exclusive_range_pattern, "exclusive range pattern syntax is experimental" diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index a3b13c4d907..1820e172ea5 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -436,6 +436,8 @@ declare_features! ( (unstable, deprecated_safe, "1.61.0", Some(94978)), /// Allows having using `suggestion` in the `#[deprecated]` attribute. (unstable, deprecated_suggestion, "1.61.0", Some(94785)), + /// Allows deref patterns. + (incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121)), /// Controls errors in trait implementations. (unstable, do_not_recommend, "1.67.0", Some(51992)), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 491da7eb2c2..633f851c7d5 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -18,8 +18,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Span; -use rustc_span::{BytePos, DUMMY_SP}; +use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::traits::{ObligationCause, Pattern}; use ty::VariantDef; @@ -211,6 +210,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Tuple(elements, ddpos) => { self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info) } + PatKind::Box(inner) if self.tcx.features().deref_patterns => { + self.check_pat_deref(pat.span, inner, expected, pat_info) + } PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), PatKind::Slice(before, slice, after) => { @@ -1975,6 +1977,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { box_ty } + fn check_pat_deref( + &self, + span: Span, + inner: &'tcx Pat<'tcx>, + expected: Ty<'tcx>, + pat_info: PatInfo<'tcx, '_>, + ) -> Ty<'tcx> { + let tcx = self.tcx; + // FIXME(deref_patterns): use `DerefPure` for soundness + // FIXME(deref_patterns): use `DerefMut` when required + // ::Target + let ty = Ty::new_projection( + tcx, + tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)), + [expected], + ); + let ty = self.normalize(span, ty); + let ty = self.try_structurally_resolve_type(span, ty); + self.check_pat(inner, ty, pat_info); + expected + } + // Precondition: Pat is Ref(inner) fn check_pat_ref( &self, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 96a61883cc1..fc9950a51fb 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -647,6 +647,7 @@ impl<'tcx> Pat<'tcx> { AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } + | DerefPattern { subpattern } | InlineConstant { subpattern, .. } => subpattern.walk_(it), Leaf { subpatterns } | Variant { subpatterns, .. } => { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) @@ -762,6 +763,11 @@ pub enum PatKind<'tcx> { subpattern: Box>, }, + /// Deref pattern, written `box P` for now. + DerefPattern { + subpattern: Box>, + }, + /// One of the following: /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus /// exhaustiveness checking will detect if you use the same string twice in different @@ -1172,6 +1178,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } write!(f, "{subpattern}") } + PatKind::DerefPattern { ref subpattern } => { + write!(f, "k#deref {subpattern}") + } PatKind::Constant { value } => write!(f, "{value}"), PatKind::InlineConstant { def: _, ref subpattern } => { write!(f, "{} (from inline const)", subpattern) diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 5952c296fb6..99ab006bcc0 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -229,6 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( match &pat.kind { AscribeUserType { subpattern, ascription: _ } | Deref { subpattern } + | DerefPattern { subpattern } | Binding { subpattern: Some(subpattern), mutability: _, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index d2cbbf9be32..f4f452d474f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -879,6 +879,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f); } + PatKind::DerefPattern { ref subpattern } => { + self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f); + } + PatKind::AscribeUserType { ref subpattern, ascription: thir::Ascription { ref annotation, variance: _ }, diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index d0d49c13f13..1148cd19a01 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -256,6 +256,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { subpairs.push(MatchPair::new(place_builder, subpattern, cx)); default_irrefutable() } + + PatKind::DerefPattern { .. } => { + // FIXME(deref_patterns) + // Treat it like a wildcard for now. + default_irrefutable() + } }; MatchPair { place, test_case, subpairs, pattern } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 1ce8da162bf..e04fe31a76f 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -250,6 +250,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | PatKind::Variant { .. } | PatKind::Leaf { .. } | PatKind::Deref { .. } + | PatKind::DerefPattern { .. } | PatKind::Range { .. } | PatKind::Slice { .. } | PatKind::Array { .. } => { @@ -310,7 +311,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } visit::walk_pat(self, pat); } - PatKind::Deref { .. } => { + PatKind::Deref { .. } | PatKind::DerefPattern { .. } => { let old_inside_adt = std::mem::replace(&mut self.inside_adt, false); visit::walk_pat(self, pat); self.inside_adt = old_inside_adt; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 03eda9a9322..f4aed91cd72 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -257,6 +257,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { return self.lower_path(qpath, pat.hir_id, pat.span); } + hir::PatKind::Box(subpattern) if self.tcx.features().deref_patterns => { + PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) } + } hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => { PatKind::Deref { subpattern: self.lower_pattern(subpattern) } } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index d53704f89e7..16c4248a159 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -688,6 +688,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } + PatKind::DerefPattern { subpattern } => { + print_indented!(self, "DerefPattern { ", depth_lvl + 1); + print_indented!(self, "subpattern:", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } PatKind::Constant { value } => { print_indented!(self, "Constant {", depth_lvl + 1); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index eedc00a5613..4cb306b1950 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -462,6 +462,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty), }; } + PatKind::DerefPattern { .. } => { + // FIXME(deref_patterns): At least detect that `box _` is irrefutable. + fields = vec![]; + arity = 0; + ctor = Opaque(OpaqueId::new()); + } PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { match ty.kind() { ty::Tuple(fs) => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b911a41a11..8b35087a005 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -674,6 +674,7 @@ symbols! { deref_method, deref_mut, deref_mut_method, + deref_patterns, deref_target, derive, derive_const, diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr index 9309b59ca59..542aeaf5caf 100644 --- a/tests/ui/cfg/cfg-false-feature.stderr +++ b/tests/ui/cfg/cfg-false-feature.stderr @@ -1,15 +1,3 @@ -warning: trait aliases are experimental - --> $DIR/cfg-false-feature.rs:12:1 - | -LL | trait A = Clone; - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #41517 for more information - = help: add `#![feature(trait_alias)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = warning: unstable syntax can change at any point in the future, causing a hard error! - = note: for more information, see issue #65860 - warning: box pattern syntax is experimental --> $DIR/cfg-false-feature.rs:16:9 | @@ -22,5 +10,17 @@ LL | let box _ = Box::new(0); = warning: unstable syntax can change at any point in the future, causing a hard error! = note: for more information, see issue #65860 +warning: trait aliases are experimental + --> $DIR/cfg-false-feature.rs:12:1 + | +LL | trait A = Clone; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #41517 for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = warning: unstable syntax can change at any point in the future, causing a hard error! + = note: for more information, see issue #65860 + warning: 2 warnings emitted diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.rs b/tests/ui/feature-gates/feature-gate-deref_patterns.rs new file mode 100644 index 00000000000..b43001f2d53 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-deref_patterns.rs @@ -0,0 +1,9 @@ +fn main() { + // We reuse the `box` syntax so this doesn't actually test the feature gate but eh. + let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental + println!("x: {}", x); + + // `box` syntax is allowed to be cfg-ed out for historical reasons (#65742). + #[cfg(FALSE)] + let box _x = Box::new('c'); +} diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.stderr b/tests/ui/feature-gates/feature-gate-deref_patterns.stderr new file mode 100644 index 00000000000..48426b50d89 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-deref_patterns.stderr @@ -0,0 +1,13 @@ +error[E0658]: box pattern syntax is experimental + --> $DIR/feature-gate-deref_patterns.rs:3:9 + | +LL | let box x = Box::new('c'); + | ^^^^^ + | + = note: see issue #29641 for more information + = help: add `#![feature(box_patterns)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs new file mode 100644 index 00000000000..20577abe485 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/typeck.rs @@ -0,0 +1,31 @@ +//@ check-pass +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +use std::rc::Rc; + +fn main() { + let vec: Vec = Vec::new(); + match vec { + box [..] => {} + _ => {} + } + match Box::new(true) { + box true => {} + _ => {} + } + match &Box::new(true) { + box true => {} + _ => {} + } + match &Rc::new(0) { + box (1..) => {} + _ => {} + } + // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a + // place of type `str`. + // match "foo".to_string() { + // box "foo" => {} + // _ => {} + // } +} -- cgit 1.4.1-3-g733a5 From ae4c5c891ec55e2bf78615650daded9124552ca0 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 22 Mar 2024 00:48:36 +0900 Subject: Implement `FusedIterator` for `gen` block --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_span/src/symbol.rs | 2 ++ .../src/solve/assembly/mod.rs | 9 ++++++ .../src/solve/normalizes_to/mod.rs | 7 +++++ .../rustc_trait_selection/src/solve/trait_goals.rs | 22 +++++++++++++++ .../src/traits/select/candidate_assembly.rs | 33 +++++++++++++++++----- .../src/traits/select/confirmation.rs | 2 ++ .../rustc_trait_selection/src/traits/select/mod.rs | 14 +++++++++ library/core/src/iter/traits/marker.rs | 1 + tests/ui/coroutine/gen_block_is_fused_iter.rs | 21 ++++++++++++++ 10 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 tests/ui/coroutine/gen_block_is_fused_iter.rs (limited to 'compiler/rustc_span/src') diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 5118bf5c3b7..dbf86f5cf74 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -214,6 +214,7 @@ language_item_table! { FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); + FusedIterator, sym::fused_iterator, fused_iterator_trait, Target::Trait, GenericRequirement::Exact(0); Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b911a41a11..c28c577d780 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -207,6 +207,7 @@ symbols! { FromResidual, FsOpenOptions, FsPermissions, + FusedIterator, Future, FutureOutput, GlobalAlloc, @@ -885,6 +886,7 @@ symbols! { fsub_algebraic, fsub_fast, fundamental, + fused_iterator, future, future_trait, gdb_script_file, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 9f33dce2a6d..d92bae2528f 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -215,6 +215,13 @@ pub(super) trait GoalKind<'tcx>: goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + /// A coroutine (that comes from a `gen` desugaring) is known to implement + /// `FusedIterator` + fn consider_builtin_fused_iterator_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; + fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -497,6 +504,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_future_candidate(self, goal) } else if lang_items.iterator_trait() == Some(trait_def_id) { G::consider_builtin_iterator_candidate(self, goal) + } else if lang_items.fused_iterator_trait() == Some(trait_def_id) { + G::consider_builtin_fused_iterator_candidate(self, goal) } else if lang_items.async_iterator_trait() == Some(trait_def_id) { G::consider_builtin_async_iterator_candidate(self, goal) } else if lang_items.coroutine_trait() == Some(trait_def_id) { diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 85bb6338daf..66688893235 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -647,6 +647,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ) } + fn consider_builtin_fused_iterator_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`FusedIterator` does not have an associated type: {:?}", goal); + } + fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index c252ad76dfe..184ba31f19d 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -456,6 +456,28 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + fn consider_builtin_fused_iterator_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + + let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else { + return Err(NoSolution); + }; + + // Coroutines are not iterators unless they come from `gen` desugaring + let tcx = ecx.tcx(); + if !tcx.coroutine_is_gen(def_id) { + return Err(NoSolution); + } + + // Gen coroutines unconditionally implement `FusedIterator` + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + fn consider_builtin_async_iterator_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 49091e53be7..9fb4577fb21 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -118,6 +118,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_future_candidates(obligation, &mut candidates); } else if lang_items.iterator_trait() == Some(def_id) { self.assemble_iterator_candidates(obligation, &mut candidates); + } else if lang_items.fused_iterator_trait() == Some(def_id) { + self.assemble_fused_iterator_candidates(obligation, &mut candidates); } else if lang_items.async_iterator_trait() == Some(def_id) { self.assemble_async_iterator_candidates(obligation, &mut candidates); } else if lang_items.async_fn_kind_helper() == Some(def_id) { @@ -302,14 +304,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) { let self_ty = obligation.self_ty().skip_binder(); - if let ty::Coroutine(did, ..) = self_ty.kind() { - // gen constructs get lowered to a special kind of coroutine that - // should directly `impl Iterator`. - if self.tcx().coroutine_is_gen(*did) { - debug!(?self_ty, ?obligation, "assemble_iterator_candidates",); + // gen constructs get lowered to a special kind of coroutine that + // should directly `impl Iterator`. + if let ty::Coroutine(did, ..) = self_ty.kind() + && self.tcx().coroutine_is_gen(*did) + { + debug!(?self_ty, ?obligation, "assemble_iterator_candidates",); - candidates.vec.push(IteratorCandidate); - } + candidates.vec.push(IteratorCandidate); + } + } + + fn assemble_fused_iterator_candidates( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let self_ty = obligation.self_ty().skip_binder(); + // gen constructs get lowered to a special kind of coroutine that + // should directly `impl FusedIterator`. + if let ty::Coroutine(did, ..) = self_ty.kind() + && self.tcx().coroutine_is_gen(*did) + { + debug!(?self_ty, ?obligation, "assemble_fused_iterator_candidates",); + + candidates.vec.push(BuiltinCandidate { has_nested: false }); } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 51fc223a5d1..aeac2ad77d7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -267,6 +267,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.copy_clone_conditions(obligation) } else if Some(trait_def) == lang_items.clone_trait() { self.copy_clone_conditions(obligation) + } else if Some(trait_def) == lang_items.fused_iterator_trait() { + self.fused_iterator_conditions(obligation) } else { bug!("unexpected builtin trait {:?}", trait_def) }; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 53aadfb8a44..adbc7d12a64 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2259,6 +2259,20 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } + fn fused_iterator_conditions( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> BuiltinImplConditions<'tcx> { + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + if let ty::Coroutine(did, ..) = *self_ty.kind() + && self.tcx().coroutine_is_gen(did) + { + BuiltinImplConditions::Where(ty::Binder::dummy(Vec::new())) + } else { + BuiltinImplConditions::None + } + } + /// For default impls, we need to break apart a type into its /// "constituent types" -- meaning, the types that it contains. /// diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index 8bdbca120d7..ad4d63d83b5 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -28,6 +28,7 @@ pub unsafe trait TrustedFused {} #[rustc_unsafe_specialization_marker] // FIXME: this should be a #[marker] and have another blanket impl for T: TrustedFused // but that ICEs iter::Fuse specializations. +#[cfg_attr(not(bootstrap), lang = "fused_iterator")] pub trait FusedIterator: Iterator {} #[stable(feature = "fused", since = "1.26.0")] diff --git a/tests/ui/coroutine/gen_block_is_fused_iter.rs b/tests/ui/coroutine/gen_block_is_fused_iter.rs new file mode 100644 index 00000000000..f3e19a7f54f --- /dev/null +++ b/tests/ui/coroutine/gen_block_is_fused_iter.rs @@ -0,0 +1,21 @@ +//@ revisions: next old +//@compile-flags: --edition 2024 -Zunstable-options +//@[next] compile-flags: -Znext-solver +//@ check-pass +#![feature(gen_blocks)] + +use std::iter::FusedIterator; + +fn foo() -> impl FusedIterator { + gen { yield 42 } +} + +fn bar() -> impl FusedIterator { + gen { yield 42 } +} + +fn baz() -> impl FusedIterator + Iterator { + gen { yield 42 } +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From 6f2c6efe019ef57585e1099e701c800417037e04 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 21 Mar 2024 19:47:46 +0000 Subject: Change syntax of the never type attribute thingy Previous: ```rust #![rustc_never_type_mode = "fallback_to_unit|..."] ``` New: ```rust #![rustc_never_type_options(fallback = "unit|...")] ``` This allows adding other options for other never-related experiments. --- compiler/rustc_feature/src/builtin_attrs.rs | 7 ++-- compiler/rustc_hir_typeck/src/fallback.rs | 36 +++---------------- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 52 +++++++++++++++++++++++++++- compiler/rustc_span/src/symbol.rs | 8 ++--- 4 files changed, 63 insertions(+), 40 deletions(-) (limited to 'compiler/rustc_span/src') diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index d4d7833cb21..22cf50fce7f 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -597,9 +597,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( - rustc_never_type_mode, Normal, template!(NameValueStr: "fallback_to_unit|fallback_to_niko|fallback_to_never|no_fallback"), ErrorFollowing, + rustc_never_type_options, + Normal, + template!(List: r#"/*opt*/ fallback = "unit|niko|never|no""#), + ErrorFollowing, EncodeCrossCrate::No, - "`rustc_never_type_fallback` is used to experiment with never type fallback and work on \ + "`rustc_never_type_options` is used to experiment with never type fallback and work on \ never type stabilization, and will never be stable" ), diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index c16e941d4c5..140618e97cc 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -4,12 +4,11 @@ use rustc_data_structures::{ graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, unord::{UnordBag, UnordMap, UnordSet}, }; -use rustc_hir::def_id::CRATE_DEF_ID; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; -enum DivergingFallbackBehavior { +#[derive(Copy, Clone)] +pub enum DivergingFallbackBehavior { /// Always fallback to `()` (aka "always spontaneous decay") FallbackToUnit, /// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken. @@ -78,9 +77,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { return false; } - let diverging_behavior = self.diverging_fallback_behavior(); - let diverging_fallback = - self.calculate_diverging_fallback(&unresolved_variables, diverging_behavior); + let diverging_fallback = self + .calculate_diverging_fallback(&unresolved_variables, self.diverging_fallback_behavior); // We do fallback in two passes, to try to generate // better error messages. @@ -94,32 +92,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fallback_occurred } - fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior { - let Some((mode, span)) = self - .tcx - .get_attr(CRATE_DEF_ID, sym::rustc_never_type_mode) - .map(|attr| (attr.value_str().unwrap(), attr.span)) - else { - if self.tcx.features().never_type_fallback { - return DivergingFallbackBehavior::FallbackToNiko; - } - - return DivergingFallbackBehavior::FallbackToUnit; - }; - - match mode { - sym::fallback_to_unit => DivergingFallbackBehavior::FallbackToUnit, - sym::fallback_to_niko => DivergingFallbackBehavior::FallbackToNiko, - sym::fallback_to_never => DivergingFallbackBehavior::FallbackToNever, - sym::no_fallback => DivergingFallbackBehavior::NoFallback, - _ => { - self.tcx.dcx().span_err(span, format!("unknown never type mode: `{mode}` (supported: `fallback_to_unit`, `fallback_to_niko`, `fallback_to_never` and `no_fallback`)")); - - DivergingFallbackBehavior::FallbackToUnit - } - } - } - fn fallback_effects(&self) -> bool { let unsolved_effects = self.unsolved_effects(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 685b1af931e..fa948451d70 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -5,7 +5,9 @@ mod checks; mod suggestions; use crate::coercion::DynamicCoerceMany; +use crate::fallback::DivergingFallbackBehavior; use crate::{CoroutineTypes, Diverges, EnclosingBreakables, Inherited}; +use hir::def_id::CRATE_DEF_ID; use rustc_errors::{DiagCtxt, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -18,7 +20,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::symbol::Ident; -use rustc_span::{self, Span, DUMMY_SP}; +use rustc_span::{self, sym, Span, DUMMY_SP}; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; use std::cell::{Cell, RefCell}; @@ -108,6 +110,8 @@ pub struct FnCtxt<'a, 'tcx> { pub(super) inh: &'a Inherited<'tcx>, pub(super) fallback_has_occurred: Cell, + + pub(super) diverging_fallback_behavior: DivergingFallbackBehavior, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -116,6 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, ) -> FnCtxt<'a, 'tcx> { + let diverging_fallback_behavior = parse_never_type_options_attr(inh.tcx); FnCtxt { body_id, param_env, @@ -131,6 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }), inh, fallback_has_occurred: Cell::new(false), + diverging_fallback_behavior, } } @@ -374,3 +380,47 @@ impl<'tcx> LoweredTy<'tcx> { LoweredTy { raw, normalized } } } + +fn parse_never_type_options_attr(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior { + use DivergingFallbackBehavior::*; + + // Error handling is dubious here (unwraps), but that's probably fine for an internal attribute. + // Just don't write incorrect attributes <3 + + let mut fallback = None; + + let items = tcx + .get_attr(CRATE_DEF_ID, sym::rustc_never_type_options) + .map(|attr| attr.meta_item_list().unwrap()) + .unwrap_or_default(); + + for item in items { + if item.has_name(sym::fallback) && fallback.is_none() { + let mode = item.value_str().unwrap(); + match mode { + sym::unit => fallback = Some(FallbackToUnit), + sym::niko => fallback = Some(FallbackToNiko), + sym::never => fallback = Some(FallbackToNever), + sym::no => fallback = Some(NoFallback), + _ => { + tcx.dcx().span_err(item.span(), format!("unknown never type fallback mode: `{mode}` (supported: `unit`, `niko`, `never` and `no`)")); + } + }; + continue; + } + + tcx.dcx().span_err( + item.span(), + format!( + "unknown never type option: `{}` (supported: `fallback`)", + item.name_or_empty() + ), + ); + } + + let fallback = fallback.unwrap_or_else(|| { + if tcx.features().never_type_fallback { FallbackToNiko } else { FallbackToUnit } + }); + + fallback +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b911a41a11..77170406c06 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -814,9 +814,7 @@ symbols! { fadd_algebraic, fadd_fast, fake_variadic, - fallback_to_never, - fallback_to_niko, - fallback_to_unit, + fallback, fdiv_algebraic, fdiv_fast, feature, @@ -1227,6 +1225,7 @@ symbols! { new_v1, new_v1_formatted, next, + niko, nll, no, no_builtins, @@ -1235,7 +1234,6 @@ symbols! { no_crate_inject, no_debug, no_default_passes, - no_fallback, no_implicit_prelude, no_inline, no_link, @@ -1553,7 +1551,7 @@ symbols! { rustc_mir, rustc_must_implement_one_of, rustc_never_returns_null_ptr, - rustc_never_type_mode, + rustc_never_type_options, rustc_no_mir_inline, rustc_nonnull_optimization_guaranteed, rustc_nounwind, -- cgit 1.4.1-3-g733a5 From 93297bfb052a8dd72123547072872915f4d60675 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Thu, 21 Mar 2024 20:53:22 +0000 Subject: Add a never type option to make diverging blocks `()` ```rust #![allow(internal_features)] #![feature(never_type, rustc_attrs)] #![rustc_never_type_options(diverging_block_default = "unit")] fn main() { let _: u8 = { //~ error: expected `u8`, found `()` return; }; } ``` --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 27 ++++++++++++++++++++++++- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 27 ++++++++++++++++++++++--- compiler/rustc_span/src/symbol.rs | 1 + 3 files changed, 51 insertions(+), 4 deletions(-) (limited to 'compiler/rustc_span/src') diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 5c56c6acd27..19f839b6240 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -45,6 +45,29 @@ use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext} use std::iter; use std::mem; +#[derive(Clone, Copy, Default)] +pub enum DivergingBlockBehavior { + /// This is the current stable behavior: + /// + /// ```rust + /// { + /// return; + /// } // block has type = !, even though we are supposedly dropping it with `;` + /// ``` + #[default] + Never, + + /// Alternative behavior: + /// + /// ```ignore (very-unstable-new-attribute) + /// #![rustc_never_type_options(diverging_block_default = "unit")] + /// { + /// return; + /// } // block has type = (), since we are dropping `!` from `return` with `;` + /// ``` + Unit, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_casts(&mut self) { // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors @@ -1710,7 +1733,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // #41425 -- label the implicit `()` as being the // "found type" here, rather than the "expected type". - if !self.diverges.get().is_always() { + if !self.diverges.get().is_always() + || matches!(self.diverging_block_behavior, DivergingBlockBehavior::Unit) + { // #50009 -- Do not point at the entire fn block span, point at the return type // span, as it is the cause of the requirement, and // `consider_hint_about_removing_semicolon` will point at the last expression diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index fa948451d70..1850463194d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -6,6 +6,7 @@ mod suggestions; use crate::coercion::DynamicCoerceMany; use crate::fallback::DivergingFallbackBehavior; +use crate::fn_ctxt::checks::DivergingBlockBehavior; use crate::{CoroutineTypes, Diverges, EnclosingBreakables, Inherited}; use hir::def_id::CRATE_DEF_ID; use rustc_errors::{DiagCtxt, ErrorGuaranteed}; @@ -112,6 +113,7 @@ pub struct FnCtxt<'a, 'tcx> { pub(super) fallback_has_occurred: Cell, pub(super) diverging_fallback_behavior: DivergingFallbackBehavior, + pub(super) diverging_block_behavior: DivergingBlockBehavior, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -120,7 +122,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, ) -> FnCtxt<'a, 'tcx> { - let diverging_fallback_behavior = parse_never_type_options_attr(inh.tcx); + let (diverging_fallback_behavior, diverging_block_behavior) = + parse_never_type_options_attr(inh.tcx); FnCtxt { body_id, param_env, @@ -137,6 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inh, fallback_has_occurred: Cell::new(false), diverging_fallback_behavior, + diverging_block_behavior, } } @@ -381,13 +385,16 @@ impl<'tcx> LoweredTy<'tcx> { } } -fn parse_never_type_options_attr(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior { +fn parse_never_type_options_attr( + tcx: TyCtxt<'_>, +) -> (DivergingFallbackBehavior, DivergingBlockBehavior) { use DivergingFallbackBehavior::*; // Error handling is dubious here (unwraps), but that's probably fine for an internal attribute. // Just don't write incorrect attributes <3 let mut fallback = None; + let mut block = None; let items = tcx .get_attr(CRATE_DEF_ID, sym::rustc_never_type_options) @@ -409,6 +416,18 @@ fn parse_never_type_options_attr(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior { continue; } + if item.has_name(sym::diverging_block_default) && fallback.is_none() { + let mode = item.value_str().unwrap(); + match mode { + sym::unit => block = Some(DivergingBlockBehavior::Unit), + sym::never => block = Some(DivergingBlockBehavior::Never), + _ => { + tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{mode}` (supported: `unit` and `never`)")); + } + }; + continue; + } + tcx.dcx().span_err( item.span(), format!( @@ -422,5 +441,7 @@ fn parse_never_type_options_attr(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior { if tcx.features().never_type_fallback { FallbackToNiko } else { FallbackToUnit } }); - fallback + let block = block.unwrap_or_default(); + + (fallback, block) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 77170406c06..4fa8ba2aa05 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -689,6 +689,7 @@ symbols! { dispatch_from_dyn, div, div_assign, + diverging_block_default, do_not_recommend, doc, doc_alias, -- cgit 1.4.1-3-g733a5 From 82c2c8deb1fb7640fedfbc49b5647957a1d572db Mon Sep 17 00:00:00 2001 From: León Orell Valerian Liehr Date: Sun, 11 Feb 2024 09:22:52 +0100 Subject: Update (doc) comments Several (doc) comments were super outdated or didn't provide enough context. Some doc comments shoved everything in a single paragraph without respecting the fact that the first paragraph should be a single sentence because rustdoc treats these as item descriptions / synopses on module pages. --- compiler/rustc_ast/src/ast.rs | 4 - compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/delegation.rs | 7 +- compiler/rustc_ast_lowering/src/item.rs | 4 +- compiler/rustc_hir/src/hir.rs | 8 +- compiler/rustc_hir_analysis/src/astconv/bounds.rs | 103 ++++--- .../rustc_hir_analysis/src/astconv/generics.rs | 28 +- compiler/rustc_hir_analysis/src/astconv/mod.rs | 299 ++++++++++++++------- .../src/astconv/object_safety.rs | 1 + compiler/rustc_hir_analysis/src/bounds.rs | 4 +- compiler/rustc_hir_analysis/src/check/check.rs | 4 +- .../src/check/compare_impl_item.rs | 2 +- compiler/rustc_hir_analysis/src/check/region.rs | 2 +- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 16 +- .../rustc_hir_analysis/src/collect/item_bounds.rs | 4 +- .../src/collect/predicates_of.rs | 21 +- .../src/collect/resolve_bound_vars.rs | 6 +- compiler/rustc_hir_analysis/src/collect/type_of.rs | 6 +- compiler/rustc_hir_analysis/src/lib.rs | 16 +- .../rustc_hir_analysis/src/variance/constraints.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 4 +- .../rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 2 +- .../src/solve/normalizes_to/inherent.rs | 2 +- .../src/traits/object_safety.rs | 5 +- .../src/traits/select/confirmation.rs | 2 +- .../src/traits/specialize/specialization_graph.rs | 2 +- compiler/rustc_type_ir/src/ty_kind.rs | 2 +- .../clippy/book/src/development/type_checking.md | 10 +- .../clippy_lints/src/types/redundant_allocation.rs | 2 +- src/tools/clippy/clippy_lints/src/use_self.rs | 2 +- src/tools/clippy/tests/ui/crashes/ice-6179.rs | 2 +- tests/ui/issues/issue-17361.rs | 2 +- tests/ui/traits/alias/self-in-generics.rs | 2 +- 36 files changed, 332 insertions(+), 252 deletions(-) (limited to 'compiler/rustc_span/src') diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e4096e244e1..ea73f88dacf 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -303,10 +303,6 @@ impl TraitBoundModifiers { }; } -/// The AST represents all type param bounds as types. -/// `typeck::collect::compute_bounds` matches these against -/// the "special" built-in traits (see `middle::lang_items`) and -/// detects `Copy`, `Send` and `Sync`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum GenericBound { Trait(PolyTraitRef, TraitBoundModifiers), diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 7bdbf48a81f..dedf67e6a94 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -480,7 +480,7 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( try_visit!(visitor.visit_path(&use_tree.prefix, id)); match use_tree.kind { UseTreeKind::Simple(rename) => { - // The extra IDs are handled during HIR lowering. + // The extra IDs are handled during AST lowering. visit_opt!(visitor, visit_ident, rename); } UseTreeKind::Glob => {} diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 4e1c477a3d7..e26a65c1f29 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -29,11 +29,12 @@ //! item id (`item_id`) in case of impl trait or path resolution id (`path_id`) otherwise. //! //! Since we do not have a proper way to obtain function type information by path resolution -//! in AST, we mark each function parameter type as `InferDelegation` and inherit it in `AstConv`. +//! in AST, we mark each function parameter type as `InferDelegation` and inherit it during +//! HIR ty lowering. //! //! Similarly generics, predicates and header are set to the "default" values. //! In case of discrepancy with callee function the `NotSupportedDelegation` error will -//! also be emitted in `AstConv`. +//! also be emitted during HIR ty lowering. use crate::{ImplTraitPosition, ResolverAstLoweringExt}; @@ -129,7 +130,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> &'hir hir::FnDecl<'hir> { let args_count = if let Some(local_sig_id) = sig_id.as_local() { // Map may be filled incorrectly due to recursive delegation. - // Error will be emmited later in astconv. + // Error will be emitted later during HIR ty lowering. self.resolver.fn_parameter_counts.get(&local_sig_id).cloned().unwrap_or_default() } else { self.tcx.fn_arg_names(sig_id).len() diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 2d03c854bd0..c9786328565 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1427,8 +1427,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // Error if `?Trait` bounds in where clauses don't refer directly to type parameters. // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering // these into hir when we lower thee where clauses), but this makes it quite difficult to - // keep track of the Span info. Now, `add_implicitly_sized` in `AstConv` checks both param bounds and - // where clauses for `?Sized`. + // keep track of the Span info. Now, `::add_implicit_sized_bound` + // checks both param bounds and where clauses for `?Sized`. for pred in &generics.where_clause.predicates { let WherePredicate::BoundPredicate(bound_pred) = pred else { continue; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 21aec11b314..87e21785c8c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -428,10 +428,6 @@ pub enum TraitBoundModifier { MaybeConst, } -/// The AST represents all type param bounds as types. -/// `typeck::collect::compute_bounds` matches these against -/// the "special" built-in traits (see `middle::lang_items`) and -/// detects `Copy`, `Send` and `Sync`. #[derive(Clone, Copy, Debug, HashStable_Generic)] pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), @@ -1860,7 +1856,7 @@ pub enum ExprKind<'hir> { /// Wraps the expression in a terminating scope. /// This makes it semantically equivalent to `{ let _t = expr; _t }`. /// - /// This construct only exists to tweak the drop order in HIR lowering. + /// This construct only exists to tweak the drop order in AST lowering. /// An example of that is the desugaring of `for` loops. DropTemps(&'hir Expr<'hir>), /// A `let $pat = $expr` expression. @@ -2293,7 +2289,7 @@ pub enum ImplItemKind<'hir> { /// Bind a type to an associated type (i.e., `A = Foo`). /// /// Bindings like `A: Debug` are represented as a special type `A = -/// $::Debug` that is understood by the astconv code. +/// $::Debug` that is understood by the HIR ty lowering code. /// /// FIXME(alexreg): why have a separate type for the binding case, /// wouldn't it be better to make the `ty` field an enum like the diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index dd11f58ca19..1fe7baaa250 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -17,7 +17,9 @@ use crate::bounds::Bounds; use crate::errors; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { - /// Sets `implicitly_sized` to true on `Bounds` if necessary + /// Add a `Sized` bound to the `bounds` if appropriate. + /// + /// Doesn't add the bound if the HIR bounds contain any of `Sized`, `?Sized` or `!Sized`. pub(crate) fn add_sized_bound( &self, bounds: &mut Bounds<'tcx>, @@ -101,21 +103,27 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// This helper takes a *converted* parameter type (`param_ty`) - /// and an *unconverted* list of bounds: + /// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any. + /// + /// ### Examples /// - /// ```text - /// fn foo - /// ^ ^^^^^ `ast_bounds` parameter, in HIR form - /// | - /// `param_ty`, in ty form + /// ```ignore (illustrative) + /// fn foo() where for<'a> T: Trait<'a> + Copy {} + /// // ^^^^^^^ ^ ^^^^^^^^^^^^^^^^ `ast_bounds`, in HIR form + /// // | | + /// // | `param_ty`, in ty form + /// // `bound_vars`, in ty form + /// + /// fn bar() where T: for<'a> Trait<'a> + Copy {} // no overarching `bound_vars` here! + /// // ^ ^^^^^^^^^^^^^^^^^^^^^^^^ `ast_bounds`, in HIR form + /// // | + /// // `param_ty`, in ty form /// ``` /// - /// It adds these `ast_bounds` into the `bounds` structure. + /// ### A Note on Binders /// - /// **A note on binders:** there is an implied binder around - /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` - /// for more details. + /// There is an implied binder around `param_ty` and `ast_bounds`. + /// See `lower_poly_trait_ref` for more details. #[instrument(level = "debug", skip(self, ast_bounds, bounds))] pub(crate) fn lower_poly_bounds<'hir, I: Iterator>>( &self, @@ -170,22 +178,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Translates a list of bounds from the HIR into the `Bounds` data structure. - /// The self-type for the bounds is given by `param_ty`. + /// Lower HIR bounds into `bounds` given the self type `param_ty` and *no* overarching late-bound vars. /// - /// Example: + /// ### Example /// /// ```ignore (illustrative) - /// fn foo() { } + /// fn foo() {} /// // ^ ^^^^^^^^^ ast_bounds /// // param_ty /// ``` - /// - /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be - /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the - /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`. - /// - /// `span` should be the declaration size of the parameter. pub(crate) fn lower_mono_bounds( &self, param_ty: Ty<'tcx>, @@ -227,12 +228,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds } - /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates - /// onto `bounds`. + /// Lower an associated item binding from HIR into `bounds`. + /// + /// ### A Note on Binders /// - /// **A note on binders:** given something like `T: for<'a> Iterator`, the - /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* - /// the binder (e.g., `&'a u32`) and hence may reference bound regions. + /// Given something like `T: for<'a> Iterator`, + /// the `trait_ref` here will be `for<'a> T: Iterator`. + /// The `binding` data however is from *inside* the binder + /// (e.g., `&'a u32`) and hence may reference bound regions. #[instrument(level = "debug", skip(self, bounds, dup_bindings, path_span))] pub(super) fn lower_assoc_item_binding( &self, @@ -244,22 +247,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { path_span: Span, only_self_bounds: OnlySelfBounds, ) -> Result<(), ErrorGuaranteed> { - // Given something like `U: SomeTrait`, we want to produce a - // predicate like `::T = X`. This is somewhat - // subtle in the event that `T` is defined in a supertrait of - // `SomeTrait`, because in that case we need to upcast. - // - // That is, consider this case: - // - // ``` - // trait SubTrait: SuperTrait { } - // trait SuperTrait { type T; } - // - // ... B: SubTrait ... - // ``` - // - // We want to produce `>::T == foo`. - let tcx = self.tcx(); let assoc_kind = if binding.gen_args.parenthesized @@ -272,6 +259,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::AssocKind::Type }; + // Given something like `U: Trait`, we want to produce a predicate like + // `::T = X`. + // This is somewhat subtle in the event that `T` is defined in a supertrait of `Trait`, + // because in that case we need to upcast. I.e., we want to produce + // `>::T == X` for `B: SubTrait` where + // + // trait SubTrait: SuperTrait {} + // trait SuperTrait { type T; } let candidate = if self.probe_trait_that_defines_assoc_item( trait_ref.def_id(), assoc_kind, @@ -449,6 +444,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: binding.span, })); } + // Lower an equality constraint like `Item = u32` as found in HIR bound `T: Iterator` + // to a projection predicate: `::Item = u32`. hir::TypeBindingKind::Equality { term } => { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), @@ -490,10 +487,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ); - // "Desugar" a constraint like `T: Iterator` this to - // the "projection predicate" for: - // - // `::Item = u32` bounds.push_projection_bound( tcx, projection_ty @@ -501,18 +494,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { binding.span, ); } + // Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator` + // to a bound involving a projection: `::Item: Debug`. hir::TypeBindingKind::Constraint { bounds: ast_bounds } => { - // "Desugar" a constraint like `T: Iterator` to - // - // `::Item: Debug` - // - // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` - // parameter to have a skipped binder. - // - // NOTE: If `only_self_bounds` is true, do NOT expand this associated - // type bound into a trait predicate, since we only want to add predicates - // for the `Self` type. + // NOTE: If `only_self_bounds` is true, do NOT expand this associated type bound into + // a trait predicate, since we only want to add predicates for the `Self` type. if !only_self_bounds.0 { + // Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty` + // parameter to have a skipped binder. let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder()); self.lower_poly_bounds( param_ty, diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index 9ad6fec22ac..cd980526db1 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -143,24 +143,22 @@ fn generic_arg_mismatch_err( err.emit() } -/// Creates the relevant generic arguments -/// corresponding to a set of generic parameters. This is a -/// rather complex function. Let us try to explain the role +/// Lower generic arguments from the HIR to the [`rustc_middle::ty`] representation. +/// +/// This is a rather complex function. Let us try to explain the role /// of each of its parameters: /// -/// To start, we are given the `def_id` of the thing whose generic -/// parameters we are instantiating, and a partial set of -/// arguments `parent_args`. In general, the generic arguments -/// for an item begin with arguments for all the "parents" of -/// that item -- e.g., for a method it might include the -/// parameters from the impl. +/// To start, we are given the `def_id` of the thing whose generic parameters we +/// are creating, and a partial set of arguments `parent_args`. In general, +/// the generic arguments for an item begin with arguments for all the "parents" +/// of that item -- e.g., for a method it might include the parameters from the impl. /// /// Therefore, the method begins by walking down these parents, /// starting with the outermost parent and proceed inwards until /// it reaches `def_id`. For each parent `P`, it will check `parent_args` /// first to see if the parent's arguments are listed in there. If so, -/// we can append those and move on. Otherwise, it invokes the -/// three callback functions: +/// we can append those and move on. Otherwise, it uses the provided +/// [`GenericArgsLowerer`] `ctx` which has the following methods: /// /// - `args_for_def_id`: given the `DefId` `P`, supplies back the /// generic arguments that were given to that parent from within @@ -168,10 +166,10 @@ fn generic_arg_mismatch_err( /// might refer to the trait `Foo`, and the arguments might be /// `[T]`. The boolean value indicates whether to infer values /// for arguments whose values were not explicitly provided. -/// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`, -/// instantiate a `GenericArg`. -/// - `inferred_kind`: if no parameter was provided, and inference is enabled, then -/// creates a suitable inference variable. +/// - `provided_kind`: given the generic parameter and the value +/// from `args_for_def_id`, creating a `GenericArg`. +/// - `inferred_kind`: if no parameter was provided, and inference +/// is enabled, then creates a suitable inference variable. pub fn lower_generic_args<'tcx: 'a, 'a>( tcx: TyCtxt<'tcx>, def_id: DefId, diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 14864da1e39..a9e3c3b75bd 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1,6 +1,17 @@ -//! Conversion from AST representation of types to the `ty.rs` representation. -//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an -//! instance of `AstConv`. +//! HIR ty lowering: Lowers type-system entities[^1] from the [HIR][hir] to +//! the [`rustc_middle::ty`] representation. +//! +//! Not to be confused with *AST lowering* which lowers AST constructs to HIR ones +//! or with *THIR* / *MIR* *lowering* / *building* which lowers HIR *bodies* +//! (i.e., “executable code”) to THIR / MIR. +//! +//! Most lowering routines are defined on [`dyn HirTyLowerer`](HirTyLowerer) directly, +//! like the main routine of this module, `lower_ty`. +//! +//! This module used to be called `astconv`. +//! +//! [^1]: This includes types, lifetimes / regions, constants in type positions, +//! trait references and bounds. mod bounds; mod errors; @@ -43,6 +54,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt}; use std::fmt::Display; use std::slice; +/// A path segment that is semantically allowed to have generic arguments. #[derive(Debug)] pub struct GenericPathSegment(pub DefId, pub usize); @@ -67,23 +79,30 @@ pub enum PredicateFilter { SelfAndAssociatedTypeBounds, } +/// A context which can lower type-system entities from the [HIR][hir] to +/// the [`rustc_middle::ty`] representation. +/// +/// This trait used to be called `AstConv`. pub trait HirTyLowerer<'tcx> { fn tcx(&self) -> TyCtxt<'tcx>; + /// Returns the [`DefId`] of the overarching item whose constituents get lowered. fn item_def_id(&self) -> DefId; - /// Returns predicates in scope of the form `X: Foo`, where `X` - /// is a type parameter `X` with the given id `def_id` and T - /// matches `assoc_name`. This is a subset of the full set of - /// predicates. + /// Probe bounds in scope where the bounded type coincides with the given type parameter. + /// + /// Rephrased, this returns bounds of the form `T: Trait`, where `T` is a type parameter + /// with the given `def_id`. This is a subset of the full set of bounds. + /// + /// This method may use the given `assoc_name` to disregard bounds whose trait reference + /// doesn't define an associated item with the provided name. /// - /// This is used for one specific purpose: resolving "short-hand" - /// associated type references like `T::Item`. In principle, we - /// would do that by first getting the full set of predicates in - /// scope and then filtering down to find those that apply to `T`, - /// but this can lead to cycle errors. The problem is that we have - /// to do this resolution *in order to create the predicates in - /// the first place*. Hence, we have this "special pass". + /// This is used for one specific purpose: Resolving “short-hand” associated type references + /// like `T::Item` where `T` is a type parameter. In principle, we would do that by first + /// getting the full set of predicates in scope and then filtering down to find those that + /// apply to `T`, but this can lead to cycle errors. The problem is that we have to do this + /// resolution *in order to create the predicates in the first place*. + /// Hence, we have this “special pass”. fn probe_ty_param_bounds( &self, span: Span, @@ -91,14 +110,14 @@ pub trait HirTyLowerer<'tcx> { assoc_name: Ident, ) -> ty::GenericPredicates<'tcx>; - /// Returns the lifetime to use when a lifetime is omitted (and not elided). + /// Returns the region to use when a lifetime is omitted (and not elided). fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Option>; /// Returns the type to use when a type is omitted. fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; - /// Returns `true` if `_` is allowed in type signatures in the current context. + /// Returns `true` if the current context allows the use of inference variables. fn allow_infer(&self) -> bool; /// Returns the const to use when a const is omitted. @@ -109,13 +128,18 @@ pub trait HirTyLowerer<'tcx> { span: Span, ) -> Const<'tcx>; - /// Projecting an associated type from a (potentially) - /// higher-ranked trait reference is more complicated, because of - /// the possibility of late-bound regions appearing in the - /// associated type binding. This is not legal in function - /// signatures for that reason. In a function body, we can always - /// handle it because we can use inference variables to remove the - /// late-bound regions. + /// Lower an associated type to a projection. + /// + /// This method has to be defined by the concrete lowering context because + /// dealing with higher-ranked trait references depends on its capabilities: + /// + /// If the context can make use of type inference, it can simply instantiate + /// any late-bound vars bound by the trait reference with inference variables. + /// If it doesn't support type inference, there is nothing reasonable it can + /// do except reject the associated type. + /// + /// The canonical example of this is associated type `T::P` where `T` is a type + /// param constrained by `T: for<'a> Trait<'a>` and where `Trait` defines `P`. fn lower_assoc_ty( &self, span: Span, @@ -125,20 +149,26 @@ pub trait HirTyLowerer<'tcx> { ) -> Ty<'tcx>; /// Returns `AdtDef` if `ty` is an ADT. - /// Note that `ty` might be a projection type that needs normalization. + /// + /// Note that `ty` might be a alias type that needs normalization. /// This used to get the enum variants in scope of the type. /// For example, `Self::A` could refer to an associated type /// or to an enum variant depending on the result of this function. fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option>; - /// Invoked when we encounter an error from some prior pass - /// (e.g., resolve) that is translated into a ty-error. This is - /// used to help suppress derived errors typeck might otherwise - /// report. + /// Taint the context with errors. + /// + /// Invoke this when you encounter an error from some prior pass like name resolution. + /// This is used to help suppress derived errors typeck might otherwise report. fn set_tainted_by_errors(&self, e: ErrorGuaranteed); + /// Record the lowered type of a HIR node in this context. fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span); + /// Convenience method for coercing the lowering context into a trait object type. + /// + /// Most lowering routines are defined on the trait object type directly + /// necessitating a coercion step from the concrete lowering context. fn lowerer(&self) -> &dyn HirTyLowerer<'tcx> where Self: Sized, @@ -146,6 +176,7 @@ pub trait HirTyLowerer<'tcx> { self } + /// The inference context of the lowering context if applicable. fn infcx(&self) -> Option<&InferCtxt<'tcx>>; } @@ -197,6 +228,10 @@ pub struct GenericArgCountResult { pub correct: Result<(), GenericArgCountMismatch>, } +/// A context which can lower HIR's [`GenericArg`] to `rustc_middle`'s [`ty::GenericArg`]. +/// +/// Its only consumer is [`generics::lower_generic_args`]. +/// Read its documentation to learn more. pub trait GenericArgsLowerer<'a, 'tcx> { fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool); @@ -215,6 +250,7 @@ pub trait GenericArgsLowerer<'a, 'tcx> { } impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { + /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. #[instrument(level = "debug", skip(self), ret)] pub fn lower_lifetime( &self, @@ -271,8 +307,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, - /// returns an appropriate set of generic arguments for this particular reference to `I`. pub fn lower_generic_args_of_path_segment( &self, span: Span, @@ -293,14 +327,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { args } - /// Given the type/lifetime/const arguments provided to some path (along with - /// an implicit `Self`, if this is a trait reference), returns the complete - /// set of generic arguments. This may involve applying defaulted type parameters. + /// Lower the generic arguments provided to some path. /// - /// Constraints on associated types are not converted here but - /// separately in `add_predicates_for_ast_type_binding`. + /// If this is a trait reference, you also need to pass the self type `self_ty`. + /// The lowering process may involve applying defaulted type parameters. /// - /// Example: + /// Associated item bindings are not handled here! + /// + /// ### Example /// /// ```ignore (illustrative) /// T: std::ops::Index @@ -589,16 +623,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let Some(b) = item_segment.args().bindings.first() { prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span))); } - args } - /// Instantiates the path for the given trait reference, assuming that it's - /// bound to a valid trait type. Returns the `DefId` of the defining trait. - /// The type _cannot_ be a type other than a trait type. + /// Lower a trait reference as found in an impl header as the implementee. /// - /// If the `projections` argument is `None`, then assoc type bindings like `Foo` - /// are disallowed. Otherwise, they are pushed onto the vector given. + /// The self type `self_ty` is the implementer of the trait. pub fn lower_impl_trait_ref( &self, trait_ref: &hir::TraitRef<'tcx>, @@ -616,25 +646,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) } - /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct - /// a full trait reference. The resulting trait reference is returned. This may also generate - /// auxiliary bounds, which are added to `bounds`. + /// Lower a polymorphic trait reference given a self type into `bounds`. /// - /// Example: + /// *Polymorphic* in the sense that it may bind late-bound vars. /// - /// ```ignore (illustrative) - /// poly_trait_ref = Iterator - /// self_ty = Foo - /// ``` + /// This may generate auxiliary bounds if the trait reference contains associated item bindings. + /// + /// ### Example /// - /// this would return `Foo: Iterator` and add `::Item = u32` into `bounds`. + /// Given the trait ref `Iterator` and the self type `Ty`, this will add the + /// + /// 1. *trait predicate* `` (known as `Foo: Iterator` in surface syntax) and the + /// 2. *projection predicate* `::Item = u32` + /// + /// to `bounds`. + /// + /// ### A Note on Binders + /// + /// Against our usual convention, there is an implied binder around the `self_ty` and the + /// `trait_ref` here. So they may reference late-bound vars. /// - /// **A note on binders:** against our usual convention, there is an implied binder around - /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` - /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be - /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, - /// however. + /// where `'a` is a bound region at depth 0. Similarly, the `trait_ref` would be `Bar<'a>`. + /// The lowered poly-trait-ref will track this binder explicitly, however. #[instrument(level = "debug", skip(self, span, constness, bounds))] pub(crate) fn lower_poly_trait_ref( &self, @@ -702,6 +736,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { arg_count } + /// Lower a monomorphic trait reference given a self type while prohibiting associated item bindings. + /// + /// *Monomorphic* in the sense that it doesn't bind any late-bound vars. fn lower_mono_trait_ref( &self, span: Span, @@ -709,7 +746,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, trait_segment: &hir::PathSegment<'tcx>, is_impl: bool, - // FIXME(effects) move all host param things in astconv to hir lowering + // FIXME(effects): Move all host param things in HIR ty lowering to AST lowering. constness: ty::BoundConstness, ) -> ty::TraitRef<'tcx> { self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl); @@ -762,10 +799,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - // Search for a bound on a type parameter which includes the associated item - // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter - // This function will fail if there are no suitable bounds or there is - // any ambiguity. + /// Search for a trait bound on a type parameter whose trait defines the associated type given by `assoc_name`. + /// + /// This fails if there is no such bound in the list of candidates or if there are multiple + /// candidates in which case it reports ambiguity. + /// + /// `ty_param_def_id` is the `LocalDefId` of the type parameter. fn probe_single_ty_param_bound_for_assoc_ty( &self, ty_param_def_id: LocalDefId, @@ -803,8 +842,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) } - // Checks that `bounds` contains exactly one element and reports appropriate - // errors otherwise. + /// Search for a single trait bound whose trait defines the associated item given by `assoc_name`. + /// + /// This fails if there is no such bound in the list of candidates or if there are multiple + /// candidates in which case it reports ambiguity. #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, binding), ret)] fn probe_single_bound_for_assoc_item( &self, @@ -927,12 +968,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ok(bound) } - // Create a type from a path to an associated type or to an enum variant. - // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C` - // and item_segment is the path segment for `D`. We return a type and a def for - // the whole path. - // Will fail except for `T::A` and `Self::A`; i.e., if `qself_ty`/`qself_def` are not a type - // parameter or `Self`. + /// Lower a [type-relative] path referring to an associated type or to an enum variant. + /// + /// If the path refers to an enum variant and `permit_variants` holds, + /// the returned type is simply the provided self type `qself_ty`. + /// + /// A path like `A::B::C::D` is understood as `::D`. I.e., + /// `qself_ty` / `qself` is `A::B::C` and `assoc_segment` is `D`. + /// We return the lowered type and the `DefId` for the whole path. + /// + /// We only support associated type paths whose self type is a type parameter or a `Self` + /// type alias (in a trait impl) like `T::Ty` (where `T` is a ty param) or `Self::Ty`. + /// We **don't** support paths whose self type is an arbitrary type like `Struct::Ty` where + /// struct `Struct` impls an in-scope trait that defines an associated type called `Ty`. + /// For the latter case, we report ambiguity. + /// While desirable to support, the implemention would be non-trivial. Tracked in [#22519]. + /// + /// At the time of writing, *inherent associated types* are also resolved here. This however + /// is [problematic][iat]. A proper implementation would be as non-trivial as the one + /// described in the previous paragraph and their modeling of projections would likely be + /// very similar in nature. + /// + /// [type-relative]: hir::QPath::TypeRelative + /// [#22519]: https://github.com/rust-lang/rust/issues/22519 + /// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403 + // // NOTE: When this function starts resolving `Trait::AssocTy` successfully // it should also start reporting the `BARE_TRAIT_OBJECTS` lint. #[instrument(level = "debug", skip(self, hir_ref_id, span, qself, assoc_segment), fields(assoc_ident=?assoc_segment.ident), ret)] @@ -1064,6 +1124,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + // FIXME(inherent_associated_types, #106719): Support self types other than ADTs. if let Some((ty, did)) = self.probe_inherent_assoc_ty( assoc_ident, assoc_segment, @@ -1233,8 +1294,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Don't attempt to look up inherent associated types when the feature is not enabled. // Theoretically it'd be fine to do so since we feature-gate their definition site. // However, due to current limitations of the implementation (caused by us performing - // selection in AstConv), IATs can lead to cycle errors (#108491, #110106) which mask the - // feature-gate error, needlessly confusing users that use IATs by accident (#113265). + // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle + // errors (#108491) which mask the feature-gate error, needlessly confusing users + // who use IATs by accident (#113265). if !tcx.features().inherent_associated_types { return Ok(None); } @@ -1289,7 +1351,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.check_assoc_ty(assoc_item, name, def_scope, block, span); // FIXME(fmease): Currently creating throwaway `parent_args` to please - // `create_args_for_associated_item`. Modify the latter instead (or sth. similar) to + // `lower_generic_args_of_assoc_item`. Modify the latter instead (or sth. similar) to // not require the parent args logic. let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_); let args = self.lower_generic_args_of_assoc_item(span, assoc_item, segment, parent_args); @@ -1490,6 +1552,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect() } + /// Lower a qualified path to a type. fn lower_qpath( &self, span: Span, @@ -1676,6 +1739,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { emitted } + /// Probe path segments that are semantically allowed to have generic arguments. + /// + /// ### Example + /// + /// ```ignore (illustrative) + /// Option::None::<()> + /// // ^^^^ permitted to have generic args + /// + /// // ==> [GenericPathSegment(Option_def_id, 1)] + /// + /// Option::<()>::None + /// // ^^^^^^ ^^^^ *not* permitted to have generic args + /// // permitted to have generic args + /// + /// // ==> [GenericPathSegment(Option_def_id, 0)] + /// ``` // FIXME(eddyb, varkor) handle type paths here too, not just value ones. pub fn probe_generic_path_segments( &self, @@ -1685,9 +1764,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { def_id: DefId, span: Span, ) -> Vec { - // We need to extract the type parameters supplied by the user in + // We need to extract the generic arguments supplied by the user in // the path `path`. Due to the current setup, this is a bit of a - // tricky-process; the problem is that resolve only tells us the + // tricky process; the problem is that resolve only tells us the // end-point of the path resolution, and not the intermediate steps. // Luckily, we can (at least for now) deduce the intermediate steps // just from the end-point. @@ -1698,35 +1777,35 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // // struct Foo(...) // - // In this case, the parameters are declared in the type space. + // In this case, the generic arguments are declared in the type space. // // 2. Reference to a constructor of an enum variant: // // enum E { Foo(...) } // - // In this case, the parameters are defined in the type space, + // In this case, the generic arguments are defined in the type space, // but may be specified either on the type or the variant. // - // 3. Reference to a fn item or a free constant: + // 3. Reference to a free function or constant: // - // fn foo() { } + // fn foo() {} // // In this case, the path will again always have the form - // `a::b::foo::` where only the final segment should have - // type parameters. However, in this case, those parameters are - // declared on a value, and hence are in the `FnSpace`. + // `a::b::foo::` where only the final segment should have generic + // arguments. However, in this case, those arguments are declared on + // a value, and hence are in the value space. // - // 4. Reference to a method or an associated constant: + // 4. Reference to an associated function or constant: // // impl SomeStruct { - // fn foo(...) + // fn foo(...) {} // } // - // Here we can have a path like - // `a::b::SomeStruct::::foo::`, in which case parameters - // may appear in two places. The penultimate segment, - // `SomeStruct::`, contains parameters in TypeSpace, and the - // final segment, `foo::` contains parameters in fn space. + // Here we can have a path like `a::b::SomeStruct::::foo::`, + // in which case generic arguments may appear in two places. The + // penultimate segment, `SomeStruct::`, contains generic arguments + // in the type space, and the final segment, `foo::` contains + // generic arguments in value space. // // The first step then is to categorize the segments appropriately. @@ -1804,7 +1883,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { generic_segments } - /// Check a type `Path` and convert it to a `Ty`. + /// Lower a type `Path` to a type. pub fn lower_path( &self, opt_self_ty: Option>, @@ -1844,7 +1923,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_path_segment(span, did, path.segments.last().unwrap()) } Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => { - // Convert "variant type" as if it were a real type. + // Lower "variant type" as if it were a real type. // The resulting `Ty` is type of the variant's enum for now. assert_eq!(opt_self_ty, None); @@ -2045,8 +2124,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - // Converts a hir id corresponding to a type parameter to - // a early-bound `ty::Param` or late-bound `ty::Bound`. + /// Lower a type parameter from the HIR to our internal notion of a type. + /// + /// Early-bound type parameters get lowered to [`ty::Param`] + /// and late-bound ones to [`ty::Bound`]. pub(crate) fn lower_ty_param(&self, hir_id: hir::HirId) -> Ty<'tcx> { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { @@ -2070,8 +2151,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - // Converts a hir id corresponding to a const parameter to - // a early-bound `ConstKind::Param` or late-bound `ConstKind::Bound`. + /// Lower a const parameter from the HIR to our internal notion of a constant. + /// + /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`] + /// and late-bound ones to [`ty::ConstKind::Bound`]. pub(crate) fn lower_const_param(&self, hir_id: hir::HirId, param_ty: Ty<'tcx>) -> Const<'tcx> { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { @@ -2092,14 +2175,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Parses the programmer's textual representation of a type into our - /// internal notion of a type. + /// Lower a type from the HIR to our internal notion of a type. pub fn lower_ty(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { self.lower_ty_common(ast_ty, false, false) } - /// Parses the programmer's textual representation of a type into our - /// internal notion of a type. This is meant to be used within a path. + /// Lower a type inside of a path from the HIR to our internal notion of a type. pub fn lower_ty_in_path(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { self.lower_ty_common(ast_ty, false, true) } @@ -2202,8 +2283,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { sig.instantiate_identity() }; - // Bound vars are also inherited from `sig_id`. They will be - // rebinded later in `ty_of_fn`. + // Bound vars are also inherited from `sig_id`. + // They will be rebound later in `lower_fn_ty`. let sig = sig.skip_binder(); match idx { @@ -2212,8 +2293,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait - /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. + /// Lower a type from the HIR to our internal notion of a type given some extra data for diagnostics. + /// + /// Extra diagnostic data: + /// + /// 1. `borrowed`: Whether trait object types are borrowed like in `&dyn Trait`. + /// Used to avoid emitting redundant errors. + /// 2. `in_path`: Whether the type appears inside of a path. + /// Used to provide correct diagnostics for bare trait object types. #[instrument(level = "debug", skip(self), ret)] fn lower_ty_common(&self, ast_ty: &hir::Ty<'tcx>, borrowed: bool, in_path: bool) -> Ty<'tcx> { let tcx = self.tcx(); @@ -2348,6 +2435,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { result_ty } + /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. #[instrument(level = "debug", skip(self), ret)] fn lower_opaque_ty( &self, @@ -2405,6 +2493,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + /// Lower a function type from the HIR to our internal notion of a function signature. #[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)] pub fn lower_fn_ty( &self, @@ -2484,7 +2573,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) { // We always collect the spans for placeholder types when evaluating `fn`s, but we // only want to emit an error complaining about them if infer types (`_`) are not - // allowed. `allow_ty_infer` gates this behavior. We check for the presence of + // allowed. `allow_infer` gates this behavior. We check for the presence of // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. let mut diag = crate::collect::placeholder_type_error_diag( @@ -2610,7 +2699,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Given the bounds on an object, determines what single region bound (if any) we can - /// use to summarize this type. The basic idea is that we will use the bound the user + /// use to summarize this type. + /// + /// The basic idea is that we will use the bound the user /// provided, if they provided one, and otherwise search the supertypes of trait bounds /// for region bounds. It may be that we can derive no bound at all, in which case /// we return `None`. diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 140055cf764..2a3f956bfba 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -18,6 +18,7 @@ use smallvec::{smallvec, SmallVec}; use super::HirTyLowerer; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { + /// Lower a trait object type from the HIR to our internal notion of a type. pub(super) fn lower_trait_object_ty( &self, span: Span, diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index b69f679880d..d659d2c5235 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -1,5 +1,5 @@ -//! Bounds are restrictions applied to some types after they've been converted into the -//! `ty` form from the HIR. +//! Bounds are restrictions applied to some types after they've been lowered from the HIR to the +//! [`rustc_middle::ty`] form. use rustc_hir::LangItem; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d1fed13ee9f..09b20917e2a 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -382,8 +382,8 @@ fn check_opaque_meets_bounds<'tcx>( Ok(()) => {} Err(ty_err) => { // Some types may be left "stranded" if they can't be reached - // from an astconv'd bound but they're mentioned in the HIR. This - // will happen, e.g., when a nested opaque is inside of a non- + // from a lowered rustc_middle bound but they're mentioned in the HIR. + // This will happen, e.g., when a nested opaque is inside of a non- // existent associated type, like `impl Trait`. // See . let ty_err = ty_err.to_string(tcx); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index d2fdff6177e..8fb6569aa14 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -746,7 +746,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // We may not collect all RPITITs that we see in the HIR for a trait signature // because an RPITIT was located within a missing item. Like if we have a sig - // returning `-> Missing`, that gets converted to `-> [type error]`, + // returning `-> Missing`, that gets converted to `-> {type error}`, // and when walking through the signature we end up never collecting the def id // of the `impl Sized`. Insert that here, so we don't ICE later. for assoc_item in tcx.associated_types_for_impl_traits_in_associated_fn(trait_m.def_id) { diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index eb31e1546cf..e84bce92fc5 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -760,7 +760,7 @@ impl<'tcx> RegionResolutionVisitor<'tcx> { fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) { // If node was previously marked as a terminating scope during the - // recursive visit of its parent node in the AST, then we need to + // recursive visit of its parent node in the HIR, then we need to // account for the destruction scope representing the scope of // the destructors that run immediately after it completes. if self.terminating_scopes.contains(&id) { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e466fc5e44e..2b4a35d0b9b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -272,7 +272,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() } Some(ty::ImplPolarity::Negative) => { let ast::ImplPolarity::Negative(span) = impl_.polarity else { - bug!("impl_polarity query disagrees with impl's polarity in AST"); + bug!("impl_polarity query disagrees with impl's polarity in HIR"); }; // FIXME(#27579): what amount of WF checking do we need for neg impls? if let hir::Defaultness::Default { .. } = impl_.defaultness { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 06e7576e897..1fa8cbd9627 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -88,13 +88,12 @@ pub fn provide(providers: &mut Providers) { /////////////////////////////////////////////////////////////////////////// -/// Context specific to some particular item. This is what implements -/// [`AstConv`]. +/// Context specific to some particular item. This is what implements [`HirTyLowerer`]. /// /// # `ItemCtxt` vs `FnCtxt` /// /// `ItemCtxt` is primarily used to type-check item signatures and lower them -/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`]. +/// from HIR to their [`ty::Ty`] representation, which is exposed using [`HirTyLowerer`]. /// It's also used for the bodies of items like structs where the body (the fields) /// are just signatures. /// @@ -111,11 +110,11 @@ pub fn provide(providers: &mut Providers) { /// `ItemCtxt` has information about the predicates that are defined /// on the trait. Unfortunately, this predicate information is /// available in various different forms at various points in the -/// process. So we can't just store a pointer to e.g., the AST or the +/// process. So we can't just store a pointer to e.g., the HIR or the /// parsed ty form, we have to be more flexible. To this end, the /// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy -/// `get_type_parameter_bounds` requests, drawing the information from -/// the AST (`hir::Generics`), recursively. +/// `probe_ty_param_bounds` requests, drawing the information from +/// the HIR (`hir::Generics`), recursively. pub struct ItemCtxt<'tcx> { tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, @@ -785,8 +784,7 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { tcx.ensure().predicates_of(f.did); } - // Convert the ctor, if any. This also registers the variant as - // an item. + // Lower the ctor, if any. This also registers the variant as an item. if let Some(ctor_def_id) = variant.ctor_def_id() { lower_variant_ctor(tcx, ctor_def_id.expect_local()); } @@ -1545,7 +1543,7 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option::lower_ty`, when we're + // asking for the item bounds of the *opaques* in a trait's default method signature, we // need to map these projections back to opaques. hir::Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: true, origin, .. }), diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 4c4cf9fa1b6..6d90a867486 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -542,8 +542,8 @@ pub(super) fn explicit_predicates_of<'tcx>( } /// Ensures that the super-predicates of the trait with a `DefId` -/// of `trait_def_id` are converted and stored. This also ensures that -/// the transitive super-predicates are converted. +/// of `trait_def_id` are lowered and stored. This also ensures that +/// the transitive super-predicates are lowered. pub(super) fn super_predicates_of( tcx: TyCtxt<'_>, trait_def_id: LocalDefId, @@ -574,8 +574,8 @@ pub(super) fn implied_predicates_of( } /// Ensures that the super-predicates of the trait with a `DefId` -/// of `trait_def_id` are converted and stored. This also ensures that -/// the transitive super-predicates are converted. +/// of `trait_def_id` are lowered and stored. This also ensures that +/// the transitive super-predicates are lowered. pub(super) fn implied_predicates_with_filter( tcx: TyCtxt<'_>, trait_def_id: DefId, @@ -615,7 +615,7 @@ pub(super) fn implied_predicates_with_filter( &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match)); debug!(?implied_bounds); - // Now require that immediate supertraits are converted, which will, in + // Now require that immediate supertraits are lowered, which will, in // turn, reach indirect supertraits, so we detect cycles now instead of // overflowing during elaboration. Same for implied predicates, which // make sure we walk into associated type bounds. @@ -656,7 +656,7 @@ pub(super) fn type_param_predicates( use rustc_hir::*; use rustc_middle::ty::Ty; - // In the AST, bounds can derive from two places. Either + // In the HIR, bounds can derive from two places. Either // written inline like `` or in a where-clause like // `where T: Foo`. @@ -714,10 +714,11 @@ pub(super) fn type_param_predicates( } impl<'tcx> ItemCtxt<'tcx> { - /// Finds bounds from `hir::Generics`. This requires scanning through the - /// AST. We do this to avoid having to convert *all* the bounds, which - /// would create artificial cycles. Instead, we can only convert the - /// bounds for a type parameter `X` if `X::Foo` is used. + /// Finds bounds from `hir::Generics`. + /// + /// This requires scanning through the HIR. + /// We do this to avoid having to lower *all* the bounds, which would create artificial cycles. + /// Instead, we can only lower the bounds for a type parameter `X` if `X::Foo` is used. #[instrument(level = "trace", skip(self, ast_generics))] fn probe_ty_param_bounds_in_generics( &self, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 83877bff98c..27a26cfe474 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1917,7 +1917,7 @@ fn is_late_bound_map( /// /// If we conservatively considered `'a` unconstrained then we could break users who had written code before /// we started correctly handling aliases. If we considered `'a` constrained then it would become late bound - /// causing an error during astconv as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc` + /// causing an error during HIR ty lowering as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc` /// but appears in the output type `<() as Trait<'a>>::Assoc`. /// /// We must therefore "look into" the `Alias` to see whether we should consider `'a` constrained or not. @@ -1970,8 +1970,8 @@ fn is_late_bound_map( None, hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span }, )) => { - // See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider - // args to be unconstrained. + // See comments on `ConstrainedCollectorPostHirTyLowering` for why this arm does not + // just consider args to be unconstrained. let generics = self.tcx.generics_of(alias_def); let mut walker = ConstrainedCollectorPostHirTyLowering { arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(), diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 4d8e0e04c73..722def2563c 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -97,10 +97,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => { // Find the Item containing the associated type so we can create an ItemCtxt. - // Using the ItemCtxt convert the HIR for the unresolved assoc type into a + // Using the ItemCtxt lower the HIR for the unresolved assoc type into a // ty which is a fully resolved projection. - // For the code example above, this would mean converting Self::Assoc<3> - // into a ty::Alias(ty::Projection, ::Assoc<3>) + // For the code example above, this would mean lowering `Self::Assoc<3>` + // to a ty::Alias(ty::Projection, `::Assoc<3>`). let item_def_id = tcx .hir() .parent_owner_iter(hir_id) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index e95ed554a78..d7fcb19a536 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -30,8 +30,8 @@ several major phases: The type checker is defined into various submodules which are documented independently: -- astconv: converts the AST representation of types - into the `ty` representation. +- astconv: lowers type-system entities from the [HIR][hir] to the + [`rustc_middle::ty`] representation. - collect: computes the types of each top-level item and enters them into the `tcx.types` table for later use. @@ -211,8 +211,16 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { Ok(()) } -/// A quasi-deprecated helper used in rustdoc and clippy to get -/// the type from a HIR node. +/// Lower a [`hir::Ty`] to a [`Ty`]. +/// +///
+/// +/// This function is **quasi-deprecated**. It can cause ICEs if called inside of a body +/// (of a function or constant) and especially if it contains inferred types (`_`). +/// +/// It's used in rustdoc and Clippy. +/// +///
pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { // In case there are any projections, etc., find the "environment" // def-ID that will be used to determine the traits/predicates in diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 580cdb4a3a2..93a0e924099 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -1,6 +1,6 @@ //! Constraint construction and representation //! -//! The second pass over the AST determines the set of constraints. +//! The second pass over the HIR determines the set of constraints. //! We walk the set of items and, for each member, generate new constraints. use hir::def_id::{DefId, LocalDefId}; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index c7d88438fbe..b8f1c0e73c0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -826,7 +826,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } QPath::TypeRelative(ref qself, ref segment) => { - // Don't use `self.to_ty`, since this will register a WF obligation. + // Don't use `self.lower_ty`, since this will register a WF obligation. // If we're trying to call a nonexistent method on a trait // (e.g. `MyTrait::missing_method`), then resolution will // give us a `QPath::TypeRelative` with a trait object as diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 7922c0bfc96..ed70c63ccdc 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -360,8 +360,8 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { /// The `ty` representation of a user-provided type. Depending on the use-site /// we want to either use the unnormalized or the normalized form of this type. /// -/// This is a bridge between the interface of `AstConv`, which outputs a raw `Ty`, -/// and the API in this module, which expect `Ty` to be fully normalized. +/// This is a bridge between the interface of HIR ty lowering, which outputs a raw +/// `Ty`, and the API in this module, which expect `Ty` to be fully normalized. #[derive(Clone, Copy, Debug)] pub struct LoweredTy<'tcx> { /// The unnormalized type provided by the user. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 13ac1de7b36..a7763e91b7a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -957,7 +957,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bounded_ty, .. }) => { - // FIXME: Maybe these calls to `ast_ty_to_ty` can be removed (and the ones below) + // FIXME: Maybe these calls to `lower_ty` can be removed (and the ones below) let ty = self.lowerer().lower_ty(bounded_ty); Some((ty, bounds)) } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 527938daae4..37fea6c122c 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1062,7 +1062,7 @@ pub enum ExpnKind { Macro(MacroKind, Symbol), /// Transform done by the compiler on the AST. AstPass(AstPass), - /// Desugaring done by the compiler during HIR lowering. + /// Desugaring done by the compiler during AST lowering. Desugaring(DesugaringKind), } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs index d60490bce44..439f9eec831 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs @@ -1,5 +1,5 @@ //! Computes a normalizes-to (projection) goal for inherent associated types, -//! `#![feature(inherent_associated_type)]`. Since astconv already determines +//! `#![feature(inherent_associated_type)]`. Since HIR ty lowering already determines //! which impl the IAT is being projected from, we just: //! 1. instantiate generic parameters, //! 2. equate the self type, and diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 013f6e16481..feca4d384bc 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -32,8 +32,9 @@ use std::ops::ControlFlow; pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation}; -/// Returns the object safety violations that affect -/// astconv -- currently, `Self` in supertraits. This is needed +/// Returns the object safety violations that affect HIR ty lowering. +/// +/// Currently that is `Self` in supertraits. This is needed /// because `object_safety_violations` can't be used during /// type collection. pub fn hir_ty_lowering_object_safety_violations( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 6f16194d44f..eca36fc343e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1264,7 +1264,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Extract `TailField` and `TailField` from `Struct` and `Struct`, // normalizing in the process, since `type_of` returns something directly from - // astconv (which means it's un-normalized). + // HIR ty lowering (which means it's un-normalized). let source_tail = normalize_with_depth_to( self, obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 95db9e2092f..1aa65b87f0b 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -396,7 +396,7 @@ pub(crate) fn assoc_def( // associated type. Normally this situation // could only arise through a compiler bug -- // if the user wrote a bad item name, it - // should have failed in astconv. + // should have failed during HIR ty lowering. bug!( "No associated type `{}` for {}", tcx.item_name(assoc_def_id), diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index de8f56618d0..c83428af50a 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -60,7 +60,7 @@ impl AliasKind { /// Defines the kinds of types used by the type system. /// /// Types written by the user start out as `hir::TyKind` and get -/// converted to this representation using `AstConv::ast_ty_to_ty`. +/// converted to this representation using `::lower_ty`. #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")] #[derive(derivative::Derivative)] #[derivative( diff --git a/src/tools/clippy/book/src/development/type_checking.md b/src/tools/clippy/book/src/development/type_checking.md index 136b3fd0270..e6da4322a17 100644 --- a/src/tools/clippy/book/src/development/type_checking.md +++ b/src/tools/clippy/book/src/development/type_checking.md @@ -118,10 +118,10 @@ Here the HIR sees the types without "thinking" about them, it knows that the fun an `u32`. As far as `hir::Ty` is concerned those might be different types. But at the `ty::Ty` level the compiler understands that they're the same type, in-depth lifetimes, etc... -To get from a `hir::Ty` to a `ty::Ty`, you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function outside of bodies or +To get from a `hir::Ty` to a `ty::Ty`, you can use the [`lower_ty`][lower_ty] function outside of bodies or the [`TypeckResults::node_type()`][node_type] method inside of bodies. -> **Warning**: Don't use `hir_ty_to_ty` inside of bodies, because this can cause ICEs. +> **Warning**: Don't use `lower_ty` inside of bodies, because this can cause ICEs. ## Creating Types programmatically @@ -162,6 +162,6 @@ in this chapter: [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html [TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html -[middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html -[hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html -[hir_ty_to_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir_analysis/fn.hir_ty_to_ty.html +[middle_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html +[hir_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.Ty.html +[lower_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/fn.lower_ty.html diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs index 9729c971672..37437cbfbec 100644 --- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs +++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: }; let inner_span = match qpath_generic_tys(inner_qpath).next() { Some(hir_ty) => { - // Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use + // Reallocation of a fat pointer causes it to become thin. `lower_ty` is safe to use // here because `mod.rs` guarantees this lint is only run on types outside of bodies and // is not run on locals. let ty = lower_ty(cx.tcx, hir_ty); diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index dfa816963bc..a6b411d6c0f 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -193,7 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } fn check_body(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) { - // `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies + // `lower_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`. // However the `node_type()` method can *only* be called in bodies. if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() { diff --git a/src/tools/clippy/tests/ui/crashes/ice-6179.rs b/src/tools/clippy/tests/ui/crashes/ice-6179.rs index fffc0f7d0d4..91160eef03d 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6179.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6179.rs @@ -1,5 +1,5 @@ //! This is a minimal reproducer for the ICE in https://github.com/rust-lang/rust-clippy/pull/6179. -//! The ICE is mainly caused by using `hir_ty_to_ty`. See the discussion in the PR for details. +//! The ICE is mainly caused by using `lower_ty`. See the discussion in the PR for details. #![warn(clippy::use_self)] #![allow(dead_code, clippy::let_with_type_underscore)] diff --git a/tests/ui/issues/issue-17361.rs b/tests/ui/issues/issue-17361.rs index 8e85f0791d6..1b1eeb5a252 100644 --- a/tests/ui/issues/issue-17361.rs +++ b/tests/ui/issues/issue-17361.rs @@ -1,5 +1,5 @@ //@ run-pass -// Test that astconv doesn't forget about mutability of &mut str +// Test that HIR ty lowering doesn't forget about mutability of `&mut str`. //@ pretty-expanded FIXME #23616 diff --git a/tests/ui/traits/alias/self-in-generics.rs b/tests/ui/traits/alias/self-in-generics.rs index dcb33b7a90a..433b741532d 100644 --- a/tests/ui/traits/alias/self-in-generics.rs +++ b/tests/ui/traits/alias/self-in-generics.rs @@ -1,4 +1,4 @@ -// astconv uses `FreshTy(0)` as a dummy `Self` type when instanciating trait objects. +// HIR ty lowering uses `FreshTy(0)` as a dummy `Self` type when instanciating trait objects. // This `FreshTy(0)` can leak into substs, causing ICEs in several places. #![feature(trait_alias)] -- cgit 1.4.1-3-g733a5