Skip to content

Commit 83b2b14

Browse files
committed
Rewrite constrained type params code to operate generically over
multiple kinds of parameters (regions and types, specifically)
1 parent a53d674 commit 83b2b14

File tree

3 files changed

+90
-39
lines changed

3 files changed

+90
-39
lines changed

src/librustc_typeck/check/wf.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use astconv::AstConv;
1212
use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck};
13-
use constrained_type_params::identify_constrained_type_params;
13+
use constrained_type_params::{identify_constrained_type_params, Parameter};
1414
use CrateCtxt;
1515
use middle::region;
1616
use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
@@ -287,10 +287,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
287287

288288
let mut constrained_parameters: HashSet<_> =
289289
variances.types
290-
.iter_enumerated()
291-
.filter(|&(_, _, &variance)| variance != ty::Bivariant)
292-
.map(|(space, index, _)| self.param_ty(ast_generics, space, index))
293-
.collect();
290+
.iter_enumerated()
291+
.filter(|&(_, _, &variance)| variance != ty::Bivariant)
292+
.map(|(space, index, _)| self.param_ty(ast_generics, space, index))
293+
.map(|p| Parameter::Type(p))
294+
.collect();
294295

295296
identify_constrained_type_params(self.tcx(),
296297
ty_predicates.predicates.as_slice(),
@@ -299,7 +300,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
299300

300301
for (space, index, _) in variances.types.iter_enumerated() {
301302
let param_ty = self.param_ty(ast_generics, space, index);
302-
if constrained_parameters.contains(&param_ty) {
303+
if constrained_parameters.contains(&Parameter::Type(param_ty)) {
303304
continue;
304305
}
305306
let span = self.ty_param_span(ast_generics, item, space, index);

src/librustc_typeck/collect.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ There are some shortcomings in this design:
6666

6767
use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
6868
use middle::def;
69-
use constrained_type_params::identify_constrained_type_params;
69+
use constrained_type_params as ctp;
7070
use middle::lang_items::SizedTraitLangItem;
7171
use middle::region;
7272
use middle::resolve_lifetime;
@@ -2200,23 +2200,21 @@ fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
22002200
// reachable from there, to start (if this is an inherent impl,
22012201
// then just examine the self type).
22022202
let mut input_parameters: HashSet<_> =
2203-
impl_trait_ref.iter()
2204-
.flat_map(|t| t.input_types().iter()) // Types in trait ref, if any
2205-
.chain(Some(impl_scheme.ty).iter()) // Self type, always
2206-
.flat_map(|t| t.walk())
2207-
.filter_map(|t| t.as_opt_param_ty())
2208-
.collect();
2209-
2210-
identify_constrained_type_params(tcx,
2211-
impl_predicates.predicates.as_slice(),
2212-
impl_trait_ref,
2213-
&mut input_parameters);
2203+
ctp::parameters_for_type(impl_scheme.ty).into_iter().collect();
2204+
if let Some(ref trait_ref) = impl_trait_ref {
2205+
input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref));
2206+
}
2207+
2208+
ctp::identify_constrained_type_params(tcx,
2209+
impl_predicates.predicates.as_slice(),
2210+
impl_trait_ref,
2211+
&mut input_parameters);
22142212

22152213
for (index, ty_param) in ast_generics.ty_params.iter().enumerate() {
22162214
let param_ty = ty::ParamTy { space: TypeSpace,
22172215
idx: index as u32,
22182216
name: ty_param.ident.name };
2219-
if !input_parameters.contains(&param_ty) {
2217+
if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) {
22202218
span_err!(tcx.sess, ty_param.span, E0207,
22212219
"the type parameter `{}` is not constrained by the \
22222220
impl trait, self type, or predicates",

src/librustc_typeck/constrained_type_params.rs

+72-20
Original file line numberDiff line numberDiff line change
@@ -8,49 +8,101 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use middle::ty::{self};
11+
use middle::subst;
12+
use middle::ty::{self, Ty};
1213

1314
use std::collections::HashSet;
1415
use std::rc::Rc;
1516

17+
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
18+
pub enum Parameter {
19+
Type(ty::ParamTy),
20+
Region(ty::EarlyBoundRegion),
21+
}
22+
23+
pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
24+
ty.walk()
25+
.flat_map(|ty| parameters_for_type_shallow(ty).into_iter())
26+
.collect()
27+
}
28+
29+
pub fn parameters_for_trait_ref<'tcx>(trait_ref: &Rc<ty::TraitRef<'tcx>>) -> Vec<Parameter> {
30+
let mut region_parameters =
31+
parameters_for_regions_in_substs(&trait_ref.substs);
32+
33+
let type_parameters =
34+
trait_ref.substs.types.iter()
35+
.flat_map(|ty| parameters_for_type(ty).into_iter());
36+
37+
region_parameters.extend(type_parameters);
38+
39+
region_parameters
40+
}
41+
42+
fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
43+
match ty.sty {
44+
ty::ty_param(ref d) =>
45+
vec![Parameter::Type(d.clone())],
46+
ty::ty_rptr(region, _) =>
47+
parameters_for_region(region).into_iter().collect(),
48+
ty::ty_struct(_, substs) |
49+
ty::ty_enum(_, substs) =>
50+
parameters_for_regions_in_substs(substs),
51+
ty::ty_trait(ref data) =>
52+
parameters_for_regions_in_substs(&data.principal.skip_binder().substs),
53+
_ =>
54+
vec![],
55+
}
56+
}
57+
58+
fn parameters_for_regions_in_substs(substs: &subst::Substs) -> Vec<Parameter> {
59+
substs.regions()
60+
.iter()
61+
.filter_map(|r| parameters_for_region(r))
62+
.collect()
63+
}
64+
65+
fn parameters_for_region(region: &ty::Region) -> Option<Parameter> {
66+
match *region {
67+
ty::ReEarlyBound(data) => Some(Parameter::Region(data)),
68+
_ => None,
69+
}
70+
}
71+
1672
pub fn identify_constrained_type_params<'tcx>(_tcx: &ty::ctxt<'tcx>,
1773
predicates: &[ty::Predicate<'tcx>],
1874
impl_trait_ref: Option<Rc<ty::TraitRef<'tcx>>>,
19-
input_parameters: &mut HashSet<ty::ParamTy>)
75+
input_parameters: &mut HashSet<Parameter>)
2076
{
2177
loop {
2278
let num_inputs = input_parameters.len();
2379

24-
let projection_predicates =
80+
let poly_projection_predicates = // : iterator over PolyProjectionPredicate
2581
predicates.iter()
2682
.filter_map(|predicate| {
2783
match *predicate {
28-
// Ignore higher-ranked binders. For the purposes
29-
// of this check, they don't matter because they
30-
// only affect named regions, and we're just
31-
// concerned about type parameters here.
32-
ty::Predicate::Projection(ref data) => Some(data.0.clone()),
84+
ty::Predicate::Projection(ref data) => Some(data.clone()),
3385
_ => None,
3486
}
3587
});
3688

37-
for projection in projection_predicates {
89+
for poly_projection in poly_projection_predicates {
90+
// Note that we can skip binder here because the impl
91+
// trait ref never contains any late-bound regions.
92+
let projection = poly_projection.skip_binder();
93+
3894
// Special case: watch out for some kind of sneaky attempt
39-
// to project out an associated type defined by this very trait.
40-
if Some(projection.projection_ty.trait_ref.clone()) == impl_trait_ref {
95+
// to project out an associated type defined by this very
96+
// trait.
97+
let unbound_trait_ref = &projection.projection_ty.trait_ref;
98+
if Some(unbound_trait_ref.clone()) == impl_trait_ref {
4199
continue;
42100
}
43101

44-
let relies_only_on_inputs =
45-
projection.projection_ty.trait_ref.input_types()
46-
.iter()
47-
.flat_map(|t| t.walk())
48-
.filter_map(|t| t.as_opt_param_ty())
49-
.all(|t| input_parameters.contains(&t));
50-
102+
let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref);
103+
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
51104
if relies_only_on_inputs {
52-
input_parameters.extend(
53-
projection.ty.walk().filter_map(|t| t.as_opt_param_ty()));
105+
input_parameters.extend(parameters_for_type(projection.ty));
54106
}
55107
}
56108

0 commit comments

Comments
 (0)