Make traits::util::* free functions.

This commit is contained in:
Camille GILLOT 2020-01-05 20:27:00 +01:00
parent 56a0aec07f
commit 787cd5493a
10 changed files with 194 additions and 179 deletions

View File

@ -64,6 +64,10 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
pub use self::util::{
get_vtable_index_of_object_method, impl_is_default, impl_item_is_final,
predicate_for_trait_def, upcast_choices,
};
pub use self::util::{
supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
};

View File

@ -1057,7 +1057,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
node_item.item.defaultness.has_value()
} else {
node_item.item.defaultness.is_default()
|| selcx.tcx().impl_is_default(node_item.node.def_id())
|| super::util::impl_is_default(selcx.tcx(), node_item.node.def_id())
};
// Only reveal a specializable default if we're past type-checking
@ -1263,26 +1263,30 @@ fn confirm_generator_candidate<'cx, 'tcx>(
let gen_def_id = tcx.lang_items().gen_trait().unwrap();
let predicate = tcx
.generator_trait_ref_and_outputs(gen_def_id, obligation.predicate.self_ty(), gen_sig)
.map_bound(|(trait_ref, yield_ty, return_ty)| {
let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
let ty = if name == sym::Return {
return_ty
} else if name == sym::Yield {
yield_ty
} else {
bug!()
};
let predicate = super::util::generator_trait_ref_and_outputs(
tcx,
gen_def_id,
obligation.predicate.self_ty(),
gen_sig,
)
.map_bound(|(trait_ref, yield_ty, return_ty)| {
let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
let ty = if name == sym::Return {
return_ty
} else if name == sym::Yield {
yield_ty
} else {
bug!()
};
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
substs: trait_ref.substs,
item_def_id: obligation.predicate.item_def_id,
},
ty: ty,
}
});
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
substs: trait_ref.substs,
item_def_id: obligation.predicate.item_def_id,
},
ty: ty,
}
});
confirm_param_env_candidate(selcx, obligation, predicate)
.with_addl_obligations(vtable.nested)
@ -1349,21 +1353,21 @@ fn confirm_callable_candidate<'cx, 'tcx>(
// the `Output` associated type is declared on `FnOnce`
let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap();
let predicate = tcx
.closure_trait_ref_and_return_type(
fn_once_def_id,
obligation.predicate.self_ty(),
fn_sig,
flag,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy::from_ref_and_name(
tcx,
trait_ref,
Ident::with_dummy_span(FN_OUTPUT_NAME),
),
ty: ret_type,
});
let predicate = super::util::closure_trait_ref_and_return_type(
tcx,
fn_once_def_id,
obligation.predicate.self_ty(),
fn_sig,
flag,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy::from_ref_and_name(
tcx,
trait_ref,
Ident::with_dummy_span(FN_OUTPUT_NAME),
),
ty: ret_type,
});
confirm_param_env_candidate(selcx, obligation, predicate)
}

View File

