auto merge of #19884 : nikomatsakis/rust/issue-19730-perfect-forwarding, r=pnkfelix

Rewrite how the HRTB algorithm matches impls against obligations. Instead of impls providing higher-ranked trait-references, impls now once again only have early-bound regions. The skolemization checks are thus moved out into trait matching itself. This allows to implement "perfect forwarding" impls like those described in #19730. This PR builds on a previous PR that was already reviewed by @pnkfelix.

r? @pnkfelix 

Fixes #19730
This commit is contained in:
bors 2014-12-19 13:22:10 +00:00
commit bd90b936d7
84 changed files with 3195 additions and 2414 deletions

View file

@ -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

View file

@ -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]

View file

@ -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()
}
}
}

View file

@ -704,7 +704,7 @@ pub fn get_enum_variants<'tcx>(intr: Rc<IdentInterner>, 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)

View file

@ -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;

View file

@ -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);

View file

@ -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<Ty<'tcx>>;
fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> Rc<ty::TraitRef<'tcx>>;
fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> Rc<ty::PolyTraitRef<'tcx>>;
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<ty::PolyTraitRef<'tcx>> {
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);
}

View file

@ -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");
}
}
}

View file

@ -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 {

View file

@ -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<T, F>(&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,

View file

@ -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<Ty<'tcx>>>
{
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<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
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<C:Combine<'tcx>>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>;
}
impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> {
fn combine<C:Combine<'tcx>>(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<C:Combine<'tcx>>(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))
}
}

View file

@ -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<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
where T : Combineable<'tcx>
{
try!(self.sub().binders(a, b));
self.sub().binders(b, a)
}
}

View file

