diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 81633316671..a7154e78bc5 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -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_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) => { + check_type_parameter_bounds_in_vtable_result( + cx, + span, + vtable_res) + } + }; + check_trait_cast_bounds(cx, span, source_ty, bounds); + } + _ => {} } - _ => {} - }, + } _ => {} } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 33e0d0331be..bda47d99ed7 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -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, diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index e159d0d00c8..7b6935df420 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -216,9 +216,9 @@ pub type vtable_res = VecPerParamSpace; #[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), diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs new file mode 100644 index 00000000000..48e1bdd671a --- /dev/null +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -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 or the MIT license +// , 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; + +trait Gettable {} + +impl Gettable for S {} + +fn f(val: T) { + let t: S = S; + let a = &t as &Gettable; + //~^ ERROR instantiating a type parameter with an incompatible type `T` + let a: &Gettable = &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> = box S; + let a = t as Box>; + //~^ ERROR instantiating a type parameter with an incompatible type + let t: Box> = box S; + let a: Box> = t; + //~^ ERROR instantiating a type parameter with an incompatible type +} +