Skip to content

Commit 8297edd

Browse files
pcwaltonalexcrichton
authored andcommitted
librustc: Have the kind checker check sub-bounds in trait casts.
This can break code that looked like: struct S<T> { val: T, } trait Gettable<T> { ... } impl<T: Copy> Gettable<T> for S<T> { ... } let t: Box<S<String>> = box S { val: "one".to_string(), }; let a = t as Box<Gettable<String>>; // ^ note no `Copy` bound Change this code to: impl<T> Gettable<T> for S<T> { // ^ remove `Copy` bound ... } Closes #14061. [breaking-change]
1 parent 704f11d commit 8297edd

File tree

4 files changed

+116
-10
lines changed

4 files changed

+116
-10
lines changed

src/librustc/middle/kind.rs

+72-8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use middle::freevars::freevar_entry;
1313
use middle::freevars;
1414
use middle::subst;
1515
use middle::ty;
16+
use middle::typeck::{MethodCall, NoAdjustment};
1617
use middle::typeck;
1718
use util::ppaux::{Repr, ty_to_str};
1819
use util::ppaux::UserString;
@@ -261,7 +262,15 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
261262
ExprCast(ref source, _) => {
262263
let source_ty = ty::expr_ty(cx.tcx, &**source);
263264
let target_ty = ty::expr_ty(cx.tcx, e);
264-
check_trait_cast(cx, source_ty, target_ty, source.span);
265+
let method_call = MethodCall {
266+
expr_id: e.id,
267+
adjustment: NoAdjustment,
268+
};
269+
check_trait_cast(cx,
270+
source_ty,
271+
target_ty,
272+
source.span,
273+
method_call);
265274
}
266275
ExprRepeat(ref element, ref count_expr) => {
267276
let count = ty::eval_repeat_count(cx.tcx, &**count_expr);
@@ -281,7 +290,15 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
281290
ty::AutoObject(..) => {
282291
let source_ty = ty::expr_ty(cx.tcx, e);
283292
let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
284-
check_trait_cast(cx, source_ty, target_ty, e.span);
293+
let method_call = MethodCall {
294+
expr_id: e.id,
295+
adjustment: typeck::AutoObject,
296+
};
297+
check_trait_cast(cx,
298+
source_ty,
299+
target_ty,
300+
e.span,
301+
method_call);
285302
}
286303
ty::AutoAddEnv(..) |
287304
ty::AutoDerefRef(..) => {}
@@ -364,15 +381,62 @@ fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
364381
}
365382
}
366383

367-
fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
384+
fn check_type_parameter_bounds_in_vtable_result(
385+
cx: &mut Context,
386+
span: Span,
387+
vtable_res: &typeck::vtable_res) {
388+
for origins in vtable_res.iter() {
389+
for origin in origins.iter() {
390+
let (type_param_defs, substs) = match *origin {
391+
typeck::vtable_static(def_id, ref tys, _) => {
392+
let type_param_defs =
393+
ty::lookup_item_type(cx.tcx, def_id).generics
394+
.types
395+
.clone();
396+
(type_param_defs, (*tys).clone())
397+
}
398+
_ => {
399+
// Nothing to do here.
400+
continue
401+
}
402+
};
403+
for type_param_def in type_param_defs.iter() {
404+
let typ = substs.types.get(type_param_def.space,
405+
type_param_def.index);
406+
check_typaram_bounds(cx, span, *typ, type_param_def)
407+
}
408+
}
409+
}
410+
}
411+
412+
fn check_trait_cast(cx: &mut Context,
413+
source_ty: ty::t,
414+
target_ty: ty::t,
415+
span: Span,
416+
method_call: MethodCall) {
368417
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
369418
match ty::get(target_ty).sty {
370-
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => match ty::get(ty).sty {
371-
ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
372-
check_trait_cast_bounds(cx, span, source_ty, bounds);
419+
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
420+
match ty::get(ty).sty {
421+
ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
422+
match cx.tcx.vtable_map.borrow().find(&method_call) {
423+
None => {
424+
cx.tcx.sess.span_bug(span,
425+
"trait cast not in vtable \
426+
map?!")
427+
}
428+
Some(vtable_res) => {
429+
check_type_parameter_bounds_in_vtable_result(
430+
cx,
431+
span,
432+
vtable_res)
433+
}
434+
};
435+
check_trait_cast_bounds(cx, span, source_ty, bounds);
436+
}
437+
_ => {}
373438
}
374-
_ => {}
375-
},
439+
}
376440
_ => {}
377441
}
378442
}

src/librustc/middle/typeck/check/vtable.rs

+3
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,9 @@ fn search_for_vtable(vcx: &VtableContext,
398398
// Resolve any sub bounds. Note that there still may be free
399399
// type variables in substs. This might still be OK: the
400400
// process of looking up bounds might constrain some of them.
401+
//
402+
// This does not check built-in traits because those are handled
403+
// later in the kind checking pass.
401404
let im_generics =
402405
ty::lookup_item_type(tcx, impl_did).generics;
403406
let subres = lookup_vtables(vcx,

src/librustc/middle/typeck/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,9 @@ pub type vtable_res = VecPerParamSpace<vtable_param_res>;
216216
#[deriving(Clone)]
217217
pub enum vtable_origin {
218218
/*
219-
Statically known vtable. def_id gives the class or impl item
219+
Statically known vtable. def_id gives the impl item
220220
from whence comes the vtable, and tys are the type substs.
221-
vtable_res is the vtable itself
221+
vtable_res is the vtable itself.
222222
*/
223223
vtable_static(ast::DefId, subst::Substs, vtable_res),
224224

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Issue #14061: tests the interaction between generic implementation
12+
// parameter bounds and trait objects.
13+
14+
struct S<T>;
15+
16+
trait Gettable<T> {}
17+
18+
impl<T: Send + Copy> Gettable<T> for S<T> {}
19+
20+
fn f<T>(val: T) {
21+
let t: S<T> = S;
22+
let a = &t as &Gettable<T>;
23+
//~^ ERROR instantiating a type parameter with an incompatible type `T`
24+
let a: &Gettable<T> = &t;
25+
//~^ ERROR instantiating a type parameter with an incompatible type `T`
26+
}
27+
28+
fn main() {
29+
let t: S<&int> = S;
30+
let a = &t as &Gettable<&int>;
31+
//~^ ERROR instantiating a type parameter with an incompatible type `&int`
32+
let t: Box<S<String>> = box S;
33+
let a = t as Box<Gettable<String>>;
34+
//~^ ERROR instantiating a type parameter with an incompatible type
35+
let t: Box<S<String>> = box S;
36+
let a: Box<Gettable<String>> = t;
37+
//~^ ERROR instantiating a type parameter with an incompatible type
38+
}
39+

0 commit comments

Comments
 (0)