@ -395,7 +395,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String> {
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<ty::TraitRef<'tcx>> {
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
-> Rc<ty::TraitRef<'tcx>> {
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<ty::PolyTraitRef<'tcx>> {
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
-> Rc<ty::PolyTraitRef<'tcx>> {
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<ast::LifetimeDef> {

View file

@ -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<ty::InferTy, Ty<'tcx>>,
freshen_count: uint,
freshen_map: hash_map::HashMap<ty::InferTy, Ty<'tcx>>,
}
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<F>(&mut self,
opt_ty: Option<Ty<'tcx>>,
key: ty::InferTy,
skolemizer: F)
-> Ty<'tcx> where
fn freshen<F>(&mut self,
opt_ty: Option<Ty<'tcx>>,
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 |

View file

@ -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<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
where T : Combineable<'tcx>
{
self.higher_ranked_glb(a, b)
}
}

View file

@ -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

View file

@ -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<C:Combine<'tcx>>(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<T>(&self, a: &T, b: &T) -> cres<'tcx, T>
where T : HigherRankedCombineable<'tcx>;
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
where T : Combineable<'tcx>;
fn higher_ranked_lub<T>(&self, a: &T, b: &T) -> cres<'tcx, T>
where T : HigherRankedCombineable<'tcx>;
fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
where T : Combineable<'tcx>;
fn higher_ranked_glb<T>(&self, a: &T, b: &T) -> cres<'tcx, T>
where T : HigherRankedCombineable<'tcx>;
fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
where T : Combineable<'tcx>;
}
trait InferCtxtExt<'tcx> {
fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region>;
fn region_vars_confined_to_snapshot(&self,
snapshot: &CombinedSnapshot)
-> Vec<ty::RegionVid>;
}
impl<'tcx,C> HigherRankedRelations<'tcx> for C
where C : Combine<'tcx>
{
fn higher_ranked_sub<T>(&self, a: &T, b: &T) -> cres<'tcx, T>
where T : HigherRankedCombineable<'tcx>
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
-> cres<'tcx, Binder<T>>
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();
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);
// 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);
// 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()));
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));
// 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; }
// 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));
}
_ => {
if *tainted_region == skol { continue; }
}
};
// 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<T>(&self, a: &T, b: &T) -> cres<'tcx, T>
where T : HigherRankedCombineable<'tcx>
fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
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();
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);
// 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()));
// 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_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));
// 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()));
debug!("lub({},{}) = {}",
a.repr(self.tcx()),
b.repr(self.tcx()),
result1.repr(self.tcx()));
return Ok(result1);
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<ty::BoundRegion, ty::Region>,
@ -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<T>(&self, a: &T, b: &T) -> cres<'tcx, T>
where T : HigherRankedCombineable<'tcx>
fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> cres<'tcx, Binder<T>>
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();
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);
// 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()));
// 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 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));
// 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()));
debug!("glb({},{}) = {}",
a.repr(self.tcx()),
b.repr(self.tcx()),
result1.repr(self.tcx()));
return Ok(result1);
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<ty::BoundRegion, ty::Region>,
@ -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<C:Combine<'tcx>>(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<Ty<'tcx>>>
{
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<C:Combine<'tcx>>(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<ty::BoundRegion, ty::Region>)
-> Vec<ty::RegionVid> {
@ -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<ty::Region> {
self.region_vars.tainted(&snapshot.region_vars_snapshot, r)
}
fn region_vars_confined_to_snapshot(&self,
snapshot: &CombinedSnapshot)
-> Vec<ty::RegionVid>
{
/*!
* 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(|&region_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<T>,
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<A,R> Fn<A,R> 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<ty::Region, ty::BoundRegion> =
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
}

View file

@ -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<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
where T : Combineable<'tcx>
{
self.higher_ranked_lub(a, b)
}
}

View file

@ -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<ty::BoundRegion,ty::Region>;
/// 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<Ty<'tcx>>),
TraitRefs(ty::expected_found<Rc<ty::TraitRef<'tcx>>>),
PolyTraitRefs(ty::expected_found<Rc<ty::PolyTraitRef<'tcx>>>),
}
/// 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<ty::TraitRef<'tcx>>,
b: Rc<ty::TraitRef<'tcx>>)
a: Rc<ty::PolyTraitRef<'tcx>>,
b: Rc<ty::PolyTraitRef<'tcx>>)
-> 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<T>(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<Span>,
a: Ty<'tcx>,
modes: uint)
-> fres<Ty<'tcx>> {
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<ty::Region> {
let mut resolver = resolver(cx, modes, None);
resolver.resolve_region_chk(r)
}
trait then<'tcx> {
fn then<T, F>(&self, f: F) -> Result<T, ty::type_err<'tcx>> 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<ty::IntVid>,
@ -528,8 +510,8 @@ pub struct CombinedSnapshot {
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn skolemize<T:TypeFoldable<'tcx>>(&self, t: T) -> T {
t.fold_with(&mut self.skolemizer())
pub fn freshen<T:TypeFoldable<'tcx>>(&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<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce() -> Result<T, E>
{
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<T, E, F>(&self, f: F) -> Result<T, E> where
F: FnOnce() -> Result<T, E>
F: FnOnce(&CombinedSnapshot) -> Result<T, E>
{
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<R, F>(&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<ty::PolyTraitRef<'tcx>>,
b: Rc<ty::PolyTraitRef<'tcx>>)
-> 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<T>(&self,
value: &ty::Binder<T>,
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<T>(&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<ty::TraitRef<'tcx>>) -> 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<T:TypeFoldable<'tcx>>(&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<T:TypeFoldable<'tcx>>(&self, value: &T) -> fres<T> {
/*!
* 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>)
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
where T : HigherRankedFoldable<'tcx>
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
ty::replace_late_bound_regions(
self.tcx,

View file

@ -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<RegionVid>
pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot)
-> Vec<RegionVid>
{
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<Region> {
pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec<Region> {
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 => {

View file

@ -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 `<T0>` we may
// end up with something like `[<T1>]`. If the option
// `resolve_nested_tvar` is passed, we will then go and recursively
// resolve `<T1>`.
//
// 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};
use middle::ty_fold::{mod, TypeFoldable};
use util::ppaux::Repr;
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;
///////////////////////////////////////////////////////////////////////////
// OPPORTUNISTIC TYPE RESOLVER
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> {
/// 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<fixup_err>,
type_depth: uint,
}
pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>,
modes: uint,
_: Option<Span>)
-> 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)
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)
}
}
}
///////////////////////////////////////////////////////////////////////////
// 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<T>
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),
}
}
// 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<fixup_err>,
}
impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> {
self.infcx.tcx
}
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)
}
}
}
}
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<Ty<'tcx>> {
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<ty::Region> {
self.err = None;
let resolved = self.resolve_region(orig);
match self.err {
None => Ok(resolved),
Some(e) => Err(e)
}
}
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
}
}
}
}
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
}
}
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)
}
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) {
self.err = Some(unresolved_ty(vid));
}
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)
}
match r {
ty::ReInfer(ty::ReVar(rid)) => self.infcx.region_vars.resolve_var(rid),
_ => r,
}
}
}

View file

@ -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<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
where T : Combineable<'tcx>
{
self.higher_ranked_sub(a, b)
}
}

View file

@ -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<Ty<'tcx>> {
/*!
* 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<TypeVariableData<'tcx>,UndoEntry> for Delegate {

View file

@ -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);
}
}

View file

@ -1534,6 +1534,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
.unwrap()
.closure_type
.sig
.0
.output,
_ => ty::ty_fn_ret(fn_ty)
}

View file

@ -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);
})
}
}
});
}

View file

@ -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, &param_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

View file

@ -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<T:Clone>(x: &[T]) -> Vec<T> { ... }
//!
//! and then a call to that function:
//!
//! let v: Vec<int> = 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<T:Clone>(x: &[T]) -> Vec<T> {
//! 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<Target> {
//! 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<uint> for int { ... } // int -> uint
//! impl Convert<int> 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<uint> 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<T:Copy> Get for T {
//! fn get(&self) -> T { *self }
//! }
//!
//! impl<T:Get> Get for Box<T> {
//! fn get(&self) -> Box<T> { box get_it(&**self) }
//! }
//! ```
//!
//! What happens when we invoke `get_it(&box 1_u16)`, for example? In this
//! case, the `Self` type is `Box<u16>` -- 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<u16> : 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<X:A2+B> { ... }
//!
//! 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<U,T:Bar<U>> Foo for Vec<T> { ... }
//!
//! impl Bar<uint> for int { ... }
//!
//! After one shallow round of selection for an obligation like `Vec<int>
//! : 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<U>` 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<Y>`. 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<int> 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<T> Vec<T> {
//! fn foo(x: T)
//! where T : Foo
//! { ... }
//!
//! fn bar(x: T)
//! { ... }
//! }
//!
//! If there is an obligation `T : Foo`, or `int : Bar<T>`, 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<Self>;
//! fn load() -> Box<Self> {
//! 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<T> { ... }
//! pub trait Bar { ... }
//! impl<U,T:Bar> Foo<U> for T { ... } // Impl A
//! impl Foo<char> 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<T:Clone>(x: &[T]) -> Vec<T> { ... }
and then a call to that function:
let v: Vec<int> = 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<T:Clone>(x: &[T]) -> Vec<T> {
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<Target> {
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<uint> for int { ... } // int -> uint
impl Convert<int> 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<uint> 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<T:Copy> Get for T {
fn get(&self) -> T { *self }
}
impl<T:Get> Get for Box<T> {
fn get(&self) -> Box<T> { box get_it(&**self) }
}
```
What happens when we invoke `get_it(&box 1_u16)`, for example? In this
case, the `Self` type is `Box<u16>` -- 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<u16> : 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<X:A2+B> { ... }
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<U,T:Bar<U>> Foo for Vec<T> { ... }
impl Bar<uint> for int { ... }
After one shallow round of selection for an obligation like `Vec<int>
: 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<U>` 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<X> {
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<T>() 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<X> {
fn foo(&self, x: X) { }
}
trait Bar<X> {
fn bar(&self, x: X) { }
}
impl<X,F> Foo<X> for F
where F : Bar<X>
{
}
```
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<Y>`. 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<int> 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<T> Vec<T> {
fn foo(x: T)
where T : Foo
{ ... }
fn bar(x: T)
{ ... }
}
If there is an obligation `T : Foo`, or `int : Bar<T>`, 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<Self>;
fn load() -> Box<Self> {
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<T> { ... }
pub trait Bar { ... }
impl<U,T:Bar> Foo<U> for T { ... } // Impl A
impl Foo<char> 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.
*/

View file

@ -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<ty::TraitRef<'tcx>>,
trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
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
}
}
}
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`
true
}
ty::Predicate::TypeOutlives(t_a, r_b) => {
register_region_obligation(tcx, t_a, r_b, predicate.cause, region_obligations);
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(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>,
}
}

View file

@ -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<ty::TraitRef<'tcx>>>;
pub type TraitObligation<'tcx> = Obligation<'tcx, Rc<ty::PolyTraitRef<'tcx>>>;
/// 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<ty::TraitRef<'tcx>>, Rc<ty::TraitRef<'tcx>>, ty::type_err<'tcx>),
OutputTypeParameterMismatch(Rc<ty::PolyTraitRef<'tcx>>,
Rc<ty::PolyTraitRef<'tcx>>,
ty::type_err<'tcx>),
}
pub struct FulfillmentError<'tcx> {
@ -226,7 +228,7 @@ pub struct VtableBuiltinData<N> {
#[deriving(PartialEq,Eq,Clone)]
pub struct VtableParamData<'tcx> {
// In the above example, this would `Eq`
pub bound: Rc<ty::TraitRef<'tcx>>,
pub bound: Rc<ty::PolyTraitRef<'tcx>>,
}
/// 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<ty::TraitRef<'tcx>>> {
impl<'tcx> TraitObligation<'tcx> {
pub fn self_ty(&self) -> Ty<'tcx> {
self.trait_ref.self_ty()
}

View file

@ -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<ty::TraitRef<'tcx>>,
/// selection-context's freshener. Used to check for recursion.
fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
previous: Option<&'prev TraitObligationStack<'prev, 'tcx>>
}
#[deriving(Clone)]
pub struct SelectionCache<'tcx> {
hashmap: RefCell<HashMap<Rc<ty::TraitRef<'tcx>>,
hashmap: RefCell<HashMap<Rc<ty::PolyTraitRef<'tcx>>,
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<Box<List<T>>>` is `Send` if `Box<List<T>>` 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<ty::TraitRef<'tcx>>)
cache_fresh_trait_ref: &Rc<ty::PolyTraitRef<'tcx>>)
-> &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<ty::TraitRef<'tcx>>)
cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
-> Option<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 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<ty::TraitRef<'tcx>>,
cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
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<Rc<ty::TraitRef>> =
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<ty::PolyTraitRef<'tcx>>,
expected_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
-> 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<ty::TraitRef<'tcx>>)
-> 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<ty::TraitRef<'tcx>>)
-> Result<Substs<'tcx>, ()>
{
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<ty::TraitRef<'tcx>>)
fn match_where_clause(&mut self,
obligation: &TraitObligation<'tcx>,
where_clause_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
-> 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<char> for Elems<int>` using the following impl:
///
/// impl<T> Iterator<T> for Elems<T> { ... }
///
/// 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<ty::TraitRef<'tcx>>,
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<T> Iterator<T> for Vec<T> { ... }
///
/// and our obligation is `Iterator<Foo> for Vec<int>` (note the mismatch in the obligation
/// types). Up until this step, no error would be reported: the self type is `Vec<int>`, and
/// that matches `Vec<T>` 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<int> for Vec<int>`, and the
/// `obligation_trait_ref` would be `Iterator<Foo> for Vec<int>`.
///
/// 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<ty::TraitRef<'tcx>>,
expected_trait_ref: Rc<ty::TraitRef<'tcx>>)
-> 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<PredicateObligation<'tcx>>
{
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)
}

View file

@ -47,7 +47,7 @@ struct StackEntry<'tcx> {
pub fn elaborate_trait_ref<'cx, 'tcx>(
tcx: &'cx ty::ctxt<'tcx>,
trait_ref: Rc<ty::TraitRef<'tcx>>)
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
-> 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<ty::TraitRef<'tcx>>])
trait_refs: &[Rc<ty::PolyTraitRef<'tcx>>])
-> 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<ty::TraitRef<'tcx>>)
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
-> 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<ty::TraitRef<'tcx>>])
bounds: &[Rc<ty::PolyTraitRef<'tcx>>])
-> Supertraits<'cx, 'tcx>
{
let elaborator = elaborate_trait_refs(tcx, bounds);
Supertraits { elaborator: elaborator }
}
impl<'cx, 'tcx> Iterator<Rc<ty::TraitRef<'tcx>>> for Supertraits<'cx, 'tcx> {
fn next(&mut self) -> Option<Rc<ty::TraitRef<'tcx>>> {
impl<'cx, 'tcx> Iterator<Rc<ty::PolyTraitRef<'tcx>>> for Supertraits<'cx, 'tcx> {
fn next(&mut self) -> Option<Rc<ty::PolyTraitRef<'tcx>>> {
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<Rc<ty::TraitRef<'tcx>>, ErrorReported>
-> Result<Rc<ty::PolyTraitRef<'tcx>>, 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<PredicateObligation<'tcx>, 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<ty::TraitRef<'tcx>>,
mut test: F)
-> Option<VtableParamData<'tcx>> where
F: FnMut(ast::DefId) -> bool,
pub fn search_trait_and_supertraits_from_bound<'tcx,F>(tcx: &ty::ctxt<'tcx>,
caller_bound: Rc<ty::PolyTraitRef<'tcx>>,
mut test: F)
-> Option<VtableParamData<'tcx>>
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);
}

