diff --git a/mk/crates.mk b/mk/crates.mk index c0fd04401bcda..0011a7245e56d 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -59,7 +59,7 @@ CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc DEPS_core := -DEPS_rlibc := +DEPS_rlibc := core DEPS_unicode := core DEPS_alloc := core libc native:jemalloc DEPS_debug := std diff --git a/src/doc/guide-unsafe.md b/src/doc/guide-unsafe.md index a95401682cf0d..8c67634d57aec 100644 --- a/src/doc/guide-unsafe.md +++ b/src/doc/guide-unsafe.md @@ -461,11 +461,12 @@ fn start(_argc: int, _argv: *const *const u8) -> int { 0 } -// These functions are invoked by the compiler, but not +// These functions and traits are used by the compiler, but not // for a bare-bones hello world. These are normally // provided by libstd. #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "sized"] trait Sized { } # // fn main() {} tricked you, rustdoc! ``` @@ -488,13 +489,14 @@ pub extern fn main(argc: int, argv: *const *const u8) -> int { #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "sized"] trait Sized { } # // fn main() {} tricked you, rustdoc! ``` The compiler currently makes a few assumptions about symbols which are available in the executable to call. Normally these functions are provided by the standard -library, but without it you must define your own. +xlibrary, but without it you must define your own. The first of these two functions, `stack_exhausted`, is invoked whenever stack overflow is detected. This function has a number of restrictions about how it @@ -508,6 +510,12 @@ mechanisms of the compiler. This is often mapped to GCC's personality function information), but crates which do not trigger failure can be assured that this function is never called. +The final item in the example is a trait called `Sized`. This a trait +that represents data of a known static size: it is integral to the +Rust type system, and so the compiler expects the standard library to +provide it. Since you are not using the standard library, you have to +provide it yourself. + ## Using libcore > **Note**: the core library's structure is unstable, and it is recommended to @@ -686,6 +694,7 @@ fn main(argc: int, argv: *const *const u8) -> int { #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "sized"] trait Sized {} ``` Note the use of `abort`: the `exchange_malloc` lang item is assumed to diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index c7bc1bb973330..0dc62e7363447 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -255,7 +255,6 @@ mod imp { #[cfg(not(jemalloc), unix)] mod imp { use core::cmp; - use core::mem; use core::ptr; use libc; use libc_heap; diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs index 2ab7a6c52fac3..c24a7e9ca77d1 100644 --- a/src/librlibc/lib.rs +++ b/src/librlibc/lib.rs @@ -35,12 +35,13 @@ // LLVM to optimize these function calls to themselves! #![no_builtins] +#[phase(plugin, link)] extern crate core; + #[cfg(test)] extern crate native; #[cfg(test)] extern crate test; #[cfg(test)] extern crate debug; #[cfg(test)] #[phase(plugin, link)] extern crate std; -#[cfg(test)] #[phase(plugin, link)] extern crate core; // Require the offset intrinsics for LLVM to properly optimize the // implementations below. If pointer arithmetic is done through integers the diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index fd643a70c7b95..af3d19c4d2d40 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -108,6 +108,7 @@ pub mod middle { pub mod save; pub mod stability; pub mod subst; + pub mod traits; pub mod trans; pub mod ty; pub mod ty_fold; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 58c05bee44373..eed41edac9d6c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1470,17 +1470,17 @@ impl LintPass for Stability { def_id } typeck::MethodParam(typeck::MethodParam { - trait_id: trait_id, + trait_ref: ref trait_ref, method_num: index, .. - }) - | typeck::MethodObject(typeck::MethodObject { - trait_id: trait_id, + }) | + typeck::MethodObject(typeck::MethodObject { + trait_ref: ref trait_ref, method_num: index, .. }) => { match ty::trait_item(cx.tcx, - trait_id, + trait_ref.def_id, index) { ty::MethodTraitItem(method) => { method.def_id diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index ca2f47328db90..3ec91bf984052 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -140,9 +140,10 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f tag_table_unboxed_closures = 0x54, tag_table_upvar_borrow_map = 0x55, tag_table_capture_modes = 0x56, + tag_table_object_cast_map = 0x57, } static first_astencode_tag: uint = tag_ast as uint; -static last_astencode_tag: uint = tag_table_capture_modes as uint; +static last_astencode_tag: uint = tag_table_object_cast_map as uint; impl astencode_tag { pub fn from_uint(value : uint) -> Option { let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 376cccc3f10fc..3ab50b0efd17c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -20,9 +20,7 @@ use metadata::cstore; use metadata::decoder; use metadata::tyencode; use middle::ty::{lookup_item_type}; -use middle::astencode; use middle::ty; -use middle::typeck; use middle::stability; use middle; use util::nodemap::{NodeMap, NodeSet}; @@ -125,14 +123,6 @@ fn encode_trait_ref(rbml_w: &mut Encoder, rbml_w.end_tag(); } -fn encode_impl_vtables(rbml_w: &mut Encoder, - ecx: &EncodeContext, - vtables: &typeck::vtable_res) { - rbml_w.start_tag(tag_item_impl_vtables); - astencode::encode_vtable_res(ecx, rbml_w, vtables); - rbml_w.end_tag(); -} - // Item info table encoding fn encode_family(rbml_w: &mut Encoder, c: char) { rbml_w.start_tag(tag_items_data_item_family); @@ -191,6 +181,18 @@ pub fn write_type(ecx: &EncodeContext, tyencode::enc_ty(rbml_w.writer, ty_str_ctxt, typ); } +pub fn write_trait_ref(ecx: &EncodeContext, + rbml_w: &mut Encoder, + trait_ref: &ty::TraitRef) { + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + tyencode::enc_trait_ref(rbml_w.writer, ty_str_ctxt, trait_ref); +} + pub fn write_region(ecx: &EncodeContext, rbml_w: &mut Encoder, r: ty::Region) { @@ -399,7 +401,7 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext, let impl_items = ecx.tcx.impl_items.borrow(); match ecx.tcx.inherent_impls.borrow().find(&exp.def_id) { Some(implementations) => { - for base_impl_did in implementations.borrow().iter() { + for base_impl_did in implementations.iter() { for &method_did in impl_items.get(base_impl_did).iter() { let impl_item = ty::impl_or_trait_item( ecx.tcx, @@ -946,7 +948,7 @@ fn encode_inherent_implementations(ecx: &EncodeContext, match ecx.tcx.inherent_impls.borrow().find(&def_id) { None => {} Some(implementations) => { - for &impl_def_id in implementations.borrow().iter() { + for &impl_def_id in implementations.iter() { rbml_w.start_tag(tag_items_data_item_inherent_impl); encode_def_id(rbml_w, impl_def_id); rbml_w.end_tag(); @@ -1203,8 +1205,6 @@ fn encode_info_for_item(ecx: &EncodeContext, let trait_ref = ty::node_id_to_trait_ref( tcx, ast_trait_ref.ref_id); encode_trait_ref(rbml_w, ecx, &*trait_ref, tag_item_trait_ref); - let impl_vtables = ty::lookup_impl_vtables(tcx, def_id); - encode_impl_vtables(rbml_w, ecx, &impl_vtables); } encode_path(rbml_w, path.clone()); encode_stability(rbml_w, stab); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 2dab3c2b1da02..21d0292d2fe3a 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -43,6 +43,7 @@ use libc; use std::io::Seek; use std::mem; use std::gc::GC; +use std::rc::Rc; use rbml::io::SeekableMemWriter; use rbml::{reader, writer}; @@ -589,7 +590,7 @@ fn encode_method_callee(ecx: &e::EncodeContext, adjustment.encode(rbml_w) }); rbml_w.emit_struct_field("origin", 1u, |rbml_w| { - method.origin.encode(rbml_w) + Ok(rbml_w.emit_method_origin(ecx, &method.origin)) }); rbml_w.emit_struct_field("ty", 2u, |rbml_w| { Ok(rbml_w.emit_ty(ecx, method.ty)) @@ -610,9 +611,7 @@ impl<'a> read_method_callee_helper for reader::Decoder<'a> { }).unwrap(); Ok((adjustment, MethodCallee { origin: this.read_struct_field("origin", 1, |this| { - let method_origin: MethodOrigin = - Decodable::decode(this).unwrap(); - Ok(method_origin.tr(dcx)) + Ok(this.read_method_origin(dcx)) }).unwrap(), ty: this.read_struct_field("ty", 2, |this| { Ok(this.read_ty(dcx)) @@ -635,15 +634,16 @@ impl tr for MethodOrigin { typeck::MethodParam(ref mp) => { typeck::MethodParam( typeck::MethodParam { - trait_id: mp.trait_id.tr(dcx), - .. *mp + // def-id is already translated when we read it out + trait_ref: mp.trait_ref.clone(), + method_num: mp.method_num, } ) } typeck::MethodObject(ref mo) => { typeck::MethodObject( typeck::MethodObject { - trait_id: mo.trait_id.tr(dcx), + trait_ref: mo.trait_ref.clone(), .. *mo } ) @@ -655,22 +655,6 @@ impl tr for MethodOrigin { // ______________________________________________________________________ // Encoding and decoding vtable_res -fn encode_vtable_res_with_key(ecx: &e::EncodeContext, - rbml_w: &mut Encoder, - adjustment: typeck::ExprAdjustment, - dr: &typeck::vtable_res) { - use serialize::Encoder; - - rbml_w.emit_struct("VtableWithKey", 2, |rbml_w| { - rbml_w.emit_struct_field("adjustment", 0u, |rbml_w| { - adjustment.encode(rbml_w) - }); - rbml_w.emit_struct_field("vtable_res", 1u, |rbml_w| { - Ok(encode_vtable_res(ecx, rbml_w, dr)) - }) - }).unwrap() -} - pub fn encode_vtable_res(ecx: &e::EncodeContext, rbml_w: &mut Encoder, dr: &typeck::vtable_res) { @@ -913,11 +897,15 @@ trait rbml_writer_helpers { fn emit_closure_type(&mut self, ecx: &e::EncodeContext, closure_type: &ty::ClosureTy); + fn emit_method_origin(&mut self, + ecx: &e::EncodeContext, + method_origin: &typeck::MethodOrigin); fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t); fn emit_tys(&mut self, ecx: &e::EncodeContext, tys: &[ty::t]); fn emit_type_param_def(&mut self, ecx: &e::EncodeContext, type_param_def: &ty::TypeParameterDef); + fn emit_trait_ref(&mut self, ecx: &e::EncodeContext, ty: &ty::TraitRef); fn emit_polytype(&mut self, ecx: &e::EncodeContext, pty: ty::Polytype); @@ -939,6 +927,63 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { }); } + fn emit_method_origin(&mut self, + ecx: &e::EncodeContext, + method_origin: &typeck::MethodOrigin) + { + use serialize::Encoder; + + self.emit_enum("MethodOrigin", |this| { + match *method_origin { + typeck::MethodStatic(def_id) => { + this.emit_enum_variant("MethodStatic", 0, 1, |this| { + Ok(this.emit_def_id(def_id)) + }) + } + + typeck::MethodStaticUnboxedClosure(def_id) => { + this.emit_enum_variant("MethodStaticUnboxedClosure", 1, 1, |this| { + Ok(this.emit_def_id(def_id)) + }) + } + + typeck::MethodParam(ref p) => { + this.emit_enum_variant("MethodParam", 2, 1, |this| { + this.emit_struct("MethodParam", 2, |this| { + try!(this.emit_struct_field("trait_ref", 0, |this| { + Ok(this.emit_trait_ref(ecx, &*p.trait_ref)) + })); + try!(this.emit_struct_field("method_num", 0, |this| { + this.emit_uint(p.method_num) + })); + Ok(()) + }) + }) + } + + typeck::MethodObject(ref o) => { + this.emit_enum_variant("MethodObject", 3, 1, |this| { + this.emit_struct("MethodObject", 2, |this| { + try!(this.emit_struct_field("trait_ref", 0, |this| { + Ok(this.emit_trait_ref(ecx, &*o.trait_ref)) + })); + try!(this.emit_struct_field("object_trait_id", 0, |this| { + Ok(this.emit_def_id(o.object_trait_id)) + })); + try!(this.emit_struct_field("method_num", 0, |this| { + this.emit_uint(o.method_num) + })); + try!(this.emit_struct_field("real_index", 0, |this| { + this.emit_uint(o.real_index) + })); + Ok(()) + }) + }) + } + } + }); + } + fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t) { self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty))); } @@ -947,6 +992,12 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { self.emit_from_vec(tys, |this, ty| Ok(this.emit_ty(ecx, *ty))); } + fn emit_trait_ref(&mut self, + ecx: &e::EncodeContext, + trait_ref: &ty::TraitRef) { + self.emit_opaque(|this| Ok(e::write_trait_ref(ecx, this, trait_ref))); + } + fn emit_type_param_def(&mut self, ecx: &e::EncodeContext, type_param_def: &ty::TypeParameterDef) { @@ -1103,12 +1154,16 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { this.emit_enum_variant_arg(1, |this| idx.encode(this)) }) } - ty::UnsizeVtable(ref b, def_id, ref substs) => { - this.emit_enum_variant("UnsizeVtable", 2, 3, |this| { + ty::UnsizeVtable(ty::TyTrait { def_id: def_id, + bounds: ref b, + substs: ref substs }, + self_ty) => { + this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { this.emit_enum_variant_arg( 0, |this| Ok(this.emit_existential_bounds(ecx, b))); this.emit_enum_variant_arg(1, |this| def_id.encode(this)); - this.emit_enum_variant_arg(2, |this| Ok(this.emit_substs(ecx, substs))) + this.emit_enum_variant_arg(2, |this| Ok(this.emit_ty(ecx, self_ty))); + this.emit_enum_variant_arg(3, |this| Ok(this.emit_substs(ecx, substs))) }) } } @@ -1282,11 +1337,11 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) } - for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { + for &trait_ref in tcx.object_cast_map.borrow().find(&id).iter() { + rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| { rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr); + rbml_w.emit_trait_ref(ecx, &**trait_ref); }) }) } @@ -1303,15 +1358,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) }) } - - for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { - rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr); - }) - }) - } } ty::AutoDerefRef(ref adj) => { assert!(!ty::adjust_is_object(adjustment)); @@ -1326,16 +1372,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) }) } - - for &dr in tcx.vtable_map.borrow().find(&method_call).iter() { - rbml_w.tag(c::tag_table_vtable_map, |rbml_w| { - rbml_w.id(id); - rbml_w.tag(c::tag_table_val, |rbml_w| { - encode_vtable_res_with_key(ecx, rbml_w, - method_call.adjustment, dr); - }) - }) - } } } _ => { @@ -1378,8 +1414,10 @@ impl<'a> doc_decoder_helpers for rbml::Doc<'a> { } trait rbml_decoder_decoder_helpers { + fn read_method_origin(&mut self, dcx: &DecodeContext) -> typeck::MethodOrigin; fn read_ty(&mut self, dcx: &DecodeContext) -> ty::t; fn read_tys(&mut self, dcx: &DecodeContext) -> Vec; + fn read_trait_ref(&mut self, dcx: &DecodeContext) -> Rc; fn read_type_param_def(&mut self, dcx: &DecodeContext) -> ty::TypeParameterDef; fn read_polytype(&mut self, dcx: &DecodeContext) @@ -1447,6 +1485,77 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { }).unwrap() } + fn read_method_origin(&mut self, dcx: &DecodeContext) + -> typeck::MethodOrigin + { + self.read_enum("MethodOrigin", |this| { + let variants = ["MethodStatic", "MethodStaticUnboxedClosure", + "MethodParam", "MethodObject"]; + this.read_enum_variant(variants, |this, i| { + Ok(match i { + 0 => { + let def_id = this.read_def_id(dcx); + typeck::MethodStatic(def_id) + } + + 1 => { + let def_id = this.read_def_id(dcx); + typeck::MethodStaticUnboxedClosure(def_id) + } + + 2 => { + this.read_struct("MethodParam", 2, |this| { + Ok(typeck::MethodParam( + typeck::MethodParam { + trait_ref: { + this.read_struct_field("trait_ref", 0, |this| { + Ok(this.read_trait_ref(dcx)) + }).unwrap() + }, + method_num: { + this.read_struct_field("method_num", 1, |this| { + this.read_uint() + }).unwrap() + } + })) + }).unwrap() + } + + 3 => { + this.read_struct("MethodObject", 2, |this| { + Ok(typeck::MethodObject( + typeck::MethodObject { + trait_ref: { + this.read_struct_field("trait_ref", 0, |this| { + Ok(this.read_trait_ref(dcx)) + }).unwrap() + }, + object_trait_id: { + this.read_struct_field("object_trait_id", 1, |this| { + Ok(this.read_def_id(dcx)) + }).unwrap() + }, + method_num: { + this.read_struct_field("method_num", 2, |this| { + this.read_uint() + }).unwrap() + }, + real_index: { + this.read_struct_field("real_index", 3, |this| { + this.read_uint() + }).unwrap() + }, + })) + }).unwrap() + } + + _ => fail!("..") + }) + }) + }).unwrap() + } + + fn read_ty(&mut self, dcx: &DecodeContext) -> ty::t { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode @@ -1479,6 +1588,18 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { self.read_to_vec(|this| Ok(this.read_ty(dcx))).unwrap().move_iter().collect() } + fn read_trait_ref(&mut self, dcx: &DecodeContext) -> Rc { + Rc::new(self.read_opaque(|this, doc| { + let ty = tydecode::parse_trait_ref_data( + doc.data, + dcx.cdata.cnum, + doc.start, + dcx.tcx, + |s, a| this.convert_def_id(dcx, s, a)); + Ok(ty) + }).unwrap()) + } + fn read_type_param_def(&mut self, dcx: &DecodeContext) -> ty::TypeParameterDef { self.read_opaque(|this, doc| { @@ -1667,10 +1788,14 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { 0, |this| Ok(this.read_existential_bounds(dcx))).unwrap(); let def_id: ast::DefId = this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); - let substs = this.read_enum_variant_arg(2, + let self_ty = + this.read_enum_variant_arg(2, |this| Ok(this.read_ty(dcx))).unwrap(); + let substs = this.read_enum_variant_arg(3, |this| Ok(this.read_substs(dcx))).unwrap(); - - ty::UnsizeVtable(b, def_id.tr(dcx), substs) + let ty_trait = ty::TyTrait { def_id: def_id.tr(dcx), + bounds: b, + substs: substs }; + ty::UnsizeVtable(ty_trait, self_ty) } _ => fail!("bad enum variant for ty::UnsizeKind") }) @@ -1828,15 +1953,10 @@ fn decode_side_tables(dcx: &DecodeContext, }; dcx.tcx.method_map.borrow_mut().insert(method_call, method); } - c::tag_table_vtable_map => { - let (adjustment, vtable_res) = - val_dsr.read_vtable_res_with_key(dcx.tcx, - dcx.cdata); - let vtable_key = MethodCall { - expr_id: id, - adjustment: adjustment - }; - dcx.tcx.vtable_map.borrow_mut().insert(vtable_key, vtable_res); + c::tag_table_object_cast_map => { + let trait_ref = val_dsr.read_trait_ref(dcx); + dcx.tcx.object_cast_map.borrow_mut() + .insert(id, trait_ref); } c::tag_table_adjustments => { let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(dcx); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 46e3585912a7f..f13c6bc3336fc 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -102,17 +102,17 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } typeck::MethodStaticUnboxedClosure(_) => {} typeck::MethodParam(typeck::MethodParam { - trait_id: trait_id, + trait_ref: ref trait_ref, method_num: index, .. - }) - | typeck::MethodObject(typeck::MethodObject { - trait_id: trait_id, + }) | + typeck::MethodObject(typeck::MethodObject { + trait_ref: ref trait_ref, method_num: index, .. }) => { let trait_item = ty::trait_item(self.tcx, - trait_id, + trait_ref.def_id, index); match trait_item { ty::MethodTraitItem(method) => { @@ -470,7 +470,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { match self.tcx.inherent_impls.borrow().find(&local_def(id)) { None => (), Some(impl_list) => { - for impl_did in impl_list.borrow().iter() { + for impl_did in impl_list.iter() { for item_did in impl_items.get(impl_did).iter() { if self.live_symbols.contains(&item_did.def_id() .node) { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 1e79ea68eebac..d6c11caefe84b 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -174,11 +174,9 @@ impl OverloadedCallType { MethodStaticUnboxedClosure(def_id) => { OverloadedCallType::from_unboxed_closure(tcx, def_id) } - MethodParam(ref method_param) => { - OverloadedCallType::from_trait_id(tcx, method_param.trait_id) - } - MethodObject(ref method_object) => { - OverloadedCallType::from_trait_id(tcx, method_object.trait_id) + MethodParam(MethodParam { trait_ref: ref trait_ref, .. }) | + MethodObject(MethodObject { trait_ref: ref trait_ref, .. }) => { + OverloadedCallType::from_trait_id(tcx, trait_ref.def_id) } } } diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 33f7680d873c3..aeb0c155a3f48 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -10,50 +10,30 @@ use middle::freevars::freevar_entry; use middle::freevars; +use middle::mem_categorization::Typer; use middle::subst; -use middle::ty::ParameterEnvironment; use middle::ty; use middle::ty_fold::TypeFoldable; use middle::ty_fold; -use middle::typeck::check::vtable; -use middle::typeck::{MethodCall, NoAdjustment}; -use middle::typeck; -use util::ppaux::{Repr, ty_to_string}; +use util::ppaux::{ty_to_string}; use util::ppaux::UserString; -use std::collections::HashSet; use syntax::ast::*; -use syntax::ast_util; use syntax::attr; use syntax::codemap::Span; use syntax::print::pprust::{expr_to_string, ident_to_string}; use syntax::visit::Visitor; use syntax::visit; -// Kind analysis pass. -// -// There are several kinds defined by various operations. The most restrictive -// kind is noncopyable. The noncopyable kind can be extended with any number -// of the following attributes. -// -// Send: Things that can be sent on channels or included in spawned closures. It -// includes scalar types as well as classes and unique types containing only -// sendable types. -// 'static: Things that do not contain references. -// -// This pass ensures that type parameters are only instantiated with types -// whose kinds are equal or less general than the way the type parameter was -// annotated (with the `Send` bound). -// -// It also verifies that noncopyable kinds are not copied. Sendability is not -// applied, since none of our language primitives send. Instead, the sending -// primitives in the stdlib are explicitly annotated to only take sendable -// types. +// Kind analysis pass. This pass does some ad-hoc checks that are more +// convenient to do after type checking is complete and all checks are +// known. These are generally related to the builtin bounds `Copy` and +// `Sized`. Note that many of the builtin bound properties that used +// to be checked here are actually checked by trait checking these +// days. -pub struct Context<'a, 'tcx: 'a> { +pub struct Context<'a,'tcx:'a> { tcx: &'a ty::ctxt<'tcx>, - struct_and_enum_bounds_checked: HashSet, - parameter_environments: Vec, } impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { @@ -77,17 +57,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { fn visit_pat(&mut self, p: &Pat) { check_pat(self, p); } - - fn visit_local(&mut self, l: &Local) { - check_local(self, l); - } } pub fn check_crate(tcx: &ty::ctxt) { let mut ctx = Context { tcx: tcx, - struct_and_enum_bounds_checked: HashSet::new(), - parameter_environments: Vec::new(), }; visit::walk_crate(&mut ctx, tcx.map.krate()); tcx.sess.abort_if_errors(); @@ -135,27 +109,11 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t .find(&trait_ref.ref_id) .expect("trait ref not in def map!"); let trait_def_id = ast_trait_def.def_id(); - let trait_def = cx.tcx.trait_defs.borrow() - .find_copy(&trait_def_id) - .expect("trait def not in trait-defs map!"); - - // If this trait has builtin-kind supertraits, meet them. - let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id); - debug!("checking impl with self type {}", ty::get(self_ty).sty); - check_builtin_bounds( - cx, self_ty, trait_def.bounds.builtin_bounds, - |missing| { - span_err!(cx.tcx.sess, self_type.span, E0142, - "the type `{}', which does not fulfill `{}`, \ - cannot implement this trait", - ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx)); - span_note!(cx.tcx.sess, self_type.span, - "types implementing this trait must fulfill `{}`", - trait_def.bounds.user_string(cx.tcx)); - }); // If this is a destructor, check kinds. - if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) { + if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) && + !attr::contains_name(it.attrs.as_slice(), "unsafe_destructor") + { match self_type.node { TyPath(_, ref bounds, path_node_id) => { assert!(bounds.is_none()); @@ -172,133 +130,50 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t } fn check_item(cx: &mut Context, item: &Item) { - if !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") { - match item.node { - ItemImpl(_, ref trait_ref, ref self_type, _) => { - let parameter_environment = - ParameterEnvironment::for_item(cx.tcx, item.id); - cx.parameter_environments.push(parameter_environment); - - // Check bounds on the `self` type. - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - item.span, - ty::node_id_to_type(cx.tcx, item.id)); - - match trait_ref { - &Some(ref trait_ref) => { - check_impl_of_trait(cx, item, trait_ref, &**self_type); - - // Check bounds on the trait ref. - match ty::impl_trait_ref(cx.tcx, - ast_util::local_def(item.id)) { - None => {} - Some(trait_ref) => { - check_bounds_on_structs_or_enums_in_trait_ref( - cx, - item.span, - &*trait_ref); - - let trait_def = ty::lookup_trait_def(cx.tcx, trait_ref.def_id); - for (ty, type_param_def) in trait_ref.substs.types - .iter() - .zip(trait_def.generics - .types - .iter()) { - check_typaram_bounds(cx, item.span, *ty, type_param_def); - } - } - } - } - &None => {} - } - - drop(cx.parameter_environments.pop()); - } - ItemEnum(..) => { - let parameter_environment = - ParameterEnvironment::for_item(cx.tcx, item.id); - cx.parameter_environments.push(parameter_environment); - - let def_id = ast_util::local_def(item.id); - for variant in ty::enum_variants(cx.tcx, def_id).iter() { - for arg in variant.args.iter() { - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - item.span, - *arg) - } - } - - drop(cx.parameter_environments.pop()); - } - ItemStruct(..) => { - let parameter_environment = - ParameterEnvironment::for_item(cx.tcx, item.id); - cx.parameter_environments.push(parameter_environment); - - let def_id = ast_util::local_def(item.id); - for field in ty::lookup_struct_fields(cx.tcx, def_id).iter() { - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - item.span, - ty::node_id_to_type(cx.tcx, field.id.node)) - } - - drop(cx.parameter_environments.pop()); - - } - ItemStatic(..) => { - let parameter_environment = - ParameterEnvironment::for_item(cx.tcx, item.id); - cx.parameter_environments.push(parameter_environment); - - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - item.span, - ty::node_id_to_type(cx.tcx, item.id)); - - drop(cx.parameter_environments.pop()); - } - _ => {} + match item.node { + ItemImpl(_, Some(ref trait_ref), ref self_type, _) => { + check_impl_of_trait(cx, item, trait_ref, &**self_type); } + _ => {} } visit::walk_item(cx, item) } -fn check_local(cx: &mut Context, local: &Local) { - check_bounds_on_structs_or_enums_in_type_if_possible( - cx, - local.span, - ty::node_id_to_type(cx.tcx, local.id)); - - visit::walk_local(cx, local) -} - // Yields the appropriate function to check the kind of closed over // variables. `id` is the NodeId for some expression that creates the // closure. fn with_appropriate_checker(cx: &Context, id: NodeId, + fn_span: Span, b: |checker: |&Context, &freevar_entry||) { - fn check_for_uniq(cx: &Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) { + fn check_for_uniq(cx: &Context, + fn_span: Span, + fv: &freevar_entry, + bounds: ty::BuiltinBounds) { // all captured data must be owned, regardless of whether it is // moved in or copied in. let id = fv.def.def_id().node; let var_t = ty::node_id_to_type(cx.tcx, id); - check_freevar_bounds(cx, fv.span, var_t, bounds, None); + check_freevar_bounds(cx, fn_span, fv.span, var_t, bounds, None); } - fn check_for_block(cx: &Context, fv: &freevar_entry, - bounds: ty::BuiltinBounds, region: ty::Region) { + fn check_for_block(cx: &Context, + fn_span: Span, + fn_id: NodeId, + fv: &freevar_entry, + bounds: ty::BuiltinBounds) { let id = fv.def.def_id().node; let var_t = ty::node_id_to_type(cx.tcx, id); - // FIXME(#3569): Figure out whether the implicit borrow is actually - // mutable. Currently we assume all upvars are referenced mutably. - let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t); - check_freevar_bounds(cx, fv.span, implicit_borrowed_type, + let upvar_id = ty::UpvarId { var_id: id, closure_expr_id: fn_id }; + let upvar_borrow = cx.tcx.upvar_borrow(upvar_id); + let implicit_borrowed_type = + ty::mk_rptr(cx.tcx, + upvar_borrow.region, + ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(), + ty: var_t }); + check_freevar_bounds(cx, fn_span, fv.span, implicit_borrowed_type, bounds, Some(var_t)); } @@ -315,12 +190,16 @@ fn with_appropriate_checker(cx: &Context, bounds: bounds, .. }) => { - b(|cx, fv| check_for_uniq(cx, fv, bounds.builtin_bounds)) + b(|cx, fv| check_for_uniq(cx, fn_span, fv, + bounds.builtin_bounds)) } ty::ty_closure(box ty::ClosureTy { - store: ty::RegionTraitStore(region, _), bounds, .. - }) => b(|cx, fv| check_for_block(cx, fv, bounds.builtin_bounds, region)), + store: ty::RegionTraitStore(..), bounds, .. + }) => { + b(|cx, fv| check_for_block(cx, fn_span, id, fv, + bounds.builtin_bounds)) + } ty::ty_bare_fn(_) => { b(check_for_bare) @@ -346,8 +225,8 @@ fn check_fn( sp: Span, fn_id: NodeId) { - // Check kinds on free variables: - with_appropriate_checker(cx, fn_id, |chk| { + // { - let ty = ty::node_id_to_type(cx.tcx, fn_id); - check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty); - visit::walk_fn(cx, fk, decl, body, sp) } visit::FkItemFn(..) | visit::FkMethod(..) => { - let parameter_environment = ParameterEnvironment::for_item(cx.tcx, - fn_id); - cx.parameter_environments.push(parameter_environment); - - let ty = ty::node_id_to_type(cx.tcx, fn_id); - check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty); - visit::walk_fn(cx, fk, decl, body, sp); - drop(cx.parameter_environments.pop()); } } } @@ -379,30 +247,7 @@ fn check_fn( pub fn check_expr(cx: &mut Context, e: &Expr) { debug!("kind::check_expr({})", expr_to_string(e)); - // Handle any kind bounds on type parameters - check_bounds_on_type_parameters(cx, e); - - // Check bounds on structures or enumerations in the type of the - // expression. - let expression_type = ty::expr_ty(cx.tcx, e); - check_bounds_on_structs_or_enums_in_type_if_possible(cx, - e.span, - expression_type); - match e.node { - ExprCast(ref source, _) => { - let source_ty = ty::expr_ty(cx.tcx, &**source); - let target_ty = ty::expr_ty(cx.tcx, e); - 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); if count > 1 { @@ -427,174 +272,8 @@ pub fn check_expr(cx: &mut Context, e: &Expr) { _ => {} } - // Search for auto-adjustments to find trait coercions. - match cx.tcx.adjustments.borrow().find(&e.id) { - Some(adjustment) => { - match adjustment { - adj if ty::adjust_is_object(adj) => { - let source_ty = ty::expr_ty(cx.tcx, e); - let target_ty = ty::expr_ty_adjusted(cx.tcx, e); - let method_call = MethodCall { - expr_id: e.id, - adjustment: typeck::AutoObject, - }; - check_trait_cast(cx, - source_ty, - target_ty, - e.span, - method_call); - } - _ => {} - } - } - None => {} - } - visit::walk_expr(cx, e); } - -fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) { - let method_map = cx.tcx.method_map.borrow(); - let method_call = typeck::MethodCall::expr(e.id); - let method = method_map.find(&method_call); - - // Find the values that were provided (if any) - let item_substs = cx.tcx.item_substs.borrow(); - let (types, is_object_call) = match method { - Some(method) => { - let is_object_call = match method.origin { - typeck::MethodObject(..) => true, - typeck::MethodStatic(..) | - typeck::MethodStaticUnboxedClosure(..) | - typeck::MethodParam(..) => false - }; - (&method.substs.types, is_object_call) - } - None => { - match item_substs.find(&e.id) { - None => { return; } - Some(s) => { (&s.substs.types, false) } - } - } - }; - - // Find the relevant type parameter definitions - let def_map = cx.tcx.def_map.borrow(); - let type_param_defs = match e.node { - ExprPath(_) => { - let did = def_map.get_copy(&e.id).def_id(); - ty::lookup_item_type(cx.tcx, did).generics.types.clone() - } - _ => { - // Type substitutions should only occur on paths and - // method calls, so this needs to be a method call. - - // Even though the callee_id may have been the id with - // node_type_substs, e.id is correct here. - match method { - Some(method) => { - ty::method_call_type_param_defs(cx.tcx, method.origin) - } - None => { - cx.tcx.sess.span_bug(e.span, - "non path/method call expr has type substs??"); - } - } - } - }; - - // Check that the value provided for each definition meets the - // kind requirements - for type_param_def in type_param_defs.iter() { - let ty = *types.get(type_param_def.space, type_param_def.index); - - // If this is a call to an object method (`foo.bar()` where - // `foo` has a type like `Trait`), then the self type is - // unknown (after all, this is a virtual call). In that case, - // we will have put a ty_err in the substitutions, and we can - // just skip over validating the bounds (because the bounds - // would have been enforced when the object instance was - // created). - if is_object_call && type_param_def.space == subst::SelfSpace { - assert_eq!(type_param_def.index, 0); - assert!(ty::type_is_error(ty)); - continue; - } - - debug!("type_param_def space={} index={} ty={}", - type_param_def.space, type_param_def.index, ty.repr(cx.tcx)); - check_typaram_bounds(cx, e.span, ty, type_param_def) - } - - // Check the vtable. - let vtable_map = cx.tcx.vtable_map.borrow(); - let vtable_res = match vtable_map.find(&method_call) { - None => return, - Some(vtable_res) => vtable_res, - }; - check_type_parameter_bounds_in_vtable_result(cx, e.span, vtable_res); -} - -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) { - 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, .. }) => { - 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.builtin_bounds); - } - _ => {} - } - } - _ => {} - } -} - fn check_ty(cx: &mut Context, aty: &Ty) { match aty.node { TyPath(_, _, id) => { @@ -651,77 +330,7 @@ pub fn check_typaram_bounds(cx: &Context, }); } -fn check_bounds_on_structs_or_enums_in_type_if_possible(cx: &mut Context, - span: Span, - ty: ty::t) { - // If we aren't in a function, structure, or enumeration context, we don't - // have enough information to ensure that bounds on structures or - // enumerations are satisfied. So we don't perform the check. - if cx.parameter_environments.len() == 0 { - return - } - - // If we've already checked for this type, don't do it again. This - // massively speeds up kind checking. - if cx.struct_and_enum_bounds_checked.contains(&ty) { - return - } - cx.struct_and_enum_bounds_checked.insert(ty); - - ty::walk_ty(ty, |ty| { - match ty::get(ty).sty { - ty::ty_struct(type_id, ref substs) | - ty::ty_enum(type_id, ref substs) => { - let polytype = ty::lookup_item_type(cx.tcx, type_id); - - // Check builtin bounds. - for (ty, type_param_def) in substs.types - .iter() - .zip(polytype.generics - .types - .iter()) { - check_typaram_bounds(cx, span, *ty, type_param_def); - } - - // Check trait bounds. - let parameter_environment = - cx.parameter_environments.get(cx.parameter_environments - .len() - 1); - debug!( - "check_bounds_on_structs_or_enums_in_type_if_possible(): \ - checking {}", - ty.repr(cx.tcx)); - vtable::check_param_bounds(cx.tcx, - span, - parameter_environment, - &polytype.generics.types, - substs, - |missing| { - cx.tcx - .sess - .span_err(span, - format!("instantiating a type parameter with \ - an incompatible type `{}`, which \ - does not fulfill `{}`", - ty_to_string(cx.tcx, ty), - missing.user_string( - cx.tcx)).as_slice()); - }) - } - _ => {} - } - }); -} - -fn check_bounds_on_structs_or_enums_in_trait_ref(cx: &mut Context, - span: Span, - trait_ref: &ty::TraitRef) { - for ty in trait_ref.substs.types.iter() { - check_bounds_on_structs_or_enums_in_type_if_possible(cx, span, *ty) - } -} - -pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t, +pub fn check_freevar_bounds(cx: &Context, fn_span: Span, sp: Span, ty: ty::t, bounds: ty::BuiltinBounds, referenced_ty: Option) { check_builtin_bounds(cx, ty, bounds, |missing| { @@ -741,7 +350,7 @@ pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t, ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx)); } } - span_note!(cx.tcx.sess, sp, + span_note!(cx.tcx.sess, fn_span, "this closure's environment must satisfy `{}`", bounds.user_string(cx.tcx)); }); diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 24782240f06c4..1ea0681085b1a 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -85,6 +85,17 @@ impl LanguageItems { } } + pub fn from_builtin_kind(&self, bound: ty::BuiltinBound) + -> Result + { + match bound { + ty::BoundSend => self.require(SendTraitLangItem), + ty::BoundSized => self.require(SizedTraitLangItem), + ty::BoundCopy => self.require(CopyTraitLangItem), + ty::BoundSync => self.require(SyncTraitLangItem), + } + } + pub fn to_builtin_kind(&self, id: ast::DefId) -> Option { if Some(id) == self.send_trait() { Some(ty::BoundSend) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index feacbf84f6739..56c785d3c2592 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -782,19 +782,19 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } // Checks that a method is in scope. - fn check_method(&mut self, span: Span, origin: MethodOrigin, + fn check_method(&mut self, span: Span, origin: &MethodOrigin, ident: ast::Ident) { - match origin { + match *origin { MethodStatic(method_id) => { self.check_static_method(span, method_id, ident) } MethodStaticUnboxedClosure(_) => {} // Trait methods are always all public. The only controlling factor // is whether the trait itself is accessible or not. - MethodParam(MethodParam { trait_id: trait_id, .. }) | - MethodObject(MethodObject { trait_id: trait_id, .. }) => { - self.report_error(self.ensure_public(span, trait_id, None, - "source trait")); + MethodParam(MethodParam { trait_ref: ref trait_ref, .. }) | + MethodObject(MethodObject { trait_ref: ref trait_ref, .. }) => { + self.report_error(self.ensure_public(span, trait_ref.def_id, + None, "source trait")); } } } @@ -835,7 +835,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } Some(method) => { debug!("(privacy checking) checking impl method"); - self.check_method(expr.span, method.origin, ident.node); + self.check_method(expr.span, &method.origin, ident.node); } } } diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index 04e04efd93c26..5859e5ceeeeb1 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -908,10 +908,10 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { }; (Some(def_id), decl_id) } - typeck::MethodParam(mp) => { + typeck::MethodParam(ref mp) => { // method invoked on a type parameter let trait_item = ty::trait_item(&self.analysis.ty_cx, - mp.trait_id, + mp.trait_ref.def_id, mp.method_num); match trait_item { ty::MethodTraitItem(method) => { @@ -919,10 +919,10 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { } } }, - typeck::MethodObject(mo) => { + typeck::MethodObject(ref mo) => { // method invoked on a trait instance let trait_item = ty::trait_item(&self.analysis.ty_cx, - mo.trait_id, + mo.trait_ref.def_id, mo.method_num); match trait_item { ty::MethodTraitItem(method) => { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index c1c23dff98406..d7e6fd18ed563 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -164,6 +164,11 @@ impl Substs { s } + pub fn erase_regions(self) -> Substs { + let Substs { types: types, regions: _ } = self; + Substs { types: types, regions: ErasedRegions } + } + pub fn regions<'a>(&'a self) -> &'a VecPerParamSpace { /*! * Since ErasedRegions are only to be used in trans, most of @@ -333,6 +338,16 @@ impl VecPerParamSpace { } } + fn new_internal(content: Vec, type_limit: uint, self_limit: uint) + -> VecPerParamSpace + { + VecPerParamSpace { + type_limit: type_limit, + self_limit: self_limit, + content: content, + } + } + pub fn sort(t: Vec, space: |&T| -> ParamSpace) -> VecPerParamSpace { let mut result = VecPerParamSpace::empty(); for t in t.move_iter() { @@ -448,13 +463,17 @@ impl VecPerParamSpace { } pub fn map(&self, pred: |&T| -> U) -> VecPerParamSpace { - // FIXME (#15418): this could avoid allocating the intermediate - // Vec's, but note that the values of type_limit and self_limit - // also need to be kept in sync during construction. - VecPerParamSpace::new( - self.get_slice(TypeSpace).iter().map(|p| pred(p)).collect(), - self.get_slice(SelfSpace).iter().map(|p| pred(p)).collect(), - self.get_slice(FnSpace).iter().map(|p| pred(p)).collect()) + let result = self.iter().map(pred).collect(); + VecPerParamSpace::new_internal(result, + self.type_limit, + self.self_limit) + } + + pub fn map_move(self, pred: |T| -> U) -> VecPerParamSpace { + let (t, s, f) = self.split(); + VecPerParamSpace::new(t.move_iter().map(|p| pred(p)).collect(), + s.move_iter().map(|p| pred(p)).collect(), + f.move_iter().map(|p| pred(p)).collect()) } pub fn map_rev(&self, pred: |&T| -> U) -> VecPerParamSpace { diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs new file mode 100644 index 0000000000000..415eed380fc54 --- /dev/null +++ b/src/librustc/middle/traits/coherence.rs @@ -0,0 +1,168 @@ +// Copyright 2014 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. + +/*! See `doc.rs` for high-level documentation */ + +use super::DUMMY_CAUSE; +use super::{EvaluatedToMatch, EvaluatedToAmbiguity, EvaluatedToUnmatch}; +use super::{evaluate_impl}; +use super::util; + +use middle::subst; +use middle::subst::Subst; +use middle::ty; +use middle::typeck::infer::InferCtxt; +use syntax::ast; +use syntax::codemap::DUMMY_SP; +use util::nodemap::DefIdMap; +use util::ppaux::Repr; + +pub fn impl_can_satisfy(infcx: &InferCtxt, + impl1_def_id: ast::DefId, + impl2_def_id: ast::DefId) + -> bool +{ + // `impl1` provides an implementation of `Foo for Z`. + let impl1_substs = + util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id); + let impl1_self_ty = + ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap() + .self_ty() + .subst(infcx.tcx, &impl1_substs); + + // Determine whether `impl2` can provide an implementation for those + // same types. + let param_env = ty::empty_parameter_environment(); + let unboxed_closures = DefIdMap::new(); + match evaluate_impl(infcx, ¶m_env, &unboxed_closures, DUMMY_CAUSE, + impl2_def_id, impl1_self_ty) { + EvaluatedToMatch | EvaluatedToAmbiguity => true, + EvaluatedToUnmatch => false, + } +} + +pub fn impl_is_local(tcx: &ty::ctxt, + impl_def_id: ast::DefId) + -> bool +{ + debug!("impl_is_local({})", impl_def_id.repr(tcx)); + + // We only except this routine to be invoked on implementations + // of a trait, not inherent implementations. + let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap(); + debug!("trait_ref={}", trait_ref.repr(tcx)); + + // If the trait is local to the crate, ok. + if trait_ref.def_id.krate == ast::LOCAL_CRATE { + debug!("trait {} is local to current crate", + trait_ref.def_id.repr(tcx)); + return true; + } + + // Otherwise, self type must be local to the crate. + let self_ty = ty::lookup_item_type(tcx, impl_def_id).ty; + return ty_is_local(tcx, self_ty); +} + +pub fn ty_is_local(tcx: &ty::ctxt, + ty: ty::t) + -> bool +{ + debug!("ty_is_local({})", ty.repr(tcx)); + + match ty::get(ty).sty { + ty::ty_nil | + ty::ty_bot | + ty::ty_bool | + ty::ty_char | + ty::ty_int(..) | + ty::ty_uint(..) | + ty::ty_float(..) | + ty::ty_str(..) => { + false + } + + ty::ty_unboxed_closure(..) => { + // This routine is invoked on types specified by users as + // part of an impl and hence an unboxed closure type + // cannot appear. + tcx.sess.bug("ty_is_local applied to unboxed closure type") + } + + ty::ty_bare_fn(..) | + ty::ty_closure(..) => { + false + } + + ty::ty_uniq(t) => { + let krate = tcx.lang_items.owned_box().map(|d| d.krate); + krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t) + } + + ty::ty_box(t) => { + let krate = tcx.lang_items.gc().map(|d| d.krate); + krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t) + } + + ty::ty_vec(t, _) | + ty::ty_ptr(ty::mt { ty: t, .. }) | + ty::ty_rptr(_, ty::mt { ty: t, .. }) => { + ty_is_local(tcx, t) + } + + ty::ty_tup(ref ts) => { + ts.iter().any(|&t| ty_is_local(tcx, t)) + } + + ty::ty_enum(def_id, ref substs) | + ty::ty_struct(def_id, ref substs) => { + def_id.krate == ast::LOCAL_CRATE || { + let variances = ty::item_variances(tcx, def_id); + subst::ParamSpace::all().iter().any(|&space| { + substs.types.get_slice(space).iter().enumerate().any( + |(i, &t)| { + match *variances.types.get(space, i) { + ty::Bivariant => { + // If Foo is bivariant with respect to + // T, then it doesn't matter whether T is + // local or not, because `Foo` for any + // U will be a subtype of T. + false + } + ty::Contravariant | + ty::Covariant | + ty::Invariant => { + ty_is_local(tcx, t) + } + } + }) + }) + } + } + + ty::ty_trait(ref tt) => { + tt.def_id.krate == ast::LOCAL_CRATE + } + + // Type parameters may be bound to types that are not local to + // the crate. + ty::ty_param(..) => { + false + } + + ty::ty_infer(..) | + ty::ty_open(..) | + ty::ty_err => { + tcx.sess.bug( + format!("ty_is_local invoked on unexpected type: {}", + ty.repr(tcx)).as_slice()) + } + } +} diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs new file mode 100644 index 0000000000000..98db226387453 --- /dev/null +++ b/src/librustc/middle/traits/doc.rs @@ -0,0 +1,268 @@ +// Copyright 2014 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. + +/*! + +# TRAIT RESOLUTION + +This document describes the general process and points out some non-obvious +things. + +## Major concepts + +Trait resolution is the process of pairing up an impl with each +reference to a trait. So, for example, if there is a generic function like: + + fn clone_slice(x: &[T]) -> Vec { ... } + +and then a call to that function: + + let v: Vec = clone_slice([1, 2, 3].as_slice()) + +it is the job of trait resolution to figure out (in which case) +whether there exists an impl of `int : Clone` + +Note that in some cases, like generic functions, we may not be able to +find a specific impl, but we can figure out that the caller must +provide an impl. To see what I mean, consider the body of `clone_slice`: + + fn clone_slice(x: &[T]) -> Vec { + let mut v = Vec::new(); + for e in x.iter() { + v.push((*e).clone()); // (*) + } + } + +The line marked `(*)` is only legal if `T` (the type of `*e`) +implements the `Clone` trait. Naturally, since we don't know what `T` +is, we can't find the specific impl; but based on the bound `T:Clone`, +we can say that there exists an impl which the caller must provide. + +We use the term *obligation* to refer to a trait reference in need of +an impl. + +## Overview + +Trait resolution consists of three major parts: + +- SELECTION: Deciding how to resolve a specific obligation. For + example, selection might decide that a specific obligation can be + resolved by employing an impl which matches the self type, or by + using a parameter bound. In the case of an impl, Selecting one + obligation can create *nested obligations* because of where clauses + on the impl itself. + +- FULFILLMENT: The fulfillment code is what tracks that obligations + are completely fulfilled. Basically it is a worklist of obligations + to be selected: once selection is successful, the obligation is + removed from the worklist and any nested obligations are enqueued. + +- COHERENCE: The coherence checks are intended to ensure that there + are never overlapping impls, where two impls could be used with + equal precedence. + +## Selection + +Selection is the process of deciding whether an obligation can be +resolved and, if so, how it is to be resolved (via impl, where clause, etc). +The main interface is the `select()` function, which takes an obligation +and returns a `SelectionResult`. There are three possible outcomes: + +- `Ok(Some(selection))` -- yes, the obligation can be resolved, and + `selection` indicates how. If the impl was resolved via an impl, + then `selection` may also indicate nested obligations that are required + by the impl. + +- `Ok(None)` -- we are not yet sure whether the obligation can be + resolved or not. This happens most commonly when the obligation + contains unbound type variables. + +- `Err(err)` -- the obligation definitely cannot be resolved due to a + type error, or because there are no impls that could possibly apply, + etc. + +The basic algorithm for selection is broken into two big phases: +candidate assembly and confirmation. + +### Candidate assembly + +Searches for impls/where-clauses/etc that might +possibly be used to satisfy the obligation. Each of those is called +a candidate. To avoid ambiguity, we want to find exactly one +candidate that is definitively applicable. In some cases, we may not +know whether an impl/where-clause applies or not -- this occurs when +the obligation contains unbound inference variables. + +One important point is that candidate assembly considers *only the +input types* of the obligation when deciding whether an impl applies +or not. Consider the following example: + + trait Convert { // T is output, Self is input + fn convert(&self) -> T; + } + + impl Convert for int { ... } + +Now assume we have an obligation `int : Convert`. During +candidate assembly, the impl above would be considered a definitively +applicable candidate, because it has the same self type (`int`). The +fact that the output type parameter `T` is `uint` on the impl and +`char` in the obligation is not considered. + +#### Skolemization + +We (at least currently) wish to guarantee "crate concatenability" -- +which basically means that you could take two crates, concatenate +them textually, and the combined crate would continue to compile. The +only real way that this relates to trait matching is with +inference. We have to be careful not to influence unbound type +variables during the selection process, basically. + +Here is an example: + + trait Foo { fn method() { ... }} + impl Foo for int { ... } + + fn something() { + let mut x = None; // `x` has type `Option` + loop { + match x { + Some(ref y) => { // `y` has type ? + y.method(); // (*) + ... + }}} + } + +The question is, can we resolve the call to `y.method()`? We don't yet +know what type `y` has. However, there is only one impl in scope, and +it is for `int`, so perhaps we could deduce that `y` *must* have type +`int` (and hence the type of `x` is `Option`)? This is actually +sound reasoning: `int` is the only type in scope that could possibly +make this program type check. However, this deduction is a bit +"unstable", though, because if we concatenated with another crate that +defined a newtype and implemented `Foo` for this newtype, then the +inference would fail, because there would be two potential impls, not +one. + +It is unclear how important this property is. It might be nice to drop it. +But for the time being we maintain it. + +The way we do this is by *skolemizing* the obligation self type during +the selection process -- skolemizing means, basically, replacing all +unbound type variables with a new "skolemized" type. Each skolemized +type is basically considered "as if" it were some fresh type that is +distinct from all other types. The skolemization process also replaces +lifetimes with `'static`, see the section on lifetimes below for an +explanation. + +In the example above, this means that when matching `y.method()` we +would convert the type of `y` from a type variable `?` to a skolemized +type `X`. Then, since `X` cannot unify with `int`, the match would +fail. Special code exists to check that the match failed because a +skolemized type could not be unified with another kind of type -- this is +not considered a definitive failure, but rather an ambiguous result, +since if the type variable were later to be unified with int, then this +obligation could be resolved then. + +*Note:* Currently, method matching does not use the trait resolution +code, so if you in fact type in the example above, it may +compile. Hopefully this will be fixed in later patches. + +#### Matching + +The subroutines that decide whether a particular impl/where-clause/etc +applies to a particular obligation. At the moment, this amounts to +unifying the self types, but in the future we may also recursively +consider some of the nested obligations, in the case of an impl. + +#### Lifetimes and selection + +Because of how that lifetime inference works, it is not possible to +give back immediate feedback as to whether a unification or subtype +relationship between lifetimes holds or not. Therefore, lifetime +matching is *not* considered during selection. This is achieved by +having the skolemization process just replace *ALL* lifetimes with +`'static`. Later, during confirmation, the non-skolemized self-type +will be unified with the type from the impl (or whatever). This may +yield lifetime constraints that will later be found to be in error (in +contrast, the non-lifetime-constraints have already been checked +during selection and can never cause an error, though naturally they +may lead to other errors downstream). + +#### Where clauses + +Besides an impl, the other major way to resolve an obligation is via a +where clause. The selection process is always given a *parameter +environment* which contains a list of where clauses, which are +basically obligations that can assume are satisfiable. We will iterate +over that list and check whether our current obligation can be found +in that list, and if so it is considered satisfied. More precisely, we +want to check whether there is a where-clause obligation that is for +the same trait (or some subtrait) and for which the self types match, +using the definition of *matching* given above. + +Consider this simple example: + + trait A1 { ... } + trait A2 : A1 { ... } + + trait B { ... } + + fn foo { ... } + +Clearly we can use methods offered by `A1`, `A2`, or `B` within the +body of `foo`. In each case, that will incur an obligation like `X : +A1` or `X : A2`. The parameter environment will contain two +where-clauses, `X : A2` and `X : B`. For each obligation, then, we +search this list of where-clauses. To resolve an obligation `X:A1`, +we would note that `X:A2` implies that `X:A1`. + +### Confirmation + +Confirmation unifies the output type parameters of the trait with the +values found in the obligation, possibly yielding a type error. If we +return to our example of the `Convert` trait from the previous +section, confirmation is where an error would be reported, because the +impl specified that `T` would be `uint`, but the obligation reported +`char`. Hence the result of selection would be an error. + +### Selection during translation + +During type checking, we do not store the results of trait selection. +We simply wish to verify that trait selection will succeed. Then +later, at trans time, when we have all concrete types available, we +can repeat the trait selection. In this case, we do not consider any +where-clauses to be in scope. We know that therefore each resolution +will resolve to a particular impl. + +One interesting twist has to do with nested obligations. In general, in trans, +we only need to do a "shallow" selection for an obligation. That is, we wish to +identify which impl applies, but we do not (yet) need to decide how to select +any nested obligations. Nonetheless, we *do* currently do a complete resolution, +and that is because it can sometimes inform the results of type inference. That is, +we do not have the full substitutions in terms of the type varibales of the impl available +to us, so we must run trait selection to figure everything out. + +Here is an example: + + trait Foo { ... } + impl> Foo for Vec { ... } + + impl Bar for int { ... } + +After one shallow round of selection for an obligation like `Vec +: Foo`, we would know which impl we want, and we would know that +`T=int`, but we do not know the type of `U`. We must select the +nested obligation `int : Bar` to find out that `U=uint`. + +It would be good to only do *just as much* nested resolution as +necessary. Currently, though, we just do a full resolution. + +*/ diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs new file mode 100644 index 0000000000000..78d105c251edb --- /dev/null +++ b/src/librustc/middle/traits/fulfill.rs @@ -0,0 +1,250 @@ +// Copyright 2014 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. + +use middle::ty; +use middle::typeck::infer::{InferCtxt, skolemize}; +use util::nodemap::DefIdMap; +use util::ppaux::Repr; + +use super::Ambiguity; +use super::Obligation; +use super::FulfillmentError; +use super::SelectionError; +use super::select::SelectionContext; +use super::Unimplemented; + +/** + * The fulfillment context is used to drive trait resolution. It + * consists of a list of obligations that must be (eventually) + * satisfied. The job is to track which are satisfied, which yielded + * errors, and which are still pending. At any point, users can call + * `select_where_possible`, and the fulfilment context will try to do + * selection, retaining only those obligations that remain + * ambiguous. This may be helpful in pushing type inference + * along. Once all type inference constraints have been generated, the + * method `select_all_or_error` can be used to report any remaining + * ambiguous cases as errors. + */ +pub struct FulfillmentContext { + // A list of all obligations that have been registered with this + // fulfillment context. + trait_obligations: Vec, + + // For semi-hacky reasons (see FIXME below) we keep the builtin + // trait obligations segregated. + builtin_obligations: Vec, +} + +impl FulfillmentContext { + pub fn new() -> FulfillmentContext { + FulfillmentContext { + trait_obligations: Vec::new(), + builtin_obligations: Vec::new() + } + } + + pub fn register_obligation(&mut self, + tcx: &ty::ctxt, + obligation: Obligation) + { + debug!("register_obligation({})", obligation.repr(tcx)); + match tcx.lang_items.to_builtin_kind(obligation.trait_ref.def_id) { + Some(_) => { + self.builtin_obligations.push(obligation); + } + None => { + self.trait_obligations.push(obligation); + } + } + } + + pub fn select_all_or_error(&mut self, + infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap) + -> Result<(),Vec> + { + try!(self.select_where_possible(infcx, param_env, + unboxed_closures)); + + // Anything left is ambiguous. + let errors: Vec = + self.trait_obligations + .iter() + .map(|o| FulfillmentError::new((*o).clone(), Ambiguity)) + .collect(); + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } + + pub fn select_where_possible(&mut self, + infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap) + -> Result<(),Vec> + { + let tcx = infcx.tcx; + let selcx = SelectionContext::new(infcx, param_env, + unboxed_closures); + + debug!("select_where_possible({} obligations) start", + self.trait_obligations.len()); + + let mut errors = Vec::new(); + + loop { + let count = self.trait_obligations.len(); + + debug!("select_where_possible({} obligations) iteration", + count); + + let mut selections = Vec::new(); + + // First pass: walk each obligation, retaining + // only those that we cannot yet process. + self.trait_obligations.retain(|obligation| { + match selcx.select(obligation) { + Ok(None) => { + true + } + Ok(Some(s)) => { + selections.push(s); + false + } + Err(selection_err) => { + debug!("obligation: {} error: {}", + obligation.repr(tcx), + selection_err.repr(tcx)); + + errors.push(FulfillmentError::new( + (*obligation).clone(), + SelectionError(selection_err))); + false + } + } + }); + + if self.trait_obligations.len() == count { + // Nothing changed. + break; + } + + // Now go through all the successful ones, + // registering any nested obligations for the future. + for selection in selections.move_iter() { + selection.map_move_nested( + |o| self.register_obligation(tcx, o)); + } + } + + debug!("select_where_possible({} obligations, {} errors) done", + self.trait_obligations.len(), + errors.len()); + + if errors.len() == 0 { + Ok(()) + } else { + Err(errors) + } + } + + pub fn check_builtin_bound_obligations( + &self, + infcx: &InferCtxt) + -> Result<(),Vec> + { + let tcx = infcx.tcx; + let mut errors = Vec::new(); + debug!("check_builtin_bound_obligations"); + for obligation in self.builtin_obligations.iter() { + debug!("obligation={}", obligation.repr(tcx)); + + let def_id = obligation.trait_ref.def_id; + let bound = match tcx.lang_items.to_builtin_kind(def_id) { + Some(bound) => { bound } + None => { continue; } + }; + + let unskol_self_ty = obligation.self_ty(); + + // Skolemize the self-type so that it no longer contains + // inference variables. Note that this also replaces + // regions with 'static. You might think that this is not + // ok, because checking whether something is `Send` + // implies checking whether it is 'static: that's true, + // but in fact the region bound is fed into region + // inference separately and enforced there (and that has + // even already been done before this code executes, + // generally speaking). + let self_ty = skolemize(infcx, unskol_self_ty); + + debug!("bound={} self_ty={}", bound, self_ty.repr(tcx)); + if ty::type_is_error(self_ty) { + // Indicates an error that was/will-be + // reported elsewhere. + continue; + } + + // Determine if builtin bound is met. + let tc = ty::type_contents(tcx, self_ty); + debug!("tc={}", tc); + let met = match bound { + ty::BoundSend => tc.is_sendable(tcx), + ty::BoundSized => tc.is_sized(tcx), + ty::BoundCopy => tc.is_copy(tcx), + ty::BoundSync => tc.is_sync(tcx), + }; + + if met { + continue; + } + + // FIXME -- This is kind of a hack: it requently happens + // that some earlier error prevents types from being fully + // inferred, and then we get a bunch of uninteresting + // errors saying something like " doesn't + // implement Sized". It may even be true that we could + // just skip over all checks where the self-ty is an + // inference variable, but I was afraid that there might + // be an inference variable created, registered as an + // obligation, and then never forced by writeback, and + // hence by skipping here we'd be ignoring the fact that + // we don't KNOW the type works out. Though even that + // would probably be harmless, given that we're only + // talking about builtin traits, which are known to be + // inhabited. But in any case I just threw in this check + // for has_errors() to be sure that compilation isn't + // happening anyway. In that case, why inundate the user. + if ty::type_needs_infer(self_ty) && + tcx.sess.has_errors() + { + debug!("skipping printout because self_ty={}", + self_ty.repr(tcx)); + continue; + } + + errors.push( + FulfillmentError::new( + (*obligation).clone(), + SelectionError(Unimplemented))); + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } +} + diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs new file mode 100644 index 0000000000000..62b3c982ccd0a --- /dev/null +++ b/src/librustc/middle/traits/mod.rs @@ -0,0 +1,438 @@ +// Copyright 2014 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. + +/*! + * Trait Resolution. See doc.rs. + */ + +use middle::subst; +use middle::ty; +use middle::typeck::infer::InferCtxt; +use std::rc::Rc; +use syntax::ast; +use syntax::codemap::{Span, DUMMY_SP}; +use util::nodemap::DefIdMap; + +pub use self::fulfill::FulfillmentContext; +pub use self::select::SelectionContext; +pub use self::util::supertraits; +pub use self::util::transitive_bounds; +pub use self::util::Supertraits; +pub use self::util::search_trait_and_supertraits_from_bound; + +mod coherence; +mod fulfill; +mod select; +mod util; + +/** + * An `Obligation` represents some trait reference (e.g. `int:Eq`) for + * which the vtable must be found. The process of finding a vtable is + * called "resolving" the `Obligation`. This process consists of + * either identifying an `impl` (e.g., `impl Eq for int`) that + * provides the required vtable, or else finding a bound that is in + * scope. The eventual result is usually a `Selection` (defined below). + */ +#[deriving(Clone)] +pub struct Obligation { + pub cause: ObligationCause, + pub recursion_depth: uint, + pub trait_ref: Rc, +} + +/** + * Why did we incur this obligation? Used for error reporting. + */ +#[deriving(Clone)] +pub struct ObligationCause { + pub span: Span, + pub code: ObligationCauseCode +} + +#[deriving(Clone)] +pub enum ObligationCauseCode { + /// Not well classified or should be obvious from span. + MiscObligation, + + /// In an impl of trait X for type Y, type Y must + /// also implement all supertraits of X. + ItemObligation(ast::DefId), + + /// Obligation incurred due to an object cast. + ObjectCastObligation(/* Object type */ ty::t), + + /// Various cases where expressions must be sized/copy/etc: + AssignmentLhsSized, // L = X implies that L is Sized + StructInitializerSized, // S { ... } must be Sized + VariableType(ast::NodeId), // Type of each variable must be Sized + RepeatVec, // [T,..n] --> T must be Copy +} + +pub static DUMMY_CAUSE: ObligationCause = + ObligationCause { span: DUMMY_SP, + code: MiscObligation }; + +pub type Obligations = subst::VecPerParamSpace; + +pub type Selection = Vtable; + +#[deriving(Clone,Show)] +pub enum SelectionError { + Unimplemented, + Overflow, + OutputTypeParameterMismatch(Rc, ty::type_err) +} + +pub struct FulfillmentError { + pub obligation: Obligation, + pub code: FulfillmentErrorCode +} + +#[deriving(Clone)] +pub enum FulfillmentErrorCode { + SelectionError(SelectionError), + Ambiguity, +} + +/** + * When performing resolution, it is typically the case that there + * can be one of three outcomes: + * + * - `Ok(Some(r))`: success occurred with result `r` + * - `Ok(None)`: could not definitely determine anything, usually due + * to inconclusive type inference. + * - `Err(e)`: error `e` occurred + */ +pub type SelectionResult = Result,SelectionError>; + +#[deriving(PartialEq,Eq,Show)] +pub enum EvaluationResult { + EvaluatedToMatch, + EvaluatedToAmbiguity, + EvaluatedToUnmatch +} + +/** + * Given the successful resolution of an obligation, the `Vtable` + * indicates where the vtable comes from. Note that while we call this + * a "vtable", it does not necessarily indicate dynamic dispatch at + * runtime. `Vtable` instances just tell the compiler where to find + * methods, but in generic code those methods are typically statically + * dispatched -- only when an object is constructed is a `Vtable` + * instance reified into an actual vtable. + * + * For example, the vtable may be tied to a specific impl (case A), + * or it may be relative to some bound that is in scope (case B). + * + * + * ``` + * impl Clone for Option { ... } // Impl_1 + * impl Clone for Box { ... } // Impl_2 + * impl Clone for int { ... } // Impl_3 + * + * fn foo(concrete: Option>, + * param: T, + * mixed: Option) { + * + * // Case A: Vtable points at a specific impl. Only possible when + * // type is concretely known. If the impl itself has bounded + * // type parameters, Vtable will carry resolutions for those as well: + * concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) + * + * // Case B: Vtable must be provided by caller. This applies when + * // type is a type parameter. + * param.clone(); // VtableParam(Oblig_1) + * + * // Case C: A mix of cases A and B. + * mixed.clone(); // Vtable(Impl_1, [VtableParam(Oblig_1)]) + * } + * ``` + * + * ### The type parameter `N` + * + * See explanation on `VtableImpl`. + */ +#[deriving(Show,Clone)] +pub enum Vtable { + /// Vtable identifying a particular impl. + VtableImpl(VtableImpl), + + /// Vtable automatically generated for an unboxed closure. The def + /// ID is the ID of the closure expression. This is a `VtableImpl` + /// in spirit, but the impl is generated by the compiler and does + /// not appear in the source. + VtableUnboxedClosure(ast::DefId), + + /// Successful resolution to an obligation provided by the caller + /// for some type parameter. + VtableParam(VtableParam), + + /// Successful resolution for a builtin trait. + VtableBuiltin, +} + +/** + * Identifies a particular impl in the source, along with a set of + * substitutions from the impl's type/lifetime parameters. The + * `nested` vector corresponds to the nested obligations attached to + * the impl's type parameters. + * + * The type parameter `N` indicates the type used for "nested + * obligations" that are required by the impl. During type check, this + * is `Obligation`, as one might expect. During trans, however, this + * is `()`, because trans only requires a shallow resolution of an + * impl, and nested obligations are satisfied later. + */ +#[deriving(Clone)] +pub struct VtableImpl { + pub impl_def_id: ast::DefId, + pub substs: subst::Substs, + pub nested: subst::VecPerParamSpace +} + +/** + * A vtable provided as a parameter by the caller. For example, in a + * function like `fn foo(...)`, if the `eq()` method is invoked + * on an instance of `T`, the vtable would be of type `VtableParam`. + */ +#[deriving(Clone)] +pub struct VtableParam { + // In the above example, this would `Eq` + pub bound: Rc, +} + +pub fn try_select_obligation(infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap, + obligation: &Obligation) + -> SelectionResult +{ + /*! + * Attempts to select the impl/bound/etc for the obligation + * given. Returns `None` if we are unable to resolve, either + * because of ambiguity or due to insufficient inference. Note + * that selection is a shallow process and hence the result may + * contain nested obligations that must be resolved. The caller is + * responsible for ensuring that those get resolved. (But see + * `try_select_obligation_deep` below.) + */ + + let selcx = select::SelectionContext::new(infcx, param_env, unboxed_closures); + selcx.select(obligation) +} + +pub fn evaluate_obligation(infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + obligation: &Obligation, + unboxed_closures: &DefIdMap) + -> EvaluationResult +{ + /*! + * Attempts to resolve the obligation given. Returns `None` if + * we are unable to resolve, either because of ambiguity or + * due to insufficient inference. + */ + + let selcx = select::SelectionContext::new(infcx, param_env, + unboxed_closures); + selcx.evaluate_obligation(obligation) +} + +pub fn evaluate_impl(infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap, + cause: ObligationCause, + impl_def_id: ast::DefId, + self_ty: ty::t) + -> EvaluationResult +{ + /*! + * Tests whether the impl `impl_def_id` can be applied to the self + * type `self_ty`. This is similar to "selection", but simpler: + * + * - It does not take a full trait-ref as input, so it skips over + * the "confirmation" step which would reconcile output type + * parameters. + * - It returns an `EvaluationResult`, which is a tri-value return + * (yes/no/unknown). + */ + + let selcx = select::SelectionContext::new(infcx, param_env, unboxed_closures); + selcx.evaluate_impl(impl_def_id, cause, self_ty) +} + +pub fn select_inherent_impl(infcx: &InferCtxt, + param_env: &ty::ParameterEnvironment, + unboxed_closures: &DefIdMap, + cause: ObligationCause, + impl_def_id: ast::DefId, + self_ty: ty::t) + -> SelectionResult> +{ + /*! + * Matches the self type of the inherent impl `impl_def_id` + * against `self_ty` and returns the resulting resolution. This + * routine may modify the surrounding type context (for example, + * it may unify variables). + */ + + // This routine is only suitable for inherent impls. This is + // because it does not attempt to unify the output type parameters + // from the trait ref against the values from the obligation. + // (These things do not apply to inherent impls, for which there + // is no trait ref nor obligation.) + // + // Matching against non-inherent impls should be done with + // `try_resolve_obligation()`. + assert!(ty::impl_trait_ref(infcx.tcx, impl_def_id).is_none()); + + let selcx = select::SelectionContext::new(infcx, param_env, + unboxed_closures); + selcx.select_inherent_impl(impl_def_id, cause, self_ty) +} + +pub fn is_orphan_impl(tcx: &ty::ctxt, + impl_def_id: ast::DefId) + -> bool +{ + /*! + * True if neither the trait nor self type is local. Note that + * `impl_def_id` must refer to an impl of a trait, not an inherent + * impl. + */ + + !coherence::impl_is_local(tcx, impl_def_id) +} + +pub fn overlapping_impls(infcx: &InferCtxt, + impl1_def_id: ast::DefId, + impl2_def_id: ast::DefId) + -> bool +{ + /*! + * True if there exist types that satisfy both of the two given impls. + */ + + coherence::impl_can_satisfy(infcx, impl1_def_id, impl2_def_id) && + coherence::impl_can_satisfy(infcx, impl2_def_id, impl1_def_id) +} + +pub fn obligations_for_generics(tcx: &ty::ctxt, + cause: ObligationCause, + generics: &ty::Generics, + substs: &subst::Substs) + -> subst::VecPerParamSpace +{ + /*! + * Given generics for an impl like: + * + * impl ... + * + * and a substs vector like ``, yields a result like + * + * [[Foo for A0, Bar for B0, Qux for B0], [], []] + */ + + util::obligations_for_generics(tcx, cause, 0, generics, substs) +} + +pub fn obligation_for_builtin_bound(tcx: &ty::ctxt, + cause: ObligationCause, + source_ty: ty::t, + builtin_bound: ty::BuiltinBound) + -> Obligation +{ + util::obligation_for_builtin_bound(tcx, cause, builtin_bound, 0, source_ty) +} + +impl Obligation { + pub fn new(cause: ObligationCause, trait_ref: Rc) -> Obligation { + Obligation { cause: cause, + recursion_depth: 0, + trait_ref: trait_ref } + } + + pub fn misc(span: Span, trait_ref: Rc) -> Obligation { + Obligation::new(ObligationCause::misc(span), trait_ref) + } + + pub fn self_ty(&self) -> ty::t { + self.trait_ref.self_ty() + } +} + +impl ObligationCause { + pub fn new(span: Span, code: ObligationCauseCode) -> ObligationCause { + ObligationCause { span: span, code: code } + } + + pub fn misc(span: Span) -> ObligationCause { + ObligationCause { span: span, code: MiscObligation } + } +} + +impl Vtable { + pub fn map_nested(&self, op: |&N| -> M) -> Vtable { + match *self { + VtableImpl(ref i) => VtableImpl(i.map_nested(op)), + VtableUnboxedClosure(d) => VtableUnboxedClosure(d), + VtableParam(ref p) => VtableParam((*p).clone()), + VtableBuiltin => VtableBuiltin, + } + } + + pub fn map_move_nested(self, op: |N| -> M) -> Vtable { + match self { + VtableImpl(i) => VtableImpl(i.map_move_nested(op)), + VtableUnboxedClosure(d) => VtableUnboxedClosure(d), + VtableParam(p) => VtableParam(p), + VtableBuiltin => VtableBuiltin, + } + } +} + +impl VtableImpl { + pub fn map_nested(&self, + op: |&N| -> M) + -> VtableImpl + { + VtableImpl { + impl_def_id: self.impl_def_id, + substs: self.substs.clone(), + nested: self.nested.map(op) + } + } + + pub fn map_move_nested(self, op: |N| -> M) -> VtableImpl { + let VtableImpl { impl_def_id, substs, nested } = self; + VtableImpl { + impl_def_id: impl_def_id, + substs: substs, + nested: nested.map_move(op) + } + } +} + +impl EvaluationResult { + pub fn potentially_applicable(&self) -> bool { + match *self { + EvaluatedToMatch | EvaluatedToAmbiguity => true, + EvaluatedToUnmatch => false + } + } +} + +impl FulfillmentError { + fn new(obligation: Obligation, code: FulfillmentErrorCode) + -> FulfillmentError + { + FulfillmentError { obligation: obligation, code: code } + } +} diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs new file mode 100644 index 0000000000000..681e2650f39fa --- /dev/null +++ b/src/librustc/middle/traits/select.rs @@ -0,0 +1,1024 @@ +// Copyright 2014 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. + +/*! See `doc.rs` for high-level documentation */ + +use super::{Obligation, ObligationCause}; +use super::{EvaluationResult, EvaluatedToMatch, + EvaluatedToAmbiguity, EvaluatedToUnmatch}; +use super::{SelectionError, Unimplemented, Overflow, + OutputTypeParameterMismatch}; +use super::{Selection}; +use super::{SelectionResult}; +use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure}; +use super::{util}; + +use middle::subst::{Subst, Substs, VecPerParamSpace}; +use middle::ty; +use middle::typeck::check::regionmanip; +use middle::typeck::infer; +use middle::typeck::infer::InferCtxt; +use std::rc::Rc; +use syntax::ast; +use util::nodemap::DefIdMap; +use util::ppaux::Repr; + +pub struct SelectionContext<'cx, 'tcx:'cx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + param_env: &'cx ty::ParameterEnvironment, + unboxed_closures: &'cx DefIdMap, +} + +// pub struct SelectionCache { +// hashmap: RefCell>, +// } + +// #[deriving(Hash,Eq,PartialEq)] +// struct CacheKey { +// trait_def_id: ast::DefId, +// skol_obligation_self_ty: ty::t, +// } + +enum MatchResult { + Matched(T), + AmbiguousMatch, + NoMatch +} + +/** + * The selection process begins by considering all impls, where + * clauses, and so forth that might resolve an obligation. Sometimes + * we'll be able to say definitively that (e.g.) an impl does not + * apply to the obligation: perhaps it is defined for `uint` but the + * obligation is for `int`. In that case, we drop the impl out of the + * list. But the other cases are considered *candidates*. + * + * Candidates can either be definitive or ambiguous. An ambiguous + * candidate is one that might match or might not, depending on how + * type variables wind up being resolved. This only occurs during inference. + * + * For selection to suceed, there must be exactly one non-ambiguous + * candidate. Usually, it is not possible to have more than one + * definitive candidate, due to the coherence rules. However, there is + * one case where it could occur: if there is a blanket impl for a + * trait (that is, an impl applied to all T), and a type parameter + * with a where clause. In that case, we can have a candidate from the + * where clause and a second candidate from the impl. This is not a + * problem because coherence guarantees us that the impl which would + * be used to satisfy the where clause is the same one that we see + * now. To resolve this issue, therefore, we ignore impls if we find a + * matching where clause. Part of the reason for this is that where + * clauses can give additional information (like, the types of output + * parameters) that would have to be inferred from the impl. + */ +#[deriving(Clone)] +enum Candidate { + MatchedBuiltinCandidate, + AmbiguousBuiltinCandidate, + MatchedParamCandidate(VtableParam), + AmbiguousParamCandidate, + Impl(ImplCandidate), + MatchedUnboxedClosureCandidate(/* closure */ ast::DefId) +} + +#[deriving(Clone)] +enum ImplCandidate { + MatchedImplCandidate(ast::DefId), + AmbiguousImplCandidate(ast::DefId), +} + +impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, + param_env: &'cx ty::ParameterEnvironment, + unboxed_closures: &'cx DefIdMap) + -> SelectionContext<'cx, 'tcx> { + SelectionContext { infcx: infcx, param_env: param_env, + unboxed_closures: unboxed_closures } + } + + pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> { + self.infcx.tcx + } + + /////////////////////////////////////////////////////////////////////////// + // Selection + // + // The selection phase tries to identify *how* an obligation will + // be resolved. For example, it will identify which impl or + // parameter bound is to be used. The process can be inconclusive + // if the self type in the obligation is not fully inferred. Selection + // can result in an error in one of two ways: + // + // 1. If no applicable impl or parameter bound can be found. + // 2. If the output type parameters in the obligation do not match + // those specified by the impl/bound. For example, if the obligation + // is `Vec:Iterable`, but the impl specifies + // `impl Iterable for Vec`, than an error would result. + + pub fn select(&self, obligation: &Obligation) -> SelectionResult { + /*! + * Evaluates whether the obligation can be satisfied. Returns + * an indication of whether the obligation can be satisfied + * and, if so, by what means. Never affects surrounding typing + * environment. + */ + + debug!("select({})", obligation.repr(self.tcx())); + + match try!(self.candidate_from_obligation(obligation)) { + None => Ok(None), + Some(candidate) => self.confirm_candidate(obligation, candidate), + } + } + + pub fn select_inherent_impl(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_self_ty: ty::t) + -> SelectionResult> + { + debug!("select_inherent_impl(impl_def_id={}, obligation_self_ty={})", + impl_def_id.repr(self.tcx()), + obligation_self_ty.repr(self.tcx())); + + match self.candidate_from_impl(impl_def_id, + obligation_cause, + obligation_self_ty) { + Some(MatchedImplCandidate(impl_def_id)) => { + let vtable_impl = + try!(self.confirm_inherent_impl_candidate( + impl_def_id, + obligation_cause, + obligation_self_ty, + 0)); + Ok(Some(vtable_impl)) + } + Some(AmbiguousImplCandidate(_)) => { + Ok(None) + } + None => { + Err(Unimplemented) + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // EVALUATION + // + // Tests whether an obligation can be selected or whether an impl can be + // applied to particular types. It skips the "confirmation" step and + // hence completely ignores output type parameters. + + pub fn evaluate_obligation(&self, + obligation: &Obligation) + -> EvaluationResult + { + /*! + * Evaluates whether the obligation `obligation` can be + * satisfied (by any means). + */ + + debug!("evaluate_obligation({})", + obligation.repr(self.tcx())); + + match self.candidate_from_obligation(obligation) { + Ok(Some(c)) => c.to_evaluation_result(), + Ok(None) => EvaluatedToAmbiguity, + Err(_) => EvaluatedToUnmatch, + } + } + + pub fn evaluate_impl(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_self_ty: ty::t) + -> EvaluationResult + { + /*! + * Evaluates whether the impl with id `impl_def_id` could be + * applied to the self type `obligation_self_ty`. This can be + * used either for trait or inherent impls. + */ + + debug!("evaluate_impl(impl_def_id={}, obligation_self_ty={})", + impl_def_id.repr(self.tcx()), + obligation_self_ty.repr(self.tcx())); + + match self.candidate_from_impl(impl_def_id, + obligation_cause, + obligation_self_ty) { + Some(c) => c.to_evaluation_result(), + None => EvaluatedToUnmatch, + } + } + + /////////////////////////////////////////////////////////////////////////// + // CANDIDATE ASSEMBLY + // + // The selection process begins by examining all in-scope impls, + // caller obligations, and so forth and assembling a list of + // candidates. See `doc.rs` and the `Candidate` type for more details. + + fn candidate_from_obligation(&self, obligation: &Obligation) + -> SelectionResult + { + debug!("candidate_from_obligation({}, self_ty={})", + obligation.repr(self.tcx()), + self.infcx.ty_to_string(obligation.self_ty())); + + let skol_obligation_self_ty = + infer::skolemize(self.infcx, obligation.self_ty()); + + // First, check the cache. + match self.check_candidate_cache(obligation, skol_obligation_self_ty) { + Some(c) => { + return Ok(Some(c)); + } + None => { } + } + + let mut candidates = + try!(self.assemble_candidates(obligation, + skol_obligation_self_ty)); + + debug!("candidate_from_obligation: {} candidates for {}", + candidates.len(), obligation.repr(self.tcx())); + + // Examine candidates to determine outcome. Ideally we will + // have exactly one candidate that is definitively applicable. + + if candidates.len() == 0 { + // Annoying edge case: if there are no impls, then there + // is no way that this trait reference is implemented, + // *unless* it contains unbound variables. In that case, + // it is possible that one of those unbound variables will + // be bound to a new type from some other crate which will + // also contain impls. + let trait_ref = &*obligation.trait_ref; + return if !self.trait_ref_unconstrained(trait_ref) { + debug!("candidate_from_obligation({}) -> 0 matches, unimpl", + obligation.repr(self.tcx())); + Err(Unimplemented) + } else { + debug!("candidate_from_obligation({}) -> 0 matches, ambig", + obligation.repr(self.tcx())); + Ok(None) + }; + } + + if candidates.len() > 1 { + // Ambiguity. Possibly we should report back more + // information on the potential candidates so we can give + // a better error message. + debug!("candidate_from_obligation({}) -> multiple matches, ambig", + obligation.repr(self.tcx())); + + return Ok(None); + } + + let candidate = candidates.pop().unwrap(); + self.insert_candidate_cache(obligation, skol_obligation_self_ty, + candidate.clone()); + Ok(Some(candidate)) + } + + fn check_candidate_cache(&self, + _obligation: &Obligation, + _skol_obligation_self_ty: ty::t) + -> Option + { + // let cache_key = CacheKey::new(obligation.trait_ref.def_id, + // skol_obligation_self_ty); + // let hashmap = self.tcx().selection_cache.hashmap.borrow(); + // hashmap.find(&cache_key).map(|c| (*c).clone()) + None + } + + fn insert_candidate_cache(&self, + _obligation: &Obligation, + _skol_obligation_self_ty: ty::t, + _candidate: Candidate) + { + // FIXME -- Enable caching. I think the right place to put the cache + // is in the ParameterEnvironment, not the tcx, because otherwise + // when there are distinct where clauses in scope the cache can get + // confused. + // + //let cache_key = CacheKey::new(obligation.trait_ref.def_id, + // skol_obligation_self_ty); + //let mut hashmap = self.tcx().selection_cache.hashmap.borrow_mut(); + //hashmap.insert(cache_key, candidate); + } + + fn assemble_candidates(&self, + obligation: &Obligation, + skol_obligation_self_ty: ty::t) + -> Result, SelectionError> + { + // Check for overflow. + + let recursion_limit = self.infcx.tcx.sess.recursion_limit.get(); + if obligation.recursion_depth >= recursion_limit { + debug!("{} --> overflow", obligation.repr(self.tcx())); + return Err(Overflow); + } + + let mut candidates = Vec::new(); + + match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id) { + Some(_) => { + // FIXME -- The treatment of builtin bounds is a bit + // hacky right now. Eventually, the idea is to move + // the logic for selection out of type_contents and + // into this module (And make it based on the generic + // mechanisms of OIBTT2). However, I want to land + // some code today, so we're going to cut a few + // corners. What we do now is that the trait selection + // code always considers builtin obligations to + // match. The fulfillment code (which also has the job + // of tracking all the traits that must hold) will + // then just accumulate the various + // builtin-bound-related obligations that must be met. + // Later, at the end of typeck, after writeback etc, + // we will rewalk this list and extract all the + // builtin-bound-related obligations and test them + // again using type contents. Part of the motivation + // for this is that the type contents code requires + // that writeback has been completed in some cases. + + candidates.push(AmbiguousBuiltinCandidate); + } + + None => { + // Other bounds. Consider both in-scope bounds from fn decl + // and applicable impls. + + try!(self.assemble_candidates_from_caller_bounds( + obligation, + skol_obligation_self_ty, + &mut candidates)); + + try!(self.assemble_unboxed_candidates( + obligation, + skol_obligation_self_ty, + &mut candidates)); + + // If there is a fn bound that applies, forego the + // impl search. It can only generate conflicts. + + if candidates.len() == 0 { + try!(self.assemble_candidates_from_impls( + obligation, + skol_obligation_self_ty, + &mut candidates)); + } + } + } + + Ok(candidates) + } + + fn assemble_candidates_from_caller_bounds(&self, + obligation: &Obligation, + skol_obligation_self_ty: ty::t, + candidates: &mut Vec) + -> Result<(),SelectionError> + { + /*! + * Given an obligation like ``, search the obligations + * that the caller supplied to find out whether it is listed among + * them. + * + * Never affects inference environment. +v */ + + debug!("assemble_candidates_from_caller_bounds({})", + obligation.repr(self.tcx())); + + for caller_obligation in self.param_env.caller_obligations.iter() { + debug!("caller_obligation={}", + caller_obligation.repr(self.tcx())); + + // Skip over obligations that don't apply to + // `self_ty`. + let caller_bound = &caller_obligation.trait_ref; + let caller_self_ty = caller_bound.substs.self_ty().unwrap(); + match self.match_self_types(obligation.cause, + caller_self_ty, + skol_obligation_self_ty) { + AmbiguousMatch => { + debug!("-> AmbiguousParamCandidate"); + candidates.push(AmbiguousParamCandidate); + return Ok(()); + } + NoMatch => { + continue; + } + Matched(()) => { } + } + + // Search through the trait (and its supertraits) to + // see if it matches the def-id we are looking for. + let caller_bound = (*caller_bound).clone(); + match util::search_trait_and_supertraits_from_bound( + self.infcx.tcx, caller_bound, + |d| d == obligation.trait_ref.def_id) + { + Some(vtable_param) => { + // If so, we're done! + debug!("-> MatchedParamCandidate({})", vtable_param); + candidates.push(MatchedParamCandidate(vtable_param)); + return Ok(()); + } + + None => { + } + } + } + + Ok(()) + } + + fn assemble_unboxed_candidates(&self, + obligation: &Obligation, + skol_obligation_self_ty: ty::t, + candidates: &mut Vec) + -> Result<(),SelectionError> + { + /*! + * Check for the artificial impl that the compiler will create + * for an obligation like `X : FnMut<..>` where `X` is an + * unboxed closure type. + */ + + let closure_def_id = match ty::get(skol_obligation_self_ty).sty { + ty::ty_unboxed_closure(id, _) => id, + _ => { return Ok(()); } + }; + + let tcx = self.tcx(); + let fn_traits = [ + (ty::FnUnboxedClosureKind, tcx.lang_items.fn_trait()), + (ty::FnMutUnboxedClosureKind, tcx.lang_items.fn_mut_trait()), + (ty::FnOnceUnboxedClosureKind, tcx.lang_items.fn_once_trait()), + ]; + for tuple in fn_traits.iter() { + let kind = match tuple { + &(kind, Some(ref fn_trait)) + if *fn_trait == obligation.trait_ref.def_id => + { + kind + } + _ => continue, + }; + + // Check to see whether the argument and return types match. + let closure_kind = match self.unboxed_closures.find(&closure_def_id) { + Some(closure) => closure.kind, + None => { + self.tcx().sess.span_bug( + obligation.cause.span, + format!("No entry for unboxed closure: {}", + closure_def_id.repr(self.tcx())).as_slice()); + } + }; + + if closure_kind != kind { + continue; + } + + candidates.push(MatchedUnboxedClosureCandidate(closure_def_id)); + } + + Ok(()) + } + + fn assemble_candidates_from_impls(&self, + obligation: &Obligation, + skol_obligation_self_ty: ty::t, + candidates: &mut Vec) + -> Result<(), SelectionError> + { + /*! + * Search for impls that might apply to `obligation`. + */ + + let all_impls = self.all_impls(obligation.trait_ref.def_id); + for &impl_def_id in all_impls.iter() { + self.infcx.probe(|| { + match self.candidate_from_impl(impl_def_id, + obligation.cause, + skol_obligation_self_ty) { + Some(c) => { + candidates.push(Impl(c)); + } + + None => { } + } + }); + } + Ok(()) + } + + fn candidate_from_impl(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + skol_obligation_self_ty: ty::t) + -> Option + { + match self.match_impl_self_types(impl_def_id, + obligation_cause, + skol_obligation_self_ty) { + Matched(_) => { + Some(MatchedImplCandidate(impl_def_id)) + } + + AmbiguousMatch => { + Some(AmbiguousImplCandidate(impl_def_id)) + } + + NoMatch => { + None + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // CONFIRMATION + // + // Confirmation unifies the output type parameters of the trait + // with the values found in the obligation, possibly yielding a + // type error. See `doc.rs` for more details. + + fn confirm_candidate(&self, + obligation: &Obligation, + candidate: Candidate) + -> SelectionResult + { + debug!("confirm_candidate({}, {})", + obligation.repr(self.tcx()), + candidate.repr(self.tcx())); + + match candidate { + AmbiguousBuiltinCandidate | + AmbiguousParamCandidate | + Impl(AmbiguousImplCandidate(_)) => { + Ok(None) + } + + MatchedBuiltinCandidate => { + Ok(Some(VtableBuiltin)) + } + + MatchedParamCandidate(param) => { + Ok(Some(VtableParam( + try!(self.confirm_param_candidate(obligation, param))))) + } + + Impl(MatchedImplCandidate(impl_def_id)) => { + let vtable_impl = try!(self.confirm_impl_candidate(obligation, + impl_def_id)); + Ok(Some(VtableImpl(vtable_impl))) + } + + MatchedUnboxedClosureCandidate(closure_def_id) => { + try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id)); + Ok(Some(VtableUnboxedClosure(closure_def_id))) + } + } + } + + fn confirm_param_candidate(&self, + obligation: &Obligation, + param: VtableParam) + -> Result + { + debug!("confirm_param_candidate({},{})", + obligation.repr(self.tcx()), + param.repr(self.tcx())); + + let () = try!(self.confirm(obligation.cause, + obligation.trait_ref.clone(), + param.bound.clone())); + Ok(param) + } + + fn confirm_impl_candidate(&self, + obligation: &Obligation, + impl_def_id: ast::DefId) + -> Result,SelectionError> + { + debug!("confirm_impl_candidate({},{})", + obligation.repr(self.tcx()), + impl_def_id.repr(self.tcx())); + + // For a non-inhernet impl, we begin the same way as an + // inherent impl, by matching the self-type and assembling + // list of nested obligations. + let vtable_impl = + try!(self.confirm_inherent_impl_candidate( + impl_def_id, + obligation.cause, + obligation.trait_ref.self_ty(), + obligation.recursion_depth)); + + // But then we must also match the output types. + let () = try!(self.confirm_impl_vtable(impl_def_id, + obligation.cause, + obligation.trait_ref.clone(), + &vtable_impl.substs)); + Ok(vtable_impl) + } + + fn confirm_inherent_impl_candidate(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_self_ty: ty::t, + obligation_recursion_depth: uint) + -> Result, + SelectionError> + { + let substs = match self.match_impl_self_types(impl_def_id, + obligation_cause, + obligation_self_ty) { + Matched(substs) => substs, + AmbiguousMatch | NoMatch => { + self.tcx().sess.bug( + format!("Impl {} was matchable against {} but now is not", + impl_def_id.repr(self.tcx()), + obligation_self_ty.repr(self.tcx())) + .as_slice()); + } + }; + + let impl_obligations = + self.impl_obligations(obligation_cause, + obligation_recursion_depth, + impl_def_id, + &substs); + let vtable_impl = VtableImpl { impl_def_id: impl_def_id, + substs: substs, + nested: impl_obligations }; + + Ok(vtable_impl) + } + + fn confirm_unboxed_closure_candidate(&self, + obligation: &Obligation, + closure_def_id: ast::DefId) + -> Result<(),SelectionError> + { + debug!("confirm_unboxed_closure_candidate({},{})", + obligation.repr(self.tcx()), + closure_def_id.repr(self.tcx())); + + let closure_type = match self.unboxed_closures.find(&closure_def_id) { + Some(closure) => closure.closure_type.clone(), + None => { + self.tcx().sess.span_bug( + obligation.cause.span, + format!("No entry for unboxed closure: {}", + closure_def_id.repr(self.tcx())).as_slice()); + } + }; + + // FIXME(pcwalton): This is a bogus thing to do, but + // it'll do for now until we get the new trait-bound + // region skolemization working. + let (_, new_signature) = + regionmanip::replace_late_bound_regions_in_fn_sig( + self.tcx(), + &closure_type.sig, + |br| self.infcx.next_region_var( + infer::LateBoundRegion(obligation.cause.span, br))); + + let arguments_tuple = *new_signature.inputs.get(0); + let trait_ref = Rc::new(ty::TraitRef { + def_id: obligation.trait_ref.def_id, + substs: Substs::new_trait( + vec![arguments_tuple, new_signature.output], + vec![], + obligation.self_ty()) + }); + + self.confirm(obligation.cause, + obligation.trait_ref.clone(), + trait_ref) + } + + /////////////////////////////////////////////////////////////////////////// + // Matching + // + // Matching is a common path used for both evaluation and + // confirmation. It basically unifies types that appear in impls + // and traits. This does affect the surrounding environment; + // therefore, when used during evaluation, match routines must be + // run inside of a `probe()` so that their side-effects are + // contained. + + fn match_impl_self_types(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_self_ty: ty::t) + -> MatchResult + { + /*! + * Determines whether the self type declared against + * `impl_def_id` matches `obligation_self_ty`. If successful, + * returns the substitutions used to make them match. See + * `match_impl()`. For example, if `impl_def_id` is declared + * as: + * + * impl Foo for ~T { ... } + * + * and `obligation_self_ty` is `int`, we'd back an `Err(_)` + * result. But if `obligation_self_ty` were `~int`, we'd get + * back `Ok(T=int)`. + */ + + // Create fresh type variables for each type parameter declared + // on the impl etc. + let impl_substs = util::fresh_substs_for_impl(self.infcx, + obligation_cause.span, + impl_def_id); + + // Find the self type for the impl. + let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty; + let impl_self_ty = impl_self_ty.subst(self.tcx(), &impl_substs); + + debug!("match_impl_self_types(obligation_self_ty={}, impl_self_ty={})", + obligation_self_ty.repr(self.tcx()), + impl_self_ty.repr(self.tcx())); + + match self.match_self_types(obligation_cause, + impl_self_ty, + obligation_self_ty) { + Matched(()) => { + debug!("Matched impl_substs={}", impl_substs.repr(self.tcx())); + Matched(impl_substs) + } + AmbiguousMatch => { + debug!("AmbiguousMatch"); + AmbiguousMatch + } + NoMatch => { + debug!("NoMatch"); + NoMatch + } + } + } + + fn match_self_types(&self, + cause: ObligationCause, + + // The self type provided by the impl/caller-obligation: + provided_self_ty: ty::t, + + // The self type the obligation is for: + required_self_ty: ty::t) + -> MatchResult<()> + { + // FIXME(#5781) -- equating the types is stronger than + // necessary. Should consider variance of trait w/r/t Self. + + let origin = infer::RelateSelfType(cause.span); + match self.infcx.eq_types(false, + origin, + provided_self_ty, + required_self_ty) { + Ok(()) => Matched(()), + Err(ty::terr_sorts(ty::expected_found{expected: t1, found: t2})) => { + // This error occurs when there is an unresolved type + // variable in the `required_self_ty` that was forced + // to unify with a non-type-variable. That basically + // means we don't know enough to say with certainty + // whether there is a match or not -- it depends on + // how that type variable is ultimately resolved. + if ty::type_is_skolemized(t1) || ty::type_is_skolemized(t2) { + AmbiguousMatch + } else { + NoMatch + } + } + Err(_) => NoMatch, + } + } + + /////////////////////////////////////////////////////////////////////////// + // Confirmation + // + // The final step of selection: once we know how an obligation is + // is resolved, we confirm that selection in order to have + // side-effects on the typing environment. This step also unifies + // the output type parameters from the obligation with those found + // on the impl/bound, which may yield type errors. + + fn confirm_impl_vtable(&self, + impl_def_id: ast::DefId, + obligation_cause: ObligationCause, + obligation_trait_ref: Rc, + substs: &Substs) + -> Result<(), SelectionError> + { + /*! + * Relates the output type parameters from an impl to the + * trait. This may lead to type errors. The confirmation step + * is separated from the main match procedure because these + * type errors do not cause us to select another impl. + * + * As an example, consider matching the obligation + * `Iterator for Elems` using the following impl: + * + * impl Iterator for Elems { ... } + * + * The match phase will succeed with substitution `T=int`. + * The confirm step will then try to unify `int` and `char` + * and yield an error. + */ + + let impl_trait_ref = ty::impl_trait_ref(self.tcx(), + impl_def_id).unwrap(); + let impl_trait_ref = impl_trait_ref.subst(self.tcx(), + substs); + self.confirm(obligation_cause, obligation_trait_ref, impl_trait_ref) + } + + fn confirm(&self, + obligation_cause: ObligationCause, + obligation_trait_ref: Rc, + expected_trait_ref: Rc) + -> Result<(), SelectionError> + { + /*! + * After we have determined which impl applies, and with what + * substitutions, there is one last step. We have to go back + * and relate the "output" type parameters from the obligation + * to the types that are specified in the impl. + * + * For example, imagine we have: + * + * impl Iterator for Vec { ... } + * + * and our obligation is `Iterator for Vec` (note + * the mismatch in the obligation types). Up until this step, + * no error would be reported: the self type is `Vec`, + * and that matches `Vec` with the substitution `T=int`. + * At this stage, we could then go and check that the type + * parameters to the `Iterator` trait match. + * (In terms of the parameters, the `expected_trait_ref` + * here would be `Iterator for Vec`, and the + * `obligation_trait_ref` would be `Iterator for Vec`. + * + * Note that this checking occurs *after* the impl has + * selected, because these output type parameters should not + * affect the selection of the impl. Therefore, if there is a + * mismatch, we report an error to the user. + */ + + let origin = infer::RelateOutputImplTypes(obligation_cause.span); + + let obligation_trait_ref = obligation_trait_ref.clone(); + match self.infcx.sub_trait_refs(false, + origin, + expected_trait_ref.clone(), + obligation_trait_ref) { + Ok(()) => Ok(()), + Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, e)) + } + } + + /////////////////////////////////////////////////////////////////////////// + // Miscellany + + fn all_impls(&self, trait_def_id: ast::DefId) -> Vec { + /*! + * Returns se tof all impls for a given trait. + */ + + ty::populate_implementations_for_trait_if_necessary(self.tcx(), + trait_def_id); + match self.tcx().trait_impls.borrow().find(&trait_def_id) { + None => Vec::new(), + Some(impls) => impls.borrow().clone() + } + } + + fn impl_obligations(&self, + cause: ObligationCause, + recursion_depth: uint, + impl_def_id: ast::DefId, + impl_substs: &Substs) + -> VecPerParamSpace + { + let impl_generics = ty::lookup_item_type(self.tcx(), + impl_def_id).generics; + util::obligations_for_generics(self.tcx(), cause, recursion_depth, + &impl_generics, impl_substs) + } + + fn trait_ref_unconstrained(&self, + trait_ref: &ty::TraitRef) + -> bool + { + /*! + * True if the self type of the trait-ref contains + * unconstrained type variables. + */ + + let mut found_skol = false; + + // Skolemization replaces all unconstrained type vars with + // a SkolemizedTy instance. Then we search to see if we + // found any. + let skol_ty = infer::skolemize(self.infcx, trait_ref.self_ty()); + ty::walk_ty(skol_ty, |t| { + match ty::get(t).sty { + ty::ty_infer(ty::SkolemizedTy(_)) => { found_skol = true; } + _ => { } + } + }); + + found_skol + } +} + +impl Candidate { + fn to_evaluation_result(&self) -> EvaluationResult { + match *self { + Impl(ref i) => i.to_evaluation_result(), + + MatchedUnboxedClosureCandidate(..) | + MatchedBuiltinCandidate | + MatchedParamCandidate(..) => { + EvaluatedToMatch + } + + AmbiguousBuiltinCandidate | + AmbiguousParamCandidate => { + EvaluatedToAmbiguity + } + } + } +} + +impl ImplCandidate { + fn to_evaluation_result(&self) -> EvaluationResult { + match *self { + MatchedImplCandidate(..) => EvaluatedToMatch, + AmbiguousImplCandidate(..) => EvaluatedToAmbiguity + } + } +} + +impl Repr for Candidate { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + MatchedBuiltinCandidate => format!("MatchedBuiltinCandidate"), + AmbiguousBuiltinCandidate => format!("AmbiguousBuiltinCandidate"), + MatchedUnboxedClosureCandidate(c) => format!("MatchedUnboxedClosureCandidate({})", c), + MatchedParamCandidate(ref r) => format!("MatchedParamCandidate({})", + r.repr(tcx)), + AmbiguousParamCandidate => format!("AmbiguousParamCandidate"), + Impl(ref i) => i.repr(tcx) + } + } +} + +impl Repr for ImplCandidate { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + MatchedImplCandidate(ref d) => format!("MatchedImplCandidate({})", + d.repr(tcx)), + AmbiguousImplCandidate(ref d) => format!("AmbiguousImplCandidate({})", + d.repr(tcx)), + } + } +} + + +// impl SelectionCache { +// pub fn new() -> SelectionCache { +// SelectionCache { +// hashmap: RefCell::new(HashMap::new()) +// } +// } +// } + +// impl CacheKey { +// pub fn new(trait_def_id: ast::DefId, +// skol_obligation_self_ty: ty::t) +// -> CacheKey +// { +// CacheKey { +// trait_def_id: trait_def_id, +// skol_obligation_self_ty: skol_obligation_self_ty +// } +// } +// } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs new file mode 100644 index 0000000000000..11b954f2ba6af --- /dev/null +++ b/src/librustc/middle/traits/util.rs @@ -0,0 +1,356 @@ + +// Copyright 2014 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. + +use middle::subst; +use middle::subst::{ParamSpace, Subst, Substs, VecPerParamSpace}; +use middle::typeck::infer::InferCtxt; +use middle::ty; +use std::fmt; +use std::rc::Rc; +use syntax::ast; +use syntax::codemap::Span; +use util::ppaux::Repr; + +use super::{Obligation, ObligationCause, VtableImpl, VtableParam}; + +/////////////////////////////////////////////////////////////////////////// +// Supertrait iterator + +pub struct Supertraits<'cx, 'tcx:'cx> { + tcx: &'cx ty::ctxt<'tcx>, + stack: Vec, +} + +struct SupertraitEntry { + position: uint, + supertraits: Vec>, +} + +pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, + trait_ref: Rc) + -> Supertraits<'cx, 'tcx> +{ + /*! + * Returns an iterator over the trait reference `T` and all of its + * supertrait references. May contain duplicates. In general + * the ordering is not defined. + * + * Example: + * + * ``` + * trait Foo { ... } + * trait Bar : Foo { ... } + * trait Baz : Bar+Foo { ... } + * ``` + * + * `supertraits(Baz)` yields `[Baz, Bar, Foo, Foo]` in some order. + */ + + transitive_bounds(tcx, [trait_ref]) +} + +pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, + bounds: &[Rc]) + -> Supertraits<'cx, 'tcx> +{ + let bounds = Vec::from_fn(bounds.len(), |i| bounds[i].clone()); + let entry = SupertraitEntry { position: 0, supertraits: bounds }; + Supertraits { tcx: tcx, stack: vec![entry] } +} + +impl<'cx, 'tcx> Supertraits<'cx, 'tcx> { + fn push(&mut self, trait_ref: &ty::TraitRef) { + let bounds = ty::bounds_for_trait_ref(self.tcx, trait_ref); + let entry = SupertraitEntry { position: 0, + supertraits: bounds.trait_bounds }; + self.stack.push(entry); + } + + pub fn indices(&self) -> Vec { + /*! + * Returns the path taken through the trait supertraits to + * reach the current point. + */ + + self.stack.iter().map(|e| e.position).collect() + } +} + +impl<'cx, 'tcx> Iterator> for Supertraits<'cx, 'tcx> { + fn next(&mut self) -> Option> { + loop { + // Extract next item from top-most stack frame, if any. + let next_trait = match self.stack.mut_last() { + None => { + // No more stack frames. Done. + return None; + } + Some(entry) => { + let p = entry.position; + if p < entry.supertraits.len() { + // Still more supertraits left in the top stack frame. + entry.position += 1; + + let next_trait = + (*entry.supertraits.get(p)).clone(); + Some(next_trait) + } else { + None + } + } + }; + + match next_trait { + Some(next_trait) => { + self.push(&*next_trait); + return Some(next_trait); + } + + None => { + // Top stack frame is exhausted, pop it. + self.stack.pop(); + } + } + } + } +} + +// determine the `self` type, using fresh variables for all variables +// declared on the impl declaration e.g., `impl for ~[(A,B)]` +// would return ($0, $1) where $0 and $1 are freshly instantiated type +// variables. +pub fn fresh_substs_for_impl(infcx: &InferCtxt, + span: Span, + impl_def_id: ast::DefId) + -> Substs +{ + let tcx = infcx.tcx; + let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; + infcx.fresh_substs_for_generics(span, &impl_generics) +} + +impl fmt::Show for VtableImpl { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableImpl({})", self.impl_def_id) + } +} + +impl fmt::Show for VtableParam { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableParam(...)") + } +} + +pub fn obligations_for_generics(tcx: &ty::ctxt, + cause: ObligationCause, + recursion_depth: uint, + generics: &ty::Generics, + substs: &Substs) + -> VecPerParamSpace +{ + /*! See `super::obligations_for_generics` */ + + debug!("obligations_for_generics(generics={}, substs={})", + generics.repr(tcx), substs.repr(tcx)); + + let mut obligations = VecPerParamSpace::empty(); + + for def in generics.types.iter() { + push_obligations_for_param_bounds(tcx, + cause, + recursion_depth, + def.space, + def.index, + &def.bounds, + substs, + &mut obligations); + } + + debug!("obligations() ==> {}", obligations.repr(tcx)); + + return obligations; +} + +fn push_obligations_for_param_bounds( + tcx: &ty::ctxt, + cause: ObligationCause, + recursion_depth: uint, + space: subst::ParamSpace, + index: uint, + param_bounds: &ty::ParamBounds, + param_substs: &Substs, + obligations: &mut VecPerParamSpace) +{ + let param_ty = *param_substs.types.get(space, index); + + for builtin_bound in param_bounds.builtin_bounds.iter() { + obligations.push( + space, + obligation_for_builtin_bound(tcx, + cause, + builtin_bound, + recursion_depth, + param_ty)); + } + + for bound_trait_ref in param_bounds.trait_bounds.iter() { + let bound_trait_ref = bound_trait_ref.subst(tcx, param_substs); + obligations.push( + space, + Obligation { cause: cause, + recursion_depth: recursion_depth, + trait_ref: bound_trait_ref }); + } +} + +pub fn obligation_for_builtin_bound( + tcx: &ty::ctxt, + cause: ObligationCause, + builtin_bound: ty::BuiltinBound, + recursion_depth: uint, + param_ty: ty::t) + -> Obligation +{ + match tcx.lang_items.from_builtin_kind(builtin_bound) { + Ok(def_id) => { + Obligation { + cause: cause, + recursion_depth: recursion_depth, + trait_ref: Rc::new(ty::TraitRef { + def_id: def_id, + substs: Substs::empty().with_self_ty(param_ty), + }), + } + } + Err(e) => { + tcx.sess.span_bug(cause.span, e.as_slice()); + } + } +} + +pub fn search_trait_and_supertraits_from_bound(tcx: &ty::ctxt, + caller_bound: Rc, + test: |ast::DefId| -> bool) + -> Option +{ + /*! + * Starting from a caller obligation `caller_bound` (which has + * coordinates `space`/`i` in the list of caller obligations), + * search through the trait and supertraits to find one where + * `test(d)` is true, where `d` is the def-id of the + * trait/supertrait. If any is found, return `Some(p)` where `p` + * is the path to that trait/supertrait. Else `None`. + */ + + for (bound_index, bound) in + transitive_bounds(tcx, &[caller_bound]).enumerate() + { + if test(bound.def_id) { + let vtable_param = VtableParam { bound: bound }; + return Some(vtable_param); + } + } + + return None; +} + +impl Repr for super::Obligation { + fn repr(&self, tcx: &ty::ctxt) -> String { + format!("Obligation(trait_ref={},depth={})", + self.trait_ref.repr(tcx), + self.recursion_depth) + } +} + +impl Repr for super::Vtable { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + super::VtableImpl(ref v) => + v.repr(tcx), + + super::VtableUnboxedClosure(ref d) => + format!("VtableUnboxedClosure({})", + d.repr(tcx)), + + super::VtableParam(ref v) => + format!("VtableParam({})", v.repr(tcx)), + + super::VtableBuiltin => + format!("Builtin"), + } + } +} + +impl Repr for super::VtableImpl { + fn repr(&self, tcx: &ty::ctxt) -> String { + format!("VtableImpl(impl_def_id={}, substs={}, nested={})", + self.impl_def_id.repr(tcx), + self.substs.repr(tcx), + self.nested.repr(tcx)) + } +} + +impl Repr for super::VtableParam { + fn repr(&self, tcx: &ty::ctxt) -> String { + format!("VtableParam(bound={})", + self.bound.repr(tcx)) + } +} + +impl Repr for super::SelectionError { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + super::Unimplemented => + format!("Unimplemented"), + + super::Overflow => + format!("Overflow"), + + super::OutputTypeParameterMismatch(ref t, ref e) => + format!("OutputTypeParameterMismatch({}, {})", + t.repr(tcx), + e.repr(tcx)), + } + } +} + +impl Repr for super::FulfillmentError { + fn repr(&self, tcx: &ty::ctxt) -> String { + format!("FulfillmentError({},{})", + self.obligation.repr(tcx), + self.code.repr(tcx)) + } +} + +impl Repr for super::FulfillmentErrorCode { + fn repr(&self, tcx: &ty::ctxt) -> String { + match *self { + super::SelectionError(ref o) => o.repr(tcx), + super::Ambiguity => format!("Ambiguity") + } + } +} + +impl fmt::Show for super::FulfillmentErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + super::SelectionError(ref e) => write!(f, "{}", e), + super::Ambiguity => write!(f, "Ambiguity") + } + } +} + +impl Repr for ty::type_err { + fn repr(&self, tcx: &ty::ctxt) -> String { + ty::type_err_to_str(tcx, self) + } +} + diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index e86df86511870..0230668b15aec 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -75,7 +75,6 @@ use middle::trans::type_of; use middle::trans::type_of::*; use middle::trans::value::Value; use middle::ty; -use middle::typeck; use util::common::indenter; use util::ppaux::{Repr, ty_to_string}; use util::sha2::Sha256; @@ -547,8 +546,7 @@ pub fn get_res_dtor(ccx: &CrateContext, // Since we're in trans we don't care for any region parameters let ref substs = subst::Substs::erased(substs.types.clone()); - let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx(), did.node, substs); - let (val, _) = monomorphize::monomorphic_fn(ccx, did, substs, vtables, None); + let (val, _) = monomorphize::monomorphic_fn(ccx, did, substs, None); val } else if did.krate == ast::LOCAL_CRATE { diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 878d95773ada5..ef98a73430264 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -25,7 +25,7 @@ use llvm; use metadata::csearch; use middle::def; use middle::subst; -use middle::subst::{Subst, VecPerParamSpace}; +use middle::subst::{Subst}; use middle::trans::adt; use middle::trans::base; use middle::trans::base::*; @@ -47,7 +47,6 @@ use middle::trans::monomorphize; use middle::trans::type_::Type; use middle::trans::type_of; use middle::ty; -use middle::typeck; use middle::typeck::coherence::make_substs_for_receiver_types; use middle::typeck::MethodCall; use util::ppaux::Repr; @@ -227,61 +226,27 @@ pub fn trans_fn_ref(bcx: Block, def_id: ast::DefId, node: ExprOrMethodCall) -> V let _icx = push_ctxt("trans_fn_ref"); let substs = node_id_substs(bcx, node); - let vtable_key = match node { - ExprId(id) => MethodCall::expr(id), - MethodCall(method_call) => method_call - }; - let vtables = node_vtables(bcx, vtable_key); - debug!("trans_fn_ref(def_id={}, node={:?}, substs={}, vtables={})", + debug!("trans_fn_ref(def_id={}, node={:?}, substs={})", def_id.repr(bcx.tcx()), node, - substs.repr(bcx.tcx()), - vtables.repr(bcx.tcx())); - trans_fn_ref_with_vtables(bcx, def_id, node, substs, vtables) + substs.repr(bcx.tcx())); + trans_fn_ref_with_substs(bcx, def_id, node, substs) } -fn trans_fn_ref_with_vtables_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - def_id: ast::DefId, - ref_id: ast::NodeId, - substs: subst::Substs, - vtables: typeck::vtable_res) - -> Callee<'blk, 'tcx> { +fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + def_id: ast::DefId, + ref_id: ast::NodeId, + substs: subst::Substs) + -> Callee<'blk, 'tcx> { Callee { bcx: bcx, - data: Fn(trans_fn_ref_with_vtables(bcx, - def_id, - ExprId(ref_id), - substs, - vtables)), + data: Fn(trans_fn_ref_with_substs(bcx, + def_id, + ExprId(ref_id), + substs)), } } -fn resolve_default_method_vtables(bcx: Block, - impl_id: ast::DefId, - substs: &subst::Substs, - impl_vtables: typeck::vtable_res) - -> typeck::vtable_res -{ - // Get the vtables that the impl implements the trait at - let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id); - - // Build up a param_substs that we are going to resolve the - // trait_vtables under. - let param_substs = param_substs { - substs: (*substs).clone(), - vtables: impl_vtables.clone() - }; - - let mut param_vtables = resolve_vtables_under_param_substs( - bcx.tcx(), ¶m_substs, &impl_res); - - // Now we pull any vtables for parameters on the actual method. - param_vtables.push_all(subst::FnSpace, - impl_vtables.get_slice(subst::FnSpace)); - - param_vtables -} - /// Translates the adapter that deconstructs a `Box` object into /// `Trait` so that a by-value self method can be called. pub fn trans_unboxing_shim(bcx: Block, @@ -408,12 +373,11 @@ pub fn trans_unboxing_shim(bcx: Block, llfn } -pub fn trans_fn_ref_with_vtables( +pub fn trans_fn_ref_with_substs( bcx: Block, // def_id: ast::DefId, // def id of fn node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A - substs: subst::Substs, // values for fn's ty params - vtables: typeck::vtable_res) // vtables for the call + substs: subst::Substs) // vtables for the call -> ValueRef { /*! @@ -428,20 +392,18 @@ pub fn trans_fn_ref_with_vtables( * This parameter may be zero; but, if so, the resulting value may not * have the right type, so it must be cast before being used. * - `substs`: values for each of the fn/method's parameters - * - `vtables`: values for each bound on each of the type parameters */ - let _icx = push_ctxt("trans_fn_ref_with_vtables"); + let _icx = push_ctxt("trans_fn_ref_with_substs"); let ccx = bcx.ccx(); let tcx = bcx.tcx(); - debug!("trans_fn_ref_with_vtables(bcx={}, def_id={}, node={:?}, \ - substs={}, vtables={})", + debug!("trans_fn_ref_with_substs(bcx={}, def_id={}, node={:?}, \ + substs={})", bcx.to_str(), def_id.repr(tcx), node, - substs.repr(tcx), - vtables.repr(tcx)); + substs.repr(tcx)); assert!(substs.types.all(|t| !ty::type_needs_infer(*t))); @@ -456,9 +418,8 @@ pub fn trans_fn_ref_with_vtables( // We need to do a bunch of special handling for default methods. // We need to modify the def_id and our substs in order to monomorphize // the function. - let (is_default, def_id, substs, vtables) = - match ty::provided_source(tcx, def_id) { - None => (false, def_id, substs, vtables), + let (is_default, def_id, substs) = match ty::provided_source(tcx, def_id) { + None => (false, def_id, substs), Some(source_id) => { // There are two relevant substitutions when compiling // default methods. First, there is the substitution for @@ -491,23 +452,11 @@ pub fn trans_fn_ref_with_vtables( debug!("trans_fn_with_vtables - default method: \ substs = {}, trait_subst = {}, \ - first_subst = {}, new_subst = {}, \ - vtables = {}", + first_subst = {}, new_subst = {}", substs.repr(tcx), trait_ref.substs.repr(tcx), - first_subst.repr(tcx), new_substs.repr(tcx), - vtables.repr(tcx)); - - let param_vtables = - resolve_default_method_vtables(bcx, - impl_id, - &substs, - vtables); - - debug!("trans_fn_with_vtables - default method: \ - param_vtables = {}", - param_vtables.repr(tcx)); + first_subst.repr(tcx), new_substs.repr(tcx)); - (true, source_id, new_substs, param_vtables) + (true, source_id, new_substs) } } } @@ -556,8 +505,7 @@ pub fn trans_fn_ref_with_vtables( }; let (val, must_cast) = - monomorphize::monomorphic_fn(ccx, def_id, &substs, - vtables, opt_ref_id); + monomorphize::monomorphic_fn(ccx, def_id, &substs, opt_ref_id); let mut val = val; if must_cast && node != ExprId(0) { // Monotype of the REFERENCE to the function (type params @@ -678,11 +626,10 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, None, fty, |bcx, _| { - trans_fn_ref_with_vtables_to_callee(bcx, - did, - 0, - subst::Substs::empty(), - VecPerParamSpace::empty()) + trans_fn_ref_with_substs_to_callee(bcx, + did, + 0, + subst::Substs::empty()) }, ArgVals(args), dest) diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index bbb9ba4bbb685..60ae26439b483 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -29,8 +29,11 @@ use middle::trans::datum; use middle::trans::debuginfo; use middle::trans::type_::Type; use middle::trans::type_of; +use middle::traits; use middle::ty; +use middle::ty_fold; use middle::typeck; +use middle::typeck::infer; use util::ppaux::Repr; use util::nodemap::{DefIdMap, NodeMap}; @@ -39,6 +42,7 @@ use std::collections::HashMap; use libc::{c_uint, c_longlong, c_ulonglong, c_char}; use std::c_str::ToCStr; use std::cell::{Cell, RefCell}; +use std::rc::Rc; use std::vec::Vec; use syntax::ast::Ident; use syntax::ast; @@ -188,14 +192,12 @@ pub type ExternMap = HashMap; // will only be set in the case of default methods. pub struct param_substs { pub substs: subst::Substs, - pub vtables: typeck::vtable_res, } impl param_substs { pub fn empty() -> param_substs { param_substs { substs: subst::Substs::trans_empty(), - vtables: subst::VecPerParamSpace::empty(), } } @@ -204,15 +206,9 @@ impl param_substs { } } -fn param_substs_to_string(this: ¶m_substs, tcx: &ty::ctxt) -> String { - format!("param_substs(substs={},vtables={})", - this.substs.repr(tcx), - this.vtables.repr(tcx)) -} - impl Repr for param_substs { fn repr(&self, tcx: &ty::ctxt) -> String { - param_substs_to_string(self, tcx) + self.substs.repr(tcx) } } @@ -766,6 +762,98 @@ pub fn expr_ty_adjusted(bcx: Block, ex: &ast::Expr) -> ty::t { monomorphize_type(bcx, ty::expr_ty_adjusted(bcx.tcx(), ex)) } +pub fn fulfill_obligation(ccx: &CrateContext, + span: Span, + trait_ref: Rc) + -> traits::Vtable<()> +{ + /*! + * Attempts to resolve an obligation. The result is a shallow + * vtable resolution -- meaning that we do not (necessarily) resolve + * all nested obligations on the impl. Note that type check should + * guarantee to us that all nested obligations *could be* resolved + * if we wanted to. + */ + + let tcx = ccx.tcx(); + + // Remove any references to regions; this helps improve caching. + let trait_ref = ty_fold::erase_regions(tcx, trait_ref); + + // First check the cache. + match ccx.trait_cache().borrow().find(&trait_ref) { + Some(vtable) => { + info!("Cache hit: {}", trait_ref.repr(ccx.tcx())); + return (*vtable).clone(); + } + None => { } + } + + ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id); + let infcx = infer::new_infer_ctxt(tcx); + + // Parameter environment is used to give details about type parameters, + // but since we are in trans, everything is fully monomorphized. + let param_env = ty::empty_parameter_environment(); + let unboxed_closures = tcx.unboxed_closures.borrow(); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + let selcx = traits::SelectionContext::new(&infcx, ¶m_env, + &*unboxed_closures); + let obligation = traits::Obligation::misc(span, trait_ref.clone()); + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + tcx.sess.span_bug( + span, + format!("Encountered ambiguity selecting `{}` during trans", + trait_ref.repr(tcx)).as_slice()) + } + Err(e) => { + tcx.sess.span_bug( + span, + format!("Encountered error `{}` selecting `{}` during trans", + e.repr(tcx), + trait_ref.repr(tcx)).as_slice()) + } + }; + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. However, in principle, + // we only need to do this until the impl's type parameters are + // fully bound. It could be a slight optimization to stop + // iterating early. + let mut fulfill_cx = traits::FulfillmentContext::new(); + let vtable = selection.map_move_nested(|obligation| { + fulfill_cx.register_obligation(tcx, obligation); + }); + match fulfill_cx.select_all_or_error(&infcx, ¶m_env, &*unboxed_closures) { + Ok(()) => { } + Err(e) => { + tcx.sess.span_bug( + span, + format!("Encountered errors `{}` fulfilling `{}` during trans", + e.repr(tcx), + trait_ref.repr(tcx)).as_slice()); + } + } + + // Use skolemize to simultaneously replace all type variables with + // their bindings and replace all regions with 'static. This is + // sort of overkill because we do not expect there to be any + // unbound type variables, hence no skolemized types should ever + // be inserted. + let vtable = infer::skolemize(&infcx, vtable); + + info!("Cache miss: {}", trait_ref.repr(ccx.tcx())); + ccx.trait_cache().borrow_mut().insert(trait_ref, + vtable.clone()); + + vtable +} + // Key used to lookup values supplied for type parameters in an expr. #[deriving(PartialEq)] pub enum ExprOrMethodCall { @@ -778,7 +866,8 @@ pub enum ExprOrMethodCall { pub fn node_id_substs(bcx: Block, node: ExprOrMethodCall) - -> subst::Substs { + -> subst::Substs +{ let tcx = bcx.tcx(); let substs = match node { @@ -798,87 +887,10 @@ pub fn node_id_substs(bcx: Block, substs.repr(bcx.tcx())).as_slice()); } + let substs = substs.erase_regions(); substs.substp(tcx, bcx.fcx.param_substs) } -pub fn node_vtables(bcx: Block, id: typeck::MethodCall) - -> typeck::vtable_res { - bcx.tcx().vtable_map.borrow().find(&id).map(|vts| { - resolve_vtables_in_fn_ctxt(bcx.fcx, vts) - }).unwrap_or_else(|| subst::VecPerParamSpace::empty()) -} - -// Apply the typaram substitutions in the FunctionContext to some -// vtables. This should eliminate any vtable_params. -pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, - vts: &typeck::vtable_res) - -> typeck::vtable_res { - resolve_vtables_under_param_substs(fcx.ccx.tcx(), - fcx.param_substs, - vts) -} - -pub fn resolve_vtables_under_param_substs(tcx: &ty::ctxt, - param_substs: ¶m_substs, - vts: &typeck::vtable_res) - -> typeck::vtable_res -{ - vts.map(|ds| { - resolve_param_vtables_under_param_substs(tcx, - param_substs, - ds) - }) -} - -pub fn resolve_param_vtables_under_param_substs(tcx: &ty::ctxt, - param_substs: ¶m_substs, - ds: &typeck::vtable_param_res) - -> typeck::vtable_param_res -{ - ds.iter().map(|d| { - resolve_vtable_under_param_substs(tcx, - param_substs, - d) - }).collect() -} - - - -pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt, - param_substs: ¶m_substs, - vt: &typeck::vtable_origin) - -> typeck::vtable_origin -{ - match *vt { - typeck::vtable_static(trait_id, ref vtable_substs, ref sub) => { - let vtable_substs = vtable_substs.substp(tcx, param_substs); - typeck::vtable_static( - trait_id, - vtable_substs, - resolve_vtables_under_param_substs(tcx, param_substs, sub)) - } - typeck::vtable_param(n_param, n_bound) => { - find_vtable(tcx, param_substs, n_param, n_bound) - } - typeck::vtable_unboxed_closure(def_id) => { - typeck::vtable_unboxed_closure(def_id) - } - typeck::vtable_error => typeck::vtable_error - } -} - -pub fn find_vtable(tcx: &ty::ctxt, - ps: ¶m_substs, - n_param: typeck::param_index, - n_bound: uint) - -> typeck::vtable_origin { - debug!("find_vtable(n_param={:?}, n_bound={}, ps={})", - n_param, n_bound, ps.repr(tcx)); - - let param_bounds = ps.vtables.get(n_param.space, n_param.index); - param_bounds.get(n_bound).clone() -} - pub fn langcall(bcx: Block, span: Option, msg: &str, diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 3b4b50c7e85ac..093849b47ad98 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -16,6 +16,7 @@ use llvm::{TargetData}; use llvm::mk_target_data; use metadata::common::LinkMeta; use middle::resolve; +use middle::traits; use middle::trans::adt; use middle::trans::base; use middle::trans::builder::Builder; @@ -103,7 +104,7 @@ pub struct LocalCrateContext { monomorphized: RefCell>, monomorphizing: RefCell>, /// Cache generated vtables - vtables: RefCell>, + vtables: RefCell), ValueRef>>, /// Cache of constant strings, const_cstr_cache: RefCell>, @@ -150,6 +151,9 @@ pub struct LocalCrateContext { /// This is used to perform some basic load-balancing to keep all LLVM /// contexts around the same size. n_llvm_insns: Cell, + + trait_cache: RefCell, + traits::Vtable<()>>>, } pub struct CrateContext<'a, 'tcx: 'a> { @@ -426,6 +430,7 @@ impl LocalCrateContext { eh_personality: RefCell::new(None), intrinsics: RefCell::new(HashMap::new()), n_llvm_insns: Cell::new(0u), + trait_cache: RefCell::new(HashMap::new()), }; local_ccx.int_type = Type::int(&local_ccx.dummy_ccx(shared)); @@ -617,7 +622,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.monomorphizing } - pub fn vtables<'a>(&'a self) -> &'a RefCell> { + pub fn vtables<'a>(&'a self) -> &'a RefCell), ValueRef>> { &self.local.vtables } @@ -713,6 +718,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { pub fn count_llvm_insn(&self) { self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1); } + + pub fn trait_cache(&self) -> &RefCell, traits::Vtable<()>>> { + &self.local.trait_cache + } } fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 8a6f3dd6ffab6..af57d49d9d815 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -41,6 +41,7 @@ use middle::def; use middle::lang_items::MallocFnLangItem; use middle::mem_categorization::Typer; use middle::subst; +use middle::subst::Subst; use middle::trans::_match; use middle::trans::adt; use middle::trans::asm; @@ -78,6 +79,7 @@ use syntax::ast; use syntax::codemap; use syntax::print::pprust::{expr_to_string}; use syntax::ptr::P; +use std::rc::Rc; // Destinations @@ -319,10 +321,18 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => bcx.sess().bug(format!("UnsizeStruct with bad sty: {}", bcx.ty_to_string(unsized_ty)).as_slice()) }, - &ty::UnsizeVtable(..) => + &ty::UnsizeVtable(ty::TyTrait { def_id: def_id, substs: ref substs, .. }, _) => { + let substs = substs.with_self_ty(unsized_ty); + let trait_ref = + Rc::new(ty::TraitRef { def_id: def_id, + substs: substs }); + let trait_ref = + trait_ref.subst(bcx.tcx(), &bcx.fcx.param_substs.substs); + let box_ty = mk_ty(unsized_ty); PointerCast(bcx, - meth::vtable_ptr(bcx, id, mk_ty(unsized_ty)), + meth::get_vtable(bcx, box_ty, trait_ref), Type::vtable_ptr(bcx.ccx())) + } } } @@ -1052,8 +1062,16 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::ExprCast(ref val, _) => { // DPS output mode means this is a trait cast: if ty::type_is_trait(node_id_type(bcx, expr.id)) { + let trait_ref = + bcx.tcx().object_cast_map.borrow() + .find(&expr.id) + .map(|t| (*t).clone()) + .unwrap(); + let trait_ref = + trait_ref.subst(bcx.tcx(), &bcx.fcx.param_substs.substs); let datum = unpack_datum!(bcx, trans(bcx, &**val)); - meth::trans_trait_cast(bcx, datum, expr.id, dest) + meth::trans_trait_cast(bcx, datum, expr.id, + trait_ref, dest) } else { bcx.tcx().sess.span_bug(expr.span, "expr_cast of non-trait"); diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 4202c2deff6fc..a87557a26cc67 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -13,8 +13,10 @@ use back::abi; use llvm; use llvm::ValueRef; use metadata::csearch; +use middle::subst::{Subst,Substs}; use middle::subst::VecPerParamSpace; use middle::subst; +use middle::traits; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::callee::*; @@ -26,20 +28,20 @@ use middle::trans::expr::{SaveIn, Ignore}; use middle::trans::expr; use middle::trans::glue; use middle::trans::machine; -use middle::trans::monomorphize; use middle::trans::type_::Type; use middle::trans::type_of::*; use middle::ty; use middle::typeck; use middle::typeck::MethodCall; -use util::common::indenter; use util::ppaux::Repr; use std::c_str::ToCStr; +use std::rc::Rc; use syntax::abi::{Rust, RustCall}; use syntax::parse::token; use syntax::{ast, ast_map, attr, visit}; use syntax::ast_util::PostExpansionMethod; +use syntax::codemap::DUMMY_SP; // drop_glue pointer, size, align. static VTABLE_OFFSET: uint = 3; @@ -109,18 +111,12 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, -> Callee<'blk, 'tcx> { let _icx = push_ctxt("meth::trans_method_callee"); - let (origin, method_ty) = match bcx.tcx().method_map - .borrow().find(&method_call) { - Some(method) => { - debug!("trans_method_callee({:?}, method={})", - method_call, method.repr(bcx.tcx())); - (method.origin, method.ty) - } - None => { - bcx.sess().span_bug(bcx.tcx().map.span(method_call.expr_id), - "method call expr wasn't in method map") - } - }; + let (origin, method_ty) = + bcx.tcx().method_map + .borrow() + .find(&method_call) + .map(|method| (method.origin.clone(), method.ty)) + .unwrap(); match origin { typeck::MethodStatic(did) | @@ -132,19 +128,21 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, MethodCall(method_call))), } } + typeck::MethodParam(typeck::MethodParam { - trait_id: trait_id, - method_num: off, - param_num: p, - bound_num: b + trait_ref: ref trait_ref, + method_num: method_num }) => { - ty::populate_implementations_for_trait_if_necessary( - bcx.tcx(), - trait_id); - - let vtbl = find_vtable(bcx.tcx(), bcx.fcx.param_substs, p, b); - trans_monomorphized_callee(bcx, method_call, - trait_id, off, vtbl) + let trait_ref = + Rc::new(trait_ref.subst(bcx.tcx(), + &bcx.fcx.param_substs.substs)); + let span = bcx.tcx().map.span(method_call.expr_id); + let origin = fulfill_obligation(bcx.ccx(), + span, + (*trait_ref).clone()); + debug!("origin = {}", origin.repr(bcx.tcx())); + trans_monomorphized_callee(bcx, method_call, trait_ref.def_id, + method_num, origin) } typeck::MethodObject(ref mt) => { @@ -169,7 +167,8 @@ pub fn trans_static_method_callee(bcx: Block, method_id: ast::DefId, trait_id: ast::DefId, expr_id: ast::NodeId) - -> ValueRef { + -> ValueRef +{ let _icx = push_ctxt("meth::trans_static_method_callee"); let ccx = bcx.ccx(); @@ -178,9 +177,6 @@ pub fn trans_static_method_callee(bcx: Block, method_id, ty::item_path_str(bcx.tcx(), trait_id), expr_id); - let _indenter = indenter(); - - ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id); let mname = if method_id.krate == ast::LOCAL_CRATE { match bcx.tcx().map.get(method_id.node) { @@ -196,38 +192,91 @@ pub fn trans_static_method_callee(bcx: Block, } else { csearch::get_item_path(bcx.tcx(), method_id).last().unwrap().name() }; - debug!("trans_static_method_callee: method_id={:?}, expr_id={:?}, \ + debug!("trans_static_method_callee: method_id={}, expr_id={}, \ name={}", method_id, expr_id, token::get_name(mname)); - let vtable_key = MethodCall::expr(expr_id); - let vtbls = resolve_vtables_in_fn_ctxt( - bcx.fcx, - ccx.tcx().vtable_map.borrow().get(&vtable_key)); - - match *vtbls.get_self().unwrap().get(0) { - typeck::vtable_static(impl_did, ref rcvr_substs, ref rcvr_origins) => { - assert!(rcvr_substs.types.all(|t| !ty::type_needs_infer(*t))); + // Find the substitutions for the fn itself. This includes + // type parameters that belong to the trait but also some that + // belong to the method: + let rcvr_substs = node_id_substs(bcx, ExprId(expr_id)); + let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.split(); + + // Lookup the precise impl being called. To do that, we need to + // create a trait reference identifying the self type and other + // input type parameters. To create that trait reference, we have + // to pick apart the type parameters to identify just those that + // pertain to the trait. This is easiest to explain by example: + // + // trait Convert { + // fn from(n: U) -> Option; + // } + // ... + // let f = as Convert>::from::(...) + // + // Here, in this call, which I've written with explicit UFCS + // notation, the set of type parameters will be: + // + // rcvr_type: [] <-- nothing declared on the trait itself + // rcvr_self: [Vec] <-- the self type + // rcvr_method: [String] <-- method type parameter + // + // So we create a trait reference using the first two, + // basically corresponding to ` as Convert>`. + // The remaining type parameters (`rcvr_method`) will be used below. + let trait_substs = + Substs::erased(VecPerParamSpace::new(rcvr_type, + rcvr_self, + Vec::new())); + debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); + let trait_ref = Rc::new(ty::TraitRef { def_id: trait_id, + substs: trait_substs }); + let vtbl = fulfill_obligation(bcx.ccx(), + DUMMY_SP, + trait_ref); + + // Now that we know which impl is being used, we can dispatch to + // the actual function: + match vtbl { + traits::VtableImpl(traits::VtableImpl { + impl_def_id: impl_did, + substs: impl_substs, + nested: _ }) => + { + assert!(impl_substs.types.all(|t| !ty::type_needs_infer(*t))); + + // Create the substitutions that are in scope. This combines + // the type parameters from the impl with those declared earlier. + // To see what I mean, consider a possible impl: + // + // impl Convert for Vec { + // fn from(n: U) { ... } + // } + // + // Recall that we matched ` as Convert>`. Trait + // resolution will have given us a substitution + // containing `impl_substs=[[T=int],[],[]]` (the type + // parameters defined on the impl). We combine + // that with the `rcvr_method` from before, which tells us + // the type parameters from the *method*, to yield + // `callee_substs=[[T=int],[],[U=String]]`. + let (impl_type, impl_self, _) = impl_substs.types.split(); + let callee_substs = + Substs::erased(VecPerParamSpace::new(impl_type, + impl_self, + rcvr_method)); let mth_id = method_with_name(ccx, impl_did, mname); - let (callee_substs, callee_origins) = - combine_impl_and_methods_tps( - bcx, ExprId(expr_id), - (*rcvr_substs).clone(), (*rcvr_origins).clone()); - - let llfn = trans_fn_ref_with_vtables(bcx, mth_id, ExprId(expr_id), - callee_substs, - callee_origins); + let llfn = trans_fn_ref_with_substs(bcx, mth_id, ExprId(expr_id), + callee_substs); let callee_ty = node_id_type(bcx, expr_id); let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to(); PointerCast(bcx, llfn, llty) } - typeck::vtable_unboxed_closure(_) => { - bcx.tcx().sess.bug("can't call a closure vtable in a static way"); - } _ => { - fail!("vtable_param left in monomorphized \ - function's vtable substs"); + bcx.tcx().sess.bug( + format!("static call to invalid vtable: {}", + vtbl.repr(bcx.tcx())).as_slice()); } } } @@ -265,33 +314,33 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_call: MethodCall, trait_id: ast::DefId, n_method: uint, - vtbl: typeck::vtable_origin) + vtable: traits::Vtable<()>) -> Callee<'blk, 'tcx> { let _icx = push_ctxt("meth::trans_monomorphized_callee"); - match vtbl { - typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => { - let ccx = bcx.ccx(); - let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) { - ty::MethodTraitItem(method) => method.ident, - }; - let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name); - - // create a concatenated set of substitutions which includes - // those from the impl and those from the method: - let (callee_substs, callee_origins) = - combine_impl_and_methods_tps( - bcx, MethodCall(method_call), rcvr_substs, rcvr_origins); - - // translate the function - let llfn = trans_fn_ref_with_vtables(bcx, - mth_id, - MethodCall(method_call), - callee_substs, - callee_origins); - - Callee { bcx: bcx, data: Fn(llfn) } - } - typeck::vtable_unboxed_closure(closure_def_id) => { + match vtable { + traits::VtableImpl(vtable_impl) => { + let ccx = bcx.ccx(); + let impl_did = vtable_impl.impl_def_id; + let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) { + ty::MethodTraitItem(method) => method.ident, + }; + let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name); + + // create a concatenated set of substitutions which includes + // those from the impl and those from the method: + let callee_substs = + combine_impl_and_methods_tps( + bcx, MethodCall(method_call), vtable_impl.substs); + + // translate the function + let llfn = trans_fn_ref_with_substs(bcx, + mth_id, + MethodCall(method_call), + callee_substs); + + Callee { bcx: bcx, data: Fn(llfn) } + } + traits::VtableUnboxedClosure(closure_def_id) => { // The static region and type parameters are lies, but we're in // trans so it doesn't matter. // @@ -300,33 +349,27 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx, closure_def_id); - let llfn = trans_fn_ref_with_vtables(bcx, - closure_def_id, - MethodCall(method_call), - callee_substs, - VecPerParamSpace::empty()); - - Callee { - bcx: bcx, - data: Fn(llfn), - } - } - typeck::vtable_param(..) => { - bcx.tcx().sess.bug( - "vtable_param left in monomorphized function's vtable substs"); - } - typeck::vtable_error => { - bcx.tcx().sess.bug( - "vtable_error left in monomorphized function's vtable substs"); - } + let llfn = trans_fn_ref_with_substs(bcx, + closure_def_id, + MethodCall(method_call), + callee_substs); + + Callee { + bcx: bcx, + data: Fn(llfn), + } + } + _ => { + bcx.tcx().sess.bug( + "vtable_param left in monomorphized function's vtable substs"); + } } } fn combine_impl_and_methods_tps(bcx: Block, node: ExprOrMethodCall, - rcvr_substs: subst::Substs, - rcvr_origins: typeck::vtable_res) - -> (subst::Substs, typeck::vtable_res) + rcvr_substs: subst::Substs) + -> subst::Substs { /*! * Creates a concatenated set of substitutions which includes @@ -347,33 +390,20 @@ fn combine_impl_and_methods_tps(bcx: Block, let ccx = bcx.ccx(); - let vtable_key = match node { - ExprId(id) => MethodCall::expr(id), - MethodCall(method_call) => method_call - }; let node_substs = node_id_substs(bcx, node); - let node_vtables = node_vtables(bcx, vtable_key); - debug!("rcvr_substs={:?}", rcvr_substs.repr(ccx.tcx())); - debug!("node_substs={:?}", node_substs.repr(ccx.tcx())); + debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx())); + debug!("node_substs={}", node_substs.repr(ccx.tcx())); // Break apart the type parameters from the node and type // parameters from the receiver. let (_, _, node_method) = node_substs.types.split(); let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.clone().split(); assert!(rcvr_method.is_empty()); - let ty_substs = subst::Substs { + subst::Substs { regions: subst::ErasedRegions, types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method) - }; - - // Now do the same work for the vtables. - let (rcvr_type, rcvr_self, rcvr_method) = rcvr_origins.split(); - let (_, _, node_method) = node_vtables.split(); - assert!(rcvr_method.is_empty()); - let vtables = subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method); - - (ty_substs, vtables) + } } fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, @@ -493,43 +523,56 @@ fn get_callee_substitutions_for_unboxed_closure(bcx: Block, /// Creates a returns a dynamic vtable for the given type and vtable origin. /// This is used only for objects. -fn get_vtable(bcx: Block, - self_ty: ty::t, - origins: typeck::vtable_param_res) - -> ValueRef +/// +/// The `trait_ref` encodes the erased self type. Hence if we are +/// making an object `Foo` from a value of type `Foo`, then +/// `trait_ref` would map `T:Trait`, but `box_ty` would be +/// `Foo`. This `box_ty` is primarily used to encode the destructor. +/// This will hopefully change now that DST is underway. +pub fn get_vtable(bcx: Block, + box_ty: ty::t, + trait_ref: Rc) + -> ValueRef { - debug!("get_vtable(self_ty={}, origins={})", - self_ty.repr(bcx.tcx()), - origins.repr(bcx.tcx())); + debug!("get_vtable(box_ty={}, trait_ref={})", + box_ty.repr(bcx.tcx()), + trait_ref.repr(bcx.tcx())); + let tcx = bcx.tcx(); let ccx = bcx.ccx(); let _icx = push_ctxt("meth::get_vtable"); // Check the cache. - let hash_id = (self_ty, monomorphize::make_vtable_id(ccx, origins.get(0))); - match ccx.vtables().borrow().find(&hash_id) { + let cache_key = (box_ty, trait_ref.clone()); + match ccx.vtables().borrow().find(&cache_key) { Some(&val) => { return val } None => { } } - // Not in the cache. Actually build it. - let methods = origins.move_iter().flat_map(|origin| { - match origin { - typeck::vtable_static(id, substs, sub_vtables) => { - emit_vtable_methods(bcx, id, substs, sub_vtables).move_iter() + // Not in the cache. Build it. + let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| { + let vtable = fulfill_obligation(bcx.ccx(), + DUMMY_SP, + trait_ref.clone()); + match vtable { + traits::VtableImpl( + traits::VtableImpl { + impl_def_id: id, + substs: substs, + nested: _ }) => { + emit_vtable_methods(bcx, id, substs).move_iter() } - typeck::vtable_unboxed_closure(closure_def_id) => { + traits::VtableUnboxedClosure(closure_def_id) => { let callee_substs = get_callee_substitutions_for_unboxed_closure( bcx, closure_def_id); - let mut llfn = trans_fn_ref_with_vtables( + let mut llfn = trans_fn_ref_with_substs( bcx, closure_def_id, ExprId(0), - callee_substs.clone(), - VecPerParamSpace::empty()); + callee_substs.clone()); { let unboxed_closures = bcx.tcx() @@ -585,21 +628,27 @@ fn get_vtable(bcx: Block, (vec!(llfn)).move_iter() } - _ => ccx.sess().bug("get_vtable: expected a static origin"), + traits::VtableBuiltin | + traits::VtableParam(..) => { + bcx.sess().bug( + format!("resolved vtable for {} to bad vtable {} in trans", + trait_ref.repr(bcx.tcx()), + vtable.repr(bcx.tcx())).as_slice()); + } } }); - let size_ty = sizing_type_of(ccx, self_ty); + let size_ty = sizing_type_of(ccx, trait_ref.self_ty()); let size = machine::llsize_of_alloc(ccx, size_ty); let ll_size = C_uint(ccx, size as uint); - let align = align_of(ccx, self_ty); + let align = align_of(ccx, trait_ref.self_ty()); let ll_align = C_uint(ccx, align as uint); // Generate a destructor for the vtable. - let drop_glue = glue::get_drop_glue(ccx, self_ty); + let drop_glue = glue::get_drop_glue(ccx, box_ty); let vtable = make_vtable(ccx, drop_glue, ll_size, ll_align, methods); - ccx.vtables().borrow_mut().insert(hash_id, vtable); + ccx.vtables().borrow_mut().insert(cache_key, vtable); vtable } @@ -630,8 +679,7 @@ pub fn make_vtable>(ccx: &CrateContext, fn emit_vtable_methods(bcx: Block, impl_id: ast::DefId, - substs: subst::Substs, - vtables: typeck::vtable_res) + substs: subst::Substs) -> Vec { let ccx = bcx.ccx(); let tcx = ccx.tcx(); @@ -664,12 +712,11 @@ fn emit_vtable_methods(bcx: Block, token::get_ident(ident)); C_null(Type::nil(ccx).ptr_to()) } else { - let mut fn_ref = trans_fn_ref_with_vtables( + let mut fn_ref = trans_fn_ref_with_substs( bcx, m_id, ExprId(0), - substs.clone(), - vtables.clone()); + substs.clone()); if m.explicit_self == ty::ByValueExplicitSelfCategory { fn_ref = trans_unboxing_shim(bcx, fn_ref, @@ -684,29 +731,10 @@ fn emit_vtable_methods(bcx: Block, }).collect() } -pub fn vtable_ptr(bcx: Block, - id: ast::NodeId, - self_ty: ty::t) -> ValueRef { - let ccx = bcx.ccx(); - let origins = { - let vtable_map = ccx.tcx().vtable_map.borrow(); - // This trait cast might be because of implicit coercion - let adjs = ccx.tcx().adjustments.borrow(); - let adjust = adjs.find(&id); - let method_call = if adjust.is_some() && ty::adjust_is_object(adjust.unwrap()) { - MethodCall::autoobject(id) - } else { - MethodCall::expr(id) - }; - let vres = vtable_map.get(&method_call).get_self().unwrap(); - resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres) - }; - get_vtable(bcx, self_ty, origins) -} - pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum, id: ast::NodeId, + trait_ref: Rc, dest: expr::Dest) -> Block<'blk, 'tcx> { /*! @@ -717,17 +745,20 @@ pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, */ let mut bcx = bcx; - let _icx = push_ctxt("meth::trans_cast"); + let _icx = push_ctxt("meth::trans_trait_cast"); let lldest = match dest { Ignore => { - return datum.clean(bcx, "trait_cast", id); + return datum.clean(bcx, "trait_trait_cast", id); } SaveIn(dest) => dest }; - let v_ty = datum.ty; - let llbox_ty = type_of(bcx.ccx(), v_ty); + debug!("trans_trait_cast: trait_ref={}", + trait_ref.repr(bcx.tcx())); + + let datum_ty = datum.ty; + let llbox_ty = type_of(bcx.ccx(), datum_ty); // Store the pointer into the first half of pair. let llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]); @@ -735,7 +766,7 @@ pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx = datum.store_to(bcx, llboxdest); // Store the vtable into the second half of pair. - let vtable = vtable_ptr(bcx, id, v_ty); + let vtable = get_vtable(bcx, datum_ty, trait_ref); let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]); let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to()); Store(bcx, vtable, llvtabledest); diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 57004922ef7d1..00e9d9f0e39b6 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -34,17 +34,14 @@ use std::hash::{sip, Hash}; pub fn monomorphic_fn(ccx: &CrateContext, fn_id: ast::DefId, real_substs: &subst::Substs, - vtables: typeck::vtable_res, ref_id: Option) -> (ValueRef, bool) { debug!("monomorphic_fn(\ fn_id={}, \ real_substs={}, \ - vtables={}, \ ref_id={:?})", fn_id.repr(ccx.tcx()), real_substs.repr(ccx.tcx()), - vtables.repr(ccx.tcx()), ref_id); assert!(real_substs.types.all(|t| { @@ -69,7 +66,6 @@ pub fn monomorphic_fn(ccx: &CrateContext, let psubsts = param_substs { substs: (*real_substs).clone(), - vtables: vtables, }; debug!("monomorphic_fn(\ @@ -286,7 +282,7 @@ pub fn monomorphic_fn(ccx: &CrateContext, (lldecl, true) } -// Used to identify cached monomorphized functions and vtables +// Used to identify cached monomorphized functions #[deriving(PartialEq, Eq, Hash)] pub struct MonoParamId { pub subst: ty::t, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index bf35e25635aa2..d0b94cb3abb8b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -28,6 +28,7 @@ use middle::resolve_lifetime; use middle::stability; use middle::subst::{Subst, Substs, VecPerParamSpace}; use middle::subst; +use middle::traits; use middle::ty; use middle::typeck; use middle::ty_fold; @@ -272,9 +273,7 @@ pub enum UnsizeKind { // An unsize coercion applied to the tail field of a struct. // The uint is the index of the type parameter which is unsized. UnsizeStruct(Box, uint), - UnsizeVtable(ty::ExistentialBounds, - ast::DefId, /* Trait ID */ - subst::Substs /* Trait substitutions */) + UnsizeVtable(TyTrait, /* the self type of the trait */ ty::t) } #[deriving(Clone)] @@ -365,13 +364,13 @@ pub fn type_of_adjust(cx: &ctxt, adj: &AutoAdjustment) -> Option { fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option { match autoref { &AutoUnsize(ref k) => match k { - &UnsizeVtable(bounds, def_id, ref substs) => { + &UnsizeVtable(TyTrait { def_id, substs: ref substs, bounds }, _) => { Some(mk_trait(cx, def_id, substs.clone(), bounds)) } _ => None }, &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(bounds, def_id, ref substs) => { + &UnsizeVtable(TyTrait { def_id, substs: ref substs, bounds }, _) => { Some(mk_uniq(cx, mk_trait(cx, def_id, substs.clone(), bounds))) } _ => None @@ -458,6 +457,10 @@ pub struct ctxt<'tcx> { pub trait_refs: RefCell>>, pub trait_defs: RefCell>>, + /// Maps from node-id of a trait object cast (like `foo as + /// Box`) to the trait reference. + pub object_cast_map: typeck::ObjectCastMap, + pub map: ast_map::Map<'tcx>, pub intrinsic_defs: RefCell>, pub freevars: RefCell, @@ -499,7 +502,7 @@ pub struct ctxt<'tcx> { /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. - pub inherent_impls: RefCell>>>>, + pub inherent_impls: RefCell>>>, /// Maps a DefId of an impl to a list of its items. /// Note that this contains all of the impls that we know about, @@ -516,9 +519,6 @@ pub struct ctxt<'tcx> { /// about. pub used_mut_nodes: RefCell, - /// vtable resolution information for impl declarations - pub impl_vtables: typeck::impl_vtable_map, - /// The set of external nominal types whose implementations have been read. /// This is used for lazy resolution of methods. pub populated_external_types: RefCell, @@ -536,7 +536,6 @@ pub struct ctxt<'tcx> { pub extern_const_variants: RefCell>, pub method_map: typeck::MethodMap, - pub vtable_map: typeck::vtable_map, pub dependency_formats: RefCell, @@ -1089,7 +1088,13 @@ pub struct RegionVid { pub enum InferTy { TyVar(TyVid), IntVar(IntVid), - FloatVar(FloatVid) + FloatVar(FloatVid), + SkolemizedTy(uint), + + // FIXME -- once integral fallback is impl'd, we should remove + // this type. It's only needed to prevent spurious errors for + // integers whose type winds up never being constrained. + SkolemizedIntTy(uint), } #[deriving(Clone, Encodable, Decodable, Eq, Hash, Show)] @@ -1152,6 +1157,8 @@ impl fmt::Show for InferTy { TyVar(ref v) => v.fmt(f), IntVar(ref v) => v.fmt(f), FloatVar(ref v) => v.fmt(f), + SkolemizedTy(v) => write!(f, "SkolemizedTy({})", v), + SkolemizedIntTy(v) => write!(f, "SkolemizedIntTy({})", v), } } } @@ -1207,6 +1214,12 @@ impl Generics { } } +impl TraitRef { + pub fn self_ty(&self) -> ty::t { + self.substs.self_ty().unwrap() + } +} + /// When type checking, we use the `ParameterEnvironment` to track /// details about the type/lifetime parameters that are in scope. /// It primarily stores the bounds information. @@ -1235,6 +1248,14 @@ pub struct ParameterEnvironment { /// may specify stronger requirements). This field indicates the /// region of the callee. pub implicit_region_bound: ty::Region, + + /// Obligations that the caller must satisfy. This is basically + /// the set of bounds on the in-scope type parameters, translated + /// into Obligations. + /// + /// Note: This effectively *duplicates* the `bounds` array for + /// now. + pub caller_obligations: VecPerParamSpace, } impl ParameterEnvironment { @@ -1249,6 +1270,7 @@ impl ParameterEnvironment { let method_generics = &method_ty.generics; construct_parameter_environment( cx, + method.span, method_generics, method.pe_body().id) } @@ -1272,6 +1294,7 @@ impl ParameterEnvironment { let method_generics = &method_ty.generics; construct_parameter_environment( cx, + method.span, method_generics, method.pe_body().id) } @@ -1287,6 +1310,7 @@ impl ParameterEnvironment { let fn_pty = ty::lookup_item_type(cx, fn_def_id); construct_parameter_environment(cx, + item.span, &fn_pty.generics, body.id) } @@ -1296,7 +1320,8 @@ impl ParameterEnvironment { ast::ItemStatic(..) => { let def_id = ast_util::local_def(id); let pty = ty::lookup_item_type(cx, def_id); - construct_parameter_environment(cx, &pty.generics, id) + construct_parameter_environment(cx, item.span, + &pty.generics, id) } _ => { cx.sess.span_bug(item.span, @@ -1328,7 +1353,14 @@ pub struct Polytype { /// As `Polytype` but for a trait ref. pub struct TraitDef { + /// Generic type definitions. Note that `Self` is listed in here + /// as having a single bound, the trait itself (e.g., in the trait + /// `Eq`, there is a single bound `Self : Eq`). This is so that + /// default methods get to assume that the `Self` parameters + /// implements the trait. pub generics: Generics, + + /// The "supertrait" bounds. pub bounds: ParamBounds, pub trait_ref: Rc, } @@ -1345,6 +1377,7 @@ pub type type_cache = RefCell>; pub type node_type_table = RefCell>; /// Records information about each unboxed closure. +#[deriving(Clone)] pub struct UnboxedClosure { /// The type of the unboxed closure. pub closure_type: ClosureTy, @@ -1352,7 +1385,7 @@ pub struct UnboxedClosure { pub kind: UnboxedClosureKind, } -#[deriving(PartialEq, Eq)] +#[deriving(Clone, PartialEq, Eq)] pub enum UnboxedClosureKind { FnUnboxedClosureKind, FnMutUnboxedClosureKind, @@ -1401,6 +1434,7 @@ pub fn mk_ctxt<'tcx>(s: Session, item_substs: RefCell::new(NodeMap::new()), trait_refs: RefCell::new(NodeMap::new()), trait_defs: RefCell::new(DefIdMap::new()), + object_cast_map: RefCell::new(NodeMap::new()), map: map, intrinsic_defs: RefCell::new(DefIdMap::new()), freevars: RefCell::new(freevars), @@ -1429,14 +1463,12 @@ pub fn mk_ctxt<'tcx>(s: Session, impl_items: RefCell::new(DefIdMap::new()), used_unsafe: RefCell::new(NodeSet::new()), used_mut_nodes: RefCell::new(NodeSet::new()), - impl_vtables: RefCell::new(DefIdMap::new()), populated_external_types: RefCell::new(DefIdSet::new()), populated_external_traits: RefCell::new(DefIdSet::new()), upvar_borrow_map: RefCell::new(HashMap::new()), extern_const_statics: RefCell::new(DefIdMap::new()), extern_const_variants: RefCell::new(DefIdMap::new()), method_map: RefCell::new(FnvHashMap::new()), - vtable_map: RefCell::new(FnvHashMap::new()), dependency_formats: RefCell::new(HashMap::new()), unboxed_closures: RefCell::new(DefIdMap::new()), node_lint_levels: RefCell::new(HashMap::new()), @@ -1523,7 +1555,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => { flags |= sflags(substs); } - &ty_trait(box ty::TyTrait { ref substs, ref bounds, .. }) => { + &ty_trait(box TyTrait { ref substs, ref bounds, .. }) => { flags |= sflags(substs); flags |= flags_for_bounds(bounds); } @@ -2394,6 +2426,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } // Scalar and unique types are sendable, and durable + ty_infer(ty::SkolemizedIntTy(_)) | ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty::ty_char => { TC::None @@ -2414,7 +2447,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } } - ty_trait(box ty::TyTrait { bounds, .. }) => { + ty_trait(box TyTrait { bounds, .. }) => { object_contents(cx, bounds) | TC::ReachesFfiUnsafe | TC::Nonsized } @@ -2909,13 +2942,17 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability { } pub fn type_is_trait(ty: t) -> bool { + type_trait_info(ty).is_some() +} + +pub fn type_trait_info(ty: t) -> Option<&'static TyTrait> { match get(ty).sty { ty_uniq(ty) | ty_rptr(_, mt { ty, ..}) | ty_ptr(mt { ty, ..}) => match get(ty).sty { - ty_trait(..) => true, - _ => false + ty_trait(ref t) => Some(&**t), + _ => None }, - ty_trait(..) => true, - _ => false + ty_trait(ref t) => Some(&**t), + _ => None } } @@ -2926,6 +2963,14 @@ pub fn type_is_integral(ty: t) -> bool { } } +pub fn type_is_skolemized(ty: t) -> bool { + match get(ty).sty { + ty_infer(SkolemizedTy(_)) => true, + ty_infer(SkolemizedIntTy(_)) => true, + _ => false + } +} + pub fn type_is_uint(ty: t) -> bool { match get(ty).sty { ty_infer(IntVar(_)) | ty_uint(ast::TyU) => true, @@ -3448,7 +3493,7 @@ pub fn unsize_ty(cx: &ctxt, format!("UnsizeStruct with bad sty: {}", ty_to_string(cx, ty)).as_slice()) }, - &UnsizeVtable(bounds, def_id, ref substs) => { + &UnsizeVtable(TyTrait { def_id, substs: ref substs, bounds }, _) => { mk_trait(cx, def_id, substs.clone(), bounds) } } @@ -3468,10 +3513,10 @@ impl AutoRef { } pub fn method_call_type_param_defs<'tcx, T>(typer: &T, - origin: typeck::MethodOrigin) + origin: &typeck::MethodOrigin) -> VecPerParamSpace where T: mc::Typer<'tcx> { - match origin { + match *origin { typeck::MethodStatic(did) => { ty::lookup_item_type(typer.tcx(), did).generics.types.clone() } @@ -3486,16 +3531,16 @@ pub fn method_call_type_param_defs<'tcx, T>(typer: &T, lookup_trait_def(typer.tcx(), def_id).generics.types.clone() } typeck::MethodParam(typeck::MethodParam{ - trait_id: trt_id, + trait_ref: ref trait_ref, method_num: n_mth, .. }) | typeck::MethodObject(typeck::MethodObject{ - trait_id: trt_id, + trait_ref: ref trait_ref, method_num: n_mth, .. }) => { - match ty::trait_item(typer.tcx(), trt_id, n_mth) { + match ty::trait_item(typer.tcx(), trait_ref.def_id, n_mth) { ty::MethodTraitItem(method) => method.generics.types.clone(), } } @@ -3760,6 +3805,8 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String { ty_infer(TyVar(_)) => "inferred type".to_string(), ty_infer(IntVar(_)) => "integral variable".to_string(), ty_infer(FloatVar(_)) => "floating-point variable".to_string(), + ty_infer(SkolemizedTy(_)) => "skolemized type".to_string(), + ty_infer(SkolemizedIntTy(_)) => "skolemized integral type".to_string(), ty_param(ref p) => { if p.space == subst::SelfSpace { "Self".to_string() @@ -4362,14 +4409,6 @@ pub fn lookup_item_type(cx: &ctxt, || csearch::get_type(cx, did)) } -pub fn lookup_impl_vtables(cx: &ctxt, - did: ast::DefId) - -> typeck::vtable_res { - lookup_locally_or_in_crate_store( - "impl_vtables", did, &mut *cx.impl_vtables.borrow_mut(), - || csearch::get_impl_vtables(cx, did) ) -} - /// Given the did of a trait, returns its canonical trait ref. pub fn lookup_trait_def(cx: &ctxt, did: ast::DefId) -> Rc { let mut trait_defs = cx.trait_defs.borrow_mut(); @@ -4683,7 +4722,7 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t { struct TypeNormalizer<'a, 'tcx: 'a>(&'a ctxt<'tcx>); impl<'a, 'tcx> TypeFolder<'tcx> for TypeNormalizer<'a, 'tcx> { - fn tcx<'a>(&'a self) -> &'a ctxt<'tcx> { let TypeNormalizer(c) = *self; c } + fn tcx(&self) -> &ctxt<'tcx> { let TypeNormalizer(c) = *self; c } fn fold_ty(&mut self, t: ty::t) -> ty::t { match self.tcx().normalized_cache.borrow().find_copy(&t) { @@ -4783,42 +4822,11 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { pub fn each_bound_trait_and_supertraits(tcx: &ctxt, bounds: &[Rc], f: |Rc| -> bool) - -> bool { - for bound_trait_ref in bounds.iter() { - let mut supertrait_set = HashMap::new(); - let mut trait_refs = Vec::new(); - let mut i = 0; - - // Seed the worklist with the trait from the bound - supertrait_set.insert(bound_trait_ref.def_id, ()); - trait_refs.push(bound_trait_ref.clone()); - - // Add the given trait ty to the hash map - while i < trait_refs.len() { - debug!("each_bound_trait_and_supertraits(i={:?}, trait_ref={})", - i, trait_refs.get(i).repr(tcx)); - - if !f(trait_refs.get(i).clone()) { - return false; - } - - // Add supertraits to supertrait_set - let trait_ref = trait_refs.get(i).clone(); - let trait_def = lookup_trait_def(tcx, trait_ref.def_id); - for supertrait_ref in trait_def.bounds.trait_bounds.iter() { - let supertrait_ref = supertrait_ref.subst(tcx, &trait_ref.substs); - debug!("each_bound_trait_and_supertraits(supertrait_ref={})", - supertrait_ref.repr(tcx)); - - let d_id = supertrait_ref.def_id; - if !supertrait_set.contains_key(&d_id) { - // FIXME(#5527) Could have same trait multiple times - supertrait_set.insert(d_id, ()); - trait_refs.push(supertrait_ref.clone()); - } - } - - i += 1; + -> bool +{ + for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { + if !f(bound_trait_ref) { + return false; } } return true; @@ -4944,6 +4952,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, return } + let mut inherent_impls = Vec::new(); csearch::each_implementation_for_type(&tcx.sess.cstore, type_id, |impl_def_id| { let impl_items = csearch::get_impl_items(&tcx.sess.cstore, @@ -4975,18 +4984,11 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, // If this is an inherent implementation, record it. if associated_traits.is_none() { - match tcx.inherent_impls.borrow().find(&type_id) { - Some(implementation_list) => { - implementation_list.borrow_mut().push(impl_def_id); - return; - } - None => {} - } - tcx.inherent_impls.borrow_mut().insert(type_id, - Rc::new(RefCell::new(vec!(impl_def_id)))); + inherent_impls.push(impl_def_id); } }); + tcx.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); tcx.populated_external_types.borrow_mut().insert(type_id); } @@ -5218,7 +5220,7 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { } } } - ty_trait(box ty::TyTrait { def_id: d, bounds, .. }) => { + ty_trait(box TyTrait { def_id: d, bounds, .. }) => { byte!(17); did(&mut state, d); hash!(bounds); @@ -5261,8 +5263,22 @@ impl Variance { } } +pub fn empty_parameter_environment() -> ParameterEnvironment { + /*! + * Construct a parameter environment suitable for static contexts + * or other contexts where there are no free type/lifetime + * parameters in scope. + */ + + ty::ParameterEnvironment { free_substs: Substs::empty(), + bounds: VecPerParamSpace::empty(), + caller_obligations: VecPerParamSpace::empty(), + implicit_region_bound: ty::ReEmpty } +} + pub fn construct_parameter_environment( tcx: &ctxt, + span: Span, generics: &ty::Generics, free_id: ast::NodeId) -> ParameterEnvironment @@ -5321,10 +5337,14 @@ pub fn construct_parameter_environment( free_substs.repr(tcx), bounds.repr(tcx)); + let obligations = traits::obligations_for_generics(tcx, traits::ObligationCause::misc(span), + generics, &free_substs); + return ty::ParameterEnvironment { free_substs: free_substs, bounds: bounds, implicit_region_bound: ty::ReScope(free_id), + caller_obligations: obligations, }; fn push_region_params(regions: &mut VecPerParamSpace, @@ -5398,6 +5418,26 @@ impl BorrowKind { } } + pub fn to_mutbl_lossy(self) -> ast::Mutability { + /*! + * Returns a mutability `m` such that an `&m T` pointer could + * be used to obtain this borrow kind. Because borrow kinds + * are richer than mutabilities, we sometimes have to pick a + * mutability that is stronger than necessary so that it at + * least *would permit* the borrow in question. + */ + + match self { + MutBorrow => ast::MutMutable, + ImmBorrow => ast::MutImmutable, + + // We have no type correponding to a unique imm borrow, so + // use `&mut`. It gives all the capabilities of an `&uniq` + // and hence is a safe "over approximation". + UniqueImmBorrow => ast::MutMutable, + } + } + pub fn to_user_str(&self) -> &'static str { match *self { MutBorrow => "mutable", diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index bc53568694df6..549f0daef8112 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -8,11 +8,38 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Generalized type folding mechanism. +/*! + * Generalized type folding mechanism. The setup is a bit convoluted + * but allows for convenient usage. Let T be an instance of some + * "foldable type" (one which implements `TypeFoldable`) and F be an + * instance of a "folder" (a type which implements `TypeFolder`). Then + * the setup is intended to be: + * + * T.fold_with(F) --calls--> F.fold_T(T) --calls--> super_fold_T(F, T) + * + * This way, when you define a new folder F, you can override + * `fold_T()` to customize the behavior, and invoke `super_fold_T()` + * to get the original behavior. Meanwhile, to actually fold + * something, you can just write `T.fold_with(F)`, which is + * convenient. (Note that `fold_with` will also transparently handle + * things like a `Vec` where T is foldable and so on.) + * + * In this ideal setup, the only function that actually *does* + * anything is `super_fold_T`, which traverses the type `T`. Moreover, + * `super_fold_T` should only ever call `T.fold_with()`. + * + * In some cases, we follow a degenerate pattern where we do not have + * a `fold_T` nor `super_fold_T` method. Instead, `T.fold_with` + * traverses the structure directly. This is suboptimal because the + * behavior cannot be overriden, but it's much less work to implement. + * If you ever *do* need an override that doesn't exist, it's not hard + * to convert the degenerate pattern into the proper thing. + */ use middle::subst; use middle::subst::VecPerParamSpace; use middle::ty; +use middle::traits; use middle::typeck; use std::rc::Rc; use syntax::ast; @@ -97,6 +124,10 @@ pub trait TypeFolder<'tcx> { fn fold_item_substs(&mut self, i: ty::ItemSubsts) -> ty::ItemSubsts { super_fold_item_substs(self, i) } + + fn fold_obligation(&mut self, o: &traits::Obligation) -> traits::Obligation { + super_fold_obligation(self, o) + } } /////////////////////////////////////////////////////////////////////////// @@ -110,6 +141,12 @@ pub trait TypeFolder<'tcx> { // can easily refactor the folding into the TypeFolder trait as // needed. +impl TypeFoldable for () { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, _: &mut F) -> () { + () + } +} + impl TypeFoldable for Option { fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Option { self.as_ref().map(|t| t.fold_with(folder)) @@ -296,13 +333,54 @@ impl TypeFoldable for ty::UnsizeKind { match *self { ty::UnsizeLength(len) => ty::UnsizeLength(len), ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n), - ty::UnsizeVtable(bounds, def_id, ref substs) => { - ty::UnsizeVtable(bounds.fold_with(folder), def_id, substs.fold_with(folder)) + ty::UnsizeVtable(ty::TyTrait{bounds, def_id, substs: ref substs}, self_ty) => { + ty::UnsizeVtable( + ty::TyTrait { + bounds: bounds.fold_with(folder), + def_id: def_id, + substs: substs.fold_with(folder) + }, + self_ty.fold_with(folder)) } } } } +impl TypeFoldable for traits::Obligation { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Obligation { + folder.fold_obligation(self) + } +} + +impl TypeFoldable for traits::VtableImpl { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableImpl { + traits::VtableImpl { + impl_def_id: self.impl_def_id, + substs: self.substs.fold_with(folder), + nested: self.nested.fold_with(folder), + } + } +} + +impl TypeFoldable for traits::Vtable { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable { + match *self { + traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)), + traits::VtableUnboxedClosure(d) => traits::VtableUnboxedClosure(d), + traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)), + traits::VtableBuiltin => traits::VtableBuiltin, + } + } +} + +impl TypeFoldable for traits::VtableParam { + fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableParam { + traits::VtableParam { + bound: self.bound.fold_with(folder), + } + } +} + /////////////////////////////////////////////////////////////////////////// // "super" routines: these are the default implementations for TypeFolder. // @@ -482,6 +560,17 @@ pub fn super_fold_item_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T, } } +pub fn super_fold_obligation<'tcx, T:TypeFolder<'tcx>>(this: &mut T, + obligation: &traits::Obligation) + -> traits::Obligation +{ + traits::Obligation { + cause: obligation.cause, + recursion_depth: obligation.recursion_depth, + trait_ref: obligation.trait_ref.fold_with(this), + } +} + /////////////////////////////////////////////////////////////////////////// // Some sample folders @@ -591,3 +680,28 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { } } } + +/////////////////////////////////////////////////////////////////////////// +// Region eraser +// +// Replaces all free regions with 'static. Useful in trans. + +pub struct RegionEraser<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx>, +} + +pub fn erase_regions(tcx: &ty::ctxt, t: T) -> T { + let mut eraser = RegionEraser { tcx: tcx }; + t.fold_with(&mut eraser) +} + +impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> { + fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReLateBound(..) | ty::ReEarlyBound(..) => r, + _ => ty::ReStatic + } + } +} diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 1602dfeaa280a..46aba94a5f12a 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -555,11 +555,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) { None); match tcx.def_map.borrow().find(&pat.id) { Some(def) => { - let item_type = ty::lookup_item_type(tcx, def.def_id()); - let substitutions = fcx.infcx().fresh_substs_for_type( - pat.span, &item_type.generics); + let struct_ty = fcx.instantiate_item_type(pat.span, def.def_id()); check_struct_pat(pcx, pat.span, fields.as_slice(), - etc, def.def_id(), &substitutions); + etc, def.def_id(), &struct_ty.substs); } None => { tcx.sess.span_bug(pat.span, diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index ecda5890fc5b4..074074c13ae90 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -82,6 +82,7 @@ obtained the type `Foo`, we would never match this method. use middle::subst; use middle::subst::Subst; +use middle::traits; use middle::ty::*; use middle::ty; use middle::typeck::astconv::AstConv; @@ -91,7 +92,6 @@ use middle::typeck::infer; use middle::typeck::MethodCallee; use middle::typeck::{MethodOrigin, MethodParam}; use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject}; -use middle::typeck::{param_index}; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::TypeAndSubsts; use util::common::indenter; @@ -538,14 +538,12 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { return } - let vcx = self.fcx.vtable_context(); - // Get the tupled type of the arguments. let arguments_type = *closure_function_type.sig.inputs.get(0); let return_type = closure_function_type.sig.output; let closure_region = - vcx.infcx.next_region_var(infer::MiscVariable(self.span)); + self.fcx.infcx().next_region_var(infer::MiscVariable(self.span)); let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(), closure_did, closure_region); @@ -555,7 +553,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { rcvr_substs: subst::Substs::new_trait( vec![arguments_type, return_type], vec![], - *vcx.infcx.next_ty_vars(1).get(0)), + *self.fcx.infcx().next_ty_vars(1).get(0)), method_ty: method, origin: MethodStaticUnboxedClosure(closure_did), }); @@ -618,7 +616,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.push_inherent_candidates_from_bounds_inner( &[trait_ref.clone()], - |_this, new_trait_ref, m, method_num, _bound_num| { + |_this, new_trait_ref, m, method_num| { let vtable_index = get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num); @@ -633,7 +631,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { rcvr_substs: new_trait_ref.substs.clone(), method_ty: Rc::new(m), origin: MethodObject(MethodObject { - trait_id: new_trait_ref.def_id, + trait_ref: new_trait_ref, object_trait_id: did, method_num: method_num, real_index: vtable_index @@ -652,8 +650,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { rcvr_ty, param_ty.space, param_ty.idx, - restrict_to, - param_index { space: param_ty.space, index: param_ty.idx }); + restrict_to); } @@ -661,13 +658,12 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self_ty: ty::t, space: subst::ParamSpace, index: uint, - restrict_to: Option, - param: param_index) { + restrict_to: Option) { let bounds = self.fcx.inh.param_env.bounds.get(space, index).trait_bounds .as_slice(); self.push_inherent_candidates_from_bounds_inner(bounds, - |this, trait_ref, m, method_num, bound_num| { + |this, trait_ref, m, method_num| { match restrict_to { Some(trait_did) => { if trait_did != trait_ref.def_id { @@ -701,10 +697,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { rcvr_substs: trait_ref.substs.clone(), method_ty: m, origin: MethodParam(MethodParam { - trait_id: trait_ref.def_id, + trait_ref: trait_ref, method_num: method_num, - param_num: param, - bound_num: bound_num, }) }) }) @@ -718,15 +712,16 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { mk_cand: |this: &mut LookupContext, tr: Rc, m: Rc, - method_num: uint, - bound_num: uint| - -> Option) { + method_num: uint| + -> Option) + { let tcx = self.tcx(); - let mut next_bound_idx = 0; // count only trait bounds - - ty::each_bound_trait_and_supertraits(tcx, bounds, |bound_trait_ref| { - let this_bound_idx = next_bound_idx; - next_bound_idx += 1; + let mut cache = HashSet::new(); + for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { + // Already visited this trait, skip it. + if !cache.insert(bound_trait_ref.def_id) { + continue; + } let trait_items = ty::trait_items(tcx, bound_trait_ref.def_id); match trait_items.iter().position(|ti| { @@ -745,8 +740,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { match mk_cand(self, bound_trait_ref, method, - pos, - this_bound_idx) { + pos) { Some(cand) => { debug!("pushing inherent candidate for param: {}", cand.repr(self.tcx())); @@ -761,8 +755,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { // check next trait or bound } } - true - }); + } } @@ -773,7 +766,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { let impl_items = self.tcx().impl_items.borrow(); for impl_infos in self.tcx().inherent_impls.borrow().find(&did).iter() { - for impl_did in impl_infos.borrow().iter() { + for impl_did in impl_infos.iter() { let items = impl_items.get(impl_did); self.push_candidates_from_impl(*impl_did, items.as_slice(), @@ -825,11 +818,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { // determine the `self` of the impl with fresh // variables for each parameter: let span = self.self_expr.map_or(self.span, |e| e.span); - let vcx = self.fcx.vtable_context(); let TypeAndSubsts { substs: impl_substs, ty: impl_ty - } = impl_self_ty(&vcx, span, impl_did); + } = impl_self_ty(self.fcx, span, impl_did); let condition = match method.explicit_self { ByReferenceExplicitSelfCategory(_, mt) if mt == MutMutable => @@ -877,7 +869,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { adjustment {:?} for {}", adjustment, self.ty_to_string(self_ty)); match adjustment { Some((self_expr_id, adj)) => { - self.fcx.write_adjustment(self_expr_id, adj); + self.fcx.write_adjustment(self_expr_id, self.span, adj); } None => {} } @@ -1109,7 +1101,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { ty_err => None, - ty_infer(TyVar(_)) => { + ty_infer(TyVar(_)) | + ty_infer(SkolemizedTy(_)) | + ty_infer(SkolemizedIntTy(_)) => { self.bug(format!("unexpected type: {}", self.ty_to_string(self_ty)).as_slice()); } @@ -1150,6 +1144,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { Some(self_expr_id) => { self.fcx.write_adjustment( self_expr_id, + self.span, ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, autoref: Some(kind(region, *mutbl)) @@ -1209,7 +1204,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { // return something so we don't get errors for every mutability return Some(MethodCallee { - origin: relevant_candidates.get(0).origin, + origin: relevant_candidates.get(0).origin.clone(), ty: ty::mk_err(), substs: subst::Substs::empty() }); @@ -1237,12 +1232,14 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { candidate_b.repr(self.tcx())); match (&candidate_a.origin, &candidate_b.origin) { (&MethodParam(ref p1), &MethodParam(ref p2)) => { - let same_trait = p1.trait_id == p2.trait_id; - let same_method = p1.method_num == p2.method_num; - let same_param = p1.param_num == p2.param_num; - // The bound number may be different because - // multiple bounds may lead to the same trait - // impl + let same_trait = + p1.trait_ref.def_id == p2.trait_ref.def_id; + let same_method = + p1.method_num == p2.method_num; + // it's ok to compare self-ty with `==` here because + // they are always a TyParam + let same_param = + p1.trait_ref.self_ty() == p2.trait_ref.self_ty(); same_trait && same_method && same_param } _ => false @@ -1369,13 +1366,13 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } } - self.fcx.add_region_obligations_for_parameters( - self.span, + self.fcx.add_obligations_for_parameters( + traits::ObligationCause::misc(self.span), &all_substs, &candidate.method_ty.generics); MethodCallee { - origin: candidate.origin, + origin: candidate.origin.clone(), ty: fty, substs: all_substs } @@ -1452,10 +1449,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { MethodStaticUnboxedClosure(_) => bad = false, // FIXME: does this properly enforce this on everything now // that self has been merged in? -sully - MethodParam(MethodParam { trait_id: trait_id, .. }) | - MethodObject(MethodObject { trait_id: trait_id, .. }) => { + MethodParam(MethodParam { trait_ref: ref trait_ref, .. }) | + MethodObject(MethodObject { trait_ref: ref trait_ref, .. }) => { bad = self.tcx().destructor_for_type.borrow() - .contains_key(&trait_id); + .contains_key(&trait_ref.def_id); } } @@ -1602,10 +1599,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.report_static_candidate(idx, did) } MethodParam(ref mp) => { - self.report_param_candidate(idx, (*mp).trait_id) + self.report_param_candidate(idx, mp.trait_ref.def_id) } MethodObject(ref mo) => { - self.report_trait_candidate(idx, mo.trait_id) + self.report_trait_candidate(idx, mo.trait_ref.def_id) } } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 375fc75bf62f5..20fe8186adf40 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -87,6 +87,7 @@ use middle::pat_util::pat_id_map; use middle::pat_util; use middle::subst; use middle::subst::{Subst, Substs, VecPerParamSpace, ParamSpace}; +use middle::traits; use middle::ty::{FnSig, VariantInfo}; use middle::ty::{Polytype}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; @@ -102,15 +103,14 @@ use middle::typeck::check::method::{CheckTraitsAndInherentMethods}; use middle::typeck::check::method::{DontAutoderefReceiver}; use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods}; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; -use middle::typeck::check::vtable::VtableContext; use middle::typeck::CrateCtxt; use middle::typeck::infer::{resolve_type, force_tvar}; use middle::typeck::infer; use middle::typeck::rscope::RegionScope; use middle::typeck::{lookup_def_ccx}; use middle::typeck::no_params; -use middle::typeck::{require_same_types, vtable_map}; -use middle::typeck::{MethodCall, MethodMap}; +use middle::typeck::{require_same_types}; +use middle::typeck::{MethodCall, MethodMap, ObjectCastMap}; use middle::typeck::{TypeAndSubsts}; use middle::typeck; use middle::lang_items::TypeIdLangItem; @@ -143,12 +143,13 @@ use syntax::visit::Visitor; use syntax; pub mod _match; -pub mod vtable; +pub mod vtable2; // New trait code pub mod writeback; pub mod regionmanip; pub mod regionck; pub mod demand; pub mod method; +pub mod wf; /// Fields that are part of a `FnCtxt` which are inherited by /// closures defined within the function. For example: @@ -170,9 +171,9 @@ pub struct Inherited<'a, 'tcx: 'a> { item_substs: RefCell>, adjustments: RefCell>, method_map: MethodMap, - vtable_map: vtable_map, upvar_borrow_map: RefCell, unboxed_closures: RefCell>, + object_cast_map: ObjectCastMap, // A mapping from each fn's id to its signature, with all bound // regions replaced with free ones. Unlike the other tables, this @@ -190,7 +191,7 @@ pub struct Inherited<'a, 'tcx: 'a> { // then in some expression `let x = Foo { ... }` it will // instantiate the type parameter `T` with a fresh type `$0`. At // the same time, it will record a region obligation of - // `$0:'static`. This will get checked later by regionck. (We + // `$0:'static`. This will get checked later by regionck. (We // can't generally check these things right away because we have // to wait until types are resolved.) // @@ -204,6 +205,9 @@ pub struct Inherited<'a, 'tcx: 'a> { // obligations (otherwise, it's easy to fail to walk to a // particular node-id). region_obligations: RefCell>>, + + // Tracks trait obligations incurred during this function body. + fulfillment_cx: RefCell, } struct RegionObligation { @@ -335,11 +339,12 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { item_substs: RefCell::new(NodeMap::new()), adjustments: RefCell::new(NodeMap::new()), method_map: RefCell::new(FnvHashMap::new()), - vtable_map: RefCell::new(FnvHashMap::new()), + object_cast_map: RefCell::new(NodeMap::new()), upvar_borrow_map: RefCell::new(HashMap::new()), unboxed_closures: RefCell::new(DefIdMap::new()), fn_sig_map: RefCell::new(NodeMap::new()), region_obligations: RefCell::new(NodeMap::new()), + fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), } } } @@ -369,20 +374,12 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>) free_substs: subst::Substs::empty(), bounds: subst::VecPerParamSpace::empty(), implicit_region_bound: ty::ReStatic, + caller_obligations: subst::VecPerParamSpace::empty(), }; Inherited::new(ccx.tcx, param_env) } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } -struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } - -impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> { - fn visit_item(&mut self, i: &ast::Item) { - check_type_well_formed(self.ccx, i); - visit::walk_item(self, i); - } -} - impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemTypesVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &ast::Item) { @@ -404,8 +401,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemSizedTypesVisitor<'a, 'tcx> { pub fn check_item_types(ccx: &CrateCtxt) { let krate = ccx.tcx.map.krate(); - - let mut visit = CheckTypeWellFormedVisitor { ccx: ccx }; + let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx); visit::walk_crate(&mut visit, krate); // If types are not well-formed, it leads to all manner of errors @@ -437,9 +433,10 @@ fn check_bare_fn(ccx: &CrateCtxt, let fcx = check_fn(ccx, fn_ty.fn_style, id, &fn_ty.sig, decl, id, body, &inh); - vtable::resolve_in_block(&fcx, body); + vtable2::select_all_fcx_obligations_or_error(&fcx); regionck::regionck_fn(&fcx, id, body); writeback::resolve_type_vars_in_fn(&fcx, decl, body); + vtable2::check_builtin_bound_obligations(&fcx); // must happen after writeback } _ => ccx.tcx.sess.impossible_case(body.span, "check_bare_fn: function type expected") @@ -451,19 +448,21 @@ struct GatherLocalsVisitor<'a, 'tcx: 'a> { } impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { - fn assign(&mut self, nid: ast::NodeId, ty_opt: Option) { - match ty_opt { - None => { - // infer the variable's type - let var_id = self.fcx.infcx().next_ty_var_id(); - let var_ty = ty::mk_var(self.fcx.tcx(), var_id); - self.fcx.inh.locals.borrow_mut().insert(nid, var_ty); - } - Some(typ) => { - // take type that the user specified - self.fcx.inh.locals.borrow_mut().insert(nid, typ); - } + fn assign(&mut self, _span: Span, nid: ast::NodeId, ty_opt: Option) -> ty::t { + match ty_opt { + None => { + // infer the variable's type + let var_id = self.fcx.infcx().next_ty_var_id(); + let var_ty = ty::mk_var(self.fcx.tcx(), var_id); + self.fcx.inh.locals.borrow_mut().insert(nid, var_ty); + var_ty } + Some(typ) => { + // take type that the user specified + self.fcx.inh.locals.borrow_mut().insert(nid, typ); + typ + } + } } } @@ -474,7 +473,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> { ast::TyInfer => None, _ => Some(self.fcx.to_ty(&*local.ty)) }; - self.assign(local.id, o_ty); + self.assign(local.span, local.id, o_ty); debug!("Local variable {} is assigned type {}", self.fcx.pat_to_string(&*local.pat), self.fcx.infcx().ty_to_string( @@ -484,19 +483,23 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> { // Add pattern bindings. fn visit_pat(&mut self, p: &ast::Pat) { - match p.node { - ast::PatIdent(_, ref path1, _) - if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => { - self.assign(p.id, None); - debug!("Pattern binding {} is assigned to {}", - token::get_ident(path1.node), - self.fcx.infcx().ty_to_string( - self.fcx.inh.locals.borrow().get_copy(&p.id))); - } - _ => {} - } - visit::walk_pat(self, p); - + match p.node { + ast::PatIdent(_, ref path1, _) + if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => { + let var_ty = self.assign(p.span, p.id, None); + + self.fcx.require_type_is_sized(var_ty, p.span, + traits::VariableType(p.id)); + + debug!("Pattern binding {} is assigned to {} with type {}", + token::get_ident(path1.node), + self.fcx.infcx().ty_to_string( + self.fcx.inh.locals.borrow().get_copy(&p.id)), + var_ty.repr(self.fcx.tcx())); + } + _ => {} + } + visit::walk_pat(self, p); } fn visit_block(&mut self, b: &ast::Block) { @@ -592,11 +595,14 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, // Add formal parameters. for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) { // Create type variables for each argument. - pat_util::pat_bindings(&tcx.def_map, - &*input.pat, - |_bm, pat_id, _sp, _path| { - visit.assign(pat_id, None); - }); + pat_util::pat_bindings( + &tcx.def_map, + &*input.pat, + |_bm, pat_id, sp, _path| { + let var_ty = visit.assign(sp, pat_id, None); + fcx.require_type_is_sized(var_ty, sp, + traits::VariableType(pat_id)); + }); // Check the pattern. let pcx = pat_ctxt { @@ -713,71 +719,6 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { } } -fn check_type_well_formed(ccx: &CrateCtxt, item: &ast::Item) { - /*! - * Checks that the field types (in a struct def'n) or - * argument types (in an enum def'n) are well-formed, - * meaning that they do not require any constraints not - * declared in the struct definition itself. - * For example, this definition would be illegal: - * - * struct Ref<'a, T> { x: &'a T } - * - * because the type did not declare that `T:'a`. - * - * We do this check as a pre-pass before checking fn bodies - * because if these constraints are not included it frequently - * leads to confusing errors in fn bodies. So it's better to check - * the types first. - */ - - debug!("check_type_well_formed(it.id={}, it.ident={})", - item.id, - ty::item_path_str(ccx.tcx, local_def(item.id))); - - match item.node { - ast::ItemStruct(..) => { - check_type_defn(ccx, item, |fcx| { - ty::struct_fields(ccx.tcx, local_def(item.id), - &fcx.inh.param_env.free_substs) - .iter() - .map(|f| f.mt.ty) - .collect() - }); - } - ast::ItemEnum(..) => { - check_type_defn(ccx, item, |fcx| { - ty::substd_enum_variants(ccx.tcx, local_def(item.id), - &fcx.inh.param_env.free_substs) - .iter() - .flat_map(|variant| { - variant.args - .iter() - .map(|&arg_ty| arg_ty) - }) - .collect() - }); - } - _ => {} - } - - fn check_type_defn(ccx: &CrateCtxt, - item: &ast::Item, - lookup_fields: |&FnCtxt| -> Vec) - { - let item_def_id = local_def(item.id); - let polytype = ty::lookup_item_type(ccx.tcx, item_def_id); - let param_env = - ty::construct_parameter_environment(ccx.tcx, - &polytype.generics, - item.id); - let inh = Inherited::new(ccx.tcx, param_env); - let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id); - let field_tys = lookup_fields(&fcx); - regionck::regionck_type_defn(&fcx, item.span, field_tys.as_slice()); - } -} - pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) { debug!("check_item(it.id={}, it.ident={})", it.id, @@ -836,7 +777,6 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { ast_trait_ref, &*impl_trait_ref, impl_items.as_slice()); - vtable::resolve_impl(ccx.tcx, it, &impl_pty.generics, &*impl_trait_ref); } None => { } } @@ -1409,10 +1349,12 @@ fn compare_impl_method(tcx: &ty::ctxt, } fn check_cast(fcx: &FnCtxt, + cast_expr: &ast::Expr, e: &ast::Expr, - t: &ast::Ty, - id: ast::NodeId, - span: Span) { + t: &ast::Ty) { + let id = cast_expr.id; + let span = cast_expr.span; + // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. let t_1 = fcx.to_ty(t); @@ -1443,6 +1385,7 @@ fn check_cast(fcx: &FnCtxt, if ty::type_is_trait(t_1) { // This will be looked up later on. + vtable2::check_object_cast(fcx, cast_expr, e, t_1); fcx.write_ty(id, t_1); return } @@ -1582,14 +1525,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn err_count_since_creation(&self) -> uint { self.ccx.tcx.sess.err_count() - self.err_count_on_creation } - - pub fn vtable_context<'a>(&'a self) -> VtableContext<'a, 'tcx> { - VtableContext { - infcx: self.infcx(), - param_env: &self.inh.param_env, - unboxed_closures: &self.inh.unboxed_closures, - } - } } impl<'a, 'tcx> RegionScope for infer::InferCtxt<'a, 'tcx> { @@ -1629,6 +1564,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.inh.node_types.borrow_mut().insert(node_id, ty); } + pub fn write_object_cast(&self, + key: ast::NodeId, + trait_ref: Rc) { + debug!("write_object_cast key={} trait_ref={}", + key, trait_ref.repr(self.tcx())); + self.inh.object_cast_map.borrow_mut().insert(key, trait_ref); + } + pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts) { if !substs.substs.is_noop() { debug!("write_substs({}, {}) in fcx {}", @@ -1651,10 +1594,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_autoderef_adjustment(&self, node_id: ast::NodeId, + span: Span, derefs: uint) { if derefs == 0 { return; } self.write_adjustment( node_id, + span, ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: derefs, autoref: None }) @@ -1663,11 +1608,109 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_adjustment(&self, node_id: ast::NodeId, + span: Span, adj: ty::AutoAdjustment) { debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj); + + // Careful: adjustments can imply trait obligations if we are + // casting from a concrete type to an object type. I think + // it'd probably be nicer to move the logic that creates the + // obligation into the code that creates the adjustment, but + // that's a bit awkward, so instead we go digging and pull the + // obligation out here. + self.register_adjustment_obligations(span, &adj); self.inh.adjustments.borrow_mut().insert(node_id, adj); } + fn register_adjustment_obligations(&self, + span: Span, + adj: &ty::AutoAdjustment) { + match *adj { + ty::AutoAddEnv(..) => { } + ty::AutoDerefRef(ref d_r) => { + match d_r.autoref { + Some(ref a_r) => { + self.register_autoref_obligations(span, a_r); + } + None => {} + } + } + } + } + + fn register_autoref_obligations(&self, + span: Span, + autoref: &ty::AutoRef) { + match *autoref { + ty::AutoUnsize(ref unsize) => { + self.register_unsize_obligations(span, unsize); + } + ty::AutoPtr(_, _, None) | + ty::AutoUnsafe(_, None) => { + } + ty::AutoPtr(_, _, Some(ref a_r)) | + ty::AutoUnsafe(_, Some(ref a_r)) => { + self.register_autoref_obligations(span, &**a_r) + } + ty::AutoUnsizeUniq(ref unsize) => { + self.register_unsize_obligations(span, unsize); + } + } + } + + fn register_unsize_obligations(&self, + span: Span, + unsize: &ty::UnsizeKind) { + debug!("register_unsize_obligations: unsize={:?}", unsize); + + match *unsize { + ty::UnsizeLength(..) => {} + ty::UnsizeStruct(ref u, _) => { + self.register_unsize_obligations(span, &**u) + } + ty::UnsizeVtable(ref ty_trait, self_ty) => { + vtable2::register_object_cast_obligations(self, + span, + ty_trait, + self_ty); + } + } + } + + pub fn instantiate_item_type(&self, + span: Span, + def_id: ast::DefId) + -> TypeAndSubsts + { + /*! + * Returns the type of `def_id` with all generics replaced by + * by fresh type/region variables. Also returns the + * substitution from the type parameters on `def_id` to the + * fresh variables. Registers any trait obligations specified + * on `def_id` at the same time. + */ + + let polytype = + ty::lookup_item_type(self.tcx(), def_id); + let substs = + self.infcx().fresh_substs_for_generics( + span, + &polytype.generics); + self.add_obligations_for_parameters( + traits::ObligationCause::new( + span, + traits::ItemObligation(def_id)), + &substs, + &polytype.generics); + let monotype = + polytype.ty.subst(self.tcx(), &substs); + + TypeAndSubsts { + ty: monotype, + substs: substs + } + } + pub fn write_nil(&self, node_id: ast::NodeId) { self.write_ty(node_id, ty::mk_nil()); } @@ -1678,8 +1721,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.write_ty(node_id, ty::mk_err()); } + pub fn require_type_meets(&self, + ty: ty::t, + span: Span, + code: traits::ObligationCauseCode, + bound: ty::BuiltinBound) + { + self.register_obligation( + traits::obligation_for_builtin_bound( + self.tcx(), + traits::ObligationCause::new(span, code), + ty, + bound)); + } + + pub fn require_type_is_sized(&self, + ty: ty::t, + span: Span, + code: traits::ObligationCauseCode) + { + self.require_type_meets(ty, span, code, ty::BoundSized); + } + + pub fn require_expr_have_sized_type(&self, + expr: &ast::Expr, + code: traits::ObligationCauseCode) + { + self.require_type_is_sized(self.expr_ty(expr), expr.span, code); + } + + pub fn register_obligation(&self, + obligation: traits::Obligation) + { + debug!("register_obligation({})", + obligation.repr(self.tcx())); + + self.inh.fulfillment_cx + .borrow_mut() + .register_obligation(self.tcx(), obligation); + } + pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t { - ast_ty_to_ty(self, self.infcx(), ast_t) + let t = ast_ty_to_ty(self, self.infcx(), ast_t); + + let mut bounds_checker = wf::BoundsChecker::new(self, + ast_t.span, + self.body_id, + None); + bounds_checker.check_ty(t); + + t } pub fn pat_to_string(&self, pat: &ast::Pat) -> String { @@ -1761,7 +1852,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(None) => Ok(()), Err(ref e) => Err((*e)), Ok(Some(adjustment)) => { - self.write_adjustment(expr.id, adjustment); + self.write_adjustment(expr.id, expr.span, adjustment); Ok(()) } } @@ -1829,10 +1920,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { origin: origin }); } - pub fn add_region_obligations_for_parameters(&self, - span: Span, - substs: &Substs, - generics: &ty::Generics) + pub fn add_obligations_for_parameters(&self, + cause: traits::ObligationCause, + substs: &Substs, + generics: &ty::Generics) { /*! * Given a set of generic parameter definitions (`generics`) @@ -1853,10 +1944,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { * locally. */ - debug!("add_region_obligations_for_parameters(substs={}, generics={})", + debug!("add_obligations_for_parameters(substs={}, generics={})", substs.repr(self.tcx()), generics.repr(self.tcx())); + self.add_trait_obligations_for_generics(cause, substs, generics); + self.add_region_obligations_for_generics(cause, substs, generics); + } + + fn add_trait_obligations_for_generics(&self, + cause: traits::ObligationCause, + substs: &Substs, + generics: &ty::Generics) { + let obligations = + traits::obligations_for_generics(self.tcx(), + cause, + generics, + substs); + obligations.map_move(|o| self.register_obligation(o)); + } + + fn add_region_obligations_for_generics(&self, + cause: traits::ObligationCause, + substs: &Substs, + generics: &ty::Generics) + { assert_eq!(generics.types.iter().len(), substs.types.iter().len()); for (type_def, &type_param) in @@ -1867,8 +1979,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { idx: type_def.index, def_id: type_def.def_id }; let bounds = type_def.bounds.subst(self.tcx(), substs); - add_region_obligations_for_type_parameter( - self, span, param_ty, &bounds, type_param); + self.add_region_obligations_for_type_parameter( + cause.span, param_ty, &bounds, type_param); } assert_eq!(generics.regions.iter().len(), @@ -1878,42 +1990,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { substs.regions().iter()) { let bounds = region_def.bounds.subst(self.tcx(), substs); - add_region_obligations_for_region_parameter( - self, span, bounds.as_slice(), region_param); - } - - fn add_region_obligations_for_type_parameter( - fcx: &FnCtxt, - span: Span, - param_ty: ty::ParamTy, - param_bound: &ty::ParamBounds, - ty: ty::t) - { - // For each declared region bound `T:r`, `T` must outlive `r`. - let region_bounds = - ty::required_region_bounds( - fcx.tcx(), - param_bound.opt_region_bound.as_slice(), - param_bound.builtin_bounds, - param_bound.trait_bounds.as_slice()); - for &r in region_bounds.iter() { - let origin = infer::RelateParamBound(span, param_ty, ty); - fcx.register_region_obligation(origin, ty, r); - } + self.add_region_obligations_for_region_parameter( + cause.span, bounds.as_slice(), region_param); } + } - fn add_region_obligations_for_region_parameter( - fcx: &FnCtxt, - span: Span, - region_bounds: &[ty::Region], - region_param: ty::Region) - { - for &b in region_bounds.iter() { - // For each bound `region:b`, `b <= region` must hold - // (i.e., `region` must outlive `b`). - let origin = infer::RelateRegionParamBound(span); - fcx.mk_subr(origin, b, region_param); - } + fn add_region_obligations_for_type_parameter(&self, + span: Span, + param_ty: ty::ParamTy, + param_bound: &ty::ParamBounds, + ty: ty::t) + { + // For each declared region bound `T:r`, `T` must outlive `r`. + let region_bounds = + ty::required_region_bounds( + self.tcx(), + param_bound.opt_region_bound.as_slice(), + param_bound.builtin_bounds, + param_bound.trait_bounds.as_slice()); + for &r in region_bounds.iter() { + let origin = infer::RelateParamBound(span, param_ty, ty); + self.register_region_obligation(origin, ty, r); + } + } + + fn add_region_obligations_for_region_parameter(&self, + span: Span, + region_bounds: &[ty::Region], + region_param: ty::Region) + { + for &b in region_bounds.iter() { + // For each bound `region:b`, `b <= region` must hold + // (i.e., `region` must outlive `b`). + let origin = infer::RelateRegionParamBound(span); + self.mk_subr(origin, b, region_param); } } } @@ -2272,7 +2382,7 @@ fn check_method_argument_types(fcx: &FnCtxt, fn check_argument_types(fcx: &FnCtxt, sp: Span, fn_inputs: &[ty::t], - callee_expr: &ast::Expr, + _callee_expr: &ast::Expr, args: &[P], deref_args: DerefArgs, variadic: bool, @@ -2369,7 +2479,7 @@ fn check_argument_types(fcx: &FnCtxt, // an "opportunistic" vtable resolution of any trait // bounds on the call. if check_blocks { - vtable::early_resolve_expr(callee_expr, fcx, true); + vtable2::select_fcx_obligations_where_possible(fcx); } // For variadic functions, we don't have a declared type for all of @@ -2568,16 +2678,15 @@ fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr, check_expr_with_unifier(fcx, expr, NoExpectation, lvalue_pref, || ()) } - // determine the `self` type, using fresh variables for all variables // declared on the impl declaration e.g., `impl for ~[(A,B)]` // would return ($0, $1) where $0 and $1 are freshly instantiated type // variables. -pub fn impl_self_ty(vcx: &VtableContext, +pub fn impl_self_ty(fcx: &FnCtxt, span: Span, // (potential) receiver for this impl did: ast::DefId) -> TypeAndSubsts { - let tcx = vcx.tcx(); + let tcx = fcx.tcx(); let ity = ty::lookup_item_type(tcx, did); let (n_tps, rps, raw_ty) = @@ -2585,8 +2694,8 @@ pub fn impl_self_ty(vcx: &VtableContext, ity.generics.regions.get_slice(subst::TypeSpace), ity.ty); - let rps = vcx.infcx.region_vars_for_defs(span, rps); - let tps = vcx.infcx.next_ty_vars(n_tps); + let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); + let tps = fcx.inh.infcx.next_ty_vars(n_tps); let substs = subst::Substs::new_type(tps, rps); let substd_ty = raw_ty.subst(tcx, &substs); @@ -3260,7 +3369,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, match field_ty { Some(field_ty) => { fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); return; } None => {} @@ -3344,7 +3453,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, match field_ty { Some(field_ty) => { fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); return; } None => {} @@ -3467,15 +3576,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt, base_expr: Option<&ast::Expr>) { let tcx = fcx.ccx.tcx; - // Look up the number of type parameters and the raw type, and - // determine whether the class is region-parameterized. - let item_type = ty::lookup_item_type(tcx, class_id); - let raw_type = item_type.ty; - // Generate the struct type. - let substitutions = fcx.infcx().fresh_substs_for_type( - span, &item_type.generics); - let mut struct_type = raw_type.subst(tcx, &substitutions); + let TypeAndSubsts { + ty: mut struct_type, + substs: struct_substs + } = fcx.instantiate_item_type(span, class_id); // Look up and check the fields. let class_fields = ty::lookup_struct_fields(tcx, class_id); @@ -3484,7 +3589,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, span, class_id, id, - substitutions, + struct_substs, class_fields.as_slice(), fields, base_expr.is_none()); @@ -3517,9 +3622,10 @@ fn check_expr_with_unifier(fcx: &FnCtxt, // Look up the number of type parameters and the raw type, and // determine whether the enum is region-parameterized. - let item_type = ty::lookup_item_type(tcx, enum_id); - let substitutions = fcx.infcx().fresh_substs_for_type(span, &item_type.generics); - let enum_type = item_type.ty.subst(tcx, &substitutions); + let TypeAndSubsts { + ty: enum_type, + substs: substitutions + } = fcx.instantiate_item_type(span, enum_id); // Look up and check the enum variant fields. let variant_fields = ty::lookup_struct_fields(tcx, variant_id); @@ -3619,6 +3725,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, span_err!(tcx.sess, lhs.span, E0067, "illegal left-hand side expression"); } + fcx.require_expr_have_sized_type(&**lhs, traits::AssignmentLhsSized); + // Overwrite result of check_binop...this preserves existing behavior // but seems quite dubious with regard to user-defined methods // and so forth. - Niko @@ -3833,6 +3941,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, check_expr_has_type(fcx, &**rhs, lhs_ty); let rhs_ty = fcx.expr_ty(&**rhs); + fcx.require_expr_have_sized_type(&**lhs, traits::AssignmentLhsSized); + if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) { fcx.write_error(id); } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) { @@ -3863,7 +3973,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ast::ExprForLoop(ref pat, ref head, ref block, _) => { check_expr(fcx, &**head); let typ = lookup_method_for_for_loop(fcx, &**head, expr.id); - vtable::early_resolve_expr(expr, fcx, true); + vtable2::select_fcx_obligations_where_possible(fcx); let pcx = pat_ctxt { fcx: fcx, @@ -3958,7 +4068,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } _ => {} } - check_cast(fcx, &**e, &**t, id, expr.span); + check_cast(fcx, expr, &**e, &**t); } ast::ExprVec(ref args) => { let uty = match expected { @@ -4015,6 +4125,16 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } }; + if count > 1 { + // For [foo, ..n] where n > 1, `foo` must have + // Copy type: + fcx.require_type_meets( + t, + expr.span, + traits::RepeatVec, + ty::BoundCopy); + } + if ty::type_is_error(element_ty) { fcx.write_error(id); } else if ty::type_is_bot(element_ty) { @@ -4143,6 +4263,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } } } + + fcx.require_expr_have_sized_type(expr, traits::StructInitializerSized); } ast::ExprField(ref base, ref field, ref tys) => { check_field(fcx, expr, lvalue_pref, &**base, field, tys.as_slice()); @@ -4167,7 +4289,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, Some(ty) => { check_expr_has_type(fcx, &**idx, ty::mk_uint()); fcx.write_ty(id, ty); - fcx.write_autoderef_adjustment(base.id, autoderefs); + fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); } None => { // This is an overloaded method. @@ -4520,8 +4642,10 @@ pub fn check_const_with_ty(fcx: &FnCtxt, check_expr_with_hint(fcx, e, declty); demand::coerce(fcx, e.span, declty, e); + vtable2::select_all_fcx_obligations_or_error(fcx); regionck::regionck_expr(fcx, e); writeback::resolve_type_vars_in_expr(fcx, e); + vtable2::check_builtin_bound_obligations(fcx); } /// Checks whether a type can be represented in memory. In particular, it @@ -5009,8 +5133,11 @@ pub fn instantiate_path(fcx: &FnCtxt, assert_eq!(substs.regions().len(space), region_defs.len(space)); } - fcx.add_region_obligations_for_parameters( - span, &substs, &polytype.generics); + fcx.add_obligations_for_parameters( + traits::ObligationCause::new(span, + traits::ItemObligation(def.def_id())), + &substs, + &polytype.generics); fcx.write_ty_substs(node_id, polytype.ty, ty::ItemSubsts { substs: substs, diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 95b7e03e6d9aa..45ffddf3fe80e 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -155,18 +155,9 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { fcx.infcx().resolve_regions_and_report_errors(); } -pub fn regionck_type_defn(fcx: &FnCtxt, - span: Span, - component_tys: &[ty::t]) { - let mut rcx = Rcx::new(fcx, 0); - for &component_ty in component_tys.iter() { - // Check that each type outlives the empty region. Since the - // empty region is a subregion of all others, this can't fail - // unless the type does not meet the well-formedness - // requirements. - type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span), - component_ty, ty::ReEmpty); - } +pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) { + let mut rcx = Rcx::new(fcx, item.id); + rcx.visit_region_obligations(item.id); fcx.infcx().resolve_regions_and_report_errors(); } @@ -179,6 +170,26 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) { fcx.infcx().resolve_regions_and_report_errors(); } +pub fn regionck_ensure_component_tys_wf(fcx: &FnCtxt, + span: Span, + component_tys: &[ty::t]) { + /*! + * Checks that the types in `component_tys` are well-formed. + * This will add constraints into the region graph. + * Does *not* run `resolve_regions_and_report_errors` and so forth. + */ + + let mut rcx = Rcx::new(fcx, 0); + for &component_ty in component_tys.iter() { + // Check that each type outlives the empty region. Since the + // empty region is a subregion of all others, this can't fail + // unless the type does not meet the well-formedness + // requirements. + type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span), + component_ty, ty::ReEmpty); + } +} + /////////////////////////////////////////////////////////////////////////// // INTERNALS diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs deleted file mode 100644 index 9a70cf574fc4d..0000000000000 --- a/src/librustc/middle/typeck/check/vtable.rs +++ /dev/null @@ -1,1077 +0,0 @@ -// Copyright 2012-2014 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. - - -use middle::ty; -use middle::ty::{AutoDerefRef, ParamTy}; -use middle::ty_fold::TypeFolder; -use middle::typeck::astconv::AstConv; -use middle::typeck::check::{FnCtxt, impl_self_ty}; -use middle::typeck::check::{structurally_resolved_type}; -use middle::typeck::check::regionmanip; -use middle::typeck::check::writeback; -use middle::typeck::infer::fixup_err_to_string; -use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; -use middle::typeck::infer; -use middle::typeck::{MethodCall, TypeAndSubsts}; -use middle::typeck::{param_index, vtable_error, vtable_origin, vtable_param}; -use middle::typeck::{vtable_param_res, vtable_res, vtable_static}; -use middle::typeck::{vtable_unboxed_closure}; -use middle::subst; -use middle::subst::{Subst, VecPerParamSpace}; -use util::common::indenter; -use util::nodemap::DefIdMap; -use util::ppaux; -use util::ppaux::Repr; - -use std::cell::RefCell; -use std::rc::Rc; -use std::collections::HashSet; -use syntax::ast; -use syntax::ast_util; -use syntax::codemap::Span; -use syntax::print::pprust::expr_to_string; -use syntax::visit; -use syntax::visit::Visitor; - -// vtable resolution looks for places where trait bounds are -// substituted in and figures out which vtable is used. There is some -// extra complication thrown in to support early "opportunistic" -// vtable resolution. This is a hacky mechanism that is invoked while -// typechecking function calls (after typechecking non-closure -// arguments and before typechecking closure arguments) in the hope of -// solving for the trait parameters from the impl. (For example, -// determining that if a parameter bounded by BaseIter is -// instantiated with Option, that A = int.) -// -// In early resolution mode, no vtables are recorded, and a number of -// errors are ignored. Early resolution only works if a type is -// *fully* resolved. (We could be less restrictive than that, but it -// would require much more care, and this seems to work decently in -// practice.) -// -// While resolution on a single type requires the type to be fully -// resolved, when resolving a substitution against a list of bounds, -// we do not require all of the types to be resolved in advance. -// Furthermore, we process substitutions in reverse order, which -// allows resolution on later parameters to give information on -// earlier params referenced by the typeclass bounds. -// It may be better to do something more clever, like processing fully -// resolved types first. - -/// A vtable context includes an inference context, a parameter environment, -/// and a list of unboxed closure types. -pub struct VtableContext<'a, 'tcx: 'a> { - pub infcx: &'a infer::InferCtxt<'a, 'tcx>, - pub param_env: &'a ty::ParameterEnvironment, - pub unboxed_closures: &'a RefCell>, -} - -impl<'a, 'tcx> VtableContext<'a, 'tcx> { - pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.infcx.tcx } -} - -fn lookup_vtables(vcx: &VtableContext, - span: Span, - type_param_defs: &VecPerParamSpace, - substs: &subst::Substs, - is_early: bool) - -> VecPerParamSpace { - debug!("lookup_vtables(\ - type_param_defs={}, \ - substs={}", - type_param_defs.repr(vcx.tcx()), - substs.repr(vcx.tcx())); - - // We do this backwards for reasons discussed above. - let result = type_param_defs.map_rev(|def| { - let ty = *substs.types.get(def.space, def.index); - lookup_vtables_for_param(vcx, span, Some(substs), - &def.bounds, ty, is_early) - }); - - debug!("lookup_vtables result(\ - type_param_defs={}, \ - substs={}, \ - result={})", - type_param_defs.repr(vcx.tcx()), - substs.repr(vcx.tcx()), - result.repr(vcx.tcx())); - - result -} - -fn lookup_vtables_for_param(vcx: &VtableContext, - span: Span, - // None for substs means the identity - substs: Option<&subst::Substs>, - type_param_bounds: &ty::ParamBounds, - ty: ty::t, - is_early: bool) - -> vtable_param_res { - let tcx = vcx.tcx(); - - debug!("lookup_vtables_for_param(ty={}, type_param_bounds={}, is_early={})", - ty.repr(vcx.tcx()), - type_param_bounds.repr(vcx.tcx()), - is_early); - - // ty is the value supplied for the type parameter A... - let mut param_result = Vec::new(); - - ty::each_bound_trait_and_supertraits(tcx, - type_param_bounds.trait_bounds - .as_slice(), - |trait_ref| { - // ...and here trait_ref is each bound that was declared on A, - // expressed in terms of the type parameters. - - debug!("matching ty={} trait_ref={}", - ty.repr(vcx.tcx()), - trait_ref.repr(vcx.tcx())); - - ty::populate_implementations_for_trait_if_necessary(tcx, - trait_ref.def_id); - - // Substitute the values of the type parameters that may - // appear in the bound. - let trait_ref = substs.as_ref().map_or(trait_ref.clone(), |substs| { - debug!("about to subst: {}, {}", - trait_ref.repr(tcx), substs.repr(tcx)); - trait_ref.subst(tcx, *substs) - }); - - debug!("after subst: {}", trait_ref.repr(tcx)); - - match lookup_vtable(vcx, span, ty, trait_ref.clone(), is_early) { - Some(vtable) => param_result.push(vtable), - None => { - vcx.tcx().sess.span_err(span, - format!("failed to find an implementation of \ - trait {} for {}", - vcx.infcx.trait_ref_to_string(&*trait_ref), - vcx.infcx.ty_to_string(ty)).as_slice()); - param_result.push(vtable_error) - } - } - true - }); - - debug!("lookup_vtables_for_param result(\ - type_param_bounds={}, \ - ty={}, \ - result={})", - type_param_bounds.repr(vcx.tcx()), - ty.repr(vcx.tcx()), - param_result.repr(vcx.tcx())); - - param_result -} - -fn relate_trait_refs(vcx: &VtableContext, - span: Span, - act_trait_ref: Rc, - exp_trait_ref: Rc) { - /*! - * - * Checks that an implementation of `act_trait_ref` is suitable - * for use where `exp_trait_ref` is required and reports an - * error otherwise. - */ - - match infer::mk_sub_trait_refs(vcx.infcx, - false, - infer::RelateTraitRefs(span), - act_trait_ref.clone(), - exp_trait_ref.clone()) { - Ok(()) => {} // Ok. - Err(ref err) => { - // There is an error, but we need to do some work to make - // the message good. - // Resolve any type vars in the trait refs - let r_act_trait_ref = - vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(&*act_trait_ref); - let r_exp_trait_ref = - vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(&*exp_trait_ref); - // Only print the message if there aren't any previous type errors - // inside the types. - if !ty::trait_ref_contains_error(&r_act_trait_ref) && - !ty::trait_ref_contains_error(&r_exp_trait_ref) - { - let tcx = vcx.tcx(); - span_err!(tcx.sess, span, E0095, "expected {}, found {} ({})", - ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref), - ppaux::trait_ref_to_string(tcx, &r_act_trait_ref), - ty::type_err_to_str(tcx, err)); - } - } - } -} - -// Look up the vtable implementing the trait `trait_ref` at type `t` -fn lookup_vtable(vcx: &VtableContext, - span: Span, - ty: ty::t, - trait_ref: Rc, - is_early: bool) - -> Option -{ - debug!("lookup_vtable(ty={}, trait_ref={})", - ty.repr(vcx.tcx()), - trait_ref.repr(vcx.tcx())); - let _i = indenter(); - - let ty = match fixup_ty(vcx, span, ty, is_early) { - Some(ty) => ty, - None => { - // fixup_ty can only fail if this is early resolution - assert!(is_early); - // The type has unconstrained type variables in it, so we can't - // do early resolution on it. Return some completely bogus vtable - // information: we aren't storing it anyways. - return Some(vtable_error); - } - }; - - if ty::type_is_error(ty) { - return Some(vtable_error); - } - - // If the type is self or a param, we look at the trait/supertrait - // bounds to see if they include the trait we are looking for. - let vtable_opt = match ty::get(ty).sty { - ty::ty_param(ParamTy {space, idx: n, ..}) => { - let env_bounds = &vcx.param_env.bounds; - let type_param_bounds = &env_bounds.get(space, n).trait_bounds; - lookup_vtable_from_bounds(vcx, - span, - type_param_bounds.as_slice(), - param_index { - space: space, - index: n, - }, - trait_ref.clone()) - } - - // Default case just falls through - _ => None - }; - - if vtable_opt.is_some() { return vtable_opt; } - - // If we aren't a self type or param, or it was, but we didn't find it, - // do a search. - search_for_vtable(vcx, span, ty, trait_ref, is_early) -} - -// Given a list of bounds on a type, search those bounds to see if any -// of them are the vtable we are looking for. -fn lookup_vtable_from_bounds(vcx: &VtableContext, - span: Span, - bounds: &[Rc], - param: param_index, - trait_ref: Rc) - -> Option { - let tcx = vcx.tcx(); - - let mut n_bound = 0; - let mut ret = None; - ty::each_bound_trait_and_supertraits(tcx, bounds, |bound_trait_ref| { - debug!("checking bounds trait {}", - bound_trait_ref.repr(vcx.tcx())); - - if bound_trait_ref.def_id == trait_ref.def_id { - relate_trait_refs(vcx, span, bound_trait_ref, trait_ref.clone()); - let vtable = vtable_param(param, n_bound); - debug!("found param vtable: {:?}", - vtable); - ret = Some(vtable); - false - } else { - n_bound += 1; - true - } - }); - ret -} - -fn search_for_unboxed_closure_vtable(vcx: &VtableContext, - span: Span, - ty: ty::t, - trait_ref: Rc) - -> Option { - let tcx = vcx.tcx(); - let closure_def_id = match ty::get(ty).sty { - ty::ty_unboxed_closure(closure_def_id, _) => closure_def_id, - _ => return None, - }; - - let fn_traits = [ - (ty::FnUnboxedClosureKind, tcx.lang_items.fn_trait()), - (ty::FnMutUnboxedClosureKind, tcx.lang_items.fn_mut_trait()), - (ty::FnOnceUnboxedClosureKind, tcx.lang_items.fn_once_trait()), - ]; - for tuple in fn_traits.iter() { - let kind = match tuple { - &(kind, Some(ref fn_trait)) if *fn_trait == trait_ref.def_id => { - kind - } - _ => continue, - }; - - // Check to see whether the argument and return types match. - let unboxed_closures = tcx.unboxed_closures.borrow(); - let closure_type = match unboxed_closures.find(&closure_def_id) { - Some(closure) => { - if closure.kind != kind { - continue - } - closure.closure_type.clone() - } - None => { - // Try the inherited unboxed closure type map. - let unboxed_closures = vcx.unboxed_closures.borrow(); - match unboxed_closures.find(&closure_def_id) { - Some(closure) => { - if closure.kind != kind { - continue - } - closure.closure_type.clone() - } - None => { - tcx.sess.span_bug(span, - "didn't find unboxed closure type \ - in tcx map or inh map") - } - } - } - }; - - // FIXME(pcwalton): This is a bogus thing to do, but - // it'll do for now until we get the new trait-bound - // region skolemization working. - let (_, new_signature) = - regionmanip::replace_late_bound_regions_in_fn_sig( - tcx, - &closure_type.sig, - |br| { - vcx.infcx.next_region_var(infer::LateBoundRegion(span, - br)) - }); - - let arguments_tuple = *new_signature.inputs.get(0); - let corresponding_trait_ref = Rc::new(ty::TraitRef { - def_id: trait_ref.def_id, - substs: subst::Substs::new_trait( - vec![arguments_tuple, new_signature.output], - Vec::new(), - ty) - }); - - relate_trait_refs(vcx, span, corresponding_trait_ref, trait_ref); - return Some(vtable_unboxed_closure(closure_def_id)) - } - - None -} - -fn search_for_vtable(vcx: &VtableContext, - span: Span, - ty: ty::t, - trait_ref: Rc, - is_early: bool) - -> Option { - let tcx = vcx.tcx(); - - // First, check to see whether this is a call to the `call` method of an - // unboxed closure. If so, and the arguments match, we're done. - match search_for_unboxed_closure_vtable(vcx, - span, - ty, - trait_ref.clone()) { - Some(vtable_origin) => return Some(vtable_origin), - None => {} - } - - // Nope. Continue. - - let mut found = Vec::new(); - let mut impls_seen = HashSet::new(); - - // Load the implementations from external metadata if necessary. - ty::populate_implementations_for_trait_if_necessary(tcx, - trait_ref.def_id); - - let impls = match tcx.trait_impls.borrow().find_copy(&trait_ref.def_id) { - Some(impls) => impls, - None => { - return None; - } - }; - // impls is the list of all impls in scope for trait_ref. - for &impl_did in impls.borrow().iter() { - // im is one specific impl of trait_ref. - - // First, ensure we haven't processed this impl yet. - if impls_seen.contains(&impl_did) { - continue; - } - impls_seen.insert(impl_did); - - // ty::impl_traits gives us the trait im implements. - // - // If foo implements a trait t, and if t is the same trait as - // trait_ref, we need to unify it with trait_ref in order to - // get all the ty vars sorted out. - let r = ty::impl_trait_ref(tcx, impl_did); - let of_trait_ref = r.expect("trait_ref missing on trait impl"); - if of_trait_ref.def_id != trait_ref.def_id { continue; } - - // At this point, we know that of_trait_ref is the same trait - // as trait_ref, but possibly applied to different substs. - // - // Next, we check whether the "for" ty in the impl is - // compatible with the type that we're casting to a - // trait. That is, if im is: - // - // impl some_trait for self_ty { ... } - // - // we check whether self_ty is the type of the thing that - // we're trying to cast to some_trait. If not, then we try - // the next impl. - // - // FIXME: document a bit more what this means - let TypeAndSubsts { - substs: substs, - ty: for_ty - } = impl_self_ty(vcx, span, impl_did); - match infer::mk_eqty(vcx.infcx, - false, - infer::RelateSelfType(span), - ty, - for_ty) { - Err(_) => continue, - Ok(()) => () - } - - // Now, in the previous example, for_ty is bound to - // the type self_ty, and substs is bound to [T]. - debug!("The self ty is {} and its substs are {}", - for_ty.repr(tcx), - substs.types.repr(tcx)); - - // Next, we unify trait_ref -- the type that we want to cast - // to -- with of_trait_ref -- the trait that im implements. At - // this point, we require that they be unifiable with each - // other -- that's what relate_trait_refs does. - // - // For example, in the above example, of_trait_ref would be - // some_trait, so we would be unifying trait_ref (for - // some value of U) with some_trait. This would fail if T - // and U weren't compatible. - - let of_trait_ref = of_trait_ref.subst(tcx, &substs); - - debug!("(checking vtable) num 2 relating trait \ - ty {} to of_trait_ref {}", - vcx.infcx.trait_ref_to_string(&*trait_ref), - vcx.infcx.trait_ref_to_string(&*of_trait_ref)); - - relate_trait_refs(vcx, span, of_trait_ref, trait_ref.clone()); - - - // Recall that trait_ref -- the trait type we're casting to -- - // is the trait with id trait_ref.def_id applied to the substs - // trait_ref.substs. - - // 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, - span, - &im_generics.types, - &substs, - is_early); - - // substs might contain type variables, so we call - // fixup_substs to resolve them. - let substs_f = match fixup_substs(vcx, span, - trait_ref.def_id, - substs, - is_early) { - Some(ref substs) => (*substs).clone(), - None => { - assert!(is_early); - // Bail out with a bogus answer - return Some(vtable_error); - } - }; - - debug!("The fixed-up substs are {} - \ - they will be unified with the bounds for \ - the target ty, {}", - substs_f.types.repr(tcx), - trait_ref.repr(tcx)); - - // Next, we unify the fixed-up substitutions for the impl self - // ty with the substitutions from the trait type that we're - // trying to cast to. connect_trait_tps requires these lists - // of types to unify pairwise. - // I am a little confused about this, since it seems to be - // very similar to the relate_trait_refs we already do, - // but problems crop up if it is removed, so... -sully - connect_trait_tps(vcx, span, &substs_f, trait_ref.clone(), impl_did); - - // Finally, we register that we found a matching impl, and - // record the def ID of the impl as well as the resolved list - // of type substitutions for the target trait. - found.push(vtable_static(impl_did, substs_f, subres)); - } - - match found.len() { - 0 => { return None } - 1 => return Some(found.get(0).clone()), - _ => { - if !is_early { - span_err!(vcx.tcx().sess, span, E0096, - "multiple applicable methods in scope"); - } - return Some(found.get(0).clone()); - } - } -} - - -fn fixup_substs(vcx: &VtableContext, - span: Span, - id: ast::DefId, - substs: subst::Substs, - is_early: bool) - -> Option { - let tcx = vcx.tcx(); - // use a dummy type just to package up the substs that need fixing up - let t = ty::mk_trait(tcx, - id, substs, - ty::region_existential_bound(ty::ReStatic)); - fixup_ty(vcx, span, t, is_early).map(|t_f| { - match ty::get(t_f).sty { - ty::ty_trait(ref inner) => inner.substs.clone(), - _ => fail!("t_f should be a trait") - } - }) -} - -fn fixup_ty(vcx: &VtableContext, - span: Span, - ty: ty::t, - is_early: bool) - -> Option { - let tcx = vcx.tcx(); - match resolve_type(vcx.infcx, Some(span), ty, resolve_and_force_all_but_regions) { - Ok(new_type) => Some(new_type), - Err(e) if !is_early => { - tcx.sess.span_err(span, - format!("cannot determine a type for this bounded type \ - parameter: {}", - fixup_err_to_string(e)).as_slice()); - Some(ty::mk_err()) - } - Err(_) => { - None - } - } -} - -fn connect_trait_tps(vcx: &VtableContext, - span: Span, - impl_substs: &subst::Substs, - trait_ref: Rc, - impl_did: ast::DefId) { - let tcx = vcx.tcx(); - - let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) { - Some(t) => t, - None => vcx.tcx().sess.span_bug(span, - "connect_trait_tps invoked on a type impl") - }; - - let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); - relate_trait_refs(vcx, span, impl_trait_ref, trait_ref); -} - -fn insert_vtables(fcx: &FnCtxt, vtable_key: MethodCall, vtables: vtable_res) { - debug!("insert_vtables(vtable_key={}, vtables={})", - vtable_key, vtables.repr(fcx.tcx())); - fcx.inh.vtable_map.borrow_mut().insert(vtable_key, vtables); -} - -pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { - fn mutability_allowed(a_mutbl: ast::Mutability, - b_mutbl: ast::Mutability) -> bool { - a_mutbl == b_mutbl || - (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable) - } - - debug!("vtable: early_resolve_expr() ex with id {:?} (early: {}): {}", - ex.id, is_early, expr_to_string(ex)); - let _indent = indenter(); - - let cx = fcx.ccx; - let check_object_cast = |src_ty: ty::t, target_ty: ty::t| { - debug!("check_object_cast {} to {}", - fcx.infcx().ty_to_string(src_ty), - fcx.infcx().ty_to_string(target_ty)); - // Check that a cast is of correct types. - match (&ty::get(target_ty).sty, &ty::get(src_ty).sty) { - (&ty::ty_rptr(_, ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt)) - | (&ty::ty_ptr(ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt)) - if !mutability_allowed(mt.mutbl, mutbl) => { - match ty::get(ty).sty { - ty::ty_trait(..) => { - span_err!(fcx.tcx().sess, ex.span, E0097, "types differ in mutability"); - } - _ => {} - } - } - (&ty::ty_uniq(..), &ty::ty_uniq(..) ) - | (&ty::ty_ptr(..), &ty::ty_ptr(..) ) - | (&ty::ty_ptr(..), &ty::ty_rptr(..)) => {} - (&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => { - infer::mk_subr(fcx.infcx(), - infer::RelateObjectBound(ex.span), - r_t, - r_s); - } - (&ty::ty_uniq(ty), _) => { - match ty::get(ty).sty { - ty::ty_trait(..) => { - span_err!(fcx.ccx.tcx.sess, ex.span, E0098, - "can only cast an boxed pointer to a boxed object, not a {}", - ty::ty_sort_string(fcx.tcx(), src_ty)); - } - _ => {} - } - - } - (&ty::ty_rptr(_, ty::mt{ty, ..}), _) => { - match ty::get(ty).sty { - ty::ty_trait(..) => { - span_err!(fcx.ccx.tcx.sess, ex.span, E0099, - "can only cast an &-pointer to an &-object, not a {}", - ty::ty_sort_string(fcx.tcx(), src_ty)); - } - _ => {} - } - } - (&ty::ty_ptr(ty::mt{ty, ..}), _) => { - match ty::get(ty).sty { - ty::ty_trait(..) => { - span_err!(fcx.ccx.tcx.sess, ex.span, E0160, - "can only cast an *-pointer or &-pointer to an *-object, not a {}", - ty::ty_sort_string(fcx.tcx(), src_ty)); - } - _ => {} - } - } - _ => {} - } - }; - let resolve_object_cast = |src_ty: ty::t, target_ty: ty::t, key: MethodCall| { - // Look up vtables for the type we're casting to, - // passing in the source and target type. The source - // must be a pointer type suitable to the object sigil, - // e.g.: `&x as &Trait` or `box x as Box` - // Bounds of type's contents are not checked here, but in kind.rs. - match ty::get(target_ty).sty { - ty::ty_trait(box ty::TyTrait { - def_id: target_def_id, substs: ref target_substs, .. - }) => { - let vcx = fcx.vtable_context(); - - // Take the type parameters from the object - // type, but set the Self type (which is - // unknown, for the object type) to be the type - // we are casting from. - let mut target_types = target_substs.types.clone(); - assert!(target_types.get_self().is_none()); - target_types.push(subst::SelfSpace, src_ty); - - let target_trait_ref = Rc::new(ty::TraitRef { - def_id: target_def_id, - substs: subst::Substs { - regions: target_substs.regions.clone(), - types: target_types - } - }); - - let param_bounds = ty::ParamBounds { - opt_region_bound: None, - builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: vec!(target_trait_ref) - }; - - let vtables = - lookup_vtables_for_param(&vcx, - ex.span, - None, - ¶m_bounds, - src_ty, - is_early); - - if !is_early { - let mut r = VecPerParamSpace::empty(); - r.push(subst::SelfSpace, vtables); - insert_vtables(fcx, key, r); - } - } - _ => {} - } - }; - match ex.node { - ast::ExprPath(..) => { - fcx.opt_node_ty_substs(ex.id, |item_substs| { - debug!("vtable resolution on parameter bounds for expr {}", - ex.repr(fcx.tcx())); - let def = cx.tcx.def_map.borrow().get_copy(&ex.id); - let did = def.def_id(); - let item_ty = ty::lookup_item_type(cx.tcx, did); - debug!("early resolve expr: def {:?} {:?}, {:?}, {}", ex.id, did, def, - fcx.infcx().ty_to_string(item_ty.ty)); - debug!("early_resolve_expr: looking up vtables for type params {}", - item_ty.generics.types.repr(fcx.tcx())); - let vcx = fcx.vtable_context(); - let vtbls = lookup_vtables(&vcx, ex.span, - &item_ty.generics.types, - &item_substs.substs, is_early); - if !is_early { - insert_vtables(fcx, MethodCall::expr(ex.id), vtbls); - } - }); - } - - // Must resolve bounds on methods with bounded params - ast::ExprBinary(_, _, _) | - ast::ExprUnary(_, _) | - ast::ExprAssignOp(_, _, _) | - ast::ExprIndex(_, _) | - ast::ExprMethodCall(_, _, _) | - ast::ExprForLoop(..) | - ast::ExprCall(..) => { - match fcx.inh.method_map.borrow().find(&MethodCall::expr(ex.id)) { - Some(method) => { - debug!("vtable resolution on parameter bounds for method call {}", - ex.repr(fcx.tcx())); - let type_param_defs = - ty::method_call_type_param_defs(fcx, method.origin); - let substs = fcx.method_ty_substs(ex.id); - let vcx = fcx.vtable_context(); - let vtbls = lookup_vtables(&vcx, ex.span, - &type_param_defs, - &substs, is_early); - if !is_early { - insert_vtables(fcx, MethodCall::expr(ex.id), vtbls); - } - } - None => {} - } - } - ast::ExprCast(ref src, _) => { - debug!("vtable resolution on expr {}", ex.repr(fcx.tcx())); - let target_ty = fcx.expr_ty(ex); - let src_ty = structurally_resolved_type(fcx, ex.span, - fcx.expr_ty(&**src)); - check_object_cast(src_ty, target_ty); - match (ty::deref(src_ty, false), ty::deref(target_ty, false)) { - (Some(s), Some(t)) => { - let key = MethodCall::expr(ex.id); - resolve_object_cast(s.ty, t.ty, key) - } - _ => {} - } - } - _ => () - } - - // Search for auto-adjustments to find trait coercions - match fcx.inh.adjustments.borrow().find(&ex.id) { - Some(adjustment) => { - match *adjustment { - _ if ty::adjust_is_object(adjustment) => { - let src_ty = structurally_resolved_type(fcx, ex.span, - fcx.expr_ty(ex)); - match ty::type_of_adjust(fcx.tcx(), adjustment) { - Some(target_ty) => { - check_object_cast(src_ty, target_ty) - } - None => {} - } - - match trait_cast_types(fcx, adjustment, src_ty, ex.span) { - Some((s, t)) => { - let key = MethodCall::autoobject(ex.id); - resolve_object_cast(s, t, key) - } - None => fail!("Couldn't extract types from adjustment") - } - } - AutoDerefRef(ref adj) => { - for autoderef in range(0, adj.autoderefs) { - let method_call = MethodCall::autoderef(ex.id, autoderef); - match fcx.inh.method_map.borrow().find(&method_call) { - Some(method) => { - debug!("vtable resolution on parameter bounds for autoderef {}", - ex.repr(fcx.tcx())); - let type_param_defs = - ty::method_call_type_param_defs(cx.tcx, method.origin); - let vcx = fcx.vtable_context(); - let vtbls = lookup_vtables(&vcx, ex.span, - &type_param_defs, - &method.substs, is_early); - if !is_early { - insert_vtables(fcx, method_call, vtbls); - } - } - None => {} - } - } - } - _ => {} - } - } - None => {} - } -} - -// When we coerce (possibly implicitly) from a concrete type to a trait type, this -// function returns the concrete type and trait. This might happen arbitrarily -// deep in the adjustment. This function will fail if the adjustment does not -// match the source type. -// This function will always return types if ty::adjust_is_object is true for the -// adjustment -fn trait_cast_types(fcx: &FnCtxt, - adj: &ty::AutoAdjustment, - src_ty: ty::t, - sp: Span) - -> Option<(ty::t, ty::t)> { - fn trait_cast_types_autoref(fcx: &FnCtxt, - autoref: &ty::AutoRef, - src_ty: ty::t, - sp: Span) - -> Option<(ty::t, ty::t)> { - fn trait_cast_types_unsize(fcx: &FnCtxt, - k: &ty::UnsizeKind, - src_ty: ty::t, - sp: Span) - -> Option<(ty::t, ty::t)> { - match k { - &ty::UnsizeVtable(bounds, def_id, ref substs) => { - Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds))) - } - &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(src_ty).sty { - ty::ty_struct(_, ref substs) => { - let ty_substs = substs.types.get_slice(subst::TypeSpace); - let field_ty = structurally_resolved_type(fcx, sp, ty_substs[tp_index]); - trait_cast_types_unsize(fcx, k, field_ty, sp) - } - _ => fail!("Failed to find a ty_struct to correspond with \ - UnsizeStruct whilst walking adjustment. Found {}", - ppaux::ty_to_string(fcx.tcx(), src_ty)) - }, - _ => None - } - } - - match autoref { - &ty::AutoUnsize(ref k) | - &ty::AutoUnsizeUniq(ref k) => trait_cast_types_unsize(fcx, k, src_ty, sp), - &ty::AutoPtr(_, _, Some(box ref autoref)) | - &ty::AutoUnsafe(_, Some(box ref autoref)) => { - trait_cast_types_autoref(fcx, autoref, src_ty, sp) - } - _ => None - } - } - - match adj { - &ty::AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), autoderefs}) => { - let mut derefed_type = src_ty; - for _ in range(0, autoderefs) { - derefed_type = ty::deref(derefed_type, true).unwrap().ty; - derefed_type = structurally_resolved_type(fcx, sp, derefed_type) - } - trait_cast_types_autoref(fcx, autoref, derefed_type, sp) - } - _ => None - } -} - -pub fn resolve_impl(tcx: &ty::ctxt, - impl_item: &ast::Item, - impl_generics: &ty::Generics, - impl_trait_ref: &ty::TraitRef) { - /*! - * The situation is as follows. We have some trait like: - * - * trait Foo : Bar { - * fn method() { ... } - * } - * - * and an impl like: - * - * impl Foo for int { ... } - * - * We want to validate that the various requirements of the trait - * are met: - * - * A:Clone, Self:Bar - * - * But of course after substituting the types from the impl: - * - * B:Clone, int:Bar - * - * We store these results away as the "impl_res" for use by the - * default methods. - */ - - debug!("resolve_impl(impl_item.id={})", - impl_item.id); - - let param_env = ty::construct_parameter_environment(tcx, - impl_generics, - impl_item.id); - - // The impl_trait_ref in our example above would be - // `Foo for int` - let impl_trait_ref = impl_trait_ref.subst(tcx, ¶m_env.free_substs); - debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx)); - - let infcx = &infer::new_infer_ctxt(tcx); - let unboxed_closures = RefCell::new(DefIdMap::new()); - let vcx = VtableContext { - infcx: infcx, - param_env: ¶m_env, - unboxed_closures: &unboxed_closures, - }; - - // Resolve the vtables for the trait reference on the impl. This - // serves many purposes, best explained by example. Imagine we have: - // - // trait A : C { fn x(&self) { ... } } - // - // and - // - // impl A for uint { ... } - // - // In that case, the trait ref will be `A for uint`. Resolving - // this will first check that the various types meet their requirements: - // - // 1. Because of T:B, int must implement the trait B - // 2. Because of the supertrait C, uint must implement the trait C. - // - // Simultaneously, the result of this resolution (`vtbls`), is precisely - // the set of vtable information needed to compile the default method - // `x()` adapted to the impl. (After all, a default method is basically - // the same as: - // - // fn default_x(...) { .. .}) - - let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id); - let vtbls = lookup_vtables(&vcx, - impl_item.span, - &trait_def.generics.types, - &impl_trait_ref.substs, - false); - - infcx.resolve_regions_and_report_errors(); - - let vtbls = writeback::resolve_impl_res(infcx, impl_item.span, &vtbls); - let impl_def_id = ast_util::local_def(impl_item.id); - - debug!("impl_vtables for {} are {}", - impl_def_id.repr(tcx), - vtbls.repr(tcx)); - - tcx.impl_vtables.borrow_mut().insert(impl_def_id, vtbls); -} - -/// Resolve vtables for a method call after typeck has finished. -/// Used by trans to monomorphize artificial method callees (e.g. drop). -pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId, - substs: &subst::Substs) -> vtable_res { - let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics; - let unboxed_closures = RefCell::new(DefIdMap::new()); - let vcx = VtableContext { - infcx: &infer::new_infer_ctxt(tcx), - param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id), - unboxed_closures: &unboxed_closures, - }; - - lookup_vtables(&vcx, - tcx.map.span(id), - &generics.types, - substs, - false) -} - -impl<'a, 'b, 'tcx, 'v> Visitor<'v> for &'a FnCtxt<'b, 'tcx> { - fn visit_expr(&mut self, ex: &ast::Expr) { - early_resolve_expr(ex, *self, false); - visit::walk_expr(self, ex); - } - fn visit_item(&mut self, _: &ast::Item) { - // no-op - } -} - -// Detect points where a trait-bounded type parameter is -// instantiated, resolve the impls for the parameters. -pub fn resolve_in_block(mut fcx: &FnCtxt, bl: &ast::Block) { - visit::walk_block(&mut fcx, bl); -} - -/// Used in the kind checker after typechecking has finished. Calls -/// `any_missing` if any bounds were missing. -pub fn check_param_bounds(tcx: &ty::ctxt, - span: Span, - parameter_environment: &ty::ParameterEnvironment, - type_param_defs: - &VecPerParamSpace, - substs: &subst::Substs, - any_missing: |&ty::TraitRef|) { - let unboxed_closures = RefCell::new(DefIdMap::new()); - let vcx = VtableContext { - infcx: &infer::new_infer_ctxt(tcx), - param_env: parameter_environment, - unboxed_closures: &unboxed_closures, - }; - let vtable_param_results = - lookup_vtables(&vcx, span, type_param_defs, substs, false); - for (vtable_param_result, type_param_def) in - vtable_param_results.iter().zip(type_param_defs.iter()) { - for (vtable_result, trait_ref) in - vtable_param_result.iter() - .zip(type_param_def.bounds - .trait_bounds - .iter()) { - match *vtable_result { - vtable_error => any_missing(&**trait_ref), - vtable_static(..) | - vtable_param(..) | - vtable_unboxed_closure(..) => {} - } - } - } -} - diff --git a/src/librustc/middle/typeck/check/vtable2.rs b/src/librustc/middle/typeck/check/vtable2.rs new file mode 100644 index 0000000000000..f75d2622fdb89 --- /dev/null +++ b/src/librustc/middle/typeck/check/vtable2.rs @@ -0,0 +1,407 @@ +// Copyright 2014 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. + +use middle::subst::{SelfSpace}; +use middle::traits; +use middle::traits::{SelectionError, Overflow, + OutputTypeParameterMismatch, Unimplemented}; +use middle::traits::{Obligation, obligation_for_builtin_bound}; +use middle::traits::{FulfillmentError, Ambiguity}; +use middle::traits::{ObligationCause}; +use middle::ty; +use middle::typeck::check::{FnCtxt, + structurally_resolved_type}; +use middle::typeck::infer; +use std::rc::Rc; +use syntax::ast; +use syntax::codemap::Span; +use util::ppaux::UserString; +use util::ppaux::Repr; + +/// When reporting an error about a failed trait obligation, it's nice +/// to include some context indicating why we were checking that +/// obligation in the first place. The span is often enough but +/// sometimes it's not. Currently this enum is a bit of a hack and I +/// suspect it should be carried in the obligation or more deeply +/// integrated somehow. +pub enum ErrorReportingContext { + GenericContext, + ImplSupertraitCheck, +} + +pub fn check_object_cast(fcx: &FnCtxt, + cast_expr: &ast::Expr, + source_expr: &ast::Expr, + target_object_ty: ty::t) +{ + debug!("check_object_cast(cast_expr={}, target_object_ty={})", + cast_expr.repr(fcx.tcx()), + target_object_ty.repr(fcx.tcx())); + + // Look up vtables for the type we're casting to, + // passing in the source and target type. The source + // must be a pointer type suitable to the object sigil, + // e.g.: `&x as &Trait` or `box x as Box` + let source_ty = fcx.expr_ty(source_expr); + let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty); + debug!("source_ty={}", source_ty.repr(fcx.tcx())); + match (&ty::get(source_ty).sty, &ty::get(target_object_ty).sty) { + (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => { + let object_trait = object_trait(&object_trait_ty); + + // Ensure that if ~T is cast to ~Trait, then T : Trait + push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); + } + + (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, + mutbl: referent_mutbl }), + &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty, + mutbl: target_mutbl })) => + { + let object_trait = object_trait(&object_trait_ty); + if !mutability_allowed(referent_mutbl, target_mutbl) { + fcx.tcx().sess.span_err(source_expr.span, + "types differ in mutability"); + } else { + // Ensure that if &'a T is cast to &'b Trait, then T : Trait + push_cast_obligation(fcx, cast_expr, + object_trait, + referent_ty); + + // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a + infer::mk_subr(fcx.infcx(), + infer::RelateObjectBound(source_expr.span), + target_region, + referent_region); + } + } + + (_, &ty::ty_uniq(..)) => { + fcx.ccx.tcx.sess.span_err( + source_expr.span, + format!("can only cast an boxed pointer \ + to a boxed object, not a {}", + ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice()); + } + + (_, &ty::ty_rptr(..)) => { + fcx.ccx.tcx.sess.span_err( + source_expr.span, + format!("can only cast a &-pointer \ + to an &-object, not a {}", + ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice()); + } + + _ => { + fcx.tcx().sess.span_bug( + source_expr.span, + "expected object type"); + } + } + + // Because we currently give unsound lifetimes to the "ty_box", I + // could have written &'static ty::TyTrait here, but it seems + // gratuitously unsafe. + fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait { + match ty::get(*t).sty { + ty::ty_trait(ref ty_trait) => &**ty_trait, + _ => fail!("expected ty_trait") + } + } + + fn mutability_allowed(a_mutbl: ast::Mutability, + b_mutbl: ast::Mutability) + -> bool { + a_mutbl == b_mutbl || + (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable) + } + + fn push_cast_obligation(fcx: &FnCtxt, + cast_expr: &ast::Expr, + object_trait: &ty::TyTrait, + referent_ty: ty::t) { + let object_trait_ref = + register_object_cast_obligations(fcx, + cast_expr.span, + object_trait, + referent_ty); + + // Finally record the object_trait_ref for use during trans + // (it would prob be better not to do this, but it's just kind + // of a pain to have to reconstruct it). + fcx.write_object_cast(cast_expr.id, object_trait_ref); + } +} + +pub fn register_object_cast_obligations(fcx: &FnCtxt, + span: Span, + object_trait: &ty::TyTrait, + referent_ty: ty::t) + -> Rc +{ + // This is just for better error reporting. Kinda goofy. The object type stuff + // needs some refactoring so there is a more convenient type to pass around. + let object_trait_ty = + ty::mk_trait(fcx.tcx(), + object_trait.def_id, + object_trait.substs.clone(), + object_trait.bounds); + + debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}", + referent_ty.repr(fcx.tcx()), + object_trait_ty.repr(fcx.tcx())); + + // Take the type parameters from the object type, but set + // the Self type (which is unknown, for the object type) + // to be the type we are casting from. + let mut object_substs = object_trait.substs.clone(); + assert!(object_substs.self_ty().is_none()); + object_substs.types.push(SelfSpace, referent_ty); + + // Create the obligation for casting from T to Trait. + let object_trait_ref = + Rc::new(ty::TraitRef { def_id: object_trait.def_id, + substs: object_substs }); + let object_obligation = + Obligation::new( + ObligationCause::new(span, + traits::ObjectCastObligation(object_trait_ty)), + object_trait_ref.clone()); + fcx.register_obligation(object_obligation); + + // Create additional obligations for all the various builtin + // bounds attached to the object cast. (In other words, if the + // object type is Foo+Send, this would create an obligation + // for the Send check.) + for builtin_bound in object_trait.bounds.builtin_bounds.iter() { + fcx.register_obligation( + obligation_for_builtin_bound( + fcx.tcx(), + ObligationCause::new(span, + traits::ObjectCastObligation(object_trait_ty)), + referent_ty, + builtin_bound)); + } + + object_trait_ref +} + +pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) { + debug!("select_all_fcx_obligations_or_error"); + + let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut(); + let r = + fulfillment_cx.select_all_or_error( + fcx.infcx(), + &fcx.inh.param_env, + &*fcx.inh.unboxed_closures.borrow()); + match r { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(fcx, &errors); } + } +} + +pub fn check_builtin_bound_obligations(fcx: &FnCtxt) { + /*! + * Hacky second pass to check builtin-bounds obligations *after* + * writeback occurs. + */ + + match + fcx.inh.fulfillment_cx.borrow() + .check_builtin_bound_obligations(fcx.infcx()) + { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(fcx, &errors); } + } +} + +fn resolve_trait_ref(fcx: &FnCtxt, obligation: &Obligation) + -> (ty::TraitRef, ty::t) +{ + let trait_ref = + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + &*obligation.trait_ref); + let self_ty = + trait_ref.substs.self_ty().unwrap(); + (trait_ref, self_ty) +} + +pub fn report_fulfillment_errors(fcx: &FnCtxt, + errors: &Vec) { + for error in errors.iter() { + report_fulfillment_error(fcx, error); + } +} + +pub fn report_fulfillment_error(fcx: &FnCtxt, + error: &FulfillmentError) { + match error.code { + SelectionError(ref e) => { + report_selection_error(fcx, &error.obligation, e); + } + Ambiguity => { + maybe_report_ambiguity(fcx, &error.obligation); + } + } +} + +pub fn report_selection_error(fcx: &FnCtxt, + obligation: &Obligation, + error: &SelectionError) { + match *error { + Unimplemented => { + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + if !ty::type_is_error(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "the trait `{}` is not implemented for the type `{}`", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } + } + Overflow => { + report_overflow(fcx, obligation); + } + OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => { + let expected_trait_ref = + fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + &**expected_trait_ref); + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + if !ty::type_is_error(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "type mismatch: the type `{}` implements the trait `{}`, \ + but the trait `{}` is required ({})", + self_ty.user_string(fcx.tcx()), + expected_trait_ref.user_string(fcx.tcx()), + trait_ref.user_string(fcx.tcx()), + ty::type_err_to_str(fcx.tcx(), e)).as_slice()); + note_obligation_cause(fcx, obligation); + } + } + } +} + +pub fn report_overflow(fcx: &FnCtxt, obligation: &Obligation) { + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + if ty::type_is_error(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "could not locate an impl of the trait `{}` for \ + the type `{}` due to overflow; possible cyclic \ + dependency between impls", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } +} + +pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) { + // Unable to successfully determine, probably means + // insufficient type information, but could mean + // ambiguous impls. The latter *ought* to be a + // coherence violation, so we don't report it here. + let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation); + debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})", + trait_ref.repr(fcx.tcx()), + self_ty.repr(fcx.tcx()), + obligation.repr(fcx.tcx())); + if ty::type_is_error(self_ty) { + } else if ty::type_needs_infer(self_ty) { + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "unable to infer enough type information to \ + locate the impl of the trait `{}` for \ + the type `{}`; type annotations required", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + note_obligation_cause(fcx, obligation); + } else if fcx.tcx().sess.err_count() == 0 { + // Ambiguity. Coherence should have reported an error. + fcx.tcx().sess.span_bug( + obligation.cause.span, + format!( + "coherence failed to report ambiguity: \ + cannot locate the impl of the trait `{}` for \ + the type `{}`", + trait_ref.user_string(fcx.tcx()), + self_ty.user_string(fcx.tcx())).as_slice()); + } +} + +pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) { + /*! Select as many obligations as we can at present. */ + + match + fcx.inh.fulfillment_cx + .borrow_mut() + .select_where_possible(fcx.infcx(), + &fcx.inh.param_env, + &*fcx.inh.unboxed_closures.borrow()) + { + Ok(()) => { } + Err(errors) => { report_fulfillment_errors(fcx, &errors); } + } +} + +fn note_obligation_cause(fcx: &FnCtxt, + obligation: &Obligation) { + let tcx = fcx.tcx(); + let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id); + match obligation.cause.code { + traits::MiscObligation => { } + traits::ItemObligation(item_def_id) => { + let item_name = ty::item_path_str(tcx, item_def_id); + tcx.sess.span_note( + obligation.cause.span, + format!( + "the trait `{}` must be implemented because it is required by `{}`", + trait_name, + item_name).as_slice()); + } + traits::ObjectCastObligation(object_ty) => { + tcx.sess.span_note( + obligation.cause.span, + format!( + "the trait `{}` must be implemented for the cast \ + to the object type `{}`", + trait_name, + fcx.infcx().ty_to_string(object_ty)).as_slice()); + } + traits::RepeatVec => { + tcx.sess.span_note( + obligation.cause.span, + format!( + "the `Copy` trait is required because the \ + repeated element will be copied").as_slice()); + } + traits::VariableType(_) => { + tcx.sess.span_note( + obligation.cause.span, + "all local variables must have a statically known size"); + } + traits::AssignmentLhsSized => { + tcx.sess.span_note( + obligation.cause.span, + "the left-hand-side of an assignment must have a statically known size"); + } + traits::StructInitializerSized => { + tcx.sess.span_note( + obligation.cause.span, + "structs must have a statically known size to be initialized"); + } + } +} diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs new file mode 100644 index 0000000000000..73c0a4e10fc2a --- /dev/null +++ b/src/librustc/middle/typeck/check/wf.rs @@ -0,0 +1,365 @@ +// Copyright 2014 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. + +use middle::subst::{Subst}; +use middle::traits; +use middle::ty; +use middle::ty_fold::{TypeFolder, TypeFoldable}; +use middle::typeck::astconv::AstConv; +use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable2, regionck}; +use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; +use middle::typeck::CrateCtxt; +use util::ppaux::Repr; + +use std::collections::HashSet; +use syntax::ast; +use syntax::ast_util::{local_def}; +use syntax::codemap::Span; +use syntax::visit; +use syntax::visit::Visitor; + +pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> { + ccx: &'ccx CrateCtxt<'ccx, 'tcx>, + cache: HashSet +} + +impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { + pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>) -> CheckTypeWellFormedVisitor<'ccx, 'tcx> { + CheckTypeWellFormedVisitor { ccx: ccx, cache: HashSet::new() } + } + + fn check_item_well_formed(&mut self, ccx: &CrateCtxt, item: &ast::Item) { + /*! + * Checks that the field types (in a struct def'n) or + * argument types (in an enum def'n) are well-formed, + * meaning that they do not require any constraints not + * declared in the struct definition itself. + * For example, this definition would be illegal: + * + * struct Ref<'a, T> { x: &'a T } + * + * because the type did not declare that `T:'a`. + * + * We do this check as a pre-pass before checking fn bodies + * because if these constraints are not included it frequently + * leads to confusing errors in fn bodies. So it's better to check + * the types first. + */ + + debug!("check_item_well_formed(it.id={}, it.ident={})", + item.id, + ty::item_path_str(ccx.tcx, local_def(item.id))); + + let ccx = self.ccx; + match item.node { + ast::ItemImpl(..) => { + self.check_impl(item); + } + ast::ItemFn(..) => { + self.check_item_type(item); + } + ast::ItemStatic(..) => { + self.check_item_type(item); + } + ast::ItemStruct(..) => { + self.check_type_defn(item, |fcx| { + ty::struct_fields(ccx.tcx, local_def(item.id), + &fcx.inh.param_env.free_substs) + .iter() + .map(|f| f.mt.ty) + .collect() + }); + } + ast::ItemEnum(..) => { + self.check_type_defn(item, |fcx| { + ty::substd_enum_variants(ccx.tcx, local_def(item.id), + &fcx.inh.param_env.free_substs) + .iter() + .flat_map(|variant| { + variant.args + .iter() + .map(|&arg_ty| arg_ty) + }) + .collect() + }); + } + _ => {} + } + } + + fn with_fcx(&mut self, + ccx: &CrateCtxt, + item: &ast::Item, + f: |&mut CheckTypeWellFormedVisitor, &FnCtxt|) { + let item_def_id = local_def(item.id); + let polytype = ty::lookup_item_type(ccx.tcx, item_def_id); + let param_env = + ty::construct_parameter_environment(ccx.tcx, + item.span, + &polytype.generics, + item.id); + let inh = Inherited::new(ccx.tcx, param_env); + let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id); + f(self, &fcx); + vtable2::select_all_fcx_obligations_or_error(&fcx); + regionck::regionck_item(&fcx, item); + vtable2::check_builtin_bound_obligations(&fcx); + } + + fn check_type_defn(&mut self, + item: &ast::Item, + lookup_fields: |&FnCtxt| -> Vec) + { + /*! + * In a type definition, we check that to ensure that the types of the fields are + * well-formed. + */ + + self.with_fcx(self.ccx, item, |this, fcx| { + let field_tys = lookup_fields(fcx); + let mut bounds_checker = BoundsChecker::new(fcx, item.span, + item.id, Some(&mut this.cache)); + for &ty in field_tys.iter() { + // Regions are checked below. + bounds_checker.check_traits_in_ty(ty); + } + + regionck::regionck_ensure_component_tys_wf( + fcx, item.span, field_tys.as_slice()); + }); + } + + fn check_item_type(&mut self, + item: &ast::Item) + { + self.with_fcx(self.ccx, item, |this, fcx| { + let mut bounds_checker = BoundsChecker::new(fcx, item.span, + item.id, Some(&mut this.cache)); + let polytype = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); + let item_ty = polytype.ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + bounds_checker.check_traits_in_ty(item_ty); + }); + } + + fn check_impl(&mut self, + item: &ast::Item) + { + self.with_fcx(self.ccx, item, |this, fcx| { + let mut bounds_checker = BoundsChecker::new(fcx, item.span, + item.id, Some(&mut this.cache)); + + let self_ty = ty::node_id_to_type(fcx.tcx(), item.id); + let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + + bounds_checker.check_traits_in_ty(self_ty); + + let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) { + None => { return; } + Some(t) => { t } + }; + let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + + // We are stricter on the trait-ref in an impl than the + // self-type. In particular, we enforce region + // relationships. The reason for this is that (at least + // presently) "appyling" an impl does not require that the + // application site check the well-formedness constraints on the + // trait reference. Instead, this is done at the impl site. + // Arguably this is wrong and we should treat the trait-reference + // the same way as we treat the self-type. + bounds_checker.check_trait_ref(&trait_ref); + + let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_ref.def_id); + + let cause = + traits::ObligationCause::new( + item.span, + traits::ItemObligation(trait_ref.def_id)); + + // Find the supertrait bounds. This will add `int:Bar`. + // + // FIXME -- This is a bit ill-factored. There is very similar + // code in traits::util::obligations_for_generics. + fcx.add_region_obligations_for_type_parameter(item.span, + ty::ParamTy::for_self(trait_ref.def_id), + &trait_def.bounds, + trait_ref.self_ty()); + for builtin_bound in trait_def.bounds.builtin_bounds.iter() { + fcx.register_obligation( + traits::obligation_for_builtin_bound(fcx.tcx(), + cause, + trait_ref.self_ty(), + builtin_bound)); + } + for trait_bound in trait_def.bounds.trait_bounds.iter() { + let trait_bound = trait_bound.subst(fcx.tcx(), &trait_ref.substs); + fcx.register_obligation( + traits::Obligation::new(cause, trait_bound)); + } + }); + } +} + +impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { + fn visit_item(&mut self, i: &'v ast::Item) { + self.check_item_well_formed(self.ccx, i); + visit::walk_item(self, i); + } +} + +pub struct BoundsChecker<'cx,'tcx:'cx> { + fcx: &'cx FnCtxt<'cx,'tcx>, + span: Span, + scope_id: ast::NodeId, + binding_count: uint, + cache: Option<&'cx mut HashSet>, +} + +impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { + pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>, + span: Span, + scope_id: ast::NodeId, + cache: Option<&'cx mut HashSet>) + -> BoundsChecker<'cx,'tcx> { + BoundsChecker { fcx: fcx, span: span, scope_id: scope_id, + cache: cache, binding_count: 0 } + } + + pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef) { + /*! + * Given a trait ref like `A : Trait`, where `Trait` is + * defined as (say): + * + * trait Trait : Copy { ... } + * + * This routine will check that `B : OtherTrait` and `A : + * Trait`. It will also recursively check that the types + * `A` and `B` are well-formed. + * + * Note that it does not (currently, at least) + * check that `A : Copy` (that check is delegated to the point + * where impl `A : Trait` is implemented). + */ + + let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id); + + self.fcx.add_obligations_for_parameters( + traits::ObligationCause::new( + self.span, + traits::ItemObligation(trait_ref.def_id)), + &trait_ref.substs, + &trait_def.generics); + + for &ty in trait_ref.substs.types.iter() { + self.check_traits_in_ty(ty); + } + } + + pub fn check_ty(&mut self, ty: ty::t) { + ty.fold_with(self); + } + + fn check_traits_in_ty(&mut self, ty: ty::t) { + // When checking types outside of a type def'n, we ignore + // region obligations. See discussion below in fold_ty(). + self.binding_count += 1; + ty.fold_with(self); + self.binding_count -= 1; + } +} + +impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.fcx.tcx() + } + + fn fold_ty(&mut self, t: ty::t) -> ty::t { + debug!("BoundsChecker t={}", + t.repr(self.tcx())); + + match self.cache { + Some(ref mut cache) => { + if !cache.insert(t) { + // Already checked this type! Don't check again. + debug!("cached"); + return t; + } + } + None => { } + } + + match ty::get(t).sty{ + ty::ty_struct(type_id, ref substs) | + ty::ty_enum(type_id, ref substs) => { + let polytype = ty::lookup_item_type(self.fcx.tcx(), type_id); + + if self.binding_count == 0 { + self.fcx.add_obligations_for_parameters( + traits::ObligationCause::new(self.span, + traits::ItemObligation(type_id)), + substs, + &polytype.generics); + } else { + // There are two circumstances in which we ignore + // region obligations. + // + // The first is when we are inside of a closure + // type. This is because in that case the region + // obligations for the parameter types are things + // that the closure body gets to assume and the + // caller must prove at the time of call. In other + // words, if there is a type like `<'a, 'b> | &'a + // &'b int |`, it is well-formed, and caller will + // have to show that `'b : 'a` at the time of + // call. + // + // The second is when we are checking for + // well-formedness outside of a type def'n or fn + // body. This is for a similar reason: in general, + // we only do WF checking for regions in the + // result of expressions and type definitions, so + // to as allow for implicit where clauses. + // + // (I believe we should do the same for traits, but + // that will require an RFC. -nmatsakis) + self.fcx.add_trait_obligations_for_generics( + traits::ObligationCause::new(self.span, + traits::ItemObligation(type_id)), + substs, + &polytype.generics); + } + + self.fold_substs(substs); + } + ty::ty_bare_fn(ty::BareFnTy{sig: ref fn_sig, ..}) | + ty::ty_closure(box ty::ClosureTy{sig: ref fn_sig, ..}) => { + self.binding_count += 1; + + let (_, fn_sig) = + replace_late_bound_regions_in_fn_sig( + self.fcx.tcx(), fn_sig, + |br| ty::ReFree(ty::FreeRegion{scope_id: self.scope_id, + bound_region: br})); + + debug!("late-bound regions replaced: {}", + fn_sig.repr(self.tcx())); + + self.fold_sig(&fn_sig); + + self.binding_count -= 1; + } + ref sty => { + self.fold_sty(sty); + } + } + + t // we're not folding to produce a new type, so just return `t` here + } +} diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 4716ffe700b50..ffe019b314a87 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -44,6 +44,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) { wbcx.visit_expr(e); wbcx.visit_upvar_borrow_map(); wbcx.visit_unboxed_closures(); + wbcx.visit_object_cast_map(); } pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, @@ -63,6 +64,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, } wbcx.visit_upvar_borrow_map(); wbcx.visit_unboxed_closures(); + wbcx.visit_object_cast_map(); } pub fn resolve_impl_res(infcx: &infer::InferCtxt, @@ -128,8 +130,6 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> { self.visit_node_id(ResolvingExpr(e.span), e.id); self.visit_method_map_entry(ResolvingExpr(e.span), MethodCall::expr(e.id)); - self.visit_vtable_map_entry(ResolvingExpr(e.span), - MethodCall::expr(e.id)); match e.node { ast::ExprFnBlock(_, ref decl, _) | @@ -235,6 +235,27 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_object_cast_map(&self) { + if self.fcx.writeback_errors.get() { + return + } + + for (&node_id, trait_ref) in self.fcx + .inh + .object_cast_map + .borrow() + .iter() + { + let span = ty::expr_span(self.tcx(), node_id); + let reason = ResolvingExpr(span); + let closure_ty = self.resolve(trait_ref, reason); + self.tcx() + .object_cast_map + .borrow_mut() + .insert(node_id, closure_ty); + } + } + fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) { // Resolve any borrowings for the node with id `id` self.visit_adjustments(reason, id); @@ -284,13 +305,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { for autoderef in range(0, adj.autoderefs) { let method_call = MethodCall::autoderef(id, autoderef); self.visit_method_map_entry(reason, method_call); - self.visit_vtable_map_entry(reason, method_call); } if adj_object { let method_call = MethodCall::autoobject(id); self.visit_method_map_entry(reason, method_call); - self.visit_vtable_map_entry(reason, method_call); } ty::AutoDerefRef(ty::AutoDerefRef { @@ -329,22 +348,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn visit_vtable_map_entry(&self, - reason: ResolveReason, - vtable_key: MethodCall) { - // Resolve any vtable map entry - match self.fcx.inh.vtable_map.borrow_mut().pop(&vtable_key) { - Some(origins) => { - let r_origins = self.resolve(&origins, reason); - debug!("writeback::resolve_vtable_map_entry(\ - vtable_key={}, vtables={:?})", - vtable_key, r_origins.repr(self.tcx())); - self.tcx().vtable_map.borrow_mut().insert(vtable_key, r_origins); - } - None => {} - } - } - fn resolve(&self, t: &T, reason: ResolveReason) -> T { t.resolve_in(&mut Resolver::new(self.fcx, reason)) } @@ -504,3 +507,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } } } + +/////////////////////////////////////////////////////////////////////////// +// During type check, we store promises with the result of trait +// lookup rather than the actual results (because the results are not +// necessarily available immediately). These routines unwind the +// promises. It is expected that we will have already reported any +// errors that may be encountered, so if the promises store an error, +// a dummy result is returned. diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence/mod.rs similarity index 61% rename from src/librustc/middle/typeck/coherence.rs rename to src/librustc/middle/typeck/coherence/mod.rs index 8de17627e2825..76c5cab234f37 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,12 +10,13 @@ // Coherence phase // -// The job of the coherence phase of typechecking is to ensure that each trait -// has at most one implementation for each type. Then we build a mapping from -// each trait in the system to its implementations. +// The job of the coherence phase of typechecking is to ensure that +// each trait has at most one implementation for each type. This is +// done by the orphan and overlap modules. Then we build up various +// mappings. That mapping code resides here. -use metadata::csearch::{each_impl, get_impl_trait, each_implementation_for_trait}; +use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; use middle::subst; use middle::subst::{Substs}; @@ -35,27 +36,24 @@ use middle::typeck::CrateCtxt; use middle::typeck::infer::combine::Combine; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; -use middle::typeck::infer; -use util::ppaux::Repr; -use middle::def::{DefStruct, DefTy}; +use std::collections::{HashSet}; +use std::cell::RefCell; +use std::rc::Rc; use syntax::ast::{Crate, DefId}; -use syntax::ast::{Item, ItemEnum, ItemImpl, ItemMod, ItemStruct}; -use syntax::ast::{LOCAL_CRATE, TraitRef, TyPath}; +use syntax::ast::{Item, ItemImpl}; +use syntax::ast::{LOCAL_CRATE, TraitRef}; use syntax::ast; use syntax::ast_map::NodeItem; use syntax::ast_map; use syntax::ast_util::{local_def}; -use syntax::codemap::{Span, DUMMY_SP}; +use syntax::codemap::{Span}; use syntax::parse::token; use syntax::visit; +use util::nodemap::{DefIdMap, FnvHashMap}; +use util::ppaux::Repr; -use std::collections::HashSet; -use std::cell::RefCell; -use std::rc::Rc; - -struct UniversalQuantificationResult { - monotype: t -} +mod orphan; +mod overlap; fn get_base_type(inference_context: &InferCtxt, span: Span, @@ -96,53 +94,6 @@ fn get_base_type(inference_context: &InferCtxt, } } -fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool { - /*! - * - * For coherence, when we have `impl Trait for Type`, we need to - * guarantee that `Type` is "local" to the - * crate. For our purposes, this means that it must contain - * some nominal type defined in this crate. - */ - - let mut found_nominal = false; - ty::walk_ty(original_type, |t| { - match get(t).sty { - ty_enum(def_id, _) | - ty_struct(def_id, _) | - ty_unboxed_closure(def_id, _) => { - if def_id.krate == ast::LOCAL_CRATE { - found_nominal = true; - } - } - ty_trait(box ty::TyTrait { def_id, .. }) => { - if def_id.krate == ast::LOCAL_CRATE { - found_nominal = true; - } - } - ty_uniq(..) => { - match tcx.lang_items.owned_box() { - Some(did) if did.krate == ast::LOCAL_CRATE => { - found_nominal = true; - } - _ => {} - } - } - ty_box(..) => { - match tcx.lang_items.gc() { - Some(did) if did.krate == ast::LOCAL_CRATE => { - found_nominal = true; - } - _ => {} - } - } - - _ => { } - } - }); - return found_nominal; -} - // Returns the def ID of the base type, if there is one. fn get_base_type_def_id(inference_context: &InferCtxt, span: Span, @@ -185,6 +136,7 @@ fn get_base_type_def_id(inference_context: &InferCtxt, struct CoherenceChecker<'a, 'tcx: 'a> { crate_context: &'a CrateCtxt<'a, 'tcx>, inference_context: InferCtxt<'a, 'tcx>, + inherent_impls: RefCell>>>>, } struct CoherenceCheckVisitor<'a, 'tcx: 'a> { @@ -214,57 +166,6 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> { } } -struct PrivilegedScopeVisitor<'a, 'tcx: 'a> { - cc: &'a CoherenceChecker<'a, 'tcx> -} - -impl<'a, 'tcx, 'v> visit::Visitor<'v> for PrivilegedScopeVisitor<'a, 'tcx> { - fn visit_item(&mut self, item: &Item) { - - match item.node { - ItemMod(ref module_) => { - // Then visit the module items. - visit::walk_mod(self, module_); - } - ItemImpl(_, None, ref ast_ty, _) => { - if !self.cc.ast_type_is_defined_in_local_crate(&**ast_ty) { - // This is an error. - let session = &self.cc.crate_context.tcx.sess; - span_err!(session, item.span, E0116, - "cannot associate methods with a type outside the \ - crate the type is defined in; define and implement \ - a trait or new type instead"); - } - } - ItemImpl(_, Some(ref trait_ref), _, _) => { - let tcx = self.cc.crate_context.tcx; - // `for_ty` is `Type` in `impl Trait for Type` - let for_ty = ty::node_id_to_type(tcx, item.id); - if !type_is_defined_in_local_crate(tcx, for_ty) { - // This implementation is not in scope of its base - // type. This still might be OK if the trait is - // defined in the same crate. - - let trait_def_id = - self.cc.trait_ref_to_trait_def_id(trait_ref); - - if trait_def_id.krate != LOCAL_CRATE { - let session = &self.cc.crate_context.tcx.sess; - span_err!(session, item.span, E0117, - "cannot provide an extension implementation \ - where both trait and type are not defined in this crate"); - } - } - - visit::walk_item(self, item); - } - _ => { - visit::walk_item(self, item); - } - } - } -} - impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { fn check(&self, krate: &Crate) { // Check implementations and traits. This populates the tables @@ -273,11 +174,14 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let mut visitor = CoherenceCheckVisitor { cc: self }; visit::walk_crate(&mut visitor, krate); - // Check that there are no overlapping trait instances - self.check_implementation_coherence(); - - // Check whether traits with base types are in privileged scopes. - self.check_privileged_scopes(krate); + // Copy over the inherent impls we gathered up during the walk into + // the tcx. + let mut tcx_inherent_impls = + self.crate_context.tcx.inherent_impls.borrow_mut(); + for (k, v) in self.inherent_impls.borrow().iter() { + tcx_inherent_impls.insert((*k).clone(), + Rc::new((*v.borrow()).clone())); + } // Bring in external crates. It's fine for this to happen after the // coherence checks, because we ensure by construction that no errors @@ -290,7 +194,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { self.populate_destructor_table(); } - fn check_implementation(&self, item: &Item, + fn check_implementation(&self, + item: &Item, associated_traits: &[TraitRef]) { let tcx = self.crate_context.tcx; let impl_did = local_def(item.id); @@ -299,25 +204,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { // If there are no traits, then this implementation must have a // base type. - if associated_traits.len() == 0 { - debug!("(checking implementation) no associated traits for item '{}'", - token::get_ident(item.ident)); - - match get_base_type_def_id(&self.inference_context, - item.span, - self_type.ty) { - None => { - let session = &self.crate_context.tcx.sess; - span_err!(session, item.span, E0118, - "no base type found for inherent implementation; \ - implement a trait or new type instead"); - } - Some(_) => { - // Nothing to do. - } - } - } - let impl_items = self.create_impl_from_item(item); for associated_trait in associated_traits.iter() { @@ -408,8 +294,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { - let tcx = self.crate_context.tcx; - match tcx.inherent_impls.borrow().find(&base_def_id) { + match self.inherent_impls.borrow().find(&base_def_id) { Some(implementation_list) => { implementation_list.borrow_mut().push(impl_def_id); return; @@ -417,178 +302,24 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { None => {} } - tcx.inherent_impls.borrow_mut().insert(base_def_id, - Rc::new(RefCell::new(vec!(impl_def_id)))); + self.inherent_impls.borrow_mut().insert( + base_def_id, + Rc::new(RefCell::new(vec!(impl_def_id)))); } fn add_trait_impl(&self, base_def_id: DefId, impl_def_id: DefId) { + debug!("add_trait_impl: base_def_id={} impl_def_id={}", + base_def_id, impl_def_id); ty::record_trait_implementation(self.crate_context.tcx, base_def_id, impl_def_id); } - fn check_implementation_coherence(&self) { - for trait_id in self.crate_context.tcx.trait_impls.borrow().keys() { - self.check_implementation_coherence_of(*trait_id); - } - } - - fn check_implementation_coherence_of(&self, trait_def_id: DefId) { - // Unify pairs of polytypes. - self.iter_impls_of_trait_local(trait_def_id, |impl_a| { - let polytype_a = - self.get_self_type_for_implementation(impl_a); - - // "We have an impl of trait for type , - // and that impl is " - self.iter_impls_of_trait(trait_def_id, |impl_b| { - - // An impl is coherent with itself - if impl_a != impl_b { - let polytype_b = self.get_self_type_for_implementation( - impl_b); - - if self.polytypes_unify(polytype_a.clone(), polytype_b) { - let session = &self.crate_context.tcx.sess; - span_err!(session, self.span_of_impl(impl_a), E0119, - "conflicting implementations for trait `{}`", - ty::item_path_str(self.crate_context.tcx, trait_def_id)); - if impl_b.krate == LOCAL_CRATE { - span_note!(session, self.span_of_impl(impl_b), - "note conflicting implementation here"); - } else { - let crate_store = &self.crate_context.tcx.sess.cstore; - let cdata = crate_store.get_crate_data(impl_b.krate); - span_note!(session, self.span_of_impl(impl_a), - "conflicting implementation in crate `{}`", - cdata.name); - } - } - } - }) - }) - } - - fn iter_impls_of_trait(&self, trait_def_id: DefId, f: |DefId|) { - self.iter_impls_of_trait_local(trait_def_id, |x| f(x)); - - if trait_def_id.krate == LOCAL_CRATE { - return; - } - - let crate_store = &self.crate_context.tcx.sess.cstore; - csearch::each_implementation_for_trait(crate_store, trait_def_id, |impl_def_id| { - // Is this actually necessary? - let _ = lookup_item_type(self.crate_context.tcx, impl_def_id); - f(impl_def_id); - }); - } - - fn iter_impls_of_trait_local(&self, trait_def_id: DefId, f: |DefId|) { - match self.crate_context.tcx.trait_impls.borrow().find(&trait_def_id) { - Some(impls) => { - for &impl_did in impls.borrow().iter() { - f(impl_did); - } - } - None => { /* no impls? */ } - } - } - - fn polytypes_unify(&self, - polytype_a: Polytype, - polytype_b: Polytype) - -> bool { - let universally_quantified_a = - self.universally_quantify_polytype(polytype_a); - let universally_quantified_b = - self.universally_quantify_polytype(polytype_b); - - return self.can_unify_universally_quantified( - &universally_quantified_a, &universally_quantified_b) || - self.can_unify_universally_quantified( - &universally_quantified_b, &universally_quantified_a); - } - - // Converts a polytype to a monotype by replacing all parameters with - // type variables. Returns the monotype and the type variables created. - fn universally_quantify_polytype(&self, polytype: Polytype) - -> UniversalQuantificationResult - { - let substitutions = - self.inference_context.fresh_substs_for_type(DUMMY_SP, - &polytype.generics); - let monotype = polytype.ty.subst(self.crate_context.tcx, &substitutions); - - UniversalQuantificationResult { - monotype: monotype - } - } - - fn can_unify_universally_quantified<'a>(&self, - a: &'a UniversalQuantificationResult, - b: &'a UniversalQuantificationResult) - -> bool - { - infer::can_mk_subty(&self.inference_context, - a.monotype, - b.monotype).is_ok() - } - fn get_self_type_for_implementation(&self, impl_did: DefId) -> Polytype { self.crate_context.tcx.tcache.borrow().get_copy(&impl_did) } - // Privileged scope checking - fn check_privileged_scopes(&self, krate: &Crate) { - let mut visitor = PrivilegedScopeVisitor{ cc: self }; - visit::walk_crate(&mut visitor, krate); - } - - fn trait_ref_to_trait_def_id(&self, trait_ref: &TraitRef) -> DefId { - let def_map = &self.crate_context.tcx.def_map; - let trait_def = def_map.borrow().get_copy(&trait_ref.ref_id); - let trait_id = trait_def.def_id(); - return trait_id; - } - - /// For coherence, when we have `impl Type`, we need to guarantee that - /// `Type` is "local" to the crate. For our purposes, this means that it - /// must precisely name some nominal type defined in this crate. - fn ast_type_is_defined_in_local_crate(&self, original_type: &ast::Ty) -> bool { - match original_type.node { - TyPath(_, _, path_id) => { - match self.crate_context.tcx.def_map.borrow().get_copy(&path_id) { - DefTy(def_id) | DefStruct(def_id) => { - if def_id.krate != LOCAL_CRATE { - return false; - } - - // Make sure that this type precisely names a nominal - // type. - match self.crate_context.tcx.map.find(def_id.node) { - None => { - self.crate_context.tcx.sess.span_bug( - original_type.span, - "resolve didn't resolve this type?!"); - } - Some(NodeItem(item)) => { - match item.node { - ItemStruct(..) | ItemEnum(..) => true, - _ => false, - } - } - Some(_) => false, - } - } - _ => false - } - } - _ => false - } - } - // Converts an implementation in the AST to a vector of items. fn create_impl_from_item(&self, item: &Item) -> Vec { match item.node { @@ -623,11 +354,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } } - fn span_of_impl(&self, impl_did: DefId) -> Span { - assert_eq!(impl_did.krate, LOCAL_CRATE); - self.crate_context.tcx.map.span(impl_did.node) - } - // External crate handling fn add_external_impl(&self, @@ -824,5 +550,8 @@ pub fn check_coherence(crate_context: &CrateCtxt) { CoherenceChecker { crate_context: crate_context, inference_context: new_infer_ctxt(crate_context.tcx), + inherent_impls: RefCell::new(FnvHashMap::new()), }.check(crate_context.tcx.map.krate()); + orphan::check(crate_context.tcx); + overlap::check(crate_context.tcx); } diff --git a/src/librustc/middle/typeck/coherence/orphan.rs b/src/librustc/middle/typeck/coherence/orphan.rs new file mode 100644 index 0000000000000..e7139e1229b23 --- /dev/null +++ b/src/librustc/middle/typeck/coherence/orphan.rs @@ -0,0 +1,75 @@ +// Copyright 2014 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. + +/*! + * Orphan checker: every impl either implements a trait defined in this + * crate or pertains to a type defined in this crate. + */ + +use middle::traits; +use middle::ty; +use syntax::ast::{Item, ItemImpl}; +use syntax::ast; +use syntax::ast_util; +use syntax::visit; +use util::ppaux::Repr; + +pub fn check(tcx: &ty::ctxt) { + let mut orphan = OrphanChecker { tcx: tcx }; + visit::walk_crate(&mut orphan, tcx.map.krate()); +} + +struct OrphanChecker<'cx, 'tcx:'cx> { + tcx: &'cx ty::ctxt<'tcx> +} + +impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { + fn visit_item(&mut self, item: &'v ast::Item) { + let def_id = ast_util::local_def(item.id); + match item.node { + ast::ItemImpl(_, None, _, _) => { + // For inherent impls, self type must be a nominal type + // defined in this crate. + debug!("coherence2::orphan check: inherent impl {}", item.repr(self.tcx)); + let self_ty = ty::lookup_item_type(self.tcx, def_id).ty; + match ty::get(self_ty).sty { + ty::ty_enum(def_id, _) | + ty::ty_struct(def_id, _) => { + if def_id.krate != ast::LOCAL_CRATE { + span_err!(self.tcx.sess, item.span, E0116, + "cannot associate methods with a type outside the \ + crate the type is defined in; define and implement \ + a trait or new type instead"); + } + } + _ => { + span_err!(self.tcx.sess, item.span, E0118, + "no base type found for inherent implementation; \ + implement a trait or new type instead"); + } + } + } + ast::ItemImpl(_, Some(_), _, _) => { + // "Trait" impl + debug!("coherence2::orphan check: trait impl {}", item.repr(self.tcx)); + if traits::is_orphan_impl(self.tcx, def_id) { + span_err!(self.tcx.sess, item.span, E0117, + "cannot provide an extension implementation \ + where both trait and type are not defined in this crate"); + } + } + _ => { + // Not an impl + } + } + + visit::walk_item(self, item); + } +} diff --git a/src/librustc/middle/typeck/coherence/overlap.rs b/src/librustc/middle/typeck/coherence/overlap.rs new file mode 100644 index 0000000000000..48f71d95c429a --- /dev/null +++ b/src/librustc/middle/typeck/coherence/overlap.rs @@ -0,0 +1,119 @@ +// Copyright 2014 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. + +/*! + * Overlap: No two impls for the same trait are implemented for the + * same type. + */ + +use middle::traits; +use middle::ty; +use middle::typeck::infer::{new_infer_ctxt}; +use middle::typeck::infer; +use syntax::ast::{DefId}; +use syntax::ast::{LOCAL_CRATE}; +use syntax::ast; +use syntax::codemap::{Span}; +use util::ppaux::Repr; + +pub fn check(tcx: &ty::ctxt) { + let overlap = OverlapChecker { tcx: tcx }; + overlap.check_for_overlapping_impls(); +} + +struct OverlapChecker<'cx, 'tcx:'cx> { + tcx: &'cx ty::ctxt<'tcx> +} + +impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { + fn check_for_overlapping_impls(&self) { + debug!("check_for_overlapping_impls"); + let trait_impls = self.tcx.trait_impls.borrow(); + for trait_def_id in trait_impls.keys() { + self.check_for_overlapping_impls_of_trait(*trait_def_id); + } + } + + fn check_for_overlapping_impls_of_trait(&self, + trait_def_id: ast::DefId) + { + debug!("check_for_overlapping_impls_of_trait(trait_def_id={})", + trait_def_id.repr(self.tcx)); + + // FIXME -- it seems like this method actually pushes + // duplicate impls onto the list + ty::populate_implementations_for_type_if_necessary(self.tcx, + trait_def_id); + + let mut impls = Vec::new(); + self.push_impls_of_trait(trait_def_id, &mut impls); + + for (i, &impl1_def_id) in impls.iter().enumerate() { + if impl1_def_id.krate != ast::LOCAL_CRATE { + // we don't need to check impls if both are external; + // that's the other crate's job. + continue; + } + + for &impl2_def_id in impls.slice_from(i+1).iter() { + self.check_if_impls_overlap(trait_def_id, + impl1_def_id, + impl2_def_id); + } + } + } + + fn check_if_impls_overlap(&self, + trait_def_id: ast::DefId, + impl1_def_id: ast::DefId, + impl2_def_id: ast::DefId) + { + assert_eq!(impl1_def_id.krate, ast::LOCAL_CRATE); + + debug!("check_if_impls_overlap({}, {}, {})", + trait_def_id.repr(self.tcx), + impl1_def_id.repr(self.tcx), + impl2_def_id.repr(self.tcx)); + + let infcx = infer::new_infer_ctxt(self.tcx); + if !traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) { + return; + } + + span_err!(self.tcx.sess, self.span_of_impl(impl1_def_id), E0119, + "conflicting implementations for trait `{}`", + ty::item_path_str(self.tcx, trait_def_id)); + + if impl2_def_id.krate == ast::LOCAL_CRATE { + span_note!(self.tcx.sess, self.span_of_impl(impl2_def_id), + "note conflicting implementation here"); + } else { + let crate_store = &self.tcx.sess.cstore; + let cdata = crate_store.get_crate_data(impl2_def_id.krate); + span_note!(self.tcx.sess, self.span_of_impl(impl1_def_id), + "conflicting implementation in crate `{}`", + cdata.name); + } + } + + fn push_impls_of_trait(&self, + trait_def_id: ast::DefId, + out: &mut Vec) { + match self.tcx.trait_impls.borrow().find(&trait_def_id) { + Some(impls) => { out.push_all(impls.borrow().as_slice()); } + None => { /* no impls */ } + } + } + + fn span_of_impl(&self, impl_did: ast::DefId) -> Span { + assert_eq!(impl_did.krate, ast::LOCAL_CRATE); + self.tcx.map.span(impl_did.node) + } +} diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 44141f25418e4..e0a35dc72a39f 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -327,10 +327,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let sty_b = &ty::get(b).sty; match (sty_a, sty_b) { - (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_rptr(_, mt_b)) => { + (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => { self.unpack_actual_value(t_a, |sty_a| { - match self.unsize_ty(sty_a, mt_b.ty) { + match self.unsize_ty(t_a, sty_a, mt_b.ty) { Some((ty, kind)) => { + if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { + return Err(ty::terr_mutability); + } + let coercion = Coercion(self.get_ref().trace.clone()); let r_borrow = self.get_ref().infcx.next_region_var(coercion); let ty = ty::mk_rptr(self.get_ref().infcx.tcx, @@ -349,10 +353,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } }) } - (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_ptr(mt_b)) => { + (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => { self.unpack_actual_value(t_a, |sty_a| { - match self.unsize_ty(sty_a, mt_b.ty) { + match self.unsize_ty(t_a, sty_a, mt_b.ty) { Some((ty, kind)) => { + if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { + return Err(ty::terr_mutability); + } + let ty = ty::mk_ptr(self.get_ref().infcx.tcx, ty::mt{ty: ty, mutbl: mt_b.mutbl}); try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); @@ -370,7 +378,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { self.unpack_actual_value(t_a, |sty_a| { - match self.unsize_ty(sty_a, t_b) { + match self.unsize_ty(t_a, sty_a, t_b) { Some((ty, kind)) => { let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty); try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); @@ -393,6 +401,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // performed to unsize it. // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))` fn unsize_ty(&self, + ty_a: ty::t, sty_a: &ty::sty, ty_b: ty::t) -> Option<(ty::t, ty::UnsizeKind)> { @@ -412,9 +421,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { def_id, substs.clone(), bounds); - Some((ty, ty::UnsizeVtable(bounds, - def_id, - substs.clone()))) + Some((ty, ty::UnsizeVtable(ty::TyTrait { def_id: def_id, + bounds: bounds, + substs: substs.clone() }, + ty_a))) } (&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref substs_b)) if did_a == did_b => { @@ -432,7 +442,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() { continue; } - match self.unpack_actual_value(*tp_a, |tp| self.unsize_ty(tp, *tp_b)) { + match + self.unpack_actual_value( + *tp_a, + |tp| self.unsize_ty(*tp_a, tp, *tp_b)) + { Some((new_tp, k)) => { // Check that the whole types match. let mut new_substs = substs_a.clone(); @@ -471,14 +485,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { { let tcx = self.get_ref().infcx.tcx; - debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})", + debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={}, b_mutbl={})", a.repr(tcx), sty_a, - b.repr(tcx)); + b.repr(tcx), b_mutbl); let coercion = Coercion(self.get_ref().trace.clone()); let r_a = self.get_ref().infcx.next_region_var(coercion); - self.coerce_object(a, sty_a, b, + self.coerce_object(a, sty_a, b, b_mutbl, |tr| ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr }), || AutoPtr(r_a, b_mutbl, None)) } @@ -491,11 +505,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { { let tcx = self.get_ref().infcx.tcx; - debug!("coerce_unsafe_object(a={}, sty_a={:?}, b={})", + debug!("coerce_unsafe_object(a={}, sty_a={:?}, b={}, b_mutbl={})", a.repr(tcx), sty_a, - b.repr(tcx)); + b.repr(tcx), b_mutbl); - self.coerce_object(a, sty_a, b, + self.coerce_object(a, sty_a, b, b_mutbl, |tr| ty::mk_ptr(tcx, ty::mt{ mutbl: b_mutbl, ty: tr }), || AutoUnsafe(b_mutbl, None)) } @@ -504,19 +518,23 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { a: ty::t, sty_a: &ty::sty, b: ty::t, + b_mutbl: ast::Mutability, mk_ty: |ty::t| -> ty::t, mk_adjust: || -> ty::AutoRef) -> CoerceResult { let tcx = self.get_ref().infcx.tcx; match *sty_a { - ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { + ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty::get(ty).sty { ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds, .. - }) => { + }) => + { + debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl); + let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds); try!(self.subtype(mk_ty(tr), b)); Ok(Some(AutoDerefRef(AutoDerefRef { @@ -618,3 +636,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { }))) } } + +fn can_coerce_mutbls(from_mutbl: ast::Mutability, + to_mutbl: ast::Mutability) + -> bool { + match (from_mutbl, to_mutbl) { + (ast::MutMutable, ast::MutMutable) => true, + (ast::MutImmutable, ast::MutImmutable) => true, + (ast::MutMutable, ast::MutImmutable) => true, + (ast::MutImmutable, ast::MutMutable) => false, + } +} diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 17e7aa8ddc34c..4412b7d94d468 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -34,7 +34,7 @@ use middle::subst; -use middle::subst::Substs; +use middle::subst::{ErasedRegions, NonerasedRegions, Substs}; use middle::ty::{FloatVar, FnSig, IntVar, TyVar}; use middle::ty::{IntType, UintType}; use middle::ty::{BuiltinBounds}; @@ -113,29 +113,40 @@ pub trait Combine<'tcx> { let a_tps = a_subst.types.get_slice(space); let b_tps = b_subst.types.get_slice(space); let tps = try!(self.tps(space, a_tps, b_tps)); + substs.types.replace(space, tps); + } - let a_regions = a_subst.regions().get_slice(space); - let b_regions = b_subst.regions().get_slice(space); - - let mut invariance = Vec::new(); - let r_variances = match variances { - Some(ref variances) => variances.regions.get_slice(space), - None => { - for _ in a_regions.iter() { - invariance.push(ty::Invariant); - } - invariance.as_slice() - } - }; + match (&a_subst.regions, &b_subst.regions) { + (&ErasedRegions, _) | (_, &ErasedRegions) => { + substs.regions = ErasedRegions; + } - let regions = try!(relate_region_params(self, - item_def_id, - r_variances, - a_regions, - b_regions)); + (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => { + for &space in subst::ParamSpace::all().iter() { + let a_regions = a.get_slice(space); + let b_regions = b.get_slice(space); - substs.types.replace(space, tps); - substs.mut_regions().replace(space, regions); + let mut invariance = Vec::new(); + let r_variances = match variances { + Some(ref variances) => { + variances.regions.get_slice(space) + } + None => { + for _ in a_regions.iter() { + invariance.push(ty::Invariant); + } + invariance.as_slice() + } + }; + + let regions = try!(relate_region_params(self, + item_def_id, + r_variances, + a_regions, + b_regions)); + substs.mut_regions().replace(space, regions); + } + } } return Ok(substs); diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index b5b4cc80faac1..4f663df58824a 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -363,6 +363,7 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> { infer::ExprAssignable(_) => "mismatched types", infer::RelateTraitRefs(_) => "mismatched traits", infer::RelateSelfType(_) => "mismatched types", + infer::RelateOutputImplTypes(_) => "mismatched types", infer::MatchExpressionArm(_, _) => "match arms have incompatible types", infer::IfExpression(_) => "if and else have incompatible types", }; @@ -1465,7 +1466,11 @@ impl<'a, 'tcx> ErrorReportingHelpers for InferCtxt<'a, 'tcx> { format!("traits are compatible") } infer::RelateSelfType(_) => { - format!("type matches impl") + format!("self type matches impl self type") + } + infer::RelateOutputImplTypes(_) => { + format!("trait type parameters matches those \ + specified on the impl") } infer::MatchExpressionArm(_, _) => { format!("match arms have compatible types") diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index f11584e9356c6..db90593b5b36b 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -26,6 +26,7 @@ use middle::subst::Substs; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid}; use middle::ty; use middle::ty_fold; +use middle::ty_fold::TypeFoldable; use middle::ty_fold::TypeFolder; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::infer::coercion::Coerce; @@ -57,6 +58,7 @@ pub mod lattice; pub mod lub; pub mod region_inference; pub mod resolve; +mod skolemize; pub mod sub; pub mod test; pub mod type_variable; @@ -114,9 +116,12 @@ pub enum TypeOrigin { // Relating trait refs when resolving vtables RelateTraitRefs(Span), - // Relating trait refs when resolving vtables + // Relating self types when resolving vtables RelateSelfType(Span), + // Relating trait type parameters to those found in impl etc + RelateOutputImplTypes(Span), + // Computing common supertype in the arms of a match expression MatchExpressionArm(Span, Span), @@ -262,6 +267,7 @@ pub enum RegionVariableOrigin { BoundRegionInCoherence(ast::Name), } +#[deriving(Show)] pub enum fixup_err { unresolved_int_ty(IntVid), unresolved_float_ty(FloatVid), @@ -336,17 +342,12 @@ pub fn mk_subty(cx: &InferCtxt, origin: TypeOrigin, a: ty::t, b: ty::t) - -> ures { + -> ures +{ debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - indent(|| { - cx.commit_if_ok(|| { - let trace = TypeTrace { - origin: origin, - values: Types(expected_found(a_is_expected, a, b)) - }; - cx.sub(a_is_expected, trace).tys(a, b) - }) - }).to_ures() + cx.commit_if_ok(|| { + cx.sub_types(a_is_expected, origin, a, b) + }) } pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures { @@ -356,8 +357,8 @@ pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) }; - cx.sub(true, trace).tys(a, b) - }).to_ures() + cx.sub(true, trace).tys(a, b).to_ures() + }) } pub fn can_mk_eqty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures { @@ -393,6 +394,14 @@ pub fn verify_param_bound(cx: &InferCtxt, cx.region_vars.verify_param_bound(origin, param_ty, a, bs); } + +pub fn skolemize(cx: &InferCtxt, a: T) -> T { + let mut skol = skolemize::TypeSkolemizer::new(cx); + let b = a.fold_with(&mut skol); + debug!("skol(a={}) -> {}", a.repr(cx.tcx), b.repr(cx.tcx)); + b +} + pub fn mk_eqty(cx: &InferCtxt, a_is_expected: bool, origin: TypeOrigin, @@ -401,14 +410,8 @@ pub fn mk_eqty(cx: &InferCtxt, -> ures { debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.commit_if_ok(|| { - let trace = TypeTrace { - origin: origin, - values: Types(expected_found(a_is_expected, a, b)) - }; - try!(cx.equate(a_is_expected, trace).tys(a, b)); - Ok(()) - }) + cx.commit_if_ok( + || cx.eq_types(a_is_expected, origin, a, b)) } pub fn mk_sub_trait_refs(cx: &InferCtxt, @@ -416,25 +419,19 @@ pub fn mk_sub_trait_refs(cx: &InferCtxt, origin: TypeOrigin, a: Rc, b: Rc) - -> ures + -> ures { debug!("mk_sub_trait_refs({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - indent(|| { - cx.commit_if_ok(|| { - let trace = TypeTrace { - origin: origin, - values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) - }; - let suber = cx.sub(a_is_expected, trace); - suber.trait_refs(&*a, &*b) - }) - }).to_ures() + cx.commit_if_ok( + || cx.sub_trait_refs(a_is_expected, origin, a.clone(), b.clone())) } fn expected_found(a_is_expected: bool, a: T, - b: T) -> ty::expected_found { + b: T) + -> ty::expected_found +{ if a_is_expected { ty::expected_found {expected: a, found: b} } else { @@ -629,7 +626,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Execute `f` then unroll any bindings it creates - pub fn probe(&self, f: || -> Result) -> Result { + pub fn probe(&self, f: || -> R) -> R { debug!("probe()"); let snapshot = self.start_snapshot(); let r = f(); @@ -643,6 +640,54 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { self.region_vars.add_given(sub, sup); } + + pub fn sub_types(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: ty::t, + b: ty::t) + -> ures + { + debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); + let trace = TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + }; + self.sub(a_is_expected, trace).tys(a, b).to_ures() + } + + pub fn eq_types(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: ty::t, + b: ty::t) + -> ures + { + let trace = TypeTrace { + origin: origin, + values: Types(expected_found(a_is_expected, a, b)) + }; + self.equate(a_is_expected, trace).tys(a, b).to_ures() + } + + pub fn sub_trait_refs(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: Rc, + b: Rc) + -> ures + { + debug!("sub_trait_refs({} <: {})", + a.repr(self.tcx), + b.repr(self.tcx)); + let trace = TypeTrace { + origin: origin, + values: TraitRefs(expected_found(a_is_expected, + a.clone(), b.clone())) + }; + let suber = self.sub(a_is_expected, trace); + suber.trait_refs(&*a, &*b).to_ures() + } } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -685,17 +730,40 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .collect() } - pub fn fresh_substs_for_type(&self, - span: Span, - generics: &ty::Generics) - -> subst::Substs + pub fn fresh_substs_for_generics(&self, + span: Span, + generics: &ty::Generics) + -> subst::Substs { /*! * Given a set of generics defined on a type or impl, returns * a substitution mapping each type/region parameter to a * fresh inference variable. */ - assert!(generics.types.len(subst::SelfSpace) == 0); + + let type_params = + generics.types.map( + |_| self.next_ty_var()); + let region_params = + generics.regions.map( + |d| self.next_region_var(EarlyBoundRegion(span, d.name))); + subst::Substs::new(type_params, region_params) + } + + pub fn fresh_substs_for_trait(&self, + span: Span, + generics: &ty::Generics, + self_ty: ty::t) + -> subst::Substs + { + /*! + * Given a set of generics defined on a trait, returns a + * substitution mapping each output type/region parameter to a + * fresh inference variable, and mapping the self type to + * `self_ty`. + */ + + assert!(generics.types.len(subst::SelfSpace) == 1); assert!(generics.types.len(subst::FnSpace) == 0); assert!(generics.regions.len(subst::SelfSpace) == 0); assert!(generics.regions.len(subst::FnSpace) == 0); @@ -704,7 +772,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let region_param_defs = generics.regions.get_slice(subst::TypeSpace); let regions = self.region_vars_for_defs(span, region_param_defs); let type_parameters = self.next_ty_vars(type_parameter_count); - subst::Substs::new_type(type_parameters, regions) + subst::Substs::new_trait(type_parameters, regions, self_ty) } pub fn fresh_bound_region(&self, binder_id: ast::NodeId) -> ty::Region { @@ -731,6 +799,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_ref_to_string(self.tcx, &t) } + pub fn contains_unbound_type_variables(&self, typ: ty::t) -> ty::t { + match resolve_type(self, + None, + typ, resolve_nested_tvar | resolve_ivar) { + Ok(new_type) => new_type, + Err(_) => typ + } + } + pub fn resolve_type_vars_if_possible(&self, typ: ty::t) -> ty::t { match resolve_type(self, None, @@ -907,6 +984,7 @@ impl TypeOrigin { Misc(span) => span, RelateTraitRefs(span) => span, RelateSelfType(span) => span, + RelateOutputImplTypes(span) => span, MatchExpressionArm(match_span, _) => match_span, IfExpression(span) => span, } @@ -929,6 +1007,9 @@ impl Repr for TypeOrigin { RelateSelfType(a) => { format!("RelateSelfType({})", a.repr(tcx)) } + RelateOutputImplTypes(a) => { + format!("RelateOutputImplTypes({})", a.repr(tcx)) + } MatchExpressionArm(a, b) => { format!("MatchExpressionArm({}, {})", a.repr(tcx), b.repr(tcx)) } diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 569206f6754f9..2c0b2dbe2ba79 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -46,7 +46,6 @@ // future). If you want to resolve everything but one type, you are // probably better off writing `resolve_all - resolve_ivar`. - use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; use middle::ty::{IntType, UintType}; use middle::ty; @@ -54,7 +53,6 @@ use middle::ty_fold; use middle::typeck::infer::{fixup_err, fres, InferCtxt}; use middle::typeck::infer::{unresolved_int_ty,unresolved_float_ty,unresolved_ty}; use syntax::codemap::Span; -use util::common::indent; use util::ppaux::{Repr, ty_to_string}; pub static resolve_nested_tvar: uint = 0b0000000001; @@ -94,7 +92,7 @@ pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>, } impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'a, 'tcx> { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } @@ -114,7 +112,8 @@ impl<'a, 'tcx> ResolveState<'a, 'tcx> { pub fn resolve_type_chk(&mut self, typ: ty::t) - -> fres { + -> fres + { self.err = None; debug!("Resolving {} (modes={:x})", @@ -126,14 +125,16 @@ impl<'a, 'tcx> ResolveState<'a, 'tcx> { let rty = self.resolve_type(typ); match self.err { - None => { - debug!("Resolved {} to {} (modes={:x})", - ty_to_string(self.infcx.tcx, typ), - ty_to_string(self.infcx.tcx, rty), - self.modes); - return Ok(rty); - } - Some(e) => return Err(e) + None => { + debug!("Resolved {} to {} (modes={:x})", + ty_to_string(self.infcx.tcx, typ), + ty_to_string(self.infcx.tcx, rty), + self.modes); + return Ok(rty); + } + Some(e) => { + return Err(e); + } } } @@ -141,7 +142,7 @@ impl<'a, 'tcx> ResolveState<'a, 'tcx> { orig: ty::Region) -> fres { self.err = None; - let resolved = indent(|| self.resolve_region(orig) ); + let resolved = self.resolve_region(orig); match self.err { None => Ok(resolved), Some(e) => Err(e) diff --git a/src/librustc/middle/typeck/infer/skolemize.rs b/src/librustc/middle/typeck/infer/skolemize.rs new file mode 100644 index 0000000000000..e1d48407f2e43 --- /dev/null +++ b/src/librustc/middle/typeck/infer/skolemize.rs @@ -0,0 +1,157 @@ +// Copyright 2014 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. + +/*! + * Skolemization is the process of replacing unknown variables with + * fresh types. The idea is that the type, after skolemization, + * contains no inference variables but instead contains either a value + * for each variable (if the variable had already fresh "arbitrary" + * types wherever a variable would have been. + * + * Skolemization is used wherever we want to test what the type + * inferencer knows "so far". The primary place it is used right now + * is in the trait matching algorithm, which needs to be able to test + * whether an `impl` self type matches some other type X -- *without* + * affecting `X`. That means if that if the type `X` is in fact an + * unbound type variable, we want the match to be regarded as + * ambiguous, because depending on what type that type variable is + * ultimately assigned, the match may or may not succeed. + * + * Note that you should be careful not to allow the output of + * skolemization to leak to the user in error messages or in any other + * form. Skolemization is only really useful as an internal detail. + * + * __An important detail concerning regions.__ The skolemizer also + * replaces *all* regions with 'static. The reason behind this is + * that, in general, we do not take region relationships into account + * when making type-overloaded decisions. This is important because of + * the design of the region inferencer, which is not based on + * unification but rather on accumulating and then solving a set of + * constraints. In contrast, the type inferencer assigns a value to + * each type variable only once, and it does so as soon as it can, so + * it is reasonable to ask what the type inferencer knows "so far". + */ + +use middle::ty; +use middle::ty_fold; +use middle::ty_fold::TypeFoldable; +use middle::ty_fold::TypeFolder; + +use super::InferCtxt; +use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; +use super::unify::SimplyUnifiable; +use super::unify::UnifyKey; + +pub struct TypeSkolemizer<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + skolemization_count: uint +} + +impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { + pub fn new<'tcx>(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeSkolemizer<'a, 'tcx> { + TypeSkolemizer { infcx: infcx, skolemization_count: 0 } + } + + fn probe_ty(&mut self, v: ty::TyVid) -> ty::t { + self.skolemize_if_none(self.infcx.type_variables.borrow().probe(v), ty::SkolemizedTy) + } + + fn probe_unifiable>>(&mut self, k: K) -> ty::t { + self.skolemize_if_none(self.infcx.probe_var(k), ty::SkolemizedIntTy) + } + + fn skolemize_if_none(&mut self, o: Option, + skolemizer: |uint| -> ty::InferTy) + -> ty::t { + match o { + Some(t) => t.fold_with(self), + None => { + let index = self.skolemization_count; + self.skolemization_count += 1; + ty::mk_infer(self.tcx(), skolemizer(index)) + } + } + } +} + +impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> { + fn tcx<'b>(&'b self) -> &'b ty::ctxt<'tcx> { + self.infcx.tcx + } + + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReEarlyBound(..) | + ty::ReLateBound(..) => { + // leave bound regions alone + r + } + + ty::ReStatic | + ty::ReFree(_) | + ty::ReScope(_) | + ty::ReInfer(_) | + ty::ReEmpty => { + // replace all free regions with 'static + ty::ReStatic + } + } + } + + fn fold_ty(&mut self, t: ty::t) -> ty::t { + match ty::get(t).sty { + ty::ty_infer(ty::TyVar(v)) => { + self.probe_ty(v) + } + + ty::ty_infer(ty::IntVar(v)) => { + self.probe_unifiable(v) + } + + ty::ty_infer(ty::FloatVar(v)) => { + self.probe_unifiable(v) + } + + ty::ty_infer(ty::SkolemizedTy(_)) | + ty::ty_infer(ty::SkolemizedIntTy(_)) => { + self.tcx().sess.bug("Cannot skolemize a skolemized type"); + } + + ty::ty_open(..) => { + self.tcx().sess.bug("Cannot skolemize an open existential type"); + } + + ty::ty_nil | + ty::ty_bot | + ty::ty_bool | + ty::ty_char | + ty::ty_int(..) | + ty::ty_uint(..) | + ty::ty_float(..) | + ty::ty_enum(..) | + ty::ty_box(..) | + ty::ty_uniq(..) | + ty::ty_str | + ty::ty_err | + ty::ty_vec(..) | + ty::ty_ptr(..) | + ty::ty_rptr(..) | + ty::ty_bare_fn(..) | + ty::ty_closure(..) | + ty::ty_trait(..) | + ty::ty_struct(..) | + ty::ty_unboxed_closure(..) | + ty::ty_tup(..) | + ty::ty_param(..) => { + ty_fold::super_fold_ty(self, t) + } + } + } +} diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index 22d78340e9637..301582d55d6eb 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -258,6 +258,7 @@ impl sv::SnapshotVecDelegate,()> for Delegate { * relationship. */ pub trait SimplyUnifiable : Clone + PartialEq + Repr { + fn to_type(&self) -> ty::t; fn to_type_err(expected_found) -> ty::type_err; } @@ -286,6 +287,7 @@ pub trait InferCtxtMethodsForSimplyUnifiableTypes ures; + fn probe_var(&self, a_id: K) -> Option; } impl<'a,'tcx,V:SimplyUnifiable,K:UnifyKey>> @@ -370,6 +372,16 @@ impl<'a,'tcx,V:SimplyUnifiable,K:UnifyKey>> } } } + + fn probe_var(&self, a_id: K) -> Option { + let tcx = self.tcx; + let table = UnifyKey::unification_table(self); + let node_a = table.borrow_mut().get(tcx, a_id); + match node_a.value { + None => None, + Some(ref a_t) => Some(a_t.to_type()) + } + } } /////////////////////////////////////////////////////////////////////////// @@ -393,6 +405,13 @@ impl UnifyKey> for ty::IntVid { } impl SimplyUnifiable for IntVarValue { + fn to_type(&self) -> ty::t { + match *self { + ty::IntType(i) => ty::mk_mach_int(i), + ty::UintType(i) => ty::mk_mach_uint(i), + } + } + fn to_type_err(err: expected_found) -> ty::type_err { return ty::terr_int_mismatch(err); } @@ -422,6 +441,10 @@ impl UnifyValue for Option { } impl SimplyUnifiable for ast::FloatTy { + fn to_type(&self) -> ty::t { + ty::mk_mach_float(*self) + } + fn to_type_err(err: expected_found) -> ty::type_err { return ty::terr_float_mismatch(err); } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index e59f1aa3ce4c1..7a913699280bc 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -71,9 +71,10 @@ use middle::ty; use util::common::time; use util::ppaux::Repr; use util::ppaux; -use util::nodemap::{DefIdMap, FnvHashMap}; +use util::nodemap::{NodeMap, FnvHashMap}; use std::cell::RefCell; +use std::rc::Rc; use syntax::codemap::Span; use syntax::print::pprust::*; use syntax::{ast, ast_map, abi}; @@ -92,7 +93,7 @@ pub struct param_index { pub index: uint } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone)] pub enum MethodOrigin { // fully statically resolved method MethodStatic(ast::DefId), @@ -110,27 +111,21 @@ pub enum MethodOrigin { // details for a method invoked with a receiver whose type is a type parameter // with a bounded trait. -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone)] pub struct MethodParam { - // the trait containing the method to be invoked - pub trait_id: ast::DefId, + // the precise trait reference that occurs as a bound -- this may + // be a supertrait of what the user actually typed. + pub trait_ref: Rc, - // index of the method to be invoked amongst the trait's methods + // index of uint in the list of methods for the trait pub method_num: uint, - - // index of the type parameter (from those that are in scope) that is - // the type of the receiver - pub param_num: param_index, - - // index of the bound for this type parameter which specifies the trait - pub bound_num: uint, } // details for a method invoked with a receiver whose type is an object -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone)] pub struct MethodObject { // the (super)trait containing the method to be invoked - pub trait_id: ast::DefId, + pub trait_ref: Rc, // the actual base trait id of the object pub object_trait_id: ast::DefId, @@ -154,7 +149,7 @@ pub struct MethodCallee { /** * With method calls, we store some extra information in - * side tables (i.e method_map, vtable_map). We use + * side tables (i.e method_map). We use * MethodCall as a key to index into these tables instead of * just directly using the expression's NodeId. The reason * for this being that we may apply adjustments (coercions) @@ -276,10 +271,9 @@ impl Repr for vtable_origin { } } -pub type vtable_map = RefCell>; - - -pub type impl_vtable_map = RefCell>; +// For every explicit cast into an object type, maps from the cast +// expr to the associated trait ref. +pub type ObjectCastMap = RefCell>>; pub struct CrateCtxt<'a, 'tcx: 'a> { // A mapping from method call sites to traits that have that method. diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index ba1f7ca2cb231..be4a1c95e5550 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -496,7 +496,13 @@ pub fn parameterized(cx: &ctxt, if cx.sess.verbose() { for t in substs.types.get_slice(subst::SelfSpace).iter() { - strs.push(format!("for {}", t.repr(cx))); + strs.push(format!("self {}", t.repr(cx))); + } + + // generally there shouldn't be any substs in the fn param + // space, but in verbose mode, print them out. + for t in substs.types.get_slice(subst::FnSpace).iter() { + strs.push(format!("fn {}", t.repr(cx))); } } @@ -539,15 +545,15 @@ impl Repr for () { } } -impl Repr for Rc { +impl<'a,T:Repr> Repr for &'a T { fn repr(&self, tcx: &ctxt) -> String { (&**self).repr(tcx) } } -impl<'a, T:Repr> Repr for &'a T { +impl Repr for Rc { fn repr(&self, tcx: &ctxt) -> String { - (*self).repr(tcx) + (&**self).repr(tcx) } } @@ -690,7 +696,11 @@ impl Repr for ty::ParamBounds { impl Repr for ty::TraitRef { fn repr(&self, tcx: &ctxt) -> String { - trait_ref_to_string(tcx, self) + let base = ty::item_path_str(tcx, self.def_id); + let trait_def = ty::lookup_trait_def(tcx, self.def_id); + format!("<{} as {}>", + self.substs.self_ty().repr(tcx), + parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics)) } } @@ -962,18 +972,16 @@ impl Repr for typeck::MethodOrigin { impl Repr for typeck::MethodParam { fn repr(&self, tcx: &ctxt) -> String { - format!("MethodParam({},{:?},{:?},{:?})", - self.trait_id.repr(tcx), - self.method_num, - self.param_num, - self.bound_num) + format!("MethodParam({},{})", + self.trait_ref.repr(tcx), + self.method_num) } } impl Repr for typeck::MethodObject { fn repr(&self, tcx: &ctxt) -> String { format!("MethodObject({},{:?},{:?})", - self.trait_id.repr(tcx), + self.trait_ref.repr(tcx), self.method_num, self.real_index) } @@ -1231,3 +1239,4 @@ impl Repr for (A,B) { format!("({},{})", a.repr(tcx), b.repr(tcx)) } } + diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e0afb80ad37f5..7272425761e02 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -226,7 +226,7 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt, match tcx.inherent_impls.borrow().find(&did) { None => {} Some(i) => { - impls.extend(i.borrow().iter().map(|&did| { build_impl(cx, tcx, did) })); + impls.extend(i.iter().map(|&did| { build_impl(cx, tcx, did) })); } } diff --git a/src/librustuv/access.rs b/src/librustuv/access.rs index 664c942500732..b7475c8c077fc 100644 --- a/src/librustuv/access.rs +++ b/src/librustuv/access.rs @@ -136,7 +136,7 @@ impl<'a, T: Send> DerefMut for Guard<'a, T> { } #[unsafe_destructor] -impl<'a, T> Drop for Guard<'a, T> { +impl<'a, T:Send> Drop for Guard<'a, T> { fn drop(&mut self) { // This guard's homing missile is still armed, so we're guaranteed to be // on the same I/O event loop, so this unsafety should be ok. diff --git a/src/libsync/comm/mod.rs b/src/libsync/comm/mod.rs index c8b86c47c90b5..9177fa4a6b446 100644 --- a/src/libsync/comm/mod.rs +++ b/src/libsync/comm/mod.rs @@ -379,7 +379,7 @@ pub struct Receiver { inner: UnsafeCell>, receives: Cell, // can't share in an arc - marker: marker::NoSync, + _marker: marker::NoSync, } /// An iterator over messages on a receiver, this iterator will block @@ -397,7 +397,7 @@ pub struct Sender { inner: UnsafeCell>, sends: Cell, // can't share in an arc - marker: marker::NoSync, + _marker: marker::NoSync, } /// The sending-half of Rust's synchronous channel type. This half can only be @@ -406,7 +406,7 @@ pub struct Sender { pub struct SyncSender { inner: Arc>>, // can't share in an arc - marker: marker::NoSync, + _marker: marker::NoSync, } /// This enumeration is the list of the possible reasons that try_recv could not @@ -543,7 +543,7 @@ impl Sender { Sender { inner: UnsafeCell::new(inner), sends: Cell::new(0), - marker: marker::NoSync, + _marker: marker::NoSync, } } @@ -719,7 +719,7 @@ impl Drop for Sender { impl SyncSender { fn new(inner: Arc>>) -> SyncSender { - SyncSender { inner: inner, marker: marker::NoSync } + SyncSender { inner: inner, _marker: marker::NoSync } } /// Sends a value on this synchronous channel. @@ -807,7 +807,7 @@ impl Drop for SyncSender { impl Receiver { fn new(inner: Flavor) -> Receiver { - Receiver { inner: UnsafeCell::new(inner), receives: Cell::new(0), marker: marker::NoSync } + Receiver { inner: UnsafeCell::new(inner), receives: Cell::new(0), _marker: marker::NoSync } } /// Blocks waiting for a value on this receiver diff --git a/src/libsync/deque.rs b/src/libsync/deque.rs index e70a730dc3a13..521a7d0bd73d7 100644 --- a/src/libsync/deque.rs +++ b/src/libsync/deque.rs @@ -87,7 +87,7 @@ struct Deque { /// There may only be one worker per deque. pub struct Worker { deque: Arc>, - noshare: marker::NoSync, + _noshare: marker::NoSync, } /// The stealing half of the work-stealing deque. Stealers have access to the @@ -95,7 +95,7 @@ pub struct Worker { /// `steal` method. pub struct Stealer { deque: Arc>, - noshare: marker::NoSync, + _noshare: marker::NoSync, } /// When stealing some data, this is an enumeration of the possible outcomes. @@ -153,8 +153,8 @@ impl BufferPool { pub fn deque(&self) -> (Worker, Stealer) { let a = Arc::new(Deque::new(self.clone())); let b = a.clone(); - (Worker { deque: a, noshare: marker::NoSync }, - Stealer { deque: b, noshare: marker::NoSync }) + (Worker { deque: a, _noshare: marker::NoSync }, + Stealer { deque: b, _noshare: marker::NoSync }) } fn alloc(&mut self, bits: uint) -> Box> { @@ -217,7 +217,7 @@ impl Stealer { impl Clone for Stealer { fn clone(&self) -> Stealer { - Stealer { deque: self.deque.clone(), noshare: marker::NoSync } + Stealer { deque: self.deque.clone(), _noshare: marker::NoSync } } } diff --git a/src/test/compile-fail/bad-method-typaram-kind.rs b/src/test/compile-fail/bad-method-typaram-kind.rs index b63ecc6b66f26..cf07dc02b9609 100644 --- a/src/test/compile-fail/bad-method-typaram-kind.rs +++ b/src/test/compile-fail/bad-method-typaram-kind.rs @@ -9,7 +9,7 @@ // except according to those terms. fn foo() { - 1u.bar::(); //~ ERROR: does not fulfill `Send` + 1u.bar::(); //~ ERROR `core::kinds::Send` is not implemented } trait bar { diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index fb9a060cb602a..4e0ad8088bee4 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -16,10 +16,8 @@ trait Trait {} pub fn main() { let x: Vec = Vec::new(); - //~^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` - //~^^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` - //~^^^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` + //~^ ERROR the trait `core::kinds::Sized` is not implemented + //~^^ ERROR the trait `core::kinds::Sized` is not implemented let x: Vec>> = Vec::new(); - //~^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` - //~^^ ERROR instantiating a type parameter with an incompatible type `Trait+Sized`, which does not fulfill `Sized` + //~^ ERROR the trait `core::kinds::Sized` is not implemented } diff --git a/src/test/compile-fail/builtin-superkinds-double-superkind.rs b/src/test/compile-fail/builtin-superkinds-double-superkind.rs index d5a648e3e2001..f3b9c395e4514 100644 --- a/src/test/compile-fail/builtin-superkinds-double-superkind.rs +++ b/src/test/compile-fail/builtin-superkinds-double-superkind.rs @@ -13,9 +13,9 @@ trait Foo : Send+Sync { } -impl Foo for (T,) { } //~ ERROR cannot implement this trait +impl Foo for (T,) { } //~ ERROR the trait `core::kinds::Send` is not implemented -impl Foo for (T,T) { } //~ ERROR cannot implement this trait +impl Foo for (T,T) { } //~ ERROR the trait `core::kinds::Sync` is not implemented impl Foo for (T,T,T) { } // (ok) diff --git a/src/test/compile-fail/builtin-superkinds-in-metadata.rs b/src/test/compile-fail/builtin-superkinds-in-metadata.rs index 889d82383e74e..76835c9955f6e 100644 --- a/src/test/compile-fail/builtin-superkinds-in-metadata.rs +++ b/src/test/compile-fail/builtin-superkinds-in-metadata.rs @@ -21,6 +21,7 @@ struct X(T); impl RequiresShare for X { } -impl RequiresRequiresShareAndSend for X { } //~ ERROR cannot implement this trait +impl RequiresRequiresShareAndSend for X { } +//~^ ERROR the trait `core::kinds::Send` is not implemented fn main() { } diff --git a/src/test/compile-fail/builtin-superkinds-self-type.rs b/src/test/compile-fail/builtin-superkinds-self-type.rs index 726413981a5f1..86d3d7e9cbc6c 100644 --- a/src/test/compile-fail/builtin-superkinds-self-type.rs +++ b/src/test/compile-fail/builtin-superkinds-self-type.rs @@ -12,12 +12,12 @@ // to use capabilities granted by builtin kinds as supertraits. trait Foo : Sync+'static { - fn foo(self, mut chan: Sender) { - chan.send(self); //~ ERROR does not fulfill `Send` - } + fn foo(self, mut chan: Sender) { } } impl Foo for T { } +//~^ ERROR the parameter type `T` may not live long enough +//~^^ ERROR the parameter type `T` may not live long enough fn main() { let (tx, rx) = channel(); diff --git a/src/test/compile-fail/builtin-superkinds-simple.rs b/src/test/compile-fail/builtin-superkinds-simple.rs index caf968612922b..fda83c03a7dce 100644 --- a/src/test/compile-fail/builtin-superkinds-simple.rs +++ b/src/test/compile-fail/builtin-superkinds-simple.rs @@ -14,6 +14,6 @@ trait Foo : Send { } impl <'a> Foo for &'a mut () { } -//~^ ERROR which does not fulfill `Send`, cannot implement this trait +//~^ ERROR does not fulfill the required lifetime fn main() { } diff --git a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs index 166ca10ee1875..e77177f7f6d29 100644 --- a/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs +++ b/src/test/compile-fail/builtin-superkinds-typaram-not-send.rs @@ -12,6 +12,6 @@ trait Foo : Send { } -impl Foo for T { } //~ ERROR cannot implement this trait +impl Foo for T { } //~ ERROR the trait `core::kinds::Send` is not implemented fn main() { } diff --git a/src/test/compile-fail/comm-not-freeze.rs b/src/test/compile-fail/comm-not-freeze.rs index 5820818167cbd..b6277a3e2bd98 100644 --- a/src/test/compile-fail/comm-not-freeze.rs +++ b/src/test/compile-fail/comm-not-freeze.rs @@ -11,7 +11,7 @@ fn test() {} fn main() { - test::>(); //~ ERROR: does not fulfill `Sync` - test::>(); //~ ERROR: does not fulfill `Sync` - test::>(); //~ ERROR: does not fulfill `Sync` + test::>(); //~ ERROR: `core::kinds::Sync` is not implemented + test::>(); //~ ERROR: `core::kinds::Sync` is not implemented + test::>(); //~ ERROR: `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/conflicting-implementations-aux.rs b/src/test/compile-fail/conflicting-implementations-aux.rs index 6c7722bbd254d..c1aa6ccd9bde6 100644 --- a/src/test/compile-fail/conflicting-implementations-aux.rs +++ b/src/test/compile-fail/conflicting-implementations-aux.rs @@ -15,10 +15,7 @@ extern crate trait_impl_conflict; use trait_impl_conflict::Foo; -impl Foo for A { -//~^ ERROR conflicting implementations for trait `trait_impl_conflict::Foo` -//~^^ ERROR cannot provide an extension implementation where both trait and type -// are not defined in this crate +impl Foo for A { //~ ERROR E0117 } fn main() { diff --git a/src/test/compile-fail/conflicting-implementations.rs b/src/test/compile-fail/conflicting-implementations.rs index 598da145b9283..b5a04491111bf 100644 --- a/src/test/compile-fail/conflicting-implementations.rs +++ b/src/test/compile-fail/conflicting-implementations.rs @@ -8,15 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: conflicting implementations for trait `Foo` trait Foo { } -impl Foo for int { +impl Foo for int { //~ ERROR conflicting implementations } -impl Foo for A { +impl Foo for A { //~ NOTE conflicting implementation here } diff --git a/src/test/compile-fail/deriving-span-Default-struct.rs b/src/test/compile-fail/deriving-span-Default-struct.rs index 90d567bfd5da9..1da88f2e2577e 100644 --- a/src/test/compile-fail/deriving-span-Default-struct.rs +++ b/src/test/compile-fail/deriving-span-Default-struct.rs @@ -18,7 +18,7 @@ struct Error; #[deriving(Default)] struct Struct { - x: Error //~ ERROR + x: Error //~ ERROR `core::default::Default` is not implemented } fn main() {} diff --git a/src/test/compile-fail/deriving-span-Zero-struct.rs b/src/test/compile-fail/deriving-span-Zero-struct.rs index fec1b3ed492f6..fb7759c6032e8 100644 --- a/src/test/compile-fail/deriving-span-Zero-struct.rs +++ b/src/test/compile-fail/deriving-span-Zero-struct.rs @@ -16,11 +16,9 @@ extern crate rand; struct Error; -#[deriving(Zero)] //~ ERROR failed to find an implementation +#[deriving(Zero)] //~ ERROR not implemented struct Struct { - x: Error //~ ERROR failed to find an implementation - //~^ ERROR failed to find an implementation - //~^^ ERROR type `Error` does not implement any method in scope + x: Error } fn main() {} diff --git a/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs b/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs index 0661e5ee8b285..193e4b5c6b2d5 100644 --- a/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs +++ b/src/test/compile-fail/deriving-span-Zero-tuple-struct.rs @@ -16,11 +16,9 @@ extern crate rand; struct Error; -#[deriving(Zero)] //~ ERROR failed to find an implementation +#[deriving(Zero)] //~ ERROR not implemented struct Struct( - Error //~ ERROR - //~^ ERROR failed to find an implementation - //~^^ ERROR type `Error` does not implement any method in scope + Error ); fn main() {} diff --git a/src/test/compile-fail/drop-on-non-struct.rs b/src/test/compile-fail/drop-on-non-struct.rs index af4c12c754b96..8304afa1141ee 100644 --- a/src/test/compile-fail/drop-on-non-struct.rs +++ b/src/test/compile-fail/drop-on-non-struct.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - - -type Foo = Vec; - -impl Drop for Foo { -//~^ ERROR cannot provide an extension implementation +impl Drop for int { + //~^ ERROR the Drop trait may only be implemented on structures + //~^^ ERROR cannot provide an extension implementation fn drop(&mut self) { println!("kaboom"); } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index 76becdc855dcd..112a424427a86 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -42,6 +42,6 @@ pub fn main() { // Assignment. let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = box Bar1 {f: 36}; - f5.ptr = *z; //~ ERROR dynamically sized type on lhs of assignment - //~^ ERROR E0161 + f5.ptr = *z; + //~^ ERROR the trait `core::kinds::Sized` is not implemented } diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index 17149941a7e1a..f18f4a36640c9 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -43,4 +43,5 @@ pub fn main() { let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; let z: Box = box Bar1 {f: 36}; f5.ptr = Bar1 {f: 36}; //~ ERROR mismatched types: expected `ToBar`, found `Bar1` + //~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `ToBar` } diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs index a609740eaebf5..4247f91a4fc53 100644 --- a/src/test/compile-fail/dst-bad-coerce1.rs +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -28,5 +28,5 @@ pub fn main() { let f1 = Fat { ptr: Foo }; let f2: &Fat = &f1; let f3: &Fat = f2; - //~^ ERROR failed to find an implementation of trait Bar for Foo + //~^ ERROR the trait `Bar` is not implemented for the type `Foo` } diff --git a/src/test/compile-fail/dst-bad-coerce2.rs b/src/test/compile-fail/dst-bad-coerce2.rs index 118e4ce7e0834..e1a754b633208 100644 --- a/src/test/compile-fail/dst-bad-coerce2.rs +++ b/src/test/compile-fail/dst-bad-coerce2.rs @@ -22,10 +22,10 @@ pub fn main() { // With a vec of ints. let f1 = Fat { ptr: [1, 2, 3] }; let f2: &Fat<[int, ..3]> = &f1; - let f3: &mut Fat<[int]> = f2; //~ ERROR cannot borrow immutable dereference + let f3: &mut Fat<[int]> = f2; //~ ERROR mismatched types // With a trait. let f1 = Fat { ptr: Foo }; let f2: &Fat = &f1; - let f3: &mut Fat = f2; //~ ERROR cannot borrow immutable dereference + let f3: &mut Fat = f2; //~ ERROR mismatched types } diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index cc5d3b520f95c..c3a814e3f44ff 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -30,10 +30,9 @@ pub fn main() { let y: &T = x; //~ ERROR mismatched types // Test that we cannot convert an immutable ptr to a mutable one using *-ptrs - let x: &mut T = &S; //~ ERROR types differ in mutability - let x: *mut T = &S; //~ ERROR types differ in mutability - let x: *mut S = &S; - //~^ ERROR mismatched types + let x: &mut T = &S; //~ ERROR mismatched types + let x: *mut T = &S; //~ ERROR mismatched types + let x: *mut S = &S; //~ ERROR mismatched types // The below four sets of tests test that we cannot implicitly deref a *-ptr // during a coercion. diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs index e2e387e1a48f4..506322d41f531 100644 --- a/src/test/compile-fail/dst-bad-deep.rs +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -21,6 +21,5 @@ pub fn main() { let f: Fat<[int, ..3]> = Fat { ptr: [5i, 6, 7] }; let g: &Fat<[int]> = &f; let h: &Fat> = &Fat { ptr: *g }; - //~^ ERROR trying to initialise a dynamically sized struct - //~^^ ERROR E0161 + //~^ ERROR the trait `core::kinds::Sized` is not implemented } diff --git a/src/test/compile-fail/dst-sized-trait-param.rs b/src/test/compile-fail/dst-sized-trait-param.rs new file mode 100644 index 0000000000000..750b475adb2bb --- /dev/null +++ b/src/test/compile-fail/dst-sized-trait-param.rs @@ -0,0 +1,23 @@ +// Copyright 2014 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. + +// Check that when you implement a trait that has a sized type +// parameter, the corresponding value must be sized. Also that the +// self type must be sized if appropriate. + +trait Foo { fn take(self, x: &T) { } } // Note: T is sized + +impl Foo<[int]> for uint { } +//~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `[int]` + +impl Foo for [uint] { } +//~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `[uint]` + +pub fn main() { } diff --git a/src/test/compile-fail/error-should-say-copy-not-pod.rs b/src/test/compile-fail/error-should-say-copy-not-pod.rs index 9186dada780c0..3d25c7ee772f6 100644 --- a/src/test/compile-fail/error-should-say-copy-not-pod.rs +++ b/src/test/compile-fail/error-should-say-copy-not-pod.rs @@ -13,5 +13,5 @@ fn check_bound(_: T) {} fn main() { - check_bound("nocopy".to_string()); //~ ERROR does not fulfill `Copy` + check_bound("nocopy".to_string()); //~ ERROR the trait `core::kinds::Copy` is not implemented } diff --git a/src/test/compile-fail/ifmt-unimpl.rs b/src/test/compile-fail/ifmt-unimpl.rs index 897717971bc17..194047ce848f6 100644 --- a/src/test/compile-fail/ifmt-unimpl.rs +++ b/src/test/compile-fail/ifmt-unimpl.rs @@ -10,5 +10,5 @@ fn main() { format!("{:d}", "3"); - //~^ ERROR: failed to find an implementation of trait core::fmt::Signed + //~^ ERROR: the trait `core::fmt::Signed` is not implemented } diff --git a/src/test/compile-fail/impl-bounds-checking.rs b/src/test/compile-fail/impl-bounds-checking.rs index 00c415a860d4f..69a35bcbd7b11 100644 --- a/src/test/compile-fail/impl-bounds-checking.rs +++ b/src/test/compile-fail/impl-bounds-checking.rs @@ -17,7 +17,7 @@ trait Getter { fn get(&self) -> T; } -impl Getter for int { //~ ERROR failed to find an implementation of trait Clone2 for int +impl Getter for int { //~ ERROR the trait `Clone2` is not implemented fn get(&self) -> int { *self } } diff --git a/src/test/compile-fail/issue-14915.rs b/src/test/compile-fail/issue-14915.rs index 3754d669be6a2..75b9626a6596f 100644 --- a/src/test/compile-fail/issue-14915.rs +++ b/src/test/compile-fail/issue-14915.rs @@ -15,8 +15,8 @@ fn main() { let y: Gc = box (GC) 0; println!("{}", x + 1); //~ ERROR binary operation `+` cannot be applied to type `Box` - //~^ ERROR cannot determine a type for this bounded type parameter: unconstrained type + //~^ ERROR unable to infer enough type information println!("{}", y + 1); //~^ ERROR binary operation `+` cannot be applied to type `Gc` - //~^^ ERROR cannot determine a type for this bounded type parameter: unconstrained type + //~^^ ERROR unable to infer enough type information } diff --git a/src/test/compile-fail/issue-3907-2.rs b/src/test/compile-fail/issue-3907-2.rs index 71f91050256ed..981abf6cc23d8 100644 --- a/src/test/compile-fail/issue-3907-2.rs +++ b/src/test/compile-fail/issue-3907-2.rs @@ -17,6 +17,6 @@ struct S { name: int } -fn bar(_x: Foo) {} //~ ERROR variable `_x` has dynamically sized type +fn bar(_x: Foo) {} //~ ERROR the trait `core::kinds::Sized` is not implemented fn main() {} diff --git a/src/test/compile-fail/issue-5035-2.rs b/src/test/compile-fail/issue-5035-2.rs index 0251a06c5bd39..d0830ff8e4d76 100644 --- a/src/test/compile-fail/issue-5035-2.rs +++ b/src/test/compile-fail/issue-5035-2.rs @@ -11,6 +11,6 @@ trait I {} type K = I+'static; -fn foo(_x: K) {} //~ ERROR: variable `_x` has dynamically sized type +fn foo(_x: K) {} //~ ERROR: the trait `core::kinds::Sized` is not implemented fn main() {} diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 7ea282c599f51..71b1bcd69da33 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -15,10 +15,9 @@ struct Struct { } fn new_struct(r: A+'static) -> Struct { - //~^ ERROR variable `r` has dynamically sized type - Struct { r: r } //~ ERROR trying to initialise a dynamically sized struct - //~^ ERROR E0161 - //~^^ ERROR E0161 + //~^ ERROR the trait `core::kinds::Sized` is not implemented + Struct { r: r } + //~^ ERROR the trait `core::kinds::Sized` is not implemented } trait Curve {} diff --git a/src/test/compile-fail/issue-6458-2.rs b/src/test/compile-fail/issue-6458-2.rs index f302472d070bd..701bee85fd732 100644 --- a/src/test/compile-fail/issue-6458-2.rs +++ b/src/test/compile-fail/issue-6458-2.rs @@ -11,5 +11,6 @@ extern crate debug; fn main() { - format!("{:?}", None); //~ ERROR: cannot determine a type for this bounded + // Unconstrained type: + format!("{:?}", None); //~ ERROR: E0101 } diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index ef585998aa5a5..3d16ff0a3fac9 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -32,10 +32,5 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR cannot pack type `Box`, which does not fulfill `Send`, as a trait bounded by Send - let v = Rc::new(RefCell::new(a)); - let w = v.clone(); - let b = &*v; - let mut b = b.borrow_mut(); - b.v.set(w.clone()); + //~^ ERROR the trait `core::kinds::Send` is not implemented for the type `B` } diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs index 2ca171ed99837..3524d11d1842a 100644 --- a/src/test/compile-fail/kindck-copy.rs +++ b/src/test/compile-fail/kindck-copy.rs @@ -34,14 +34,14 @@ fn test<'a,T,U:Copy>(_: &'a int) { assert_copy::<&'a [int]>(); // ...unless they are mutable - assert_copy::<&'static mut int>(); //~ ERROR does not fulfill - assert_copy::<&'a mut int>(); //~ ERROR does not fulfill + assert_copy::<&'static mut int>(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::<&'a mut int>(); //~ ERROR `core::kinds::Copy` is not implemented // ~ pointers are not ok - assert_copy::>(); //~ ERROR does not fulfill - assert_copy::(); //~ ERROR does not fulfill - assert_copy:: >(); //~ ERROR does not fulfill - assert_copy::>(); //~ ERROR does not fulfill + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy:: >(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented // borrowed object types are generally ok assert_copy::<&'a Dummy>(); @@ -49,14 +49,14 @@ fn test<'a,T,U:Copy>(_: &'a int) { assert_copy::<&'static Dummy+Copy>(); // owned object types are not ok - assert_copy::>(); //~ ERROR does not fulfill - assert_copy::>(); //~ ERROR does not fulfill + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented // mutable object types are not ok - assert_copy::<&'a mut Dummy+Copy>(); //~ ERROR does not fulfill + assert_copy::<&'a mut Dummy+Copy>(); //~ ERROR `core::kinds::Copy` is not implemented // closures are like an `&mut` object - assert_copy::<||>(); //~ ERROR does not fulfill + assert_copy::<||>(); //~ ERROR `core::kinds::Copy` is not implemented // unsafe ptrs are ok assert_copy::<*const int>(); @@ -74,11 +74,11 @@ fn test<'a,T,U:Copy>(_: &'a int) { assert_copy::(); // structs containing non-POD are not ok - assert_copy::(); //~ ERROR does not fulfill + assert_copy::(); //~ ERROR `core::kinds::Copy` is not implemented // managed or ref counted types are not ok - assert_copy::>(); //~ ERROR does not fulfill - assert_copy::>(); //~ ERROR does not fulfill + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented + assert_copy::>(); //~ ERROR `core::kinds::Copy` is not implemented } pub fn main() { diff --git a/src/test/compile-fail/kindck-impl-type-params-2.rs b/src/test/compile-fail/kindck-impl-type-params-2.rs index a034e252d31dc..6b25289567b27 100644 --- a/src/test/compile-fail/kindck-impl-type-params-2.rs +++ b/src/test/compile-fail/kindck-impl-type-params-2.rs @@ -19,5 +19,5 @@ fn take_param(foo: &T) { } fn main() { let x = box 3i; take_param(&x); - //~^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR the trait `core::kinds::Copy` is not implemented } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index 4cc03ee3dcd44..c92887965c0d2 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -20,20 +20,22 @@ 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` + //~^ ERROR the trait `core::kinds::Send` is not implemented + //~^^ ERROR the trait `core::kinds::Copy` is not implemented let a: &Gettable = &t; - //~^ ERROR instantiating a type parameter with an incompatible type `T` + //~^ ERROR the trait `core::kinds::Send` is not implemented + //~^^ ERROR the trait `core::kinds::Copy` is not implemented } -fn main() { - let t: S<&int> = S; - let a = &t as &Gettable<&int>; - //~^ ERROR instantiating a type parameter with an incompatible type +fn foo<'a>() { + let t: S<&'a int> = S; + let a = &t as &Gettable<&'a int>; let t: Box> = box S; let a = t as Box>; - //~^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR the trait `core::kinds::Copy` is not implemented let t: Box> = box S; let a: Box> = t; - //~^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR the trait `core::kinds::Copy` is not implemented } +fn main() { } diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index 2520ed215d55e..51ee38d5cfed2 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -23,8 +23,8 @@ fn take_param(foo: &T) { } fn main() { let x = box 3i; - take_param(&x); //~ ERROR does not fulfill `Copy` + take_param(&x); //~ ERROR `core::kinds::Copy` is not implemented let y = &x; - let z = &x as &Foo; //~ ERROR does not fulfill `Copy` + let z = &x as &Foo; //~ ERROR `core::kinds::Copy` is not implemented } diff --git a/src/test/compile-fail/kindck-proc-bounds.rs b/src/test/compile-fail/kindck-proc-bounds.rs index 57c8cc3da8aab..d87d1a33ca131 100644 --- a/src/test/compile-fail/kindck-proc-bounds.rs +++ b/src/test/compile-fail/kindck-proc-bounds.rs @@ -13,10 +13,10 @@ fn is_freeze() {} fn foo<'a>() { is_send::(); - //~^ ERROR: instantiating a type parameter with an incompatible type + //~^ ERROR: the trait `core::kinds::Send` is not implemented is_freeze::(); - //~^ ERROR: instantiating a type parameter with an incompatible type + //~^ ERROR: the trait `core::kinds::Sync` is not implemented } fn main() { } diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs index 99519263923be..9217d05002d88 100644 --- a/src/test/compile-fail/kindck-send-object.rs +++ b/src/test/compile-fail/kindck-send-object.rs @@ -19,19 +19,20 @@ trait Message : Send { } // careful with object types, who knows what they close over... fn object_ref_with_static_bound_not_ok() { - assert_send::<&'static Dummy+'static>(); //~ ERROR does not fulfill + assert_send::<&'static Dummy+'static>(); + //~^ ERROR the trait `core::kinds::Send` is not implemented } fn box_object_with_no_bound_not_ok<'a>() { - assert_send::>(); //~ ERROR does not fulfill + assert_send::>(); //~ ERROR the trait `core::kinds::Send` is not implemented } fn proc_with_no_bound_not_ok<'a>() { - assert_send::(); //~ ERROR does not fulfill + assert_send::(); //~ ERROR the trait `core::kinds::Send` is not implemented } fn closure_with_no_bound_not_ok<'a>() { - assert_send::<||:'static>(); //~ ERROR does not fulfill + assert_send::<||:'static>(); //~ ERROR the trait `core::kinds::Send` is not implemented } fn object_with_send_bound_ok() { diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs index 6a90fd5535604..9b0991e9ac6de 100644 --- a/src/test/compile-fail/kindck-send-object1.rs +++ b/src/test/compile-fail/kindck-send-object1.rs @@ -18,6 +18,7 @@ trait Dummy { } // careful with object types, who knows what they close over... fn test51<'a>() { assert_send::<&'a Dummy>(); //~ ERROR does not fulfill the required lifetime + //~^ ERROR the trait `core::kinds::Send` is not implemented } fn test52<'a>() { assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill the required lifetime @@ -35,10 +36,12 @@ fn test61() { // them not ok fn test_70<'a>() { assert_send::(); //~ ERROR does not fulfill the required lifetime + //~^ ERROR the trait `core::kinds::Send` is not implemented } fn test_71<'a>() { assert_send::>(); //~ ERROR does not fulfill the required lifetime + //~^ ERROR the trait `core::kinds::Send` is not implemented } fn main() { } diff --git a/src/test/compile-fail/kindck-send-object2.rs b/src/test/compile-fail/kindck-send-object2.rs index 75006477837c2..d46c6e68c05c2 100644 --- a/src/test/compile-fail/kindck-send-object2.rs +++ b/src/test/compile-fail/kindck-send-object2.rs @@ -14,11 +14,11 @@ fn assert_send() { } trait Dummy { } fn test50() { - assert_send::<&'static Dummy>(); //~ ERROR does not fulfill `Send` + assert_send::<&'static Dummy>(); //~ ERROR the trait `core::kinds::Send` is not implemented } fn test53() { - assert_send::>(); //~ ERROR does not fulfill `Send` + assert_send::>(); //~ ERROR the trait `core::kinds::Send` is not implemented } // ...unless they are properly bounded diff --git a/src/test/compile-fail/kindck-send-unsafe.rs~rust-lang_master b/src/test/compile-fail/kindck-send-unsafe.rs~rust-lang_master new file mode 100644 index 0000000000000..a9bbfcfa26263 --- /dev/null +++ b/src/test/compile-fail/kindck-send-unsafe.rs~rust-lang_master @@ -0,0 +1,22 @@ +// Copyright 2014 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. + +fn assert_send() { } + +// unsafe ptrs are ok unless they point at unsendable things +fn test70() { + assert_send::<*mut int>(); +} +fn test71<'a>() { + assert_send::<*mut &'a int>(); //~ ERROR does not fulfill the required lifetime +} + +fn main() { +} diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index 9a974e595d3c1..cbe391324794f 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -18,6 +18,5 @@ fn main() { let x: Box> = box HashMap::new(); let x: Box> = x; let y: Box> = box x; - //~^ ERROR failed to find an implementation of trait collections::Map - //~^^ ERROR failed to find an implementation of trait core::collections::Collection + //~^ ERROR the trait `collections::Map` is not implemented } diff --git a/src/test/compile-fail/marker-no-copy.rs b/src/test/compile-fail/marker-no-copy.rs index 5a7cddc250a16..d620c13cc2520 100644 --- a/src/test/compile-fail/marker-no-copy.rs +++ b/src/test/compile-fail/marker-no-copy.rs @@ -14,5 +14,5 @@ fn foo(p: P) { } fn main() { - foo(marker::NoCopy); //~ ERROR does not fulfill + foo(marker::NoCopy); //~ ERROR the trait `core::kinds::Copy` is not implemented } diff --git a/src/test/compile-fail/marker-no-send.rs b/src/test/compile-fail/marker-no-send.rs index 101959035eb9b..813e2548398b5 100644 --- a/src/test/compile-fail/marker-no-send.rs +++ b/src/test/compile-fail/marker-no-send.rs @@ -14,5 +14,5 @@ fn foo(p: P) { } fn main() { - foo(marker::NoSend); //~ ERROR does not fulfill `Send` + foo(marker::NoSend); //~ ERROR the trait `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/marker-no-share.rs b/src/test/compile-fail/marker-no-share.rs index 25fe95b80c42c..735e61fa139f0 100644 --- a/src/test/compile-fail/marker-no-share.rs +++ b/src/test/compile-fail/marker-no-share.rs @@ -14,5 +14,5 @@ fn foo(p: P) { } fn main() { - foo(marker::NoSync); //~ ERROR does not fulfill `Sync` + foo(marker::NoSync); //~ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/mut-not-freeze.rs b/src/test/compile-fail/mut-not-freeze.rs index a5b6acc447f84..60921c041356f 100644 --- a/src/test/compile-fail/mut-not-freeze.rs +++ b/src/test/compile-fail/mut-not-freeze.rs @@ -14,5 +14,5 @@ fn f(_: T) {} fn main() { let x = RefCell::new(0i); - f(x); //~ ERROR: which does not fulfill `Sync` + f(x); //~ ERROR `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/mutable-enum-indirect.rs b/src/test/compile-fail/mutable-enum-indirect.rs index 9d4c35baea38b..96937524ad513 100644 --- a/src/test/compile-fail/mutable-enum-indirect.rs +++ b/src/test/compile-fail/mutable-enum-indirect.rs @@ -19,5 +19,5 @@ fn bar(_: T) {} fn main() { let x = A(marker::NoSync); - bar(&x); //~ ERROR type parameter with an incompatible type + bar(&x); //~ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/no-send-res-ports.rs b/src/test/compile-fail/no-send-res-ports.rs index 5b688c6156ab7..f58350cf0934f 100644 --- a/src/test/compile-fail/no-send-res-ports.rs +++ b/src/test/compile-fail/no-send-res-ports.rs @@ -36,7 +36,8 @@ fn main() { let x = foo(Port(box(GC) ())); task::spawn(proc() { - let y = x; //~ ERROR does not fulfill `Send` + let y = x; + //~^ ERROR does not fulfill `Send` println!("{:?}", y); }); } diff --git a/src/test/compile-fail/no_send-enum.rs b/src/test/compile-fail/no_send-enum.rs index 4395151cbc157..2235a265bba16 100644 --- a/src/test/compile-fail/no_send-enum.rs +++ b/src/test/compile-fail/no_send-enum.rs @@ -19,6 +19,5 @@ fn bar(_: T) {} fn main() { let x = A(marker::NoSend); bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `Foo`, - // which does not fulfill `Send` + //~^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs index 291340e55b856..c05b17afe1d27 100644 --- a/src/test/compile-fail/no_send-rc.rs +++ b/src/test/compile-fail/no_send-rc.rs @@ -15,6 +15,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(5i); bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `alloc::rc::Rc`, - // which does not fulfill `Send` + //~^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/no_send-struct.rs b/src/test/compile-fail/no_send-struct.rs index 5b083374c51e6..6e84578e92e3b 100644 --- a/src/test/compile-fail/no_send-struct.rs +++ b/src/test/compile-fail/no_send-struct.rs @@ -20,6 +20,5 @@ fn bar(_: T) {} fn main() { let x = Foo { a: 5, ns: marker::NoSend }; bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `Foo`, - // which does not fulfill `Send` + //~^ ERROR the trait `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/no_share-enum.rs b/src/test/compile-fail/no_share-enum.rs index f96d751af7e9d..1a692dab6d490 100644 --- a/src/test/compile-fail/no_share-enum.rs +++ b/src/test/compile-fail/no_share-enum.rs @@ -17,6 +17,5 @@ fn bar(_: T) {} fn main() { let x = A(marker::NoSync); bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `Foo`, - // which does not fulfill `Sync` + //~^ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/no_share-rc.rs b/src/test/compile-fail/no_share-rc.rs index 7a840674be6f0..5572f72d8fe83 100644 --- a/src/test/compile-fail/no_share-rc.rs +++ b/src/test/compile-fail/no_share-rc.rs @@ -16,6 +16,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(RefCell::new(5i)); bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type - // `std::rc::Rc>`, which does not fulfill `Sync` + //~^ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/no_share-struct.rs b/src/test/compile-fail/no_share-struct.rs index 6b87a5fa09c98..1379a9f7382b0 100644 --- a/src/test/compile-fail/no_share-struct.rs +++ b/src/test/compile-fail/no_share-struct.rs @@ -17,6 +17,5 @@ fn bar(_: T) {} fn main() { let x = Foo { a: 5, m: marker::NoSync }; bar(x); - //~^ ERROR instantiating a type parameter with an incompatible type `Foo`, - // which does not fulfill `Sync` + //~^ ERROR the trait `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/object-does-not-impl-trait.rs b/src/test/compile-fail/object-does-not-impl-trait.rs index 0cbdb87d56c54..cfaf149a49cac 100644 --- a/src/test/compile-fail/object-does-not-impl-trait.rs +++ b/src/test/compile-fail/object-does-not-impl-trait.rs @@ -14,6 +14,6 @@ trait Foo {} fn take_foo(f: F) {} -fn take_object(f: Box) { take_foo(f); } //~ ERROR failed to find an implementation of trait -//~^ ERROR failed to find an implementation +fn take_object(f: Box) { take_foo(f); } +//~^ ERROR the trait `Foo` is not implemented fn main() {} diff --git a/src/test/compile-fail/pinned-deep-copy.rs b/src/test/compile-fail/pinned-deep-copy.rs index e62f5fe1a4daf..0e8bb40e0ffee 100644 --- a/src/test/compile-fail/pinned-deep-copy.rs +++ b/src/test/compile-fail/pinned-deep-copy.rs @@ -43,8 +43,7 @@ fn main() { { // Can't do this copy let x = box box box A {y: r(i)}; - let _z = x.clone(); //~ ERROR failed to find an implementation - //~^ ERROR failed to find an implementation + let _z = x.clone(); //~ ERROR not implemented println!("{:?}", x); } println!("{:?}", *i); diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs index 0c9f5004f5787..c6a9f67cfc651 100644 --- a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs +++ b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs @@ -12,8 +12,6 @@ // nominal types (but not on other types) and that they are type // checked. -#![no_std] - struct Inv<'a> { // invariant w/r/t 'a x: &'a mut &'a int } diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs index 3c7ffbc8d1fb1..50190411bf09b 100644 --- a/src/test/compile-fail/regions-bounded-by-send.rs +++ b/src/test/compile-fail/regions-bounded-by-send.rs @@ -58,6 +58,7 @@ fn box_with_region_not_ok<'a>() { fn object_with_random_bound_not_ok<'a>() { assert_send::<&'a Dummy+'a>(); //~ ERROR does not fulfill + //~^ ERROR not implemented } fn object_with_send_bound_not_ok<'a>() { @@ -66,10 +67,12 @@ fn object_with_send_bound_not_ok<'a>() { fn proc_with_lifetime_not_ok<'a>() { assert_send::(); //~ ERROR does not fulfill + //~^ ERROR not implemented } fn closure_with_lifetime_not_ok<'a>() { assert_send::<||:'a>(); //~ ERROR does not fulfill + //~^ ERROR not implemented } // unsafe pointers are ok unless they point at unsendable things diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters.rs b/src/test/compile-fail/regions-bounded-method-type-parameters.rs index ba1993686d5d9..279139d8de96a 100644 --- a/src/test/compile-fail/regions-bounded-method-type-parameters.rs +++ b/src/test/compile-fail/regions-bounded-method-type-parameters.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![no_std] - // Check that explicit region bounds are allowed on the various // nominal types (but not on other types) and that they are type // checked. diff --git a/src/test/compile-fail/regions-escape-via-trait-or-not.rs b/src/test/compile-fail/regions-escape-via-trait-or-not.rs index b73b5e0649ff5..adc960b069d05 100644 --- a/src/test/compile-fail/regions-escape-via-trait-or-not.rs +++ b/src/test/compile-fail/regions-escape-via-trait-or-not.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![no_std] - #![allow(dead_code)] trait Deref { diff --git a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs index a52d2f9f9a0f7..773d6e2c70365 100644 --- a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs +++ b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![no_std] - fn a<'a, 'b:'a>(x: &mut &'a int, y: &mut &'b int) { // Note: this is legal because of the `'b:'a` declaration. *x = *y; diff --git a/src/test/compile-fail/repeat-to-run-dtor-twice.rs b/src/test/compile-fail/repeat-to-run-dtor-twice.rs index 77146b65ae676..8fdf586b3d1de 100644 --- a/src/test/compile-fail/repeat-to-run-dtor-twice.rs +++ b/src/test/compile-fail/repeat-to-run-dtor-twice.rs @@ -24,5 +24,6 @@ impl Drop for Foo { fn main() { let a = Foo { x: 3 }; - let _ = [ a, ..5 ]; //~ ERROR copying a value of non-copyable type + let _ = [ a, ..5 ]; + //~^ ERROR the trait `core::kinds::Copy` is not implemented for the type `Foo` } diff --git a/src/test/compile-fail/task-rng-isnt-sendable.rs b/src/test/compile-fail/task-rng-isnt-sendable.rs index 366e1fd4dcae4..e9997083babd2 100644 --- a/src/test/compile-fail/task-rng-isnt-sendable.rs +++ b/src/test/compile-fail/task-rng-isnt-sendable.rs @@ -16,5 +16,5 @@ fn test_send() {} pub fn main() { test_send::(); - //~^ ERROR: incompatible type `std::rand::TaskRng`, which does not fulfill `Send` + //~^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs index 78b4ab817bfac..85a2761172d61 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -14,7 +14,7 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ERROR variable `_x` has dynamically sized type `Foo+Send` + //~^ERROR the trait `core::kinds::Sized` is not implemented } fn main() { } diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs index 226556dc78fcb..4233fa843eb61 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs @@ -16,12 +16,11 @@ struct Foo { fn main() { let foo = Foo { - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR not implemented x: 3i }; + let baz: Foo = fail!(); - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type + //~^ ERROR not implemented } diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs index 142ead75bcf19..c26cccc8b146c 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-static.rs @@ -15,8 +15,7 @@ struct Foo { } static X: Foo = Foo { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented x: 1, }; diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs index 9be519960b81f..d01f9d59fb437 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc.rs @@ -15,22 +15,11 @@ extern crate trait_bounds_on_structs_and_enums_xc; use trait_bounds_on_structs_and_enums_xc::{Bar, Foo, Trait}; fn explode(x: Foo) {} -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented fn kaboom(y: Bar) {} -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented fn main() { - let foo = Foo { - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type - x: 3i - }; - let bar: Bar = return; - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type - let _ = bar; } diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc1.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc1.rs new file mode 100644 index 0000000000000..d3689067aef71 --- /dev/null +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-xc1.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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. + +// aux-build:trait_bounds_on_structs_and_enums_xc.rs + +extern crate trait_bounds_on_structs_and_enums_xc; + +use trait_bounds_on_structs_and_enums_xc::{Bar, Foo, Trait}; + +fn main() { + let foo = Foo { + //~^ ERROR not implemented + x: 3i + }; + let bar: Bar = return; + //~^ ERROR not implemented + let _ = bar; +} + diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs index ba035dd2c6f19..5fe8e435e6806 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs @@ -20,40 +20,34 @@ enum Bar { CBar(uint), } -fn explode(x: Foo) {} -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +fn explode(x: Foo) {} +//~^ ERROR not implemented fn kaboom(y: Bar) {} -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented -impl Foo { //~ ERROR failed to find an implementation -//~^ ERROR instantiating a type parameter with an incompatible type +impl Foo { +//~^ ERROR the trait `Trait` is not implemented fn uhoh() {} } struct Baz { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented a: Foo, } enum Boo { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented Quux(Bar), } struct Badness { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented b: Foo, } enum MoreBadness { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented EvenMoreBadness(Bar), } @@ -64,15 +58,10 @@ trait PolyTrait { struct Struct; impl PolyTrait> for Struct { -//~^ ERROR failed to find an implementation -//~^^ ERROR instantiating a type parameter with an incompatible type +//~^ ERROR not implemented fn whatever() {} } fn main() { - let bar: Bar = return; - //~^ ERROR failed to find an implementation - //~^^ ERROR instantiating a type parameter with an incompatible type - let _ = bar; } diff --git a/src/test/compile-fail/trait-coercion-generic-bad.rs b/src/test/compile-fail/trait-coercion-generic-bad.rs index 55e5a02cfaebf..74982946d7ddd 100644 --- a/src/test/compile-fail/trait-coercion-generic-bad.rs +++ b/src/test/compile-fail/trait-coercion-generic-bad.rs @@ -25,7 +25,6 @@ impl Trait<&'static str> for Struct { fn main() { let s: Box> = box Struct { person: "Fred" }; - //~^ ERROR expected Trait, found Trait<&'static str> - //~^^ ERROR expected Trait, found Trait<&'static str> + //~^ ERROR type mismatch s.f(1); } diff --git a/src/test/compile-fail/type-params-in-different-spaces-2.rs b/src/test/compile-fail/type-params-in-different-spaces-2.rs index 4143d9d9b849a..580aea651857b 100644 --- a/src/test/compile-fail/type-params-in-different-spaces-2.rs +++ b/src/test/compile-fail/type-params-in-different-spaces-2.rs @@ -15,12 +15,12 @@ trait Tr { // these compile as if Self: Tr, even tho only Self: Tr trait A: Tr { fn test(u: U) -> Self { - Tr::op(u) //~ ERROR expected Tr, found Tr + Tr::op(u) //~ ERROR type mismatch } } trait B: Tr { fn test(u: U) -> Self { - Tr::op(u) //~ ERROR expected Tr, found Tr + Tr::op(u) //~ ERROR type mismatch } } diff --git a/src/test/compile-fail/typeck-unsafe-always-share.rs b/src/test/compile-fail/typeck-unsafe-always-share.rs index 369bd0a15c452..7c74cdc890d85 100644 --- a/src/test/compile-fail/typeck-unsafe-always-share.rs +++ b/src/test/compile-fail/typeck-unsafe-always-share.rs @@ -39,5 +39,5 @@ fn main() { let ns = NoSync{m: marker::NoSync}; test(ns); - //~^ ERROR instantiating a type parameter with an incompatible type `NoSync`, which does not fulfill `Sync` + //~^ ERROR `core::kinds::Sync` is not implemented } diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs index 2ee632b9093c8..a96bde7cca4cd 100644 --- a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs +++ b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs @@ -18,8 +18,7 @@ fn call_it>(y: int, mut f: F) -> int { pub fn main() { let f = |&mut: x: uint, y: int| -> int { (x as int) + y }; - let z = call_it(3, f); //~ ERROR expected core::ops::FnMut - //~^ ERROR expected core::ops::FnMut + let z = call_it(3, f); //~ ERROR type mismatch println!("{}", z); } diff --git a/src/test/compile-fail/unboxed-closures-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-wrong-trait.rs index 50d90c6200e12..27f1da75c3aef 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-trait.rs @@ -17,6 +17,6 @@ fn c int>(f: F) -> int { fn main() { let z: int = 7; assert_eq!(c(|&: x: int, y| x + y + z), 10); - //~^ ERROR failed to find an implementation + //~^ ERROR not implemented } diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs index e5b7bf08715b0..940ca76582802 100644 --- a/src/test/compile-fail/unique-pinned-nocopy.rs +++ b/src/test/compile-fail/unique-pinned-nocopy.rs @@ -20,7 +20,6 @@ impl Drop for r { fn main() { let i = box r { b: true }; - let _j = i.clone(); //~ ERROR failed to find an implementation - //~^ ERROR failed to find an implementation + let _j = i.clone(); //~ ERROR not implemented println!("{:?}", i); } diff --git a/src/test/compile-fail/unique-unique-kind.rs b/src/test/compile-fail/unique-unique-kind.rs index dd0c7953434b6..7d6cdaef85b2f 100644 --- a/src/test/compile-fail/unique-unique-kind.rs +++ b/src/test/compile-fail/unique-unique-kind.rs @@ -16,5 +16,5 @@ fn f(_i: T) { fn main() { let i = box box(GC) 100i; - f(i); //~ ERROR does not fulfill `Send` + f(i); //~ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/unique-vec-res.rs b/src/test/compile-fail/unique-vec-res.rs index dfb04323005f3..54b1fdea7190d 100644 --- a/src/test/compile-fail/unique-vec-res.rs +++ b/src/test/compile-fail/unique-vec-res.rs @@ -36,10 +36,8 @@ fn main() { let r1 = vec!(box r { i: i1 }); let r2 = vec!(box r { i: i2 }); f(r1.clone(), r2.clone()); - //~^ ERROR failed to find an implementation of - //~^^ ERROR failed to find an implementation of - //~^^^ ERROR failed to find an implementation of - //~^^^^ ERROR failed to find an implementation of + //~^ ERROR the trait `core::clone::Clone` is not implemented + //~^^ ERROR the trait `core::clone::Clone` is not implemented println!("{:?}", (r2, i1.get())); println!("{:?}", (r1, i2.get())); } diff --git a/src/test/compile-fail/unsendable-class.rs b/src/test/compile-fail/unsendable-class.rs index 2991a60835da3..c3fea8e86d4f4 100644 --- a/src/test/compile-fail/unsendable-class.rs +++ b/src/test/compile-fail/unsendable-class.rs @@ -28,6 +28,6 @@ fn foo(i:int, j: Gc) -> foo { fn main() { let cat = "kitty".to_string(); - let (tx, _) = channel(); //~ ERROR does not fulfill `Send` - tx.send(foo(42, box(GC) (cat))); //~ ERROR does not fulfill `Send` + let (tx, _) = channel(); //~ ERROR `core::kinds::Send` is not implemented + tx.send(foo(42, box(GC) (cat))); //~ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/compile-fail/unsized-bare-typaram.rs b/src/test/compile-fail/unsized-bare-typaram.rs index 6fd749b129819..7b5d42954117c 100644 --- a/src/test/compile-fail/unsized-bare-typaram.rs +++ b/src/test/compile-fail/unsized-bare-typaram.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: instantiating a type parameter with an incompatible type fn bar() { } -fn foo() { bar::() } +fn foo() { bar::() } //~ ERROR the trait `core::kinds::Sized` is not implemented fn main() { } diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs index 651eb26cadc6f..edef3ae649269 100644 --- a/src/test/compile-fail/unsized-enum.rs +++ b/src/test/compile-fail/unsized-enum.rs @@ -8,7 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: instantiating a type parameter with an incompatible type +enum Foo { FooSome(T), FooNone } + fn bar() { } -fn foo() { bar::>() } +fn foo() { bar::>() } +//~^ ERROR the trait `core::kinds::Sized` is not implemented +//~^^ ERROR the trait `core::kinds::Sized` is not implemented +// +// One error is for T being provided to Foo, the other is +// for Foo being provided to bar. + fn main() { } diff --git a/src/test/compile-fail/unsized-struct.rs b/src/test/compile-fail/unsized-struct.rs index ec6aafb43f46f..58aba1a264648 100644 --- a/src/test/compile-fail/unsized-struct.rs +++ b/src/test/compile-fail/unsized-struct.rs @@ -8,10 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: instantiating a type parameter with an incompatible type - struct Foo { data: T } fn bar() { } fn foo() { bar::>() } +//~^ ERROR the trait `core::kinds::Sized` is not implemented +//~^^ ERROR the trait `core::kinds::Sized` is not implemented +// One error is for the T in Foo, the other is for Foo as a value +// for bar's type parameter. + fn main() { } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index f71afeb1b308f..fba1237340fe5 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test sized-ness checking in substitution. +// Test sized-ness checking in substitution within fn bodies.. // Unbounded. fn f1(x: &X) { - f2::(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n + f2::(x); + //~^ ERROR the trait `core::kinds::Sized` is not implemented } fn f2(x: &X) { } @@ -21,7 +22,8 @@ fn f2(x: &X) { // Bounded. trait T for Sized? {} fn f3(x: &X) { - f4::(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n + f4::(x); + //~^ ERROR the trait `core::kinds::Sized` is not implemented } fn f4(x: &X) { } @@ -34,7 +36,8 @@ enum E { fn f5(x: &Y) {} fn f6(x: &X) {} fn f7(x1: &E, x2: &E) { - f5(x1); //~ERROR instantiating a type parameter with an incompatible type `E`, which does not + f5(x1); + //~^ ERROR the trait `core::kinds::Sized` is not implemented f6(x2); // ok } @@ -45,40 +48,18 @@ struct S { } fn f8(x1: &S, x2: &S) { - f5(x1); //~ERROR instantiating a type parameter with an incompatible type `S`, which does not + f5(x1); + //~^ ERROR the trait `core::kinds::Sized` is not implemented f6(x2); // ok } // Test some tuples. fn f9(x1: Box>, x2: Box>) { - f5(&(*x1, 34i)); //~ERROR E0161 - //~^ ERROR instantiating a type parameter with an incompatible type - f5(&(32i, *x2)); //~ERROR E0161 - //~^ ERROR instantiating a type parameter with an incompatible type + f5(&(*x1, 34i)); + //~^ ERROR the trait `core::kinds::Sized` is not implemented + f5(&(32i, *x2)); + //~^ ERROR the trait `core::kinds::Sized` is not implemented } -// impl - bounded -trait T1 { -} -struct S3; -impl T1 for S3 { //~ ERROR instantiating a type parameter with an incompatible -} - -// impl - unbounded -trait T2 { -} -impl T2 for S3 { //~ ERROR instantiating a type parameter with an incompatible type -} - -// impl - struct -trait T3 { -} -struct S4; -impl T3 for S4 { //~ ERROR instantiating a type parameter with an incompatible type -} -impl S4 { //~ ERROR instantiating a type parameter with an incompatible type -} - - pub fn main() { } diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 6618cce0214f4..0efd178f75b8c 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -14,33 +14,29 @@ trait T for Sized? {} fn f1(x: &X) { - let _: X; //~ERROR variable `_` has dynamically sized type `X` - let _: (int, (X, int)); //~ERROR variable `_` has dynamically sized type `(int,(X,int))` - let y: X; //~ERROR variable `y` has dynamically sized type `X` - let y: (int, (X, int)); //~ERROR variable `y` has dynamically sized type `(int,(X,int))` + let _: X; // <-- this is OK, no bindings created, no initializer. + let _: (int, (X, int)); // same + let y: X; //~ERROR the trait `core::kinds::Sized` is not implemented + let y: (int, (X, int)); //~ERROR the trait `core::kinds::Sized` is not implemented } fn f2(x: &X) { - let _: X; //~ERROR variable `_` has dynamically sized type `X` - let _: (int, (X, int)); //~ERROR variable `_` has dynamically sized type `(int,(X,int))` - let y: X; //~ERROR variable `y` has dynamically sized type `X` - let y: (int, (X, int)); //~ERROR variable `y` has dynamically sized type `(int,(X,int))` + let y: X; //~ERROR the trait `core::kinds::Sized` is not implemented + let y: (int, (X, int)); //~ERROR the trait `core::kinds::Sized` is not implemented } fn f3(x1: Box, x2: Box, x3: Box) { - let y: X = *x1; //~ERROR variable `y` has dynamically sized type `X` - let y = *x2; //~ERROR variable `y` has dynamically sized type `X` - let (y, z) = (*x3, 4i); //~ERROR variable `y` has dynamically sized type `X` - //~^ ERROR E0161 + let y: X = *x1; //~ERROR the trait `core::kinds::Sized` is not implemented + let y = *x2; //~ERROR the trait `core::kinds::Sized` is not implemented + let (y, z) = (*x3, 4i); //~ERROR the trait `core::kinds::Sized` is not implemented } fn f4(x1: Box, x2: Box, x3: Box) { - let y: X = *x1; //~ERROR variable `y` has dynamically sized type `X` - let y = *x2; //~ERROR variable `y` has dynamically sized type `X` - let (y, z) = (*x3, 4i); //~ERROR variable `y` has dynamically sized type `X` - //~^ ERROR E0161 + let y: X = *x1; //~ERROR the trait `core::kinds::Sized` is not implemented + let y = *x2; //~ERROR the trait `core::kinds::Sized` is not implemented + let (y, z) = (*x3, 4i); //~ERROR the trait `core::kinds::Sized` is not implemented } -fn g1(x: X) {} //~ERROR variable `x` has dynamically sized type `X` -fn g2(x: X) {} //~ERROR variable `x` has dynamically sized type `X` +fn g1(x: X) {} //~ERROR the trait `core::kinds::Sized` is not implemented +fn g2(x: X) {} //~ERROR the trait `core::kinds::Sized` is not implemented pub fn main() { } diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs new file mode 100644 index 0000000000000..fd9dffe00d2d5 --- /dev/null +++ b/src/test/compile-fail/unsized7.rs @@ -0,0 +1,43 @@ +// Copyright 2014 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. + +// Test sized-ness checking in substitution in impls. + +trait T for Sized? {} + +// I would like these to fail eventually. +// impl - bounded +trait T1 { +} +struct S3; +impl T1 for S3 { + //~^ ERROR `core::kinds::Sized` is not implemented for the type `X` +} + +// impl - unbounded +trait T2 { +} +struct S4; +impl T2 for S4 { + //~^ ERROR `core::kinds::Sized` is not implemented for the type `X` +} + +// impl - struct +trait T3 { +} +struct S5; +impl T3 for S5 { //~ ERROR not implemented +} + +impl S5 { //~ ERROR not implemented +} + + +fn main() { } diff --git a/src/test/compile-fail/vec-res-add.rs b/src/test/compile-fail/vec-res-add.rs index 8da9511b493de..bfd52d69cb217 100644 --- a/src/test/compile-fail/vec-res-add.rs +++ b/src/test/compile-fail/vec-res-add.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: failed to find an implementation - struct r { i:int } @@ -25,5 +23,7 @@ fn main() { let i = vec!(r(0)); let j = vec!(r(1)); let k = i + j; + //~^ ERROR not implemented println!("{}", j); + //~^ ERROR not implemented } diff --git a/src/test/compile-fail/vtable-res-trait-param.rs b/src/test/compile-fail/vtable-res-trait-param.rs index 2baa89d52f28b..12cfe9c20fa9b 100644 --- a/src/test/compile-fail/vtable-res-trait-param.rs +++ b/src/test/compile-fail/vtable-res-trait-param.rs @@ -24,8 +24,7 @@ impl TraitB for int { fn call_it(b: B) -> int { let y = 4u; - b.gimme_an_a(y) //~ ERROR failed to find an implementation of trait TraitA - //~^ ERROR failed to find an implementation of trait TraitA + b.gimme_an_a(y) //~ ERROR the trait `TraitA` is not implemented } fn main() { diff --git a/src/test/compile-fail/where-clauses-unsatisfied.rs b/src/test/compile-fail/where-clauses-unsatisfied.rs index 2324da6b8f422..4a4a5f3193d3a 100644 --- a/src/test/compile-fail/where-clauses-unsatisfied.rs +++ b/src/test/compile-fail/where-clauses-unsatisfied.rs @@ -15,9 +15,6 @@ struct Struct; fn main() { drop(equal(&Struct, &Struct)) - //~^ ERROR failed to find an implementation of trait core::cmp::Eq - //~^^ ERROR failed to find an implementation of trait core::cmp::PartialEq - //~^^^ ERROR failed to find an implementation of trait core::cmp::Eq - //~^^^^ ERROR failed to find an implementation of trait core::cmp::PartialEq + //~^ ERROR the trait `core::cmp::Eq` is not implemented } diff --git a/src/test/run-pass/drop-struct-as-object.rs b/src/test/run-pass/drop-struct-as-object.rs new file mode 100644 index 0000000000000..6d7715ed9a5a0 --- /dev/null +++ b/src/test/run-pass/drop-struct-as-object.rs @@ -0,0 +1,42 @@ +// Copyright 2012-2014 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. + +// Test that destructor on a struct runs successfully after the struct +// is boxed and converted to an object. + +static mut value: uint = 0; + +struct Cat { + name : uint, +} + +trait Dummy { + fn get(&self) -> uint; +} + +impl Dummy for Cat { + fn get(&self) -> uint { self.name } +} + +impl Drop for Cat { + fn drop(&mut self) { + unsafe { value = self.name; } + } +} + +pub fn main() { + { + let x = box Cat {name: 22}; + let nyan: Box = x as Box; + } + unsafe { + assert_eq!(value, 22); + } +} diff --git a/src/test/run-pass/object-one-type-two-traits.rs b/src/test/run-pass/object-one-type-two-traits.rs new file mode 100644 index 0000000000000..f8bc0929bfa80 --- /dev/null +++ b/src/test/run-pass/object-one-type-two-traits.rs @@ -0,0 +1,39 @@ +// Copyright 2014 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. + +// Testing creating two vtables with the same self type, but different +// traits. + +use std::any::Any; +use std::any::AnyRefExt; + +trait Wrap { + fn get(&self) -> int; + fn wrap(self: Box) -> Box; +} + +impl Wrap for int { + fn get(&self) -> int { + *self + } + fn wrap(self: Box) -> Box { + self as Box + } +} + +fn is(x: &Any) -> bool { + x.is::() +} + +fn main() { + let x = box 22i as Box; + println!("x={}", x.get()); + let y = x.wrap(); +}