Skip to content

Commit b683e87

Browse files
committed
Add check to ensure trait bounds are only placed o
Add check to ensure trait bounds are only placed on ty_param
1 parent 340ac04 commit b683e87

File tree

3 files changed

+59
-26
lines changed

3 files changed

+59
-26
lines changed

src/librustc_typeck/check/wf.rs

+36-3
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
8686
{
8787
let ccx = self.ccx;
8888
let item_def_id = local_def(item.id);
89-
let polytype = ty::lookup_item_type(ccx.tcx, item_def_id);
89+
let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id);
90+
reject_non_type_param_bounds(ccx.tcx, item.span, &type_scheme.generics);
9091
let param_env =
9192
ty::construct_parameter_environment(ccx.tcx,
92-
&polytype.generics,
93+
&type_scheme.generics,
9394
item.id);
9495
let inh = Inherited::new(ccx.tcx, param_env);
95-
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(polytype.ty), item.id);
96+
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id);
9697
f(self, &fcx);
9798
vtable::select_all_fcx_obligations_or_error(&fcx);
9899
regionck::regionck_item(&fcx, item);
@@ -143,10 +144,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
143144
item.span,
144145
region::CodeExtent::from_node_id(item.id),
145146
Some(&mut this.cache));
147+
146148
let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
147149
let item_ty = fcx.instantiate_type_scheme(item.span,
148150
&fcx.inh.param_env.free_substs,
149151
&type_scheme.ty);
152+
150153
bounds_checker.check_traits_in_ty(item_ty);
151154
});
152155
}
@@ -178,6 +181,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
178181
None => { return; }
179182
Some(t) => { t }
180183
};
184+
181185
let trait_ref = fcx.instantiate_type_scheme(item.span,
182186
&fcx.inh.param_env.free_substs,
183187
&trait_ref);
@@ -229,6 +233,35 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
229233
}
230234
}
231235

236+
// Reject any predicates that do not involve a type parameter.
237+
fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>,
238+
span: Span,
239+
generics: &ty::Generics<'tcx>) {
240+
for predicate in generics.predicates.iter() {
241+
match predicate {
242+
&ty::Predicate::Trait(ty::Binder(ref tr)) => {
243+
let self_ty = tr.self_ty();
244+
if !self_ty.walk().any(|t| is_ty_param(t)) {
245+
tcx.sess.span_err(
246+
span,
247+
format!("cannot bound type `{}`, where clause \
248+
bounds may only be attached to types involving \
249+
type parameters",
250+
self_ty.repr(tcx)).as_slice())
251+
}
252+
}
253+
_ => {}
254+
}
255+
}
256+
257+
fn is_ty_param(ty: ty::Ty) -> bool {
258+
match &ty.sty {
259+
&ty::sty::ty_param(_) => true,
260+
_ => false
261+
}
262+
}
263+
}
264+
232265
impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
233266
fn visit_item(&mut self, i: &ast::Item) {
234267
self.check_item_well_formed(i);

src/test/compile-fail/where-clauses-not-parameter.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,34 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
struct A;
11+
fn equal<T>(_: &T, _: &T) -> bool where int : Eq {
12+
true //~^ ERROR cannot bound type `int`, where clause bounds may only be attached
13+
}
14+
15+
// This should be fine involves a type parameter.
16+
fn test<T: Eq>() -> bool where Option<T> : Eq {}
17+
18+
// This should be rejected as well.
19+
fn test2() -> bool where Option<int> : Eq {}
1220

13-
trait U {}
21+
#[derive(PartialEq)]
22+
//~^ ERROR cannot bound type `int`, where clause bounds
23+
enum Foo<T> where int : Eq { MkFoo }
1424

15-
// impl U for A {}
25+
fn test3<T: Eq>() -> bool where Option<Foo<T>> : Eq {}
26+
27+
fn test4() -> bool where Option<Foo<int>> : Eq {}
28+
//~^ ERROR cannot bound type `core::option::Option<Foo<int>>`, where clause bounds
29+
30+
trait Baz<T> where int : Eq {
31+
fn baz() where String : Eq;
32+
}
1633

17-
fn equal<T>(_: &T, _: &T) -> bool where A : U {
18-
true
34+
impl Baz<int> for int where int : Eq {
35+
//~^ ERROR cannot bound type `int`, where clause bounds
36+
fn baz() where String : Eq {}
1937
}
2038

2139
fn main() {
2240
equal(&0i, &0i);
23-
//~^ ERROR the trait `U` is not implemented for the type `A`
2441
}

src/test/run-pass/where-clauses-not-parameter.rs

-17
This file was deleted.

0 commit comments

Comments
 (0)