View file

@ -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<ty::TraitRef<'tcx>>,
// 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<NodeMap<Rc<ty::TraitRef<'tcx>>>>;
pub type ObjectCastMap<'tcx> = RefCell<NodeMap<Rc<ty::PolyTraitRef<'tcx>>>>;
/// 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<Ty<'tcx>>,
@ -955,6 +953,8 @@ pub struct FnSig<'tcx> {
pub variadic: bool
}
pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
#[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<TraitRef>, 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<ty::PolyTraitRef<'tcx>>
{
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,20 +1348,35 @@ 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<T> {
pub value: T
pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
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 input_types(&self) -> &[Ty<'tcx>] {
self.0.input_types()
}
}
pub fn bind<T>(value: T) -> Binder<T> {
Binder { value: value }
}
/// 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<TraitRef>`). Note that when we skolemize, instantiate,
/// erase, or otherwise "discharge" these bound reons, we change the
/// type from `Binder<T>` to just `T` (see
/// e.g. `liberate_late_bound_regions`).
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
pub struct Binder<T>(pub T);
#[deriving(Clone, PartialEq)]
pub enum IntVarValue {
@ -1416,7 +1446,7 @@ impl<'tcx> Copy for type_err<'tcx> {}
pub struct ParamBounds<'tcx> {
pub region_bounds: Vec<ty::Region>,
pub builtin_bounds: BuiltinBounds,
pub trait_bounds: Vec<Rc<TraitRef<'tcx>>>
pub trait_bounds: Vec<Rc<PolyTraitRef<'tcx>>>
}
/// 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<A,B,C>`. `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<TraitRef<'tcx>>),
Trait(Rc<PolyTraitRef<'tcx>>),
/// 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<EquatePredicate<'tcx>>;
#[deriving(Clone, PartialEq, Eq, Hash, Show)]
pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate<ty::Region, ty::Region>;
pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region>;
pub trait AsPredicate<'tcx> {
fn as_predicate(&self) -> Predicate<'tcx>;
}
impl<'tcx> AsPredicate<'tcx> for Rc<PolyTraitRef<'tcx>> {
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<Rc<TraitRef<'tcx>>> {
pub fn to_trait(&self) -> Option<Rc<PolyTraitRef<'tcx>>> {
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<TraitRef<'tcx>>])
traits: &[Rc<PolyTraitRef<'tcx>>])
-> 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<TraitRef<'tcx>>],
traits: &[Rc<PolyTraitRef<'tcx>>],
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<ast::DefId> {
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<ty::Predicate<'tcx>>
{
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 &region_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<TraitRef<'tcx>>],
bounds: &[Rc<PolyTraitRef<'tcx>>],
mut f: F)
-> bool where
F: FnMut(Rc<TraitRef<'tcx>>) -> bool,
F: FnMut(Rc<PolyTraitRef<'tcx>>) -> 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<ty::Region>
{
// 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<ty::Predicate<'tcx>>)
-> Vec<ty::Region>
{
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<FnSig<'tcx>>| {
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<ty::Region>,
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>)
-> 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<T>)
-> 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>)
-> 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>)
-> 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<T>,
mut mapf: F)
-> (HR, FnvHashMap<ty::BoundRegion, ty::Region>) where
HR : HigherRankedFoldable<'tcx>,
F: FnMut(BoundRegion, DebruijnIndex) -> ty::Region,
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
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<T> {
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<T:RegionEscape,U:RegionEscape> RegionEscape for OutlivesPredicate<T,U> {
fn has_regions_escaping_depth(&self, depth: uint) -> bool {
self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
}
}

View file

@ -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<T> {
impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
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<F:TypeFolder<'tcx>>(&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<T,U>
where T : TypeFoldable<'tcx>,
U : TypeFoldable<'tcx>,
{
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::OutlivesPredicate<T,U> {
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<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
}
impl<'tcx> HigherRankedFoldable<'tcx> for ty::FnSig<'tcx> {
fn fold_contents<F: TypeFolder<'tcx>>(&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<F: TypeFolder<'tcx>>(&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<T> {
fn fold_contents<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
ty::bind(self.value.fold_with(folder))
}
}
impl<'tcx, T:HigherRankedFoldable<'tcx>> HigherRankedFoldable<'tcx> for Rc<T> {
fn fold_contents<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Rc<T> {
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<F>(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<ty::Region>
where T : TypeFoldable<'tcx>
{
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.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>,
{
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)
}))
}

View file

@ -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<T, F>(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<ast::Ident>,
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::<Vec<_>>();
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<T>
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<T> {
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<K,V,H>
where K : Hash<S> + Eq + Repr<'tcx>,
V : Repr<'tcx>,
H : Hasher<S>
{
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
format!("HashMap({})",
self.iter()
.map(|(k,v)| format!("{} => {}", k.repr(tcx), v.repr(tcx)))
.collect::<Vec<String>>()
.connect(", "))
}
}
impl<'tcx, T, U> Repr<'tcx> for ty::OutlivesPredicate<T,U>
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<T,U>
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),
}
}
}

View file

@ -23,7 +23,7 @@ use self::UndoLog::*;
use std::mem;
#[deriving(PartialEq)]
enum UndoLog<T,U> {
pub enum UndoLog<T,U> {
/// Indicates where a snapshot started.
OpenSnapshot,
@ -113,6 +113,12 @@ impl<T,U,D:SnapshotVecDelegate<T,U>> SnapshotVec<T,U,D> {
Snapshot { length: length }
}
pub fn actions_since_snapshot(&self,
snapshot: &Snapshot)
-> &[UndoLog<T,U>] {
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);

View file

@ -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| {

View file

@ -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 {

View file

@ -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")
};

View file

@ -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);

View file

@ -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<ty::TraitRef<'tcx>>)
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
-> 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,

View file

@ -99,7 +99,7 @@ pub struct LocalCrateContext<'tcx> {
monomorphized: RefCell<FnvHashMap<MonoId<'tcx>, ValueRef>>,
monomorphizing: RefCell<DefIdMap<uint>>,
/// Cache generated vtables
vtables: RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::TraitRef<'tcx>>), ValueRef>>,
vtables: RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::PolyTraitRef<'tcx>>), ValueRef>>,
/// Cache of constant strings,
const_cstr_cache: RefCell<FnvHashMap<InternedString, ValueRef>>,
@ -150,7 +150,7 @@ pub struct LocalCrateContext<'tcx> {
/// contexts around the same size.
n_llvm_insns: Cell<uint>,
trait_cache: RefCell<FnvHashMap<Rc<ty::TraitRef<'tcx>>,
trait_cache: RefCell<FnvHashMap<Rc<ty::PolyTraitRef<'tcx>>,
traits::Vtable<'tcx, ()>>>,
}
@ -601,7 +601,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local.monomorphizing
}
pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::TraitRef<'tcx>>),
pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::PolyTraitRef<'tcx>>),
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<FnvHashMap<Rc<ty::TraitRef<'tcx>>,
pub fn trait_cache(&self) -> &RefCell<FnvHashMap<Rc<ty::PolyTraitRef<'tcx>>,
traits::Vtable<'tcx, ()>>> {
&self.local.trait_cache
}

View file

@ -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 &parameter_type in sig.inputs.iter() {
for &parameter_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 &parameter_type in sig.inputs.iter() {
for &parameter_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<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
let mut signature_metadata: Vec<DIType> = 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 &parameter_type in sig.inputs.iter() {
if sig.0.inputs.len() > 0 {
for &parameter_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 &parameter_type in sig.inputs.iter() {
if sig.0.inputs.len() > 0 {
for &parameter_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(" -> ");

View file

@ -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,

View file

@ -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)

View file

@ -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())

View file

@ -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);

View file

@ -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<ty::TraitRef<'tcx>>)
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
-> 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<ty::TraitRef<'tcx>>,
trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
dest: expr::Dest)
-> Block<'blk, 'tcx> {
let mut bcx = bcx;

View file

@ -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)

View file

@ -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<Ty<'tcx>>,
allow_eq: AllowEqConstraints)
-> Rc<ty::PolyTraitRef<'tcx>>
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<ty::TraitRef<'tcx>, ErrorReported>
-> Result<ty::PolyTraitRef<'tcx>, 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<ty::Region>
{
@ -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
{

View file

@ -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<SomeTrait>", 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<SomeTrait>", an error.
span_err!(tcx.sess, span, E0033,
"type `{}` cannot be dereferenced",
fcx.infcx().ty_to_string(expected));
false
}
_ => true
})
} else {
true
}
}

