Skip to content

librustc: Have the kind checker check sub-bounds in trait casts. #15352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 72 additions & 8 deletions src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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(..) => {}
Expand Down Expand Up @@ -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_trait(box ty::TyTrait { bounds, .. }) => {
check_trait_cast_bounds(cx, span, source_ty, bounds);
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) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block would be better off in its own function

check_type_parameter_bounds_in_vtable_result(
cx,
span,
vtable_res)
}
};
check_trait_cast_bounds(cx, span, source_ty, bounds);
}
_ => {}
}
_ => {}
},
}
_ => {}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/typeck/check/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/typeck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),

Expand Down
39 changes: 39 additions & 0 deletions src/test/compile-fail/kindck-impl-type-params.rs
Original file line number Diff line number Diff line change
@@ -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
}