diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 8f75113c01dbf..4ef2e681992ae 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -762,8 +762,8 @@ mod test { expected: &'b [int], } - impl<'a, 'b> FnMut(&int) -> bool for Counter<'a, 'b> { - extern "rust-call" fn call_mut(&mut self, (&x,): (&int,)) -> bool { + impl<'a, 'b, 'c> FnMut(&'c int) -> bool for Counter<'a, 'b> { + extern "rust-call" fn call_mut(&mut self, (&x,): (&'c int,)) -> bool { assert_eq!(x, self.expected[*self.i]); *self.i += 1; true diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 28110cf7b1a37..8fe41c0bd89c2 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -21,6 +21,7 @@ pub use self::Searcher::{Naive, TwoWay, TwoWayLong}; use char::Char; use char; +use clone::Clone; use cmp::{Eq, mod}; use default::Default; use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator}; @@ -31,7 +32,7 @@ use mem; use num::Int; use option::Option; use option::Option::{None, Some}; -use ops::FnMut; +use ops::{Fn, FnMut}; use ptr::RawPtr; use raw::{Repr, Slice}; use slice::{mod, SliceExt}; @@ -316,7 +317,23 @@ impl<'a> DoubleEndedIterator<(uint, char)> for CharOffsets<'a> { /// External iterator for a string's bytes. /// Use with the `std::iter` module. -pub type Bytes<'a> = Map<&'a u8, u8, slice::Items<'a, u8>, fn(&u8) -> u8>; +pub type Bytes<'a> = Map<&'a u8, u8, slice::Items<'a, u8>, BytesFn>; + +/// A temporary new type wrapper that ensures that the `Bytes` iterator +/// is cloneable. +#[deriving(Copy)] +#[experimental = "iterator type instability"] +pub struct BytesFn(fn(&u8) -> u8); + +impl<'a> Fn(&'a u8) -> u8 for BytesFn { + extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 { + (self.0)(ptr) + } +} + +impl Clone for BytesFn { + fn clone(&self) -> BytesFn { *self } +} /// An iterator over the substrings of a string, separated by `sep`. #[deriving(Clone)] @@ -2009,7 +2026,7 @@ impl StrPrelude for str { fn bytes(&self) -> Bytes { fn deref(&x: &u8) -> u8 { x } - self.as_bytes().iter().map(deref) + self.as_bytes().iter().map(BytesFn(deref)) } #[inline] diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 8c25bc702b336..f6fd9f60e5c3f 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1784,9 +1784,7 @@ impl LintPass for Stability { method_num: index, .. }) => { - ty::trait_item(cx.tcx, - trait_ref.def_id, - index).def_id() + ty::trait_item(cx.tcx, trait_ref.def_id, index).def_id() } } } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index b78112f1f7850..7f1df80da3c8f 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -704,7 +704,7 @@ pub fn get_enum_variants<'tcx>(intr: Rc, cdata: Cmd, id: ast::Nod let name = item_name(&*intr, item); let (ctor_ty, arg_tys, arg_names) = match ctor_ty.sty { ty::ty_bare_fn(ref f) => - (Some(ctor_ty), f.sig.inputs.clone(), None), + (Some(ctor_ty), f.sig.0.inputs.clone(), None), _ => { // Nullary or struct enum variant. let mut arg_names = Vec::new(); let arg_tys = get_struct_fields(intr.clone(), cdata, did.node) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index d649c6491314c..f2a41c48d1203 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -21,7 +21,7 @@ pub use self::DefIdSource::*; use middle::region; use middle::subst; use middle::subst::VecPerParamSpace; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, AsPredicate, Ty}; use std::rc::Rc; use std::str; @@ -414,7 +414,7 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> { } 'x' => { assert_eq!(next(st), '['); - let trait_ref = parse_trait_ref(st, |x,y| conv(x,y)); + let trait_ref = ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))); let bounds = parse_existential_bounds(st, |x,y| conv(x,y)); assert_eq!(next(st), ']'); return ty::mk_trait(st.tcx, trait_ref, bounds); @@ -603,7 +603,7 @@ fn parse_bare_fn_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, } } -fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::FnSig<'tcx> { +fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::PolyFnSig<'tcx> { assert_eq!(next(st), '['); let mut inputs = Vec::new(); while peek(st) != ']' { @@ -622,9 +622,9 @@ fn parse_sig<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> ty::FnSig<' } _ => ty::FnConverging(parse_ty(st, |x,y| conv(x,y))) }; - ty::FnSig {inputs: inputs, - output: output, - variadic: variadic} + ty::Binder(ty::FnSig {inputs: inputs, + output: output, + variadic: variadic}) } // Rust metadata parsing @@ -669,13 +669,13 @@ pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>, -> ty::Predicate<'tcx> { match next(st) { - 't' => ty::Predicate::Trait(Rc::new(parse_trait_ref(st, conv))), - 'e' => ty::Predicate::Equate(parse_ty(st, |x,y| conv(x,y)), - parse_ty(st, |x,y| conv(x,y))), - 'r' => ty::Predicate::RegionOutlives(parse_region(st, |x,y| conv(x,y)), - parse_region(st, |x,y| conv(x,y))), - 'o' => ty::Predicate::TypeOutlives(parse_ty(st, |x,y| conv(x,y)), - parse_region(st, |x,y| conv(x,y))), + 't' => Rc::new(ty::Binder(parse_trait_ref(st, conv))).as_predicate(), + 'e' => ty::Binder(ty::EquatePredicate(parse_ty(st, |x,y| conv(x,y)), + parse_ty(st, |x,y| conv(x,y)))).as_predicate(), + 'r' => ty::Binder(ty::OutlivesPredicate(parse_region(st, |x,y| conv(x,y)), + parse_region(st, |x,y| conv(x,y)))).as_predicate(), + 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty(st, |x,y| conv(x,y)), + parse_region(st, |x,y| conv(x,y)))).as_predicate(), c => panic!("Encountered invalid character in metadata: {}", c) } } @@ -759,10 +759,12 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) loop { match next(st) { 'R' => { - param_bounds.region_bounds.push(parse_region(st, |x, y| conv (x, y))); + param_bounds.region_bounds.push( + parse_region(st, |x, y| conv (x, y))); } 'I' => { - param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y)))); + param_bounds.trait_bounds.push( + Rc::new(ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))))); } '.' => { return param_bounds; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 2a057da7db368..5d7d85d4679d7 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -251,7 +251,7 @@ fn enc_sty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { mywrite!(w, "x["); - enc_trait_ref(w, cx, principal); + enc_trait_ref(w, cx, &principal.0); enc_existential_bounds(w, cx, bounds); mywrite!(w, "]"); } @@ -351,18 +351,18 @@ pub fn enc_closure_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, } fn enc_fn_sig<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, - fsig: &ty::FnSig<'tcx>) { + fsig: &ty::PolyFnSig<'tcx>) { mywrite!(w, "["); - for ty in fsig.inputs.iter() { + for ty in fsig.0.inputs.iter() { enc_ty(w, cx, *ty); } mywrite!(w, "]"); - if fsig.variadic { + if fsig.0.variadic { mywrite!(w, "V"); } else { mywrite!(w, "N"); } - match fsig.output { + match fsig.0.output { ty::FnConverging(result_type) => { enc_ty(w, cx, result_type); } @@ -401,7 +401,7 @@ pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, for tp in bs.trait_bounds.iter() { mywrite!(w, "I"); - enc_trait_ref(w, cx, &**tp); + enc_trait_ref(w, cx, &tp.0); } mywrite!(w, "."); @@ -425,19 +425,19 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter, match *p { ty::Predicate::Trait(ref trait_ref) => { mywrite!(w, "t"); - enc_trait_ref(w, cx, &**trait_ref); + enc_trait_ref(w, cx, &trait_ref.0); } - ty::Predicate::Equate(a, b) => { + ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => { mywrite!(w, "e"); enc_ty(w, cx, a); enc_ty(w, cx, b); } - ty::Predicate::RegionOutlives(a, b) => { + ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { mywrite!(w, "r"); enc_region(w, cx, a); enc_region(w, cx, b); } - ty::Predicate::TypeOutlives(a, b) => { + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { mywrite!(w, "o"); enc_ty(w, cx, a); enc_region(w, cx, b); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index a37f9cb939d5e..69fbd59fd9241 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1113,7 +1113,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { this.emit_enum_variant_arg(0, |this| { try!(this.emit_struct_field("principal", 0, |this| { - Ok(this.emit_trait_ref(ecx, &*principal)) + Ok(this.emit_trait_ref(ecx, &principal.0)) })); this.emit_struct_field("bounds", 1, |this| { Ok(this.emit_existential_bounds(ecx, b)) @@ -1277,7 +1277,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| { rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { - rbml_w.emit_trait_ref(ecx, &**trait_ref); + rbml_w.emit_trait_ref(ecx, &trait_ref.0); }) }) } @@ -1356,6 +1356,8 @@ trait rbml_decoder_decoder_helpers<'tcx> { fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec>; fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Rc>; + fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) + -> Rc>; fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::TypeParameterDef<'tcx>; fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -1548,6 +1550,19 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap()) } + fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> Rc> { + Rc::new(ty::Binder(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<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::TypeParameterDef<'tcx> { self.read_opaque(|this, doc| { @@ -1753,7 +1768,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { 2 => { let ty_trait = try!(this.read_enum_variant_arg(0, |this| { let principal = try!(this.read_struct_field("principal", 0, |this| { - Ok(this.read_trait_ref(dcx)) + Ok(this.read_poly_trait_ref(dcx)) })); Ok(ty::TyTrait { principal: (*principal).clone(), @@ -1926,7 +1941,7 @@ fn decode_side_tables(dcx: &DecodeContext, dcx.tcx.method_map.borrow_mut().insert(method_call, method); } c::tag_table_object_cast_map => { - let trait_ref = val_dsr.read_trait_ref(dcx); + let trait_ref = val_dsr.read_poly_trait_ref(dcx); dcx.tcx.object_cast_map.borrow_mut() .insert(id, trait_ref); } diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 65412ff8effc9..af2be6e088dd5 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -31,7 +31,6 @@ use middle::infer; use middle::traits; use middle::mem_categorization as mc; use middle::expr_use_visitor as euv; -use util::common::ErrorReported; use util::nodemap::NodeSet; use syntax::ast; @@ -122,17 +121,12 @@ impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> { let ty = ty::node_id_to_type(self.tcx, e.id); let infcx = infer::new_infer_ctxt(self.tcx); let mut fulfill_cx = traits::FulfillmentContext::new(); - match traits::trait_ref_for_builtin_bound(self.tcx, ty::BoundSync, ty) { - Ok(trait_ref) => { - fulfill_cx.register_trait_ref(self.tcx, trait_ref, - traits::ObligationCause::dummy()); - let env = ty::empty_parameter_environment(); - if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() { - self.tcx.sess.span_err(e.span, "shared static items must have a \ - type which implements Sync"); - } - } - Err(ErrorReported) => { } + fulfill_cx.register_builtin_bound(self.tcx, ty, ty::BoundSync, + traits::ObligationCause::dummy()); + let env = ty::empty_parameter_environment(); + if !fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok() { + self.tcx.sess.span_err(e.span, "shared static items must have a \ + type which implements Sync"); } } } diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 6780177933fd1..5c0d4b4841ee3 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -60,7 +60,7 @@ pub fn simplify_type(tcx: &ty::ctxt, ty::ty_vec(..) => Some(VecSimplifiedType), ty::ty_ptr(_) => Some(PtrSimplifiedType), ty::ty_trait(ref trait_info) => { - Some(TraitSimplifiedType(trait_info.principal.def_id)) + Some(TraitSimplifiedType(trait_info.principal.def_id())) } ty::ty_struct(def_id, _) => { Some(StructSimplifiedType(def_id)) @@ -83,10 +83,10 @@ pub fn simplify_type(tcx: &ty::ctxt, Some(TupleSimplifiedType(tys.len())) } ty::ty_closure(ref f) => { - Some(FunctionSimplifiedType(f.sig.inputs.len())) + Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } ty::ty_bare_fn(ref f) => { - Some(FunctionSimplifiedType(f.sig.inputs.len())) + Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } ty::ty_param(_) => { if can_simplify_params { diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index e268160a42b85..805d4532aa1c4 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -60,10 +60,9 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use super::{CoerceResult, resolve_type, Coercion}; +use super::{CoerceResult, Coercion}; use super::combine::{CombineFields, Combine}; use super::sub::Sub; -use super::resolve::try_resolve_tvar_shallow; use middle::subst; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; @@ -197,18 +196,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { pub fn unpack_actual_value(&self, a: Ty<'tcx>, f: F) -> T where F: FnOnce(&ty::sty<'tcx>) -> T, { - match resolve_type(self.get_ref().infcx, None, - a, try_resolve_tvar_shallow) { - Ok(t) => { - f(&t.sty) - } - Err(e) => { - self.get_ref().infcx.tcx.sess.span_bug( - self.get_ref().trace.origin.span(), - format!("failed to resolve even without \ - any force options: {}", e).as_slice()); - } - } + f(&self.get_ref().infcx.shallow_resolve(a).sty) } // ~T -> &T or &mut T -> &T (including where T = [U] or str) @@ -286,7 +274,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_rptr(self.get_ref().infcx.tcx, r_borrow, ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -309,7 +297,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { 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))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -327,7 +315,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { 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))); + try!(self.get_ref().infcx.try(|_| sub.tys(ty, b))); debug!("Success, coerced with AutoDerefRef(1, \ AutoUnsizeUniq({}))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -366,7 +354,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } (_, &ty::ty_trait(box ty::TyTrait { ref principal, bounds })) => { // FIXME what is the purpose of `ty`? - let ty = ty::mk_trait(tcx, (*principal).clone(), bounds); + let ty = ty::mk_trait(tcx, principal.clone(), bounds); Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: (*principal).clone(), bounds: bounds }, ty_a))) @@ -384,7 +372,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut result = None; let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); for (i, (tp_a, tp_b)) in tps { - if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() { + if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() { continue; } match @@ -397,7 +385,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut new_substs = substs_a.clone(); new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; let ty = ty::mk_struct(tcx, did_a, new_substs); - if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() { + if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() { debug!("Unsized type parameter '{}', but still \ could not match types {} and {}", ppaux::ty_to_string(tcx, *tp_a), @@ -476,7 +464,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl); // FIXME what is purpose of this type `tr`? - let tr = ty::mk_trait(tcx, (*principal).clone(), bounds); + let tr = ty::mk_trait(tcx, principal.clone(), bounds); try!(self.subtype(mk_ty(tr), b)); Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 26bba55594b5e..82ddbcee5a72e 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -195,7 +195,7 @@ pub trait Combine<'tcx> { b: &ty::BareFnTy<'tcx>) -> cres<'tcx, ty::BareFnTy<'tcx>> { let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety)); let abi = try!(self.abi(a.abi, b.abi)); - let sig = try!(self.fn_sigs(&a.sig, &b.sig)); + let sig = try!(self.binders(&a.sig, &b.sig)); Ok(ty::BareFnTy {unsafety: unsafety, abi: abi, sig: sig}) @@ -222,7 +222,7 @@ pub trait Combine<'tcx> { let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety)); let onceness = try!(self.oncenesses(a.onceness, b.onceness)); let bounds = try!(self.existential_bounds(a.bounds, b.bounds)); - let sig = try!(self.fn_sigs(&a.sig, &b.sig)); + let sig = try!(self.binders(&a.sig, &b.sig)); let abi = try!(self.abi(a.abi, b.abi)); Ok(ty::ClosureTy { unsafety: unsafety, @@ -234,7 +234,43 @@ pub trait Combine<'tcx> { }) } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>>; + fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>> { + if a.variadic != b.variadic { + return Err(ty::terr_variadic_mismatch(expected_found(self, a.variadic, b.variadic))); + } + + let inputs = try!(argvecs(self, + a.inputs.as_slice(), + b.inputs.as_slice())); + + let output = try!(match (a.output, b.output) { + (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => + Ok(ty::FnConverging(try!(self.tys(a_ty, b_ty)))), + (ty::FnDiverging, ty::FnDiverging) => + Ok(ty::FnDiverging), + (a, b) => + Err(ty::terr_convergence_mismatch( + expected_found(self, a != ty::FnDiverging, b != ty::FnDiverging))), + }); + + return Ok(ty::FnSig {inputs: inputs, + output: output, + variadic: a.variadic}); + + + fn argvecs<'tcx, C: Combine<'tcx>>(combiner: &C, + a_args: &[Ty<'tcx>], + b_args: &[Ty<'tcx>]) + -> cres<'tcx, Vec>> + { + if a_args.len() == b_args.len() { + a_args.iter().zip(b_args.iter()) + .map(|(a, b)| combiner.args(*a, *b)).collect() + } else { + Err(ty::terr_arg_count) + } + } + } fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { self.contratys(a, b).and_then(|t| Ok(t)) @@ -301,11 +337,47 @@ pub trait Combine<'tcx> { fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>>; + -> cres<'tcx, ty::TraitRef<'tcx>> + { + // Different traits cannot be related + if a.def_id != b.def_id { + Err(ty::terr_traits(expected_found(self, a.def_id, b.def_id))) + } else { + let substs = try!(self.substs(a.def_id, &a.substs, &b.substs)); + Ok(ty::TraitRef { def_id: a.def_id, substs: substs }) + } + } + + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + where T : Combineable<'tcx>; // this must be overridden to do correctly, so as to account for higher-ranked // behavior } +pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> { + fn combine>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; +} + +impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> { + fn combine>(combiner: &C, + a: &ty::TraitRef<'tcx>, + b: &ty::TraitRef<'tcx>) + -> cres<'tcx, ty::TraitRef<'tcx>> + { + combiner.trait_refs(a, b) + } +} + +impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> { + fn combine>(combiner: &C, + a: &ty::FnSig<'tcx>, + b: &ty::FnSig<'tcx>) + -> cres<'tcx, ty::FnSig<'tcx>> + { + combiner.fn_sigs(a, b) + } +} + #[deriving(Clone)] pub struct CombineFields<'a, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'tcx>, @@ -410,7 +482,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => { debug!("Trying to match traits {} and {}", a, b); - let principal = try!(this.trait_refs(&a_.principal, &b_.principal)); + let principal = try!(this.binders(&a_.principal, &b_.principal)); let bounds = try!(this.existential_bounds(a_.bounds, b_.bounds)); Ok(ty::mk_trait(tcx, principal, bounds)) } @@ -706,14 +778,38 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { fn fold_region(&mut self, r: ty::Region) -> ty::Region { match r { - ty::ReLateBound(..) | ty::ReEarlyBound(..) => r, - _ if self.make_region_vars => { - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - self.infcx.next_region_var(MiscVariable(self.span)) + // Never make variables for regions bound within the type itself. + ty::ReLateBound(..) => { return r; } + + // Early-bound regions should really have been substituted away before + // we get to this point. + ty::ReEarlyBound(..) => { + self.tcx().sess.span_bug( + self.span, + format!("Encountered early bound region when generalizing: {}", + r.repr(self.tcx()))[]); + } + + // Always make a fresh region variable for skolemized regions; + // the higher-ranked decision procedures rely on this. + ty::ReInfer(ty::ReSkolemized(..)) => { } + + // For anything else, we make a region variable, unless we + // are *equating*, in which case it's just wasteful. + ty::ReEmpty | + ty::ReStatic | + ty::ReScope(..) | + ty::ReInfer(ty::ReVar(..)) | + ty::ReFree(..) => { + if !self.make_region_vars { + return r; + } } - _ => r, } + + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + self.infcx.next_region_var(MiscVariable(self.span)) } } diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 1738b8db99b37..2a4d20f4dd379 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -133,15 +133,10 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { } } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - try!(self.sub().fn_sigs(a, b)); - self.sub().fn_sigs(b, a) - } - - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { - try!(self.sub().trait_refs(a, b)); - self.sub().trait_refs(b, a) + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + where T : Combineable<'tcx> + { + try!(self.sub().binders(a, b)); + self.sub().binders(b, a) } } diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index ab685dd5dbc13..b4c1c0b396b64 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -395,7 +395,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn values_str(&self, values: &ValuePairs<'tcx>) -> Option { match *values { infer::Types(ref exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found) + infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), + infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found) } } @@ -1640,7 +1641,7 @@ pub trait Resolvable<'tcx> { impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> { - infcx.resolve_type_vars_if_possible(*self) + infcx.resolve_type_vars_if_possible(self) } fn contains_error(&self) -> bool { ty::type_is_error(*self) @@ -1650,13 +1651,23 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { impl<'tcx> Resolvable<'tcx> for Rc> { fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Rc> { - Rc::new(infcx.resolve_type_vars_in_trait_ref_if_possible(&**self)) + Rc::new(infcx.resolve_type_vars_if_possible(&**self)) } fn contains_error(&self) -> bool { ty::trait_ref_contains_error(&**self) } } +impl<'tcx> Resolvable<'tcx> for Rc> { + fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) + -> Rc> { + Rc::new(infcx.resolve_type_vars_if_possible(&**self)) + } + fn contains_error(&self) -> bool { + ty::trait_ref_contains_error(&self.0) + } +} + fn lifetimes_in_scope(tcx: &ty::ctxt, scope_id: ast::NodeId) -> Vec { diff --git a/src/librustc/middle/infer/skolemize.rs b/src/librustc/middle/infer/freshen.rs similarity index 63% rename from src/librustc/middle/infer/skolemize.rs rename to src/librustc/middle/infer/freshen.rs index 8336131c54acc..ebff854060cae 100644 --- a/src/librustc/middle/infer/skolemize.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -8,21 +8,21 @@ // 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 +//! Freshening is the process of replacing unknown variables with fresh types. The idea is that +//! the type, after freshening, contains no inference variables but instead contains either a //! value for each variable or fresh "arbitrary" types wherever a variable would have been. //! -//! Skolemization is used primarily to get a good type for inserting into a cache. The result +//! Freshening is used primarily to get a good type for inserting into a cache. The result //! summarizes 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 cache 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. +//! Note that you should be careful not to allow the output of freshening to leak to the user in +//! error messages or in any other form. Freshening is only really useful as an internal detail. //! -//! __An important detail concerning regions.__ The skolemizer also replaces *all* regions with +//! __An important detail concerning regions.__ The freshener 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 @@ -39,26 +39,26 @@ use std::collections::hash_map; use super::InferCtxt; use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; -pub struct TypeSkolemizer<'a, 'tcx:'a> { +pub struct TypeFreshener<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, - skolemization_count: uint, - skolemization_map: hash_map::HashMap>, + freshen_count: uint, + freshen_map: hash_map::HashMap>, } -impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeSkolemizer<'a, 'tcx> { - TypeSkolemizer { +impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> { + TypeFreshener { infcx: infcx, - skolemization_count: 0, - skolemization_map: hash_map::HashMap::new(), + freshen_count: 0, + freshen_map: hash_map::HashMap::new(), } } - fn skolemize(&mut self, - opt_ty: Option>, - key: ty::InferTy, - skolemizer: F) - -> Ty<'tcx> where + fn freshen(&mut self, + opt_ty: Option>, + key: ty::InferTy, + freshener: F) + -> Ty<'tcx> where F: FnOnce(uint) -> ty::InferTy, { match opt_ty { @@ -66,12 +66,12 @@ impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { None => { } } - match self.skolemization_map.entry(key) { + match self.freshen_map.entry(key) { hash_map::Occupied(entry) => *entry.get(), hash_map::Vacant(entry) => { - let index = self.skolemization_count; - self.skolemization_count += 1; - let t = ty::mk_infer(self.infcx.tcx, skolemizer(index)); + let index = self.freshen_count; + self.freshen_count += 1; + let t = ty::mk_infer(self.infcx.tcx, freshener(index)); entry.set(t); t } @@ -79,7 +79,7 @@ impl<'a, 'tcx> TypeSkolemizer<'a, 'tcx> { } } -impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> { +impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { fn tcx<'b>(&'b self) -> &'b ty::ctxt<'tcx> { self.infcx.tcx } @@ -106,37 +106,37 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.sty { ty::ty_infer(ty::TyVar(v)) => { - self.skolemize(self.infcx.type_variables.borrow().probe(v), + self.freshen(self.infcx.type_variables.borrow().probe(v), ty::TyVar(v), - ty::SkolemizedTy) + ty::FreshTy) } ty::ty_infer(ty::IntVar(v)) => { - self.skolemize(self.infcx.probe_var(v), - ty::IntVar(v), - ty::SkolemizedIntTy) + self.freshen(self.infcx.probe_var(v), + ty::IntVar(v), + ty::FreshIntTy) } ty::ty_infer(ty::FloatVar(v)) => { - self.skolemize(self.infcx.probe_var(v), - ty::FloatVar(v), - ty::SkolemizedIntTy) + self.freshen(self.infcx.probe_var(v), + ty::FloatVar(v), + ty::FreshIntTy) } - ty::ty_infer(ty::SkolemizedTy(c)) | - ty::ty_infer(ty::SkolemizedIntTy(c)) => { - if c >= self.skolemization_count { + ty::ty_infer(ty::FreshTy(c)) | + ty::ty_infer(ty::FreshIntTy(c)) => { + if c >= self.freshen_count { self.tcx().sess.bug( - format!("Encountered a skolemized type with id {} \ + format!("Encountered a freshend type with id {} \ but our counter is only at {}", c, - self.skolemization_count).as_slice()); + self.freshen_count).as_slice()); } t } ty::ty_open(..) => { - self.tcx().sess.bug("Cannot skolemize an open existential type"); + self.tcx().sess.bug("Cannot freshen an open existential type"); } ty::ty_bool | diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 9fc4e095c43bd..434be32fe5fa7 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -121,13 +121,9 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { super_lattice_tys(self, a, b) } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - self.higher_ranked_glb(a, b) - } - - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + where T : Combineable<'tcx> + { self.higher_ranked_glb(a, b) } } diff --git a/src/librustc/middle/infer/higher_ranked/doc.rs b/src/librustc/middle/infer/higher_ranked/doc.rs index 2bad3616a05d1..f6f254c0e8dfc 100644 --- a/src/librustc/middle/infer/higher_ranked/doc.rs +++ b/src/librustc/middle/infer/higher_ranked/doc.rs @@ -249,19 +249,21 @@ //! in T and try to, in some cases, replace them with bound regions to //! yield the final result. //! -//! To decide whether to replace a region `R` that appears in `T` with a -//! bound region, the algorithms make use of two bits of information. -//! First is a set `V` that contains all region variables created as part -//! of the LUB/GLB computation. `V` will contain the region variables -//! created to replace the bound regions in the input types, but it also -//! contains 'intermediate' variables created to represent the LUB/GLB of -//! individual regions. Basically, when asked to compute the LUB/GLB of a -//! region variable with another region, the inferencer cannot oblige -//! immediately since the values of that variables are not known. -//! Therefore, it creates a new variable that is related to the two -//! regions. For example, the LUB of two variables `$x` and `$y` is a -//! fresh variable `$z` that is constrained such that `$x <= $z` and `$y -//! <= $z`. So `V` will contain these intermediate variables as well. +//! To decide whether to replace a region `R` that appears in `T` with +//! a bound region, the algorithms make use of two bits of +//! information. First is a set `V` that contains all region +//! variables created as part of the LUB/GLB computation (roughly; see +//! `region_vars_confined_to_snapshot()` for full details). `V` will +//! contain the region variables created to replace the bound regions +//! in the input types, but it also contains 'intermediate' variables +//! created to represent the LUB/GLB of individual regions. +//! Basically, when asked to compute the LUB/GLB of a region variable +//! with another region, the inferencer cannot oblige immediately +//! since the values of that variables are not known. Therefore, it +//! creates a new variable that is related to the two regions. For +//! example, the LUB of two variables `$x` and `$y` is a fresh +//! variable `$z` that is constrained such that `$x <= $z` and `$y <= +//! $z`. So `V` will contain these intermediate variables as well. //! //! The other important factor in deciding how to replace a region in T is //! the function `Tainted($r)` which, for a region variable, identifies diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index be053afcca436..ab0f98ec74a7f 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -11,37 +11,40 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. -use super::{combine, cres, InferCtxt, HigherRankedType}; -use super::combine::Combine; -use super::region_inference::{RegionMark}; +use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap}; +use super::combine::{Combine, Combineable}; -use middle::ty::{mod, Ty, replace_late_bound_regions}; -use middle::ty_fold::{mod, HigherRankedFoldable, TypeFoldable}; +use middle::ty::{mod, Binder}; +use middle::ty_fold::{mod, TypeFoldable}; use syntax::codemap::Span; -use util::nodemap::FnvHashMap; -use util::ppaux::{bound_region_to_string, Repr}; - -pub trait HigherRankedCombineable<'tcx>: HigherRankedFoldable<'tcx> + - TypeFoldable<'tcx> + Repr<'tcx> { - fn super_combine>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; -} +use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::ppaux::Repr; pub trait HigherRankedRelations<'tcx> { - fn higher_ranked_sub(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx>; + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx>; + + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx>; + + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx>; +} - fn higher_ranked_lub(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx>; +trait InferCtxtExt<'tcx> { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec; - fn higher_ranked_glb(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx>; + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec; } impl<'tcx,C> HigherRankedRelations<'tcx> for C where C : Combine<'tcx> { - fn higher_ranked_sub(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx> + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) + -> cres<'tcx, Binder> + where T : Combineable<'tcx> { debug!("higher_ranked_sub(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); @@ -54,114 +57,95 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // please see the large comment at the end of the file in the (inlined) module // `doc`. - // Make a mark so we can examine "all bindings that were + // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // First, we instantiate each bound region in the subtype with a fresh - // region variable. - let (a_prime, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), - HigherRankedType, - a); - - // Second, we instantiate each bound region in the supertype with a - // fresh concrete region. - let (b_prime, skol_map) = { - replace_late_bound_regions(self.tcx(), b, |br, _| { - let skol = self.infcx().region_vars.new_skolemized(br); - debug!("Bound region {} skolemized to {}", - bound_region_to_string(self.tcx(), "", false, br), - skol); - skol - }) - }; - - debug!("a_prime={}", a_prime.repr(self.tcx())); - debug!("b_prime={}", b_prime.repr(self.tcx())); - - // Compare types now that bound regions have been replaced. - let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime)); - - // Presuming type comparison succeeds, we need to check - // that the skolemized regions do not "leak". - let new_vars = - self.infcx().region_vars.vars_created_since_mark(mark); - for (&skol_br, &skol) in skol_map.iter() { - let tainted = self.infcx().region_vars.tainted(mark, skol); - for tainted_region in tainted.iter() { - // Each skolemized should only be relatable to itself - // or new variables: - match *tainted_region { - ty::ReInfer(ty::ReVar(ref vid)) => { - if new_vars.iter().any(|x| x == vid) { continue; } - } - _ => { - if *tainted_region == skol { continue; } + return self.infcx().try(|snapshot| { + // First, we instantiate each bound region in the subtype with a fresh + // region variable. + let (a_prime, _) = + self.infcx().replace_late_bound_regions_with_fresh_var( + self.trace().origin.span(), + HigherRankedType, + a); + + // Second, we instantiate each bound region in the supertype with a + // fresh concrete region. + let (b_prime, skol_map) = + self.infcx().skolemize_late_bound_regions(b, snapshot); + + debug!("a_prime={}", a_prime.repr(self.tcx())); + debug!("b_prime={}", b_prime.repr(self.tcx())); + + // Compare types now that bound regions have been replaced. + let result = try!(Combineable::combine(self, &a_prime, &b_prime)); + + // Presuming type comparison succeeds, we need to check + // that the skolemized regions do not "leak". + match leak_check(self.infcx(), &skol_map, snapshot) { + Ok(()) => { } + Err((skol_br, tainted_region)) => { + if self.a_is_expected() { + debug!("Not as polymorphic!"); + return Err(ty::terr_regions_insufficiently_polymorphic(skol_br, + tainted_region)); + } else { + debug!("Overly polymorphic!"); + return Err(ty::terr_regions_overly_polymorphic(skol_br, + tainted_region)); } - }; - - // A is not as polymorphic as B: - if self.a_is_expected() { - debug!("Not as polymorphic!"); - return Err(ty::terr_regions_insufficiently_polymorphic( - skol_br, *tainted_region)); - } else { - debug!("Overly polymorphic!"); - return Err(ty::terr_regions_overly_polymorphic( - skol_br, *tainted_region)); } } - } - debug!("higher_ranked_sub: OK result={}", - result.repr(self.tcx())); + debug!("higher_ranked_sub: OK result={}", + result.repr(self.tcx())); - return Ok(result); + Ok(ty::Binder(result)) + }); } - fn higher_ranked_lub(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx> + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx> { - // Make a mark so we can examine "all bindings that were + // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // Instantiate each bound region with a fresh region variable. - let span = self.trace().origin.span(); - let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - span, HigherRankedType, a); - let (b_with_fresh, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( - span, HigherRankedType, b); - - // Collect constraints. - let result0 = - try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); - debug!("lub result0 = {}", result0.repr(self.tcx())); - - // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx().region_vars.vars_created_since_mark(mark); - let span = self.trace().origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn, - new_vars.as_slice(), &a_map, r)); - - debug!("lub({},{}) = {}", - a.repr(self.tcx()), - b.repr(self.tcx()), - result1.repr(self.tcx())); - - return Ok(result1); + return self.infcx().try(|snapshot| { + // Instantiate each bound region with a fresh region variable. + let span = self.trace().origin.span(); + let (a_with_fresh, a_map) = + self.infcx().replace_late_bound_regions_with_fresh_var( + span, HigherRankedType, a); + let (b_with_fresh, _) = + self.infcx().replace_late_bound_regions_with_fresh_var( + span, HigherRankedType, b); + + // Collect constraints. + let result0 = + try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); + let result0 = + self.infcx().resolve_type_vars_if_possible(&result0); + debug!("lub result0 = {}", result0.repr(self.tcx())); + + // Generalize the regions appearing in result0 if possible + let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); + let span = self.trace().origin.span(); + let result1 = + fold_regions_in( + self.tcx(), + &result0, + |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + new_vars.as_slice(), &a_map, r)); + + debug!("lub({},{}) = {}", + a.repr(self.tcx()), + b.repr(self.tcx()), + result1.repr(self.tcx())); + + Ok(ty::Binder(result1)) + }); fn generalize_region(infcx: &InferCtxt, span: Span, - mark: RegionMark, + snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FnvHashMap, @@ -174,7 +158,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C return r0; } - let tainted = infcx.region_vars.tainted(mark, r0); + let tainted = infcx.tainted_regions(snapshot, r0); // Variables created during LUB computation which are // *related* to regions that pre-date the LUB computation @@ -209,53 +193,55 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } - fn higher_ranked_glb(&self, a: &T, b: &T) -> cres<'tcx, T> - where T : HigherRankedCombineable<'tcx> + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> + where T : Combineable<'tcx> { debug!("{}.higher_ranked_glb({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); - // Make a mark so we can examine "all bindings that were + // Make a snapshot so we can examine "all bindings that were // created as part of this type comparison". - let mark = self.infcx().region_vars.mark(); - - // Instantiate each bound region with a fresh region variable. - let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), HigherRankedType, a); - let (b_with_fresh, b_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), HigherRankedType, b); - let a_vars = var_ids(self, &a_map); - let b_vars = var_ids(self, &b_map); - - // Collect constraints. - let result0 = - try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh)); - debug!("glb result0 = {}", result0.repr(self.tcx())); - - // Generalize the regions appearing in fn_ty0 if possible - let new_vars = self.infcx().region_vars.vars_created_since_mark(mark); - let span = self.trace().origin.span(); - let result1 = - fold_regions_in( - self.tcx(), - &result0, - |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn, - new_vars.as_slice(), - &a_map, a_vars.as_slice(), b_vars.as_slice(), - r)); - - debug!("glb({},{}) = {}", - a.repr(self.tcx()), - b.repr(self.tcx()), - result1.repr(self.tcx())); - - return Ok(result1); + return self.infcx().try(|snapshot| { + // Instantiate each bound region with a fresh region variable. + let (a_with_fresh, a_map) = + self.infcx().replace_late_bound_regions_with_fresh_var( + self.trace().origin.span(), HigherRankedType, a); + let (b_with_fresh, b_map) = + self.infcx().replace_late_bound_regions_with_fresh_var( + self.trace().origin.span(), HigherRankedType, b); + let a_vars = var_ids(self, &a_map); + let b_vars = var_ids(self, &b_map); + + // Collect constraints. + let result0 = + try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); + let result0 = + self.infcx().resolve_type_vars_if_possible(&result0); + debug!("glb result0 = {}", result0.repr(self.tcx())); + + // Generalize the regions appearing in result0 if possible + let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); + let span = self.trace().origin.span(); + let result1 = + fold_regions_in( + self.tcx(), + &result0, + |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + new_vars.as_slice(), + &a_map, a_vars.as_slice(), b_vars.as_slice(), + r)); + + debug!("glb({},{}) = {}", + a.repr(self.tcx()), + b.repr(self.tcx()), + result1.repr(self.tcx())); + + Ok(ty::Binder(result1)) + }); fn generalize_region(infcx: &InferCtxt, span: Span, - mark: RegionMark, + snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FnvHashMap, @@ -267,7 +253,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C return r0; } - let tainted = infcx.region_vars.tainted(mark, r0); + let tainted = infcx.tainted_regions(snapshot, r0); let mut a_r = None; let mut b_r = None; @@ -345,67 +331,6 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } -impl<'tcx> HigherRankedCombineable<'tcx> for ty::FnSig<'tcx> { - fn super_combine>(combiner: &C, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> - { - if a.variadic != b.variadic { - return Err(ty::terr_variadic_mismatch( - combine::expected_found(combiner, a.variadic, b.variadic))); - } - - let inputs = try!(argvecs(combiner, - a.inputs.as_slice(), - b.inputs.as_slice())); - - let output = try!(match (a.output, b.output) { - (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => - Ok(ty::FnConverging(try!(combiner.tys(a_ty, b_ty)))), - (ty::FnDiverging, ty::FnDiverging) => - Ok(ty::FnDiverging), - (a, b) => - Err(ty::terr_convergence_mismatch( - combine::expected_found(combiner, a != ty::FnDiverging, b != ty::FnDiverging))), - }); - - return Ok(ty::FnSig {inputs: inputs, - output: output, - variadic: a.variadic}); - - - fn argvecs<'tcx, C: Combine<'tcx>>(combiner: &C, - a_args: &[Ty<'tcx>], - b_args: &[Ty<'tcx>]) - -> cres<'tcx, Vec>> - { - if a_args.len() == b_args.len() { - a_args.iter().zip(b_args.iter()) - .map(|(a, b)| combiner.args(*a, *b)).collect() - } else { - Err(ty::terr_arg_count) - } - } - } -} - -impl<'tcx> HigherRankedCombineable<'tcx> for ty::TraitRef<'tcx> { - fn super_combine>(combiner: &C, - a: &ty::TraitRef<'tcx>, - b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> - { - // Different traits cannot be related - if a.def_id != b.def_id { - Err(ty::terr_traits( - combine::expected_found(combiner, a.def_id, b.def_id))) - } else { - let substs = try!(combiner.substs(a.def_id, &a.substs, &b.substs)); - Ok(ty::TraitRef { def_id: a.def_id, - substs: substs }) - } - } -} - fn var_ids<'tcx, T: Combine<'tcx>>(combiner: &T, map: &FnvHashMap) -> Vec { @@ -426,11 +351,14 @@ fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { } } -fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, value: &T, mut fldr: F) -> T where - T: HigherRankedFoldable<'tcx>, - F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, +fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, + unbound_value: &T, + mut fldr: F) + -> T + where T : Combineable<'tcx>, + F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, { - value.fold_contents(&mut ty_fold::RegionFolder::new(tcx, |region, current_depth| { + unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| { // we should only be encountering "escaping" late-bound regions here, // because the ones at the current level should have been replaced // with fresh variables @@ -443,3 +371,244 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, value: &T, mut fldr: F) -> })) } +impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> { + fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec { + self.region_vars.tainted(&snapshot.region_vars_snapshot, r) + } + + fn region_vars_confined_to_snapshot(&self, + snapshot: &CombinedSnapshot) + -> Vec + { + /*! + * Returns the set of region variables that do not affect any + * types/regions which existed before `snapshot` was + * started. This is used in the sub/lub/glb computations. The + * idea here is that when we are computing lub/glb of two + * regions, we sometimes create intermediate region variables. + * Those region variables may touch some of the skolemized or + * other "forbidden" regions we created to replace bound + * regions, but they don't really represent an "external" + * constraint. + * + * However, sometimes fresh variables are created for other + * purposes too, and those *may* represent an external + * constraint. In particular, when a type variable is + * instantiated, we create region variables for all the + * regions that appear within, and if that type variable + * pre-existed the snapshot, then those region variables + * represent external constraints. + * + * An example appears in the unit test + * `sub_free_bound_false_infer`. In this test, we want to + * know whether + * + * ```rust + * fn(_#0t) <: for<'a> fn(&'a int) + * ``` + * + * Note that the subtype has a type variable. Because the type + * variable can't be instantiated with a region that is bound + * in the fn signature, this comparison ought to fail. But if + * we're not careful, it will succeed. + * + * The reason is that when we walk through the subtyping + * algorith, we begin by replacing `'a` with a skolemized + * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This + * can be made true by unifying `_#0t` with `&'1 int`. In the + * process, we create a fresh variable for the skolemized + * region, `'$2`, and hence we have that `_#0t == &'$2 + * int`. However, because `'$2` was created during the sub + * computation, if we're not careful we will erroneously + * assume it is one of the transient region variables + * representing a lub/glb internally. Not good. + * + * To prevent this, we check for type variables which were + * unified during the snapshot, and say that any region + * variable created during the snapshot but which finds its + * way into a type variable is considered to "escape" the + * snapshot. + */ + + let mut region_vars = + self.region_vars.vars_created_since_snapshot(&snapshot.region_vars_snapshot); + + let escaping_types = + self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot); + + let escaping_region_vars: FnvHashSet<_> = + escaping_types + .iter() + .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t).into_iter()) + .collect(); + + region_vars.retain(|®ion_vid| { + let r = ty::ReInfer(ty::ReVar(region_vid)); + !escaping_region_vars.contains(&r) + }); + + debug!("region_vars_confined_to_snapshot: region_vars={} escaping_types={}", + region_vars.repr(self.tcx), + escaping_types.repr(self.tcx)); + + region_vars + } +} + +pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + binder: &ty::Binder, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + /*! + * Replace all regions bound by `binder` with skolemized regions and + * return a map indicating which bound-region was replaced with what + * skolemized region. This is the first step of checking subtyping + * when higher-ranked things are involved. See `doc.rs` for more details. + */ + + let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br, _| { + infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot) + }); + + debug!("skolemize_bound_regions(binder={}, result={}, map={})", + binder.repr(infcx.tcx), + result.repr(infcx.tcx), + map.repr(infcx.tcx)); + + (result, map) +} + +pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + skol_map: &SkolemizationMap, + snapshot: &CombinedSnapshot) + -> Result<(),(ty::BoundRegion,ty::Region)> +{ + /*! + * Searches the region constriants created since `snapshot` was started + * and checks to determine whether any of the skolemized regions created + * in `skol_map` would "escape" -- meaning that they are related to + * other regions in some way. If so, the higher-ranked subtyping doesn't + * hold. See `doc.rs` for more details. + */ + + debug!("leak_check: skol_map={}", + skol_map.repr(infcx.tcx)); + + let new_vars = infcx.region_vars_confined_to_snapshot(snapshot); + for (&skol_br, &skol) in skol_map.iter() { + let tainted = infcx.tainted_regions(snapshot, skol); + for &tainted_region in tainted.iter() { + // Each skolemized should only be relatable to itself + // or new variables: + match tainted_region { + ty::ReInfer(ty::ReVar(vid)) => { + if new_vars.iter().any(|&x| x == vid) { continue; } + } + _ => { + if tainted_region == skol { continue; } + } + }; + + debug!("{} (which replaced {}) is tainted by {}", + skol.repr(infcx.tcx), + skol_br.repr(infcx.tcx), + tainted_region.repr(infcx.tcx)); + + // A is not as polymorphic as B: + return Err((skol_br, tainted_region)); + } + } + Ok(()) +} + +/// This code converts from skolemized regions back to late-bound +/// regions. It works by replacing each region in the taint set of a +/// skolemized region with a bound-region. The bound region will be bound +/// by the outer-most binder in `value`; the caller must ensure that there is +/// such a binder and it is the right place. +/// +/// This routine is only intended to be used when the leak-check has +/// passed; currently, it's used in the trait matching code to create +/// a set of nested obligations frmo an impl that matches against +/// something higher-ranked. More details can be found in +/// `middle::traits::doc.rs`. +/// +/// As a brief example, consider the obligation `for<'a> Fn(&'a int) +/// -> &'a int`, and the impl: +/// +/// impl Fn for SomethingOrOther +/// where A : Clone +/// { ... } +/// +/// Here we will have replaced `'a` with a skolemized region +/// `'0`. This means that our substitution will be `{A=>&'0 +/// int, R=>&'0 int}`. +/// +/// When we apply the substitution to the bounds, we will wind up with +/// `&'0 int : Clone` as a predicate. As a last step, we then go and +/// replace `'0` with a late-bound region `'a`. The depth is matched +/// to the depth of the predicate, in this case 1, so that the final +/// predicate is `for<'a> &'a int : Clone`. +pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, + skol_map: SkolemizationMap, + snapshot: &CombinedSnapshot, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok()); + + debug!("plug_leaks(skol_map={}, value={})", + skol_map.repr(infcx.tcx), + value.repr(infcx.tcx)); + + // Compute a mapping from the "taint set" of each skolemized + // region back to the `ty::BoundRegion` that it originally + // represented. Because `leak_check` passed, we know that that + // these taint sets are mutually disjoint. + let inv_skol_map: FnvHashMap = + skol_map + .into_iter() + .flat_map(|(skol_br, skol)| { + infcx.tainted_regions(snapshot, skol) + .into_iter() + .map(move |tainted_region| (tainted_region, skol_br)) + }) + .collect(); + + debug!("plug_leaks: inv_skol_map={}", + inv_skol_map.repr(infcx.tcx)); + + // Remove any instantiated type variables from `value`; those can hide + // references to regions from the `fold_regions` code below. + let value = infcx.resolve_type_vars_if_possible(value); + + // Map any skolemization byproducts back to a late-bound + // region. Put that late-bound region at whatever the outermost + // binder is that we encountered in `value`. The caller is + // responsible for ensuring that (a) `value` contains at least one + // binder and (b) that binder is the one we want to use. + let result = ty_fold::fold_regions(infcx.tcx, &value, |r, current_depth| { + match inv_skol_map.get(&r) { + None => r, + Some(br) => { + // It is the responsibility of the caller to ensure + // that each skolemized region appears within a + // binder. In practice, this routine is only used by + // trait checking, and all of the skolemized regions + // appear inside predicates, which always have + // binders, so this assert is satisfied. + assert!(current_depth > 1); + + ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone()) + } + } + }); + + debug!("plug_leaks: result={}", + result.repr(infcx.tcx)); + + result +} diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index f27b07c9c9d45..f4909b2889163 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -113,17 +113,13 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b)) } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - self.higher_ranked_lub(a, b) - } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { super_lattice_tys(self, a, b) } - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + where T : Combineable<'tcx> + { self.higher_ranked_lub(a, b) } } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 14153907ee764..f419f050cf594 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -19,21 +19,14 @@ pub use self::TypeOrigin::*; pub use self::ValuePairs::*; pub use self::fixup_err::*; pub use middle::ty::IntVarValue; -pub use self::resolve::resolve_and_force_all_but_regions; -pub use self::resolve::{force_all, not_regions}; -pub use self::resolve::{force_ivar}; -pub use self::resolve::{force_tvar, force_rvar}; -pub use self::resolve::{resolve_ivar, resolve_all}; -pub use self::resolve::{resolve_nested_tvar}; -pub use self::resolve::{resolve_rvar}; -pub use self::skolemize::TypeSkolemizer; +pub use self::freshen::TypeFreshener; use middle::subst; use middle::subst::Substs; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid}; use middle::ty::replace_late_bound_regions; use middle::ty::{mod, Ty}; -use middle::ty_fold::{HigherRankedFoldable, TypeFolder, TypeFoldable}; +use middle::ty_fold::{TypeFolder, TypeFoldable}; use std::cell::{RefCell}; use std::rc::Rc; use syntax::ast; @@ -42,12 +35,11 @@ use syntax::codemap::Span; use util::common::indent; use util::nodemap::FnvHashMap; use util::ppaux::{ty_to_string}; -use util::ppaux::{trait_ref_to_string, Repr}; +use util::ppaux::{Repr, UserString}; use self::coercion::Coerce; use self::combine::{Combine, CombineFields}; use self::region_inference::{RegionVarBindings, RegionSnapshot}; -use self::resolve::{resolver}; use self::equate::Equate; use self::sub::Sub; use self::lub::Lub; @@ -60,12 +52,12 @@ pub mod doc; pub mod equate; pub mod error_reporting; pub mod glb; -pub mod higher_ranked; +mod higher_ranked; pub mod lattice; pub mod lub; pub mod region_inference; pub mod resolve; -mod skolemize; +mod freshen; pub mod sub; pub mod type_variable; pub mod unify; @@ -98,6 +90,10 @@ pub struct InferCtxt<'a, 'tcx: 'a> { RegionVarBindings<'a, 'tcx>, } +/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized +/// region that each late-bound region was replaced with. +pub type SkolemizationMap = FnvHashMap; + /// Why did we require that the two types be related? /// /// See `error_reporting.rs` for more details @@ -142,6 +138,7 @@ impl Copy for TypeOrigin {} pub enum ValuePairs<'tcx> { Types(ty::expected_found>), TraitRefs(ty::expected_found>>), + PolyTraitRefs(ty::expected_found>>), } /// The trace designates the path through inference that we took to @@ -353,7 +350,7 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, b: Ty<'tcx>) -> ures<'tcx> { debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.probe(|| { + cx.probe(|_| { let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) @@ -366,7 +363,7 @@ pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx> { debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.probe(|| { + cx.probe(|_| { let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) @@ -410,17 +407,17 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, || cx.eq_types(a_is_expected, origin, a, b)) } -pub fn mk_sub_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, +pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a_is_expected: bool, origin: TypeOrigin, - a: Rc>, - b: Rc>) + a: Rc>, + b: Rc>) -> ures<'tcx> { debug!("mk_sub_trait_refs({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); cx.commit_if_ok( - || cx.sub_trait_refs(a_is_expected, origin, a.clone(), b.clone())) + || cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone())) } fn expected_found(a_is_expected: bool, @@ -453,22 +450,6 @@ pub fn mk_coercety<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, }) } -// See comment on the type `resolve_state` below -pub fn resolve_type<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, - span: Option, - a: Ty<'tcx>, - modes: uint) - -> fres> { - let mut resolver = resolver(cx, modes, span); - cx.commit_unconditionally(|| resolver.resolve_type_chk(a)) -} - -pub fn resolve_region(cx: &InferCtxt, r: ty::Region, modes: uint) - -> fres { - let mut resolver = resolver(cx, modes, None); - resolver.resolve_region_chk(r) -} - trait then<'tcx> { fn then(&self, f: F) -> Result> where T: Clone, @@ -520,6 +501,7 @@ pub fn uok<'tcx>() -> ures<'tcx> { Ok(()) } +#[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot { type_snapshot: type_variable::Snapshot, int_snapshot: unify::Snapshot, @@ -528,8 +510,8 @@ pub struct CombinedSnapshot { } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn skolemize>(&self, t: T) -> T { - t.fold_with(&mut self.skolemizer()) + pub fn freshen>(&self, t: T) -> T { + t.fold_with(&mut self.freshener()) } pub fn type_var_diverges(&'a self, ty: Ty) -> bool { @@ -539,8 +521,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn skolemizer<'b>(&'b self) -> TypeSkolemizer<'b, 'tcx> { - skolemize::TypeSkolemizer::new(self) + pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { + freshen::TypeFreshener::new(self) } pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) @@ -629,16 +611,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn commit_if_ok(&self, f: F) -> Result where F: FnOnce() -> Result { - self.commit_unconditionally(move || self.try(move || f())) + self.commit_unconditionally(move || self.try(move |_| f())) } /// Execute `f`, unroll bindings on panic pub fn try(&self, f: F) -> Result where - F: FnOnce() -> Result + F: FnOnce(&CombinedSnapshot) -> Result { debug!("try()"); let snapshot = self.start_snapshot(); - let r = f(); + let r = f(&snapshot); debug!("try() -- r.is_ok() = {}", r.is_ok()); match r { Ok(_) => { @@ -653,11 +635,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Execute `f` then unroll any bindings it creates pub fn probe(&self, f: F) -> R where - F: FnOnce() -> R, + F: FnOnce(&CombinedSnapshot) -> R, { debug!("probe()"); let snapshot = self.start_snapshot(); - let r = f(); + let r = f(&snapshot); self.rollback_to(snapshot); r } @@ -715,15 +697,93 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.commit_if_ok(|| { let trace = TypeTrace { origin: origin, - values: TraitRefs(expected_found(a_is_expected, - a.clone(), b.clone())) + values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures() }) } -} -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + pub fn sub_poly_trait_refs(&self, + a_is_expected: bool, + origin: TypeOrigin, + a: Rc>, + b: Rc>) + -> ures<'tcx> + { + debug!("sub_poly_trait_refs({} <: {})", + a.repr(self.tcx), + b.repr(self.tcx)); + self.commit_if_ok(|| { + let trace = TypeTrace { + origin: origin, + values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) + }; + self.sub(a_is_expected, trace).binders(&*a, &*b).to_ures() + }) + } + + pub fn skolemize_late_bound_regions(&self, + value: &ty::Binder, + snapshot: &CombinedSnapshot) + -> (T, SkolemizationMap) + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + /*! See `higher_ranked::skolemize_late_bound_regions` */ + + higher_ranked::skolemize_late_bound_regions(self, value, snapshot) + } + + pub fn leak_check(&self, + skol_map: &SkolemizationMap, + snapshot: &CombinedSnapshot) + -> ures<'tcx> + { + /*! See `higher_ranked::leak_check` */ + + match higher_ranked::leak_check(self, skol_map, snapshot) { + Ok(()) => Ok(()), + Err((br, r)) => Err(ty::terr_regions_insufficiently_polymorphic(br, r)) + } + } + + pub fn plug_leaks(&self, + skol_map: SkolemizationMap, + snapshot: &CombinedSnapshot, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + /*! See `higher_ranked::leak_check` */ + + higher_ranked::plug_leaks(self, skol_map, snapshot, value) + } + + pub fn equality_predicate(&self, + span: Span, + predicate: &ty::PolyEquatePredicate<'tcx>) + -> ures<'tcx> { + self.try(|snapshot| { + let (ty::EquatePredicate(a, b), skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + let origin = EquatePredicate(span); + let () = try!(mk_eqty(self, false, origin, a, b)); + self.leak_check(&skol_map, snapshot) + }) + } + + pub fn region_outlives_predicate(&self, + span: Span, + predicate: &ty::PolyRegionOutlivesPredicate) + -> ures<'tcx> { + self.try(|snapshot| { + let (ty::OutlivesPredicate(r_a, r_b), skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + let origin = RelateRegionParamBound(span); + let () = mk_subr(self, origin, r_b, r_a); // `b : a` ==> `a <= b` + self.leak_check(&skol_map, snapshot) + }) + } + pub fn next_ty_var_id(&self, diverging: bool) -> TyVid { self.type_variables .borrow_mut() @@ -821,7 +881,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { ty_to_string(self.tcx, - self.resolve_type_vars_if_possible(t)) + self.resolve_type_vars_if_possible(&t)) } pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { @@ -830,24 +890,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn trait_ref_to_string(&self, t: &Rc>) -> String { - let t = self.resolve_type_vars_in_trait_ref_if_possible(&**t); - trait_ref_to_string(self.tcx, &t) - } - - pub fn contains_unbound_type_variables(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self, - None, - typ, resolve_nested_tvar | resolve_ivar) { - Ok(new_type) => new_type, - Err(_) => typ - } + let t = self.resolve_type_vars_if_possible(&**t); + t.user_string(self.tcx) } pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { match typ.sty { ty::ty_infer(ty::TyVar(v)) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifying to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. self.type_variables.borrow() .probe(v) + .map(|t| self.shallow_resolve(t)) .unwrap_or(typ) } @@ -867,35 +928,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn resolve_type_vars_if_possible(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - 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, value: &T) -> T { + /*! + * Where possible, replaces type/int/float variables in + * `value` with their final value. Note that region variables + * are unaffected. If a type variable has not been unified, it + * is left as is. This is an idempotent operation that does + * not affect inference state in any way and so you can do it + * at will. + */ + + let mut r = resolve::OpportunisticTypeResolver::new(self); + value.fold_with(&mut r) } - pub fn resolve_type_vars_in_trait_ref_if_possible(&self, - trait_ref: &ty::TraitRef<'tcx>) - -> ty::TraitRef<'tcx> { - // make up a dummy type just to reuse/abuse the resolve machinery - let dummy0 = ty::mk_trait(self.tcx, - (*trait_ref).clone(), - ty::region_existential_bound(ty::ReStatic)); - let dummy1 = self.resolve_type_vars_if_possible(dummy0); - match dummy1.sty { - ty::ty_trait(box ty::TyTrait { ref principal, .. }) => { - (*principal).clone() - } - _ => { - self.tcx.sess.bug( - format!("resolve_type_vars_if_possible() yielded {} \ - when supplied with {}", - self.ty_to_string(dummy0), - self.ty_to_string(dummy1)).as_slice()); - } - } + pub fn fully_resolve>(&self, value: &T) -> fres { + /*! + * Attempts to resolve all type/region variables in + * `value`. Region inference must have been run already (e.g., + * by calling `resolve_regions_and_report_errors`). If some + * variable was never unified, an `Err` results. + * + * This method is idempotent, but it not typically not invoked + * except during the writeback phase. + */ + + resolve::fully_resolve(self, value) } // [Note-Type-error-reporting] @@ -929,9 +987,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("hi! expected_ty = {}, actual_ty = {}", expected_ty, actual_ty); - let resolved_expected = expected_ty.map(|e_ty| { - self.resolve_type_vars_if_possible(e_ty) - }); + let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); match resolved_expected { Some(t) if ty::type_is_error(t) => (), @@ -958,7 +1014,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: Option<&ty::type_err<'tcx>>) where M: FnOnce(String) -> String, { - let actual_ty = self.resolve_type_vars_if_possible(actual_ty); + let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); // Don't report an error if actual type is ty_err. if ty::type_is_error(actual_ty) { @@ -989,9 +1045,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, span: Span, lbrct: LateBoundRegionConversionTime, - value: &T) + value: &ty::Binder) -> (T, FnvHashMap) - where T : HigherRankedFoldable<'tcx> + where T : TypeFoldable<'tcx> + Repr<'tcx> { ty::replace_late_bound_regions( self.tcx, diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index ca2860ae6b37c..d34373e66a1e0 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -81,7 +81,6 @@ impl Copy for TwoRegions {} pub enum UndoLogEntry { OpenSnapshot, CommitedSnapshot, - Mark, AddVar(RegionVid), AddConstraint(Constraint), AddVerify(uint), @@ -225,19 +224,12 @@ pub struct RegionVarBindings<'a, 'tcx: 'a> { } #[deriving(Show)] +#[allow(missing_copy_implementations)] pub struct RegionSnapshot { - length: uint + length: uint, + skolemization_count: uint, } -impl Copy for RegionSnapshot {} - -#[deriving(Show)] -pub struct RegionMark { - length: uint -} - -impl Copy for RegionMark {} - impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { pub fn new(tcx: &'a ty::ctxt<'tcx>) -> RegionVarBindings<'a, 'tcx> { RegionVarBindings { @@ -263,14 +255,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { let length = self.undo_log.borrow().len(); debug!("RegionVarBindings: start_snapshot({})", length); self.undo_log.borrow_mut().push(OpenSnapshot); - RegionSnapshot { length: length } - } - - pub fn mark(&self) -> RegionMark { - let length = self.undo_log.borrow().len(); - debug!("RegionVarBindings: mark({})", length); - self.undo_log.borrow_mut().push(Mark); - RegionMark { length: length } + RegionSnapshot { length: length, skolemization_count: self.skolemization_count.get() } } pub fn commit(&self, snapshot: RegionSnapshot) { @@ -284,6 +269,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } else { (*undo_log)[snapshot.length] = CommitedSnapshot; } + self.skolemization_count.set(snapshot.skolemization_count); } pub fn rollback_to(&self, snapshot: RegionSnapshot) { @@ -296,7 +282,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { OpenSnapshot => { panic!("Failure to observe stack discipline"); } - Mark | CommitedSnapshot => { } + CommitedSnapshot => { } AddVar(vid) => { let mut var_origins = self.var_origins.borrow_mut(); var_origins.pop().unwrap(); @@ -322,6 +308,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } let c = undo_log.pop().unwrap(); assert!(c == OpenSnapshot); + self.skolemization_count.set(snapshot.skolemization_count); } pub fn num_vars(&self) -> uint { @@ -340,7 +327,25 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { return vid; } - pub fn new_skolemized(&self, br: ty::BoundRegion) -> Region { + /// Creates a new skolemized region. Skolemized regions are fresh + /// regions used when performing higher-ranked computations. They + /// must be used in a very particular way and are never supposed + /// to "escape" out into error messages or the code at large. + /// + /// The idea is to always create a snapshot. Skolemized regions + /// can be created in the context of this snapshot, but once the + /// snapshot is commited or rolled back, their numbers will be + /// recycled, so you must be finished with them. See the extensive + /// comments in `higher_ranked.rs` to see how it works (in + /// particular, the subtyping comparison). + /// + /// The `snapshot` argument to this function is not really used; + /// it's just there to make it explicit which snapshot bounds the + /// skolemized region that results. + pub fn new_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) -> Region { + assert!(self.in_snapshot()); + assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot); + let sc = self.skolemization_count.get(); self.skolemization_count.set(sc + 1); ReInfer(ReSkolemized(sc, br)) @@ -597,8 +602,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { ReInfer(ReVar(c)) } - pub fn vars_created_since_mark(&self, mark: RegionMark) - -> Vec + pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) + -> Vec { self.undo_log.borrow() .slice_from(mark.length) @@ -613,7 +618,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// Computes all regions that have been related to `r0` in any way since the mark `mark` was /// made---`r0` itself will be the first entry. This is used when checking whether skolemized /// regions are being improperly related to other regions. - pub fn tainted(&self, mark: RegionMark, r0: Region) -> Vec { + pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec { debug!("tainted(mark={}, r0={})", mark, r0.repr(self.tcx)); let _indenter = indenter(); @@ -668,7 +673,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } } &AddCombination(..) | - &Mark | &AddVar(..) | &OpenSnapshot | &CommitedSnapshot => { diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index eaf363ffc74c2..12400de31ed9e 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -8,253 +8,108 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Resolution is the process of removing type variables and replacing -// them with their inferred values. Unfortunately our inference has -// become fairly complex and so there are a number of options to -// control *just how much* you want to resolve and how you want to do -// it. -// -// # Controlling the scope of resolution -// -// The options resolve_* determine what kinds of variables get -// resolved. Generally resolution starts with a top-level type -// variable; we will always resolve this. However, once we have -// resolved that variable, we may end up with a type that still -// contains type variables. For example, if we resolve `` we may -// end up with something like `[]`. If the option -// `resolve_nested_tvar` is passed, we will then go and recursively -// resolve ``. -// -// The options `resolve_rvar` controls whether we resolve region -// variables. The options `resolve_fvar` and `resolve_ivar` control -// whether we resolve floating point and integral variables, -// respectively. -// -// # What do if things are unconstrained -// -// Sometimes we will encounter a variable that has no constraints, and -// therefore cannot sensibly be mapped to any particular result. By -// default, we will leave such variables as is (so you will get back a -// variable in your result). The options force_* will cause the -// resolution to fail in this case instead, except for the case of -// integral variables, which resolve to `int` if forced. -// -// # resolve_all and force_all -// -// The options are a bit set, so you can use the *_all to resolve or -// force all kinds of variables (including those we may add in the -// future). If you want to resolve everything but one type, you are -// probably better off writing `resolve_all - resolve_ivar`. - -#![allow(non_upper_case_globals)] - -use super::{fixup_err, fres, InferCtxt}; -use super::{unresolved_int_ty,unresolved_float_ty,unresolved_ty}; - -use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid}; -use middle::ty::{IntType, UintType}; +use super::{InferCtxt, fixup_err, fres, unresolved_ty, unresolved_int_ty, unresolved_float_ty}; use middle::ty::{mod, Ty}; -use middle::ty_fold; -use syntax::codemap::Span; -use util::ppaux::{Repr, ty_to_string}; - -pub const resolve_nested_tvar: uint = 0b0000000001; -pub const resolve_rvar: uint = 0b0000000010; -pub const resolve_ivar: uint = 0b0000000100; -pub const resolve_fvar: uint = 0b0000001000; -pub const resolve_all: uint = 0b0000001111; -pub const force_tvar: uint = 0b0000100000; -pub const force_rvar: uint = 0b0001000000; -pub const force_ivar: uint = 0b0010000000; -pub const force_fvar: uint = 0b0100000000; -pub const force_all: uint = 0b0111100000; - -pub const not_regions: uint = !(force_rvar | resolve_rvar); - -pub const try_resolve_tvar_shallow: uint = 0; -pub const resolve_and_force_all_but_regions: uint = - (resolve_all | force_all) & not_regions; - -pub struct ResolveState<'a, 'tcx: 'a> { +use middle::ty_fold::{mod, TypeFoldable}; +use util::ppaux::Repr; + +/////////////////////////////////////////////////////////////////////////// +// OPPORTUNISTIC TYPE RESOLVER + +/// The opportunistic type resolver can be used at any time. It simply replaces +/// type variables that have been unified with the things they have +/// been unified with (similar to `shallow_resolve`, but deep). This is +/// useful for printing messages etc but also required at various +/// points for correctness. +pub struct OpportunisticTypeResolver<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - err: Option, - type_depth: uint, } -pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>, - modes: uint, - _: Option) - -> ResolveState<'a, 'tcx> { - ResolveState { - infcx: infcx, - modes: modes, - err: None, - type_depth: 0, +impl<'a, 'tcx> OpportunisticTypeResolver<'a, 'tcx> { + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> OpportunisticTypeResolver<'a, 'tcx> { + OpportunisticTypeResolver { infcx: infcx } } } -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'a, 'tcx> { +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for OpportunisticTypeResolver<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.infcx.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - self.resolve_type(t) - } - - fn fold_region(&mut self, r: ty::Region) -> ty::Region { - self.resolve_region(r) - } -} - -impl<'a, 'tcx> ResolveState<'a, 'tcx> { - pub fn should(&mut self, mode: uint) -> bool { - (self.modes & mode) == mode - } - - pub fn resolve_type_chk(&mut self, typ: Ty<'tcx>) -> fres> { - self.err = None; - - debug!("Resolving {} (modes={:x})", - ty_to_string(self.infcx.tcx, typ), - self.modes); - - // n.b. This is a hokey mess because the current fold doesn't - // allow us to pass back errors in any useful way. - - 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); - } - } - } - - pub fn resolve_region_chk(&mut self, - orig: ty::Region) - -> fres { - self.err = None; - let resolved = self.resolve_region(orig); - match self.err { - None => Ok(resolved), - Some(e) => Err(e) + if !ty::type_has_ty_infer(t) { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t0 = self.infcx.shallow_resolve(t); + ty_fold::super_fold_ty(self, t0) } } +} - pub fn resolve_type(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { - debug!("resolve_type({})", typ.repr(self.infcx.tcx)); - - if !ty::type_needs_infer(typ) { - return typ; - } - - if self.type_depth > 0 && !self.should(resolve_nested_tvar) { - return typ; - } - - match typ.sty { - ty::ty_infer(TyVar(vid)) => { - self.resolve_ty_var(vid) - } - ty::ty_infer(IntVar(vid)) => { - self.resolve_int_var(vid) - } - ty::ty_infer(FloatVar(vid)) => { - self.resolve_float_var(vid) - } - _ => { - if self.modes & resolve_all == 0 { - // if we are only resolving top-level type - // variables, and this is not a top-level type - // variable, then shortcircuit for efficiency - typ - } else { - self.type_depth += 1; - let result = ty_fold::super_fold_ty(self, typ); - self.type_depth -= 1; - result - } - } - } +/////////////////////////////////////////////////////////////////////////// +// FULL TYPE RESOLUTION + +/// Full type resolution replaces all type and region variables with +/// their concrete results. If any variable cannot be replaced (never unified, etc) +/// then an `Err` result is returned. +pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a,'tcx>, value: &T) -> fres + where T : TypeFoldable<'tcx> +{ + let mut full_resolver = FullTypeResolver { infcx: infcx, err: None }; + let result = value.fold_with(&mut full_resolver); + match full_resolver.err { + None => Ok(result), + Some(e) => Err(e), } +} - pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region { - debug!("Resolve_region({})", orig.repr(self.infcx.tcx)); - match orig { - ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid), - _ => orig - } - } +// N.B. This type is not public because the protocol around checking the +// `err` field is not enforcable otherwise. +struct FullTypeResolver<'a, 'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + err: Option, +} - pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region { - if !self.should(resolve_rvar) { - return ty::ReInfer(ty::ReVar(rid)); - } - self.infcx.region_vars.resolve_var(rid) +impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.infcx.tcx } - pub fn resolve_ty_var(&mut self, vid: TyVid) -> Ty<'tcx> { - let tcx = self.infcx.tcx; - let tv = self.infcx.type_variables.borrow(); - match tv.probe(vid) { - Some(t) => { - self.resolve_type(t) - } - None => { - if self.should(force_tvar) { + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !ty::type_needs_infer(t) { + t // micro-optimize -- if there is nothing in this type that this fold affects... + } else { + let t = self.infcx.shallow_resolve(t); + match t.sty { + ty::ty_infer(ty::TyVar(vid)) => { self.err = Some(unresolved_ty(vid)); + ty::mk_err() + } + ty::ty_infer(ty::IntVar(vid)) => { + self.err = Some(unresolved_int_ty(vid)); + ty::mk_err() + } + ty::ty_infer(ty::FloatVar(vid)) => { + self.err = Some(unresolved_float_ty(vid)); + ty::mk_err() + } + ty::ty_infer(_) => { + self.infcx.tcx.sess.bug( + format!("Unexpected type in full type resolver: {}", + t.repr(self.infcx.tcx))[]); + } + _ => { + ty_fold::super_fold_ty(self, t) } - ty::mk_var(tcx, vid) - } - } - } - - pub fn resolve_int_var(&mut self, vid: IntVid) -> Ty<'tcx> { - if !self.should(resolve_ivar) { - return ty::mk_int_var(self.infcx.tcx, vid); - } - - let tcx = self.infcx.tcx; - let table = &self.infcx.int_unification_table; - let node = table.borrow_mut().get(tcx, vid); - match node.value { - Some(IntType(t)) => ty::mk_mach_int(t), - Some(UintType(t)) => ty::mk_mach_uint(t), - None => { - if self.should(force_ivar) { - // As a last resort, emit an error. - self.err = Some(unresolved_int_ty(vid)); } - ty::mk_int_var(self.infcx.tcx, vid) - } } } - pub fn resolve_float_var(&mut self, vid: FloatVid) -> Ty<'tcx> { - if !self.should(resolve_fvar) { - return ty::mk_float_var(self.infcx.tcx, vid); - } - - let tcx = self.infcx.tcx; - let table = &self.infcx.float_unification_table; - let node = table.borrow_mut().get(tcx, vid); - match node.value { - Some(t) => ty::mk_mach_float(t), - None => { - if self.should(force_fvar) { - // As a last resort, emit an error. - self.err = Some(unresolved_float_ty(vid)); - } - ty::mk_float_var(self.infcx.tcx, vid) - } + fn fold_region(&mut self, r: ty::Region) -> ty::Region { + match r { + ty::ReInfer(ty::ReVar(rid)) => self.infcx.region_vars.resolve_var(rid), + _ => r, } } } + diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 00c79bc726cf6..2b8adfb7c1eeb 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -155,13 +155,9 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } } - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> { - self.higher_ranked_sub(a, b) - } - - fn trait_refs(&self, a: &ty::TraitRef<'tcx>, b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> { + fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> + where T : Combineable<'tcx> + { self.higher_ranked_sub(a, b) } } diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 766e930486ca2..0d7f542535c2f 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -13,7 +13,9 @@ use self::TypeVariableValue::*; use self::UndoEntry::*; use middle::ty::{mod, Ty}; +use std::cmp::min; use std::mem; +use std::uint; use util::snapshot_vec as sv; pub struct TypeVariableTable<'tcx> { @@ -78,7 +80,6 @@ impl<'tcx> TypeVariableTable<'tcx> { /// /// Precondition: neither `a` nor `b` are known. pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { - if a != b { self.relations(a).push((dir, b)); self.relations(b).push((dir.opposite(), a)); @@ -151,6 +152,49 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn commit(&mut self, s: Snapshot) { self.values.commit(s.snapshot); } + + pub fn types_escaping_snapshot(&self, s: &Snapshot) -> Vec> { + /*! + * Find the set of type variables that existed *before* `s` + * but which have only been unified since `s` started, and + * return the types with which they were unified. So if we had + * a type variable `V0`, then we started the snapshot, then we + * created a type variable `V1`, unifed `V0` with `T0`, and + * unified `V1` with `T1`, this function would return `{T0}`. + */ + + let mut new_elem_threshold = uint::MAX; + let mut escaping_types = Vec::new(); + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); + for action in actions_since_snapshot.iter() { + match *action { + sv::UndoLog::NewElem(index) => { + // if any new variables were created during the + // snapshot, remember the lower index (which will + // always be the first one we see). Note that this + // action must precede those variables being + // specified. + new_elem_threshold = min(new_elem_threshold, index); + debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); + } + + sv::UndoLog::Other(SpecifyVar(vid, _)) => { + if vid.index < new_elem_threshold { + // quick check to see if this variable was + // created since the snapshot started or not. + let escaping_type = self.probe(vid).unwrap(); + escaping_types.push(escaping_type); + } + debug!("SpecifyVar({}) new_elem_threshold={}", vid, new_elem_threshold); + } + + _ => { } + } + } + + escaping_types + } } impl<'tcx> sv::SnapshotVecDelegate,UndoEntry> for Delegate { diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index acfdf6fefb55f..ea19111ce3d67 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -124,8 +124,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> { let typ = ty::node_id_to_type(self.tcx, expr.id); match typ.sty { ty_bare_fn(ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { - if let ty::FnConverging(to) = bare_fn_ty.sig.output { - let from = bare_fn_ty.sig.inputs[0]; + if let ty::FnConverging(to) = bare_fn_ty.sig.0.output { + let from = bare_fn_ty.sig.0.inputs[0]; self.check_transmute(expr.span, from, to, expr.id); } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index c76d9bc6b1faa..4df655882b155 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1534,6 +1534,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { .unwrap() .closure_type .sig + .0 .output, _ => ty::ty_fn_ret(fn_ty) } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 1923142be9e3f..33701905aa110 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -108,7 +108,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { ast::ItemTy(_, ref generics) | ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | - ast::ItemTrait(_, ref generics, _, _, _) => { + ast::ItemTrait(_, ref generics, _, _, _) | + ast::ItemImpl(_, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. let lifetimes = &generics.lifetimes; let early_scope = EarlyScope(subst::TypeSpace, lifetimes, &ROOT_SCOPE); @@ -117,12 +118,6 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { visit::walk_item(this, item); }); } - ast::ItemImpl(_, ref generics, _, _, _) => { - // Impls have both early- and late-bound lifetimes. - this.visit_early_late(subst::TypeSpace, generics, |this| { - visit::walk_item(this, item); - }) - } } }); } diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 822979c86017b..9804f6d222afd 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,7 +17,8 @@ use super::util; use middle::subst; use middle::subst::Subst; use middle::ty::{mod, Ty}; -use middle::infer::{mod, InferCtxt}; +use middle::infer::InferCtxt; +use std::rc::Rc; use syntax::ast; use syntax::codemap::DUMMY_SP; use util::ppaux::Repr; @@ -37,18 +38,14 @@ pub fn impl_can_satisfy(infcx: &InferCtxt, let impl1_substs = util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id); let impl1_trait_ref = - ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap() - .subst(infcx.tcx, &impl1_substs); - let impl1_trait_ref = - infcx.replace_late_bound_regions_with_fresh_var(DUMMY_SP, - infer::FnCall, - &impl1_trait_ref).0; + (*ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()).subst(infcx.tcx, &impl1_substs); // Determine whether `impl2` can provide an implementation for those // same types. let param_env = ty::empty_parameter_environment(); let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx); - let obligation = Obligation::new(ObligationCause::dummy(), impl1_trait_ref); + let obligation = Obligation::new(ObligationCause::dummy(), + Rc::new(ty::Binder(impl1_trait_ref))); debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx)); selcx.evaluate_impl(impl2_def_id, &obligation) } @@ -143,7 +140,7 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::ty_trait(ref tt) => { - tt.principal.def_id.krate == ast::LOCAL_CRATE + tt.principal.def_id().krate == ast::LOCAL_CRATE } // Type parameters may be bound to types that are not local to diff --git a/src/librustc/middle/traits/doc.rs b/src/librustc/middle/traits/doc.rs index 62246b77ee940..80697cb3a41db 100644 --- a/src/librustc/middle/traits/doc.rs +++ b/src/librustc/middle/traits/doc.rs @@ -8,399 +8,513 @@ // 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. It may also require evaluating those nested -//! obligations to resolve ambiguities. -//! -//! - 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. -//! -//! The basic idea for candidate assembly is to do a first pass in which -//! we identify all possible candidates. During this pass, all that we do -//! is try and unify the type parameters. (In particular, we ignore any -//! nested where clauses.) Presuming that this unification succeeds, the -//! impl is added as a candidate. -//! -//! Once this first pass is done, we can examine the set of candidates. If -//! it is a singleton set, then we are done: this is the only impl in -//! scope that could possibly apply. Otherwise, we can winnow down the set -//! of candidates by using where clauses and other conditions. If this -//! reduced set yields a single, unambiguous entry, we're good to go, -//! otherwise the result is considered ambiguous. -//! -//! #### The basic process: Inferring based on the impls we see -//! -//! This process is easier if we work through some examples. Consider -//! the following trait: -//! -//! ``` -//! trait Convert { -//! fn convert(&self) -> Target; -//! } -//! ``` -//! -//! This trait just has one method. It's about as simple as it gets. It -//! converts from the (implicit) `Self` type to the `Target` type. If we -//! wanted to permit conversion between `int` and `uint`, we might -//! implement `Convert` like so: -//! -//! ```rust -//! impl Convert for int { ... } // int -> uint -//! impl Convert for uint { ... } // uint -> uint -//! ``` -//! -//! Now imagine there is some code like the following: -//! -//! ```rust -//! let x: int = ...; -//! let y = x.convert(); -//! ``` -//! -//! The call to convert will generate a trait reference `Convert<$Y> for -//! int`, where `$Y` is the type variable representing the type of -//! `y`. When we match this against the two impls we can see, we will find -//! that only one remains: `Convert for int`. Therefore, we can -//! select this impl, which will cause the type of `$Y` to be unified to -//! `uint`. (Note that while assembling candidates, we do the initial -//! unifications in a transaction, so that they don't affect one another.) -//! -//! There are tests to this effect in src/test/run-pass: -//! -//! traits-multidispatch-infer-convert-source-and-target.rs -//! traits-multidispatch-infer-convert-target.rs -//! -//! #### Winnowing: Resolving ambiguities -//! -//! But what happens if there are multiple impls where all the types -//! unify? Consider this example: -//! -//! ```rust -//! trait Get { -//! fn get(&self) -> Self; -//! } -//! -//! impl Get for T { -//! fn get(&self) -> T { *self } -//! } -//! -//! impl Get for Box { -//! fn get(&self) -> Box { box get_it(&**self) } -//! } -//! ``` -//! -//! What happens when we invoke `get_it(&box 1_u16)`, for example? In this -//! case, the `Self` type is `Box` -- that unifies with both impls, -//! because the first applies to all types, and the second to all -//! boxes. In the olden days we'd have called this ambiguous. But what we -//! do now is do a second *winnowing* pass that considers where clauses -//! and attempts to remove candidates -- in this case, the first impl only -//! applies if `Box : Copy`, which doesn't hold. After winnowing, -//! then, we are left with just one candidate, so we can proceed. There is -//! a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`. -//! -//! #### 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 reflected in -//! the fact that subregion assignment is infallible. 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. -//! -//! ## Method matching -//! -//! Method dispach follows a slightly different path than normal trait -//! selection. This is because it must account for the transformed self -//! type of the receiver and various other complications. The procedure is -//! described in `select.rs` in the "METHOD MATCHING" section. -//! -//! # Caching and subtle considerations therewith -//! -//! In general we attempt to cache the results of trait selection. This -//! is a somewhat complex process. Part of the reason for this is that we -//! want to be able to cache results even when all the types in the trait -//! reference are not fully known. In that case, it may happen that the -//! trait selection process is also influencing type variables, so we have -//! to be able to not only cache the *result* of the selection process, -//! but *replay* its effects on the type variables. -//! -//! ## An example -//! -//! The high-level idea of how the cache works is that we first replace -//! all unbound inference variables with skolemized versions. Therefore, -//! if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound -//! inference variable, we might replace it with `uint : Foo<%0>`, where -//! `%n` is a skolemized type. We would then look this up in the cache. -//! If we found a hit, the hit would tell us the immediate next step to -//! take in the selection process: i.e., apply impl #22, or apply where -//! clause `X : Foo`. Let's say in this case there is no hit. -//! Therefore, we search through impls and where clauses and so forth, and -//! we come to the conclusion that the only possible impl is this one, -//! with def-id 22: -//! -//! impl Foo for uint { ... } // Impl #22 -//! -//! We would then record in the cache `uint : Foo<%0> ==> -//! ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which -//! would (as a side-effect) unify `$1` with `int`. -//! -//! Now, at some later time, we might come along and see a `uint : -//! Foo<$3>`. When skolemized, this would yield `uint : Foo<%0>`, just as -//! before, and hence the cache lookup would succeed, yielding -//! `ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would -//! (as a side-effect) unify `$3` with `int`. -//! -//! ## Where clauses and the local vs global cache -//! -//! One subtle interaction is that the results of trait lookup will vary -//! depending on what where clauses are in scope. Therefore, we actually -//! have *two* caches, a local and a global cache. The local cache is -//! attached to the `ParameterEnvironment` and the global cache attached -//! to the `tcx`. We use the local cache whenever the result might depend -//! on the where clauses that are in scope. The determination of which -//! cache to use is done by the method `pick_candidate_cache` in -//! `select.rs`. -//! -//! There are two cases where we currently use the local cache. The -//! current rules are probably more conservative than necessary. -//! -//! ### Trait references that involve parameter types -//! -//! The most obvious case where you need the local environment is -//! when the trait reference includes parameter types. For example, -//! consider the following function: -//! -//! impl Vec { -//! fn foo(x: T) -//! where T : Foo -//! { ... } -//! -//! fn bar(x: T) -//! { ... } -//! } -//! -//! If there is an obligation `T : Foo`, or `int : Bar`, or whatever, -//! clearly the results from `foo` and `bar` are potentially different, -//! since the set of where clauses in scope are different. -//! -//! ### Trait references with unbound variables when where clauses are in scope -//! -//! There is another less obvious interaction which involves unbound variables -//! where *only* where clauses are in scope (no impls). This manifested as -//! issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider -//! this snippet: -//! -//! ``` -//! pub trait Foo { -//! fn load_from() -> Box; -//! fn load() -> Box { -//! Foo::load_from() -//! } -//! } -//! ``` -//! -//! The default method will incur an obligation `$0 : Foo` from the call -//! to `load_from`. If there are no impls, this can be eagerly resolved to -//! `VtableParam(Self : Foo)` and cached. Because the trait reference -//! doesn't involve any parameters types (only the resolution does), this -//! result was stored in the global cache, causing later calls to -//! `Foo::load_from()` to get nonsense. -//! -//! To fix this, we always use the local cache if there are unbound -//! variables and where clauses in scope. This is more conservative than -//! necessary as far as I can tell. However, it still seems to be a simple -//! rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt -//! us in particular. -//! -//! Here is an example of the kind of subtle case that I would be worried -//! about with a more complex rule (although this particular case works -//! out ok). Imagine the trait reference doesn't directly reference a -//! where clause, but the where clause plays a role in the winnowing -//! phase. Something like this: -//! -//! ``` -//! pub trait Foo { ... } -//! pub trait Bar { ... } -//! impl Foo for T { ... } // Impl A -//! impl Foo for uint { ... } // Impl B -//! ``` -//! -//! Now, in some function, we have no where clauses in scope, and we have -//! an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char` -//! and `$1=uint`: this is because for impl A to apply, `uint:Bar` would -//! have to hold, and we know it does not or else the coherence check -//! would have failed. So we might enter into our global cache: `$1 : -//! Foo<$0> => Impl B`. Then we come along in a different scope, where a -//! generic type `A` is around with the bound `A:Bar`. Now suddenly the -//! impl is viable. -//! -//! The flaw in this imaginary DOOMSDAY SCENARIO is that we would not -//! currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and -//! `$1 == char`, even though it is true that (absent type parameters) -//! there is no other type the user could enter. However, it is not -//! *completely* implausible that we *could* draw this conclusion in the -//! future; we wouldn't have to guess types, in particular, we could be -//! led by the impls. +/*! + +# 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. It may also require evaluating those nested + obligations to resolve ambiguities. + +- 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. + +The basic idea for candidate assembly is to do a first pass in which +we identify all possible candidates. During this pass, all that we do +is try and unify the type parameters. (In particular, we ignore any +nested where clauses.) Presuming that this unification succeeds, the +impl is added as a candidate. + +Once this first pass is done, we can examine the set of candidates. If +it is a singleton set, then we are done: this is the only impl in +scope that could possibly apply. Otherwise, we can winnow down the set +of candidates by using where clauses and other conditions. If this +reduced set yields a single, unambiguous entry, we're good to go, +otherwise the result is considered ambiguous. + +#### The basic process: Inferring based on the impls we see + +This process is easier if we work through some examples. Consider +the following trait: + +``` +trait Convert { + fn convert(&self) -> Target; +} +``` + +This trait just has one method. It's about as simple as it gets. It +converts from the (implicit) `Self` type to the `Target` type. If we +wanted to permit conversion between `int` and `uint`, we might +implement `Convert` like so: + +```rust +impl Convert for int { ... } // int -> uint +impl Convert for uint { ... } // uint -> uint +``` + +Now imagine there is some code like the following: + +```rust +let x: int = ...; +let y = x.convert(); +``` + +The call to convert will generate a trait reference `Convert<$Y> for +int`, where `$Y` is the type variable representing the type of +`y`. When we match this against the two impls we can see, we will find +that only one remains: `Convert for int`. Therefore, we can +select this impl, which will cause the type of `$Y` to be unified to +`uint`. (Note that while assembling candidates, we do the initial +unifications in a transaction, so that they don't affect one another.) + +There are tests to this effect in src/test/run-pass: + + traits-multidispatch-infer-convert-source-and-target.rs + traits-multidispatch-infer-convert-target.rs + +#### Winnowing: Resolving ambiguities + +But what happens if there are multiple impls where all the types +unify? Consider this example: + +```rust +trait Get { + fn get(&self) -> Self; +} + +impl Get for T { + fn get(&self) -> T { *self } +} + +impl Get for Box { + fn get(&self) -> Box { box get_it(&**self) } +} +``` + +What happens when we invoke `get_it(&box 1_u16)`, for example? In this +case, the `Self` type is `Box` -- that unifies with both impls, +because the first applies to all types, and the second to all +boxes. In the olden days we'd have called this ambiguous. But what we +do now is do a second *winnowing* pass that considers where clauses +and attempts to remove candidates -- in this case, the first impl only +applies if `Box : Copy`, which doesn't hold. After winnowing, +then, we are left with just one candidate, so we can proceed. There is +a test of this in `src/test/run-pass/traits-conditional-dispatch.rs`. + +#### 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 reflected in +the fact that subregion assignment is infallible. 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. + +# Higher-ranked trait bounds + +One of the more subtle concepts at work are *higher-ranked trait +bounds*. An example of such a bound is `for<'a> MyTrait<&'a int>`. +Let's walk through how selection on higher-ranked trait references +works. + +## Basic matching and skolemization leaks + +Let's walk through the test `compile-fail/hrtb-just-for-static.rs` to see +how it works. The test starts with the trait `Foo`: + +```rust +trait Foo { + fn foo(&self, x: X) { } +} +``` + +Let's say we have a function `want_hrtb` that wants a type which +implements `Foo<&'a int>` for any `'a`: + +```rust +fn want_hrtb() where T : for<'a> Foo<&'a int> { ... } +``` + +Now we have a struct `AnyInt` that implements `Foo<&'a int>` for any +`'a`: + +```rust +struct AnyInt; +impl<'a> Foo<&'a int> for AnyInt { } +``` + +And the question is, does `AnyInt : for<'a> Foo<&'a int>`? We want the +answer to be yes. The algorithm for figuring it out is closely related +to the subtyping for higher-ranked types (which is described in +`middle::infer::higher_ranked::doc`, but also in a [paper by SPJ] that +I recommend you read). + +1. Skolemize the obligation. +2. Match the impl against the skolemized obligation. +3. Check for skolemization leaks. + +[paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ + +So let's work through our example. The first thing we would do is to +skolemize the obligation, yielding `AnyInt : Foo<&'0 int>` (here `'0` +represents skolemized region #0). Note that now have no quantifiers; +in terms of the compiler type, this changes from a `ty::PolyTraitRef` +to a `TraitRef`. We would then create the `TraitRef` from the impl, +using fresh variables for it's bound regions (and thus getting +`Foo<&'$a int>`, where `'$a` is the inference variable for `'a`). Next +we relate the two trait refs, yielding a graph with the constraint +that `'0 == '$a`. Finally, we check for skolemization "leaks" -- a +leak is basically any attempt to relate a skolemized region to another +skolemized region, or to any region that pre-existed the impl match. +The leak check is done by searching from the skolemized region to find +the set of regions that it is related to in any way. This is called +the "taint" set. To pass the check, that set must consist *solely* of +itself and region variables from the impl. If the taint set includes +any other region, then the match is a failure. In this case, the taint +set for `'0` is `{'0, '$a}`, and hence the check will succeed. + +Let's consider a failure case. Imagine we also have a struct + +```rust +struct StaticInt; +impl Foo<&'static int> for StaticInt; +``` + +We want the obligation `StaticInt : for<'a> Foo<&'a int>` to be +considered unsatisfied. The check begins just as before. `'a` is +skolemized to `'0` and the impl trait reference is instantiated to +`Foo<&'static int>`. When we relate those two, we get a constraint +like `'static == '0`. This means that the taint set for `'0` is `{'0, +'static}`, which fails the leak check. + +## Higher-ranked trait obligations + +Once the basic matching is done, we get to another interesting topic: +how to deal with impl obligations. I'll work through a simple example +here. Imagine we have the traits `Foo` and `Bar` and an associated impl: + +``` +trait Foo { + fn foo(&self, x: X) { } +} + +trait Bar { + fn bar(&self, x: X) { } +} + +impl Foo for F + where F : Bar +{ +} +``` + +Now let's say we have a obligation `for<'a> Foo<&'a int>` and we match +this impl. What obligation is generated as a result? We want to get +`for<'a> Bar<&'a int>`, but how does that happen? + +After the matching, we are in a position where we have a skolemized +substitution like `X => &'0 int`. If we apply this substitution to the +impl obligations, we get `F : Bar<&'0 int>`. Obviously this is not +directly usable because the skolemized region `'0` cannot leak out of +our computation. + +What we do is to create an inverse mapping from the taint set of `'0` +back to the original bound region (`'a`, here) that `'0` resulted +from. (This is done in `higher_ranked::plug_leaks`). We know that the +leak check passed, so this taint set consists solely of the skolemized +region itself plus various intermediate region variables. We then walk +the trait-reference and convert every region in that taint set back to +a late-bound region, so in this case we'd wind up with `for<'a> F : +Bar<&'a int>`. + +# Caching and subtle considerations therewith + +In general we attempt to cache the results of trait selection. This +is a somewhat complex process. Part of the reason for this is that we +want to be able to cache results even when all the types in the trait +reference are not fully known. In that case, it may happen that the +trait selection process is also influencing type variables, so we have +to be able to not only cache the *result* of the selection process, +but *replay* its effects on the type variables. + +## An example + +The high-level idea of how the cache works is that we first replace +all unbound inference variables with skolemized versions. Therefore, +if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound +inference variable, we might replace it with `uint : Foo<%0>`, where +`%n` is a skolemized type. We would then look this up in the cache. +If we found a hit, the hit would tell us the immediate next step to +take in the selection process: i.e., apply impl #22, or apply where +clause `X : Foo`. Let's say in this case there is no hit. +Therefore, we search through impls and where clauses and so forth, and +we come to the conclusion that the only possible impl is this one, +with def-id 22: + + impl Foo for uint { ... } // Impl #22 + +We would then record in the cache `uint : Foo<%0> ==> +ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which +would (as a side-effect) unify `$1` with `int`. + +Now, at some later time, we might come along and see a `uint : +Foo<$3>`. When skolemized, this would yield `uint : Foo<%0>`, just as +before, and hence the cache lookup would succeed, yielding +`ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would +(as a side-effect) unify `$3` with `int`. + +## Where clauses and the local vs global cache + +One subtle interaction is that the results of trait lookup will vary +depending on what where clauses are in scope. Therefore, we actually +have *two* caches, a local and a global cache. The local cache is +attached to the `ParameterEnvironment` and the global cache attached +to the `tcx`. We use the local cache whenever the result might depend +on the where clauses that are in scope. The determination of which +cache to use is done by the method `pick_candidate_cache` in +`select.rs`. + +There are two cases where we currently use the local cache. The +current rules are probably more conservative than necessary. + +### Trait references that involve parameter types + +The most obvious case where you need the local environment is +when the trait reference includes parameter types. For example, +consider the following function: + + impl Vec { + fn foo(x: T) + where T : Foo + { ... } + + fn bar(x: T) + { ... } + } + +If there is an obligation `T : Foo`, or `int : Bar`, or whatever, +clearly the results from `foo` and `bar` are potentially different, +since the set of where clauses in scope are different. + +### Trait references with unbound variables when where clauses are in scope + +There is another less obvious interaction which involves unbound variables +where *only* where clauses are in scope (no impls). This manifested as +issue #18209 (`run-pass/trait-cache-issue-18209.rs`). Consider +this snippet: + +``` +pub trait Foo { + fn load_from() -> Box; + fn load() -> Box { + Foo::load_from() + } +} +``` + +The default method will incur an obligation `$0 : Foo` from the call +to `load_from`. If there are no impls, this can be eagerly resolved to +`VtableParam(Self : Foo)` and cached. Because the trait reference +doesn't involve any parameters types (only the resolution does), this +result was stored in the global cache, causing later calls to +`Foo::load_from()` to get nonsense. + +To fix this, we always use the local cache if there are unbound +variables and where clauses in scope. This is more conservative than +necessary as far as I can tell. However, it still seems to be a simple +rule and I observe ~99% hit rate on rustc, so it doesn't seem to hurt +us in particular. + +Here is an example of the kind of subtle case that I would be worried +about with a more complex rule (although this particular case works +out ok). Imagine the trait reference doesn't directly reference a +where clause, but the where clause plays a role in the winnowing +phase. Something like this: + +``` +pub trait Foo { ... } +pub trait Bar { ... } +impl Foo for T { ... } // Impl A +impl Foo for uint { ... } // Impl B +``` + +Now, in some function, we have no where clauses in scope, and we have +an obligation `$1 : Foo<$0>`. We might then conclude that `$0=char` +and `$1=uint`: this is because for impl A to apply, `uint:Bar` would +have to hold, and we know it does not or else the coherence check +would have failed. So we might enter into our global cache: `$1 : +Foo<$0> => Impl B`. Then we come along in a different scope, where a +generic type `A` is around with the bound `A:Bar`. Now suddenly the +impl is viable. + +The flaw in this imaginary DOOMSDAY SCENARIO is that we would not +currently conclude that `$1 : Foo<$0>` implies that `$0 == uint` and +`$1 == char`, even though it is true that (absent type parameters) +there is no other type the user could enter. However, it is not +*completely* implausible that we *could* draw this conclusion in the +future; we wouldn't have to guess types, in particular, we could be +led by the impls. + +*/ diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 412c188f5f4ae..213d97b4b344a 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::infer::InferCtxt; use middle::mem_categorization::Typer; use middle::ty::{mod, Ty}; -use middle::infer::{mod, InferCtxt}; use std::collections::HashSet; use std::collections::hash_map::{Occupied, Vacant}; use std::default::Default; @@ -28,7 +28,7 @@ use super::ObligationCause; use super::PredicateObligation; use super::Selection; use super::select::SelectionContext; -use super::trait_ref_for_builtin_bound; +use super::poly_trait_ref_for_builtin_bound; use super::Unimplemented; /// The fulfillment context is used to drive trait resolution. It @@ -107,7 +107,7 @@ impl<'tcx> FulfillmentContext<'tcx> { builtin_bound: ty::BuiltinBound, cause: ObligationCause<'tcx>) { - match trait_ref_for_builtin_bound(tcx, builtin_bound, ty) { + match poly_trait_ref_for_builtin_bound(tcx, builtin_bound, ty) { Ok(trait_ref) => { self.register_trait_ref(tcx, trait_ref, cause); } @@ -117,7 +117,7 @@ impl<'tcx> FulfillmentContext<'tcx> { pub fn register_trait_ref<'a>(&mut self, tcx: &ty::ctxt<'tcx>, - trait_ref: Rc>, + trait_ref: Rc>, cause: ObligationCause<'tcx>) { /*! @@ -329,30 +329,47 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, } } - ty::Predicate::Equate(a, b) => { - let origin = infer::EquatePredicate(predicate.cause.span); - match infer::mk_eqty(selcx.infcx(), false, origin, a, b) { - Ok(()) => { - true - } + ty::Predicate::Equate(ref binder) => { + match selcx.infcx().equality_predicate(predicate.cause.span, binder) { + Ok(()) => { } Err(_) => { errors.push( FulfillmentError::new( predicate.clone(), CodeSelectionError(Unimplemented))); - true } } + true } - ty::Predicate::RegionOutlives(r_a, r_b) => { - let origin = infer::RelateRegionParamBound(predicate.cause.span); - let () = infer::mk_subr(selcx.infcx(), origin, r_b, r_a); // `b : a` ==> `a <= b` + ty::Predicate::RegionOutlives(ref binder) => { + match selcx.infcx().region_outlives_predicate(predicate.cause.span, binder) { + Ok(()) => { } + Err(_) => { + errors.push( + FulfillmentError::new( + predicate.clone(), + CodeSelectionError(Unimplemented))); + } + } + true } - ty::Predicate::TypeOutlives(t_a, r_b) => { - register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); + ty::Predicate::TypeOutlives(ref binder) => { + // For now, we just check that there are no higher-ranked + // regions. If there are, we will call this obligation an + // error. Eventually we should be able to support some + // cases here, I imagine (e.g., `for<'a> int : 'a`). + if ty::count_late_bound_regions(selcx.tcx(), binder) != 0 { + errors.push( + FulfillmentError::new( + predicate.clone(), + CodeSelectionError(Unimplemented))); + } else { + let ty::OutlivesPredicate(t_a, r_b) = binder.0; + register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations); + } true } } @@ -385,3 +402,4 @@ fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>, } } + diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 936304c5eb483..3289acd0c2e5e 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -33,7 +33,7 @@ pub use self::util::supertraits; pub use self::util::Supertraits; pub use self::util::search_trait_and_supertraits_from_bound; pub use self::util::transitive_bounds; -pub use self::util::trait_ref_for_builtin_bound; +pub use self::util::poly_trait_ref_for_builtin_bound; mod coherence; mod fulfill; @@ -54,7 +54,7 @@ pub struct Obligation<'tcx, T> { } pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; -pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; +pub type TraitObligation<'tcx> = Obligation<'tcx, Rc>>; /// Why did we incur this obligation? Used for error reporting. #[deriving(Copy, Clone)] @@ -115,7 +115,9 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; pub enum SelectionError<'tcx> { Unimplemented, Overflow, - OutputTypeParameterMismatch(Rc>, Rc>, ty::type_err<'tcx>), + OutputTypeParameterMismatch(Rc>, + Rc>, + ty::type_err<'tcx>), } pub struct FulfillmentError<'tcx> { @@ -226,7 +228,7 @@ pub struct VtableBuiltinData { #[deriving(PartialEq,Eq,Clone)] pub struct VtableParamData<'tcx> { // In the above example, this would `Eq` - pub bound: Rc>, + pub bound: Rc>, } /// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl @@ -278,7 +280,7 @@ impl<'tcx,O> Obligation<'tcx,O> { } } -impl<'tcx> Obligation<'tcx,Rc>> { +impl<'tcx> TraitObligation<'tcx> { pub fn self_ty(&self) -> Ty<'tcx> { self.trait_ref.self_ty() } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index f551ff061654a..6c7ae666ae06c 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -28,9 +28,9 @@ use super::{util}; use middle::fast_reject; use middle::mem_categorization::Typer; use middle::subst::{Subst, Substs, VecPerParamSpace}; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, AsPredicate, RegionEscape, Ty}; use middle::infer; -use middle::infer::{InferCtxt, TypeSkolemizer}; +use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; use std::cell::RefCell; use std::collections::hash_map::HashMap; @@ -44,12 +44,12 @@ pub struct SelectionContext<'cx, 'tcx:'cx> { param_env: &'cx ty::ParameterEnvironment<'tcx>, typer: &'cx (Typer<'tcx>+'cx), - /// Skolemizer used specifically for skolemizing entries on the + /// Freshener used specifically for skolemizing entries on the /// obligation stack. This ensures that all entries on the stack /// at one time will have the same set of skolemized entries, /// which is important for checking for trait bounds that /// recursively require themselves. - skolemizer: TypeSkolemizer<'cx, 'tcx>, + freshener: TypeFreshener<'cx, 'tcx>, /// If true, indicates that the evaluation should be conservative /// and consider the possibility of types outside this crate. @@ -73,15 +73,15 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { obligation: &'prev TraitObligation<'tcx>, /// Trait ref from `obligation` but skolemized with the - /// selection-context's skolemizer. Used to check for recursion. - skol_trait_ref: Rc>, + /// selection-context's freshener. Used to check for recursion. + fresh_trait_ref: Rc>, previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> } #[deriving(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell>, + hashmap: RefCell>, SelectionResult<'tcx, Candidate<'tcx>>>>, } @@ -172,7 +172,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: infcx, param_env: param_env, typer: typer, - skolemizer: infcx.skolemizer(), + freshener: infcx.freshener(), intercrate: false, } } @@ -185,7 +185,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: infcx, param_env: param_env, typer: typer, - skolemizer: infcx.skolemizer(), + freshener: infcx.freshener(), intercrate: true, } } @@ -288,8 +288,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.evaluate_obligation_recursively(previous_stack, &obligation) } - ty::Predicate::Equate(a, b) => { - match infer::can_mk_eqty(self.infcx, a, b) { + ty::Predicate::Equate(ref p) => { + let result = self.infcx.probe(|_| { + self.infcx.equality_predicate(obligation.cause.span, p) + }); + match result { Ok(()) => EvaluatedToOk, Err(_) => EvaluatedToErr(Unimplemented), } @@ -347,16 +350,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This suffices to allow chains like `FnMut` implemented in // terms of `Fn` etc, but we could probably make this more // precise still. - let input_types = stack.skol_trait_ref.input_types(); - let unbound_input_types = input_types.iter().any(|&t| ty::type_is_skolemized(t)); + let input_types = stack.fresh_trait_ref.0.input_types(); + let unbound_input_types = input_types.iter().any(|&t| ty::type_is_fresh(t)); if unbound_input_types && (self.intercrate || stack.iter().skip(1).any( - |prev| stack.skol_trait_ref.def_id == prev.skol_trait_ref.def_id)) + |prev| stack.fresh_trait_ref.def_id() == prev.fresh_trait_ref.def_id())) { debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous", - stack.skol_trait_ref.repr(self.tcx())); + stack.fresh_trait_ref.repr(self.tcx())); return EvaluatedToAmbig; } @@ -373,19 +376,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Option>>` is `Send` if `Box>` is // `Send`. // - // Note that we do this comparison using the `skol_trait_ref` + // Note that we do this comparison using the `fresh_trait_ref` // fields. Because these have all been skolemized using - // `self.skolemizer`, we can be sure that (a) this will not + // `self.freshener`, we can be sure that (a) this will not // affect the inferencer state and (b) that if we see two // skolemized types with the same index, they refer to the // same unbound type variable. if stack.iter() .skip(1) // skip top-most frame - .any(|prev| stack.skol_trait_ref == prev.skol_trait_ref) + .any(|prev| stack.fresh_trait_ref == prev.fresh_trait_ref) { debug!("evaluate_stack({}) --> recursive", - stack.skol_trait_ref.repr(self.tcx())); + stack.fresh_trait_ref.repr(self.tcx())); return EvaluatedToOk; } @@ -407,13 +410,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id.repr(self.tcx()), obligation.repr(self.tcx())); - self.infcx.probe(|| { - match self.match_impl(impl_def_id, obligation) { + self.infcx.probe(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot); + match self.match_impl(impl_def_id, obligation, snapshot, + &skol_map, Rc::new(skol_obligation_trait_ref)) { Ok(substs) => { let vtable_impl = self.vtable_impl(impl_def_id, substs, obligation.cause, - obligation.recursion_depth + 1); + obligation.recursion_depth + 1, + skol_map, + snapshot); self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply() } Err(()) => { @@ -445,20 +453,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Check the cache. Note that we skolemize the trait-ref - // separately rather than using `stack.skol_trait_ref` -- this + // separately rather than using `stack.fresh_trait_ref` -- this // is because we want the unbound variables to be replaced // with fresh skolemized types starting from index 0. - let cache_skol_trait_ref = - self.infcx.skolemize(stack.obligation.trait_ref.clone()); - debug!("candidate_from_obligation(cache_skol_trait_ref={}, obligation={})", - cache_skol_trait_ref.repr(self.tcx()), + let cache_fresh_trait_ref = + self.infcx.freshen(stack.obligation.trait_ref.clone()); + debug!("candidate_from_obligation(cache_fresh_trait_ref={}, obligation={})", + cache_fresh_trait_ref.repr(self.tcx()), stack.repr(self.tcx())); assert!(!stack.obligation.trait_ref.has_escaping_regions()); - match self.check_candidate_cache(cache_skol_trait_ref.clone()) { + match self.check_candidate_cache(cache_fresh_trait_ref.clone()) { Some(c) => { - debug!("CACHE HIT: cache_skol_trait_ref={}, candidate={}", - cache_skol_trait_ref.repr(self.tcx()), + debug!("CACHE HIT: cache_fresh_trait_ref={}, candidate={}", + cache_fresh_trait_ref.repr(self.tcx()), c.repr(self.tcx())); return c; } @@ -467,9 +475,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If no match, compute result and insert into cache. let candidate = self.candidate_from_obligation_no_cache(stack); - debug!("CACHE MISS: cache_skol_trait_ref={}, candidate={}", - cache_skol_trait_ref.repr(self.tcx()), candidate.repr(self.tcx())); - self.insert_candidate_cache(cache_skol_trait_ref, candidate.clone()); + debug!("CACHE MISS: cache_fresh_trait_ref={}, candidate={}", + cache_fresh_trait_ref.repr(self.tcx()), candidate.repr(self.tcx())); + self.insert_candidate_cache(cache_fresh_trait_ref, candidate.clone()); candidate } @@ -569,7 +577,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn pick_candidate_cache(&self, - cache_skol_trait_ref: &Rc>) + cache_fresh_trait_ref: &Rc>) -> &SelectionCache<'tcx> { // High-level idea: we have to decide whether to consult the @@ -591,7 +599,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If the trait refers to any parameters in scope, then use // the cache of the param-environment. if - cache_skol_trait_ref.input_types().iter().any( + cache_fresh_trait_ref.0.input_types().iter().any( |&t| ty::type_has_self(t) || ty::type_has_params(t)) { return &self.param_env.selection_cache; @@ -604,7 +612,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // See the discussion in doc.rs for more details. if !self.param_env.caller_bounds.is_empty() && - cache_skol_trait_ref.input_types().iter().any( + cache_fresh_trait_ref.0.input_types().iter().any( |&t| ty::type_has_ty_infer(t)) { return &self.param_env.selection_cache; @@ -615,21 +623,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn check_candidate_cache(&mut self, - cache_skol_trait_ref: Rc>) + cache_fresh_trait_ref: Rc>) -> Option>> { - let cache = self.pick_candidate_cache(&cache_skol_trait_ref); + let cache = self.pick_candidate_cache(&cache_fresh_trait_ref); let hashmap = cache.hashmap.borrow(); - hashmap.get(&cache_skol_trait_ref).map(|c| (*c).clone()) + hashmap.get(&cache_fresh_trait_ref).map(|c| (*c).clone()) } fn insert_candidate_cache(&mut self, - cache_skol_trait_ref: Rc>, + cache_fresh_trait_ref: Rc>, candidate: SelectionResult<'tcx, Candidate<'tcx>>) { - let cache = self.pick_candidate_cache(&cache_skol_trait_ref); + let cache = self.pick_candidate_cache(&cache_fresh_trait_ref); let mut hashmap = cache.hashmap.borrow_mut(); - hashmap.insert(cache_skol_trait_ref, candidate); + hashmap.insert(cache_fresh_trait_ref, candidate); } fn assemble_candidates<'o>(&mut self, @@ -648,7 +656,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. - match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id) { + match self.tcx().lang_items.to_builtin_kind(obligation.trait_ref.def_id()) { Some(ty::BoundCopy) => { debug!("obligation self ty is {}", obligation.self_ty().repr(self.tcx())); @@ -696,7 +704,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("assemble_candidates_from_caller_bounds({})", obligation.repr(self.tcx())); - let caller_trait_refs: Vec> = + let caller_trait_refs: Vec<_> = self.param_env.caller_bounds.predicates.iter() .filter_map(|o| o.to_trait()) .collect(); @@ -708,8 +716,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let matching_bounds = all_bounds.filter( |bound| self.infcx.probe( - || self.match_trait_refs(obligation, - (*bound).clone())).is_ok()); + |_| self.match_where_clause(obligation, bound.clone())).is_ok()); let param_candidates = matching_bounds.map( @@ -731,7 +738,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id) { + let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id()) { Some(k) => k, None => { return Ok(()); } }; @@ -779,7 +786,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We provide a `Fn` impl for fn pointers. There is no need to provide // the other traits (e.g. `FnMut`) since those are provided by blanket // impls. - if Some(obligation.trait_ref.def_id) != self.tcx().lang_items.fn_trait() { + if Some(obligation.trait_ref.def_id()) != self.tcx().lang_items.fn_trait() { return Ok(()); } @@ -793,11 +800,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ty_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: _, output: ty::FnConverging(_), variadic: false - } + }) }) => { candidates.vec.push(FnPointerCandidate); } @@ -814,10 +821,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut CandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { - let all_impls = self.all_impls(obligation.trait_ref.def_id); + let all_impls = self.all_impls(obligation.trait_ref.def_id()); for &impl_def_id in all_impls.iter() { - self.infcx.probe(|| { - match self.match_impl(impl_def_id, obligation) { + self.infcx.probe(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot); + match self.match_impl(impl_def_id, obligation, snapshot, + &skol_map, Rc::new(skol_obligation_trait_ref)) { Ok(_) => { candidates.vec.push(ImplCandidate(impl_def_id)); } @@ -845,15 +855,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate: &Candidate<'tcx>) -> EvaluationResult<'tcx> { - /*! - * Further evaluate `candidate` to decide whether all type parameters match - * and whether nested obligations are met. Returns true if `candidate` remains - * viable after this further scrutiny. - */ - - debug!("winnow_candidate: depth={} candidate={}", - stack.obligation.recursion_depth, candidate.repr(self.tcx())); - let result = self.infcx.probe(|| { + debug!("winnow_candidate: candidate={}", candidate.repr(self.tcx())); + let result = self.infcx.probe(|_| { let candidate = (*candidate).clone(); match self.confirm_candidate(stack.obligation, candidate) { Ok(selection) => self.winnow_selection(Some(stack), selection), @@ -916,18 +919,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate_i.repr(self.tcx()), candidate_j.repr(self.tcx())); - self.infcx.probe(|| { + self.infcx.probe(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions( + &*stack.obligation.trait_ref, snapshot); let impl_substs = - self.rematch_impl(impl_def_id, stack.obligation); + self.rematch_impl(impl_def_id, stack.obligation, snapshot, + &skol_map, Rc::new(skol_obligation_trait_ref)); let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap(); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); + let poly_impl_trait_ref = + Rc::new(ty::Binder((*impl_trait_ref).clone())); let origin = infer::RelateOutputImplTypes(stack.obligation.cause.span); self.infcx - .sub_trait_refs(false, origin, - impl_trait_ref, vt.bound.clone()) + .sub_poly_trait_refs(false, origin, poly_impl_trait_ref, vt.bound.clone()) .is_ok() }) } @@ -1071,26 +1079,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { + ty::ty_trait(ref data) => { match bound { ty::BoundSized => { Err(Unimplemented) } ty::BoundCopy | ty::BoundSync | ty::BoundSend => { - if bounds.builtin_bounds.contains(&bound) { + if data.bounds.builtin_bounds.contains(&bound) { Ok(If(Vec::new())) } else { // Recursively check all supertraits to find out if any further // bounds are required and thus we must fulfill. - // We have to create a temp trait ref here since TyTraits don't - // have actual self type info (which is required for the - // supertraits iterator). - let tmp_tr = Rc::new(ty::TraitRef { - def_id: principal.def_id, - substs: principal.substs.with_self_ty(ty::mk_err()) - }); + let tmp_tr = data.principal_trait_ref_with_self_ty(ty::mk_err()); for tr in util::supertraits(self.tcx(), tmp_tr) { - let td = ty::lookup_trait_def(self.tcx(), tr.def_id); + let td = ty::lookup_trait_def(self.tcx(), tr.def_id()); if td.bounds.builtin_bounds.contains(&bound) { return Ok(If(Vec::new())) @@ -1276,8 +1278,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::ty_open(_) | - ty::ty_infer(ty::SkolemizedTy(_)) | - ty::ty_infer(ty::SkolemizedIntTy(_)) => { + ty::ty_infer(ty::FreshTy(_)) | + ty::ty_infer(ty::FreshIntTy(_)) => { self.tcx().sess.bug( format!( "asked to assemble builtin bounds of unexpected type: {}", @@ -1404,10 +1406,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.repr(self.tcx()), param.repr(self.tcx())); - let () = try!(self.confirm(obligation.cause, - obligation.trait_ref.clone(), - param.bound.clone())); - Ok(param) + // During evaluation, we already checked that this + // where-clause trait-ref could be unified with the obligation + // trait-ref. Repeat that unification now without any + // transactional boundary; it should not fail. + match self.confirm_poly_trait_refs(obligation.cause, + obligation.trait_ref.clone(), + param.bound.clone()) { + Ok(()) => Ok(param), + Err(_) => { + self.tcx().sess.bug( + format!("Where clause `{}` was applicable to `{}` but now is not", + param.bound.repr(self.tcx()), + obligation.repr(self.tcx())).as_slice()); + } + } } fn confirm_builtin_candidate(&mut self, @@ -1454,8 +1467,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.push(Obligation { cause: obligation.cause, recursion_depth: obligation.recursion_depth+1, - trait_ref: ty::Predicate::TypeOutlives(obligation.self_ty(), - ty::ReStatic) + trait_ref: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(), + ty::ReStatic)).as_predicate(), }); } @@ -1480,23 +1493,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - let substs = self.rematch_impl(impl_def_id, obligation); - debug!("confirm_impl_candidate substs={}", substs); - Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, obligation.recursion_depth + 1)) + self.infcx.try(|snapshot| { + let (skol_obligation_trait_ref, skol_map) = + self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot); + let substs = self.rematch_impl(impl_def_id, obligation, + snapshot, &skol_map, Rc::new(skol_obligation_trait_ref)); + debug!("confirm_impl_candidate substs={}", substs); + Ok(self.vtable_impl(impl_def_id, substs, obligation.cause, + obligation.recursion_depth + 1, skol_map, snapshot)) + }) } fn vtable_impl(&mut self, impl_def_id: ast::DefId, substs: Substs<'tcx>, cause: ObligationCause<'tcx>, - recursion_depth: uint) + recursion_depth: uint, + skol_map: infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { + debug!("vtable_impl(impl_def_id={}, substs={}, recursion_depth={}, skol_map={})", + impl_def_id.repr(self.tcx()), + substs.repr(self.tcx()), + recursion_depth, + skol_map.repr(self.tcx())); + let impl_predicates = self.impl_predicates(cause, recursion_depth, impl_def_id, - &substs); + &substs, + skol_map, + snapshot); + + debug!("vtable_impl: impl_def_id={} impl_predicates={}", + impl_def_id.repr(self.tcx()), + impl_predicates.repr(self.tcx())); + VtableImplData { impl_def_id: impl_def_id, substs: substs, nested: impl_predicates } @@ -1526,23 +1560,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; - let arguments_tuple = ty::mk_tup(self.tcx(), sig.inputs.to_vec()); - let output_type = sig.output.unwrap(); + let arguments_tuple = ty::mk_tup(self.tcx(), sig.0.inputs.to_vec()); + let output_type = sig.0.output.unwrap(); let substs = Substs::new_trait( vec![arguments_tuple, output_type], vec![], vec![], self_ty); - let trait_ref = Rc::new(ty::TraitRef { - def_id: obligation.trait_ref.def_id, + let trait_ref = Rc::new(ty::Binder(ty::TraitRef { + def_id: obligation.trait_ref.def_id(), substs: substs, - }); + })); - let () = - try!(self.confirm(obligation.cause, - obligation.trait_ref.clone(), - trait_ref)); + try!(self.confirm_poly_trait_refs(obligation.cause, + obligation.trait_ref.clone(), + trait_ref)); Ok(self_ty) } @@ -1569,26 +1602,69 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let closure_sig = &closure_type.sig; - let arguments_tuple = closure_sig.inputs[0]; + let arguments_tuple = closure_sig.0.inputs[0]; let substs = Substs::new_trait( vec![arguments_tuple.subst(self.tcx(), substs), - closure_sig.output.unwrap().subst(self.tcx(), substs)], + closure_sig.0.output.unwrap().subst(self.tcx(), substs)], vec![], vec![], obligation.self_ty()); - let trait_ref = Rc::new(ty::TraitRef { - def_id: obligation.trait_ref.def_id, + let trait_ref = Rc::new(ty::Binder(ty::TraitRef { + def_id: obligation.trait_ref.def_id(), substs: substs, - }); + })); debug!("confirm_unboxed_closure_candidate(closure_def_id={}, trait_ref={})", closure_def_id.repr(self.tcx()), trait_ref.repr(self.tcx())); - self.confirm(obligation.cause, - obligation.trait_ref.clone(), - trait_ref) + self.confirm_poly_trait_refs(obligation.cause, + obligation.trait_ref.clone(), + trait_ref) + } + + /// In the case of unboxed closure types and fn pointers, + /// we currently treat the input type parameters on the trait as + /// outputs. This means that when we have a match we have only + /// considered the self type, so we have to go back and make sure + /// to relate the argument types too. This is kind of wrong, but + /// since we control the full set of impls, also not that wrong, + /// and it DOES yield better error messages (since we don't report + /// errors as if there is no applicable impl, but rather report + /// errors are about mismatched argument types. + /// + /// Here is an example. Imagine we have an unboxed closure expression + /// and we desugared it so that the type of the expression is + /// `Closure`, and `Closure` expects an int as argument. Then it + /// is "as if" the compiler generated this impl: + /// + /// impl Fn(int) for Closure { ... } + /// + /// Now imagine our obligation is `Fn(uint) for Closure`. So far + /// we have matched the self-type `Closure`. At this point we'll + /// compare the `int` to `uint` and generate an error. + /// + /// 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. + fn confirm_poly_trait_refs(&mut self, + obligation_cause: ObligationCause, + obligation_trait_ref: Rc>, + expected_trait_ref: Rc>) + -> Result<(), SelectionError<'tcx>> + { + let origin = infer::RelateOutputImplTypes(obligation_cause.span); + + let obligation_trait_ref = obligation_trait_ref.clone(); + match self.infcx.sub_poly_trait_refs(false, + origin, + expected_trait_ref.clone(), + obligation_trait_ref.clone()) { + Ok(()) => Ok(()), + Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) + } } /////////////////////////////////////////////////////////////////////////// @@ -1603,10 +1679,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn rematch_impl(&mut self, impl_def_id: ast::DefId, - obligation: &TraitObligation<'tcx>) + obligation: &TraitObligation<'tcx>, + snapshot: &infer::CombinedSnapshot, + skol_map: &infer::SkolemizationMap, + skol_obligation_trait_ref: Rc>) -> Substs<'tcx> { - match self.match_impl(impl_def_id, obligation) { + match self.match_impl(impl_def_id, obligation, snapshot, + skol_map, skol_obligation_trait_ref) { Ok(substs) => { substs } @@ -1622,11 +1702,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_impl(&mut self, impl_def_id: ast::DefId, - obligation: &TraitObligation<'tcx>) + obligation: &TraitObligation<'tcx>, + snapshot: &infer::CombinedSnapshot, + skol_map: &infer::SkolemizationMap, + skol_obligation_trait_ref: Rc>) -> Result, ()> { - let impl_trait_ref = ty::impl_trait_ref(self.tcx(), - impl_def_id).unwrap(); + let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap(); // Before we create the substitutions and everything, first // consider a "quick reject". This avoids creating more types @@ -1642,10 +1724,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); - match self.match_trait_refs(obligation, impl_trait_ref) { - Ok(()) => Ok(impl_substs), - Err(()) => Err(()) + debug!("match_impl(impl_def_id={}, obligation={}, \ + impl_trait_ref={}, skol_obligation_trait_ref={})", + impl_def_id.repr(self.tcx()), + obligation.repr(self.tcx()), + impl_trait_ref.repr(self.tcx()), + skol_obligation_trait_ref.repr(self.tcx())); + + let origin = infer::RelateOutputImplTypes(obligation.cause.span); + match self.infcx.sub_trait_refs(false, + origin, + impl_trait_ref, + skol_obligation_trait_ref) { + Ok(()) => { } + Err(e) => { + debug!("match_impl: failed sub_trait_refs due to `{}`", + ty::type_err_to_str(self.tcx(), &e)); + return Err(()); + } + } + + match self.infcx.leak_check(skol_map, snapshot) { + Ok(()) => { } + Err(e) => { + debug!("match_impl: failed leak check due to `{}`", + ty::type_err_to_str(self.tcx(), &e)); + return Err(()); + } } + + debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx())); + Ok(impl_substs) } fn fast_reject_trait_refs(&mut self, @@ -1671,20 +1780,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } - fn match_trait_refs(&mut self, - obligation: &TraitObligation<'tcx>, - trait_ref: Rc>) + fn match_where_clause(&mut self, + obligation: &TraitObligation<'tcx>, + where_clause_trait_ref: Rc>) -> Result<(),()> { - debug!("match_trait_refs: obligation={} trait_ref={}", + debug!("match_where_clause: obligation={} where_clause_trait_ref={}", obligation.repr(self.tcx()), - trait_ref.repr(self.tcx())); + where_clause_trait_ref.repr(self.tcx())); let origin = infer::RelateOutputImplTypes(obligation.cause.span); - match self.infcx.sub_trait_refs(false, - origin, - trait_ref, - obligation.trait_ref.clone()) { + match self.infcx.sub_poly_trait_refs(false, + origin, + where_clause_trait_ref, + obligation.trait_ref.clone()) { Ok(()) => Ok(()), Err(_) => Err(()), } @@ -1758,78 +1867,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - /////////////////////////////////////////////////////////////////////////// - // 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. - - /// 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. - fn confirm_impl_vtable(&mut self, - impl_def_id: ast::DefId, - obligation_cause: ObligationCause<'tcx>, - obligation_trait_ref: Rc>, - substs: &Substs<'tcx>) - -> Result<(), SelectionError<'tcx>> - { - 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) - } - - /// 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. - fn confirm(&mut self, - obligation_cause: ObligationCause, - obligation_trait_ref: Rc>, - expected_trait_ref: Rc>) - -> Result<(), SelectionError<'tcx>> - { - 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.clone()) { - Ok(()) => Ok(()), - Err(e) => Err(OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) - } - } - /////////////////////////////////////////////////////////////////////////// // Miscellany @@ -1838,11 +1875,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &'o TraitObligation<'tcx>) -> TraitObligationStack<'o, 'tcx> { - let skol_trait_ref = obligation.trait_ref.fold_with(&mut self.skolemizer); + let fresh_trait_ref = obligation.trait_ref.fold_with(&mut self.freshener); TraitObligationStack { obligation: obligation, - skol_trait_ref: skol_trait_ref, + fresh_trait_ref: fresh_trait_ref, previous: previous_stack.map(|p| p), // FIXME variance } } @@ -1861,11 +1898,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause: ObligationCause<'tcx>, recursion_depth: uint, impl_def_id: ast::DefId, - impl_substs: &Substs<'tcx>) + impl_substs: &Substs<'tcx>, + skol_map: infer::SkolemizationMap, + snapshot: &infer::CombinedSnapshot) -> VecPerParamSpace> { let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics; let bounds = impl_generics.to_bounds(self.tcx(), impl_substs); + let bounds = self.infcx().plug_leaks(skol_map, snapshot, &bounds); util::predicates_for_generics(self.tcx(), cause, recursion_depth, &bounds) } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index d8956246d326f..27824ba5c6e77 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -47,7 +47,7 @@ struct StackEntry<'tcx> { pub fn elaborate_trait_ref<'cx, 'tcx>( tcx: &'cx ty::ctxt<'tcx>, - trait_ref: Rc>) + trait_ref: Rc>) -> Elaborator<'cx, 'tcx> { elaborate_predicates(tcx, vec![ty::Predicate::Trait(trait_ref)]) @@ -55,7 +55,7 @@ pub fn elaborate_trait_ref<'cx, 'tcx>( pub fn elaborate_trait_refs<'cx, 'tcx>( tcx: &'cx ty::ctxt<'tcx>, - trait_refs: &[Rc>]) + trait_refs: &[Rc>]) -> Elaborator<'cx, 'tcx> { let predicates = trait_refs.iter() @@ -174,7 +174,7 @@ pub struct Supertraits<'cx, 'tcx:'cx> { } pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - trait_ref: Rc>) + trait_ref: Rc>) -> Supertraits<'cx, 'tcx> { let elaborator = elaborate_trait_ref(tcx, trait_ref); @@ -182,15 +182,15 @@ pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, } pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>, - bounds: &[Rc>]) + bounds: &[Rc>]) -> Supertraits<'cx, 'tcx> { let elaborator = elaborate_trait_refs(tcx, bounds); Supertraits { elaborator: elaborator } } -impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { - fn next(&mut self) -> Option>> { +impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { + fn next(&mut self) -> Option>> { loop { match self.elaborator.next() { None => { @@ -266,18 +266,18 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, }) } -pub fn trait_ref_for_builtin_bound<'tcx>( +pub fn poly_trait_ref_for_builtin_bound<'tcx>( tcx: &ty::ctxt<'tcx>, builtin_bound: ty::BuiltinBound, param_ty: Ty<'tcx>) - -> Result>, ErrorReported> + -> Result>, ErrorReported> { match tcx.lang_items.from_builtin_kind(builtin_bound) { Ok(def_id) => { - Ok(Rc::new(ty::TraitRef { + Ok(Rc::new(ty::Binder(ty::TraitRef { def_id: def_id, substs: Substs::empty().with_self_ty(param_ty) - })) + }))) } Err(e) => { tcx.sess.err(e.as_slice()); @@ -294,7 +294,7 @@ pub fn predicate_for_builtin_bound<'tcx>( param_ty: Ty<'tcx>) -> Result, ErrorReported> { - let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); + let trait_ref = try!(poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty)); Ok(Obligation { cause: cause, recursion_depth: recursion_depth, @@ -306,14 +306,14 @@ pub fn predicate_for_builtin_bound<'tcx>( /// 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`. -pub fn search_trait_and_supertraits_from_bound<'tcx, F>(tcx: &ty::ctxt<'tcx>, - caller_bound: Rc>, - mut test: F) - -> Option> where - F: FnMut(ast::DefId) -> bool, +pub fn search_trait_and_supertraits_from_bound<'tcx,F>(tcx: &ty::ctxt<'tcx>, + caller_bound: Rc>, + mut test: F) + -> Option> + where F: FnMut(ast::DefId) -> bool, { for bound in transitive_bounds(tcx, &[caller_bound]) { - if test(bound.def_id) { + if test(bound.def_id()) { let vtable_param = VtableParamData { bound: bound }; return Some(vtable_param); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 0ad07bed7d923..6839e8bcc45db 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -60,7 +60,7 @@ use middle::subst::{mod, Subst, Substs, VecPerParamSpace}; use middle::traits::ObligationCause; use middle::traits; use middle::ty; -use middle::ty_fold::{mod, TypeFoldable, TypeFolder, HigherRankedFoldable}; +use middle::ty_fold::{mod, TypeFoldable, TypeFolder}; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; use util::ppaux::{trait_store_to_string, ty_to_string}; use util::ppaux::{Repr, UserString}; @@ -478,7 +478,9 @@ pub enum MethodOrigin<'tcx> { #[deriving(Clone, Show)] pub struct MethodParam<'tcx> { // the precise trait reference that occurs as a bound -- this may - // be a supertrait of what the user actually typed. + // be a supertrait of what the user actually typed. Note that it + // never contains bound regions; those regions should have been + // instantiated with fresh variables at this point. pub trait_ref: Rc>, // index of uint in the list of methods for the trait @@ -609,7 +611,7 @@ pub enum vtable_origin<'tcx> { // For every explicit cast into an object type, maps from the cast // expr to the associated trait ref. -pub type ObjectCastMap<'tcx> = RefCell>>>; +pub type ObjectCastMap<'tcx> = RefCell>>>; /// A restriction that certain types must be the same size. The use of /// `transmute` gives rise to these restrictions. @@ -908,7 +910,7 @@ pub fn type_escapes_depth(ty: Ty, depth: uint) -> bool { pub struct BareFnTy<'tcx> { pub unsafety: ast::Unsafety, pub abi: abi::Abi, - pub sig: FnSig<'tcx>, + pub sig: PolyFnSig<'tcx>, } #[deriving(Clone, PartialEq, Eq, Hash, Show)] @@ -917,7 +919,7 @@ pub struct ClosureTy<'tcx> { pub onceness: ast::Onceness, pub store: TraitStore, pub bounds: ExistentialBounds, - pub sig: FnSig<'tcx>, + pub sig: PolyFnSig<'tcx>, pub abi: abi::Abi, } @@ -944,10 +946,6 @@ impl<'tcx> Copy for FnOutput<'tcx> {} /// - `inputs` is the list of arguments and their modes. /// - `output` is the return type. /// - `variadic` indicates whether this is a varidic function. (only true for foreign fns) -/// -/// Note that a `FnSig` introduces a level of region binding, to -/// account for late-bound parameters that appear in the types of the -/// fn's arguments or the fn's return type. #[deriving(Clone, PartialEq, Eq, Hash)] pub struct FnSig<'tcx> { pub inputs: Vec>, @@ -955,6 +953,8 @@ pub struct FnSig<'tcx> { pub variadic: bool } +pub type PolyFnSig<'tcx> = Binder>; + #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct ParamTy { pub space: subst::ParamSpace, @@ -1308,10 +1308,25 @@ pub enum sty<'tcx> { #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct TyTrait<'tcx> { // Principal trait reference. - pub principal: TraitRef<'tcx>, // would use Rc, but it runs afoul of some static rules + pub principal: PolyTraitRef<'tcx>, pub bounds: ExistentialBounds } +impl<'tcx> TyTrait<'tcx> { + /// Object types don't have a self-type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self-type. A common choice is `mk_err()` + /// or some skolemized type. + pub fn principal_trait_ref_with_self_ty(&self, self_ty: Ty<'tcx>) + -> Rc> + { + Rc::new(ty::Binder(ty::TraitRef { + def_id: self.principal.def_id(), + substs: self.principal.substs().with_self_ty(self_ty), + })) + } +} + /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where clause: /// @@ -1333,21 +1348,36 @@ pub struct TraitRef<'tcx> { pub substs: Substs<'tcx>, } -/// Binder serves as a synthetic binder for lifetimes. It is used when -/// we wish to replace the escaping higher-ranked lifetimes in a type -/// or something else that is not itself a binder (this is because the -/// `replace_late_bound_regions` function replaces all lifetimes bound -/// by the binder supplied to it; but a type is not a binder, so you -/// must introduce an artificial one). -#[deriving(Clone, PartialEq, Eq, Hash, Show)] -pub struct Binder { - pub value: T -} +pub type PolyTraitRef<'tcx> = Binder>; + +impl<'tcx> PolyTraitRef<'tcx> { + pub fn self_ty(&self) -> Ty<'tcx> { + self.0.self_ty() + } + + pub fn def_id(&self) -> ast::DefId { + self.0.def_id + } + + pub fn substs(&self) -> &Substs<'tcx> { + &self.0.substs + } -pub fn bind(value: T) -> Binder { - Binder { value: value } + pub fn input_types(&self) -> &[Ty<'tcx>] { + self.0.input_types() + } } +/// Binder is a binder for higher-ranked lifetimes. It is part of the +/// compiler's representation for things like `for<'a> Fn(&'a int)` +/// (which would be represented by the type `PolyTraitRef == +/// Binder`). Note that when we skolemize, instantiate, +/// erase, or otherwise "discharge" these bound reons, we change the +/// type from `Binder` to just `T` (see +/// e.g. `liberate_late_bound_regions`). +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct Binder(pub T); + #[deriving(Clone, PartialEq)] pub enum IntVarValue { IntType(ast::IntTy), @@ -1416,7 +1446,7 @@ impl<'tcx> Copy for type_err<'tcx> {} pub struct ParamBounds<'tcx> { pub region_bounds: Vec, pub builtin_bounds: BuiltinBounds, - pub trait_bounds: Vec>> + pub trait_bounds: Vec>> } /// Bounds suitable for an existentially quantified type parameter @@ -1505,12 +1535,16 @@ pub enum InferTy { TyVar(TyVid), IntVar(IntVid), FloatVar(FloatVid), - SkolemizedTy(uint), + + /// A `FreshTy` is one that is generated as a replacement for an + /// unbound type variable. This is convenient for caching etc. See + /// `middle::infer::freshen` for more details. + FreshTy(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), + FreshIntTy(uint), } impl Copy for InferTy {} @@ -1577,8 +1611,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), + FreshTy(v) => write!(f, "FreshTy({})", v), + FreshIntTy(v) => write!(f, "FreshIntTy({})", v), } } } @@ -1657,30 +1691,67 @@ pub enum Predicate<'tcx> { /// Corresponds to `where Foo : Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the parameters in the `TypeSpace`. - Trait(Rc>), + Trait(Rc>), /// where `T1 == T2`. - Equate(/* T1 */ Ty<'tcx>, /* T2 */ Ty<'tcx>), + Equate(PolyEquatePredicate<'tcx>), /// where 'a : 'b - RegionOutlives(/* 'a */ Region, /* 'b */ Region), + RegionOutlives(PolyRegionOutlivesPredicate), /// where T : 'a - TypeOutlives(Ty<'tcx>, Region), + TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), +} + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1` +pub type PolyEquatePredicate<'tcx> = ty::Binder>; + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct OutlivesPredicate(pub A, pub B); // `A : B` +pub type PolyOutlivesPredicate = ty::Binder>; +pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; +pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; + +pub trait AsPredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx>; +} + +impl<'tcx> AsPredicate<'tcx> for Rc> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::Trait(self.clone()) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyEquatePredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::Equate(self.clone()) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyRegionOutlivesPredicate { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::RegionOutlives(self.clone()) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::TypeOutlives(self.clone()) + } } impl<'tcx> Predicate<'tcx> { pub fn has_escaping_regions(&self) -> bool { match *self { Predicate::Trait(ref trait_ref) => trait_ref.has_escaping_regions(), - Predicate::Equate(a, b) => (ty::type_has_escaping_regions(a) || - ty::type_has_escaping_regions(b)), - Predicate::RegionOutlives(a, b) => a.escapes_depth(0) || b.escapes_depth(0), - Predicate::TypeOutlives(a, b) => ty::type_has_escaping_regions(a) || b.escapes_depth(0), + Predicate::Equate(ref p) => p.has_escaping_regions(), + Predicate::RegionOutlives(ref p) => p.has_escaping_regions(), + Predicate::TypeOutlives(ref p) => p.has_escaping_regions(), } } - pub fn to_trait(&self) -> Option>> { + pub fn to_trait(&self) -> Option>> { match *self { Predicate::Trait(ref t) => { Some(t.clone()) @@ -1748,14 +1819,6 @@ impl<'tcx> TraitRef<'tcx> { // associated types. self.substs.types.as_slice() } - - pub fn has_escaping_regions(&self) -> bool { - self.substs.has_regions_escaping_depth(1) - } - - pub fn has_bound_regions(&self) -> bool { - self.substs.has_regions_escaping_depth(0) - } } /// When type checking, we use the `ParameterEnvironment` to track @@ -2160,7 +2223,7 @@ impl FlagComputation { &ty_trait(box TyTrait { ref principal, ref bounds }) => { let mut computation = FlagComputation::new(); - computation.add_substs(&principal.substs); + computation.add_substs(principal.substs()); self.add_bound_computation(&computation); self.add_bounds(bounds); @@ -2208,12 +2271,12 @@ impl FlagComputation { } } - fn add_fn_sig(&mut self, fn_sig: &FnSig) { + fn add_fn_sig(&mut self, fn_sig: &PolyFnSig) { let mut computation = FlagComputation::new(); - computation.add_tys(fn_sig.inputs[]); + computation.add_tys(fn_sig.0.inputs[]); - if let ty::FnConverging(output) = fn_sig.output { + if let ty::FnConverging(output) = fn_sig.0.output { computation.add_ty(output); } @@ -2356,17 +2419,17 @@ pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>, BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: FnSig { + sig: ty::Binder(FnSig { inputs: input_args, output: ty::FnConverging(output), variadic: false - } + }) }) } pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, - principal: ty::TraitRef<'tcx>, + principal: ty::PolyTraitRef<'tcx>, bounds: ExistentialBounds) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside @@ -2439,7 +2502,7 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) { maybe_walk_ty(tm.ty, f); } ty_trait(box TyTrait { ref principal, .. }) => { - for subty in principal.substs.types.iter() { + for subty in principal.substs().types.iter() { maybe_walk_ty(*subty, |x| f(x)); } } @@ -2452,14 +2515,14 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) { } ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } } ty_bare_fn(ref ft) => { - for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } - if let ty::FnConverging(output) = ft.sig.output { + for a in ft.sig.0.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } + if let ty::FnConverging(output) = ft.sig.0.output { maybe_walk_ty(output, f); } } ty_closure(ref ft) => { - for a in ft.sig.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } - if let ty::FnConverging(output) = ft.sig.output { + for a in ft.sig.0.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); } + if let ty::FnConverging(output) = ft.sig.0.output { maybe_walk_ty(output, f); } } @@ -2961,7 +3024,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } // Scalar and unique types are sendable, and durable - ty_infer(ty::SkolemizedIntTy(_)) | + ty_infer(ty::FreshIntTy(_)) | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty::ty_char => { TC::None @@ -3182,7 +3245,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { fn kind_bounds_to_contents<'tcx>(cx: &ctxt<'tcx>, bounds: BuiltinBounds, - traits: &[Rc>]) + traits: &[Rc>]) -> TypeContents { let _i = indenter(); let mut tc = TC::All; @@ -3198,7 +3261,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { // those inherited from traits with builtin-kind-supertraits. fn each_inherited_builtin_bound<'tcx, F>(cx: &ctxt<'tcx>, bounds: BuiltinBounds, - traits: &[Rc>], + traits: &[Rc>], mut f: F) where F: FnMut(BuiltinBound), { @@ -3207,7 +3270,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } each_bound_trait_and_supertraits(cx, traits, |trait_ref| { - let trait_def = lookup_trait_def(cx, trait_ref.def_id); + let trait_def = lookup_trait_def(cx, trait_ref.def_id()); for bound in trait_def.bounds.builtin_bounds.iter() { f(bound); } @@ -3567,10 +3630,10 @@ pub fn type_is_integral(ty: Ty) -> bool { } } -pub fn type_is_skolemized(ty: Ty) -> bool { +pub fn type_is_fresh(ty: Ty) -> bool { match ty.sty { - ty_infer(SkolemizedTy(_)) => true, - ty_infer(SkolemizedIntTy(_)) => true, + ty_infer(FreshTy(_)) => true, + ty_infer(FreshIntTy(_)) => true, _ => false } } @@ -3828,15 +3891,15 @@ pub fn node_id_item_substs<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> ItemSubsts pub fn fn_is_variadic(fty: Ty) -> bool { match fty.sty { - ty_bare_fn(ref f) => f.sig.variadic, - ty_closure(ref f) => f.sig.variadic, + ty_bare_fn(ref f) => f.sig.0.variadic, + ty_closure(ref f) => f.sig.0.variadic, ref s => { panic!("fn_is_variadic() called on non-fn type: {}", s) } } } -pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx FnSig<'tcx> { +pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> { match fty.sty { ty_bare_fn(ref f) => &f.sig, ty_closure(ref f) => &f.sig, @@ -3857,7 +3920,7 @@ pub fn ty_fn_abi(fty: Ty) -> abi::Abi { // Type accessors for substructures of types pub fn ty_fn_args<'tcx>(fty: Ty<'tcx>) -> &'tcx [Ty<'tcx>] { - ty_fn_sig(fty).inputs.as_slice() + ty_fn_sig(fty).0.inputs.as_slice() } pub fn ty_closure_store(fty: Ty) -> TraitStore { @@ -3876,8 +3939,8 @@ pub fn ty_closure_store(fty: Ty) -> TraitStore { pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> { match fty.sty { - ty_bare_fn(ref f) => f.sig.output, - ty_closure(ref f) => f.sig.output, + ty_bare_fn(ref f) => f.sig.0.output, + ty_closure(ref f) => f.sig.0.output, ref s => { panic!("ty_fn_ret() called on non-fn type: {}", s) } @@ -4393,7 +4456,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_bare_fn(_) => "extern fn".to_string(), ty_closure(_) => "fn".to_string(), ty_trait(ref inner) => { - format!("trait {}", item_path_str(cx, inner.principal.def_id)) + format!("trait {}", item_path_str(cx, inner.principal.def_id())) } ty_struct(id, _) => { format!("struct {}", item_path_str(cx, id)) @@ -4403,8 +4466,8 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> 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_infer(FreshTy(_)) => "skolemized type".to_string(), + ty_infer(FreshIntTy(_)) => "skolemized integral type".to_string(), ty_param(ref p) => { if p.space == subst::SelfSpace { "Self".to_string() @@ -4770,7 +4833,8 @@ pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) ast::ItemImpl(_, _, ref opt_trait, _, _) => { match opt_trait { &Some(ref t) => { - Some(ty::node_id_to_trait_ref(cx, t.ref_id)) + let trait_ref = ty::node_id_to_trait_ref(cx, t.ref_id); + Some(trait_ref) } &None => None } @@ -4813,7 +4877,7 @@ pub fn try_add_builtin_trait( pub fn ty_to_def_id(ty: Ty) -> Option { match ty.sty { ty_trait(ref tt) => - Some(tt.principal.def_id), + Some(tt.principal.def_id()), ty_struct(id, _) | ty_enum(id, _) | ty_unboxed_closure(id, _, _) => @@ -5073,10 +5137,10 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) /// Given a reference to a trait, returns the "superbounds" declared /// on the trait, with appropriate substitutions applied. pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, - trait_ref: &TraitRef<'tcx>) + trait_ref: &PolyTraitRef<'tcx>) -> Vec> { - let trait_def = lookup_trait_def(tcx, trait_ref.def_id); + let trait_def = lookup_trait_def(tcx, trait_ref.def_id()); debug!("bounds_for_trait_ref(trait_def={}, trait_ref={})", trait_def.repr(tcx), trait_ref.repr(tcx)); @@ -5149,8 +5213,9 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, trait_def.bounds.trait_bounds .iter() .map(|bound_trait_ref| { - ty::TraitRef::new(bound_trait_ref.def_id, - bound_trait_ref.substs.subst(tcx, &trait_ref.substs)) + ty::Binder( + ty::TraitRef::new(bound_trait_ref.def_id(), + bound_trait_ref.substs().subst(tcx, trait_ref.substs()))) }) .map(|bound_trait_ref| Rc::new(bound_trait_ref)) .collect(); @@ -5161,9 +5226,9 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, // The region bounds and builtin bounds do not currently introduce // binders so we can just substitute in a straightforward way here. let region_bounds = - trait_def.bounds.region_bounds.subst(tcx, &trait_ref.substs); + trait_def.bounds.region_bounds.subst(tcx, trait_ref.substs()); let builtin_bounds = - trait_def.bounds.builtin_bounds.subst(tcx, &trait_ref.substs); + trait_def.bounds.builtin_bounds.subst(tcx, trait_ref.substs()); let bounds = ty::ParamBounds { trait_bounds: trait_bounds, @@ -5183,18 +5248,21 @@ pub fn predicates<'tcx>( let mut vec = Vec::new(); for builtin_bound in bounds.builtin_bounds.iter() { - match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { - Ok(trait_ref) => { vec.push(Predicate::Trait(trait_ref)); } + match traits::poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { + Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); } Err(ErrorReported) => { } } } for ®ion_bound in bounds.region_bounds.iter() { - vec.push(Predicate::TypeOutlives(param_ty, region_bound)); + // account for the binder being introduced below; no need to shift `param_ty` + // because, at present at least, it can only refer to early-bound regions + let region_bound = ty_fold::shift_region(region_bound, 1); + vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).as_predicate()); } for bound_trait_ref in bounds.trait_bounds.iter() { - vec.push(Predicate::Trait((*bound_trait_ref).clone())); + vec.push(bound_trait_ref.as_predicate()); } vec @@ -5483,18 +5551,6 @@ pub fn normalize_ty<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { subst::Substs { regions: subst::ErasedRegions, types: substs.types.fold_with(self) } } - - fn fold_fn_sig(&mut self, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { - // The binder-id is only relevant to bound regions, which - // are erased at trans time. - ty::FnSig { - inputs: sig.inputs.fold_with(self), - output: sig.output.fold_with(self), - variadic: sig.variadic, - } - } } } @@ -5545,10 +5601,10 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { // relation on the supertraits from each bounded trait's constraint // list. pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, - bounds: &[Rc>], + bounds: &[Rc>], mut f: F) -> bool where - F: FnMut(Rc>) -> bool, + F: FnMut(Rc>) -> bool, { for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { if !f(bound_trait_ref) { @@ -5559,18 +5615,18 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, } pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - opt_principal: Option<&TraitRef<'tcx>>, // None for boxed closures + opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures others: BuiltinBounds) -> Vec { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically // a skolemized type. - let open_ty = ty::mk_infer(tcx, SkolemizedTy(0)); + let open_ty = ty::mk_infer(tcx, FreshTy(0)); let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| { - let substs = principal.substs.with_self_ty(open_ty); - vec!(Rc::new(ty::TraitRef::new(principal.def_id, substs))) + let substs = principal.substs().with_self_ty(open_ty); + vec!(Rc::new(ty::Binder(ty::TraitRef::new(principal.def_id(), substs)))) }); let param_bounds = ty::ParamBounds { @@ -5583,19 +5639,27 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, ty::required_region_bounds(tcx, open_ty, predicates) } -/// Given a type which must meet the builtin bounds and trait bounds, returns a set of lifetimes -/// which the type must outlive. +/// Given a set of predicates that apply to an object type, returns +/// the region bounds that the (erased) `Self` type must +/// outlive. Precisely *because* the `Self` type is erased, the +/// parameter `erased_self_ty` must be supplied to indicate what type +/// has been used to represent `Self` in the predicates +/// themselves. This should really be a unique type; `FreshTy(0)` is a +/// popular choice (see `object_region_bounds` above). /// -/// Requires that trait definitions have been processed. +/// Requires that trait definitions have been processed so that we can +/// elaborate predicates and walk supertraits. pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - param_ty: Ty<'tcx>, + erased_self_ty: Ty<'tcx>, predicates: Vec>) -> Vec { - debug!("required_region_bounds(param_ty={}, predicates={})", - param_ty.repr(tcx), + debug!("required_region_bounds(erased_self_ty={}, predicates={})", + erased_self_ty.repr(tcx), predicates.repr(tcx)); + assert!(!erased_self_ty.has_escaping_regions()); + traits::elaborate_predicates(tcx, predicates) .filter_map(|predicate| { match predicate { @@ -5604,9 +5668,22 @@ pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, ty::Predicate::RegionOutlives(..) => { None } - ty::Predicate::TypeOutlives(t, r) => { - if t == param_ty { - Some(r) + ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + if t == erased_self_ty && !r.has_escaping_regions() { + if r.has_escaping_regions() { + Some(ty::ReStatic) + } else { + Some(r) + } } else { None } @@ -5824,12 +5901,12 @@ pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId) /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. -pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { +pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -> u64 { let mut state = sip::SipState::new(); helper(tcx, ty, svh, &mut state); return state.result(); - fn helper(tcx: &ctxt, ty: Ty, svh: &Svh, state: &mut sip::SipState) { + fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, state: &mut sip::SipState) { macro_rules! byte( ($b:expr) => { ($b as u8).hash(state) } ); macro_rules! hash( ($e:expr) => { $e.hash(state) } ); @@ -5862,7 +5939,7 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { let mt = |state: &mut sip::SipState, mt: mt| { mt.mutbl.hash(state); }; - let fn_sig = |state: &mut sip::SipState, sig: &FnSig| { + let fn_sig = |state: &mut sip::SipState, sig: &Binder>| { let sig = anonymize_late_bound_regions(tcx, sig); for a in sig.inputs.iter() { helper(tcx, *a, svh, state); } if let ty::FnConverging(output) = sig.output { @@ -5938,7 +6015,7 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { } ty_trait(box TyTrait { ref principal, bounds }) => { byte!(17); - did(state, principal.def_id); + did(state, principal.def_id()); hash!(bounds); let principal = anonymize_late_bound_regions(tcx, principal); @@ -6033,7 +6110,7 @@ pub fn construct_parameter_environment<'tcx>( // let bounds = generics.to_bounds(tcx, &free_substs); - let bounds = liberate_late_bound_regions(tcx, free_id_scope, &bind(bounds)).value; + let bounds = liberate_late_bound_regions(tcx, free_id_scope, &ty::Binder(bounds)); // // Compute region bounds. For now, these relations are stored in a @@ -6088,16 +6165,20 @@ pub fn construct_parameter_environment<'tcx>( Predicate::Trait(..) | Predicate::Equate(..) | Predicate::TypeOutlives(..) => { // No region bounds here } - Predicate::RegionOutlives(ty::ReFree(fr_a), ty::ReFree(fr_b)) => { - // Record that `'a:'b`. Or, put another way, `'b <= 'a`. - tcx.region_maps.relate_free_regions(fr_b, fr_a); - } - Predicate::RegionOutlives(r_a, r_b) => { - // All named regions are instantiated with free regions. - tcx.sess.bug( - format!("record_region_bounds: non free region: {} / {}", - r_a.repr(tcx), - r_b.repr(tcx)).as_slice()); + Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { + match (r_a, r_b) { + (ty::ReFree(fr_a), ty::ReFree(fr_b)) => { + // Record that `'a:'b`. Or, put another way, `'b <= 'a`. + tcx.region_maps.relate_free_regions(fr_b, fr_a); + } + _ => { + // All named regions are instantiated with free regions. + tcx.sess.bug( + format!("record_region_bounds: non free region: {} / {}", + r_a.repr(tcx), + r_b.repr(tcx)).as_slice()); + } + } } } } @@ -6200,7 +6281,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, accumulator.push(region) } ty_trait(ref t) => { - accumulator.push_all(t.principal.substs.regions().as_slice()); + accumulator.push_all(t.principal.substs().regions().as_slice()); } ty_enum(_, ref substs) | ty_struct(_, ref substs) => { @@ -6289,25 +6370,35 @@ impl<'tcx> AutoDerefRef<'tcx> { /// Replace any late-bound regions bound in `value` with free variants attached to scope-id /// `scope_id`. -pub fn liberate_late_bound_regions<'tcx, HR>( +pub fn liberate_late_bound_regions<'tcx, T>( tcx: &ty::ctxt<'tcx>, scope: region::CodeExtent, - value: &HR) - -> HR - where HR : HigherRankedFoldable<'tcx> + value: &Binder) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { replace_late_bound_regions( tcx, value, |br, _| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0 } +pub fn count_late_bound_regions<'tcx, T>( + tcx: &ty::ctxt<'tcx>, + value: &Binder) + -> uint + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + let (_, skol_map) = replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic); + skol_map.len() +} + /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also /// method lookup and a few other places where precise region relationships are not required. -pub fn erase_late_bound_regions<'tcx, HR>( +pub fn erase_late_bound_regions<'tcx, T>( tcx: &ty::ctxt<'tcx>, - value: &HR) - -> HR - where HR : HigherRankedFoldable<'tcx> + value: &Binder) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic).0 } @@ -6320,8 +6411,12 @@ pub fn erase_late_bound_regions<'tcx, HR>( /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become /// structurally identical. For example, `for<'a, 'b> fn(&'a int, &'b int)` and /// `for<'a, 'b> fn(&'b int, &'a int)` will become identical after anonymization. -pub fn anonymize_late_bound_regions<'tcx, HR>(tcx: &ctxt<'tcx>, sig: &HR) -> HR - where HR: HigherRankedFoldable<'tcx> { +pub fn anonymize_late_bound_regions<'tcx, T>( + tcx: &ctxt<'tcx>, + sig: &Binder) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx>, +{ let mut counter = 0; replace_late_bound_regions(tcx, sig, |_, db| { counter += 1; @@ -6330,39 +6425,35 @@ pub fn anonymize_late_bound_regions<'tcx, HR>(tcx: &ctxt<'tcx>, sig: &HR) -> HR } /// Replaces the late-bound-regions in `value` that are bound by `value`. -pub fn replace_late_bound_regions<'tcx, HR, F>( +pub fn replace_late_bound_regions<'tcx, T, F>( tcx: &ty::ctxt<'tcx>, - value: &HR, + binder: &Binder, mut mapf: F) --> (HR, FnvHashMap) where - HR : HigherRankedFoldable<'tcx>, - F: FnMut(BoundRegion, DebruijnIndex) -> ty::Region, + -> (T, FnvHashMap) + where T : TypeFoldable<'tcx> + Repr<'tcx>, + F : FnMut(BoundRegion, DebruijnIndex) -> ty::Region, { - debug!("replace_late_bound_regions({})", value.repr(tcx)); + debug!("replace_late_bound_regions({})", binder.repr(tcx)); let mut map = FnvHashMap::new(); - let value = { - let mut f = ty_fold::RegionFolder::new(tcx, |region, current_depth| { - debug!("region={}", region.repr(tcx)); - match region { - ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => { - * match map.entry(br) { - Vacant(entry) => entry.set(mapf(br, debruijn)), - Occupied(entry) => entry.into_mut(), - } - } - _ => { - region + + // Note: fold the field `0`, not the binder, so that late-bound + // regions bound by `binder` are considered free. + let value = ty_fold::fold_regions(tcx, &binder.0, |region, current_depth| { + debug!("region={}", region.repr(tcx)); + match region { + ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => { + * match map.entry(br) { + Vacant(entry) => entry.set(mapf(br, debruijn)), + Occupied(entry) => entry.into_mut(), } } - }); + _ => { + region + } + } + }); - // Note: use `fold_contents` not `fold_with`. If we used - // `fold_with`, it would consider the late-bound regions bound - // by `value` to be bound, but we want to consider them as - // `free`. - value.fold_contents(&mut f) - }; debug!("resulting map: {} value: {}", map, value.repr(tcx)); (value, map) } @@ -6440,9 +6531,9 @@ impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { Predicate::Trait(ref a) => a.repr(tcx), - Predicate::Equate(a, b) => format!("Equate({},{})", a.repr(tcx), b.repr(tcx)), - Predicate::RegionOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)), - Predicate::TypeOutlives(a, b) => format!("Outlives({}:{})", a.repr(tcx), b.repr(tcx)), + Predicate::Equate(ref pair) => format!("Equate({})", pair.repr(tcx)), + Predicate::RegionOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), + Predicate::TypeOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), } } } @@ -6538,3 +6629,49 @@ pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>, Ok(()) } + +pub trait RegionEscape { + fn has_escaping_regions(&self) -> bool { + self.has_regions_escaping_depth(0) + } + + fn has_regions_escaping_depth(&self, depth: uint) -> bool; +} + +impl<'tcx> RegionEscape for Ty<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + ty::type_escapes_depth(*self, depth) + } +} + +impl RegionEscape for Region { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.escapes_depth(depth) + } +} + +impl<'tcx> RegionEscape for TraitRef<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) && + self.substs.regions().iter().any(|t| t.has_regions_escaping_depth(depth)) + } +} + +impl<'tcx,T:RegionEscape> RegionEscape for Binder { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.0.has_regions_escaping_depth(depth + 1) + } +} + +impl<'tcx> RegionEscape for EquatePredicate<'tcx> { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) + } +} + +impl RegionEscape for OutlivesPredicate { + fn has_regions_escaping_depth(&self, depth: uint) -> bool { + self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) + } +} + diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 4877512ce5816..71e42a9dbb3de 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -93,8 +93,8 @@ pub trait TypeFolder<'tcx> { } fn fold_fn_sig(&mut self, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { + sig: &ty::FnSig<'tcx>) + -> ty::FnSig<'tcx> { super_fold_fn_sig(self, sig) } @@ -183,7 +183,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { fn fold_with>(&self, folder: &mut F) -> ty::Binder { folder.enter_region_binder(); - let result = ty::bind(self.value.fold_with(folder)); + let result = ty::Binder(self.0.fold_with(folder)); folder.exit_region_binder(); result } @@ -409,15 +409,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => ty::Predicate::Trait(a.fold_with(folder)), - ty::Predicate::Equate(ref a, ref b) => - ty::Predicate::Equate(a.fold_with(folder), - b.fold_with(folder)), - ty::Predicate::RegionOutlives(ref a, ref b) => - ty::Predicate::RegionOutlives(a.fold_with(folder), - b.fold_with(folder)), - ty::Predicate::TypeOutlives(ref a, ref b) => - ty::Predicate::TypeOutlives(a.fold_with(folder), - b.fold_with(folder)), + ty::Predicate::Equate(ref binder) => + ty::Predicate::Equate(binder.fold_with(folder)), + ty::Predicate::RegionOutlives(ref binder) => + ty::Predicate::RegionOutlives(binder.fold_with(folder)), + ty::Predicate::TypeOutlives(ref binder) => + ty::Predicate::TypeOutlives(binder.fold_with(folder)), } } } @@ -501,6 +498,23 @@ impl<'tcx> TypeFoldable<'tcx> for traits::VtableParamData<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { + fn fold_with>(&self, folder: &mut F) -> ty::EquatePredicate<'tcx> { + ty::EquatePredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } +} + +impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate + where T : TypeFoldable<'tcx>, + U : TypeFoldable<'tcx>, +{ + fn fold_with>(&self, folder: &mut F) -> ty::OutlivesPredicate { + ty::OutlivesPredicate(self.0.fold_with(folder), + self.1.fold_with(folder)) + } +} + /////////////////////////////////////////////////////////////////////////// // "super" routines: these are the default implementations for TypeFolder. // @@ -532,16 +546,6 @@ pub fn super_fold_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T, pub fn super_fold_fn_sig<'tcx, T: TypeFolder<'tcx>>(this: &mut T, sig: &ty::FnSig<'tcx>) -> ty::FnSig<'tcx> -{ - this.enter_region_binder(); - let result = super_fold_fn_sig_contents(this, sig); - this.exit_region_binder(); - result -} - -pub fn super_fold_fn_sig_contents<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - sig: &ty::FnSig<'tcx>) - -> ty::FnSig<'tcx> { ty::FnSig { inputs: sig.inputs.fold_with(this), output: sig.output.fold_with(this), @@ -583,16 +587,6 @@ pub fn super_fold_closure_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, pub fn super_fold_trait_ref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, t: &ty::TraitRef<'tcx>) -> ty::TraitRef<'tcx> -{ - this.enter_region_binder(); - let result = super_fold_trait_ref_contents(this, t); - this.exit_region_binder(); - result -} - -pub fn super_fold_trait_ref_contents<'tcx, T: TypeFolder<'tcx>>(this: &mut T, - t: &ty::TraitRef<'tcx>) - -> ty::TraitRef<'tcx> { ty::TraitRef { def_id: t.def_id, @@ -706,40 +700,6 @@ pub fn super_fold_item_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T, } } -/////////////////////////////////////////////////////////////////////////// -// Higher-ranked things - -/// Designates a "binder" for late-bound regions. -pub trait HigherRankedFoldable<'tcx>: Repr<'tcx> { - /// Folds the contents of `self`, ignoring the region binder created - /// by `self`. - fn fold_contents>(&self, folder: &mut F) -> Self; -} - -impl<'tcx> HigherRankedFoldable<'tcx> for ty::FnSig<'tcx> { - fn fold_contents>(&self, folder: &mut F) -> ty::FnSig<'tcx> { - super_fold_fn_sig_contents(folder, self) - } -} - -impl<'tcx> HigherRankedFoldable<'tcx> for ty::TraitRef<'tcx> { - fn fold_contents>(&self, folder: &mut F) -> ty::TraitRef<'tcx> { - super_fold_trait_ref_contents(folder, self) - } -} - -impl<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>> HigherRankedFoldable<'tcx> for ty::Binder { - fn fold_contents>(&self, folder: &mut F) -> ty::Binder { - ty::bind(self.value.fold_with(folder)) - } -} - -impl<'tcx, T:HigherRankedFoldable<'tcx>> HigherRankedFoldable<'tcx> for Rc { - fn fold_contents>(&self, folder: &mut F) -> Rc { - Rc::new((**self).fold_contents(folder)) - } -} - /////////////////////////////////////////////////////////////////////////// // Some sample folders @@ -751,7 +711,7 @@ pub struct BottomUpFolder<'a, 'tcx: 'a, F> where F: FnMut(Ty<'tcx>) -> Ty<'tcx> impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } + fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let t1 = super_fold_ty(self, ty); @@ -770,18 +730,17 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx, F> where /// regions (aka "lifetimes") that are bound within a type are not /// visited by this folder; only regions that occur free will be /// visited by `fld_r`. -/// -/// (The distinction between "free" and "bound" is represented by -/// keeping track of each `FnSig` in the lexical context of the -/// current position of the fold.) -pub struct RegionFolder<'a, 'tcx: 'a, F> where F: FnMut(ty::Region, uint) -> ty::Region { + +pub struct RegionFolder<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, current_depth: uint, - fld_r: F, + fld_r: &'a mut (FnMut(ty::Region, uint) -> ty::Region + 'a), } -impl<'a, 'tcx, F> RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) -> ty::Region { - pub fn new(tcx: &'a ty::ctxt<'tcx>, fld_r: F) -> RegionFolder<'a, 'tcx, F> { +impl<'a, 'tcx> RegionFolder<'a, 'tcx> { + pub fn new(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionFolder<'a, 'tcx> + where F : FnMut(ty::Region, uint) -> ty::Region + { RegionFolder { tcx: tcx, current_depth: 1, @@ -790,10 +749,27 @@ impl<'a, 'tcx, F> RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) -> } } -impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where - F: FnMut(ty::Region, uint) -> ty::Region, +pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec + where T : TypeFoldable<'tcx> +{ + let mut vec = Vec::new(); + fold_regions(tcx, value, |r, _| { vec.push(r); r }); + vec +} + +pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>, + value: &T, + mut f: F) + -> T + where F : FnMut(ty::Region, uint) -> ty::Region, + T : TypeFoldable<'tcx>, { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx } + value.fold_with(&mut RegionFolder::new(tcx, &mut f)) +} + +impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> +{ + fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } fn enter_region_binder(&mut self) { self.current_depth += 1; @@ -813,7 +789,7 @@ impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where _ => { debug!("RegionFolder.fold_region({}) folding free region (current_depth={})", r.repr(self.tcx()), self.current_depth); - (self.fld_r)(r, self.current_depth) + self.fld_r.call_mut((r, self.current_depth)) } } } @@ -869,7 +845,7 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>>(tcx: &ty::ctxt<'tcx> debug!("shift_regions(value={}, amount={})", value.repr(tcx), amount); - value.fold_with(&mut RegionFolder::new(tcx, |region, _current_depth| { + value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| { shift_region(region, amount) })) } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 13b5c262bf782..b0124977c9f1b 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -23,7 +23,10 @@ use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup, ty_open}; use middle::ty::{ty_unboxed_closure}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; use middle::ty; +use middle::ty_fold::TypeFoldable; +use std::collections::HashMap; +use std::hash::{Hash, Hasher}; use std::rc::Rc; use syntax::abi; use syntax::ast_map; @@ -40,7 +43,7 @@ pub trait Repr<'tcx> for Sized? { } /// Produces a string suitable for showing to the user. -pub trait UserString<'tcx> { +pub trait UserString<'tcx> : Repr<'tcx> { fn user_string(&self, tcx: &ctxt<'tcx>) -> String; } @@ -248,21 +251,12 @@ pub fn vec_map_to_string(ts: &[T], f: F) -> String where format!("[{}]", tstrs.connect(", ")) } -pub fn fn_sig_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::FnSig<'tcx>) -> String { - format!("fn{} -> {}", typ.inputs.repr(cx), typ.output.repr(cx)) -} - -pub fn trait_ref_to_string<'tcx>(cx: &ctxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>) -> String { - trait_ref.user_string(cx).to_string() -} - pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { fn bare_fn_to_string<'tcx>(cx: &ctxt<'tcx>, unsafety: ast::Unsafety, abi: abi::Abi, ident: Option, - sig: &ty::FnSig<'tcx>) + sig: &ty::PolyFnSig<'tcx>) -> String { let mut s = String::new(); match unsafety { @@ -336,15 +330,15 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { s: &mut String, bra: char, ket: char, - sig: &ty::FnSig<'tcx>, + sig: &ty::PolyFnSig<'tcx>, bounds: &str) { s.push(bra); - let strs = sig.inputs + let strs = sig.0.inputs .iter() .map(|a| ty_to_string(cx, *a)) .collect::>(); s.push_str(strs.connect(", ").as_slice()); - if sig.variadic { + if sig.0.variadic { s.push_str(", ..."); } s.push(ket); @@ -354,7 +348,7 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { s.push_str(bounds); } - match sig.output { + match sig.0.output { ty::FnConverging(t) => { if !ty::type_is_nil(t) { s.push_str(" -> "); @@ -374,8 +368,8 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty::IntVar(ref vid) if print_var_ids => vid.repr(cx), ty::FloatVar(ref vid) if print_var_ids => vid.repr(cx), ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => format!("_"), - ty::SkolemizedTy(v) => format!("SkolemizedTy({})", v), - ty::SkolemizedIntTy(v) => format!("SkolemizedIntTy({})", v) + ty::FreshTy(v) => format!("FreshTy({})", v), + ty::FreshIntTy(v) => format!("FreshIntTy({})", v) } } @@ -433,16 +427,11 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { - let base = ty::item_path_str(cx, principal.def_id); - let trait_def = ty::lookup_trait_def(cx, principal.def_id); - let did = trait_def.trait_ref.def_id; - let ty = parameterized(cx, base.as_slice(), - &principal.substs, &trait_def.generics, - did); + let principal = principal.user_string(cx); let bound_str = bounds.user_string(cx); let bound_sep = if bound_str.is_empty() { "" } else { " + " }; format!("{}{}{}", - ty, + principal, bound_sep, bound_str) } @@ -749,7 +738,7 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> { // tells you everything you need to know. let base = ty::item_path_str(tcx, self.def_id); let trait_def = ty::lookup_trait_def(tcx, self.def_id); - format!("<{} : {}>", + format!("TraitRef({}, {})", self.substs.self_ty().repr(tcx), parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics, self.def_id)) } @@ -1018,7 +1007,7 @@ impl<'tcx> Repr<'tcx> for ty::BareFnTy<'tcx> { impl<'tcx> Repr<'tcx> for ty::FnSig<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - fn_sig_to_string(tcx, self) + format!("fn{} -> {}", self.inputs.repr(tcx), self.output.repr(tcx)) } } @@ -1161,7 +1150,9 @@ impl<'tcx> UserString<'tcx> for ty::BuiltinBounds { } } -impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { +impl<'tcx, T> UserString<'tcx> for ty::Binder + where T : UserString<'tcx> + TypeFoldable<'tcx> +{ fn user_string(&self, tcx: &ctxt<'tcx>) -> String { // Replace any anonymous late-bound regions with named // variants, using gensym'd identifiers, so that we can @@ -1169,7 +1160,7 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { // the output. We'll probably want to tweak this over time to // decide just how much information to give. let mut names = Vec::new(); - let (trait_ref, _) = ty::replace_late_bound_regions(tcx, self, |br, debruijn| { + let (unbound_value, _) = ty::replace_late_bound_regions(tcx, self, |br, debruijn| { ty::ReLateBound(debruijn, match br { ty::BrNamed(_, name) => { names.push(token::get_name(name)); @@ -1178,7 +1169,7 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { ty::BrAnon(_) | ty::BrFresh(_) | ty::BrEnv => { - let name = token::gensym("r"); + let name = token::gensym("'r"); names.push(token::get_name(name)); ty::BrNamed(ast_util::local_def(ast::DUMMY_NODE_ID), name) } @@ -1186,19 +1177,21 @@ impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { }); let names: Vec<_> = names.iter().map(|s| s.get()).collect(); - // Let the base string be either `SomeTrait` for `for<'a,'b> SomeTrait`, - // depending on whether there are bound regions. - let path_str = ty::item_path_str(tcx, self.def_id); - let base = - if names.is_empty() { - path_str - } else { - format!("for<{}> {}", names.connect(","), path_str) - }; + let value_str = unbound_value.user_string(tcx); + if names.len() == 0 { + value_str + } else { + format!("for<{}> {}", names.connect(","), value_str) + } + } +} +impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + let path_str = ty::item_path_str(tcx, self.def_id); let trait_def = ty::lookup_trait_def(tcx, self.def_id); - let did = trait_def.trait_ref.def_id; - parameterized(tcx, base.as_slice(), &trait_ref.substs, &trait_def.generics, did) + parameterized(tcx, path_str.as_slice(), &self.substs, + &trait_def.generics, self.def_id) } } @@ -1340,6 +1333,73 @@ impl<'tcx, A:Repr<'tcx>, B:Repr<'tcx>> Repr<'tcx> for (A,B) { impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for ty::Binder { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("Binder({})", self.value.repr(tcx)) + format!("Binder({})", self.0.repr(tcx)) + } +} + +impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap + where K : Hash + Eq + Repr<'tcx>, + V : Repr<'tcx>, + H : Hasher +{ + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("HashMap({})", + self.iter() + .map(|(k,v)| format!("{} => {}", k.repr(tcx), v.repr(tcx))) + .collect::>() + .connect(", ")) + } +} + +impl<'tcx, T, U> Repr<'tcx> for ty::OutlivesPredicate + where T : Repr<'tcx> + TypeFoldable<'tcx>, + U : Repr<'tcx> + TypeFoldable<'tcx>, +{ + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("OutlivesPredicate({}, {})", + self.0.repr(tcx), + self.1.repr(tcx)) + } +} + +impl<'tcx, T, U> UserString<'tcx> for ty::OutlivesPredicate + where T : UserString<'tcx> + TypeFoldable<'tcx>, + U : UserString<'tcx> + TypeFoldable<'tcx>, +{ + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + format!("{} : {}", + self.0.user_string(tcx), + self.1.user_string(tcx)) + } +} + +impl<'tcx> Repr<'tcx> for ty::EquatePredicate<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("EquatePredicate({}, {})", + self.0.repr(tcx), + self.1.repr(tcx)) + } +} + +impl<'tcx> UserString<'tcx> for ty::EquatePredicate<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + format!("{} == {}", + self.0.user_string(tcx), + self.1.user_string(tcx)) + } +} + +impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> { + fn user_string(&self, tcx: &ctxt<'tcx>) -> String { + match *self { + ty::Predicate::Trait(ref trait_ref) => { + format!("{} : {}", + trait_ref.self_ty().user_string(tcx), + trait_ref.user_string(tcx)) + } + ty::Predicate::Equate(ref predicate) => predicate.user_string(tcx), + ty::Predicate::RegionOutlives(ref predicate) => predicate.user_string(tcx), + ty::Predicate::TypeOutlives(ref predicate) => predicate.user_string(tcx), + } } } diff --git a/src/librustc/util/snapshot_vec.rs b/src/librustc/util/snapshot_vec.rs index e80e8dc535104..749c39d7a6b92 100644 --- a/src/librustc/util/snapshot_vec.rs +++ b/src/librustc/util/snapshot_vec.rs @@ -23,7 +23,7 @@ use self::UndoLog::*; use std::mem; #[deriving(PartialEq)] -enum UndoLog { +pub enum UndoLog { /// Indicates where a snapshot started. OpenSnapshot, @@ -113,6 +113,12 @@ impl> SnapshotVec { Snapshot { length: length } } + pub fn actions_since_snapshot(&self, + snapshot: &Snapshot) + -> &[UndoLog] { + self.undo_log[snapshot.length..] + } + fn assert_open_snapshot(&self, snapshot: &Snapshot) { // Or else there was a failure to follow a stack discipline: assert!(self.undo_log.len() > snapshot.length); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 508af4c28e66c..b2c661cc58aa4 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -25,6 +25,7 @@ use rustc_typeck::middle::infer::combine::Combine; use rustc_typeck::middle::infer; use rustc_typeck::middle::infer::lub::Lub; use rustc_typeck::middle::infer::glb::Glb; +use rustc_typeck::middle::infer::sub::Sub; use rustc_typeck::util::ppaux::{ty_to_string, Repr, UserString}; use rustc::session::{mod,config}; use syntax::{abi, ast, ast_map, ast_util}; @@ -274,11 +275,11 @@ impl<'a, 'tcx> Env<'a, 'tcx> { onceness: ast::Many, store: ty::RegionTraitStore(region_bound, ast::MutMutable), bounds: ty::region_existential_bound(region_bound), - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: input_tys.to_vec(), output: ty::FnConverging(output_ty), variadic: false, - }, + }), abi: abi::Rust, }) } @@ -341,6 +342,11 @@ impl<'a, 'tcx> Env<'a, 'tcx> { infer::TypeTrace::dummy() } + pub fn sub(&self) -> Sub<'a, 'tcx> { + let trace = self.dummy_type_trace(); + Sub(self.infcx.combine_fields(true, trace)) + } + pub fn lub(&self) -> Lub<'a, 'tcx> { let trace = self.dummy_type_trace(); Lub(self.infcx.combine_fields(true, trace)) @@ -359,6 +365,33 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } } + /// Checks that `t1 <: t2` is true (this may register additional + /// region checks). + pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { + match self.sub().tys(t1, t2) { + Ok(_) => { } + Err(ref e) => { + panic!("unexpected error computing sub({},{}): {}", + t1.repr(self.infcx.tcx), + t2.repr(self.infcx.tcx), + ty::type_err_to_str(self.infcx.tcx, e)); + } + } + } + + /// Checks that `t1 <: t2` is false (this may register additional + /// region checks). + pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { + match self.sub().tys(t1, t2) { + Err(_) => { } + Ok(_) => { + panic!("unexpected success computing sub({},{})", + t1.repr(self.infcx.tcx), + t2.repr(self.infcx.tcx)); + } + } + } + /// Checks that `LUB(t1,t2) == t_lub` pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { match self.lub().tys(t1, t2) { @@ -421,6 +454,74 @@ fn contravariant_region_ptr_err() { }) } +#[test] +fn sub_free_bound_false() { + //! Test that: + //! + //! fn(&'a int) <: for<'b> fn(&'b int) + //! + //! does NOT hold. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_free1 = env.t_rptr_free(0, 1); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + env.check_not_sub(env.t_fn(&[t_rptr_free1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + }) +} + +#[test] +fn sub_bound_free_true() { + //! Test that: + //! + //! for<'a> fn(&'a int) <: fn(&'b int) + //! + //! DOES hold. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_rptr_free1 = env.t_rptr_free(0, 1); + env.check_sub(env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_rptr_free1], ty::mk_int())); + }) +} + +#[test] +fn sub_free_bound_false_infer() { + //! Test that: + //! + //! fn(_#1) <: for<'b> fn(&'b int) + //! + //! does NOT hold for any instantiation of `_#1`. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_infer1 = env.infcx.next_ty_var(); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + env.check_not_sub(env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + }) +} + +#[test] +fn lub_free_bound_infer() { + //! Test result of: + //! + //! LUB(fn(_#1), for<'b> fn(&'b int)) + //! + //! This should yield `fn(&'_ int)`. We check + //! that it yields `fn(&'x int)` for some free `'x`, + //! anyhow. + + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_infer1 = env.infcx.next_ty_var(); + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_rptr_free1 = env.t_rptr_free(0, 1); + env.check_lub(env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_rptr_free1], ty::mk_int())); + }); +} + #[test] fn lub_bound_bound() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { @@ -524,6 +625,28 @@ fn glb_bound_free() { }) } +#[test] +fn glb_bound_free_infer() { + test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + let t_rptr_bound1 = env.t_rptr_late_bound(1); + let t_infer1 = env.infcx.next_ty_var(); + + // compute GLB(fn(_) -> int, for<'b> fn(&'b int) -> int), + // which should yield for<'b> fn(&'b int) -> int + env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()), + env.t_fn(&[t_infer1], ty::mk_int()), + env.t_fn(&[t_rptr_bound1], ty::mk_int())); + + // as a side-effect, computing GLB should unify `_` with + // `&'_ int` + let t_resolve1 = env.infcx.shallow_resolve(t_infer1); + match t_resolve1.sty { + ty::ty_rptr(..) => { } + _ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); } + } + }) +} + #[test] fn glb_bound_static() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f1d839e916d56..b947b1746fcab 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -282,10 +282,10 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, name: &str) -> ValueRef { let (inputs, output, abi, env) = match fn_ty.sty { ty::ty_bare_fn(ref f) => { - (f.sig.inputs.clone(), f.sig.output, f.abi, None) + (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None) } ty::ty_closure(ref f) => { - (f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx))) + (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, Some(Type::i8p(ccx))) } ty::ty_unboxed_closure(closure_did, _, ref substs) => { let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); @@ -293,8 +293,8 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let function_type = unboxed_closure.closure_type.clone(); let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty); let llenvironment_type = type_of_explicit_arg(ccx, self_type); - (function_type.sig.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(), - function_type.sig.output.subst(ccx.tcx(), substs), + (function_type.sig.0.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(), + function_type.sig.0.output.subst(ccx.tcx(), substs), RustCall, Some(llenvironment_type)) } @@ -1998,7 +1998,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let tcx = ccx.tcx(); let result_ty = match ctor_ty.sty { - ty::ty_bare_fn(ref bft) => bft.sig.output.unwrap(), + ty::ty_bare_fn(ref bft) => bft.sig.0.output.unwrap(), _ => ccx.sess().bug( format!("trans_enum_variant_constructor: \ unexpected ctor return type {}", @@ -2070,7 +2070,7 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx let ctor_ty = ctor_ty.subst(ccx.tcx(), param_substs); let result_ty = match ctor_ty.sty { - ty::ty_bare_fn(ref bft) => bft.sig.output, + ty::ty_bare_fn(ref bft) => bft.sig.0.output, _ => ccx.sess().bug( format!("trans_enum_variant_or_tuple_like_struct: \ unexpected ctor return type {}", @@ -2439,7 +2439,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< // at either 1 or 2 depending on whether there's an env slot or not let mut first_arg_offset = if has_env { 2 } else { 1 }; let mut attrs = llvm::AttrBuilder::new(); - let ret_ty = fn_sig.output; + let ret_ty = fn_sig.0.output; // These have an odd calling convention, so we need to manually // unpack the input ty's @@ -2447,15 +2447,15 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< ty::ty_unboxed_closure(_, _, _) => { assert!(abi == RustCall); - match fn_sig.inputs[0].sty { + match fn_sig.0.inputs[0].sty { ty::ty_tup(ref inputs) => inputs.clone(), _ => ccx.sess().bug("expected tuple'd inputs") } }, ty::ty_bare_fn(_) if abi == RustCall => { - let mut inputs = vec![fn_sig.inputs[0]]; + let mut inputs = vec![fn_sig.0.inputs[0]]; - match fn_sig.inputs[1].sty { + match fn_sig.0.inputs[1].sty { ty::ty_tup(ref t_in) => { inputs.push_all(t_in.as_slice()); inputs @@ -2463,7 +2463,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< _ => ccx.sess().bug("expected tuple'd inputs") } } - _ => fn_sig.inputs.clone() + _ => fn_sig.0.inputs.clone() }; if let ty::FnConverging(ret_ty) = ret_ty { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index ff2f686fff876..f8303a6f03080 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -280,9 +280,9 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( match bare_fn_ty.sty { ty::ty_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: synabi::Rust, - sig: ty::FnSig { inputs: ref input_tys, - output: output_ty, - variadic: false }}) => + sig: ty::Binder(ty::FnSig { inputs: ref input_tys, + output: output_ty, + variadic: false })}) => { (input_tys, output_ty) } @@ -296,12 +296,12 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let tuple_fn_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: synabi::RustCall, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: vec![bare_fn_ty_ref, tuple_input_ty], output: output_ty, variadic: false - }}); + })}); debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx)); // @@ -422,7 +422,6 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( match impl_or_trait_item { ty::MethodTraitItem(method) => { let trait_ref = ty::impl_trait_ref(tcx, impl_id).unwrap(); - let trait_ref = ty::erase_late_bound_regions(tcx, &trait_ref); // Compute the first substitution let first_subst = @@ -657,8 +656,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let mut bcx = callee.bcx; let (abi, ret_ty) = match callee_ty.sty { - ty::ty_bare_fn(ref f) => (f.abi, f.sig.output), - ty::ty_closure(ref f) => (f.abi, f.sig.output), + ty::ty_bare_fn(ref f) => (f.abi, f.sig.0.output), + ty::ty_closure(ref f) => (f.abi, f.sig.0.output), _ => panic!("expected bare rust fn or closure in trans_call_inner") }; diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 1811388662c45..af3daf224e326 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -658,9 +658,9 @@ pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let arena = TypedArena::new(); let empty_param_substs = Substs::trans_empty(); - let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.output, + let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.0.output, &empty_param_substs, None, &arena); - let bcx = init_function(&fcx, true, f.sig.output); + let bcx = init_function(&fcx, true, f.sig.0.output); let args = create_datums_for_fn_args(&fcx, ty::ty_fn_args(closure_ty) @@ -676,7 +676,7 @@ pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llargs.extend(args.iter().map(|arg| arg.val)); let retval = Call(bcx, fn_ptr, llargs.as_slice(), None); - match f.sig.output { + match f.sig.0.output { ty::FnConverging(output_type) => { if return_type_is_void(ccx, output_type) || fcx.llretslotptr.get().is_some() { RetVoid(bcx); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 83938fa335708..a8e88eca0e19f 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -764,7 +764,7 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ex: &ast::Expr) -> T /// guarantee to us that all nested obligations *could be* resolved if we wanted to. pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, span: Span, - trait_ref: Rc>) + trait_ref: Rc>) -> traits::Vtable<'tcx, ()> { let tcx = ccx.tcx(); @@ -783,7 +783,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("trans fulfill_obligation: trait_ref={}", trait_ref.repr(ccx.tcx())); - ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id); + 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, @@ -848,12 +848,12 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } - // Use skolemize to simultaneously replace all type variables with + // Use freshen 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 = vtable.fold_with(&mut infcx.skolemizer()); + // unbound type variables, hence no `TyFresh` types should ever be + // inserted. + let vtable = vtable.fold_with(&mut infcx.freshener()); info!("Cache miss: {}", trait_ref.repr(ccx.tcx())); ccx.trait_cache().borrow_mut().insert(trait_ref, diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 89fa6a72e883d..af003b011579f 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -99,7 +99,7 @@ pub struct LocalCrateContext<'tcx> { monomorphized: RefCell, ValueRef>>, monomorphizing: RefCell>, /// Cache generated vtables - vtables: RefCell, Rc>), ValueRef>>, + vtables: RefCell, Rc>), ValueRef>>, /// Cache of constant strings, const_cstr_cache: RefCell>, @@ -150,7 +150,7 @@ pub struct LocalCrateContext<'tcx> { /// contexts around the same size. n_llvm_insns: Cell, - trait_cache: RefCell>, + trait_cache: RefCell>, traits::Vtable<'tcx, ()>>>, } @@ -601,7 +601,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.monomorphizing } - pub fn vtables<'a>(&'a self) -> &'a RefCell, Rc>), + pub fn vtables<'a>(&'a self) -> &'a RefCell, Rc>), ValueRef>> { &self.local.vtables } @@ -699,7 +699,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1); } - pub fn trait_cache(&self) -> &RefCell>, + pub fn trait_cache(&self) -> &RefCell>, traits::Vtable<'tcx, ()>>> { &self.local.trait_cache } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index e9730f7af0ec1..96c39b5796ec4 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -429,8 +429,8 @@ impl<'tcx> TypeMap<'tcx> { from_def_id_and_substs(self, cx, - trait_data.principal.def_id, - &trait_data.principal.substs, + trait_data.principal.def_id(), + trait_data.principal.substs(), &mut unique_type_id); }, ty::ty_bare_fn(ty::BareFnTy{ unsafety, abi, ref sig } ) => { @@ -442,7 +442,7 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push_str(" fn("); - for ¶meter_type in sig.inputs.iter() { + for ¶meter_type in sig.0.inputs.iter() { let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type); let parameter_type_id = @@ -451,12 +451,12 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push(','); } - if sig.variadic { + if sig.0.variadic { unique_type_id.push_str("..."); } unique_type_id.push_str(")->"); - match sig.output { + match sig.0.output { ty::FnConverging(ret_ty) => { let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty); let return_type_id = self.get_unique_type_id_as_string(return_type_id); @@ -575,7 +575,7 @@ impl<'tcx> TypeMap<'tcx> { } }; - for ¶meter_type in sig.inputs.iter() { + for ¶meter_type in sig.0.inputs.iter() { let parameter_type_id = self.get_unique_type_id_of_type(cx, parameter_type); let parameter_type_id = @@ -584,13 +584,13 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push(','); } - if sig.variadic { + if sig.0.variadic { unique_type_id.push_str("..."); } unique_type_id.push_str("|->"); - match sig.output { + match sig.0.output { ty::FnConverging(ret_ty) => { let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty); let return_type_id = self.get_unique_type_id_as_string(return_type_id); @@ -2787,13 +2787,13 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id: UniqueTypeId, - signature: &ty::FnSig<'tcx>, + signature: &ty::PolyFnSig<'tcx>, span: Span) -> MetadataCreationResult { - let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs.len() + 1); + let mut signature_metadata: Vec = Vec::with_capacity(signature.0.inputs.len() + 1); // return type - signature_metadata.push(match signature.output { + signature_metadata.push(match signature.0.output { ty::FnConverging(ret_ty) => match ret_ty.sty { ty::ty_tup(ref tys) if tys.is_empty() => ptr::null_mut(), _ => type_metadata(cx, ret_ty, span) @@ -2802,7 +2802,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }); // regular arguments - for &argument_type in signature.inputs.iter() { + for &argument_type in signature.0.inputs.iter() { signature_metadata.push(type_metadata(cx, argument_type, span)); } @@ -2834,7 +2834,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // But it does not describe the trait's methods. let def_id = match trait_type.sty { - ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id, + ty::ty_trait(box ty::TyTrait { ref principal, .. }) => principal.def_id(), _ => { let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type); cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \ @@ -3765,8 +3765,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(']'); }, ty::ty_trait(ref trait_data) => { - push_item_name(cx, trait_data.principal.def_id, false, output); - push_type_params(cx, &trait_data.principal.substs, output); + push_item_name(cx, trait_data.principal.def_id(), false, output); + push_type_params(cx, trait_data.principal.substs(), output); }, ty::ty_bare_fn(ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == ast::Unsafety::Unsafe { @@ -3781,8 +3781,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push_str("fn("); - if sig.inputs.len() > 0 { - for ¶meter_type in sig.inputs.iter() { + if sig.0.inputs.len() > 0 { + for ¶meter_type in sig.0.inputs.iter() { push_debuginfo_type_name(cx, parameter_type, true, output); output.push_str(", "); } @@ -3790,8 +3790,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.pop(); } - if sig.variadic { - if sig.inputs.len() > 0 { + if sig.0.variadic { + if sig.0.inputs.len() > 0 { output.push_str(", ..."); } else { output.push_str("..."); @@ -3800,7 +3800,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(')'); - match sig.output { + match sig.0.output { ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {} ty::FnConverging(result_type) => { output.push_str(" -> "); @@ -3841,8 +3841,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } }; - if sig.inputs.len() > 0 { - for ¶meter_type in sig.inputs.iter() { + if sig.0.inputs.len() > 0 { + for ¶meter_type in sig.0.inputs.iter() { push_debuginfo_type_name(cx, parameter_type, true, output); output.push_str(", "); } @@ -3850,8 +3850,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.pop(); } - if sig.variadic { - if sig.inputs.len() > 0 { + if sig.0.variadic { + if sig.0.inputs.len() > 0 { output.push_str(", ..."); } else { output.push_str("..."); @@ -3860,7 +3860,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push(param_list_closing_char); - match sig.output { + match sig.0.output { ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {} ty::FnConverging(result_type) => { output.push_str(" -> "); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 304142453a9c8..db44e0ce27197 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -316,10 +316,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.ty_to_string(unadjusted_ty)).as_slice()) }, &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => { - let substs = principal.substs.with_self_ty(unadjusted_ty).erase_regions(); + let substs = principal.substs().with_self_ty(unadjusted_ty).erase_regions(); let trait_ref = - Rc::new(ty::TraitRef { def_id: principal.def_id, - substs: substs }); + Rc::new(ty::Binder(ty::TraitRef { def_id: principal.def_id(), + substs: substs })); let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs); let box_ty = mk_ty(unadjusted_ty); PointerCast(bcx, diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 615d5467f8464..d072031993050 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -22,7 +22,6 @@ use trans::machine; use trans::type_::Type; use trans::type_of::*; use trans::type_of; -use middle::ty::FnSig; use middle::ty::{mod, Ty}; use middle::subst::{Subst, Substs}; use std::cmp; @@ -41,7 +40,7 @@ use util::ppaux::Repr; struct ForeignTypes<'tcx> { /// Rust signature of the function - fn_sig: ty::FnSig<'tcx>, + fn_sig: ty::PolyFnSig<'tcx>, /// Adapter object for handling native ABI rules (trust me, you /// don't want to know) @@ -179,7 +178,7 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Make sure the calling convention is right for variadic functions // (should've been caught if not in typeck) - if tys.fn_sig.variadic { + if tys.fn_sig.0.variadic { assert!(cc == llvm::CCallConv); } @@ -386,7 +385,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("llforeign_ret_ty={}", ccx.tn().type_to_string(llforeign_ret_ty)); if llrust_ret_ty == llforeign_ret_ty { - match fn_sig.output { + match fn_sig.0.output { ty::FnConverging(result_ty) => { base::store_ty(bcx, llforeign_retval, llretptr, result_ty) } @@ -632,7 +631,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; // Push Rust return pointer, using null if it will be unused. - let rust_uses_outptr = match tys.fn_sig.output { + let rust_uses_outptr = match tys.fn_sig.0.output { ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty), ty::FnDiverging => false }; @@ -665,7 +664,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return_ty={}", ccx.tn().val_to_string(slot), ccx.tn().type_to_string(llrust_ret_ty), - tys.fn_sig.output.repr(tcx)); + tys.fn_sig.0.output.repr(tcx)); llrust_args.push(slot); return_alloca = Some(slot); } @@ -680,8 +679,8 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Build up the arguments to the call to the rust function. // Careful to adapt for cases where the native convention uses // a pointer and Rust does not or vice versa. - for i in range(0, tys.fn_sig.inputs.len()) { - let rust_ty = tys.fn_sig.inputs[i]; + for i in range(0, tys.fn_sig.0.inputs.len()) { + let rust_ty = tys.fn_sig.0.inputs[i]; let llrust_ty = tys.llsig.llarg_tys[i]; let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty); let llforeign_arg_ty = tys.fn_ty.arg_tys[i]; @@ -826,10 +825,10 @@ pub fn link_name(i: &ast::ForeignItem) -> InternedString { /// because foreign functions just plain ignore modes. They also don't pass aggregate values by /// pointer like we do. fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - fn_sig: &ty::FnSig<'tcx>, arg_tys: &[Ty<'tcx>]) + fn_sig: &ty::PolyFnSig<'tcx>, arg_tys: &[Ty<'tcx>]) -> LlvmSignature { let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect(); - let (llret_ty, ret_def) = match fn_sig.output { + let (llret_ty, ret_def) = match fn_sig.0.output { ty::FnConverging(ret_ty) => (type_of::arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)), ty::FnDiverging => @@ -853,7 +852,7 @@ fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(), _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type") }; - let llsig = foreign_signature(ccx, &fn_sig, fn_sig.inputs.as_slice()); + let llsig = foreign_signature(ccx, &fn_sig, fn_sig.0.inputs.as_slice()); let fn_ty = cabi::compute_abi_info(ccx, llsig.llarg_tys.as_slice(), llsig.llret_ty, @@ -913,7 +912,7 @@ fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> T llargument_tys.push(llarg_ty); } - if tys.fn_sig.variadic { + if tys.fn_sig.0.variadic { Type::variadic_func(llargument_tys.as_slice(), &llreturn_ty) } else { Type::func(llargument_tys.as_slice(), &llreturn_ty) diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 4575d8a41e52a..dea095ecaf594 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -227,8 +227,8 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs); let self_ty = match fty.sty { ty::ty_bare_fn(ref f) => { - assert!(f.sig.inputs.len() == 1); - f.sig.inputs[0] + assert!(f.sig.0.inputs.len() == 1); + f.sig.0.inputs[0] } _ => bcx.sess().bug(format!("Expected function type, found {}", bcx.ty_to_string(fty)).as_slice()) diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 890652401d7eb..a6f7c849f4d95 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -150,7 +150,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let tcx = bcx.tcx(); let ret_ty = match callee_ty.sty { - ty::ty_bare_fn(ref f) => f.sig.output, + ty::ty_bare_fn(ref f) => f.sig.0.output, _ => panic!("expected bare_fn in trans_intrinsic_call") }; let foreign_item = tcx.map.expect_foreign_item(node); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 9a2bc38acdfdc..f1c3c9be396af 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -133,16 +133,16 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, method_num }) => { let trait_ref = - Rc::new(trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs)); + Rc::new(ty::Binder((**trait_ref).subst(bcx.tcx(), bcx.fcx.param_substs))); let span = bcx.tcx().map.span(method_call.expr_id); debug!("method_call={} trait_ref={}", method_call, trait_ref.repr(bcx.tcx())); let origin = fulfill_obligation(bcx.ccx(), span, - (*trait_ref).clone()); + trait_ref.clone()); debug!("origin = {}", origin.repr(bcx.tcx())); - trans_monomorphized_callee(bcx, method_call, trait_ref.def_id, + trans_monomorphized_callee(bcx, method_call, trait_ref.def_id(), method_num, origin) } @@ -239,8 +239,8 @@ pub fn trans_static_method_callee(bcx: Block, rcvr_assoc, 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 trait_ref = Rc::new(ty::Binder(ty::TraitRef { def_id: trait_id, + substs: trait_substs })); let vtbl = fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref); @@ -480,8 +480,8 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::ty_bare_fn(ref f) if f.abi == Rust || f.abi == RustCall => { type_of_rust_fn(ccx, Some(Type::i8p(ccx)), - f.sig.inputs.slice_from(1), - f.sig.output, + f.sig.0.inputs.slice_from(1), + f.sig.0.output, f.abi) } _ => { @@ -515,7 +515,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// This will hopefully change now that DST is underway. pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, box_ty: Ty<'tcx>, - trait_ref: Rc>) + trait_ref: Rc>) -> ValueRef { debug!("get_vtable(box_ty={}, trait_ref={})", @@ -670,7 +670,7 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Expr>, id: ast::NodeId, - trait_ref: Rc>, + trait_ref: Rc>, dest: expr::Dest) -> Block<'blk, 'tcx> { let mut bcx = bcx; diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index adc919c91bf36..aa6fd7f0b3941 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -146,16 +146,16 @@ pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) ty::ty_closure(ref f) => { type_of_rust_fn(cx, Some(Type::i8p(cx)), - f.sig.inputs.as_slice(), - f.sig.output, + f.sig.0.inputs.as_slice(), + f.sig.0.output, f.abi) } ty::ty_bare_fn(ref f) => { if f.abi == abi::Rust || f.abi == abi::RustCall { type_of_rust_fn(cx, None, - f.sig.inputs.as_slice(), - f.sig.output, + f.sig.0.inputs.as_slice(), + f.sig.0.output, f.abi) } else { foreign::lltype_for_foreign_fn(cx, fty) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 87eda76db2990..4f4bebabead2c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -53,8 +53,7 @@ use middle::def; use middle::resolve_lifetime as rl; use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; -use middle::ty::{mod, Ty}; -use middle::ty_fold; +use middle::ty::{mod, RegionEscape, Ty}; use rscope::{mod, UnelidableRscope, RegionScope, SpecificRscope, ShiftedRscope, BindingRscope}; use TypeAndSubsts; @@ -524,6 +523,20 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC, vec![input_ty, output] } +pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( + this: &AC, + rscope: &RS, + ast_trait_ref: &ast::PolyTraitRef, + self_ty: Option>, + allow_eq: AllowEqConstraints) + -> Rc> + where AC: AstConv<'tcx>, RS: RegionScope +{ + let trait_ref = + instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, allow_eq); + let trait_ref = (*trait_ref).clone(); + Rc::new(ty::Binder(trait_ref)) // Ugh. +} /// Instantiates the path for the given trait reference, assuming that it's /// bound to a valid trait type. Returns the def_id for the defining trait. @@ -537,9 +550,7 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, where AC: AstConv<'tcx>, RS: RegionScope { - match ::lookup_def_tcx(this.tcx(), - ast_trait_ref.path.span, - ast_trait_ref.ref_id) { + match ::lookup_def_tcx(this.tcx(), ast_trait_ref.path.span, ast_trait_ref.ref_id) { def::DefTrait(trait_def_id) => { let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, @@ -749,7 +760,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, rscope: &RS, ty: &ast::Ty, bounds: &[ast::TyParamBound]) - -> Result, ErrorReported> + -> Result, ErrorReported> where AC : AstConv<'tcx>, RS : RegionScope { /*! @@ -767,12 +778,12 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, ast::TyPath(ref path, id) => { match this.tcx().def_map.borrow().get(&id) { Some(&def::DefTrait(trait_def_id)) => { - return Ok(ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow)); + return Ok(ty::Binder(ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + AllowEqConstraints::Allow))); } _ => { span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait"); @@ -814,7 +825,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, rscope: &RS, span: Span, - trait_ref: ty::TraitRef<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, bounds: &[ast::TyParamBound]) -> Ty<'tcx> where AC : AstConv<'tcx>, RS : RegionScope @@ -982,12 +993,12 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details - let result = ast_path_to_trait_ref(this, - rscope, - trait_def_id, - None, - path, - AllowEqConstraints::Allow); + let result = ty::Binder(ast_path_to_trait_ref(this, + rscope, + trait_def_id, + None, + path, + AllowEqConstraints::Allow)); trait_ref_to_object_type(this, rscope, path.span, result, &[]) } def::DefTy(did, _) | def::DefStruct(did) => { @@ -1039,7 +1050,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( let ty_param_defs = tcx.ty_param_defs.borrow(); let tp_def = &(*ty_param_defs)[did.node]; let assoc_tys = tp_def.bounds.trait_bounds.iter() - .filter_map(|b| find_assoc_ty(this, &**b, assoc_ident)) + .filter_map(|b| find_assoc_ty(this, &b.0, assoc_ident)) .collect(); (assoc_tys, token::get_name(tp_def.name).to_string()) } @@ -1189,10 +1200,9 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( let (self_ty, mut implied_output_region) = match opt_self_info { None => (None, None), Some(self_info) => { - // Shift regions in the self type by 1 to account for the binding - // level introduced by the function itself. - let untransformed_self_ty = - ty_fold::shift_regions(this.tcx(), 1, &self_info.untransformed_self_ty); + // This type comes from an impl or trait; no late-bound + // regions should be present. + assert!(!self_info.untransformed_self_ty.has_escaping_regions()); // Figure out and record the explicit self category. let explicit_self_category = @@ -1203,19 +1213,19 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( (None, None) } ty::ByValueExplicitSelfCategory => { - (Some(untransformed_self_ty), None) + (Some(self_info.untransformed_self_ty), None) } ty::ByReferenceExplicitSelfCategory(region, mutability) => { (Some(ty::mk_rptr(this.tcx(), region, ty::mt { - ty: untransformed_self_ty, + ty: self_info.untransformed_self_ty, mutbl: mutability })), Some(region)) } ty::ByBoxExplicitSelfCategory => { - (Some(ty::mk_uniq(this.tcx(), untransformed_self_ty)), None) + (Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty)), None) } } } @@ -1267,11 +1277,11 @@ fn ty_of_method_or_bare_fn<'a, 'tcx, AC: AstConv<'tcx>>( (ty::BareFnTy { unsafety: unsafety, abi: abi, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: self_and_input_tys, output: output_ty, variadic: decl.variadic - } + }), }, explicit_self_category_result) } @@ -1409,9 +1419,9 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>( store: store, bounds: bounds, abi: abi, - sig: ty::FnSig {inputs: input_tys, - output: output_ty, - variadic: decl.variadic} + sig: ty::Binder(ty::FnSig {inputs: input_tys, + output: output_ty, + variadic: decl.variadic}), } } @@ -1423,7 +1433,7 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( this: &AC, rscope: &RS, span: Span, - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures ast_bounds: &[ast::TyParamBound]) -> ty::ExistentialBounds { @@ -1450,11 +1460,11 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) { Some(trait_bound) => { - Some(instantiate_trait_ref(this, - rscope, - &trait_bound.trait_ref, - None, - AllowEqConstraints::Allow)) + Some(instantiate_poly_trait_ref(this, + rscope, + trait_bound, + None, + AllowEqConstraints::Allow)) } None => { this.tcx().sess.span_err( @@ -1481,7 +1491,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( this: &AC, rscope: &RS, span: Span, - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for boxed closures + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures partitioned_bounds: PartitionedBounds) -> ty::ExistentialBounds where AC: AstConv<'tcx>, RS:RegionScope @@ -1519,7 +1529,7 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>( fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, explicit_region_bounds: &[&ast::Lifetime], - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, builtin_bounds: ty::BuiltinBounds) -> Option { @@ -1579,7 +1589,7 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>( rscope: &RS, span: Span, region_bounds: &[&ast::Lifetime], - principal_trait_ref: Option<&ty::TraitRef<'tcx>>, // None for closures + principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for closures builtin_bounds: ty::BuiltinBounds) -> ty::Region { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b88da5d9387d3..44cc5fce53da3 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::def; -use middle::infer::{mod, resolve}; +use middle::infer; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const}; use middle::subst::{Subst, Substs}; use middle::ty::{mod, Ty}; @@ -18,6 +18,7 @@ use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; use check::{instantiate_path, structurally_resolved_type, valid_range_bounds}; use require_same_types; use util::nodemap::FnvHashMap; +use util::ppaux::Repr; use std::cmp; use std::collections::hash_map::{Occupied, Vacant}; @@ -33,6 +34,10 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; + debug!("check_pat(pat={},expected={})", + pat.repr(tcx), + expected.repr(tcx)); + match pat.node { ast::PatWild(_) => { fcx.write_ty(pat.id, expected); @@ -143,11 +148,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, ast::PatRegion(ref inner) => { let inner_ty = fcx.infcx().next_ty_var(); - let mutbl = infer::resolve_type( - fcx.infcx(), Some(pat.span), - expected, resolve::try_resolve_tvar_shallow) - .ok() - .and_then(|t| ty::deref(t, true)) + let mutbl = + ty::deref(fcx.infcx().shallow_resolve(expected), true) .map_or(ast::MutImmutable, |mt| mt.mutbl); let mt = ty::mt { ty: inner_ty, mutbl: mutbl }; @@ -214,23 +216,21 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, inner: &ast::Pat) -> bool { let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - match infer::resolve_type( - fcx.infcx(), Some(span), - expected, resolve::try_resolve_tvar_shallow) { - Ok(t) if pat_is_binding(&tcx.def_map, inner) => { - ty::deref(t, true).map_or(true, |mt| match mt.ty.sty { - ty::ty_trait(_) => { - // This is "x = SomeTrait" being reduced from - // "let &x = &SomeTrait" or "let box x = Box", an error. - span_err!(tcx.sess, span, E0033, - "type `{}` cannot be dereferenced", - fcx.infcx().ty_to_string(t)); - false - } - _ => true - }) - } - _ => true + if pat_is_binding(&tcx.def_map, inner) { + let expected = fcx.infcx().shallow_resolve(expected); + ty::deref(expected, true).map_or(true, |mt| match mt.ty.sty { + ty::ty_trait(_) => { + // This is "x = SomeTrait" being reduced from + // "let &x = &SomeTrait" or "let box x = Box", an error. + span_err!(tcx.sess, span, E0033, + "type `{}` cannot be dereferenced", + fcx.infcx().ty_to_string(expected)); + false + } + _ => true + }) + } else { + true } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index e3fec2c8b1df2..2ade3040d6cff 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -129,7 +129,7 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, // Tuple up the arguments and insert the resulting function type into // the `unboxed_closures` table. - fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)]; + fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)]; debug!("unboxed_closure for {} --> sig={} kind={}", expr_def_id.repr(fcx.tcx()), @@ -180,7 +180,7 @@ fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>( fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( fcx: &FnCtxt<'a,'tcx>, - trait_ref: &ty::TraitRef<'tcx>) + trait_ref: &ty::PolyTraitRef<'tcx>) -> Option<(ty::FnSig<'tcx>, ty::UnboxedClosureKind)> { let tcx = fcx.tcx(); @@ -188,15 +188,15 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( debug!("deduce_unboxed_closure_expectations_from_object_type({})", trait_ref.repr(tcx)); - let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id) { + let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) { Some(k) => k, None => { return None; } }; debug!("found object type {}", kind); - let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0); - let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty); + let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); + let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty); debug!("arg_param_ty {}", arg_param_ty.repr(tcx)); let input_tys = match arg_param_ty.sty { @@ -205,8 +205,8 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>( }; debug!("input_tys {}", input_tys.repr(tcx)); - let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1); - let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty); + let ret_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 1); + let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty); debug!("ret_param_ty {}", ret_param_ty.repr(tcx)); let fn_sig = ty::FnSig { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 980097eaead99..9af9eaf75f5a5 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -12,8 +12,6 @@ use check::FnCtxt; use middle::ty::{mod, Ty}; use middle::infer; -use middle::infer::resolve_type; -use middle::infer::resolve::try_resolve_tvar_shallow; use std::result::Result::{Err, Ok}; use syntax::ast; @@ -63,12 +61,7 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, debug!("demand::coerce(expected = {}, expr_ty = {})", expected.repr(fcx.ccx.tcx), expr_ty.repr(fcx.ccx.tcx)); - let expected = if ty::type_needs_infer(expected) { - resolve_type(fcx.infcx(), - None, - expected, - try_resolve_tvar_shallow).unwrap_or(expected) - } else { expected }; + let expected = fcx.infcx().resolve_type_vars_if_possible(&expected); match fcx.mk_assignty(expr, expr_ty, expected) { Ok(()) => { /* ok */ } Err(ref err) => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 7463652a93136..2c220f298262f 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -16,9 +16,9 @@ use middle::traits; use middle::ty::{mod, Ty}; use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin, MethodParam, MethodStatic, MethodTraitObject, MethodTypeParam}; +use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; -use middle::ty_fold::HigherRankedFoldable; use syntax::ast; use syntax::codemap::Span; use std::rc::Rc; @@ -114,7 +114,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Create the final `MethodCallee`. let fty = ty::mk_bare_fn(self.tcx(), ty::BareFnTy { - sig: method_sig, + sig: ty::Binder(method_sig), unsafety: pick.method_ty.fty.unsafety, abi: pick.method_ty.fty.abi.clone(), }); @@ -222,17 +222,19 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // argument type), but those cases have already // been ruled out when we deemed the trait to be // "object safe". - let substs = data.principal.substs.clone().with_self_ty(object_ty); - let original_trait_ref = - Rc::new(ty::TraitRef::new(data.principal.def_id, substs)); - let upcast_trait_ref = this.upcast(original_trait_ref.clone(), trait_def_id); - debug!("original_trait_ref={} upcast_trait_ref={} target_trait={}", - original_trait_ref.repr(this.tcx()), + let original_poly_trait_ref = + data.principal_trait_ref_with_self_ty(object_ty); + let upcast_poly_trait_ref = + this.upcast(original_poly_trait_ref.clone(), trait_def_id); + let upcast_trait_ref = + this.replace_late_bound_regions_with_fresh_var(&*upcast_poly_trait_ref); + debug!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}", + original_poly_trait_ref.repr(this.tcx()), upcast_trait_ref.repr(this.tcx()), trait_def_id.repr(this.tcx())); let substs = upcast_trait_ref.substs.clone(); let origin = MethodTraitObject(MethodObject { - trait_ref: upcast_trait_ref, + trait_ref: Rc::new(upcast_trait_ref), object_trait_id: trait_def_id, method_num: method_num, real_index: real_index, @@ -272,16 +274,21 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { &trait_def.generics, self.infcx().next_ty_var()); - let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs.clone())); + let trait_ref = + Rc::new(ty::TraitRef::new(trait_def_id, substs.clone())); let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref, method_num: method_num }); (substs, origin) } - probe::WhereClausePick(ref trait_ref, method_num) => { - let origin = MethodTypeParam(MethodParam { trait_ref: (*trait_ref).clone(), + probe::WhereClausePick(ref poly_trait_ref, method_num) => { + // Where clauses can have bound regions in them. We need to instantiate + // those to convert from a poly-trait-ref to a trait-ref. + let trait_ref = self.replace_late_bound_regions_with_fresh_var(&**poly_trait_ref); + let substs = trait_ref.substs.clone(); + let origin = MethodTypeParam(MethodParam { trait_ref: Rc::new(trait_ref), method_num: method_num }); - (trait_ref.substs.clone(), origin) + (substs, origin) } } } @@ -378,25 +385,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { all_substs: subst::Substs<'tcx>) -> InstantiatedMethodSig<'tcx> { - // If this method comes from an impl (as opposed to a trait), - // it may have late-bound regions from the impl that appear in - // the substitutions, method signature, and - // bounds. Instantiate those at this point. (If it comes from - // a trait, this step has no effect, as there are no - // late-bound regions to instantiate.) - // - // The binder level here corresponds to the impl. - let (all_substs, (method_sig, method_generics)) = - self.replace_late_bound_regions_with_fresh_var( - &ty::bind((all_substs, - (pick.method_ty.fty.sig.clone(), - pick.method_ty.generics.clone())))).value; - - debug!("late-bound lifetimes from impl instantiated, \ - all_substs={} method_sig={} method_generics={}", - all_substs.repr(self.tcx()), - method_sig.repr(self.tcx()), - method_generics.repr(self.tcx())); + debug!("instantiate_method_sig(pick={}, all_substs={})", + pick.repr(self.tcx()), + all_substs.repr(self.tcx())); // Instantiate the bounds on the method with the // type/early-bound-regions substitutions performed. The only @@ -426,8 +417,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { all_substs.clone() } }; - let method_bounds = - method_generics.to_bounds(self.tcx(), &method_bounds_substs); + let method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &method_bounds_substs); debug!("method_bounds after subst = {}", method_bounds.repr(self.tcx())); @@ -435,7 +425,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // Substitute the type/early-bound-regions into the method // signature. In addition, the method signature may bind // late-bound regions, so instantiate those. - let method_sig = method_sig.subst(self.tcx(), &all_substs); + let method_sig = pick.method_ty.fty.sig.subst(self.tcx(), &all_substs); let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig); debug!("late-bound lifetimes from method instantiated, method_sig={}", @@ -481,7 +471,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { _ => return, }; - match sig.inputs[0].sty { + match sig.0.inputs[0].sty { ty::ty_rptr(_, ty::mt { ty: _, mutbl: ast::MutMutable, @@ -637,12 +627,12 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } fn upcast(&mut self, - source_trait_ref: Rc>, + source_trait_ref: Rc>, target_trait_def_id: ast::DefId) - -> Rc> + -> Rc> { for super_trait_ref in traits::supertraits(self.tcx(), source_trait_ref.clone()) { - if super_trait_ref.def_id == target_trait_def_id { + if super_trait_ref.def_id() == target_trait_def_id { return super_trait_ref; } } @@ -654,8 +644,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { target_trait_def_id.repr(self.tcx()))[]); } - fn replace_late_bound_regions_with_fresh_var(&self, value: &T) -> T - where T : HigherRankedFoldable<'tcx> + fn replace_late_bound_regions_with_fresh_var(&self, value: &ty::Binder) -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { self.infcx().replace_late_bound_regions_with_fresh_var( self.span, infer::FnCall, value).0 diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index d97a9c9e39b19..ffaeceb3eed11 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -100,7 +100,7 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr.repr(fcx.tcx()), self_expr.repr(fcx.tcx())); - let self_ty = fcx.infcx().resolve_type_vars_if_possible(self_ty); + let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty); let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id)); Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types)) } @@ -169,9 +169,10 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); // Construct an obligation + let poly_trait_ref = Rc::new(ty::Binder((*trait_ref).clone())); let obligation = traits::Obligation::misc(span, fcx.body_id, - ty::Predicate::Trait(trait_ref.clone())); + poly_trait_ref.as_predicate()); // Now we want to know if this can be matched let mut selcx = traits::SelectionContext::new(fcx.infcx(), @@ -194,9 +195,6 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, // Substitute the trait parameters into the method type and // instantiate late-bound regions to get the actual method type. - // - // Note that as the method comes from a trait, it can only have - // late-bound regions from the fn itself, not the impl. let ref bare_fn_ty = method_ty.fty; let fn_sig = bare_fn_ty.sig.subst(tcx, &trait_ref.substs); let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span, @@ -204,7 +202,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, &fn_sig).0; let transformed_self_ty = fn_sig.inputs[0]; let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { - sig: fn_sig, + sig: ty::Binder(fn_sig), unsafety: bare_fn_ty.unsafety, abi: bare_fn_ty.abi.clone(), }); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 80e511b8fdf6f..b5776f9aeb34a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -19,8 +19,7 @@ use middle::subst; use middle::subst::Subst; use middle::traits; use middle::ty::{mod, Ty}; -use middle::ty::{MethodObject}; -use middle::ty_fold::HigherRankedFoldable; +use middle::ty_fold::TypeFoldable; use middle::infer; use middle::infer::InferCtxt; use syntax::ast; @@ -58,11 +57,11 @@ struct Candidate<'tcx> { enum CandidateKind<'tcx> { InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>), - ObjectCandidate(MethodObject<'tcx>), + ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint), ExtensionImplCandidate(/* Impl */ ast::DefId, Rc>, subst::Substs<'tcx>, MethodIndex), UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex), - WhereClauseCandidate(Rc>, MethodIndex), + WhereClauseCandidate(Rc>, MethodIndex), } pub struct Pick<'tcx> { @@ -77,7 +76,7 @@ pub enum PickKind<'tcx> { ObjectPick(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint), ExtensionImplPick(/* Impl */ ast::DefId, MethodIndex), TraitPick(/* Trait */ ast::DefId, MethodIndex), - WhereClausePick(/* Trait */ Rc>, MethodIndex), + WhereClausePick(/* Trait */ Rc>, MethodIndex), } pub type PickResult<'tcx> = Result, MethodError>; @@ -149,7 +148,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // this creates one big transaction so that all type variables etc // that we create during the probe process are removed later let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures - fcx.infcx().probe(|| { + fcx.infcx().probe(|_| { let (steps, opt_simplified_steps) = dummy.take().unwrap(); let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps); probe_cx.assemble_inherent_candidates(); @@ -231,9 +230,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self_ty.repr(self.tcx())); match self_ty.sty { - ty::ty_trait(box ty::TyTrait { ref principal, bounds, .. }) => { - self.assemble_inherent_candidates_from_object(self_ty, &*principal, bounds); - self.assemble_inherent_impl_candidates_for_type(principal.def_id); + ty::ty_trait(box ref data) => { + self.assemble_inherent_candidates_from_object(self_ty, data); + self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); } ty::ty_enum(did, _) | ty::ty_struct(did, _) | @@ -290,8 +289,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>, - principal: &ty::TraitRef<'tcx>, - _bounds: ty::ExistentialBounds) { + data: &ty::TyTrait<'tcx>) { debug!("assemble_inherent_candidates_from_object(self_ty={})", self_ty.repr(self.tcx())); @@ -304,29 +302,17 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // a substitution that replaces `Self` with the object type // itself. Hence, a `&self` method will wind up with an // argument type like `&Trait`. - let rcvr_substs = principal.substs.clone().with_self_ty(self_ty); - let trait_ref = Rc::new(ty::TraitRef { - def_id: principal.def_id, - substs: rcvr_substs.clone() - }); - + let trait_ref = data.principal_trait_ref_with_self_ty(self_ty); self.elaborate_bounds(&[trait_ref.clone()], false, |this, new_trait_ref, m, method_num| { let vtable_index = - get_method_index(tcx, &*new_trait_ref, - trait_ref.clone(), method_num); + get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num); - let xform_self_ty = - this.xform_self_ty(&m, &new_trait_ref.substs); + let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs()); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, method_ty: m, - kind: ObjectCandidate(MethodObject { - trait_ref: new_trait_ref, - object_trait_id: principal.def_id, - method_num: method_num, - real_index: vtable_index - }) + kind: ObjectCandidate(new_trait_ref.def_id(), method_num, vtable_index) }); }); } @@ -358,27 +344,27 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.elaborate_bounds(bounds.as_slice(), true, |this, trait_ref, m, method_num| { let xform_self_ty = - this.xform_self_ty(&m, &trait_ref.substs); + this.xform_self_ty(&m, trait_ref.substs()); debug!("found match: trait_ref={} substs={} m={}", trait_ref.repr(this.tcx()), - trait_ref.substs.repr(this.tcx()), + trait_ref.substs().repr(this.tcx()), m.repr(this.tcx())); assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(), - trait_ref.substs.types.get_slice(subst::TypeSpace).len()); + trait_ref.substs().types.get_slice(subst::TypeSpace).len()); assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(), - trait_ref.substs.regions().get_slice(subst::TypeSpace).len()); + trait_ref.substs().regions().get_slice(subst::TypeSpace).len()); assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(), - trait_ref.substs.types.get_slice(subst::SelfSpace).len()); + trait_ref.substs().types.get_slice(subst::SelfSpace).len()); assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(), - trait_ref.substs.regions().get_slice(subst::SelfSpace).len()); + trait_ref.substs().regions().get_slice(subst::SelfSpace).len()); // Because this trait derives from a where-clause, it // should not contain any inference variables or other // artifacts. This means it is safe to put into the // `WhereClauseCandidate` and (eventually) into the // `WhereClausePick`. - assert!(trait_ref.substs.types.iter().all(|&t| !ty::type_needs_infer(t))); + assert!(trait_ref.substs().types.iter().all(|&t| !ty::type_needs_infer(t))); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, @@ -392,10 +378,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // create the candidates. fn elaborate_bounds( &mut self, - bounds: &[Rc>], + bounds: &[Rc>], num_includes_types: bool, mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>, - tr: Rc>, + tr: Rc>, m: Rc>, method_num: uint|) { @@ -405,12 +391,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { 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) { + if !cache.insert(bound_trait_ref.def_id()) { continue; } let (pos, method) = match trait_method(tcx, - bound_trait_ref.def_id, + bound_trait_ref.def_id(), self.method_name, num_includes_types) { Some(v) => v, @@ -418,7 +404,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { }; if !self.has_applicable_self(&*method) { - self.record_static_candidate(TraitSource(bound_trait_ref.def_id)); + self.record_static_candidate(TraitSource(bound_trait_ref.def_id())); } else { mk_cand(self, bound_trait_ref, method, pos); } @@ -756,7 +742,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self_ty.repr(self.tcx()), probe.repr(self.tcx())); - self.infcx().probe(|| { + self.infcx().probe(|_| { // First check that the self type can be related. match self.make_sub_ty(self_ty, probe.xform_self_ty) { Ok(()) => { } @@ -779,7 +765,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // Erase any late-bound regions bound in the impl // which appear in the bounds. - let impl_bounds = self.erase_late_bound_regions(&ty::bind(impl_bounds)).value; + let impl_bounds = self.erase_late_bound_regions(&ty::Binder(impl_bounds)); // Convert the bounds into obligations. let obligations = @@ -881,9 +867,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn xform_self_ty(&self, method: &Rc>, substs: &subst::Substs<'tcx>) - -> Ty<'tcx> { + -> Ty<'tcx> + { debug!("xform_self_ty(self_ty={}, substs={})", - method.fty.sig.inputs[0].repr(self.tcx()), + method.fty.sig.0.inputs[0].repr(self.tcx()), substs.repr(self.tcx())); // It is possible for type parameters or early-bound lifetimes @@ -916,15 +903,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } // Replace early-bound regions and types. - let xform_self_ty = method.fty.sig.inputs[0].subst(self.tcx(), substs); + let xform_self_ty = method.fty.sig.0.inputs[0].subst(self.tcx(), substs); // Replace late-bound regions bound in the impl or - // where-clause (2 levels of binding). - let xform_self_ty = - self.erase_late_bound_regions(&ty::bind(ty::bind(xform_self_ty))).value.value; - - // Replace late-bound regions bound in the method (1 level of binding). - self.erase_late_bound_regions(&ty::bind(xform_self_ty)).value + // where-clause (2 levels of binding) and method (1 level of binding). + self.erase_late_bound_regions( + &self.erase_late_bound_regions( + &ty::Binder(ty::Binder(xform_self_ty)))) } fn impl_substs(&self, @@ -962,8 +947,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { /// region got replaced with the same variable, which requires a bit more coordination /// and/or tracking the substitution and /// so forth. - fn erase_late_bound_regions(&self, value: &T) -> T - where T : HigherRankedFoldable<'tcx> + fn erase_late_bound_regions(&self, value: &ty::Binder) -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> { ty::erase_late_bound_regions(self.tcx(), value) } @@ -1007,8 +992,8 @@ fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>, // Determine the index of a method in the list of all methods belonging // to a trait and its supertraits. fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, - subtrait: Rc>, + trait_ref: &ty::PolyTraitRef<'tcx>, + subtrait: Rc>, n_method: uint) -> uint { // We need to figure the "real index" of the method in a // listing of all the methods of an object. We do this by @@ -1017,10 +1002,10 @@ fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, // methods from them. let mut method_count = n_method; ty::each_bound_trait_and_supertraits(tcx, &[subtrait], |bound_ref| { - if bound_ref.def_id == trait_ref.def_id { + if bound_ref.def_id() == trait_ref.def_id() { false } else { - let trait_items = ty::trait_items(tcx, bound_ref.def_id); + let trait_items = ty::trait_items(tcx, bound_ref.def_id()); for trait_item in trait_items.iter() { match *trait_item { ty::MethodTraitItem(_) => method_count += 1, @@ -1042,8 +1027,8 @@ impl<'tcx> Candidate<'tcx> { InherentImplCandidate(def_id, _) => { InherentImplPick(def_id) } - ObjectCandidate(ref data) => { - ObjectPick(data.trait_ref.def_id, data.method_num, data.real_index) + ObjectCandidate(def_id, method_num, real_index) => { + ObjectPick(def_id, method_num, real_index) } ExtensionImplCandidate(def_id, _, _, index) => { ExtensionImplPick(def_id, index) @@ -1057,7 +1042,7 @@ impl<'tcx> Candidate<'tcx> { // inference variables or other artifacts. This // means they are safe to put into the // `WhereClausePick`. - assert!(trait_ref.substs.types.iter().all(|&t| !ty::type_needs_infer(t))); + assert!(trait_ref.substs().types.iter().all(|&t| !ty::type_needs_infer(t))); WhereClausePick((*trait_ref).clone(), index) } @@ -1068,10 +1053,10 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { InherentImplCandidate(def_id, _) => ImplSource(def_id), - ObjectCandidate(ref obj) => TraitSource(obj.trait_ref.def_id), + ObjectCandidate(def_id, _, _) => TraitSource(def_id), ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id), UnboxedClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id), - WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id), + WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()), } } @@ -1084,10 +1069,12 @@ impl<'tcx> Candidate<'tcx> { UnboxedClosureCandidate(trait_def_id, method_num) => { Some((trait_def_id, method_num)) } - ExtensionImplCandidate(_, ref trait_ref, _, method_num) | - WhereClauseCandidate(ref trait_ref, method_num) => { + ExtensionImplCandidate(_, ref trait_ref, _, method_num) => { Some((trait_ref.def_id, method_num)) } + WhereClauseCandidate(ref trait_ref, method_num) => { + Some((trait_ref.def_id(), method_num)) + } } } } @@ -1105,8 +1092,8 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> { match *self { InherentImplCandidate(ref a, ref b) => format!("InherentImplCandidate({},{})", a.repr(tcx), b.repr(tcx)), - ObjectCandidate(ref a) => - format!("ObjectCandidate({})", a.repr(tcx)), + ObjectCandidate(a, b, c) => + format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c), ExtensionImplCandidate(ref a, ref b, ref c, ref d) => format!("ExtensionImplCandidate({},{},{},{})", a.repr(tcx), b.repr(tcx), c.repr(tcx), d), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index def82ecd6c85b..9e249cc449d07 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -506,7 +506,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> { fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, unsafety: ast::Unsafety, unsafety_id: ast::NodeId, - fn_sig: &ty::FnSig<'tcx>, + fn_sig: &ty::PolyFnSig<'tcx>, decl: &ast::FnDecl, fn_id: ast::NodeId, body: &ast::Block, @@ -625,23 +625,20 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env); } - ast::ItemImpl(_, _, ref opt_trait_ref, _, ref impl_items) => { + ast::ItemImpl(_, _, _, _, ref impl_items) => { debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); - match *opt_trait_ref { - Some(ref ast_trait_ref) => { - let impl_trait_ref = - ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id); + match ty::impl_trait_ref(ccx.tcx, local_def(it.id)) { + Some(impl_trait_ref) => { check_impl_items_against_trait(ccx, it.span, - ast_trait_ref, &*impl_trait_ref, impl_items.as_slice()); - } - None => { } - } + } + None => { } + } for impl_item in impl_items.iter() { match *impl_item { @@ -722,12 +719,7 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_env = ParameterEnvironment::for_item(ccx.tcx, method.id); let fty = ty::node_id_to_type(ccx.tcx, method.id); - debug!("fty (raw): {}", fty.repr(ccx.tcx)); - - let body_id = method.pe_body().id; - let fty = liberate_late_bound_regions( - ccx.tcx, CodeExtent::from_node_id(body_id), &ty::bind(fty)).value; - debug!("fty (liberated): {}", fty.repr(ccx.tcx)); + debug!("check_method_body: fty={}", fty.repr(ccx.tcx)); check_bare_fn(ccx, &*method.pe_fn_decl(), @@ -739,7 +731,6 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, - ast_trait_ref: &ast::TraitRef, impl_trait_ref: &ty::TraitRef<'tcx>, impl_items: &[ast::ImplItem]) { // Locate trait methods @@ -772,21 +763,16 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_method.span, impl_method.pe_body().id, &**trait_method_ty, - impl_trait_ref); + &*impl_trait_ref); } _ => { // This is span_bug as it should have already been // caught in resolve. - tcx.sess - .span_bug(impl_method.span, - format!("item `{}` is of a \ - different kind from \ - its trait `{}`", - token::get_name( - impl_item_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)) - .as_slice()); + tcx.sess.span_bug( + impl_method.span, + format!("item `{}` is of a different kind from its trait `{}`", + token::get_name(impl_item_ty.name()), + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -795,11 +781,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // caught in resolve. tcx.sess.span_bug( impl_method.span, - format!( - "method `{}` is not a member of trait `{}`", - token::get_name(impl_item_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)).as_slice()); + format!("method `{}` is not a member of trait `{}`", + token::get_name(impl_item_ty.name()), + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -812,27 +796,19 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // corresponding type definition in the trait. let opt_associated_type = trait_items.iter() - .find(|ti| { - ti.name() == typedef_ty.name() - }); + .find(|ti| ti.name() == typedef_ty.name()); match opt_associated_type { Some(associated_type) => { match (associated_type, &typedef_ty) { - (&ty::TypeTraitItem(_), - &ty::TypeTraitItem(_)) => {} + (&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {} _ => { // This is `span_bug` as it should have // already been caught in resolve. - tcx.sess - .span_bug(typedef.span, - format!("item `{}` is of a \ - different kind from \ - its trait `{}`", - token::get_name( - typedef_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)) - .as_slice()); + tcx.sess.span_bug( + typedef.span, + format!("item `{}` is of a different kind from its trait `{}`", + token::get_name(typedef_ty.name()), + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -845,8 +821,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, "associated type `{}` is not a member of \ trait `{}`", token::get_name(typedef_ty.name()), - pprust::path_to_string( - &ast_trait_ref.path)).as_slice()); + impl_trait_ref.repr(tcx)).as_slice()); } } } @@ -854,8 +829,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // Check for missing items from trait - let provided_methods = ty::provided_trait_methods(tcx, - impl_trait_ref.def_id); + let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id); let mut missing_methods = Vec::new(); for trait_item in trait_items.iter() { match *trait_item { @@ -870,8 +844,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }); let is_provided = - provided_methods.iter().any( - |m| m.name == trait_method.name); + provided_methods.iter().any(|m| m.name == trait_method.name); if !is_implemented && !is_provided { missing_methods.push(format!("`{}`", token::get_name(trait_method.name))); } @@ -919,27 +892,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method(impl_trait_ref={})", impl_trait_ref.repr(tcx)); - let impl_m_body_scope = CodeExtent::from_node_id(impl_m_body_id); - - // The impl's trait ref may bind late-bound regions from the impl. - // Liberate them and assign them the scope of the method body. - // - // An example would be: - // - // impl<'a> Foo<&'a T> for &'a U { ... } - // - // Here, the region parameter `'a` is late-bound, so the - // trait reference associated with the impl will be - // - // for<'a> Foo<&'a T> - // - // liberating will convert this into: - // - // Foo<&'A T> - // - // where `'A` is the `ReFree` version of `'a`. - let impl_trait_ref = liberate_late_bound_regions(tcx, impl_m_body_scope, impl_trait_ref); - debug!("impl_trait_ref (liberated) = {}", impl_trait_ref.repr(tcx)); @@ -996,15 +948,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, return; } - if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() { + if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() { span_err!(tcx.sess, impl_m_span, E0050, "method `{}` has {} parameter{} \ but the declaration in trait `{}` has {}", token::get_name(trait_m.name), - impl_m.fty.sig.inputs.len(), - if impl_m.fty.sig.inputs.len() == 1 {""} else {"s"}, + impl_m.fty.sig.0.inputs.len(), + if impl_m.fty.sig.0.inputs.len() == 1 {""} else {"s"}, ty::item_path_str(tcx, trait_m.def_id), - trait_m.fty.sig.inputs.len()); + trait_m.fty.sig.0.inputs.len()); return; } @@ -1081,7 +1033,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, if !check_region_bounds_on_impl_method(tcx, impl_m_span, impl_m, - impl_m_body_scope, &trait_m.generics, &impl_m.generics, &trait_to_skol_substs, @@ -1106,7 +1057,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // `Bound<&'a T>`, the lifetime `'a` will be late-bound with a // depth of 3 (it is nested within 3 binders: the impl, method, // and trait-ref itself). So when we do the liberation, we have - // two introduce two `ty::bind` scopes, one for the impl and one + // two introduce two `ty::Binder` scopes, one for the impl and one // the method. // // The only late-bounded regions that can possibly appear here are @@ -1120,11 +1071,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, .map(|trait_param_def| &trait_param_def.bounds); let impl_bounds = impl_m.generics.types.get_slice(subst::FnSpace).iter() - .map(|impl_param_def| - liberate_late_bound_regions( - tcx, - impl_m_body_scope, - &ty::bind(ty::bind(impl_param_def.bounds.clone()))).value.value); + .map(|impl_param_def| &impl_param_def.bounds); for (i, (trait_param_bounds, impl_param_bounds)) in trait_bounds.zip(impl_bounds).enumerate() { @@ -1167,30 +1114,27 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let trait_bound = trait_bound.subst(tcx, &trait_to_skol_substs); let infcx = infer::new_infer_ctxt(tcx); - infer::mk_sub_trait_refs(&infcx, - true, - infer::Misc(impl_m_span), - trait_bound, - impl_trait_bound.clone()).is_ok() + infer::mk_sub_poly_trait_refs(&infcx, + true, + infer::Misc(impl_m_span), + trait_bound, + impl_trait_bound.clone()).is_ok() }); if !found_match_in_trait { span_err!(tcx.sess, impl_m_span, E0052, - "in method `{}`, type parameter {} requires bound `{}`, which is not \ - required by the corresponding type parameter in the trait declaration", - token::get_name(trait_m.name), - i, - ppaux::trait_ref_to_string(tcx, &*impl_trait_bound)); + "in method `{}`, type parameter {} requires bound `{}`, which is not \ + required by the corresponding type parameter in the trait declaration", + token::get_name(trait_m.name), + i, + impl_trait_bound.user_string(tcx)); } } } - // Compute skolemized form of impl and trait method tys. Note - // that we must liberate the late-bound regions from the impl. + // Compute skolemized form of impl and trait method tys. let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone()); let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); - let impl_fty = liberate_late_bound_regions( - tcx, impl_m_body_scope, &ty::bind(impl_fty)).value; let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone()); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); @@ -1252,7 +1196,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, impl_m: &ty::Method<'tcx>, - impl_m_body_scope: CodeExtent, trait_generics: &ty::Generics<'tcx>, impl_generics: &ty::Generics<'tcx>, trait_to_skol_substs: &Substs<'tcx>, @@ -1302,16 +1245,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let impl_bounds = impl_param.bounds.subst(tcx, impl_to_skol_substs); - // The bounds may reference late-bound regions from the - // impl declaration. In that case, we want to replace - // those with the liberated variety so as to match the - // versions appearing in the `trait_to_skol_substs`. - // There are two-levels of binder to be aware of: the - // impl, and the method. - let impl_bounds = - ty::liberate_late_bound_regions( - tcx, impl_m_body_scope, &ty::bind(ty::bind(impl_bounds))).value.value; - debug!("check_region_bounds_on_impl_method: \ trait_param={} \ impl_param={} \ @@ -1390,13 +1323,7 @@ fn check_cast(fcx: &FnCtxt, let t_1 = fcx.to_ty(t); let t_1 = structurally_resolved_type(fcx, span, t_1); - if ty::type_is_scalar(t_1) { - // Supply the type as a hint so as to influence integer - // literals and other things that might care. - check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)) - } else { - check_expr(fcx, e) - } + check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1)); let t_e = fcx.expr_ty(e); @@ -1638,7 +1565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn default_diverging_type_variables_to_nil(&self) { for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() { - if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(*ty)) { + if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(ty)) { demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx())); } } @@ -1653,7 +1580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_object_cast(&self, key: ast::NodeId, - trait_ref: Rc>) { + 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); @@ -1751,7 +1678,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_unsize_obligations(span, &**u) } ty::UnsizeVtable(ref ty_trait, self_ty) => { - vtable::check_object_safety(self.tcx(), &ty_trait.principal, span); + vtable::check_object_safety(self.tcx(), ty_trait, span); + // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` implements `Foo`: vtable::register_object_cast_obligations(self, @@ -2486,7 +2414,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let method_type = match method { Some(ref method) => method.ty, None => { - let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(expr_type); + let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(&expr_type); if !ty::type_is_error(true_expr_type) { let ty_string = fcx.infcx().ty_to_string(true_expr_type); @@ -2572,13 +2500,13 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // HACK(eddyb) ignore self in the definition (see above). check_argument_types(fcx, sp, - fty.sig.inputs.slice_from(1), + fty.sig.0.inputs.slice_from(1), callee_expr, args_no_rcvr, autoref_args, - fty.sig.variadic, + fty.sig.0.variadic, tuple_arguments); - fty.sig.output + fty.sig.0.output } _ => { fcx.tcx().sess.span_bug(callee_expr.span, @@ -2992,11 +2920,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to // set up all the node type bindings. - let error_fn_sig = FnSig { + let error_fn_sig = ty::Binder(FnSig { inputs: err_args(args.len()), output: ty::FnConverging(ty::mk_err()), variadic: false - }; + }); let fn_sig = match *fn_sty { ty::ty_bare_fn(ty::BareFnTy {ref sig, ..}) | @@ -3976,7 +3904,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, vtable::select_new_fcx_obligations(fcx); debug!("ExprForLoop each item has type {}", - fcx.infcx().resolve_type_vars_if_possible(typ).repr(fcx.tcx())); + fcx.infcx().resolve_type_vars_if_possible(&typ).repr(fcx.tcx())); let pcx = pat_ctxt { fcx: fcx, @@ -4371,11 +4299,11 @@ impl<'tcx> Expectation<'tcx> { } ExpectCastableToType(t) => { ExpectCastableToType( - fcx.infcx().resolve_type_vars_if_possible(t)) + fcx.infcx().resolve_type_vars_if_possible(&t)) } ExpectHasType(t) => { ExpectHasType( - fcx.infcx().resolve_type_vars_if_possible(t)) + fcx.infcx().resolve_type_vars_if_possible(&t)) } } } @@ -5096,7 +5024,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.infcx().replace_late_bound_regions_with_fresh_var( span, infer::FnCall, - &ty::bind((polytype.ty, bounds))).0.value; + &ty::Binder((polytype.ty, bounds))).0; debug!("after late-bounds have been replaced: ty_late_bound={}", ty_late_bound.repr(fcx.tcx())); debug!("after late-bounds have been replaced: bounds={}", bounds.repr(fcx.tcx())); @@ -5712,11 +5640,11 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { let fty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Unsafe, abi: abi::RustIntrinsic, - sig: FnSig { + sig: ty::Binder(FnSig { inputs: inputs, output: output, variadic: false, - } + }), }); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); let i_n_tps = i_ty.generics.types.len(subst::FnSpace); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index bfa3c384da7b2..33c015a9a081c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -124,8 +124,6 @@ use middle::region::CodeExtent; use middle::traits; use middle::ty::{ReScope}; use middle::ty::{mod, Ty, MethodCall}; -use middle::infer::resolve_and_force_all_but_regions; -use middle::infer::resolve_type; use middle::infer; use middle::pat_util; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap}; @@ -307,11 +305,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { /// of b will be `&.int` and then `*b` will require that `` be bigger than the let and /// the `*b` expression, so we will effectively resolve `` to be the block B. pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { - match resolve_type(self.fcx.infcx(), None, unresolved_ty, - resolve_and_force_all_but_regions) { - Ok(t) => t, - Err(_) => ty::mk_err() - } + self.fcx.infcx().resolve_type_vars_if_possible(&unresolved_ty) } /// Try to resolve the type for the given node. @@ -1187,7 +1181,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, // Treat overloaded autoderefs as if an AutoRef adjustment // was applied on the base type, as that is always the case. let fn_sig = ty::ty_fn_sig(method.ty); - let self_ty = fn_sig.inputs[0]; + let self_ty = fn_sig.0.inputs[0]; let (m, r) = match self_ty.sty { ty::ty_rptr(r, ref m) => (m.mutbl, r), _ => rcx.tcx().sess.span_bug(deref_expr.span, @@ -1204,7 +1198,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, // Specialized version of constrain_call. type_must_outlive(rcx, infer::CallRcvr(deref_expr.span), self_ty, r_deref_expr); - match fn_sig.output { + match fn_sig.0.output { ty::FnConverging(return_type) => { type_must_outlive(rcx, infer::CallReturn(deref_expr.span), return_type, r_deref_expr); diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 415a3d53fb284..4db795a1fda55 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -9,7 +9,7 @@ // except according to those terms. use check::{FnCtxt, structurally_resolved_type}; -use middle::subst::{SelfSpace, FnSpace}; +use middle::subst::{FnSpace}; use middle::traits; use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; use middle::traits::{Obligation, ObligationCause}; @@ -44,7 +44,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Ensure that if ~T is cast to ~Trait, then T : Trait push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); - check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span); + check_object_safety(fcx.tcx(), object_trait, source_expr.span); } (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, @@ -68,7 +68,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, target_region, referent_region); - check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span); + check_object_safety(fcx.tcx(), object_trait, source_expr.span); } } @@ -132,24 +132,19 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // self by value, has no type parameters and does not use the `Self` type, except // in self position. pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait: &ty::TraitRef<'tcx>, - span: Span) { - - let mut object = object_trait.clone(); - if object.substs.types.len(SelfSpace) == 0 { - object.substs.types.push(SelfSpace, ty::mk_err()); - } - - let object = Rc::new(object); - for tr in traits::supertraits(tcx, object) { + object_trait: &ty::TyTrait<'tcx>, + span: Span) +{ + let object_trait_ref = object_trait.principal_trait_ref_with_self_ty(ty::mk_err()); + for tr in traits::supertraits(tcx, object_trait_ref) { check_object_safety_inner(tcx, &*tr, span); } } fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, - object_trait: &ty::TraitRef<'tcx>, + object_trait: &ty::PolyTraitRef<'tcx>, span: Span) { - let trait_items = ty::trait_items(tcx, object_trait.def_id); + let trait_items = ty::trait_items(tcx, object_trait.def_id()); let mut errors = Vec::new(); for item in trait_items.iter() { @@ -163,7 +158,7 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, let mut errors = errors.iter().flat_map(|x| x.iter()).peekable(); if errors.peek().is_some() { - let trait_name = ty::item_path_str(tcx, object_trait.def_id); + let trait_name = ty::item_path_str(tcx, object_trait.def_id()); span_err!(tcx.sess, span, E0038, "cannot convert to a trait object because trait `{}` is not object-safe", trait_name); @@ -212,12 +207,12 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, } }; let ref sig = method.fty.sig; - for &input_ty in sig.inputs[1..].iter() { + for &input_ty in sig.0.inputs[1..].iter() { if let Some(msg) = check_for_self_ty(input_ty) { msgs.push(msg); } } - if let ty::FnConverging(result_type) = sig.output { + if let ty::FnConverging(result_type) = sig.0.output { if let Some(msg) = check_for_self_ty(result_type) { msgs.push(msg); } @@ -237,7 +232,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, object_trait: &ty::TyTrait<'tcx>, referent_ty: Ty<'tcx>) - -> Rc> + -> Rc> { // We can only make objects from sized types. fcx.register_builtin_bound( @@ -256,17 +251,9 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, 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.principal.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.principal.def_id, - substs: object_substs }); + object_trait.principal_trait_ref_with_self_ty(referent_ty); let object_obligation = Obligation::new( ObligationCause::new(span, @@ -328,36 +315,13 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match *error { Overflow => { // We could track the stack here more precisely if we wanted, I imagine. - match obligation.trait_ref { - ty::Predicate::Trait(ref trait_ref) => { - let trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "overflow evaluating the trait `{}` for the type `{}`", - trait_ref.user_string(fcx.tcx()), - trait_ref.self_ty().user_string(fcx.tcx())).as_slice()); - } - - ty::Predicate::Equate(a, b) => { - let a = fcx.infcx().resolve_type_vars_if_possible(a); - let b = fcx.infcx().resolve_type_vars_if_possible(b); - fcx.tcx().sess.span_err( - obligation.cause.span, - format!( - "overflow checking whether the types `{}` and `{}` are equal", - a.user_string(fcx.tcx()), - b.user_string(fcx.tcx())).as_slice()); - } - - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) => { - fcx.tcx().sess.span_err( - obligation.cause.span, - format!("overflow evaluating lifetime predicate").as_slice()); - } - } + let predicate = + fcx.infcx().resolve_type_vars_if_possible(&obligation.trait_ref); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "overflow evaluating the requirement `{}`", + predicate.user_string(fcx.tcx())).as_slice()); let current_limit = fcx.tcx().sess.recursion_limit.get(); let suggested_limit = current_limit * 2; @@ -372,9 +336,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Unimplemented => { match obligation.trait_ref { ty::Predicate::Trait(ref trait_ref) => { - let trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( - &**trait_ref); + let trait_ref = fcx.infcx().resolve_type_vars_if_possible(&**trait_ref); if !ty::type_is_error(trait_ref.self_ty()) { fcx.tcx().sess.span_err( obligation.cause.span, @@ -382,41 +344,51 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, "the trait `{}` is not implemented for the type `{}`", trait_ref.user_string(fcx.tcx()), trait_ref.self_ty().user_string(fcx.tcx())).as_slice()); - note_obligation_cause(fcx, obligation); } } - ty::Predicate::Equate(a, b) => { - let a = fcx.infcx().resolve_type_vars_if_possible(a); - let b = fcx.infcx().resolve_type_vars_if_possible(b); - let err = infer::can_mk_eqty(fcx.infcx(), a, b).unwrap_err(); + ty::Predicate::Equate(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + let err = fcx.infcx().equality_predicate(obligation.cause.span, + &predicate).unwrap_err(); fcx.tcx().sess.span_err( obligation.cause.span, format!( - "mismatched types: the types `{}` and `{}` are not equal ({})", - a.user_string(fcx.tcx()), - b.user_string(fcx.tcx()), + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(fcx.tcx()), ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); } - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) => { - // these kinds of predicates turn into - // constraints, and hence errors show up in region - // inference. - fcx.tcx().sess.span_bug( + ty::Predicate::RegionOutlives(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + let err = fcx.infcx().region_outlives_predicate(obligation.cause.span, + &predicate).unwrap_err(); + fcx.tcx().sess.span_err( obligation.cause.span, - format!("region predicate error {}", - obligation.repr(fcx.tcx())).as_slice()); + format!( + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(fcx.tcx()), + ty::type_err_to_str(fcx.tcx(), &err)).as_slice()); + } + + ty::Predicate::TypeOutlives(ref predicate) => { + let predicate = fcx.infcx().resolve_type_vars_if_possible(predicate); + fcx.tcx().sess.span_err( + obligation.cause.span, + format!( + "the requirement `{}` is not satisfied", + predicate.user_string(fcx.tcx())).as_slice()); } } + + note_obligation_cause(fcx, obligation); } OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => { let expected_trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + fcx.infcx().resolve_type_vars_if_possible( &**expected_trait_ref); let actual_trait_ref = - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible( + fcx.infcx().resolve_type_vars_if_possible( &**actual_trait_ref); if !ty::type_is_error(actual_trait_ref.self_ty()) { fcx.tcx().sess.span_err( @@ -443,7 +415,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let trait_ref = match obligation.trait_ref { ty::Predicate::Trait(ref trait_ref) => { - fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref) + fcx.infcx().resolve_type_vars_if_possible(&**trait_ref) } _ => { fcx.tcx().sess.span_bug( @@ -458,7 +430,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, trait_ref.repr(fcx.tcx()), self_ty.repr(fcx.tcx()), obligation.repr(fcx.tcx())); - let all_types = &trait_ref.substs.types; + let all_types = &trait_ref.substs().types; if all_types.iter().any(|&t| ty::type_is_error(t)) { } else if all_types.iter().any(|&t| ty::type_needs_infer(t)) { // This is kind of a hack: it frequently happens that some earlier @@ -477,7 +449,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // anyway. In that case, why inundate the user. if !fcx.tcx().sess.has_errors() { if fcx.ccx.tcx.lang_items.sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id) { + .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { fcx.tcx().sess.span_err( obligation.cause.span, format!( diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 8c82429e1c226..c09ce3db6ddd2 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -166,12 +166,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { // Find the impl self type as seen from the "inside" -- // that is, with all type parameters converted from bound - // to free, and any late-bound regions on the impl - // liberated. + // to free. 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); - let self_ty = liberate_late_bound_regions( - fcx.tcx(), item_scope, &ty::bind(self_ty)).value; bounds_checker.check_traits_in_ty(self_ty); @@ -182,7 +179,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { Some(t) => { t } }; let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs); - let trait_ref = liberate_late_bound_regions(fcx.tcx(), item_scope, &trait_ref); // There are special rules that apply to drop. if @@ -222,7 +218,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { traits::ItemObligation(trait_ref.def_id)); // Find the supertrait bounds. This will add `int:Bar`. - let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &trait_ref); + let poly_trait_ref = ty::Binder(trait_ref); + let predicates = ty::predicates_for_trait_ref(fcx.tcx(), &poly_trait_ref); for predicate in predicates.into_iter() { fcx.register_predicate(traits::Obligation::new(cause, predicate)); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 8d94cf5dd5e96..b73381966e8dc 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -19,8 +19,6 @@ use middle::def; use middle::pat_util; use middle::ty::{mod, Ty, MethodCall, MethodCallee}; use middle::ty_fold::{TypeFolder,TypeFoldable}; -use middle::infer::{force_all, resolve_all, resolve_region}; -use middle::infer::resolve_type; use middle::infer; use write_substs_to_tcx; use write_ty_to_tcx; @@ -337,8 +335,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn resolve>(&self, t: &T, reason: ResolveReason) -> T { - t.resolve_in(&mut Resolver::new(self.fcx, reason)) + fn resolve>(&self, t: &T, reason: ResolveReason) -> T { + t.fold_with(&mut Resolver::new(self.fcx, reason)) } } @@ -375,19 +373,6 @@ impl ResolveReason { } } -/////////////////////////////////////////////////////////////////////////// -// Convenience methods for resolving different kinds of things. - -trait ResolveIn<'tcx> { - fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> Self; -} - -impl<'tcx, T: TypeFoldable<'tcx>> ResolveIn<'tcx> for T { - fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> T { - self.fold_with(resolver) - } -} - /////////////////////////////////////////////////////////////////////////// // The Resolver. This is the type folding engine that detects // unresolved types and so forth. @@ -465,13 +450,11 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !ty::type_needs_infer(t) { - return t; - } - - match resolve_type(self.infcx, None, t, resolve_all | force_all) { + match self.infcx.fully_resolve(&t) { Ok(t) => t, Err(e) => { + debug!("Resolver::fold_ty: input type `{}` not fully resolvable", + t.repr(self.tcx)); self.report_error(e); ty::mk_err() } @@ -479,7 +462,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } fn fold_region(&mut self, r: ty::Region) -> ty::Region { - match resolve_region(self.infcx, r, resolve_all | force_all) { + match self.infcx.fully_resolve(&r) { Ok(r) => r, Err(e) => { self.report_error(e); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a55f3c6191940..5d0bb6622c2e1 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -19,6 +19,7 @@ use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; use middle::subst::{mod, Subst}; +use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type}; use middle::ty::{Ty, ty_bool, ty_char, ty_closure, ty_enum, ty_err}; @@ -26,12 +27,11 @@ use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_open}; use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; -use middle::ty::{type_is_ty_var}; use middle::ty; use CrateCtxt; use middle::infer::combine::Combine; use middle::infer::InferCtxt; -use middle::infer::{new_infer_ctxt, resolve_ivar, resolve_type}; +use middle::infer::{new_infer_ctxt}; use std::collections::{HashSet}; use std::cell::RefCell; use std::rc::Rc; @@ -52,80 +52,35 @@ mod orphan; mod overlap; mod unsafety; -fn get_base_type<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, - span: Span, - original_type: Ty<'tcx>) - -> Option> { - let resolved_type = match resolve_type(inference_context, - Some(span), - original_type, - resolve_ivar) { - Ok(resulting_type) if !type_is_ty_var(resulting_type) => resulting_type, - _ => { - inference_context.tcx.sess.span_fatal(span, - "the type of this value must be known in order \ - to determine the base type"); - } - }; - - match resolved_type.sty { - ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => { - debug!("(getting base type) found base type"); - Some(resolved_type) +// Returns the def ID of the base type, if there is one. +fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, + span: Span, + ty: Ty<'tcx>) + -> Option { + match ty.sty { + ty_enum(def_id, _) | + ty_struct(def_id, _) => { + Some(def_id) } - _ if ty::type_is_trait(resolved_type) => { - debug!("(getting base type) found base type (trait)"); - Some(resolved_type) + ty_trait(ref t) => { + Some(t.principal.def_id()) } ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | - ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | + ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => { - debug!("(getting base type) no base type; found {}", - original_type.sty); None } - ty_trait(..) => panic!("should have been caught") - } -} -// Returns the def ID of the base type, if there is one. -fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, - span: Span, - original_type: Ty<'tcx>) - -> Option { - match get_base_type(inference_context, span, original_type) { - None => None, - Some(base_type) => { - match base_type.sty { - ty_enum(def_id, _) | - ty_struct(def_id, _) | - ty_unboxed_closure(def_id, _, _) => { - Some(def_id) - } - ty_ptr(ty::mt {ty, ..}) | - ty_rptr(_, ty::mt {ty, ..}) | - ty_uniq(ty) => { - match ty.sty { - ty_trait(box ty::TyTrait { ref principal, .. }) => { - Some(principal.def_id) - } - _ => { - panic!("get_base_type() returned a type that wasn't an \ - enum, struct, or trait"); - } - } - } - ty_trait(box ty::TyTrait { ref principal, .. }) => { - Some(principal.def_id) - } - _ => { - panic!("get_base_type() returned a type that wasn't an \ - enum, struct, or trait"); - } - } + ty_infer(..) | ty_unboxed_closure(..) => { + // `ty` comes from a user declaration so we should only expect types + // that the user can type + inference_context.tcx.sess.span_bug( + span, + format!("coherence encountered unexpected type searching for base type: {}", + ty.repr(inference_context.tcx))[]); } } } @@ -504,6 +459,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let trait_impls = trait_impls.borrow().clone(); for &impl_did in trait_impls.iter() { + debug!("check_implementations_of_copy: impl_did={}", + impl_did.repr(tcx)); + if impl_did.krate != ast::LOCAL_CRATE { debug!("check_implementations_of_copy(): impl not in this \ crate"); @@ -511,10 +469,16 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let self_type = self.get_self_type_for_implementation(impl_did); + debug!("check_implementations_of_copy: self_type={} (bound)", + self_type.repr(tcx)); + let span = tcx.map.span(impl_did.node); - let param_env = ParameterEnvironment::for_item(tcx, - impl_did.node); + let param_env = ParameterEnvironment::for_item(tcx, impl_did.node); let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs); + assert!(!self_type.has_escaping_regions()); + + debug!("check_implementations_of_copy: self_type={} (free)", + self_type.repr(tcx)); match ty::can_type_implement_copy(tcx, self_type, ¶m_env) { Ok(()) => {} diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 1803bf766dda1..bb8efd2991070 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -55,7 +55,7 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { self.check_def_id(item.span, def_id); } ty::ty_trait(box ty::TyTrait{ ref principal, ..}) => { - self.check_def_id(item.span, principal.def_id); + self.check_def_id(item.span, principal.def_id()); } _ => { span_err!(self.tcx.sess, item.span, E0118, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 91947f67dd7f5..280b42f0959d2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -42,10 +42,9 @@ use middle::region; use middle::resolve_lifetime; use middle::subst; use middle::subst::{Substs}; -use middle::ty::{ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{Polytype}; -use middle::ty::{mod, Ty}; -use middle::ty_fold::TypeFolder; +use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; +use middle::ty::{mod, RegionEscape, Ty, Polytype}; +use middle::ty_fold::{mod, TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; @@ -227,7 +226,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast::StructVariantKind(ref struct_def) => { let pty = Polytype { - generics: ty_generics_for_type( + generics: ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes), @@ -240,7 +239,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }; let pty = Polytype { - generics: ty_generics_for_type( + generics: ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes), @@ -652,7 +651,7 @@ fn is_associated_type_valid_for_param(ty: Ty, if let ty::ty_param(param_ty) = ty.sty { let type_parameter = generics.types.get(param_ty.space, param_ty.idx); for trait_bound in type_parameter.bounds.trait_bounds.iter() { - if trait_bound.def_id == trait_id { + if trait_bound.def_id() == trait_id { return true } } @@ -1051,7 +1050,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ref selfty, ref impl_items) => { // Create generics from the generics specified in the impl head. - let ty_generics = ty_generics_for_impl( + let ty_generics = ty_generics_for_type_or_impl( ccx, generics, CreateTypeParametersForAssociatedTypes); @@ -1483,7 +1482,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) let pty = { let ty = ccx.to_ty(&ExplicitRscope, &**t); Polytype { - generics: ty_generics_for_type( + generics: ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes), @@ -1496,7 +1495,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) } ast::ItemEnum(_, ref generics) => { // Create a new generic polytype. - let ty_generics = ty_generics_for_type( + let ty_generics = ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes); @@ -1514,7 +1513,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) tcx.sess.span_bug(it.span, "invoked ty_of_item on trait"); } ast::ItemStruct(_, ref generics) => { - let ty_generics = ty_generics_for_type( + let ty_generics = ty_generics_for_type_or_impl( ccx, generics, DontCreateTypeParametersForAssociatedTypes); @@ -1581,11 +1580,11 @@ fn ty_of_trait_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_generics_for_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ast::Generics, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) - -> ty::Generics<'tcx> { +fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + generics: &ast::Generics, + create_type_parameters_for_associated_types: + CreateTypeParametersForAssociatedTypesFlag) + -> ty::Generics<'tcx> { ty_generics(ccx, subst::TypeSpace, generics.lifetimes.as_slice(), @@ -1638,8 +1637,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_id = trait_id; let self_trait_ref = - Rc::new(ty::TraitRef { def_id: local_def(trait_id), - substs: (*substs).clone() }); + Rc::new(ty::Binder(ty::TraitRef { def_id: local_def(trait_id), + substs: (*substs).clone() })); let def = ty::TypeParameterDef { space: subst::SelfSpace, @@ -1665,24 +1664,6 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics } -fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ast::Generics, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) - -> ty::Generics<'tcx> -{ - let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); - debug!("ty_generics_for_impl: early_lifetimes={}", - early_lifetimes); - ty_generics(ccx, - subst::TypeSpace, - early_lifetimes.as_slice(), - generics.ty_params.as_slice(), - ty::Generics::empty(), - &generics.where_clause, - create_type_parameters_for_associated_types) -} - fn ty_generics_for_fn_or_method<'tcx,AC>( this: &AC, generics: &ast::Generics, @@ -1920,8 +1901,12 @@ fn ty_generics<'tcx,AC>(this: &AC, for region_param_def in result.regions.get_slice(space).iter() { let region = region_param_def.to_early_bound_region(); for &bound_region in region_param_def.bounds.iter() { - result.predicates.push(space, ty::Predicate::RegionOutlives(region, - bound_region)); + // account for new binder introduced in the predicate below; no need + // to shift `region` because it is never a late-bound region + let bound_region = ty_fold::shift_region(bound_region, 1); + result.predicates.push( + space, + ty::Binder(ty::OutlivesPredicate(region, bound_region)).as_predicate()); } } } @@ -2015,7 +2000,7 @@ fn compute_bounds<'tcx,AC>(this: &AC, ¶m_bounds, span); - param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id)); + param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); param_bounds } @@ -2031,13 +2016,13 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, tcx, param_bounds.trait_bounds.as_slice(), |trait_ref| { - let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id); + let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id()); if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) { span_err!(tcx.sess, span, E0129, "incompatible bounds on type parameter `{}`, \ bound `{}` does not allow unsized type", name_of_bounded_thing.user_string(tcx), - ppaux::trait_ref_to_string(tcx, &*trait_ref)); + trait_ref.user_string(tcx)); } true }); @@ -2057,14 +2042,14 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, trait_bounds, region_bounds } = astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice()); - let trait_bounds: Vec> = + let trait_bounds: Vec> = trait_bounds.into_iter() .map(|bound| { - astconv::instantiate_trait_ref(this, - &ExplicitRscope, - &bound.trait_ref, - Some(param_ty.to_ty(this.tcx())), - AllowEqConstraints::Allow) + astconv::instantiate_poly_trait_ref(this, + &ExplicitRscope, + bound, + Some(param_ty.to_ty(this.tcx())), + AllowEqConstraints::Allow) }) .collect(); let region_bounds: Vec = @@ -2155,9 +2140,9 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::BareFnTy { abi: abi, unsafety: ast::Unsafety::Unsafe, - sig: ty::FnSig {inputs: input_tys, - output: output, - variadic: decl.variadic} + sig: ty::Binder(ty::FnSig {inputs: input_tys, + output: output, + variadic: decl.variadic}), }); let pty = Polytype { generics: ty_generics_for_fn_or_method, @@ -2183,8 +2168,12 @@ pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, subst::Substs::new(types, regions) } -/// Verifies that the explicit self type of a method matches the impl or -/// trait. +/// Verifies that the explicit self type of a method matches the impl +/// or trait. This is a bit weird but basically because right now we +/// don't handle the general case, but instead map it to one of +/// several pre-defined options using various heuristics, this method +/// comes back to check after the fact that explicit type the user +/// wrote actually matches what the pre-defined option said. fn check_method_self_type<'a, 'tcx, RS:RegionScope>( crate_context: &CrateCtxt<'a, 'tcx>, rs: &RS, @@ -2206,19 +2195,21 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( // contain late-bound regions from the method, but not the // trait (since traits only have early-bound region // parameters). - assert!(!ty::type_escapes_depth(required_type, 1)); + assert!(!base_type.has_regions_escaping_depth(1)); let required_type_free = - ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::bind(required_type)).value; - - // The "base type" comes from the impl. It may have late-bound - // regions from the impl or the method. - let base_type_free = // liberate impl regions: - ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::bind(ty::bind(base_type))).value.value; - let base_type_free = // liberate method regions: - ty::liberate_late_bound_regions( - crate_context.tcx, body_scope, &ty::bind(base_type_free)).value; + liberate_early_bound_regions( + crate_context.tcx, body_scope, + &ty::liberate_late_bound_regions( + crate_context.tcx, body_scope, &ty::Binder(required_type))); + + // The "base type" comes from the impl. It too may have late-bound + // regions from the method. + assert!(!base_type.has_regions_escaping_depth(1)); + let base_type_free = + liberate_early_bound_regions( + crate_context.tcx, body_scope, + &ty::liberate_late_bound_regions( + crate_context.tcx, body_scope, &ty::Binder(base_type))); debug!("required_type={} required_type_free={} \ base_type={} base_type_free={}", @@ -2239,4 +2230,30 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( })); infcx.resolve_regions_and_report_errors(body_id); } + + fn liberate_early_bound_regions<'tcx,T>( + tcx: &ty::ctxt<'tcx>, + scope: region::CodeExtent, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Repr<'tcx> + { + /*! + * Convert early-bound regions into free regions; normally this is done by + * applying the `free_substs` from the `ParameterEnvironment`, but this particular + * method-self-type check is kind of hacky and done very early in the process, + * before we really have a `ParameterEnvironment` to check. + */ + + ty_fold::fold_regions(tcx, value, |region, _| { + match region { + ty::ReEarlyBound(id, _, _, name) => { + let def_id = local_def(id); + ty::ReFree(ty::FreeRegion { scope: scope, + bound_region: ty::BrNamed(def_id, name) }) + } + _ => region + } + }) + } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d55d642f74651..5fc2466674ebe 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -228,11 +228,11 @@ fn check_main_fn_ty(ccx: &CrateCtxt, let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: Vec::new(), output: ty::FnConverging(ty::mk_nil(tcx)), variadic: false - } + }) }); require_same_types(tcx, None, false, main_span, main_t, se_ty, @@ -276,14 +276,14 @@ fn check_start_fn_ty(ccx: &CrateCtxt, let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { unsafety: ast::Unsafety::Normal, abi: abi::Rust, - sig: ty::FnSig { + sig: ty::Binder(ty::FnSig { inputs: vec!( ty::mk_int(), ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8())) ), output: ty::FnConverging(ty::mk_int()), variadic: false - } + }), }); require_same_types(tcx, None, false, start_span, start_t, se_ty, diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 8fe14bae0f5bc..67478e0bfa77e 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -777,13 +777,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => { - let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id); + let trait_def = ty::lookup_trait_def(self.tcx(), principal.def_id()); let generics = &trait_def.generics; // Traits DO have a Self type parameter, but it is // erased from object types. assert!(!generics.types.is_empty_in(subst::SelfSpace) && - principal.substs.types.is_empty_in(subst::SelfSpace)); + principal.substs().types.is_empty_in(subst::SelfSpace)); // Traits never declare region parameters in the self // space. @@ -799,10 +799,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_region(bounds.region_bound, contra); self.add_constraints_from_substs( - principal.def_id, + principal.def_id(), generics.types.get_slice(subst::TypeSpace), generics.regions.get_slice(subst::TypeSpace), - &principal.substs, + principal.substs(), variance); } @@ -878,13 +878,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { /// Adds constraints appropriate for a function with signature /// `sig` appearing in a context with ambient variance `variance` fn add_constraints_from_sig(&mut self, - sig: &ty::FnSig<'tcx>, + sig: &ty::PolyFnSig<'tcx>, variance: VarianceTermPtr<'a>) { let contra = self.contravariant(variance); - for &input in sig.inputs.iter() { + for &input in sig.0.inputs.iter() { self.add_constraints_from_ty(input, contra); } - if let ty::FnConverging(result_type) = sig.output { + if let ty::FnConverging(result_type) = sig.0.output { self.add_constraints_from_ty(result_type, variance); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d640f055388cb..661d6ec241ade 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -575,6 +575,12 @@ impl Clean for ty::BuiltinBound { } } +impl<'tcx> Clean for ty::PolyTraitRef<'tcx> { + fn clean(&self, cx: &DocContext) -> TyParamBound { + self.0.clean(cx) + } +} + impl<'tcx> Clean for ty::TraitRef<'tcx> { fn clean(&self, cx: &DocContext) -> TyParamBound { let tcx = match cx.tcx_opt() { @@ -913,7 +919,7 @@ impl<'tcx> Clean for ty::FnOutput<'tcx> { } } -impl<'a, 'tcx> Clean for (ast::DefId, &'a ty::FnSig<'tcx>) { +impl<'a, 'tcx> Clean for (ast::DefId, &'a ty::PolyFnSig<'tcx>) { fn clean(&self, cx: &DocContext) -> FnDecl { let (did, sig) = *self; let mut names = if did.node != 0 { @@ -925,10 +931,10 @@ impl<'a, 'tcx> Clean for (ast::DefId, &'a ty::FnSig<'tcx>) { let _ = names.next(); } FnDecl { - output: Return(sig.output.clean(cx)), + output: Return(sig.0.output.clean(cx)), attrs: Vec::new(), inputs: Arguments { - values: sig.inputs.iter().map(|t| { + values: sig.0.inputs.iter().map(|t| { Argument { type_: t.clean(cx), id: 0, @@ -1082,14 +1088,14 @@ impl<'tcx> Clean for ty::Method<'tcx> { ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(cx), self.fty.sig.clone()), s => { - let sig = ty::FnSig { - inputs: self.fty.sig.inputs[1..].to_vec(), - ..self.fty.sig.clone() - }; + let sig = ty::Binder(ty::FnSig { + inputs: self.fty.sig.0.inputs[1..].to_vec(), + ..self.fty.sig.0.clone() + }); let s = match s { ty::ByValueExplicitSelfCategory => SelfValue, ty::ByReferenceExplicitSelfCategory(..) => { - match self.fty.sig.inputs[0].sty { + match self.fty.sig.0.inputs[0].sty { ty::ty_rptr(r, mt) => { SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx)) } @@ -1097,7 +1103,7 @@ impl<'tcx> Clean for ty::Method<'tcx> { } } ty::ByBoxExplicitSelfCategory => { - SelfExplicit(self.fty.sig.inputs[0].clean(cx)) + SelfExplicit(self.fty.sig.0.inputs[0].clean(cx)) } ty::StaticExplicitSelfCategory => unreachable!(), }; @@ -1391,8 +1397,10 @@ impl<'tcx> Clean for ty::Ty<'tcx> { } ty::ty_struct(did, ref substs) | ty::ty_enum(did, ref substs) | - ty::ty_trait(box ty::TyTrait { principal: ty::TraitRef { def_id: did, ref substs }, - .. }) => { + ty::ty_trait(box ty::TyTrait { + principal: ty::Binder(ty::TraitRef { def_id: did, ref substs }), + .. }) => + { let fqn = csearch::get_item_path(cx.tcx(), did); let fqn: Vec = fqn.into_iter().map(|i| { i.to_string() diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 95d7906b44354..5a1a186c74c4e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -105,8 +105,11 @@ pub trait Visitor<'v> { None => () } } + fn visit_lifetime_bound(&mut self, lifetime: &'v Lifetime) { + walk_lifetime_bound(self, lifetime) + } fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { - self.visit_name(lifetime.span, lifetime.name) + walk_lifetime_ref(self, lifetime) } fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { walk_lifetime_def(self, lifetime) @@ -214,10 +217,20 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name); for bound in lifetime_def.bounds.iter() { - visitor.visit_lifetime_ref(bound); + visitor.visit_lifetime_bound(bound); } } +pub fn walk_lifetime_bound<'v, V: Visitor<'v>>(visitor: &mut V, + lifetime_ref: &'v Lifetime) { + visitor.visit_lifetime_ref(lifetime_ref) +} + +pub fn walk_lifetime_ref<'v, V: Visitor<'v>>(visitor: &mut V, + lifetime_ref: &'v Lifetime) { + visitor.visit_name(lifetime_ref.span, lifetime_ref.name) +} + pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { match explicit_self.node { @@ -550,7 +563,7 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, visitor.visit_poly_trait_ref(typ); } RegionTyParamBound(ref lifetime) => { - visitor.visit_lifetime_ref(lifetime); + visitor.visit_lifetime_bound(lifetime); } } } diff --git a/src/test/compile-fail/bad-match.rs b/src/test/compile-fail/bad-match.rs index 39c3ed3e2a3d2..728b577df1dd4 100644 --- a/src/test/compile-fail/bad-match.rs +++ b/src/test/compile-fail/bad-match.rs @@ -14,3 +14,6 @@ fn main() { let int x = 5; match x; } + +fn main() { +} diff --git a/src/test/compile-fail/hrtb-conflate-regions.rs b/src/test/compile-fail/hrtb-conflate-regions.rs new file mode 100644 index 0000000000000..5eb8fd6931258 --- /dev/null +++ b/src/test/compile-fail/hrtb-conflate-regions.rs @@ -0,0 +1,40 @@ +// 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 that an impl with only one bound region `'a` cannot be used to +// satisfy a constraint where there are two bound regions. + +trait Foo { + fn foo(&self, x: X) { } +} + +fn want_foo2() + where T : for<'a,'b> Foo<(&'a int, &'b int)> +{ +} + +fn want_foo1() + where T : for<'z> Foo<(&'z int, &'z int)> +{ +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as a where clause + +struct SomeStruct; + +impl<'a> Foo<(&'a int, &'a int)> for SomeStruct +{ +} + +fn a() { want_foo1::(); } // OK -- foo wants just one region +fn b() { want_foo2::(); } //~ ERROR not implemented + +fn main() { } diff --git a/src/test/compile-fail/hrtb-just-for-static.rs b/src/test/compile-fail/hrtb-just-for-static.rs new file mode 100644 index 0000000000000..36a45400eec1a --- /dev/null +++ b/src/test/compile-fail/hrtb-just-for-static.rs @@ -0,0 +1,37 @@ +// 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 a case where you have an impl of `Foo` for all `X` that +// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730. + +trait Foo { + fn foo(&self, x: X) { } +} + +fn want_hrtb() + where T : for<'a> Foo<&'a int> +{ +} + +// AnyInt implements Foo<&'a int> for any 'a, so it is a match. +struct AnyInt; +impl<'a> Foo<&'a int> for AnyInt { } +fn give_any() { + want_hrtb::() +} + +// StaticInt only implements Foo<&'static int>, so it is an error. +struct StaticInt; +impl Foo<&'static int> for StaticInt { } +fn give_static() { + want_hrtb::() //~ ERROR `for<'a> Foo<&'a int>` is not implemented +} + +fn main() { } diff --git a/src/test/compile-fail/hrtb-perfect-forwarding.rs b/src/test/compile-fail/hrtb-perfect-forwarding.rs new file mode 100644 index 0000000000000..a8ee2154fc396 --- /dev/null +++ b/src/test/compile-fail/hrtb-perfect-forwarding.rs @@ -0,0 +1,66 @@ +// 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 a case where you have an impl of `Foo` for all `X` that +// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730. + +trait Foo { + fn foo(&mut self, x: X) { } +} + +trait Bar { + fn bar(&mut self, x: X) { } +} + +impl<'a,X,F> Foo for &'a mut F + where F : Foo + Bar +{ +} + +impl<'a,X,F> Bar for &'a mut F + where F : Bar +{ +} + +fn no_hrtb<'b,T>(mut t: T) + where T : Bar<&'b int> +{ + // OK -- `T : Bar<&'b int>`, and thus the impl above ensures that + // `&mut T : Bar<&'b int>`. + no_hrtb(&mut t); +} + +fn bar_hrtb(mut t: T) + where T : for<'b> Bar<&'b int> +{ + // OK -- `T : for<'b> Bar<&'b int>`, and thus the impl above + // ensures that `&mut T : for<'b> Bar<&'b int>`. This is an + // example of a "perfect forwarding" impl. + bar_hrtb(&mut t); +} + +fn foo_hrtb_bar_not<'b,T>(mut t: T) + where T : for<'a> Foo<&'a int> + Bar<&'b int> +{ + // Not OK -- The forwarding impl for `Foo` requires that `Bar` also + // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a + // int>`, we require `T : for<'a> Bar<&'a int>`, but the where + // clause only specifies `T : Bar<&'b int>`. + foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> Bar<&'a int>` is not implemented for the type `T` +} + +fn foo_hrtb_bar_hrtb(mut t: T) + where T : for<'a> Foo<&'a int> + for<'b> Bar<&'b int> +{ + // OK -- now we have `T : for<'b> Bar&'b int>`. + foo_hrtb_bar_hrtb(&mut t); +} + +fn main() { } diff --git a/src/test/compile-fail/hrtb-type-outlives.rs b/src/test/compile-fail/hrtb-type-outlives.rs new file mode 100644 index 0000000000000..9fe8f9ab46ddc --- /dev/null +++ b/src/test/compile-fail/hrtb-type-outlives.rs @@ -0,0 +1,59 @@ +// 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 what happens when a HR obligation is applied to an impl with +// "outlives" bounds. Currently we're pretty conservative here; this +// will probably improve in time. + +trait Foo { + fn foo(&self, x: X) { } +} + +fn want_foo() + where T : for<'a> Foo<&'a int> +{ +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as a where clause + +struct SomeStruct { + x: X +} + +impl<'a,X> Foo<&'a int> for SomeStruct + where X : 'a +{ +} + +fn one() { + // In fact there is no good reason for this to be an error, but + // whatever, I'm mostly concerned it doesn't ICE right now: + want_foo::>(); + //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied +} + +/////////////////////////////////////////////////////////////////////////// +// Expressed as shorthand + +struct AnotherStruct { + x: X +} + +impl<'a,X:'a> Foo<&'a int> for AnotherStruct +{ +} + +fn two() { + want_foo::>(); + //~^ ERROR requirement `for<'a> uint : 'a` is not satisfied +} + +fn main() { } diff --git a/src/test/compile-fail/issue-14366.rs b/src/test/compile-fail/issue-14366.rs index 01a15023fbaad..d03885ca7133c 100644 --- a/src/test/compile-fail/issue-14366.rs +++ b/src/test/compile-fail/issue-14366.rs @@ -11,5 +11,4 @@ fn main() { let _x = "test" as &::std::any::Any; //~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str` -//~^^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str` } diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index 935e67706589e..f3636edeaa589 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -10,7 +10,10 @@ fn main() { return - { return () } //~ ERROR the type of this value must be known in this context + { return () } +//~^ ERROR the type of this value must be known in this context +//~| ERROR this function takes 1 parameter +//~| ERROR mismatched types () ; } diff --git a/src/test/compile-fail/issue-18345.rs b/src/test/compile-fail/issue-18345.rs index 298f155faff94..c8b3463b0911d 100644 --- a/src/test/compile-fail/issue-18345.rs +++ b/src/test/compile-fail/issue-18345.rs @@ -13,7 +13,9 @@ type Transducer<'t, R, T, U> = |Step<'t, R, U>|: 't -> Step<'t, R, T>; fn mapping<'f, R, T, U>(f: |T|: 'f -> U) -> &'f Transducer<'f, R, T, U> { |step| |r, x| - step(r, f(x)) //~ ERROR the type of this value must be known in this context + step(r, f(x)) + //~^ ERROR the type of this value must be known in this context + //~| ERROR this function takes 1 parameter but 2 parameters were supplied } fn main() {} diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index 9cf922ae99002..ec44ab7b27705 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -17,4 +17,5 @@ fn main() { (return)((),()); //~^ ERROR the type of this value must be known + //~| ERROR this function takes 1 parameter } diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index 51ee38d5cfed2..f5740992af48e 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -21,10 +21,15 @@ impl Foo for T { fn take_param(foo: &T) { } -fn main() { +fn a() { let x = box 3i; take_param(&x); //~ ERROR `core::kinds::Copy` is not implemented +} +fn b() { + let x = box 3i; let y = &x; let z = &x as &Foo; //~ ERROR `core::kinds::Copy` is not implemented } + +fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs index a82689b16491e..b0b37d077c170 100644 --- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -20,9 +20,16 @@ fn call_itint>(_: &F, _: int) -> int { 0 } fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } fn call_it_onceint>(_: F, _: int) -> int { 0 } -fn main() { +fn a() { let x = call_it(&square, 22); //~ ERROR not implemented +} + +fn b() { let y = call_it_mut(&mut square, 22); //~ ERROR not implemented +} + +fn c() { let z = call_it_once(square, 22); //~ ERROR not implemented } +fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs index 920e91958ee9e..20a4ab85d7ba8 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -20,9 +20,17 @@ fn call_itint>(_: &F, _: int) -> int { 0 } fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } fn call_it_onceint>(_: F, _: int) -> int { 0 } -fn main() { +fn a() { let x = call_it(&square, 22); //~ ERROR not implemented +} + +fn b() { let y = call_it_mut(&mut square, 22); //~ ERROR not implemented +} + +fn c() { let z = call_it_once(square, 22); //~ ERROR not implemented } +fn main() { } + diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs index a7a7b1c676267..f08cff3cd6821 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -21,9 +21,16 @@ fn call_itint>(_: &F, _: int) -> int { 0 } fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } fn call_it_onceint>(_: F, _: int) -> int { 0 } -fn main() { +fn a() { let x = call_it(&square, 22); //~ ERROR not implemented +} + +fn b() { let y = call_it_mut(&mut square, 22); //~ ERROR not implemented +} + +fn c() { let z = call_it_once(square, 22); //~ ERROR not implemented } +fn main() { } diff --git a/src/test/run-pass/hrtb-opt-in-copy.rs b/src/test/run-pass/hrtb-opt-in-copy.rs new file mode 100644 index 0000000000000..b6bba363e7236 --- /dev/null +++ b/src/test/run-pass/hrtb-opt-in-copy.rs @@ -0,0 +1,38 @@ +// 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 that we handle binder levels correctly when checking whether a +// type can implement `Copy`. In particular, we had a bug where we failed to +// liberate the late-bound regions from the impl, and thus wound up +// searching for an impl of `for<'tcx> Foo<&'tcx T>`. The impl that +// exists however is `impl Copy for Foo` and the current rules +// did not consider that a match (something I would like to revise in +// a later PR). + +#![allow(dead_code)] + +use std::kinds::marker; + +#[deriving(Copy)] +struct Foo { x: T } + +type Ty<'tcx> = &'tcx TyS<'tcx>; + +enum TyS<'tcx> { + Boop(marker::InvariantLifetime<'tcx>) +} + +enum Bar<'tcx> { + Baz(Foo>) +} + +impl<'tcx> Copy for Bar<'tcx> { } + +fn main() { } diff --git a/src/test/run-pass/issue-10501.rs b/src/test/run-pass/issue-10501.rs deleted file mode 100644 index 78f125398edcb..0000000000000 --- a/src/test/run-pass/issue-10501.rs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -pub type Foo = fn(&int) -> (); -#[deriving(Clone)] -enum Baz { Bar(Foo) } -fn main() {} diff --git a/src/test/run-pass/issue-12741.rs b/src/test/run-pass/issue-12741.rs deleted file mode 100644 index e41613b4ae305..0000000000000 --- a/src/test/run-pass/issue-12741.rs +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -#[deriving(Clone)] -pub struct Foo { - f: fn(char, |char| -> char) -> char -} - -impl Foo { - fn bar(&self) -> char { - ((*self).f)('a', |c: char| c) - } -} - -fn bla(c: char, cb: |char| -> char) -> char { - cb(c) -} - -pub fn make_foo() -> Foo { - Foo { - f: bla - } -} - -fn main() { - let a = make_foo(); - assert_eq!(a.bar(), 'a'); -}