View file

@ -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 {

View file

@ -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) => {

View file

@ -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<ty::TraitRef<'tcx>>,
source_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
target_trait_def_id: ast::DefId)
-> Rc<ty::TraitRef<'tcx>>
-> Rc<ty::PolyTraitRef<'tcx>>
{
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<T>(&self, value: &T) -> T
where T : HigherRankedFoldable<'tcx>
fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T
where T : TypeFoldable<'tcx> + Repr<'tcx>
{
self.infcx().replace_late_bound_regions_with_fresh_var(
self.span, infer::FnCall, value).0

View file

@ -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(),
});

View file

@ -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<ty::TraitRef<'tcx>>,
subst::Substs<'tcx>, MethodIndex),
UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
WhereClauseCandidate(Rc<ty::TraitRef<'tcx>>, MethodIndex),
WhereClauseCandidate(Rc<ty::PolyTraitRef<'tcx>>, 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<ty::TraitRef<'tcx>>, MethodIndex),
WhereClausePick(/* Trait */ Rc<ty::PolyTraitRef<'tcx>>, MethodIndex),
}
pub type PickResult<'tcx> = Result<Pick<'tcx>, 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<ty::TraitRef<'tcx>>],
bounds: &[Rc<ty::PolyTraitRef<'tcx>>],
num_includes_types: bool,
mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>,
tr: Rc<ty::TraitRef<'tcx>>,
tr: Rc<ty::PolyTraitRef<'tcx>>,
m: Rc<ty::Method<'tcx>>,
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<ty::Method<'tcx>>,
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<T>(&self, value: &T) -> T
where T : HigherRankedFoldable<'tcx>
fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> 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<ty::TraitRef<'tcx>>,
trait_ref: &ty::PolyTraitRef<'tcx>,
subtrait: Rc<ty::PolyTraitRef<'tcx>>,
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),

View file

@ -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<ty::TraitRef<'tcx>>) {
trait_ref: Rc<ty::PolyTraitRef<'tcx>>) {
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);

