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::freevars;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
use middle::typeck::{MethodCall, NoAdjustment};
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
use util::ppaux::{Repr, ty_to_str};
|
use util::ppaux::{Repr, ty_to_str};
|
||||||
use util::ppaux::UserString;
|
use util::ppaux::UserString;
|
||||||
|
@ -261,7 +262,15 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
||||||
ExprCast(ref source, _) => {
|
ExprCast(ref source, _) => {
|
||||||
let source_ty = ty::expr_ty(cx.tcx, &**source);
|
let source_ty = ty::expr_ty(cx.tcx, &**source);
|
||||||
let target_ty = ty::expr_ty(cx.tcx, e);
|
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) => {
|
ExprRepeat(ref element, ref count_expr) => {
|
||||||
let count = ty::eval_repeat_count(cx.tcx, &**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(..) => {
|
ty::AutoObject(..) => {
|
||||||
let source_ty = ty::expr_ty(cx.tcx, e);
|
let source_ty = ty::expr_ty(cx.tcx, e);
|
||||||
let target_ty = ty::expr_ty_adjusted(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::AutoAddEnv(..) |
|
||||||
ty::AutoDerefRef(..) => {}
|
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);
|
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
|
||||||
match ty::get(target_ty).sty {
|
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, .. }) => {
|
||||||
ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
|
match ty::get(ty).sty {
|
||||||
check_trait_cast_bounds(cx, span, source_ty, bounds);
|
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
|
// Resolve any sub bounds. Note that there still may be free
|
||||||
// type variables in substs. This might still be OK: the
|
// type variables in substs. This might still be OK: the
|
||||||
// process of looking up bounds might constrain some of them.
|
// 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 =
|
let im_generics =
|
||||||
ty::lookup_item_type(tcx, impl_did).generics;
|
ty::lookup_item_type(tcx, impl_did).generics;
|
||||||
let subres = lookup_vtables(vcx,
|
let subres = lookup_vtables(vcx,
|
||||||
|
|
|
@ -216,9 +216,9 @@ pub type vtable_res = VecPerParamSpace<vtable_param_res>;
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub enum vtable_origin {
|
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.
|
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),
|
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