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]
This commit is contained in:
parent
704f11d3d8
commit
8297edd549
4 changed files with 116 additions and 10 deletions
|
@ -13,6 +13,7 @@ use middle::freevars::freevar_entry;
|
|||
use middle::freevars;
|
||||
use middle::subst;
|
||||
use middle::ty;
|
||||
use middle::typeck::{MethodCall, NoAdjustment};
|
||||
use middle::typeck;
|
||||
use util::ppaux::{Repr, ty_to_str};
|
||||
use util::ppaux::UserString;
|
||||
|
@ -261,7 +262,15 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
|||
ExprCast(ref source, _) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, &**source);
|
||||
let target_ty = ty::expr_ty(cx.tcx, e);
|
||||
check_trait_cast(cx, source_ty, target_ty, source.span);
|
||||
let method_call = MethodCall {
|
||||
expr_id: e.id,
|
||||
adjustment: NoAdjustment,
|
||||
};
|
||||
check_trait_cast(cx,
|
||||
source_ty,
|
||||
target_ty,
|
||||
source.span,
|
||||
method_call);
|
||||
}
|
||||
ExprRepeat(ref element, ref count_expr) => {
|
||||
let count = ty::eval_repeat_count(cx.tcx, &**count_expr);
|
||||
|
@ -281,7 +290,15 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
|||
ty::AutoObject(..) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, e);
|
||||
let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
|
||||
check_trait_cast(cx, source_ty, target_ty, e.span);
|
||||
let method_call = MethodCall {
|
||||
expr_id: e.id,
|
||||
adjustment: typeck::AutoObject,
|
||||
};
|
||||
check_trait_cast(cx,
|
||||
source_ty,
|
||||
target_ty,
|
||||
e.span,
|
||||
method_call);
|
||||
}
|
||||
ty::AutoAddEnv(..) |
|
||||
ty::AutoDerefRef(..) => {}
|
||||
|
@ -364,15 +381,62 @@ fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
|
||||
fn check_type_parameter_bounds_in_vtable_result(
|
||||
cx: &mut Context,
|
||||
span: Span,
|
||||
vtable_res: &typeck::vtable_res) {
|
||||
for origins in vtable_res.iter() {
|
||||
for origin in origins.iter() {
|
||||
let (type_param_defs, substs) = match *origin {
|
||||
typeck::vtable_static(def_id, ref tys, _) => {
|
||||
let type_param_defs =
|
||||
ty::lookup_item_type(cx.tcx, def_id).generics
|
||||
.types
|
||||
.clone();
|
||||
(type_param_defs, (*tys).clone())
|
||||
}
|
||||
_ => {
|
||||
// Nothing to do here.
|
||||
continue
|
||||
}
|
||||
};
|
||||
for type_param_def in type_param_defs.iter() {
|
||||
let typ = substs.types.get(type_param_def.space,
|
||||
type_param_def.index);
|
||||
check_typaram_bounds(cx, span, *typ, type_param_def)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_cast(cx: &mut Context,
|
||||
source_ty: ty::t,
|
||||
target_ty: ty::t,
|
||||
span: Span,
|
||||
method_call: MethodCall) {
|
||||
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
|
||||
match ty::get(target_ty).sty {
|
||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => match ty::get(ty).sty {
|
||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
|
||||
match cx.tcx.vtable_map.borrow().find(&method_call) {
|
||||
None => {
|
||||
cx.tcx.sess.span_bug(span,
|
||||
"trait cast not in vtable \
|
||||
map?!")
|
||||
}
|
||||
Some(vtable_res) => {
|
||||
check_type_parameter_bounds_in_vtable_result(
|
||||
cx,
|
||||
span,
|
||||
vtable_res)
|
||||
}
|
||||
};
|
||||
check_trait_cast_bounds(cx, span, source_ty, bounds);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -398,6 +398,9 @@ fn search_for_vtable(vcx: &VtableContext,
|
|||
// Resolve any sub bounds. Note that there still may be free
|
||||
// type variables in substs. This might still be OK: the
|
||||
// process of looking up bounds might constrain some of them.
|
||||
//
|
||||
// This does not check built-in traits because those are handled
|
||||
// later in the kind checking pass.
|
||||
let im_generics =
|
||||
ty::lookup_item_type(tcx, impl_did).generics;
|
||||
let subres = lookup_vtables(vcx,
|
||||
|
|
|
@ -216,9 +216,9 @@ pub type vtable_res = VecPerParamSpace<vtable_param_res>;
|
|||
#[deriving(Clone)]
|
||||
pub enum vtable_origin {
|
||||
/*
|
||||
Statically known vtable. def_id gives the class or impl item
|
||||
Statically known vtable. def_id gives the impl item
|
||||
from whence comes the vtable, and tys are the type substs.
|
||||
vtable_res is the vtable itself
|
||||
vtable_res is the vtable itself.
|
||||
*/
|
||||
vtable_static(ast::DefId, subst::Substs, vtable_res),
|
||||
|
||||
|
|
39
src/test/compile-fail/kindck-impl-type-params.rs
Normal file
39
src/test/compile-fail/kindck-impl-type-params.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Issue #14061: tests the interaction between generic implementation
|
||||
// parameter bounds and trait objects.
|
||||
|
||||
struct S<T>;
|
||||
|
||||
trait Gettable<T> {}
|
||||
|
||||
impl<T: Send + Copy> Gettable<T> for S<T> {}
|
||||
|
||||
fn f<T>(val: T) {
|
||||
let t: S<T> = S;
|
||||
let a = &t as &Gettable<T>;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type `T`
|
||||
let a: &Gettable<T> = &t;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type `T`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let t: S<&int> = S;
|
||||
let a = &t as &Gettable<&int>;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type `&int`
|
||||
let t: Box<S<String>> = box S;
|
||||
let a = t as Box<Gettable<String>>;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type
|
||||
let t: Box<S<String>> = box S;
|
||||
let a: Box<Gettable<String>> = t;
|
||||
//~^ ERROR instantiating a type parameter with an incompatible type
|
||||
}
|
||||
|
Loading…
Reference in a new issue