View file

@ -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 `&<R0>.int` and then `*b` will require that `<R0>` be bigger than the let and
/// the `*b` expression, so we will effectively resolve `<R0>` 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);

View file

@ -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<ty::TraitRef<'tcx>>
-> Rc<ty::PolyTraitRef<'tcx>>
{
// 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!(

View file

@ -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));
}

View file

@ -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<T:ResolveIn<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
t.resolve_in(&mut Resolver::new(self.fcx, reason))
fn resolve<T:TypeFoldable<'tcx>>(&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);

View file

@ -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<Ty<'tcx>> {
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<DefId> {
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<DefId> {
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, &param_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, &param_env) {
Ok(()) => {}

View file

@ -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,

View file

@ -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,
&param_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<Rc<ty::TraitRef>> =
let trait_bounds: Vec<Rc<ty::PolyTraitRef>> =
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<ty::Region> =
@ -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;
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 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;
// 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
}
})
}
}

View file

@ -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,

View file

@ -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);
}
}

View file

@ -575,6 +575,12 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
}
}
impl<'tcx> Clean<TyParamBound> for ty::PolyTraitRef<'tcx> {
fn clean(&self, cx: &DocContext) -> TyParamBound {
self.0.clean(cx)
}
}
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
fn clean(&self, cx: &DocContext) -> TyParamBound {
let tcx = match cx.tcx_opt() {
@ -913,7 +919,7 @@ impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
}
}
impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig<'tcx>) {
impl<'a, 'tcx> Clean<FnDecl> 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<FnDecl> 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<Item> 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<Item> 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<Type> 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<String> = fqn.into_iter().map(|i| {
i.to_string()

View file

@ -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);
}
}
}

