From d97d4ebecc502bcb5eda2cdaa513e0e7922a377e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 16 Jun 2023 02:10:10 +0000 Subject: [PATCH] Remove even more redundant builtin candidates --- .../src/transform/check_consts/check.rs | 6 +- compiler/rustc_middle/src/traits/mod.rs | 39 +---- .../src/traits/structural_impls.rs | 10 +- .../src/traits/project.rs | 34 +++-- .../src/traits/select/confirmation.rs | 8 +- compiler/rustc_ty_utils/src/instance.rs | 137 ++++++++---------- 6 files changed, 96 insertions(+), 138 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index d4cde7e2c65..106cf111474 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -781,7 +781,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ); return; } - Ok(Some(ImplSource::Closure(_))) => { + // Closure: Fn{Once|Mut} + Ok(Some(ImplSource::Builtin(_))) + if poly_trait_pred.self_ty().skip_binder().is_closure() + && tcx.fn_trait_kind_from_def_id(trait_id).is_some() => + { let ty::Closure(closure_def_id, substs) = *poly_trait_pred.self_ty().no_bound_vars().unwrap().kind() else { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 98179c0f933..492b7228488 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -661,20 +661,6 @@ pub enum ImplSource<'tcx, N> { /// ImplSource for trait upcasting coercion TraitUpcasting(ImplSourceTraitUpcastingData), - /// ImplSource automatically generated for a closure. The `DefId` is the ID - /// of the closure expression. This is an `ImplSource::UserDefined` in spirit, but the - /// impl is generated by the compiler and does not appear in the source. - Closure(Vec), - - /// Same as above, but for a function pointer type with the given signature. - FnPointer(Vec), - - /// ImplSource automatically generated for a generator. - Generator(Vec), - - /// ImplSource automatically generated for a generator backing an async future. - Future(Vec), - /// ImplSource for a trait alias. TraitAlias(ImplSourceTraitAliasData<'tcx, N>), } @@ -683,12 +669,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { pub fn nested_obligations(self) -> Vec { match self { ImplSource::UserDefined(i) => i.nested, - ImplSource::Param(n, _) - | ImplSource::Builtin(n) - | ImplSource::FnPointer(n) - | ImplSource::Closure(n) - | ImplSource::Generator(n) - | ImplSource::Future(n) => n, + ImplSource::Param(n, _) | ImplSource::Builtin(n) => n, ImplSource::Object(d) => d.nested, ImplSource::TraitAlias(d) => d.nested, ImplSource::TraitUpcasting(d) => d.nested, @@ -698,12 +679,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { pub fn borrow_nested_obligations(&self) -> &[N] { match self { ImplSource::UserDefined(i) => &i.nested, - ImplSource::Param(n, _) - | ImplSource::Builtin(n) - | ImplSource::FnPointer(n) - | ImplSource::Closure(n) - | ImplSource::Generator(n) - | ImplSource::Future(n) => &n, + ImplSource::Param(n, _) | ImplSource::Builtin(n) => &n, ImplSource::Object(d) => &d.nested, ImplSource::TraitAlias(d) => &d.nested, ImplSource::TraitUpcasting(d) => &d.nested, @@ -713,12 +689,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] { match self { ImplSource::UserDefined(i) => &mut i.nested, - ImplSource::Param(n, _) - | ImplSource::Builtin(n) - | ImplSource::FnPointer(n) - | ImplSource::Closure(n) - | ImplSource::Generator(n) - | ImplSource::Future(n) => n, + ImplSource::Param(n, _) | ImplSource::Builtin(n) => n, ImplSource::Object(d) => &mut d.nested, ImplSource::TraitAlias(d) => &mut d.nested, ImplSource::TraitUpcasting(d) => &mut d.nested, @@ -742,10 +713,6 @@ impl<'tcx, N> ImplSource<'tcx, N> { vtable_base: o.vtable_base, nested: o.nested.into_iter().map(f).collect(), }), - ImplSource::Closure(n) => ImplSource::Closure(n.into_iter().map(f).collect()), - ImplSource::Generator(n) => ImplSource::Generator(n.into_iter().map(f).collect()), - ImplSource::Future(n) => ImplSource::Future(n.into_iter().map(f).collect()), - ImplSource::FnPointer(n) => ImplSource::FnPointer(n.into_iter().map(f).collect()), ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData { alias_def_id: d.alias_def_id, substs: d.substs, diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index bc0e656a656..ac02d6ed62f 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -9,13 +9,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { match *self { super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v), - super::ImplSource::Closure(ref d) => write!(f, "{:?}", d), - - super::ImplSource::Generator(ref d) => write!(f, "{:?}", d), - - super::ImplSource::Future(ref d) => write!(f, "{:?}", d), - - super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d), + super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d), super::ImplSource::Object(ref d) => write!(f, "{:?}", d), @@ -23,8 +17,6 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { write!(f, "ImplSourceParamData({:?}, {:?})", n, ct) } - super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d), - super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d), super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d), diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 1477c8957f6..8399fbfc5be 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1717,11 +1717,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( }; let eligible = match &impl_source { - super::ImplSource::Closure(_) - | super::ImplSource::Generator(_) - | super::ImplSource::Future(_) - | super::ImplSource::FnPointer(_) - | super::ImplSource::TraitAlias(_) => true, + super::ImplSource::TraitAlias(_) => true, super::ImplSource::UserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in @@ -1779,7 +1775,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); let lang_items = selcx.tcx().lang_items(); - if lang_items.discriminant_kind_trait() == Some(poly_trait_ref.def_id()) { + if [lang_items.gen_trait(), lang_items.future_trait()].contains(&Some(poly_trait_ref.def_id())) + || selcx.tcx().fn_trait_kind_from_def_id(poly_trait_ref.def_id()).is_some() + { + true + } else if lang_items.discriminant_kind_trait() == Some(poly_trait_ref.def_id()) { match self_ty.kind() { ty::Bool | ty::Char @@ -1990,11 +1990,23 @@ fn confirm_select_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { match impl_source { super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), - super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data), - super::ImplSource::Future(data) => confirm_future_candidate(selcx, obligation, data), - super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data), - super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), - super::ImplSource::Builtin(data) => confirm_builtin_candidate(selcx, obligation, data), + super::ImplSource::Builtin(data) => { + let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx()); + let lang_items = selcx.tcx().lang_items(); + if lang_items.gen_trait() == Some(trait_def_id) { + confirm_generator_candidate(selcx, obligation, data) + } else if lang_items.future_trait() == Some(trait_def_id) { + confirm_future_candidate(selcx, obligation, data) + } else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() { + if obligation.predicate.self_ty().is_closure() { + confirm_closure_candidate(selcx, obligation, data) + } else { + confirm_fn_pointer_candidate(selcx, obligation, data) + } + } else { + confirm_builtin_candidate(selcx, obligation, data) + } + } super::ImplSource::Object(_) | super::ImplSource::Param(..) | super::ImplSource::TraitUpcasting(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d369a087c9b..3c356978d5c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -85,22 +85,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ClosureCandidate { .. } => { let vtable_closure = self.confirm_closure_candidate(obligation)?; - ImplSource::Closure(vtable_closure) + ImplSource::Builtin(vtable_closure) } GeneratorCandidate => { let vtable_generator = self.confirm_generator_candidate(obligation)?; - ImplSource::Generator(vtable_generator) + ImplSource::Builtin(vtable_generator) } FutureCandidate => { let vtable_future = self.confirm_future_candidate(obligation)?; - ImplSource::Future(vtable_future) + ImplSource::Builtin(vtable_future) } FnPointerCandidate { is_const } => { let data = self.confirm_fn_pointer_candidate(obligation, is_const)?; - ImplSource::FnPointer(data) + ImplSource::Builtin(data) } TraitAliasCandidate => { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index cc7700f378a..45b1075b602 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -177,83 +177,6 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new(leaf_def.item.def_id, substs)) } - traits::ImplSource::Generator(_) => { - let ty::Generator(generator_def_id, substs, _) = *rcvr_substs.type_at(0).kind() else { - unreachable!() - }; - if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume { - // For compiler developers who'd like to add new items to `Generator`, - // you either need to generate a shim body, or perhaps return - // `InstanceDef::Item` pointing to a trait default method body if - // it is given a default implementation by the trait. - span_bug!( - tcx.def_span(generator_def_id), - "no definition for `{trait_ref}::{}` for built-in generator type", - tcx.item_name(trait_item_id) - ) - } - Some(Instance { def: ty::InstanceDef::Item(generator_def_id), substs }) - } - traits::ImplSource::Future(_) => { - let ty::Generator(generator_def_id, substs, _) = *rcvr_substs.type_at(0).kind() else { - unreachable!() - }; - if Some(trait_item_id) == tcx.lang_items().future_poll_fn() { - // `Future::poll` is generated by the compiler. - Some(Instance { def: ty::InstanceDef::Item(generator_def_id), substs: substs }) - } else { - // All other methods are default methods of the `Future` trait. - // (this assumes that `ImplSource::Future` is only used for methods on `Future`) - debug_assert!(tcx.defaultness(trait_item_id).has_value()); - Some(Instance::new(trait_item_id, rcvr_substs)) - } - } - traits::ImplSource::Closure(_) => { - let ty::Closure(closure_def_id, substs) = *rcvr_substs.type_at(0).kind() else { - unreachable!() - }; - if cfg!(debug_assertions) - && ![sym::call, sym::call_mut, sym::call_once] - .contains(&tcx.item_name(trait_item_id)) - { - // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`, - // you either need to generate a shim body, or perhaps return - // `InstanceDef::Item` pointing to a trait default method body if - // it is given a default implementation by the trait. - span_bug!( - tcx.def_span(closure_def_id), - "no definition for `{trait_ref}::{}` for built-in closure type", - tcx.item_name(trait_item_id) - ) - } - let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap(); - Instance::resolve_closure(tcx, closure_def_id, substs, trait_closure_kind) - } - traits::ImplSource::FnPointer(_) => match rcvr_substs.type_at(0).kind() { - ty::FnDef(..) | ty::FnPtr(..) => { - if cfg!(debug_assertions) - && ![sym::call, sym::call_mut, sym::call_once] - .contains(&tcx.item_name(trait_item_id)) - { - // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`, - // you either need to generate a shim body, or perhaps return - // `InstanceDef::Item` pointing to a trait default method body if - // it is given a default implementation by the trait. - bug!( - "no definition for `{trait_ref}::{}` for built-in fn type", - tcx.item_name(trait_item_id) - ) - } - Some(Instance { - def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_substs.type_at(0)), - substs: rcvr_substs, - }) - } - _ => bug!( - "no built-in definition for `{trait_ref}::{}` for non-fn type", - tcx.item_name(trait_item_id) - ), - }, traits::ImplSource::Object(ref data) => { traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| { Instance { @@ -306,6 +229,66 @@ fn resolve_associated_item<'tcx>( span: tcx.def_span(trait_item_id), }) } + } else if Some(trait_ref.def_id) == lang_items.future_trait() { + let ty::Generator(generator_def_id, substs, _) = *rcvr_substs.type_at(0).kind() else { + bug!() + }; + if Some(trait_item_id) == tcx.lang_items().future_poll_fn() { + // `Future::poll` is generated by the compiler. + Some(Instance { def: ty::InstanceDef::Item(generator_def_id), substs: substs }) + } else { + // All other methods are default methods of the `Future` trait. + // (this assumes that `ImplSource::Builtin` is only used for methods on `Future`) + debug_assert!(tcx.defaultness(trait_item_id).has_value()); + Some(Instance::new(trait_item_id, rcvr_substs)) + } + } else if Some(trait_ref.def_id) == lang_items.gen_trait() { + let ty::Generator(generator_def_id, substs, _) = *rcvr_substs.type_at(0).kind() else { + bug!() + }; + if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume { + // For compiler developers who'd like to add new items to `Generator`, + // you either need to generate a shim body, or perhaps return + // `InstanceDef::Item` pointing to a trait default method body if + // it is given a default implementation by the trait. + span_bug!( + tcx.def_span(generator_def_id), + "no definition for `{trait_ref}::{}` for built-in generator type", + tcx.item_name(trait_item_id) + ) + } + Some(Instance { def: ty::InstanceDef::Item(generator_def_id), substs }) + } else if tcx.fn_trait_kind_from_def_id(trait_ref.def_id).is_some() { + // FIXME: This doesn't check for malformed libcore that defines, e.g., + // `trait Fn { fn call_once(&self) { .. } }`. This is mostly for extension + // methods. + if cfg!(debug_assertions) + && ![sym::call, sym::call_mut, sym::call_once] + .contains(&tcx.item_name(trait_item_id)) + { + // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`, + // you either need to generate a shim body, or perhaps return + // `InstanceDef::Item` pointing to a trait default method body if + // it is given a default implementation by the trait. + bug!( + "no definition for `{trait_ref}::{}` for built-in callable type", + tcx.item_name(trait_item_id) + ) + } + match *rcvr_substs.type_at(0).kind() { + ty::Closure(closure_def_id, substs) => { + let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap(); + Instance::resolve_closure(tcx, closure_def_id, substs, trait_closure_kind) + } + ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { + def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_substs.type_at(0)), + substs: rcvr_substs, + }), + _ => bug!( + "no built-in definition for `{trait_ref}::{}` for non-fn type", + tcx.item_name(trait_item_id) + ), + } } else { None }