// reachable from there, to start (if this is an inherent impl,
// then just examine the self type).
let mut input_parameters: HashSet<_> =
- ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect();
+ ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect();
if let Some(ref trait_ref) = impl_trait_ref {
- input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false));
+ input_parameters.extend(ctp::parameters_for(trait_ref, false));
}
ctp::setup_constraining_predicates(impl_predicates.predicates.get_mut_slice(TypeSpace),
let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
let mut input_parameters: HashSet<_> =
- ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect();
+ ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect();
if let Some(ref trait_ref) = impl_trait_ref {
- input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false));
+ input_parameters.extend(ctp::parameters_for(trait_ref, false));
}
ctp::identify_constrained_type_params(
&impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
})
- .flat_map(|ty| ctp::parameters_for_type(ty, true))
+ .flat_map(|ty| ctp::parameters_for(&ty, true))
.filter_map(|p| match p {
ctp::Parameter::Type(_) => None,
ctp::Parameter::Region(r) => Some(r),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::ty::{self, subst, Ty};
-
+use rustc::ty::{self, Ty};
+use rustc::ty::fold::{TypeFoldable, TypeVisitor};
use std::collections::HashSet;
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
}
/// If `include_projections` is false, returns the list of parameters that are
-/// constrained by the type `ty` - i.e. the value of each parameter in the list is
-/// uniquely determined by `ty` (see RFC 447). If it is true, return the list
+/// constrained by `t` - i.e. the value of each parameter in the list is
+/// uniquely determined by `t` (see RFC 447). If it is true, return the list
/// of parameters whose values are needed in order to constrain `ty` - these
/// differ, with the latter being a superset, in the presence of projections.
-pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>,
- include_projections: bool) -> Vec<Parameter> {
- let mut result = vec![];
- ty.maybe_walk(|t| match t.sty {
- ty::TyProjection(..) if !include_projections => {
+pub fn parameters_for<'tcx, T>(t: &T,
+ include_nonconstraining: bool)
+ -> Vec<Parameter>
+ where T: TypeFoldable<'tcx>
+{
- false // projections are not injective.
- }
- _ => {
- result.append(&mut parameters_for_type_shallow(t));
- // non-projection type constructors are injective.
- true
- }
- });
- result
+ let mut collector = ParameterCollector {
+ parameters: vec![],
+ include_nonconstraining: include_nonconstraining
+ };
+ t.visit_with(&mut collector);
+ collector.parameters
}
-pub fn parameters_for_trait_ref<'tcx>(trait_ref: &ty::TraitRef<'tcx>,
- include_projections: bool) -> Vec<Parameter> {
- let mut region_parameters =
- parameters_for_regions_in_substs(&trait_ref.substs);
-
- let type_parameters =
- trait_ref.substs
- .types
- .iter()
- .flat_map(|ty| parameters_for_type(ty, include_projections));
-
- region_parameters.extend(type_parameters);
-
- region_parameters
+struct ParameterCollector {
+ parameters: Vec<Parameter>,
+ include_nonconstraining: bool
}
-fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
- match ty.sty {
- ty::TyParam(ref d) =>
- vec![Parameter::Type(d.clone())],
- ty::TyRef(region, _) =>
- parameters_for_region(region).into_iter().collect(),
- ty::TyStruct(_, substs) |
- ty::TyEnum(_, substs) =>
- parameters_for_regions_in_substs(substs),
- ty::TyTrait(ref data) =>
- parameters_for_regions_in_substs(&data.principal.skip_binder().substs),
- ty::TyProjection(ref pi) =>
- parameters_for_regions_in_substs(&pi.trait_ref.substs),
- ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
- ty::TyFloat(..) | ty::TyBox(..) | ty::TyStr |
- ty::TyArray(..) | ty::TySlice(..) |
- ty::TyFnDef(..) | ty::TyFnPtr(_) |
- ty::TyTuple(..) | ty::TyRawPtr(..) |
- ty::TyInfer(..) | ty::TyClosure(..) | ty::TyError =>
- vec![]
- }
-}
+impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+ match t.sty {
+ ty::TyProjection(..) if !self.include_nonconstraining => {
+ // projections are not injective
+ return false;
+ }
+ ty::TyParam(ref d) => {
+ self.parameters.push(Parameter::Type(d.clone()));
+ }
+ _ => {}
+ }
-fn parameters_for_regions_in_substs(substs: &subst::Substs) -> Vec<Parameter> {
- substs.regions
- .iter()
- .filter_map(|r| parameters_for_region(r))
- .collect()
-}
+ t.super_visit_with(self)
+ }
-fn parameters_for_region(region: &ty::Region) -> Option<Parameter> {
- match *region {
- ty::ReEarlyBound(data) => Some(Parameter::Region(data)),
- _ => None,
+ fn visit_region(&mut self, r: ty::Region) -> bool {
+ match r {
+ ty::ReEarlyBound(data) => {
+ self.parameters.push(Parameter::Region(data));
+ }
+ _ => {}
+ }
+ false
}
}
// Then the projection only applies if `T` is known, but it still
// does not determine `U`.
- let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref, true);
+ let inputs = parameters_for(&projection.projection_ty.trait_ref, true);
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
if !relies_only_on_inputs {
continue;
}
- input_parameters.extend(parameters_for_type(projection.ty, false));
+ input_parameters.extend(parameters_for(&projection.ty, false));
} else {
continue;
}