View file

@ -14,3 +14,6 @@ fn main() {
let int x = 5;
match x;
}
fn main() {
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<X> {
fn foo(&self, x: X) { }
}
fn want_foo2<T>()
where T : for<'a,'b> Foo<(&'a int, &'b int)>
{
}
fn want_foo1<T>()
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::<SomeStruct>(); } // OK -- foo wants just one region
fn b() { want_foo2::<SomeStruct>(); } //~ ERROR not implemented
fn main() { }

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test a case where you have an impl of `Foo<X>` for all `X` that
// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730.
trait Foo<X> {
fn foo(&self, x: X) { }
}
fn want_hrtb<T>()
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::<AnyInt>()
}
// StaticInt only implements Foo<&'static int>, so it is an error.
struct StaticInt;
impl Foo<&'static int> for StaticInt { }
fn give_static() {
want_hrtb::<StaticInt>() //~ ERROR `for<'a> Foo<&'a int>` is not implemented
}
fn main() { }

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test a case where you have an impl of `Foo<X>` for all `X` that
// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730.
trait Foo<X> {
fn foo(&mut self, x: X) { }
}
trait Bar<X> {
fn bar(&mut self, x: X) { }
}
impl<'a,X,F> Foo<X> for &'a mut F
where F : Foo<X> + Bar<X>
{
}
impl<'a,X,F> Bar<X> for &'a mut F
where F : Bar<X>
{
}
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<T>(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<T>(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() { }

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<X> {
fn foo(&self, x: X) { }
}
fn want_foo<T>()
where T : for<'a> Foo<&'a int>
{
}
///////////////////////////////////////////////////////////////////////////
// Expressed as a where clause
struct SomeStruct<X> {
x: X
}
impl<'a,X> Foo<&'a int> for SomeStruct<X>
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::<SomeStruct<uint>>();
//~^ ERROR requirement `for<'a> uint : 'a` is not satisfied
}
///////////////////////////////////////////////////////////////////////////
// Expressed as shorthand
struct AnotherStruct<X> {
x: X
}
impl<'a,X:'a> Foo<&'a int> for AnotherStruct<X>
{
}
fn two() {
want_foo::<AnotherStruct<uint>>();
//~^ ERROR requirement `for<'a> uint : 'a` is not satisfied
}
fn main() { }

View file

@ -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`
}

View file

@ -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
()
;
}

View file

@ -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() {}

View file

@ -17,4 +17,5 @@
fn main() {
(return)((),());
//~^ ERROR the type of this value must be known
//~| ERROR this function takes 1 parameter
}

View file

@ -21,10 +21,15 @@ impl<T:Copy> Foo for T {
fn take_param<T:Foo>(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() { }

View file

@ -20,9 +20,16 @@ fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
fn call_it_once<F:FnOnce(&int)->int>(_: 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() { }

View file

@ -20,9 +20,17 @@ fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
fn call_it_once<F:FnOnce(&int)->int>(_: 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() { }

View file

@ -21,9 +21,16 @@ fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
fn call_it_once<F:FnOnce(&int)->int>(_: 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() { }

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<T> Copy for Foo<T>` 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<T> { x: T }
type Ty<'tcx> = &'tcx TyS<'tcx>;
enum TyS<'tcx> {
Boop(marker::InvariantLifetime<'tcx>)
}
enum Bar<'tcx> {
Baz(Foo<Ty<'tcx>>)
}
impl<'tcx> Copy for Bar<'tcx> { }
fn main() { }

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub type Foo = fn(&int) -> ();
#[deriving(Clone)]
enum Baz { Bar(Foo) }
fn main() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[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');
}