@ -11,6 +11,7 @@ use super::coherence::{self, Conflict};
use super::project;
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
use super::util;
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
use super::DerivedObligationCause;
use super::Selection;
use super::SelectionResult;
@ -2651,7 +2652,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
recursion_depth,
&skol_ty,
);
let skol_obligation = self.tcx().predicate_for_trait_def(
let skol_obligation = predicate_for_trait_def(
self.tcx(),
param_env,
cause.clone(),
trait_def_id,
@ -2988,7 +2990,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// we pass over, we sum up the set of number of vtable
// entries, so that we can compute the offset for the selected
// trait.
vtable_base = nonmatching.map(|t| tcx.count_own_vtable_entries(t)).sum();
vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
}
VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested }
@ -3003,15 +3005,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Okay to skip binder; it is reintroduced below.
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let sig = self_ty.fn_sig(self.tcx());
let trait_ref = self
.tcx()
.closure_trait_ref_and_return_type(
obligation.predicate.def_id(),
self_ty,
sig,
util::TupleArgumentsFlag::Yes,
)
.map_bound(|(trait_ref, _)| trait_ref);
let trait_ref = closure_trait_ref_and_return_type(
self.tcx(),
obligation.predicate.def_id(),
self_ty,
sig,
util::TupleArgumentsFlag::Yes,
)
.map_bound(|(trait_ref, _)| trait_ref);
let Normalized { value: trait_ref, obligations } = project::normalize_with_depth(
self,
@ -3381,7 +3382,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(obligations);
// Construct the nested `Field<T>: Unsize<Field<U>>` predicate.
nested.push(tcx.predicate_for_trait_def(
nested.push(predicate_for_trait_def(
tcx,
obligation.param_env,
obligation.cause.clone(),
obligation.predicate.def_id(),
@ -3416,7 +3418,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(obligations);
// Construct the nested `T: Unsize<U>` predicate.
nested.push(tcx.predicate_for_trait_def(
nested.push(predicate_for_trait_def(
tcx,
obligation.param_env,
obligation.cause.clone(),
obligation.predicate.def_id(),
@ -3627,14 +3630,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// in fact unparameterized (or at least does not reference any
// regions bound in the obligation). Still probably some
// refactoring could make this nicer.
self.tcx()
.closure_trait_ref_and_return_type(
obligation.predicate.def_id(),
obligation.predicate.skip_binder().self_ty(), // (1)
closure_type,
util::TupleArgumentsFlag::No,
)
.map_bound(|(trait_ref, _)| trait_ref)
closure_trait_ref_and_return_type(
self.tcx(),
obligation.predicate.def_id(),
obligation.predicate.skip_binder().self_ty(), // (1)
closure_type,
util::TupleArgumentsFlag::No,
)
.map_bound(|(trait_ref, _)| trait_ref)
}
fn generator_trait_ref_unnormalized(
@ -3651,13 +3654,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// regions bound in the obligation). Still probably some
// refactoring could make this nicer.
self.tcx()
.generator_trait_ref_and_outputs(
obligation.predicate.def_id(),
obligation.predicate.skip_binder().self_ty(), // (1)
gen_sig,
)
.map_bound(|(trait_ref, ..)| trait_ref)
super::util::generator_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
obligation.predicate.skip_binder().self_ty(), // (1)
gen_sig,
)
.map_bound(|(trait_ref, ..)| trait_ref)
}
/// Returns the obligations that are implied by instantiating an

View File

@ -548,125 +548,123 @@ pub fn predicate_for_trait_ref<'tcx>(
Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() }
}
impl<'tcx> TyCtxt<'tcx> {
pub fn predicate_for_trait_def(
self,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
recursion_depth: usize,
self_ty: Ty<'tcx>,
params: &[GenericArg<'tcx>],
) -> PredicateObligation<'tcx> {
let trait_ref =
ty::TraitRef { def_id: trait_def_id, substs: self.mk_substs_trait(self_ty, params) };
predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
pub fn predicate_for_trait_def(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
recursion_depth: usize,
self_ty: Ty<'tcx>,
params: &[GenericArg<'tcx>],
) -> PredicateObligation<'tcx> {
let trait_ref =
ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) };
predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
}
/// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.
pub fn upcast_choices(
tcx: TyCtxt<'tcx>,
source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: DefId,
) -> Vec<ty::PolyTraitRef<'tcx>> {
if source_trait_ref.def_id() == target_trait_def_id {
return vec![source_trait_ref]; // Shortcut the most common case.
}
/// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.
pub fn upcast_choices(
self,
source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: DefId,
) -> Vec<ty::PolyTraitRef<'tcx>> {
if source_trait_ref.def_id() == target_trait_def_id {
return vec![source_trait_ref]; // Shortcut the most common case.
supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
}
/// Given a trait `trait_ref`, returns the number of vtable entries
/// that come from `trait_ref`, excluding its supertraits. Used in
/// computing the vtable base for an upcast trait of a trait object.
pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
let mut entries = 0;
// Count number of methods and add them to the total offset.
// Skip over associated types and constants.
for trait_item in tcx.associated_items(trait_ref.def_id()) {
if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
supertraits(self, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
}
entries
}
/// Given a trait `trait_ref`, returns the number of vtable entries
/// that come from `trait_ref`, excluding its supertraits. Used in
/// computing the vtable base for an upcast trait of a trait object.
pub fn count_own_vtable_entries(self, trait_ref: ty::PolyTraitRef<'tcx>) -> usize {
let mut entries = 0;
// Count number of methods and add them to the total offset.
// Skip over associated types and constants.
for trait_item in self.associated_items(trait_ref.def_id()) {
if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
/// Given an upcast trait object described by `object`, returns the
/// index of the method `method_def_id` (which should be part of
/// `object.upcast_trait_ref`) within the vtable for `object`.
pub fn get_vtable_index_of_object_method<N>(
tcx: TyCtxt<'tcx>,
object: &super::VtableObjectData<'tcx, N>,
method_def_id: DefId,
) -> usize {
// Count number of methods preceding the one we are selecting and
// add them to the total offset.
// Skip over associated types and constants.
let mut entries = object.vtable_base;
for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()) {
if trait_item.def_id == method_def_id {
// The item with the ID we were given really ought to be a method.
assert_eq!(trait_item.kind, ty::AssocKind::Method);
return entries;
}
entries
}
/// Given an upcast trait object described by `object`, returns the
/// index of the method `method_def_id` (which should be part of
/// `object.upcast_trait_ref`) within the vtable for `object`.
pub fn get_vtable_index_of_object_method<N>(
self,
object: &super::VtableObjectData<'tcx, N>,
method_def_id: DefId,
) -> usize {
// Count number of methods preceding the one we are selecting and
// add them to the total offset.
// Skip over associated types and constants.
let mut entries = object.vtable_base;
for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) {
if trait_item.def_id == method_def_id {
// The item with the ID we were given really ought to be a method.
assert_eq!(trait_item.kind, ty::AssocKind::Method);
return entries;
}
if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
}
bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
}
pub fn closure_trait_ref_and_return_type(
self,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::PolyFnSig<'tcx>,
tuple_arguments: TupleArgumentsFlag,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
let arguments_tuple = match tuple_arguments {
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
TupleArgumentsFlag::Yes => self.intern_tup(sig.skip_binder().inputs()),
};
let trait_ref = ty::TraitRef {
def_id: fn_trait_def_id,
substs: self.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
};
ty::Binder::bind((trait_ref, sig.skip_binder().output()))
}
pub fn generator_trait_ref_and_outputs(
self,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::PolyGenSig<'tcx>,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
let trait_ref =
ty::TraitRef { def_id: fn_trait_def_id, substs: self.mk_substs_trait(self_ty, &[]) };
ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
}
pub fn impl_is_default(self, node_item_def_id: DefId) -> bool {
match self.hir().as_local_hir_id(node_item_def_id) {
Some(hir_id) => {
let item = self.hir().expect_item(hir_id);
if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind {
defaultness.is_default()
} else {
false
}
}
None => self.impl_defaultness(node_item_def_id).is_default(),
if trait_item.kind == ty::AssocKind::Method {
entries += 1;
}
}
pub fn impl_item_is_final(self, assoc_item: &ty::AssocItem) -> bool {
assoc_item.defaultness.is_final() && !self.impl_is_default(assoc_item.container.id())
bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
}
pub fn closure_trait_ref_and_return_type(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::PolyFnSig<'tcx>,
tuple_arguments: TupleArgumentsFlag,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> {
let arguments_tuple = match tuple_arguments {
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()),
};
let trait_ref = ty::TraitRef {
def_id: fn_trait_def_id,
substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
};
ty::Binder::bind((trait_ref, sig.skip_binder().output()))
}
pub fn generator_trait_ref_and_outputs(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
sig: ty::PolyGenSig<'tcx>,
) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
let trait_ref =
ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[]) };
ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty))
}
pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool {
match tcx.hir().as_local_hir_id(node_item_def_id) {
Some(hir_id) => {
let item = tcx.hir().expect_item(hir_id);
if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind {
defaultness.is_default()
} else {
false
}
}
None => tcx.impl_defaultness(node_item_def_id).is_default(),
}
}
pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id())
}
pub enum TupleArgumentsFlag {
Yes,
No,

View File

@ -411,7 +411,7 @@ fn resolve_associated_item<'tcx>(
substs: rcvr_substs,
}),
traits::VtableObject(ref data) => {
let index = tcx.get_vtable_index_of_object_method(data, def_id);
let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
}
traits::VtableBuiltin(..) => {

View File

@ -3,6 +3,7 @@ use crate::const_eval::const_variant_index;
use rustc::infer::InferCtxt;
use rustc::lint;
use rustc::mir::Field;
use rustc::traits::predicate_for_trait_def;
use rustc::traits::{ObligationCause, PredicateObligation};
use rustc::ty::{self, Ty, TyCtxt};
use rustc_hir as hir;
@ -129,7 +130,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// not *yet* implement `PartialEq`. So for now we leave this here.
let ty_is_partial_eq: bool = {
let partial_eq_trait_id = self.tcx().lang_items().eq_trait().unwrap();
let obligation: PredicateObligation<'_> = self.tcx().predicate_for_trait_def(
let obligation: PredicateObligation<'_> = predicate_for_trait_def(
self.tcx(),
self.param_env,
ObligationCause::misc(self.span, self.id),
partial_eq_trait_id,

View File

@ -544,7 +544,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// and almost never more than 3. By using a SmallVec we avoid an
// allocation, at the (very small) cost of (occasionally) having to
// shift subsequent elements down when removing the front element.
let mut queue: SmallVec<[_; 4]> = smallvec![self.tcx.predicate_for_trait_def(
let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def(
self.tcx,
self.fcx.param_env,
cause,
coerce_unsized_did,

View File

@ -596,7 +596,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
target_trait_def_id: DefId,
) -> ty::PolyTraitRef<'tcx> {
let upcast_trait_refs =
self.tcx.upcast_choices(source_trait_ref.clone(), target_trait_def_id);
traits::upcast_choices(self.tcx, source_trait_ref.clone(), target_trait_def_id);
// must be exactly one trait ref or we'd get an ambig error etc
if upcast_trait_refs.len() != 1 {

View File

@ -1901,7 +1901,7 @@ fn check_specialization_validity<'tcx>(
match parent_item {
// Parent impl exists, and contains the parent item we're trying to specialize, but
// doesn't mark it `default`.
Some(parent_item) if tcx.impl_item_is_final(&parent_item) => {
Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {
Some(Err(parent_impl.def_id()))
}
@ -1912,7 +1912,7 @@ fn check_specialization_validity<'tcx>(
// grandparent. In that case, if parent is a `default impl`, inherited items use the
// "defaultness" from the grandparent, else they are final.
None => {
if tcx.impl_is_default(parent_impl.def_id()) {
if traits::impl_is_default(tcx, parent_impl.def_id()) {
None
} else {
Some(Err(parent_impl.def_id()))
@ -2076,7 +2076,7 @@ fn check_impl_items_against_trait<'tcx>(
.map(|node_item| !node_item.node.is_from_trait())
.unwrap_or(false);
if !is_implemented && !tcx.impl_is_default(impl_id) {
if !is_implemented && !traits::impl_is_default(tcx, impl_id) {
if !trait_item.defaultness.has_value() {
missing_items.push(trait_item);
} else if associated_type_overridden {

View File

@ -7,6 +7,7 @@ use rustc::middle::lang_items::UnsizeTraitLangItem;
use rustc::middle::region;
use rustc::infer;
use rustc::traits::predicate_for_trait_def;
use rustc::traits::{self, ObligationCause, TraitEngine};
use rustc::ty::adjustment::CoerceUnsizedInfo;
use rustc::ty::util::CopyImplementationError;
@ -284,7 +285,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) {
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
for field in coerced_fields {
let predicate = tcx.predicate_for_trait_def(
let predicate = predicate_for_trait_def(
tcx,
param_env,
cause.clone(),
dispatch_from_dyn_trait,
@ -543,7 +545,8 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_hir_id);
let predicate = tcx.predicate_for_trait_def(
let predicate = predicate_for_trait_def(
tcx,
param_env,
cause,
trait_def_id,