about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection
diff options
context:
space:
mode:
authorCharles Lew <crlf0710@gmail.com>2021-06-14 18:02:53 +0800
committerCharles Lew <crlf0710@gmail.com>2021-06-15 01:59:00 +0800
commita86d3a7e45e6c4db749df018678ef587ace21933 (patch)
tree6c7cd6bc34a3c66b00cb11a916bacb47bd957016 /compiler/rustc_trait_selection
parent14831568d506b5ee7be3e7d5a2f029ce9048b609 (diff)
downloadrust-a86d3a7e45e6c4db749df018678ef587ace21933.tar.gz
rust-a86d3a7e45e6c4db749df018678ef587ace21933.zip
Refactor to make interpreter and codegen backend neutral to vtable internal representation.
Diffstat (limited to 'compiler/rustc_trait_selection')
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs133
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs19
2 files changed, 89 insertions, 63 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index f26eb159105..d65a596a827 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -31,7 +31,8 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{
-    self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness,
+    self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
+    COMMON_VTABLE_ENTRIES,
 };
 use rustc_span::Span;
 
@@ -455,59 +456,89 @@ fn subst_and_check_impossible_predicates<'tcx>(
 
 /// Given a trait `trait_ref`, iterates the vtable entries
 /// that come from `trait_ref`, including its supertraits.
-fn vtable_methods<'tcx>(
+fn vtable_entries<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
-) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
-    debug!("vtable_methods({:?})", trait_ref);
-
-    tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
-        let trait_methods = tcx
-            .associated_items(trait_ref.def_id())
-            .in_definition_order()
-            .filter(|item| item.kind == ty::AssocKind::Fn);
-
-        // Now list each method's DefId and InternalSubsts (for within its trait).
-        // If the method can never be called from this object, produce None.
-        trait_methods.map(move |trait_method| {
-            debug!("vtable_methods: trait_method={:?}", trait_method);
-            let def_id = trait_method.def_id;
-
-            // Some methods cannot be called on an object; skip those.
-            if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
-                debug!("vtable_methods: not vtable safe");
-                return None;
-            }
+) -> &'tcx [VtblEntry<'tcx>] {
+    debug!("vtable_entries({:?})", trait_ref);
+
+    let entries = COMMON_VTABLE_ENTRIES.iter().cloned().chain(
+        supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
+            let trait_methods = tcx
+                .associated_items(trait_ref.def_id())
+                .in_definition_order()
+                .filter(|item| item.kind == ty::AssocKind::Fn);
+
+            // Now list each method's DefId and InternalSubsts (for within its trait).
+            // If the method can never be called from this object, produce `Vacant`.
+            trait_methods.map(move |trait_method| {
+                debug!("vtable_entries: trait_method={:?}", trait_method);
+                let def_id = trait_method.def_id;
+
+                // Some methods cannot be called on an object; skip those.
+                if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+                    debug!("vtable_entries: not vtable safe");
+                    return VtblEntry::Vacant;
+                }
 
-            // The method may have some early-bound lifetimes; add regions for those.
-            let substs = trait_ref.map_bound(|trait_ref| {
-                InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
-                    GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-                    GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
-                        trait_ref.substs[param.index as usize]
-                    }
-                })
-            });
-
-            // The trait type may have higher-ranked lifetimes in it;
-            // erase them if they appear, so that we get the type
-            // at some particular call site.
-            let substs =
-                tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
-
-            // It's possible that the method relies on where-clauses that
-            // do not hold for this particular set of type parameters.
-            // Note that this method could then never be called, so we
-            // do not want to try and codegen it, in that case (see #23435).
-            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
-            if impossible_predicates(tcx, predicates.predicates) {
-                debug!("vtable_methods: predicates do not hold");
-                return None;
-            }
+                // The method may have some early-bound lifetimes; add regions for those.
+                let substs = trait_ref.map_bound(|trait_ref| {
+                    InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+                        GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+                        GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+                            trait_ref.substs[param.index as usize]
+                        }
+                    })
+                });
+
+                // The trait type may have higher-ranked lifetimes in it;
+                // erase them if they appear, so that we get the type
+                // at some particular call site.
+                let substs =
+                    tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
+
+                // It's possible that the method relies on where-clauses that
+                // do not hold for this particular set of type parameters.
+                // Note that this method could then never be called, so we
+                // do not want to try and codegen it, in that case (see #23435).
+                let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+                if impossible_predicates(tcx, predicates.predicates) {
+                    debug!("vtable_entries: predicates do not hold");
+                    return VtblEntry::Vacant;
+                }
 
-            Some((def_id, substs))
-        })
-    }))
+                VtblEntry::Method(def_id, substs)
+            })
+        }),
+    );
+
+    tcx.arena.alloc_from_iter(entries)
+}
+
+/// Find slot base for trait methods within vtable entries of another trait
+fn vtable_trait_first_method_offset<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: (
+        ty::PolyTraitRef<'tcx>, // trait_to_be_found
+        ty::PolyTraitRef<'tcx>, // trait_owning_vtable
+    ),
+) -> usize {
+    let (trait_to_be_found, trait_owning_vtable) = key;
+
+    let mut supertraits = util::supertraits(tcx, trait_owning_vtable);
+
+    // For each of the non-matching predicates that
+    // we pass over, we sum up the set of number of vtable
+    // entries, so that we can compute the offset for the selected
+    // trait.
+    let vtable_base = ty::COMMON_VTABLE_ENTRIES.len()
+        + supertraits
+            .by_ref()
+            .take_while(|t| *t != trait_to_be_found)
+            .map(|t| util::count_own_vtable_entries(tcx, t))
+            .sum::<usize>();
+
+    vtable_base
 }
 
 /// Check whether a `ty` implements given trait(trait_def_id).
@@ -547,7 +578,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
         specialization_graph_of: specialize::specialization_graph_provider,
         specializes: specialize::specializes,
         codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
-        vtable_methods,
+        vtable_entries,
         type_implements_trait,
         subst_and_check_impossible_predicates,
         mir_abstract_const: |tcx, def_id| {
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index e338a21b603..f8297ee3a07 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -396,19 +396,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let mut nested = vec![];
 
         let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref));
-
-        // For each of the non-matching predicates that
-        // we pass over, we sum up the set of number of vtable
-        // entries, so that we can compute the offset for the selected
-        // trait.
-        let vtable_base = supertraits
-            .by_ref()
-            .take(index)
-            .map(|t| super::util::count_own_vtable_entries(tcx, t))
-            .sum();
-
         let unnormalized_upcast_trait_ref =
-            supertraits.next().expect("supertraits iterator no longer has as many elements");
+            supertraits.nth(index).expect("supertraits iterator no longer has as many elements");
 
         let upcast_trait_ref = normalize_with_depth_to(
             self,
@@ -490,6 +479,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         debug!(?nested, "object nested obligations");
+
+        let vtable_base = super::super::vtable_trait_first_method_offset(
+            tcx,
+            (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
+        );
+
         Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested })
     }