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:
commit
bd90b936d7
84 changed files with 3195 additions and 2414 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(|®ion_vid| {
|
||||
let r = ty::ReInfer(ty::ReVar(region_vid));
|
||||
!escaping_region_vars.contains(&r)
|
||||
});
|
||||
|
||||
debug!("region_vars_confined_to_snapshot: region_vars={} escaping_types={}",
|
||||
region_vars.repr(self.tcx),
|
||||
escaping_types.repr(self.tcx));
|
||||
|
||||
region_vars
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
binder: &ty::Binder<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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1534,6 +1534,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
.unwrap()
|
||||
.closure_type
|
||||
.sig
|
||||
.0
|
||||
.output,
|
||||
_ => ty::ty_fn_ret(fn_ty)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ use super::util;
|
|||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::infer::{mod, InferCtxt};
|
||||
use middle::infer::InferCtxt;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use util::ppaux::Repr;
|
||||
|
|
@ -37,18 +38,14 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
|
|||
let impl1_substs =
|
||||
util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id);
|
||||
let impl1_trait_ref =
|
||||
ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()
|
||||
.subst(infcx.tcx, &impl1_substs);
|
||||
let impl1_trait_ref =
|
||||
infcx.replace_late_bound_regions_with_fresh_var(DUMMY_SP,
|
||||
infer::FnCall,
|
||||
&impl1_trait_ref).0;
|
||||
(*ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()).subst(infcx.tcx, &impl1_substs);
|
||||
|
||||
// Determine whether `impl2` can provide an implementation for those
|
||||
// same types.
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx);
|
||||
let obligation = Obligation::new(ObligationCause::dummy(), impl1_trait_ref);
|
||||
let obligation = Obligation::new(ObligationCause::dummy(),
|
||||
Rc::new(ty::Binder(impl1_trait_ref)));
|
||||
debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx));
|
||||
selcx.evaluate_impl(impl2_def_id, &obligation)
|
||||
}
|
||||
|
|
@ -143,7 +140,7 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
}
|
||||
|
||||
ty::ty_trait(ref tt) => {
|
||||
tt.principal.def_id.krate == ast::LOCAL_CRATE
|
||||
tt.principal.def_id().krate == ast::LOCAL_CRATE
|
||||
}
|
||||
|
||||
// Type parameters may be bound to types that are not local to
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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>,
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ®ion_bound in bounds.region_bounds.iter() {
|
||||
vec.push(Predicate::TypeOutlives(param_ty, region_bound));
|
||||
// account for the binder being introduced below; no need to shift `param_ty`
|
||||
// because, at present at least, it can only refer to early-bound regions
|
||||
let region_bound = ty_fold::shift_region(region_bound, 1);
|
||||
vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).as_predicate());
|
||||
}
|
||||
|
||||
for bound_trait_ref in bounds.trait_bounds.iter() {
|
||||
vec.push(Predicate::Trait((*bound_trait_ref).clone()));
|
||||
vec.push(bound_trait_ref.as_predicate());
|
||||
}
|
||||
|
||||
vec
|
||||
|
|
@ -5483,18 +5551,6 @@ pub fn normalize_ty<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
|||
subst::Substs { regions: subst::ErasedRegions,
|
||||
types: substs.types.fold_with(self) }
|
||||
}
|
||||
|
||||
fn fold_fn_sig(&mut self,
|
||||
sig: &ty::FnSig<'tcx>)
|
||||
-> ty::FnSig<'tcx> {
|
||||
// The binder-id is only relevant to bound regions, which
|
||||
// are erased at trans time.
|
||||
ty::FnSig {
|
||||
inputs: sig.inputs.fold_with(self),
|
||||
output: sig.output.fold_with(self),
|
||||
variadic: sig.variadic,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5545,10 +5601,10 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint {
|
|||
// relation on the supertraits from each bounded trait's constraint
|
||||
// list.
|
||||
pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>,
|
||||
bounds: &[Rc<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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -429,8 +429,8 @@ impl<'tcx> TypeMap<'tcx> {
|
|||
|
||||
from_def_id_and_substs(self,
|
||||
cx,
|
||||
trait_data.principal.def_id,
|
||||
&trait_data.principal.substs,
|
||||
trait_data.principal.def_id(),
|
||||
trait_data.principal.substs(),
|
||||
&mut unique_type_id);
|
||||
},
|
||||
ty::ty_bare_fn(ty::BareFnTy{ unsafety, abi, ref sig } ) => {
|
||||
|
|
@ -442,7 +442,7 @@ impl<'tcx> TypeMap<'tcx> {
|
|||
|
||||
unique_type_id.push_str(" fn(");
|
||||
|
||||
for ¶meter_type in sig.inputs.iter() {
|
||||
for ¶meter_type in sig.0.inputs.iter() {
|
||||
let parameter_type_id =
|
||||
self.get_unique_type_id_of_type(cx, parameter_type);
|
||||
let parameter_type_id =
|
||||
|
|
@ -451,12 +451,12 @@ impl<'tcx> TypeMap<'tcx> {
|
|||
unique_type_id.push(',');
|
||||
}
|
||||
|
||||
if sig.variadic {
|
||||
if sig.0.variadic {
|
||||
unique_type_id.push_str("...");
|
||||
}
|
||||
|
||||
unique_type_id.push_str(")->");
|
||||
match sig.output {
|
||||
match sig.0.output {
|
||||
ty::FnConverging(ret_ty) => {
|
||||
let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty);
|
||||
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
|
||||
|
|
@ -575,7 +575,7 @@ impl<'tcx> TypeMap<'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
for ¶meter_type in sig.inputs.iter() {
|
||||
for ¶meter_type in sig.0.inputs.iter() {
|
||||
let parameter_type_id =
|
||||
self.get_unique_type_id_of_type(cx, parameter_type);
|
||||
let parameter_type_id =
|
||||
|
|
@ -584,13 +584,13 @@ impl<'tcx> TypeMap<'tcx> {
|
|||
unique_type_id.push(',');
|
||||
}
|
||||
|
||||
if sig.variadic {
|
||||
if sig.0.variadic {
|
||||
unique_type_id.push_str("...");
|
||||
}
|
||||
|
||||
unique_type_id.push_str("|->");
|
||||
|
||||
match sig.output {
|
||||
match sig.0.output {
|
||||
ty::FnConverging(ret_ty) => {
|
||||
let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty);
|
||||
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
|
||||
|
|
@ -2787,13 +2787,13 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
|
||||
fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
unique_type_id: UniqueTypeId,
|
||||
signature: &ty::FnSig<'tcx>,
|
||||
signature: &ty::PolyFnSig<'tcx>,
|
||||
span: Span)
|
||||
-> MetadataCreationResult {
|
||||
let mut signature_metadata: Vec<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 ¶meter_type in sig.inputs.iter() {
|
||||
if sig.0.inputs.len() > 0 {
|
||||
for ¶meter_type in sig.0.inputs.iter() {
|
||||
push_debuginfo_type_name(cx, parameter_type, true, output);
|
||||
output.push_str(", ");
|
||||
}
|
||||
|
|
@ -3790,8 +3790,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
output.pop();
|
||||
}
|
||||
|
||||
if sig.variadic {
|
||||
if sig.inputs.len() > 0 {
|
||||
if sig.0.variadic {
|
||||
if sig.0.inputs.len() > 0 {
|
||||
output.push_str(", ...");
|
||||
} else {
|
||||
output.push_str("...");
|
||||
|
|
@ -3800,7 +3800,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
|
||||
output.push(')');
|
||||
|
||||
match sig.output {
|
||||
match sig.0.output {
|
||||
ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {}
|
||||
ty::FnConverging(result_type) => {
|
||||
output.push_str(" -> ");
|
||||
|
|
@ -3841,8 +3841,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
};
|
||||
|
||||
if sig.inputs.len() > 0 {
|
||||
for ¶meter_type in sig.inputs.iter() {
|
||||
if sig.0.inputs.len() > 0 {
|
||||
for ¶meter_type in sig.0.inputs.iter() {
|
||||
push_debuginfo_type_name(cx, parameter_type, true, output);
|
||||
output.push_str(", ");
|
||||
}
|
||||
|
|
@ -3850,8 +3850,8 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
output.pop();
|
||||
}
|
||||
|
||||
if sig.variadic {
|
||||
if sig.inputs.len() > 0 {
|
||||
if sig.0.variadic {
|
||||
if sig.0.inputs.len() > 0 {
|
||||
output.push_str(", ...");
|
||||
} else {
|
||||
output.push_str("...");
|
||||
|
|
@ -3860,7 +3860,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
|
||||
output.push(param_list_closing_char);
|
||||
|
||||
match sig.output {
|
||||
match sig.0.output {
|
||||
ty::FnConverging(result_type) if ty::type_is_nil(result_type) => {}
|
||||
ty::FnConverging(result_type) => {
|
||||
output.push_str(" -> ");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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, ¶m_env.free_substs);
|
||||
assert!(!self_type.has_escaping_regions());
|
||||
|
||||
debug!("check_implementations_of_copy: self_type={} (free)",
|
||||
self_type.repr(tcx));
|
||||
|
||||
match ty::can_type_implement_copy(tcx, self_type, ¶m_env) {
|
||||
Ok(()) => {}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -42,10 +42,9 @@ use middle::region;
|
|||
use middle::resolve_lifetime;
|
||||
use middle::subst;
|
||||
use middle::subst::{Substs};
|
||||
use middle::ty::{ImplContainer, ImplOrTraitItemContainer, TraitContainer};
|
||||
use middle::ty::{Polytype};
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
|
||||
use middle::ty::{mod, RegionEscape, Ty, Polytype};
|
||||
use middle::ty_fold::{mod, TypeFolder, TypeFoldable};
|
||||
use middle::infer;
|
||||
use rscope::*;
|
||||
use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx};
|
||||
|
|
@ -227,7 +226,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
|
||||
ast::StructVariantKind(ref struct_def) => {
|
||||
let pty = Polytype {
|
||||
generics: ty_generics_for_type(
|
||||
generics: ty_generics_for_type_or_impl(
|
||||
ccx,
|
||||
generics,
|
||||
DontCreateTypeParametersForAssociatedTypes),
|
||||
|
|
@ -240,7 +239,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
};
|
||||
|
||||
let pty = Polytype {
|
||||
generics: ty_generics_for_type(
|
||||
generics: ty_generics_for_type_or_impl(
|
||||
ccx,
|
||||
generics,
|
||||
DontCreateTypeParametersForAssociatedTypes),
|
||||
|
|
@ -652,7 +651,7 @@ fn is_associated_type_valid_for_param(ty: Ty,
|
|||
if let ty::ty_param(param_ty) = ty.sty {
|
||||
let type_parameter = generics.types.get(param_ty.space, param_ty.idx);
|
||||
for trait_bound in type_parameter.bounds.trait_bounds.iter() {
|
||||
if trait_bound.def_id == trait_id {
|
||||
if trait_bound.def_id() == trait_id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -1051,7 +1050,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
ref selfty,
|
||||
ref impl_items) => {
|
||||
// Create generics from the generics specified in the impl head.
|
||||
let ty_generics = ty_generics_for_impl(
|
||||
let ty_generics = ty_generics_for_type_or_impl(
|
||||
ccx,
|
||||
generics,
|
||||
CreateTypeParametersForAssociatedTypes);
|
||||
|
|
@ -1483,7 +1482,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
|
|||
let pty = {
|
||||
let ty = ccx.to_ty(&ExplicitRscope, &**t);
|
||||
Polytype {
|
||||
generics: ty_generics_for_type(
|
||||
generics: ty_generics_for_type_or_impl(
|
||||
ccx,
|
||||
generics,
|
||||
DontCreateTypeParametersForAssociatedTypes),
|
||||
|
|
@ -1496,7 +1495,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
|
|||
}
|
||||
ast::ItemEnum(_, ref generics) => {
|
||||
// Create a new generic polytype.
|
||||
let ty_generics = ty_generics_for_type(
|
||||
let ty_generics = ty_generics_for_type_or_impl(
|
||||
ccx,
|
||||
generics,
|
||||
DontCreateTypeParametersForAssociatedTypes);
|
||||
|
|
@ -1514,7 +1513,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
|
|||
tcx.sess.span_bug(it.span, "invoked ty_of_item on trait");
|
||||
}
|
||||
ast::ItemStruct(_, ref generics) => {
|
||||
let ty_generics = ty_generics_for_type(
|
||||
let ty_generics = ty_generics_for_type_or_impl(
|
||||
ccx,
|
||||
generics,
|
||||
DontCreateTypeParametersForAssociatedTypes);
|
||||
|
|
@ -1581,11 +1580,11 @@ fn ty_of_trait_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn ty_generics_for_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
generics: &ast::Generics,
|
||||
create_type_parameters_for_associated_types:
|
||||
CreateTypeParametersForAssociatedTypesFlag)
|
||||
-> ty::Generics<'tcx> {
|
||||
fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
generics: &ast::Generics,
|
||||
create_type_parameters_for_associated_types:
|
||||
CreateTypeParametersForAssociatedTypesFlag)
|
||||
-> ty::Generics<'tcx> {
|
||||
ty_generics(ccx,
|
||||
subst::TypeSpace,
|
||||
generics.lifetimes.as_slice(),
|
||||
|
|
@ -1638,8 +1637,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
let param_id = trait_id;
|
||||
|
||||
let self_trait_ref =
|
||||
Rc::new(ty::TraitRef { def_id: local_def(trait_id),
|
||||
substs: (*substs).clone() });
|
||||
Rc::new(ty::Binder(ty::TraitRef { def_id: local_def(trait_id),
|
||||
substs: (*substs).clone() }));
|
||||
|
||||
let def = ty::TypeParameterDef {
|
||||
space: subst::SelfSpace,
|
||||
|
|
@ -1665,24 +1664,6 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
generics
|
||||
}
|
||||
|
||||
fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
generics: &ast::Generics,
|
||||
create_type_parameters_for_associated_types:
|
||||
CreateTypeParametersForAssociatedTypesFlag)
|
||||
-> ty::Generics<'tcx>
|
||||
{
|
||||
let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
|
||||
debug!("ty_generics_for_impl: early_lifetimes={}",
|
||||
early_lifetimes);
|
||||
ty_generics(ccx,
|
||||
subst::TypeSpace,
|
||||
early_lifetimes.as_slice(),
|
||||
generics.ty_params.as_slice(),
|
||||
ty::Generics::empty(),
|
||||
&generics.where_clause,
|
||||
create_type_parameters_for_associated_types)
|
||||
}
|
||||
|
||||
fn ty_generics_for_fn_or_method<'tcx,AC>(
|
||||
this: &AC,
|
||||
generics: &ast::Generics,
|
||||
|
|
@ -1920,8 +1901,12 @@ fn ty_generics<'tcx,AC>(this: &AC,
|
|||
for region_param_def in result.regions.get_slice(space).iter() {
|
||||
let region = region_param_def.to_early_bound_region();
|
||||
for &bound_region in region_param_def.bounds.iter() {
|
||||
result.predicates.push(space, ty::Predicate::RegionOutlives(region,
|
||||
bound_region));
|
||||
// account for new binder introduced in the predicate below; no need
|
||||
// to shift `region` because it is never a late-bound region
|
||||
let bound_region = ty_fold::shift_region(bound_region, 1);
|
||||
result.predicates.push(
|
||||
space,
|
||||
ty::Binder(ty::OutlivesPredicate(region, bound_region)).as_predicate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2015,7 +2000,7 @@ fn compute_bounds<'tcx,AC>(this: &AC,
|
|||
¶m_bounds,
|
||||
span);
|
||||
|
||||
param_bounds.trait_bounds.sort_by(|a,b| a.def_id.cmp(&b.def_id));
|
||||
param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
|
||||
|
||||
param_bounds
|
||||
}
|
||||
|
|
@ -2031,13 +2016,13 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
tcx,
|
||||
param_bounds.trait_bounds.as_slice(),
|
||||
|trait_ref| {
|
||||
let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
|
||||
let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id());
|
||||
if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) {
|
||||
span_err!(tcx.sess, span, E0129,
|
||||
"incompatible bounds on type parameter `{}`, \
|
||||
bound `{}` does not allow unsized type",
|
||||
name_of_bounded_thing.user_string(tcx),
|
||||
ppaux::trait_ref_to_string(tcx, &*trait_ref));
|
||||
trait_ref.user_string(tcx));
|
||||
}
|
||||
true
|
||||
});
|
||||
|
|
@ -2057,14 +2042,14 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
|
|||
trait_bounds,
|
||||
region_bounds } =
|
||||
astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice());
|
||||
let trait_bounds: Vec<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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,3 +14,6 @@ fn main() {
|
|||
let int x = 5;
|
||||
match x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
|
|||
40
src/test/compile-fail/hrtb-conflate-regions.rs
Normal file
40
src/test/compile-fail/hrtb-conflate-regions.rs
Normal 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() { }
|
||||
37
src/test/compile-fail/hrtb-just-for-static.rs
Normal file
37
src/test/compile-fail/hrtb-just-for-static.rs
Normal 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() { }
|
||||
66
src/test/compile-fail/hrtb-perfect-forwarding.rs
Normal file
66
src/test/compile-fail/hrtb-perfect-forwarding.rs
Normal 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() { }
|
||||
59
src/test/compile-fail/hrtb-type-outlives.rs
Normal file
59
src/test/compile-fail/hrtb-type-outlives.rs
Normal 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() { }
|
||||
|
|
@ -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`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
()
|
||||
;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -17,4 +17,5 @@
|
|||
fn main() {
|
||||
(return)((),());
|
||||
//~^ ERROR the type of this value must be known
|
||||
//~| ERROR this function takes 1 parameter
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
|
||||
|
|
|
|||
|
|
@ -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() { }
|
||||
|
|
|
|||
38
src/test/run-pass/hrtb-opt-in-copy.rs
Normal file
38
src/test/run-pass/hrtb-opt-in-copy.rs
Normal 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() { }
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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');
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue