auto merge of #20307 : nikomatsakis/rust/assoc-types-normalization-extend-bound, r=nrc
Rewrite associated types to use projection rather than dummy type parameters. This closes almost every (major) open issue, but I'm holding off on that until the code has landed and baked a bit. Probably it should have more tests, as well, but I wanted to get this landed as fast as possible so that we can collaborate on improving it. The commit history is a little messy, particularly the merge commit at the end. If I get some time, I might just "reset" to the beginning and try to carve up the final state into logical pieces. Let me know if it seems hard to follow. By far the most crucial commit is "Implement associated type projection and normalization." r? @nick29581
This commit is contained in:
commit
84f5ad8679
129 changed files with 5537 additions and 3126 deletions
|
|
@ -256,3 +256,6 @@ pub const tag_predicate_space: uint = 0xa9;
|
|||
pub const tag_predicate_data: uint = 0xb0;
|
||||
|
||||
pub const tag_unsafety: uint = 0xb1;
|
||||
|
||||
pub const tag_associated_type_names: uint = 0xb2;
|
||||
pub const tag_associated_type_name: uint = 0xb3;
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: ast::DefId) -> HashM
|
|||
|
||||
pub fn get_type<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
def: ast::DefId)
|
||||
-> ty::Polytype<'tcx> {
|
||||
-> ty::TypeScheme<'tcx> {
|
||||
let cstore = &tcx.sess.cstore;
|
||||
let cdata = cstore.get_crate_data(def.krate);
|
||||
decoder::get_type(&*cdata, def.node, tcx)
|
||||
|
|
@ -239,7 +239,7 @@ pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::TraitDe
|
|||
}
|
||||
|
||||
pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
|
||||
def: ast::DefId) -> ty::Polytype<'tcx> {
|
||||
def: ast::DefId) -> ty::TypeScheme<'tcx> {
|
||||
let cstore = &tcx.sess.cstore;
|
||||
let cdata = cstore.get_crate_data(class_id.krate);
|
||||
let all_items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_items);
|
||||
|
|
@ -257,7 +257,7 @@ pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
|
|||
def)).to_string()
|
||||
});
|
||||
let ty = decoder::item_type(def, the_field, tcx, &*cdata);
|
||||
ty::Polytype {
|
||||
ty::TypeScheme {
|
||||
generics: ty::Generics::empty(),
|
||||
ty: ty,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,14 +172,15 @@ fn item_visibility(item: rbml::Doc) -> ast::Visibility {
|
|||
}
|
||||
|
||||
fn item_sort(item: rbml::Doc) -> char {
|
||||
// NB(pcwalton): The default of 'r' here is relied upon in
|
||||
// `is_associated_type` below.
|
||||
let mut ret = 'r';
|
||||
let mut ret = None;
|
||||
reader::tagged_docs(item, tag_item_trait_item_sort, |doc| {
|
||||
ret = doc.as_str_slice().as_bytes()[0] as char;
|
||||
ret = Some(doc.as_str_slice().as_bytes()[0] as char);
|
||||
false
|
||||
});
|
||||
ret
|
||||
match ret {
|
||||
Some(r) => r,
|
||||
None => panic!("No item_sort found")
|
||||
}
|
||||
}
|
||||
|
||||
fn item_symbol(item: rbml::Doc) -> String {
|
||||
|
|
@ -245,13 +246,13 @@ pub fn item_type<'tcx>(_item_id: ast::DefId, item: rbml::Doc,
|
|||
}
|
||||
|
||||
fn doc_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
|
||||
-> ty::TraitRef<'tcx> {
|
||||
-> Rc<ty::TraitRef<'tcx>> {
|
||||
parse_trait_ref_data(doc.data, cdata.cnum, doc.start, tcx,
|
||||
|_, did| translate_def_id(cdata, did))
|
||||
}
|
||||
|
||||
fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
|
||||
-> ty::TraitRef<'tcx> {
|
||||
-> Rc<ty::TraitRef<'tcx>> {
|
||||
let tp = reader::get_doc(doc, tag_item_trait_ref);
|
||||
doc_trait_ref(tp, tcx, cdata)
|
||||
}
|
||||
|
|
@ -369,6 +370,17 @@ fn parse_unsafety(item_doc: rbml::Doc) -> ast::Unsafety {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
|
||||
let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
|
||||
let mut names = Vec::new();
|
||||
reader::tagged_docs(names_doc, tag_associated_type_name, |name_doc| {
|
||||
let name = token::intern(name_doc.as_str_slice());
|
||||
names.push(name);
|
||||
true
|
||||
});
|
||||
names
|
||||
}
|
||||
|
||||
pub fn get_trait_def<'tcx>(cdata: Cmd,
|
||||
item_id: ast::NodeId,
|
||||
tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx>
|
||||
|
|
@ -377,17 +389,19 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
|
|||
let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
|
||||
let bounds = trait_def_bounds(item_doc, tcx, cdata);
|
||||
let unsafety = parse_unsafety(item_doc);
|
||||
let associated_type_names = parse_associated_type_names(item_doc);
|
||||
|
||||
ty::TraitDef {
|
||||
unsafety: unsafety,
|
||||
generics: generics,
|
||||
bounds: bounds,
|
||||
trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata))
|
||||
trait_ref: item_trait_ref(item_doc, tcx, cdata),
|
||||
associated_type_names: associated_type_names,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
|
||||
-> ty::Polytype<'tcx> {
|
||||
-> ty::TypeScheme<'tcx> {
|
||||
|
||||
let item = lookup_item(id, cdata.data());
|
||||
|
||||
|
|
@ -396,7 +410,7 @@ pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
|
|||
|
||||
let generics = doc_generics(item, tcx, cdata, tag_item_generics);
|
||||
|
||||
ty::Polytype {
|
||||
ty::TypeScheme {
|
||||
generics: generics,
|
||||
ty: t
|
||||
}
|
||||
|
|
@ -428,7 +442,7 @@ pub fn get_impl_trait<'tcx>(cdata: Cmd,
|
|||
{
|
||||
let item_doc = lookup_item(id, cdata.data());
|
||||
reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| {
|
||||
Rc::new(doc_trait_ref(tp, tcx, cdata))
|
||||
doc_trait_ref(tp, tcx, cdata)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -924,7 +938,7 @@ pub fn get_supertraits<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
|
|||
// FIXME(#8559): The builtin bounds shouldn't be encoded in the first place.
|
||||
let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
|
||||
if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_none() {
|
||||
results.push(Rc::new(trait_ref));
|
||||
results.push(trait_ref);
|
||||
}
|
||||
true
|
||||
});
|
||||
|
|
@ -1353,7 +1367,7 @@ pub fn get_dylib_dependency_formats(cdata: Cmd)
|
|||
if spec.len() == 0 { continue }
|
||||
let cnum = spec.split(':').nth(0).unwrap();
|
||||
let link = spec.split(':').nth(1).unwrap();
|
||||
let cnum = cnum.parse().unwrap();
|
||||
let cnum: ast::CrateNum = cnum.parse().unwrap();
|
||||
let cnum = match cdata.cnum_map.get(&cnum) {
|
||||
Some(&n) => n,
|
||||
None => panic!("didn't find a crate in the cnum_map")
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ fn encode_item_variances(rbml_w: &mut Encoder,
|
|||
|
||||
fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
|
||||
ecx: &EncodeContext<'a, 'tcx>,
|
||||
pty: &ty::Polytype<'tcx>) {
|
||||
pty: &ty::TypeScheme<'tcx>) {
|
||||
encode_generics(rbml_w, ecx, &pty.generics, tag_item_generics);
|
||||
encode_type(ecx, rbml_w, pty.ty);
|
||||
}
|
||||
|
|
@ -898,7 +898,10 @@ fn encode_info_for_associated_type(ecx: &EncodeContext,
|
|||
encode_visibility(rbml_w, associated_type.vis);
|
||||
encode_family(rbml_w, 'y');
|
||||
encode_parent_item(rbml_w, local_def(parent_id));
|
||||
encode_item_sort(rbml_w, 'r');
|
||||
encode_item_sort(rbml_w, 't');
|
||||
|
||||
let type_scheme = ty::lookup_item_type(ecx.tcx, associated_type.def_id);
|
||||
encode_bounds_and_type(rbml_w, ecx, &type_scheme);
|
||||
|
||||
let stab = stability::lookup(ecx.tcx, associated_type.def_id);
|
||||
encode_stability(rbml_w, stab);
|
||||
|
|
@ -1316,6 +1319,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_item_variances(rbml_w, ecx, item.id);
|
||||
let trait_def = ty::lookup_trait_def(tcx, def_id);
|
||||
encode_unsafety(rbml_w, trait_def.unsafety);
|
||||
encode_associated_type_names(rbml_w, trait_def.associated_type_names.as_slice());
|
||||
encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics);
|
||||
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
|
||||
encode_name(rbml_w, item.ident.name);
|
||||
|
|
@ -1397,10 +1401,13 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
ty::StaticExplicitSelfCategory;
|
||||
}
|
||||
ty::TypeTraitItem(associated_type) => {
|
||||
encode_name(rbml_w, associated_type.name);
|
||||
|
||||
let elem = ast_map::PathName(associated_type.name);
|
||||
encode_path(rbml_w,
|
||||
path.clone().chain(Some(elem).into_iter()));
|
||||
|
||||
encode_item_sort(rbml_w, 't');
|
||||
encode_family(rbml_w, 'y');
|
||||
|
||||
is_nonstatic_method = false;
|
||||
|
|
@ -1689,6 +1696,14 @@ fn encode_unsafety(rbml_w: &mut Encoder, unsafety: ast::Unsafety) {
|
|||
rbml_w.wr_tagged_u8(tag_unsafety, byte);
|
||||
}
|
||||
|
||||
fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[ast::Name]) {
|
||||
rbml_w.start_tag(tag_associated_type_names);
|
||||
for &name in names.iter() {
|
||||
rbml_w.wr_tagged_str(tag_associated_type_name, token::get_name(name).get());
|
||||
}
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
|
||||
fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<decoder::CrateDep> {
|
||||
// Pull the cnums and name,vers,hash out of cstore
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ pub fn parse_bare_fn_ty_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: u
|
|||
|
||||
pub fn parse_trait_ref_data<'tcx>(data: &[u8], crate_num: ast::CrateNum, pos: uint,
|
||||
tcx: &ty::ctxt<'tcx>, conv: conv_did)
|
||||
-> ty::TraitRef<'tcx> {
|
||||
-> Rc<ty::TraitRef<'tcx>> {
|
||||
debug!("parse_trait_ref_data {}", data_log_string(data, pos));
|
||||
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
|
||||
parse_trait_ref(&mut st, conv)
|
||||
|
|
@ -200,9 +200,9 @@ pub fn parse_bounds_data<'tcx>(data: &[u8], crate_num: ast::CrateNum,
|
|||
parse_bounds(&mut st, conv)
|
||||
}
|
||||
|
||||
pub fn parse_existential_bounds_data(data: &[u8], crate_num: ast::CrateNum,
|
||||
pos: uint, tcx: &ty::ctxt, conv: conv_did)
|
||||
-> ty::ExistentialBounds {
|
||||
pub fn parse_existential_bounds_data<'tcx>(data: &[u8], crate_num: ast::CrateNum,
|
||||
pos: uint, tcx: &ty::ctxt<'tcx>, conv: conv_did)
|
||||
-> ty::ExistentialBounds<'tcx> {
|
||||
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
|
||||
parse_existential_bounds(&mut st, conv)
|
||||
}
|
||||
|
|
@ -377,89 +377,90 @@ fn parse_str(st: &mut PState, term: char) -> String {
|
|||
}
|
||||
|
||||
fn parse_trait_ref<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
|
||||
-> ty::TraitRef<'tcx> {
|
||||
-> Rc<ty::TraitRef<'tcx>> {
|
||||
let def = parse_def(st, NominalType, |x,y| conv(x,y));
|
||||
let substs = parse_substs(st, |x,y| conv(x,y));
|
||||
ty::TraitRef {def_id: def, substs: st.tcx.mk_substs(substs)}
|
||||
let substs = st.tcx.mk_substs(parse_substs(st, |x,y| conv(x,y)));
|
||||
Rc::new(ty::TraitRef {def_id: def, substs: substs})
|
||||
}
|
||||
|
||||
fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> {
|
||||
let tcx = st.tcx;
|
||||
match next(st) {
|
||||
'b' => return ty::mk_bool(),
|
||||
'i' => return ty::mk_int(),
|
||||
'u' => return ty::mk_uint(),
|
||||
'b' => return tcx.types.bool,
|
||||
'i' => return tcx.types.int,
|
||||
'u' => return tcx.types.uint,
|
||||
'M' => {
|
||||
match next(st) {
|
||||
'b' => return ty::mk_mach_uint(ast::TyU8),
|
||||
'w' => return ty::mk_mach_uint(ast::TyU16),
|
||||
'l' => return ty::mk_mach_uint(ast::TyU32),
|
||||
'd' => return ty::mk_mach_uint(ast::TyU64),
|
||||
'B' => return ty::mk_mach_int(ast::TyI8),
|
||||
'W' => return ty::mk_mach_int(ast::TyI16),
|
||||
'L' => return ty::mk_mach_int(ast::TyI32),
|
||||
'D' => return ty::mk_mach_int(ast::TyI64),
|
||||
'f' => return ty::mk_mach_float(ast::TyF32),
|
||||
'F' => return ty::mk_mach_float(ast::TyF64),
|
||||
'b' => return tcx.types.u8,
|
||||
'w' => return tcx.types.u16,
|
||||
'l' => return tcx.types.u32,
|
||||
'd' => return tcx.types.u64,
|
||||
'B' => return tcx.types.i8,
|
||||
'W' => return tcx.types.i16,
|
||||
'L' => return tcx.types.i32,
|
||||
'D' => return tcx.types.i64,
|
||||
'f' => return tcx.types.f32,
|
||||
'F' => return tcx.types.f64,
|
||||
_ => panic!("parse_ty: bad numeric type")
|
||||
}
|
||||
}
|
||||
'c' => return ty::mk_char(),
|
||||
'c' => return tcx.types.char,
|
||||
't' => {
|
||||
assert_eq!(next(st), '[');
|
||||
let def = parse_def(st, NominalType, |x,y| conv(x,y));
|
||||
let substs = parse_substs(st, |x,y| conv(x,y));
|
||||
assert_eq!(next(st), ']');
|
||||
return ty::mk_enum(st.tcx, def, st.tcx.mk_substs(substs));
|
||||
return ty::mk_enum(tcx, def, st.tcx.mk_substs(substs));
|
||||
}
|
||||
'x' => {
|
||||
assert_eq!(next(st), '[');
|
||||
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);
|
||||
return ty::mk_trait(tcx, trait_ref, bounds);
|
||||
}
|
||||
'p' => {
|
||||
let did = parse_def(st, TypeParameter, |x,y| conv(x,y));
|
||||
debug!("parsed ty_param: did={}", did);
|
||||
assert_eq!(next(st), '[');
|
||||
let index = parse_u32(st);
|
||||
assert_eq!(next(st), '|');
|
||||
let space = parse_param_space(st);
|
||||
assert_eq!(next(st), '|');
|
||||
return ty::mk_param(st.tcx, space, index, did);
|
||||
let name = token::intern(parse_str(st, ']')[]);
|
||||
return ty::mk_param(tcx, space, index, name);
|
||||
}
|
||||
'~' => return ty::mk_uniq(st.tcx, parse_ty(st, |x,y| conv(x,y))),
|
||||
'*' => return ty::mk_ptr(st.tcx, parse_mt(st, |x,y| conv(x,y))),
|
||||
'~' => return ty::mk_uniq(tcx, parse_ty(st, |x,y| conv(x,y))),
|
||||
'*' => return ty::mk_ptr(tcx, parse_mt(st, |x,y| conv(x,y))),
|
||||
'&' => {
|
||||
let r = parse_region(st, |x,y| conv(x,y));
|
||||
let mt = parse_mt(st, |x,y| conv(x,y));
|
||||
return ty::mk_rptr(st.tcx, st.tcx.mk_region(r), mt);
|
||||
return ty::mk_rptr(tcx, tcx.mk_region(r), mt);
|
||||
}
|
||||
'V' => {
|
||||
let t = parse_ty(st, |x,y| conv(x,y));
|
||||
let sz = parse_size(st);
|
||||
return ty::mk_vec(st.tcx, t, sz);
|
||||
return ty::mk_vec(tcx, t, sz);
|
||||
}
|
||||
'v' => {
|
||||
return ty::mk_str(st.tcx);
|
||||
return ty::mk_str(tcx);
|
||||
}
|
||||
'T' => {
|
||||
assert_eq!(next(st), '[');
|
||||
let mut params = Vec::new();
|
||||
while peek(st) != ']' { params.push(parse_ty(st, |x,y| conv(x,y))); }
|
||||
st.pos = st.pos + 1u;
|
||||
return ty::mk_tup(st.tcx, params);
|
||||
return ty::mk_tup(tcx, params);
|
||||
}
|
||||
'f' => {
|
||||
return ty::mk_closure(st.tcx, parse_closure_ty(st, |x,y| conv(x,y)));
|
||||
return ty::mk_closure(tcx, parse_closure_ty(st, |x,y| conv(x,y)));
|
||||
}
|
||||
'F' => {
|
||||
let def_id = parse_def(st, NominalType, |x,y| conv(x,y));
|
||||
return ty::mk_bare_fn(st.tcx, Some(def_id),
|
||||
st.tcx.mk_bare_fn(parse_bare_fn_ty(st, |x,y| conv(x,y))));
|
||||
return ty::mk_bare_fn(tcx, Some(def_id),
|
||||
tcx.mk_bare_fn(parse_bare_fn_ty(st, |x,y| conv(x,y))));
|
||||
}
|
||||
'G' => {
|
||||
return ty::mk_bare_fn(st.tcx, None,
|
||||
st.tcx.mk_bare_fn(parse_bare_fn_ty(st, |x,y| conv(x,y))));
|
||||
return ty::mk_bare_fn(tcx, None,
|
||||
tcx.mk_bare_fn(parse_bare_fn_ty(st, |x,y| conv(x,y))));
|
||||
}
|
||||
'#' => {
|
||||
let pos = parse_hex(st);
|
||||
|
|
@ -470,7 +471,7 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> {
|
|||
pos: pos,
|
||||
len: len };
|
||||
|
||||
match st.tcx.rcache.borrow().get(&key).cloned() {
|
||||
match tcx.rcache.borrow().get(&key).cloned() {
|
||||
Some(tt) => return tt,
|
||||
None => {}
|
||||
}
|
||||
|
|
@ -479,7 +480,7 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> {
|
|||
.. *st
|
||||
};
|
||||
let tt = parse_ty(&mut ps, |x,y| conv(x,y));
|
||||
st.tcx.rcache.borrow_mut().insert(key, tt);
|
||||
tcx.rcache.borrow_mut().insert(key, tt);
|
||||
return tt;
|
||||
}
|
||||
'\"' => {
|
||||
|
|
@ -503,8 +504,14 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> {
|
|||
return ty::mk_unboxed_closure(st.tcx, did,
|
||||
st.tcx.mk_region(region), st.tcx.mk_substs(substs));
|
||||
}
|
||||
'P' => {
|
||||
assert_eq!(next(st), '[');
|
||||
let trait_ref = parse_trait_ref(st, |x,y| conv(x,y));
|
||||
let name = token::intern(parse_str(st, ']').as_slice());
|
||||
return ty::mk_projection(tcx, trait_ref, name);
|
||||
}
|
||||
'e' => {
|
||||
return ty::mk_err();
|
||||
return tcx.types.err;
|
||||
}
|
||||
c => { panic!("unexpected char in type string: {}", c);}
|
||||
}
|
||||
|
|
@ -682,17 +689,32 @@ pub fn parse_predicate<'a,'tcx>(st: &mut PState<'a, 'tcx>,
|
|||
-> ty::Predicate<'tcx>
|
||||
{
|
||||
match next(st) {
|
||||
't' => Rc::new(ty::Binder(parse_trait_ref(st, conv))).as_predicate(),
|
||||
't' => 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(),
|
||||
'p' => ty::Binder(parse_projection_predicate(st, conv)).as_predicate(),
|
||||
c => panic!("Encountered invalid character in metadata: {}", c)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_projection_predicate<'a,'tcx>(
|
||||
st: &mut PState<'a, 'tcx>,
|
||||
conv: conv_did)
|
||||
-> ty::ProjectionPredicate<'tcx>
|
||||
{
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy {
|
||||
trait_ref: parse_trait_ref(st, |x,y| conv(x,y)),
|
||||
item_name: token::str_to_ident(parse_str(st, '|').as_slice()).name,
|
||||
},
|
||||
ty: parse_ty(st, |x,y| conv(x,y)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_type_param_def_data<'tcx>(data: &[u8], start: uint,
|
||||
crate_num: ast::CrateNum, tcx: &ty::ctxt<'tcx>,
|
||||
conv: conv_did) -> ty::TypeParameterDef<'tcx>
|
||||
|
|
@ -709,10 +731,6 @@ fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
|
|||
assert_eq!(next(st), '|');
|
||||
let index = parse_u32(st);
|
||||
assert_eq!(next(st), '|');
|
||||
let associated_with = parse_opt(st, |st| {
|
||||
parse_def(st, NominalType, |x,y| conv(x,y))
|
||||
});
|
||||
assert_eq!(next(st), '|');
|
||||
let bounds = parse_bounds(st, |x,y| conv(x,y));
|
||||
let default = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)));
|
||||
|
||||
|
|
@ -721,16 +739,23 @@ fn parse_type_param_def<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
|
|||
def_id: def_id,
|
||||
space: space,
|
||||
index: index,
|
||||
associated_with: associated_with,
|
||||
bounds: bounds,
|
||||
default: default
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_existential_bounds(st: &mut PState, conv: conv_did) -> ty::ExistentialBounds {
|
||||
let r = parse_region(st, |x,y| conv(x,y));
|
||||
let bb = parse_builtin_bounds(st, conv);
|
||||
return ty::ExistentialBounds { region_bound: r, builtin_bounds: bb };
|
||||
fn parse_existential_bounds<'a,'tcx>(st: &mut PState<'a,'tcx>,
|
||||
conv: conv_did)
|
||||
-> ty::ExistentialBounds<'tcx>
|
||||
{
|
||||
let ty::ParamBounds { trait_bounds, mut region_bounds, builtin_bounds, projection_bounds } =
|
||||
parse_bounds(st, conv);
|
||||
assert_eq!(region_bounds.len(), 1);
|
||||
assert_eq!(trait_bounds.len(), 0);
|
||||
let region_bound = region_bounds.pop().unwrap();
|
||||
return ty::ExistentialBounds { region_bound: region_bound,
|
||||
builtin_bounds: builtin_bounds,
|
||||
projection_bounds: projection_bounds };
|
||||
}
|
||||
|
||||
fn parse_builtin_bounds(st: &mut PState, _conv: conv_did) -> ty::BuiltinBounds {
|
||||
|
|
@ -767,7 +792,8 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
|
|||
let mut param_bounds = ty::ParamBounds {
|
||||
region_bounds: Vec::new(),
|
||||
builtin_bounds: builtin_bounds,
|
||||
trait_bounds: Vec::new()
|
||||
trait_bounds: Vec::new(),
|
||||
projection_bounds: Vec::new(),
|
||||
};
|
||||
loop {
|
||||
match next(st) {
|
||||
|
|
@ -777,7 +803,11 @@ fn parse_bounds<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did)
|
|||
}
|
||||
'I' => {
|
||||
param_bounds.trait_bounds.push(
|
||||
Rc::new(ty::Binder(parse_trait_ref(st, |x,y| conv(x,y)))));
|
||||
ty::Binder(parse_trait_ref(st, |x,y| conv(x,y))));
|
||||
}
|
||||
'P' => {
|
||||
param_bounds.projection_bounds.push(
|
||||
ty::Binder(parse_projection_predicate(st, |x,y| conv(x,y))));
|
||||
}
|
||||
'.' => {
|
||||
return param_bounds;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
|
|||
ty::ty_trait(box ty::TyTrait { ref principal,
|
||||
ref bounds }) => {
|
||||
mywrite!(w, "x[");
|
||||
enc_trait_ref(w, cx, &principal.0);
|
||||
enc_trait_ref(w, cx, &*principal.0);
|
||||
enc_existential_bounds(w, cx, bounds);
|
||||
mywrite!(w, "]");
|
||||
}
|
||||
|
|
@ -135,8 +135,8 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
|
|||
ty::ty_infer(_) => {
|
||||
cx.diag.handler().bug("cannot encode inference variable types");
|
||||
}
|
||||
ty::ty_param(ParamTy {space, idx: id, def_id: did}) => {
|
||||
mywrite!(w, "p{}|{}|{}|", (cx.ds)(did), id, space.to_uint())
|
||||
ty::ty_param(ParamTy {space, idx, name}) => {
|
||||
mywrite!(w, "p[{}|{}|{}]", idx, space.to_uint(), token::get_name(name))
|
||||
}
|
||||
ty::ty_struct(def, substs) => {
|
||||
mywrite!(w, "a[{}|", (cx.ds)(def));
|
||||
|
|
@ -149,6 +149,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
|
|||
enc_substs(w, cx, substs);
|
||||
mywrite!(w, "]");
|
||||
}
|
||||
ty::ty_projection(ref data) => {
|
||||
mywrite!(w, "P[");
|
||||
enc_trait_ref(w, cx, &*data.trait_ref);
|
||||
mywrite!(w, "{}]", token::get_name(data.item_name));
|
||||
}
|
||||
ty::ty_err => {
|
||||
mywrite!(w, "e");
|
||||
}
|
||||
|
|
@ -387,9 +392,14 @@ pub fn enc_builtin_bounds(w: &mut SeekableMemWriter, _cx: &ctxt, bs: &ty::Builti
|
|||
mywrite!(w, ".");
|
||||
}
|
||||
|
||||
pub fn enc_existential_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ExistentialBounds) {
|
||||
enc_region(w, cx, bs.region_bound);
|
||||
enc_builtin_bounds(w, cx, &bs.builtin_bounds);
|
||||
pub fn enc_existential_bounds<'a,'tcx>(w: &mut SeekableMemWriter,
|
||||
cx: &ctxt<'a,'tcx>,
|
||||
bs: &ty::ExistentialBounds<'tcx>) {
|
||||
let param_bounds = ty::ParamBounds { trait_bounds: vec!(),
|
||||
region_bounds: vec!(bs.region_bound),
|
||||
builtin_bounds: bs.builtin_bounds,
|
||||
projection_bounds: bs.projection_bounds.clone() };
|
||||
enc_bounds(w, cx, ¶m_bounds);
|
||||
}
|
||||
|
||||
pub fn enc_bounds<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>,
|
||||
|
|
@ -403,7 +413,12 @@ 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.0);
|
||||
enc_trait_ref(w, cx, &*tp.0);
|
||||
}
|
||||
|
||||
for tp in bs.projection_bounds.iter() {
|
||||
mywrite!(w, "P");
|
||||
enc_projection_predicate(w, cx, &tp.0);
|
||||
}
|
||||
|
||||
mywrite!(w, ".");
|
||||
|
|
@ -414,8 +429,6 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc
|
|||
mywrite!(w, "{}:{}|{}|{}|",
|
||||
token::get_name(v.name), (cx.ds)(v.def_id),
|
||||
v.space.to_uint(), v.index);
|
||||
enc_opt(w, v.associated_with, |w, did| mywrite!(w, "{}", (cx.ds)(did)));
|
||||
mywrite!(w, "|");
|
||||
enc_bounds(w, cx, &v.bounds);
|
||||
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
|
||||
}
|
||||
|
|
@ -427,7 +440,7 @@ 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.0);
|
||||
enc_trait_ref(w, cx, &*trait_ref.0.trait_ref);
|
||||
}
|
||||
ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => {
|
||||
mywrite!(w, "e");
|
||||
|
|
@ -444,5 +457,17 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
|
|||
enc_ty(w, cx, a);
|
||||
enc_region(w, cx, b);
|
||||
}
|
||||
ty::Predicate::Projection(ty::Binder(ref data)) => {
|
||||
mywrite!(w, "p");
|
||||
enc_projection_predicate(w, cx, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enc_projection_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
|
||||
cx: &ctxt<'a, 'tcx>,
|
||||
data: &ty::ProjectionPredicate<'tcx>) {
|
||||
enc_trait_ref(w, cx, &*data.projection_ty.trait_ref);
|
||||
mywrite!(w, "{}|", token::get_name(data.projection_ty.item_name));
|
||||
enc_ty(w, cx, data.ty);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,23 +57,23 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
|
|||
match nty {
|
||||
ast::TyBool => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
Some(ty::mk_bool())
|
||||
Some(tcx.types.bool)
|
||||
}
|
||||
ast::TyChar => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
Some(ty::mk_char())
|
||||
Some(tcx.types.char)
|
||||
}
|
||||
ast::TyInt(it) => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
Some(ty::mk_mach_int(it))
|
||||
Some(ty::mk_mach_int(tcx, it))
|
||||
}
|
||||
ast::TyUint(uit) => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
Some(ty::mk_mach_uint(uit))
|
||||
Some(ty::mk_mach_uint(tcx, uit))
|
||||
}
|
||||
ast::TyFloat(ft) => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
Some(ty::mk_mach_float(ft))
|
||||
Some(ty::mk_mach_float(tcx, ft))
|
||||
}
|
||||
ast::TyStr => {
|
||||
Some(ty::mk_str(tcx))
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ impl tr for def::Def {
|
|||
def::DefAssociatedPath(def::TyParamProvenance::FromParam(did), ident) =>
|
||||
def::DefAssociatedPath(def::TyParamProvenance::FromParam(did.tr(dcx)), ident),
|
||||
def::DefPrimTy(p) => def::DefPrimTy(p),
|
||||
def::DefTyParam(s, did, v) => def::DefTyParam(s, did.tr(dcx), v),
|
||||
def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n),
|
||||
def::DefUse(did) => def::DefUse(did.tr(dcx)),
|
||||
def::DefUpvar(nid1, nid2, nid3) => {
|
||||
def::DefUpvar(dcx.tr_id(nid1),
|
||||
|
|
@ -707,9 +707,8 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
|||
{
|
||||
let types = self.read_to_vec(|this| Ok(f(this))).unwrap();
|
||||
let selfs = self.read_to_vec(|this| Ok(f(this))).unwrap();
|
||||
let assocs = self.read_to_vec(|this| Ok(f(this))).unwrap();
|
||||
let fns = self.read_to_vec(|this| Ok(f(this))).unwrap();
|
||||
VecPerParamSpace::new(types, selfs, assocs, fns)
|
||||
VecPerParamSpace::new(types, selfs, fns)
|
||||
}
|
||||
|
||||
fn read_vtable_res_with_key(&mut self,
|
||||
|
|
@ -838,11 +837,12 @@ trait rbml_writer_helpers<'tcx> {
|
|||
predicate: &ty::Predicate<'tcx>);
|
||||
fn emit_trait_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
|
||||
ty: &ty::TraitRef<'tcx>);
|
||||
fn emit_polytype<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
|
||||
pty: ty::Polytype<'tcx>);
|
||||
fn emit_type_scheme<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
|
||||
type_scheme: ty::TypeScheme<'tcx>);
|
||||
fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
|
||||
substs: &subst::Substs<'tcx>);
|
||||
fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds);
|
||||
fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>,
|
||||
bounds: &ty::ExistentialBounds<'tcx>);
|
||||
fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds);
|
||||
fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
|
||||
adj: &ty::AutoAdjustment<'tcx>);
|
||||
|
|
@ -951,38 +951,39 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
fn emit_polytype<'b>(&mut self,
|
||||
ecx: &e::EncodeContext<'b, 'tcx>,
|
||||
pty: ty::Polytype<'tcx>) {
|
||||
fn emit_type_scheme<'b>(&mut self,
|
||||
ecx: &e::EncodeContext<'b, 'tcx>,
|
||||
type_scheme: ty::TypeScheme<'tcx>) {
|
||||
use serialize::Encoder;
|
||||
|
||||
self.emit_struct("Polytype", 2, |this| {
|
||||
self.emit_struct("TypeScheme", 2, |this| {
|
||||
this.emit_struct_field("generics", 0, |this| {
|
||||
this.emit_struct("Generics", 2, |this| {
|
||||
this.emit_struct_field("types", 0, |this| {
|
||||
Ok(encode_vec_per_param_space(
|
||||
this, &pty.generics.types,
|
||||
this, &type_scheme.generics.types,
|
||||
|this, def| this.emit_type_param_def(ecx, def)))
|
||||
});
|
||||
this.emit_struct_field("regions", 1, |this| {
|
||||
Ok(encode_vec_per_param_space(
|
||||
this, &pty.generics.regions,
|
||||
this, &type_scheme.generics.regions,
|
||||
|this, def| def.encode(this).unwrap()))
|
||||
});
|
||||
this.emit_struct_field("predicates", 2, |this| {
|
||||
Ok(encode_vec_per_param_space(
|
||||
this, &pty.generics.predicates,
|
||||
this, &type_scheme.generics.predicates,
|
||||
|this, def| this.emit_predicate(ecx, def)))
|
||||
})
|
||||
})
|
||||
});
|
||||
this.emit_struct_field("ty", 1, |this| {
|
||||
Ok(this.emit_ty(ecx, pty.ty))
|
||||
Ok(this.emit_ty(ecx, type_scheme.ty))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn emit_existential_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::ExistentialBounds) {
|
||||
fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>,
|
||||
bounds: &ty::ExistentialBounds<'tcx>) {
|
||||
self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this.writer,
|
||||
&ecx.ty_str_ctxt(),
|
||||
bounds)));
|
||||
|
|
@ -1120,7 +1121,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.0))
|
||||
Ok(this.emit_trait_ref(ecx, &*principal.0))
|
||||
}));
|
||||
this.emit_struct_field("bounds", 1, |this| {
|
||||
Ok(this.emit_existential_bounds(ecx, b))
|
||||
|
|
@ -1252,11 +1253,11 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
|||
}
|
||||
|
||||
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
|
||||
for &pty in tcx.tcache.borrow().get(&lid).iter() {
|
||||
for &type_scheme in tcx.tcache.borrow().get(&lid).iter() {
|
||||
rbml_w.tag(c::tag_table_tcache, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
rbml_w.emit_polytype(ecx, pty.clone());
|
||||
rbml_w.emit_type_scheme(ecx, type_scheme.clone());
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -1284,7 +1285,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.0);
|
||||
rbml_w.emit_trait_ref(ecx, &*trait_ref.0);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -1364,15 +1365,15 @@ trait rbml_decoder_decoder_helpers<'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>>;
|
||||
-> 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>)
|
||||
-> ty::Predicate<'tcx>;
|
||||
fn read_polytype<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> ty::Polytype<'tcx>;
|
||||
fn read_type_scheme<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> ty::TypeScheme<'tcx>;
|
||||
fn read_existential_bounds<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> ty::ExistentialBounds;
|
||||
-> ty::ExistentialBounds<'tcx>;
|
||||
fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
-> subst::Substs<'tcx>;
|
||||
fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
|
||||
|
|
@ -1546,7 +1547,20 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
|||
|
||||
fn read_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> Rc<ty::TraitRef<'tcx>> {
|
||||
Rc::new(self.read_opaque(|this, doc| {
|
||||
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_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> ty::PolyTraitRef<'tcx> {
|
||||
ty::Binder(self.read_opaque(|this, doc| {
|
||||
let ty = tydecode::parse_trait_ref_data(
|
||||
doc.data,
|
||||
dcx.cdata.cnum,
|
||||
|
|
@ -1557,19 +1571,6 @@ 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| {
|
||||
|
|
@ -1591,10 +1592,10 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
|||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_polytype<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> ty::Polytype<'tcx> {
|
||||
self.read_struct("Polytype", 2, |this| {
|
||||
Ok(ty::Polytype {
|
||||
fn read_type_scheme<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> ty::TypeScheme<'tcx> {
|
||||
self.read_struct("TypeScheme", 2, |this| {
|
||||
Ok(ty::TypeScheme {
|
||||
generics: this.read_struct_field("generics", 0, |this| {
|
||||
this.read_struct("Generics", 2, |this| {
|
||||
Ok(ty::Generics {
|
||||
|
|
@ -1626,7 +1627,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
|||
}
|
||||
|
||||
fn read_existential_bounds<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||
-> ty::ExistentialBounds
|
||||
-> ty::ExistentialBounds<'tcx>
|
||||
{
|
||||
self.read_opaque(|this, doc| {
|
||||
Ok(tydecode::parse_existential_bounds_data(doc.data,
|
||||
|
|
@ -1786,7 +1787,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
|||
Ok(this.read_poly_trait_ref(dcx))
|
||||
}));
|
||||
Ok(ty::TyTrait {
|
||||
principal: (*principal).clone(),
|
||||
principal: principal,
|
||||
bounds: try!(this.read_struct_field("bounds", 1, |this| {
|
||||
Ok(this.read_existential_bounds(dcx))
|
||||
})),
|
||||
|
|
@ -1939,9 +1940,9 @@ fn decode_side_tables(dcx: &DecodeContext,
|
|||
.insert(id, capture_mode);
|
||||
}
|
||||
c::tag_table_tcache => {
|
||||
let pty = val_dsr.read_polytype(dcx);
|
||||
let type_scheme = val_dsr.read_type_scheme(dcx);
|
||||
let lid = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
|
||||
dcx.tcx.tcache.borrow_mut().insert(lid, pty);
|
||||
dcx.tcx.tcache.borrow_mut().insert(lid, type_scheme);
|
||||
}
|
||||
c::tag_table_param_defs => {
|
||||
let bounds = val_dsr.read_type_param_def(dcx);
|
||||
|
|
|
|||
|
|
@ -1065,7 +1065,7 @@ fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>,
|
|||
};
|
||||
let mut visitor = ExprUseVisitor::new(&mut checker,
|
||||
checker.cx.tcx,
|
||||
cx.param_env.clone());
|
||||
&cx.param_env);
|
||||
visitor.walk_expr(guard);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ pub fn check_crate(tcx: &ty::ctxt,
|
|||
}
|
||||
|
||||
struct RvalueContext<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
|
||||
|
|
@ -40,21 +40,27 @@ impl<'a, 'tcx, 'v> visit::Visitor<'v> for RvalueContext<'a, 'tcx> {
|
|||
fn_id: ast::NodeId) {
|
||||
{
|
||||
let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
|
||||
let mut euv = euv::ExprUseVisitor::new(self, self.tcx, param_env);
|
||||
let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: ¶m_env };
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut delegate, self.tcx, ¶m_env);
|
||||
euv.walk_fn(fd, b);
|
||||
}
|
||||
visit::walk_fn(self, fk, fd, b, s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContext<'a, 'tcx> {
|
||||
struct RvalueContextDelegate<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
param_env: &'a ty::ParameterEnvironment<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
|
||||
fn consume(&mut self,
|
||||
_: ast::NodeId,
|
||||
span: Span,
|
||||
cmt: mc::cmt<'tcx>,
|
||||
_: euv::ConsumeMode) {
|
||||
debug!("consume; cmt: {}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
|
||||
if !ty::type_is_sized(self.tcx, cmt.ty) {
|
||||
if !ty::type_is_sized(self.tcx, cmt.ty, self.param_env) {
|
||||
span_err!(self.tcx.sess, span, E0161,
|
||||
"cannot move a value of type {0}: the size of {0} cannot be statically determined",
|
||||
ty_to_string(self.tcx, cmt.ty));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -72,7 +71,7 @@ pub fn check_crate(tcx: &ty::ctxt) {
|
|||
};
|
||||
{
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let visitor = euv::ExprUseVisitor::new(&mut checker, tcx, param_env);
|
||||
let visitor = euv::ExprUseVisitor::new(&mut checker, tcx, ¶m_env);
|
||||
visit::walk_crate(&mut GlobalVisitor(visitor), tcx.map.krate());
|
||||
}
|
||||
visit::walk_crate(&mut CheckStaticVisitor {
|
||||
|
|
@ -120,19 +119,14 @@ 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::poly_trait_ref_for_builtin_bound(self.tcx, ty::BoundSync, ty) {
|
||||
Ok(trait_ref) => {
|
||||
let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
|
||||
fulfill_cx.register_trait_ref(self.tcx, trait_ref, cause);
|
||||
let env = ty::empty_parameter_environment();
|
||||
match fulfill_cx.select_all_or_error(&infcx, &env, self.tcx) {
|
||||
Ok(()) => { },
|
||||
Err(ref errors) => {
|
||||
traits::report_fulfillment_errors(&infcx, errors);
|
||||
}
|
||||
}
|
||||
let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
|
||||
fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
|
||||
let env = ty::empty_parameter_environment();
|
||||
match fulfill_cx.select_all_or_error(&infcx, &env, self.tcx) {
|
||||
Ok(()) => { },
|
||||
Err(ref errors) => {
|
||||
traits::report_fulfillment_errors(&infcx, errors);
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,10 +36,11 @@ pub enum Def {
|
|||
// A partially resolved path to an associated type `T::U` where `T` is a concrete
|
||||
// type (indicated by the DefId) which implements a trait which has an associated
|
||||
// type `U` (indicated by the Ident).
|
||||
// FIXME(#20301) -- should use Name
|
||||
DefAssociatedPath(TyParamProvenance, ast::Ident),
|
||||
DefTrait(ast::DefId),
|
||||
DefPrimTy(ast::PrimTy),
|
||||
DefTyParam(ParamSpace, ast::DefId, u32),
|
||||
DefTyParam(ParamSpace, u32, ast::DefId, ast::Name),
|
||||
DefUse(ast::DefId),
|
||||
DefUpvar(ast::NodeId, // id of closed over local
|
||||
ast::NodeId, // expr node that creates the closure
|
||||
|
|
@ -130,7 +131,7 @@ impl Def {
|
|||
DefFn(id, _) | DefStaticMethod(id, _) | DefMod(id) |
|
||||
DefForeignMod(id) | DefStatic(id, _) |
|
||||
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(id) |
|
||||
DefTyParam(_, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
|
||||
DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
|
||||
DefMethod(id, _, _) | DefConst(id) |
|
||||
DefAssociatedPath(TyParamProvenance::FromSelf(id), _) |
|
||||
DefAssociatedPath(TyParamProvenance::FromParam(id), _) => {
|
||||
|
|
|
|||
|
|
@ -295,11 +295,11 @@ impl OverloadedCallType {
|
|||
// supplies types from the tree. After type checking is complete, you
|
||||
// can just use the tcx as the typer.
|
||||
|
||||
pub struct ExprUseVisitor<'d,'t,'tcx,TYPER:'t> {
|
||||
pub struct ExprUseVisitor<'d,'t,'tcx:'t,TYPER:'t> {
|
||||
typer: &'t TYPER,
|
||||
mc: mc::MemCategorizationContext<'t,TYPER>,
|
||||
delegate: &'d mut (Delegate<'tcx>+'d),
|
||||
param_env: ParameterEnvironment<'tcx>,
|
||||
param_env: &'t ParameterEnvironment<'tcx>,
|
||||
}
|
||||
|
||||
/// Whether the elements of an overloaded operation are passed by value or by reference
|
||||
|
|
@ -311,7 +311,7 @@ enum PassArgs {
|
|||
impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
||||
pub fn new(delegate: &'d mut Delegate<'tcx>,
|
||||
typer: &'t TYPER,
|
||||
param_env: ParameterEnvironment<'tcx>)
|
||||
param_env: &'t ParameterEnvironment<'tcx>)
|
||||
-> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
||||
ExprUseVisitor {
|
||||
typer: typer,
|
||||
|
|
@ -355,7 +355,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
cmt: mc::cmt<'tcx>) {
|
||||
let mode = copy_or_move(self.tcx(),
|
||||
cmt.ty,
|
||||
&self.param_env,
|
||||
self.param_env,
|
||||
DirectRefMove);
|
||||
self.delegate.consume(consume_id, consume_span, cmt, mode);
|
||||
}
|
||||
|
|
@ -998,7 +998,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
ast::PatIdent(ast::BindByValue(_), _, _) => {
|
||||
match copy_or_move(tcx,
|
||||
cmt_pat.ty,
|
||||
&self.param_env,
|
||||
self.param_env,
|
||||
PatBindingMove) {
|
||||
Copy => mode.lub(CopyingMatch),
|
||||
Move(_) => mode.lub(MovingMatch),
|
||||
|
|
@ -1028,8 +1028,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
let typer = self.typer;
|
||||
let def_map = &self.typer.tcx().def_map;
|
||||
let delegate = &mut self.delegate;
|
||||
let param_env = &mut self.param_env;
|
||||
|
||||
let param_env = self.param_env;
|
||||
mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
|
||||
if pat_util::pat_is_binding(def_map, pat) {
|
||||
let tcx = typer.tcx();
|
||||
|
|
@ -1249,7 +1248,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
closure_expr.span,
|
||||
freevar.def);
|
||||
let mode = copy_or_move(self.tcx(), cmt_var.ty,
|
||||
&self.param_env, CaptureMove);
|
||||
self.param_env, CaptureMove);
|
||||
self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,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))
|
||||
|
|
@ -86,6 +86,9 @@ pub fn simplify_type(tcx: &ty::ctxt,
|
|||
ty::ty_bare_fn(_, ref f) => {
|
||||
Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
|
||||
}
|
||||
ty::ty_projection(_) => {
|
||||
None
|
||||
}
|
||||
ty::ty_param(_) => {
|
||||
if can_simplify_params {
|
||||
Some(ParameterSimplifiedType)
|
||||
|
|
|
|||
|
|
@ -351,11 +351,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
(&ty::ty_trait(..), &ty::ty_trait(..)) => {
|
||||
None
|
||||
}
|
||||
(_, &ty::ty_trait(box ty::TyTrait { ref principal, bounds })) => {
|
||||
(_, &ty::ty_trait(box ty::TyTrait { ref principal, ref bounds })) => {
|
||||
// FIXME what is the purpose of `ty`?
|
||||
let ty = ty::mk_trait(tcx, principal.clone(), bounds);
|
||||
Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: (*principal).clone(),
|
||||
bounds: bounds },
|
||||
let ty = ty::mk_trait(tcx, principal.clone(), bounds.clone());
|
||||
Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: principal.clone(),
|
||||
bounds: bounds.clone() },
|
||||
ty_a)))
|
||||
}
|
||||
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
|
||||
|
|
@ -458,10 +458,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
|
||||
match a.sty {
|
||||
ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty.sty {
|
||||
ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
|
||||
ty::ty_trait(box ty::TyTrait { ref principal, ref 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.clone());
|
||||
try!(self.subtype(mk_ty(tr), b));
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ use middle::ty_fold;
|
|||
use middle::ty_fold::{TypeFoldable};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::{Onceness, Unsafety};
|
||||
use syntax::ast;
|
||||
use syntax::abi;
|
||||
|
|
@ -221,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 bounds = try!(self.existential_bounds(&a.bounds, &b.bounds));
|
||||
let sig = try!(self.binders(&a.sig, &b.sig));
|
||||
let abi = try!(self.abi(a.abi, b.abi));
|
||||
Ok(ty::ClosureTy {
|
||||
|
|
@ -288,15 +289,61 @@ pub trait Combine<'tcx> {
|
|||
|
||||
fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<'tcx, Onceness>;
|
||||
|
||||
fn projection_tys(&self,
|
||||
a: &ty::ProjectionTy<'tcx>,
|
||||
b: &ty::ProjectionTy<'tcx>)
|
||||
-> cres<'tcx, ty::ProjectionTy<'tcx>>
|
||||
{
|
||||
if a.item_name != b.item_name {
|
||||
Err(ty::terr_projection_name_mismatched(
|
||||
expected_found(self, a.item_name, b.item_name)))
|
||||
} else {
|
||||
let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref));
|
||||
Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name })
|
||||
}
|
||||
}
|
||||
|
||||
fn projection_predicates(&self,
|
||||
a: &ty::ProjectionPredicate<'tcx>,
|
||||
b: &ty::ProjectionPredicate<'tcx>)
|
||||
-> cres<'tcx, ty::ProjectionPredicate<'tcx>>
|
||||
{
|
||||
let projection_ty = try!(self.projection_tys(&a.projection_ty, &b.projection_ty));
|
||||
let ty = try!(self.tys(a.ty, b.ty));
|
||||
Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty })
|
||||
}
|
||||
|
||||
fn projection_bounds(&self,
|
||||
a: &Vec<ty::PolyProjectionPredicate<'tcx>>,
|
||||
b: &Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> cres<'tcx, Vec<ty::PolyProjectionPredicate<'tcx>>>
|
||||
{
|
||||
// To be compatible, `a` and `b` must be for precisely the
|
||||
// same set of traits and item names. We always require that
|
||||
// projection bounds lists are sorted by trait-def-id and item-name,
|
||||
// so we can just iterate through the lists pairwise, so long as they are the
|
||||
// same length.
|
||||
if a.len() != b.len() {
|
||||
Err(ty::terr_projection_bounds_length(expected_found(self, a.len(), b.len())))
|
||||
} else {
|
||||
a.iter()
|
||||
.zip(b.iter())
|
||||
.map(|(a, b)| self.binders(a, b))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn existential_bounds(&self,
|
||||
a: ty::ExistentialBounds,
|
||||
b: ty::ExistentialBounds)
|
||||
-> cres<'tcx, ty::ExistentialBounds>
|
||||
a: &ty::ExistentialBounds<'tcx>,
|
||||
b: &ty::ExistentialBounds<'tcx>)
|
||||
-> cres<'tcx, ty::ExistentialBounds<'tcx>>
|
||||
{
|
||||
let r = try!(self.contraregions(a.region_bound, b.region_bound));
|
||||
let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
|
||||
let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds));
|
||||
Ok(ty::ExistentialBounds { region_bound: r,
|
||||
builtin_bounds: nb })
|
||||
builtin_bounds: nb,
|
||||
projection_bounds: pb })
|
||||
}
|
||||
|
||||
fn builtin_bounds(&self,
|
||||
|
|
@ -358,6 +405,18 @@ pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> {
|
|||
fn combine<C:Combine<'tcx>>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>;
|
||||
}
|
||||
|
||||
impl<'tcx,T> Combineable<'tcx> for Rc<T>
|
||||
where T : Combineable<'tcx>
|
||||
{
|
||||
fn combine<C:Combine<'tcx>>(combiner: &C,
|
||||
a: &Rc<T>,
|
||||
b: &Rc<T>)
|
||||
-> cres<'tcx, Rc<T>>
|
||||
{
|
||||
Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b))))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> {
|
||||
fn combine<C:Combine<'tcx>>(combiner: &C,
|
||||
a: &ty::TraitRef<'tcx>,
|
||||
|
|
@ -368,6 +427,16 @@ impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Combineable<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
fn combine<C:Combine<'tcx>>(combiner: &C,
|
||||
a: &ty::ProjectionPredicate<'tcx>,
|
||||
b: &ty::ProjectionPredicate<'tcx>)
|
||||
-> cres<'tcx, ty::ProjectionPredicate<'tcx>>
|
||||
{
|
||||
combiner.projection_predicates(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Combineable<'tcx> for ty::FnSig<'tcx> {
|
||||
fn combine<C:Combine<'tcx>>(combiner: &C,
|
||||
a: &ty::FnSig<'tcx>,
|
||||
|
|
@ -397,8 +466,8 @@ pub fn expected_found<'tcx, C: Combine<'tcx>, T>(
|
|||
pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>)
|
||||
-> cres<'tcx, Ty<'tcx>> {
|
||||
|
||||
-> cres<'tcx, Ty<'tcx>>
|
||||
{
|
||||
let tcx = this.infcx().tcx;
|
||||
let a_sty = &a.sty;
|
||||
let b_sty = &b.sty;
|
||||
|
|
@ -415,7 +484,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
|
|||
}
|
||||
|
||||
(&ty::ty_err, _) | (_, &ty::ty_err) => {
|
||||
Ok(ty::mk_err())
|
||||
Ok(tcx.types.err)
|
||||
}
|
||||
|
||||
// Relate integral variables to other types
|
||||
|
|
@ -483,7 +552,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
|
|||
&ty::ty_trait(ref b_)) => {
|
||||
debug!("Trying to match traits {} and {}", a, b);
|
||||
let principal = try!(this.binders(&a_.principal, &b_.principal));
|
||||
let bounds = try!(this.existential_bounds(a_.bounds, b_.bounds));
|
||||
let bounds = try!(this.existential_bounds(&a_.bounds, &b_.bounds));
|
||||
Ok(ty::mk_trait(tcx, principal, bounds))
|
||||
}
|
||||
|
||||
|
|
@ -581,6 +650,11 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
|
|||
})
|
||||
}
|
||||
|
||||
(&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => {
|
||||
let projection_ty = try!(this.projection_tys(a_data, b_data));
|
||||
Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
|
||||
}
|
||||
|
||||
_ => Err(ty::terr_sorts(expected_found(this, a, b)))
|
||||
};
|
||||
|
||||
|
|
@ -592,8 +666,8 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
|
|||
{
|
||||
try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
|
||||
match val {
|
||||
IntType(v) => Ok(ty::mk_mach_int(v)),
|
||||
UintType(v) => Ok(ty::mk_mach_uint(v))
|
||||
IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)),
|
||||
UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -604,7 +678,7 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
|
|||
val: ast::FloatTy) -> cres<'tcx, Ty<'tcx>>
|
||||
{
|
||||
try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
|
||||
Ok(ty::mk_mach_float(val))
|
||||
Ok(ty::mk_mach_float(this.tcx(), val))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -763,7 +837,7 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
|
|||
ty::ty_infer(ty::TyVar(vid)) => {
|
||||
if vid == self.for_vid {
|
||||
self.cycle_detected = true;
|
||||
ty::mk_err()
|
||||
self.tcx().types.err
|
||||
} else {
|
||||
match self.infcx.type_variables.borrow().probe(vid) {
|
||||
Some(u) => self.fold_ty(u),
|
||||
|
|
|
|||
|
|
@ -1437,6 +1437,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
format!(" for {}in generic type",
|
||||
bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
|
||||
}
|
||||
infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => {
|
||||
format!(" for {}in trait containing associated type `{}`",
|
||||
bound_region_to_string(self.tcx, "lifetime parameter ", true, br),
|
||||
token::get_name(type_name))
|
||||
}
|
||||
infer::EarlyBoundRegion(_, name) => {
|
||||
format!(" for lifetime parameter `{}`",
|
||||
token::get_name(name).get())
|
||||
|
|
@ -1661,13 +1666,16 @@ impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> {
|
|||
}
|
||||
}
|
||||
|
||||
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))
|
||||
impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> {
|
||||
fn resolve<'a>(&self,
|
||||
infcx: &InferCtxt<'a, 'tcx>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
infcx.resolve_type_vars_if_possible(self)
|
||||
}
|
||||
|
||||
fn contains_error(&self) -> bool {
|
||||
ty::trait_ref_contains_error(&self.0)
|
||||
ty::trait_ref_contains_error(&*self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
|||
ty::ty_struct(..) |
|
||||
ty::ty_unboxed_closure(..) |
|
||||
ty::ty_tup(..) |
|
||||
ty::ty_projection(..) |
|
||||
ty::ty_param(..) => {
|
||||
ty_fold::super_fold_ty(self, t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ pub enum 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>>>),
|
||||
PolyTraitRefs(ty::expected_found<ty::PolyTraitRef<'tcx>>),
|
||||
}
|
||||
|
||||
/// The trace designates the path through inference that we took to
|
||||
|
|
@ -231,6 +231,9 @@ pub enum LateBoundRegionConversionTime {
|
|||
|
||||
/// when two higher-ranked types are compared
|
||||
HigherRankedType,
|
||||
|
||||
/// when projecting an associated type
|
||||
AssocTypeProjection(ast::Name),
|
||||
}
|
||||
|
||||
/// Reasons to create a region inference variable
|
||||
|
|
@ -324,7 +327,7 @@ pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
|
|||
Ok(t) => t,
|
||||
Err(ref err) => {
|
||||
cx.report_and_explain_type_error(trace, err);
|
||||
ty::mk_err()
|
||||
cx.tcx.types.err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -407,8 +410,8 @@ pub fn mk_eqty<'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::PolyTraitRef<'tcx>>,
|
||||
b: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
a: ty::PolyTraitRef<'tcx>,
|
||||
b: ty::PolyTraitRef<'tcx>)
|
||||
-> ures<'tcx>
|
||||
{
|
||||
debug!("mk_sub_trait_refs({} <: {})",
|
||||
|
|
@ -703,8 +706,8 @@ 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>>)
|
||||
a: ty::PolyTraitRef<'tcx>,
|
||||
b: ty::PolyTraitRef<'tcx>)
|
||||
-> ures<'tcx>
|
||||
{
|
||||
debug!("sub_poly_trait_refs({} <: {})",
|
||||
|
|
@ -715,7 +718,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
origin: origin,
|
||||
values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
|
||||
};
|
||||
self.sub(a_is_expected, trace).binders(&*a, &*b).to_ures()
|
||||
self.sub(a_is_expected, trace).binders(&a, &b).to_ures()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -750,7 +753,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
-> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx>
|
||||
{
|
||||
/*! See `higher_ranked::leak_check` */
|
||||
/*! See `higher_ranked::plug_leaks` */
|
||||
|
||||
higher_ranked::plug_leaks(self, skol_map, snapshot, value)
|
||||
}
|
||||
|
|
@ -861,10 +864,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
let region_param_defs = generics.regions.get_slice(subst::TypeSpace);
|
||||
let regions = self.region_vars_for_defs(span, region_param_defs);
|
||||
|
||||
let assoc_type_parameter_count = generics.types.len(subst::AssocSpace);
|
||||
let assoc_type_parameters = self.next_ty_vars(assoc_type_parameter_count);
|
||||
|
||||
subst::Substs::new_trait(type_parameters, regions, assoc_type_parameters, self_ty)
|
||||
subst::Substs::new_trait(type_parameters, regions, self_ty)
|
||||
}
|
||||
|
||||
pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
|
||||
|
|
@ -1058,12 +1058,12 @@ impl<'tcx> TypeTrace<'tcx> {
|
|||
self.origin.span()
|
||||
}
|
||||
|
||||
pub fn dummy() -> TypeTrace<'tcx> {
|
||||
pub fn dummy(tcx: &ty::ctxt<'tcx>) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
origin: Misc(codemap::DUMMY_SP),
|
||||
values: Types(ty::expected_found {
|
||||
expected: ty::mk_err(),
|
||||
found: ty::mk_err(),
|
||||
expected: tcx.types.err,
|
||||
found: tcx.types.err,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,15 +83,15 @@ impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
|
|||
match t.sty {
|
||||
ty::ty_infer(ty::TyVar(vid)) => {
|
||||
self.err = Some(unresolved_ty(vid));
|
||||
ty::mk_err()
|
||||
self.tcx().types.err
|
||||
}
|
||||
ty::ty_infer(ty::IntVar(vid)) => {
|
||||
self.err = Some(unresolved_int_ty(vid));
|
||||
ty::mk_err()
|
||||
self.tcx().types.err
|
||||
}
|
||||
ty::ty_infer(ty::FloatVar(vid)) => {
|
||||
self.err = Some(unresolved_float_ty(vid));
|
||||
ty::mk_err()
|
||||
self.tcx().types.err
|
||||
}
|
||||
ty::ty_infer(_) => {
|
||||
self.infcx.tcx.sess.bug(
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
|
|||
}
|
||||
|
||||
(&ty::ty_err, _) | (_, &ty::ty_err) => {
|
||||
Ok(ty::mk_err())
|
||||
Ok(self.tcx().types.err)
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ impl<K,V> sv::SnapshotVecDelegate<VarValue<K,V>,()> for Delegate {
|
|||
/// Indicates a type that does not have any kind of subtyping
|
||||
/// relationship.
|
||||
pub trait SimplyUnifiable<'tcx> : Clone + PartialEq + Repr<'tcx> {
|
||||
fn to_type(&self) -> Ty<'tcx>;
|
||||
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
|
||||
fn to_type_err(expected_found<Self>) -> ty::type_err<'tcx>;
|
||||
}
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ impl<'a,'tcx,V:SimplyUnifiable<'tcx>,K:UnifyKey<'tcx, Option<V>>>
|
|||
let node_a = table.borrow_mut().get(tcx, a_id);
|
||||
match node_a.value {
|
||||
None => None,
|
||||
Some(ref a_t) => Some(a_t.to_type())
|
||||
Some(ref a_t) => Some(a_t.to_type(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -363,10 +363,10 @@ impl<'tcx> UnifyKey<'tcx, Option<IntVarValue>> for ty::IntVid {
|
|||
}
|
||||
|
||||
impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue {
|
||||
fn to_type(&self) -> Ty<'tcx> {
|
||||
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
|
||||
match *self {
|
||||
ty::IntType(i) => ty::mk_mach_int(i),
|
||||
ty::UintType(i) => ty::mk_mach_uint(i),
|
||||
ty::IntType(i) => ty::mk_mach_int(tcx, i),
|
||||
ty::UintType(i) => ty::mk_mach_uint(tcx, i),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -399,8 +399,8 @@ impl<'tcx> UnifyValue<'tcx> for Option<ast::FloatTy> {
|
|||
}
|
||||
|
||||
impl<'tcx> SimplyUnifiable<'tcx> for ast::FloatTy {
|
||||
fn to_type(&self) -> Ty<'tcx> {
|
||||
ty::mk_mach_float(*self)
|
||||
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
|
||||
ty::mk_mach_float(tcx, *self)
|
||||
}
|
||||
|
||||
fn to_type_err(err: expected_found<ast::FloatTy>) -> ty::type_err<'tcx> {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@
|
|||
|
||||
use metadata::csearch;
|
||||
use middle::def::DefFn;
|
||||
use middle::subst::Subst;
|
||||
use middle::subst::{Subst, Substs, EnumeratedItems};
|
||||
use middle::ty::{TransmuteRestriction, ctxt, ty_bare_fn};
|
||||
use middle::ty::{mod, Ty};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use syntax::abi::RustIntrinsic;
|
||||
use syntax::ast::DefId;
|
||||
|
|
@ -23,52 +24,31 @@ use syntax::parse::token;
|
|||
use syntax::visit::Visitor;
|
||||
use syntax::visit;
|
||||
|
||||
fn type_size_is_affected_by_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>, typ: Ty<'tcx>)
|
||||
-> bool {
|
||||
let mut result = false;
|
||||
ty::maybe_walk_ty(typ, |typ| {
|
||||
match typ.sty {
|
||||
ty::ty_uniq(_) | ty::ty_ptr(_) | ty::ty_rptr(..) |
|
||||
ty::ty_bare_fn(..) | ty::ty_closure(..) => {
|
||||
false
|
||||
}
|
||||
ty::ty_param(_) => {
|
||||
result = true;
|
||||
// No need to continue; we now know the result.
|
||||
false
|
||||
}
|
||||
ty::ty_enum(did, substs) => {
|
||||
for enum_variant in (*ty::enum_variants(tcx, did)).iter() {
|
||||
for argument_type in enum_variant.args.iter() {
|
||||
let argument_type = argument_type.subst(tcx, substs);
|
||||
result = result ||
|
||||
type_size_is_affected_by_type_parameters(
|
||||
tcx,
|
||||
argument_type);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't traverse substitutions.
|
||||
false
|
||||
}
|
||||
ty::ty_struct(did, substs) => {
|
||||
for field in ty::struct_fields(tcx, did, substs).iter() {
|
||||
result = result ||
|
||||
type_size_is_affected_by_type_parameters(tcx,
|
||||
field.mt.ty);
|
||||
}
|
||||
|
||||
// Don't traverse substitutions.
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
result
|
||||
pub fn check_crate(tcx: &ctxt) {
|
||||
let mut visitor = IntrinsicCheckingVisitor {
|
||||
tcx: tcx,
|
||||
param_envs: Vec::new(),
|
||||
dummy_sized_ty: tcx.types.int,
|
||||
dummy_unsized_ty: ty::mk_vec(tcx, tcx.types.int, None),
|
||||
};
|
||||
visit::walk_crate(&mut visitor, tcx.map.krate());
|
||||
}
|
||||
|
||||
struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
|
||||
tcx: &'a ctxt<'tcx>,
|
||||
|
||||
// As we traverse the AST, we keep a stack of the parameter
|
||||
// environments for each function we encounter. When we find a
|
||||
// call to `transmute`, we can check it in the context of the top
|
||||
// of the stack (which ought not to be empty).
|
||||
param_envs: Vec<ty::ParameterEnvironment<'tcx>>,
|
||||
|
||||
// Dummy sized/unsized types that use to substitute for type
|
||||
// parameters in order to estimate how big a type will be for any
|
||||
// possible instantiation of the type parameters in scope. See
|
||||
// `check_transmute` for more details.
|
||||
dummy_sized_ty: Ty<'tcx>,
|
||||
dummy_unsized_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
|
||||
|
|
@ -97,26 +77,175 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>, id: ast::NodeId) {
|
||||
if type_size_is_affected_by_type_parameters(self.tcx, from) {
|
||||
span_err!(self.tcx.sess, span, E0139,
|
||||
"cannot transmute from a type that contains type parameters");
|
||||
}
|
||||
if type_size_is_affected_by_type_parameters(self.tcx, to) {
|
||||
span_err!(self.tcx.sess, span, E0140,
|
||||
"cannot transmute to a type that contains type parameters");
|
||||
// Find the parameter environment for the most recent function that
|
||||
// we entered.
|
||||
|
||||
let param_env = match self.param_envs.last() {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
self.tcx.sess.span_bug(
|
||||
span,
|
||||
"transmute encountered outside of any fn");
|
||||
}
|
||||
};
|
||||
|
||||
// Simple case: no type parameters involved.
|
||||
if
|
||||
!ty::type_has_params(from) && !ty::type_has_self(from) &&
|
||||
!ty::type_has_params(to) && !ty::type_has_self(to)
|
||||
{
|
||||
let restriction = TransmuteRestriction {
|
||||
span: span,
|
||||
original_from: from,
|
||||
original_to: to,
|
||||
substituted_from: from,
|
||||
substituted_to: to,
|
||||
id: id,
|
||||
};
|
||||
self.push_transmute_restriction(restriction);
|
||||
return;
|
||||
}
|
||||
|
||||
let restriction = TransmuteRestriction {
|
||||
span: span,
|
||||
from: from,
|
||||
to: to,
|
||||
id: id,
|
||||
};
|
||||
// The rules around type parameters are a bit subtle. We are
|
||||
// checking these rules before monomorphization, so there may
|
||||
// be unsubstituted type parameters present in the
|
||||
// types. Obviously we cannot create LLVM types for those.
|
||||
// However, if a type parameter appears only indirectly (i.e.,
|
||||
// through a pointer), it does not necessarily affect the
|
||||
// size, so that should be allowed. The only catch is that we
|
||||
// DO want to be careful around unsized type parameters, since
|
||||
// fat pointers have a different size than a thin pointer, and
|
||||
// hence `&T` and `&U` have different sizes if `T : Sized` but
|
||||
// `U : Sized` does not hold.
|
||||
//
|
||||
// However, it's not as simple as checking whether `T :
|
||||
// Sized`, because even if `T : Sized` does not hold, that
|
||||
// just means that `T` *may* not be sized. After all, even a
|
||||
// type parameter `Sized? T` could be bound to a sized
|
||||
// type. (Issue #20116)
|
||||
//
|
||||
// To handle this, we first check for "interior" type
|
||||
// parameters, which are always illegal. If there are none of
|
||||
// those, then we know that the only way that all type
|
||||
// parameters `T` are referenced indirectly, e.g. via a
|
||||
// pointer type like `&T`. In that case, we only care whether
|
||||
// `T` is sized or not, because that influences whether `&T`
|
||||
// is a thin or fat pointer.
|
||||
//
|
||||
// One could imagine establishing a sophisticated constraint
|
||||
// system to ensure that the transmute is legal, but instead
|
||||
// we do something brutally dumb. We just substitute dummy
|
||||
// sized or unsized types for every type parameter in scope,
|
||||
// exhaustively checking all possible combinations. Here are some examples:
|
||||
//
|
||||
// ```
|
||||
// fn foo<T,U>() {
|
||||
// // T=int, U=int
|
||||
// }
|
||||
//
|
||||
// fn bar<Sized? T,U>() {
|
||||
// // T=int, U=int
|
||||
// // T=[int], U=int
|
||||
// }
|
||||
//
|
||||
// fn baz<Sized? T, Sized?U>() {
|
||||
// // T=int, U=int
|
||||
// // T=[int], U=int
|
||||
// // T=int, U=[int]
|
||||
// // T=[int], U=[int]
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// In all cases, we keep the original unsubstituted types
|
||||
// around for error reporting.
|
||||
|
||||
let from_tc = ty::type_contents(self.tcx, from);
|
||||
let to_tc = ty::type_contents(self.tcx, to);
|
||||
if from_tc.interior_param() || to_tc.interior_param() {
|
||||
span_err!(self.tcx.sess, span, E0139,
|
||||
"cannot transmute to or from a type that contains \
|
||||
type parameters in its interior");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut substs = param_env.free_substs.clone();
|
||||
self.with_each_combination(
|
||||
param_env,
|
||||
param_env.free_substs.types.iter_enumerated(),
|
||||
&mut substs,
|
||||
&mut |substs| {
|
||||
let restriction = TransmuteRestriction {
|
||||
span: span,
|
||||
original_from: from,
|
||||
original_to: to,
|
||||
substituted_from: from.subst(self.tcx, substs),
|
||||
substituted_to: to.subst(self.tcx, substs),
|
||||
id: id,
|
||||
};
|
||||
self.push_transmute_restriction(restriction);
|
||||
});
|
||||
}
|
||||
|
||||
fn with_each_combination(&self,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
mut types_in_scope: EnumeratedItems<Ty<'tcx>>,
|
||||
substs: &mut Substs<'tcx>,
|
||||
callback: &mut FnMut(&Substs<'tcx>))
|
||||
{
|
||||
// This parameter invokes `callback` many times with different
|
||||
// substitutions that replace all the parameters in scope with
|
||||
// either `int` or `[int]`, depending on whether the type
|
||||
// parameter is known to be sized. See big comment above for
|
||||
// an explanation of why this is a reasonable thing to do.
|
||||
|
||||
match types_in_scope.next() {
|
||||
None => {
|
||||
debug!("with_each_combination(substs={})",
|
||||
substs.repr(self.tcx));
|
||||
|
||||
callback.call_mut((substs,));
|
||||
}
|
||||
|
||||
Some((space, index, ¶m_ty)) => {
|
||||
debug!("with_each_combination: space={}, index={}, param_ty={}",
|
||||
space, index, param_ty.repr(self.tcx));
|
||||
|
||||
if !ty::type_is_sized(self.tcx, param_ty, param_env) {
|
||||
debug!("with_each_combination: param_ty is not known to be sized");
|
||||
|
||||
substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;
|
||||
self.with_each_combination(param_env, types_in_scope.clone(), substs, callback);
|
||||
}
|
||||
|
||||
substs.types.get_mut_slice(space)[index] = self.dummy_sized_ty;
|
||||
self.with_each_combination(param_env, types_in_scope, substs, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_transmute_restriction(&self, restriction: TransmuteRestriction<'tcx>) {
|
||||
debug!("Pushing transmute restriction: {}", restriction.repr(self.tcx));
|
||||
self.tcx.transmute_restrictions.borrow_mut().push(restriction);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
|
||||
fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
|
||||
b: &'v ast::Block, s: Span, id: ast::NodeId) {
|
||||
match fk {
|
||||
visit::FkItemFn(..) | visit::FkMethod(..) => {
|
||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
|
||||
self.param_envs.push(param_env);
|
||||
visit::walk_fn(self, fk, fd, b, s);
|
||||
self.param_envs.pop();
|
||||
}
|
||||
visit::FkFnBlock(..) => {
|
||||
visit::walk_fn(self, fk, fd, b, s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &ast::Expr) {
|
||||
if let ast::ExprPath(..) = expr.node {
|
||||
match ty::resolve_expr(self.tcx, expr) {
|
||||
|
|
@ -144,7 +273,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_crate(tcx: &ctxt) {
|
||||
visit::walk_crate(&mut IntrinsicCheckingVisitor { tcx: tcx },
|
||||
tcx.map.krate());
|
||||
impl<'tcx> Repr<'tcx> for TransmuteRestriction<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
format!("TransmuteRestriction(id={}, original=({},{}), substituted=({},{}))",
|
||||
self.id,
|
||||
self.original_from.repr(tcx),
|
||||
self.original_to.repr(tcx),
|
||||
self.substituted_from.repr(tcx),
|
||||
self.substituted_to.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -755,7 +755,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
// instead of bothering to construct a proper
|
||||
// one.
|
||||
base.mutbl = McImmutable;
|
||||
base.ty = ty::mk_err();
|
||||
base.ty = self.tcx().types.err;
|
||||
Rc::new(cmt_ {
|
||||
id: id,
|
||||
span: span,
|
||||
|
|
@ -781,7 +781,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
is_unboxed: is_unboxed
|
||||
}),
|
||||
mutbl: McImmutable,
|
||||
ty: ty::mk_err(),
|
||||
ty: self.tcx().types.err,
|
||||
note: NoteNone
|
||||
};
|
||||
|
||||
|
|
@ -792,7 +792,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
span: span,
|
||||
cat: cat_deref(Rc::new(base), 0, env_ptr),
|
||||
mutbl: env_mutbl,
|
||||
ty: ty::mk_err(),
|
||||
ty: self.tcx().types.err,
|
||||
note: NoteClosureEnv(upvar_id)
|
||||
};
|
||||
}
|
||||
|
|
@ -987,7 +987,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
ty::ty_fn_args(method_ty)[0]
|
||||
}
|
||||
None => {
|
||||
match ty::array_element_ty(base_cmt.ty) {
|
||||
match ty::array_element_ty(self.tcx(), base_cmt.ty) {
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
self.tcx().sess.span_bug(
|
||||
|
|
|
|||
|
|
@ -55,18 +55,17 @@ impl<'tcx> Substs<'tcx> {
|
|||
r: Vec<ty::Region>)
|
||||
-> Substs<'tcx>
|
||||
{
|
||||
Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new(), Vec::new()),
|
||||
VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new()))
|
||||
Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()),
|
||||
VecPerParamSpace::new(r, Vec::new(), Vec::new()))
|
||||
}
|
||||
|
||||
pub fn new_trait(t: Vec<Ty<'tcx>>,
|
||||
r: Vec<ty::Region>,
|
||||
a: Vec<Ty<'tcx>>,
|
||||
s: Ty<'tcx>)
|
||||
-> Substs<'tcx>
|
||||
{
|
||||
Substs::new(VecPerParamSpace::new(t, vec!(s), a, Vec::new()),
|
||||
VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new()))
|
||||
Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()),
|
||||
VecPerParamSpace::new(r, Vec::new(), Vec::new()))
|
||||
}
|
||||
|
||||
pub fn erased(t: VecPerParamSpace<Ty<'tcx>>) -> Substs<'tcx>
|
||||
|
|
@ -123,13 +122,6 @@ impl<'tcx> Substs<'tcx> {
|
|||
s
|
||||
}
|
||||
|
||||
pub fn with_assoc_tys(&self, assoc_tys: Vec<Ty<'tcx>>) -> Substs<'tcx> {
|
||||
assert!(self.types.is_empty_in(AssocSpace));
|
||||
let mut s = (*self).clone();
|
||||
s.types.replace(AssocSpace, assoc_tys);
|
||||
s
|
||||
}
|
||||
|
||||
pub fn erase_regions(self) -> Substs<'tcx> {
|
||||
let Substs { types, regions: _ } = self;
|
||||
Substs { types: types, regions: ErasedRegions }
|
||||
|
|
@ -192,21 +184,19 @@ impl RegionSubsts {
|
|||
pub enum ParamSpace {
|
||||
TypeSpace, // Type parameters attached to a type definition, trait, or impl
|
||||
SelfSpace, // Self parameter on a trait
|
||||
AssocSpace, // Assoc types defined in a trait/impl
|
||||
FnSpace, // Type parameters attached to a method or fn
|
||||
}
|
||||
|
||||
impl ParamSpace {
|
||||
pub fn all() -> [ParamSpace, ..4] {
|
||||
[TypeSpace, SelfSpace, AssocSpace, FnSpace]
|
||||
pub fn all() -> [ParamSpace, ..3] {
|
||||
[TypeSpace, SelfSpace, FnSpace]
|
||||
}
|
||||
|
||||
pub fn to_uint(self) -> uint {
|
||||
match self {
|
||||
TypeSpace => 0,
|
||||
SelfSpace => 1,
|
||||
AssocSpace => 2,
|
||||
FnSpace => 3,
|
||||
FnSpace => 2,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -214,8 +204,7 @@ impl ParamSpace {
|
|||
match u {
|
||||
0 => TypeSpace,
|
||||
1 => SelfSpace,
|
||||
2 => AssocSpace,
|
||||
3 => FnSpace,
|
||||
2 => FnSpace,
|
||||
_ => panic!("Invalid ParamSpace: {}", u)
|
||||
}
|
||||
}
|
||||
|
|
@ -235,11 +224,9 @@ pub struct VecPerParamSpace<T> {
|
|||
//
|
||||
// AF(self) = (self.content[..self.type_limit],
|
||||
// self.content[self.type_limit..self.self_limit],
|
||||
// self.content[self.self_limit..self.assoc_limit],
|
||||
// self.content[self.assoc_limit..])
|
||||
// self.content[self.self_limit..])
|
||||
type_limit: uint,
|
||||
self_limit: uint,
|
||||
assoc_limit: uint,
|
||||
content: Vec<T>,
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +235,6 @@ pub struct VecPerParamSpace<T> {
|
|||
pub struct SeparateVecsPerParamSpace<T> {
|
||||
pub types: Vec<T>,
|
||||
pub selfs: Vec<T>,
|
||||
pub assocs: Vec<T>,
|
||||
pub fns: Vec<T>,
|
||||
}
|
||||
|
||||
|
|
@ -268,8 +254,7 @@ impl<T> VecPerParamSpace<T> {
|
|||
match space {
|
||||
TypeSpace => (0, self.type_limit),
|
||||
SelfSpace => (self.type_limit, self.self_limit),
|
||||
AssocSpace => (self.self_limit, self.assoc_limit),
|
||||
FnSpace => (self.assoc_limit, self.content.len()),
|
||||
FnSpace => (self.self_limit, self.content.len()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -277,7 +262,6 @@ impl<T> VecPerParamSpace<T> {
|
|||
VecPerParamSpace {
|
||||
type_limit: 0,
|
||||
self_limit: 0,
|
||||
assoc_limit: 0,
|
||||
content: Vec::new()
|
||||
}
|
||||
}
|
||||
|
|
@ -290,31 +274,27 @@ impl<T> VecPerParamSpace<T> {
|
|||
/// `s` is the self space.
|
||||
/// `a` is the assoc space.
|
||||
/// `f` is the fn space.
|
||||
pub fn new(t: Vec<T>, s: Vec<T>, a: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
|
||||
pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
|
||||
let type_limit = t.len();
|
||||
let self_limit = type_limit + s.len();
|
||||
let assoc_limit = self_limit + a.len();
|
||||
|
||||
let mut content = t;
|
||||
content.extend(s.into_iter());
|
||||
content.extend(a.into_iter());
|
||||
content.extend(f.into_iter());
|
||||
|
||||
VecPerParamSpace {
|
||||
type_limit: type_limit,
|
||||
self_limit: self_limit,
|
||||
assoc_limit: assoc_limit,
|
||||
content: content,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint, assoc_limit: uint)
|
||||
fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint)
|
||||
-> VecPerParamSpace<T>
|
||||
{
|
||||
VecPerParamSpace {
|
||||
type_limit: type_limit,
|
||||
self_limit: self_limit,
|
||||
assoc_limit: assoc_limit,
|
||||
content: content,
|
||||
}
|
||||
}
|
||||
|
|
@ -326,9 +306,8 @@ impl<T> VecPerParamSpace<T> {
|
|||
pub fn push(&mut self, space: ParamSpace, value: T) {
|
||||
let (_, limit) = self.limits(space);
|
||||
match space {
|
||||
TypeSpace => { self.type_limit += 1; self.self_limit += 1; self.assoc_limit += 1; }
|
||||
SelfSpace => { self.self_limit += 1; self.assoc_limit += 1; }
|
||||
AssocSpace => { self.assoc_limit += 1; }
|
||||
TypeSpace => { self.type_limit += 1; self.self_limit += 1; }
|
||||
SelfSpace => { self.self_limit += 1; }
|
||||
FnSpace => { }
|
||||
}
|
||||
self.content.insert(limit, value);
|
||||
|
|
@ -340,9 +319,8 @@ impl<T> VecPerParamSpace<T> {
|
|||
None
|
||||
} else {
|
||||
match space {
|
||||
TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; self.assoc_limit -= 1; }
|
||||
SelfSpace => { self.self_limit -= 1; self.assoc_limit -= 1; }
|
||||
AssocSpace => { self.assoc_limit -= 1; }
|
||||
TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; }
|
||||
SelfSpace => { self.self_limit -= 1; }
|
||||
FnSpace => {}
|
||||
}
|
||||
self.content.remove(limit - 1)
|
||||
|
|
@ -412,6 +390,10 @@ impl<T> VecPerParamSpace<T> {
|
|||
self.content.as_slice()
|
||||
}
|
||||
|
||||
pub fn to_vec(self) -> Vec<T> {
|
||||
self.content
|
||||
}
|
||||
|
||||
pub fn all_vecs<P>(&self, mut pred: P) -> bool where
|
||||
P: FnMut(&[T]) -> bool,
|
||||
{
|
||||
|
|
@ -435,8 +417,7 @@ impl<T> VecPerParamSpace<T> {
|
|||
let result = self.iter().map(pred).collect();
|
||||
VecPerParamSpace::new_internal(result,
|
||||
self.type_limit,
|
||||
self.self_limit,
|
||||
self.assoc_limit)
|
||||
self.self_limit)
|
||||
}
|
||||
|
||||
pub fn map_enumerated<U, P>(&self, pred: P) -> VecPerParamSpace<U> where
|
||||
|
|
@ -445,8 +426,7 @@ impl<T> VecPerParamSpace<T> {
|
|||
let result = self.iter_enumerated().map(pred).collect();
|
||||
VecPerParamSpace::new_internal(result,
|
||||
self.type_limit,
|
||||
self.self_limit,
|
||||
self.assoc_limit)
|
||||
self.self_limit)
|
||||
}
|
||||
|
||||
pub fn map_move<U, F>(self, mut pred: F) -> VecPerParamSpace<U> where
|
||||
|
|
@ -455,25 +435,22 @@ impl<T> VecPerParamSpace<T> {
|
|||
let SeparateVecsPerParamSpace {
|
||||
types: t,
|
||||
selfs: s,
|
||||
assocs: a,
|
||||
fns: f
|
||||
} = self.split();
|
||||
|
||||
VecPerParamSpace::new(t.into_iter().map(|p| pred(p)).collect(),
|
||||
s.into_iter().map(|p| pred(p)).collect(),
|
||||
a.into_iter().map(|p| pred(p)).collect(),
|
||||
f.into_iter().map(|p| pred(p)).collect())
|
||||
}
|
||||
|
||||
pub fn split(self) -> SeparateVecsPerParamSpace<T> {
|
||||
let VecPerParamSpace { type_limit, self_limit, assoc_limit, content } = self;
|
||||
let VecPerParamSpace { type_limit, self_limit, content } = self;
|
||||
|
||||
let mut content_iter = content.into_iter();
|
||||
|
||||
SeparateVecsPerParamSpace {
|
||||
types: content_iter.by_ref().take(type_limit).collect(),
|
||||
selfs: content_iter.by_ref().take(self_limit - type_limit).collect(),
|
||||
assocs: content_iter.by_ref().take(assoc_limit - self_limit).collect(),
|
||||
fns: content_iter.collect()
|
||||
}
|
||||
}
|
||||
|
|
@ -487,6 +464,7 @@ impl<T> VecPerParamSpace<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct EnumeratedItems<'a,T:'a> {
|
||||
vec: &'a VecPerParamSpace<T>,
|
||||
space_index: uint,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
|
|||
let param_env = ty::empty_parameter_environment();
|
||||
let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx);
|
||||
let obligation = Obligation::new(ObligationCause::dummy(),
|
||||
Rc::new(ty::Binder(impl1_trait_ref)));
|
||||
ty::Binder(ty::TraitPredicate {
|
||||
trait_ref: Rc::new(impl1_trait_ref),
|
||||
}));
|
||||
debug!("impl_can_satisfy(obligation={})", obligation.repr(infcx.tcx));
|
||||
selcx.evaluate_impl(impl2_def_id, &obligation)
|
||||
}
|
||||
|
|
@ -140,7 +142,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
|
||||
|
|
@ -149,6 +151,11 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
// Associated types could be anything, I guess.
|
||||
ty::ty_projection(..) => {
|
||||
false
|
||||
}
|
||||
|
||||
ty::ty_infer(..) |
|
||||
ty::ty_open(..) |
|
||||
ty::ty_err => {
|
||||
|
|
|
|||
|
|
@ -8,12 +8,18 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::{FulfillmentError, FulfillmentErrorCode,
|
||||
ObligationCauseCode, SelectionError,
|
||||
PredicateObligation, OutputTypeParameterMismatch};
|
||||
use super::{
|
||||
FulfillmentError,
|
||||
FulfillmentErrorCode,
|
||||
MismatchedProjectionTypes,
|
||||
ObligationCauseCode,
|
||||
OutputTypeParameterMismatch,
|
||||
PredicateObligation,
|
||||
SelectionError,
|
||||
};
|
||||
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::ty::{mod};
|
||||
use middle::ty::{mod, AsPredicate, ReferencesError, ToPolyTraitRef};
|
||||
use syntax::codemap::Span;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
|
|
@ -30,12 +36,32 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
FulfillmentErrorCode::CodeSelectionError(ref e) => {
|
||||
report_selection_error(infcx, &error.obligation, e);
|
||||
}
|
||||
FulfillmentErrorCode::CodeProjectionError(ref e) => {
|
||||
report_projection_error(infcx, &error.obligation, e);
|
||||
}
|
||||
FulfillmentErrorCode::CodeAmbiguity => {
|
||||
maybe_report_ambiguity(infcx, &error.obligation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
error: &MismatchedProjectionTypes<'tcx>)
|
||||
{
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
if !predicate.references_error() {
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"type mismatch resolving `{}`: {}",
|
||||
predicate.user_string(infcx.tcx),
|
||||
ty::type_err_to_str(infcx.tcx, &error.err)).as_slice());
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
error: &SelectionError<'tcx>)
|
||||
|
|
@ -43,38 +69,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
match *error {
|
||||
SelectionError::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 =
|
||||
infcx.resolve_type_vars_if_possible(&**trait_ref);
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"overflow evaluating the trait `{}` for the type `{}`",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
trait_ref.self_ty().user_string(infcx.tcx))[]);
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(ref predicate) => {
|
||||
let predicate = infcx.resolve_type_vars_if_possible(predicate);
|
||||
let err = infcx.equality_predicate(obligation.cause.span,
|
||||
&predicate).unwrap_err();
|
||||
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the requirement `{}` is not satisfied (`{}`)",
|
||||
predicate.user_string(infcx.tcx),
|
||||
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!("overflow evaluating lifetime predicate").as_slice());
|
||||
}
|
||||
}
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"overflow evaluating the requirement `{}`",
|
||||
predicate.user_string(infcx.tcx)).as_slice());
|
||||
|
||||
let current_limit = infcx.tcx.sess.recursion_limit.get();
|
||||
let suggested_limit = current_limit * 2;
|
||||
|
|
@ -87,27 +88,25 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
SelectionError::Unimplemented => {
|
||||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(
|
||||
&**trait_ref);
|
||||
if !ty::type_is_error(trait_ref.self_ty()) {
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
let trait_predicate =
|
||||
infcx.resolve_type_vars_if_possible(trait_predicate);
|
||||
if !trait_predicate.references_error() {
|
||||
let trait_ref = trait_predicate.to_poly_trait_ref();
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the trait `{}` is not implemented for the type `{}`",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
trait_ref.self_ty().user_string(infcx.tcx)).as_slice());
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::Equate(ref predicate) => {
|
||||
let predicate = infcx.resolve_type_vars_if_possible(predicate);
|
||||
let err = infcx.equality_predicate(obligation.cause.span,
|
||||
&predicate).unwrap_err();
|
||||
|
||||
&predicate).unwrap_err();
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
|
|
@ -116,9 +115,22 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
let predicate = infcx.resolve_type_vars_if_possible(&obligation.trait_ref);
|
||||
ty::Predicate::RegionOutlives(ref predicate) => {
|
||||
let predicate = infcx.resolve_type_vars_if_possible(predicate);
|
||||
let err = infcx.region_outlives_predicate(obligation.cause.span,
|
||||
&predicate).unwrap_err();
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"the requirement `{}` is not satisfied (`{}`)",
|
||||
predicate.user_string(infcx.tcx),
|
||||
ty::type_err_to_str(infcx.tcx, &err)).as_slice());
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
let predicate =
|
||||
infcx.resolve_type_vars_if_possible(&obligation.predicate);
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
|
|
@ -128,12 +140,8 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
|
||||
let expected_trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(
|
||||
&**expected_trait_ref);
|
||||
let actual_trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(
|
||||
&**actual_trait_ref);
|
||||
let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref);
|
||||
let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref);
|
||||
if !ty::type_is_error(actual_trait_ref.self_ty()) {
|
||||
infcx.tcx.sess.span_err(
|
||||
obligation.cause.span,
|
||||
|
|
@ -150,24 +158,26 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>) {
|
||||
pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>) {
|
||||
// Unable to successfully determine, probably means
|
||||
// insufficient type information, but could mean
|
||||
// ambiguous impls. The latter *ought* to be a
|
||||
// coherence violation, so we don't report it here.
|
||||
|
||||
let trait_ref = match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
infcx.resolve_type_vars_if_possible(&**trait_ref)
|
||||
let trait_ref = match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
infcx.resolve_type_vars_if_possible(
|
||||
&trait_predicate.to_poly_trait_ref())
|
||||
}
|
||||
_ => {
|
||||
infcx.tcx.sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("ambiguity from something other than a trait: {}",
|
||||
obligation.trait_ref.repr(infcx.tcx)).as_slice());
|
||||
obligation.predicate.repr(infcx.tcx)).as_slice());
|
||||
}
|
||||
};
|
||||
|
||||
let self_ty = trait_ref.self_ty();
|
||||
|
||||
debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
|
||||
|
|
@ -208,7 +218,7 @@ fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
locate the impl of the trait `{}` for \
|
||||
the type `{}`; type annotations required",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
self_ty.user_string(infcx.tcx))[]);
|
||||
self_ty.user_string(infcx.tcx)).as_slice());
|
||||
note_obligation_cause(infcx, obligation);
|
||||
}
|
||||
}
|
||||
|
|
@ -221,56 +231,38 @@ fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
cannot locate the impl of the trait `{}` for \
|
||||
the type `{}`",
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
self_ty.user_string(infcx.tcx))[]);
|
||||
self_ty.user_string(infcx.tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
fn note_obligation_cause<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
{
|
||||
let trait_ref = match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
infcx.resolve_type_vars_if_possible(&**trait_ref)
|
||||
}
|
||||
_ => {
|
||||
infcx.tcx.sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("ambiguity from something other than a trait: {}",
|
||||
obligation.trait_ref.repr(infcx.tcx)).as_slice());
|
||||
}
|
||||
};
|
||||
|
||||
note_obligation_cause_code(infcx,
|
||||
&trait_ref,
|
||||
&obligation.predicate,
|
||||
obligation.cause.span,
|
||||
&obligation.cause.code)
|
||||
&obligation.cause.code);
|
||||
}
|
||||
|
||||
fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
_predicate: &ty::Predicate<'tcx>,
|
||||
cause_span: Span,
|
||||
cause_code: &ObligationCauseCode<'tcx>)
|
||||
{
|
||||
let tcx = infcx.tcx;
|
||||
let trait_name = ty::item_path_str(tcx, trait_ref.def_id());
|
||||
match *cause_code {
|
||||
ObligationCauseCode::MiscObligation => { }
|
||||
ObligationCauseCode::ItemObligation(item_def_id) => {
|
||||
let item_name = ty::item_path_str(tcx, item_def_id);
|
||||
tcx.sess.span_note(
|
||||
cause_span,
|
||||
format!(
|
||||
"the trait `{}` must be implemented because it is required by `{}`",
|
||||
trait_name,
|
||||
item_name).as_slice());
|
||||
format!("required by `{}`", item_name).as_slice());
|
||||
}
|
||||
ObligationCauseCode::ObjectCastObligation(object_ty) => {
|
||||
tcx.sess.span_note(
|
||||
cause_span,
|
||||
format!(
|
||||
"the trait `{}` must be implemented for the cast \
|
||||
to the object type `{}`",
|
||||
trait_name,
|
||||
"required for the cast to the object type `{}`",
|
||||
infcx.ty_to_string(object_ty)).as_slice());
|
||||
}
|
||||
ObligationCauseCode::RepeatVec => {
|
||||
|
|
@ -323,27 +315,23 @@ fn note_obligation_cause_code<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
span_note!(tcx.sess, cause_span,
|
||||
"shared static variables must have a type that implements `Sync`");
|
||||
}
|
||||
ObligationCauseCode::BuiltinDerivedObligation(ref root_trait_ref, ref root_cause_code) => {
|
||||
let root_trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(&**root_trait_ref);
|
||||
ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
|
||||
let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
|
||||
span_note!(tcx.sess, cause_span,
|
||||
"the type `{}` must implement `{}` because it appears within the type `{}`",
|
||||
trait_ref.self_ty().user_string(infcx.tcx),
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
root_trait_ref.self_ty().user_string(infcx.tcx));
|
||||
note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code);
|
||||
"required because it appears within the type `{}`",
|
||||
parent_trait_ref.0.self_ty().user_string(infcx.tcx));
|
||||
let parent_predicate = parent_trait_ref.as_predicate();
|
||||
note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
|
||||
}
|
||||
ObligationCauseCode::ImplDerivedObligation(ref root_trait_ref, ref root_cause_code) => {
|
||||
let root_trait_ref =
|
||||
infcx.resolve_type_vars_if_possible(&**root_trait_ref);
|
||||
ObligationCauseCode::ImplDerivedObligation(ref data) => {
|
||||
let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
|
||||
span_note!(tcx.sess, cause_span,
|
||||
"the type `{}` must implement `{}` due to the requirements \
|
||||
on the impl of `{}` for the type `{}`",
|
||||
trait_ref.self_ty().user_string(infcx.tcx),
|
||||
trait_ref.user_string(infcx.tcx),
|
||||
root_trait_ref.user_string(infcx.tcx),
|
||||
root_trait_ref.self_ty().user_string(infcx.tcx));
|
||||
note_obligation_cause_code(infcx, &root_trait_ref, cause_span, &**root_cause_code);
|
||||
"required because of the requirements on the impl of `{}` for `{}`",
|
||||
parent_trait_ref.user_string(infcx.tcx),
|
||||
parent_trait_ref.0.self_ty().user_string(infcx.tcx));
|
||||
let parent_predicate = parent_trait_ref.as_predicate();
|
||||
note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,28 +8,28 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::infer::{mod, InferCtxt};
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, AsPredicate, RegionEscape, Ty, ToPolyTraitRef};
|
||||
use std::collections::HashSet;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use std::default::Default;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use util::common::ErrorReported;
|
||||
use util::ppaux::Repr;
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
use super::CodeAmbiguity;
|
||||
use super::CodeProjectionError;
|
||||
use super::CodeSelectionError;
|
||||
use super::FulfillmentError;
|
||||
use super::Obligation;
|
||||
use super::ObligationCause;
|
||||
use super::PredicateObligation;
|
||||
use super::Selection;
|
||||
use super::project;
|
||||
use super::select::SelectionContext;
|
||||
use super::poly_trait_ref_for_builtin_bound;
|
||||
use super::Unimplemented;
|
||||
use super::util::predicate_for_builtin_bound;
|
||||
|
||||
/// The fulfillment context is used to drive trait resolution. It
|
||||
/// consists of a list of obligations that must be (eventually)
|
||||
|
|
@ -101,55 +101,74 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn register_builtin_bound(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
cause: ObligationCause<'tcx>)
|
||||
/// "Normalize" a projection type `<SomeType as SomeTrait>::X` by
|
||||
/// creating a fresh type variable `$0` as well as a projection
|
||||
/// predicate `<SomeType as SomeTrait>::X == $0`. When the
|
||||
/// inference engine runs, it will attempt to find an impl of
|
||||
/// `SomeTrait` or a where clause that lets us unify `$0` with
|
||||
/// something concrete. If this fails, we'll unify `$0` with
|
||||
/// `projection_ty` again.
|
||||
pub fn normalize_projection_type<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
cause: ObligationCause<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
match poly_trait_ref_for_builtin_bound(tcx, builtin_bound, ty) {
|
||||
Ok(trait_ref) => {
|
||||
self.register_trait_ref(tcx, trait_ref, cause);
|
||||
debug!("normalize_associated_type(projection_ty={})",
|
||||
projection_ty.repr(infcx.tcx));
|
||||
|
||||
assert!(!projection_ty.has_escaping_regions());
|
||||
|
||||
// FIXME(#20304) -- cache
|
||||
|
||||
let ty_var = infcx.next_ty_var();
|
||||
let projection =
|
||||
ty::Binder(ty::ProjectionPredicate {
|
||||
projection_ty: projection_ty,
|
||||
ty: ty_var
|
||||
});
|
||||
let obligation = Obligation::new(cause, projection.as_predicate());
|
||||
self.register_predicate(infcx, obligation);
|
||||
|
||||
debug!("normalize_associated_type: result={}", ty_var.repr(infcx.tcx));
|
||||
|
||||
ty_var
|
||||
}
|
||||
|
||||
pub fn register_builtin_bound<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
cause: ObligationCause<'tcx>)
|
||||
{
|
||||
match predicate_for_builtin_bound(infcx.tcx, cause, builtin_bound, 0, ty) {
|
||||
Ok(predicate) => {
|
||||
self.register_predicate(infcx, predicate);
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_trait_ref<'a>(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
cause: ObligationCause<'tcx>)
|
||||
pub fn register_region_obligation<'a>(&mut self,
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
t_a: Ty<'tcx>,
|
||||
r_b: ty::Region,
|
||||
cause: ObligationCause<'tcx>)
|
||||
{
|
||||
/*!
|
||||
* A convenience function for registering trait obligations.
|
||||
*/
|
||||
|
||||
let trait_obligation = Obligation { cause: cause,
|
||||
recursion_depth: 0,
|
||||
trait_ref: ty::Predicate::Trait(trait_ref) };
|
||||
self.register_predicate(tcx, trait_obligation)
|
||||
}
|
||||
|
||||
pub fn register_region_obligation(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
t_a: Ty<'tcx>,
|
||||
r_b: ty::Region,
|
||||
cause: ObligationCause<'tcx>)
|
||||
{
|
||||
register_region_obligation(tcx, t_a, r_b, cause, &mut self.region_obligations);
|
||||
register_region_obligation(infcx.tcx, t_a, r_b, cause, &mut self.region_obligations);
|
||||
}
|
||||
|
||||
pub fn register_predicate<'a>(&mut self,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
predicate: PredicateObligation<'tcx>)
|
||||
infcx: &InferCtxt<'a,'tcx>,
|
||||
obligation: PredicateObligation<'tcx>)
|
||||
{
|
||||
if !self.duplicate_set.insert(predicate.trait_ref.clone()) {
|
||||
debug!("register_predicate({}) -- already seen, skip", predicate.repr(tcx));
|
||||
if !self.duplicate_set.insert(obligation.predicate.clone()) {
|
||||
debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("register_predicate({})", predicate.repr(tcx));
|
||||
self.predicates.push(predicate);
|
||||
debug!("register_predicate({})", obligation.repr(infcx.tcx));
|
||||
self.predicates.push(obligation);
|
||||
}
|
||||
|
||||
pub fn region_obligations(&self,
|
||||
|
|
@ -223,7 +242,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
self.predicates.len(),
|
||||
only_new_obligations);
|
||||
|
||||
let tcx = selcx.tcx();
|
||||
let mut errors = Vec::new();
|
||||
|
||||
loop {
|
||||
|
|
@ -232,7 +250,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
debug!("select_where_possible({} obligations) iteration",
|
||||
count);
|
||||
|
||||
let mut selections = Vec::new();
|
||||
let mut new_obligations = Vec::new();
|
||||
|
||||
// If we are only attempting obligations we haven't seen yet,
|
||||
// then set `skip` to the number of obligations we've already
|
||||
|
|
@ -253,7 +271,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
let processed =
|
||||
if skip == 0 {
|
||||
process_predicate(selcx, predicate,
|
||||
&mut selections, &mut errors, region_obligations)
|
||||
&mut new_obligations, &mut errors, region_obligations)
|
||||
} else {
|
||||
skip -= 1;
|
||||
false
|
||||
|
|
@ -271,8 +289,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
|
||||
// Now go through all the successful ones,
|
||||
// registering any nested obligations for the future.
|
||||
for selection in selections.into_iter() {
|
||||
selection.map_move_nested(|p| self.register_predicate(tcx, p));
|
||||
for new_obligation in new_obligations.into_iter() {
|
||||
self.register_predicate(selcx.infcx(), new_obligation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,8 +307,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
|
|||
}
|
||||
|
||||
fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
||||
predicate: &PredicateObligation<'tcx>,
|
||||
selections: &mut Vec<Selection<'tcx>>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
new_obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||
errors: &mut Vec<FulfillmentError<'tcx>>,
|
||||
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
|
||||
-> bool
|
||||
|
|
@ -303,26 +321,24 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
|||
*/
|
||||
|
||||
let tcx = selcx.tcx();
|
||||
match predicate.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_obligation = Obligation { cause: predicate.cause.clone(),
|
||||
recursion_depth: predicate.recursion_depth,
|
||||
trait_ref: trait_ref.clone() };
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
let trait_obligation = obligation.with(data.clone());
|
||||
match selcx.select(&trait_obligation) {
|
||||
Ok(None) => {
|
||||
false
|
||||
}
|
||||
Ok(Some(s)) => {
|
||||
selections.push(s);
|
||||
s.map_move_nested(|p| new_obligations.push(p));
|
||||
true
|
||||
}
|
||||
Err(selection_err) => {
|
||||
debug!("predicate: {} error: {}",
|
||||
predicate.repr(tcx),
|
||||
obligation.repr(tcx),
|
||||
selection_err.repr(tcx));
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
predicate.clone(),
|
||||
obligation.clone(),
|
||||
CodeSelectionError(selection_err)));
|
||||
true
|
||||
}
|
||||
|
|
@ -330,12 +346,12 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
|||
}
|
||||
|
||||
ty::Predicate::Equate(ref binder) => {
|
||||
match selcx.infcx().equality_predicate(predicate.cause.span, binder) {
|
||||
match selcx.infcx().equality_predicate(obligation.cause.span, binder) {
|
||||
Ok(()) => { }
|
||||
Err(_) => {
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
predicate.clone(),
|
||||
obligation.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
}
|
||||
}
|
||||
|
|
@ -343,12 +359,12 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
|||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref binder) => {
|
||||
match selcx.infcx().region_outlives_predicate(predicate.cause.span, binder) {
|
||||
match selcx.infcx().region_outlives_predicate(obligation.cause.span, binder) {
|
||||
Ok(()) => { }
|
||||
Err(_) => {
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
predicate.clone(),
|
||||
obligation.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
}
|
||||
}
|
||||
|
|
@ -364,16 +380,126 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
|
|||
if ty::count_late_bound_regions(selcx.tcx(), binder) != 0 {
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
predicate.clone(),
|
||||
obligation.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
} else {
|
||||
let ty::OutlivesPredicate(t_a, r_b) = binder.0;
|
||||
register_region_obligation(tcx, t_a, r_b,
|
||||
predicate.cause.clone(),
|
||||
obligation.cause.clone(),
|
||||
region_obligations);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
let project_obligation = obligation.with(data.clone());
|
||||
let result = project::poly_project_and_unify_type(selcx, &project_obligation);
|
||||
debug!("poly_project_and_unify_type({}) = {}",
|
||||
project_obligation.repr(tcx),
|
||||
result.repr(tcx));
|
||||
match result {
|
||||
Ok(()) => {
|
||||
true
|
||||
}
|
||||
Err(project::ProjectionError::TooManyCandidates) => {
|
||||
// Without more type information, we can't say much.
|
||||
false
|
||||
}
|
||||
Err(project::ProjectionError::NoCandidate) => {
|
||||
// This means that we have a type like `<T as
|
||||
// Trait>::name = U` but we couldn't find any more
|
||||
// information. This could just be that we're in a
|
||||
// function like:
|
||||
//
|
||||
// fn foo<T:Trait>(...)
|
||||
//
|
||||
// in which case this is not an error. But it
|
||||
// might also mean we're in a situation where we
|
||||
// don't actually know that `T : Trait` holds,
|
||||
// which would be weird (e.g., if `T` was not a
|
||||
// parameter type but a normal type, like `int`).
|
||||
//
|
||||
// So what we do is to (1) add a requirement that
|
||||
// `T : Trait` (just in case) and (2) try to unify
|
||||
// `U` with `<T as Trait>::name`.
|
||||
|
||||
if !ty::binds_late_bound_regions(selcx.tcx(), data) {
|
||||
// Check that `T : Trait` holds.
|
||||
let trait_ref = data.to_poly_trait_ref();
|
||||
new_obligations.push(obligation.with(trait_ref.as_predicate()));
|
||||
|
||||
// Fallback to `<T as Trait>::name`. If this
|
||||
// fails, then the output must be at least
|
||||
// somewhat constrained, and we cannot verify
|
||||
// that constraint, so yield an error.
|
||||
let ty_projection = ty::mk_projection(tcx,
|
||||
trait_ref.0.clone(),
|
||||
data.0.projection_ty.item_name);
|
||||
|
||||
debug!("process_predicate: falling back to projection {}",
|
||||
ty_projection.repr(selcx.tcx()));
|
||||
|
||||
match infer::mk_eqty(selcx.infcx(),
|
||||
true,
|
||||
infer::EquatePredicate(obligation.cause.span),
|
||||
ty_projection,
|
||||
data.0.ty) {
|
||||
Ok(()) => { }
|
||||
Err(_) => {
|
||||
debug!("process_predicate: fallback failed to unify; error");
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
obligation.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
// If we have something like
|
||||
//
|
||||
// for<'a> <T<'a> as Trait>::name == &'a int
|
||||
//
|
||||
// there is no "canonical form" for us to
|
||||
// make, so just report the lack of candidates
|
||||
// as an error.
|
||||
|
||||
debug!("process_predicate: can't fallback, higher-ranked");
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
obligation.clone(),
|
||||
CodeSelectionError(Unimplemented)));
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
Err(project::ProjectionError::MismatchedTypes(e)) => {
|
||||
errors.push(
|
||||
FulfillmentError::new(
|
||||
obligation.clone(),
|
||||
CodeProjectionError(e)));
|
||||
true
|
||||
}
|
||||
Err(project::ProjectionError::TraitSelectionError(_)) => {
|
||||
// There was an error matching `T : Trait` (which
|
||||
// is a pre-requisite for `<T as Trait>::Name`
|
||||
// being valid). We could just report the error
|
||||
// now, but that tends to lead to double error
|
||||
// reports for the user (one for the obligation `T
|
||||
// : Trait`, typically incurred somewhere else,
|
||||
// and one from here). Instead, we'll create the
|
||||
// `T : Trait` obligation and add THAT as a
|
||||
// requirement. This will (eventually) trigger the
|
||||
// same error, but it will also wind up flagged as
|
||||
// a duplicate if another requirement that `T :
|
||||
// Trait` arises from somewhere else.
|
||||
let trait_predicate = data.to_poly_trait_ref();
|
||||
let trait_obligation = obligation.with(trait_predicate.as_predicate());
|
||||
new_obligations.push(trait_obligation);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,27 +18,31 @@ pub use self::ObligationCauseCode::*;
|
|||
use middle::subst;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::infer::InferCtxt;
|
||||
use std::rc::Rc;
|
||||
use std::slice::Iter;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub use self::error_reporting::report_fulfillment_errors;
|
||||
pub use self::fulfill::{FulfillmentContext, RegionObligation};
|
||||
pub use self::project::MismatchedProjectionTypes;
|
||||
pub use self::project::project_type;
|
||||
pub use self::project::ProjectionResult;
|
||||
pub use self::select::SelectionContext;
|
||||
pub use self::select::SelectionCache;
|
||||
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
||||
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
|
||||
pub use self::util::elaborate_predicates;
|
||||
pub use self::util::trait_ref_for_builtin_bound;
|
||||
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::poly_trait_ref_for_builtin_bound;
|
||||
|
||||
mod coherence;
|
||||
mod error_reporting;
|
||||
mod fulfill;
|
||||
mod project;
|
||||
mod select;
|
||||
mod util;
|
||||
|
||||
|
|
@ -52,11 +56,11 @@ mod util;
|
|||
pub struct Obligation<'tcx, T> {
|
||||
pub cause: ObligationCause<'tcx>,
|
||||
pub recursion_depth: uint,
|
||||
pub trait_ref: T,
|
||||
pub predicate: T,
|
||||
}
|
||||
|
||||
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
||||
pub type TraitObligation<'tcx> = Obligation<'tcx, Rc<ty::PolyTraitRef<'tcx>>>;
|
||||
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
||||
|
||||
/// Why did we incur this obligation? Used for error reporting.
|
||||
#[deriving(Clone)]
|
||||
|
|
@ -106,9 +110,21 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
// static items must have `Sync` type
|
||||
SharedStatic,
|
||||
|
||||
BuiltinDerivedObligation(Rc<ty::PolyTraitRef<'tcx>>, Rc<ObligationCauseCode<'tcx>>),
|
||||
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
|
||||
|
||||
ImplDerivedObligation(Rc<ty::PolyTraitRef<'tcx>>, Rc<ObligationCauseCode<'tcx>>),
|
||||
ImplDerivedObligation(DerivedObligationCause<'tcx>),
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct DerivedObligationCause<'tcx> {
|
||||
/// The trait reference of the parent obligation that led to the
|
||||
/// current obligation. Note that only trait obligations lead to
|
||||
/// derived obligations, so we just store the trait reference here
|
||||
/// directly.
|
||||
parent_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
||||
/// The parent trait had this cause
|
||||
parent_code: Rc<ObligationCauseCode<'tcx>>
|
||||
}
|
||||
|
||||
pub type Obligations<'tcx, O> = subst::VecPerParamSpace<Obligation<'tcx, O>>;
|
||||
|
|
@ -121,8 +137,8 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
|
|||
pub enum SelectionError<'tcx> {
|
||||
Unimplemented,
|
||||
Overflow,
|
||||
OutputTypeParameterMismatch(Rc<ty::PolyTraitRef<'tcx>>,
|
||||
Rc<ty::PolyTraitRef<'tcx>>,
|
||||
OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>,
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
ty::type_err<'tcx>),
|
||||
}
|
||||
|
||||
|
|
@ -134,6 +150,7 @@ pub struct FulfillmentError<'tcx> {
|
|||
#[deriving(Clone)]
|
||||
pub enum FulfillmentErrorCode<'tcx> {
|
||||
CodeSelectionError(SelectionError<'tcx>),
|
||||
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
|
||||
CodeAmbiguity,
|
||||
}
|
||||
|
||||
|
|
@ -174,10 +191,10 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
|
|||
///
|
||||
/// // Case B: Vtable must be provided by caller. This applies when
|
||||
/// // type is a type parameter.
|
||||
/// param.clone(); // VtableParam(Oblig_1)
|
||||
/// param.clone(); // VtableParam
|
||||
///
|
||||
/// // Case C: A mix of cases A and B.
|
||||
/// mixed.clone(); // Vtable(Impl_1, [VtableParam(Oblig_1)])
|
||||
/// mixed.clone(); // Vtable(Impl_1, [VtableParam])
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -191,7 +208,7 @@ pub enum Vtable<'tcx, N> {
|
|||
|
||||
/// Successful resolution to an obligation provided by the caller
|
||||
/// for some type parameter.
|
||||
VtableParam(VtableParamData<'tcx>),
|
||||
VtableParam,
|
||||
|
||||
/// Successful resolution for a builtin trait.
|
||||
VtableBuiltin(VtableBuiltinData<N>),
|
||||
|
|
@ -228,15 +245,6 @@ pub struct VtableBuiltinData<N> {
|
|||
pub nested: subst::VecPerParamSpace<N>
|
||||
}
|
||||
|
||||
/// A vtable provided as a parameter by the caller. For example, in a
|
||||
/// function like `fn foo<T:Eq>(...)`, if the `eq()` method is invoked
|
||||
/// on an instance of `T`, the vtable would be of type `VtableParam`.
|
||||
#[deriving(PartialEq,Eq,Clone)]
|
||||
pub struct VtableParamData<'tcx> {
|
||||
// In the above example, this would `Eq`
|
||||
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
|
||||
/// of a trait, not an inherent impl.
|
||||
pub fn is_orphan_impl(tcx: &ty::ctxt,
|
||||
|
|
@ -265,6 +273,43 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
util::predicates_for_generics(tcx, cause, 0, generic_bounds)
|
||||
}
|
||||
|
||||
/// Determines whether the type `ty` is known to meet `bound` and
|
||||
/// returns true if so. Returns false if `ty` either does not meet
|
||||
/// `bound` or is not known to meet bound (note that this is
|
||||
/// conservative towards *no impl*, which is the opposite of the
|
||||
/// `evaluate` methods).
|
||||
pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
param_env: &ty::ParameterEnvironment<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
bound: ty::BuiltinBound)
|
||||
-> bool
|
||||
{
|
||||
debug!("type_known_to_meet_builtin_bound(ty={}, bound={})",
|
||||
ty.repr(infcx.tcx),
|
||||
bound);
|
||||
|
||||
let mut fulfill_cx = FulfillmentContext::new();
|
||||
|
||||
// We can use dummy values here because we won't report any errors
|
||||
// that result nor will we pay any mind to region obligations that arise
|
||||
// (there shouldn't really be any anyhow).
|
||||
let cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID);
|
||||
|
||||
fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
|
||||
|
||||
// Note: we only assume something is `Copy` if we can
|
||||
// *definitively* show that it implements `Copy`. Otherwise,
|
||||
// assume it is move; linear is always ok.
|
||||
let result = fulfill_cx.select_all_or_error(infcx, param_env, infcx.tcx).is_ok();
|
||||
|
||||
debug!("type_known_to_meet_builtin_bound: ty={} bound={} result={}",
|
||||
ty.repr(infcx.tcx),
|
||||
bound,
|
||||
result);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
impl<'tcx,O> Obligation<'tcx,O> {
|
||||
pub fn new(cause: ObligationCause<'tcx>,
|
||||
trait_ref: O)
|
||||
|
|
@ -272,7 +317,7 @@ impl<'tcx,O> Obligation<'tcx,O> {
|
|||
{
|
||||
Obligation { cause: cause,
|
||||
recursion_depth: 0,
|
||||
trait_ref: trait_ref }
|
||||
predicate: trait_ref }
|
||||
}
|
||||
|
||||
pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> {
|
||||
|
|
@ -282,13 +327,7 @@ impl<'tcx,O> Obligation<'tcx,O> {
|
|||
pub fn with<P>(&self, value: P) -> Obligation<'tcx,P> {
|
||||
Obligation { cause: self.cause.clone(),
|
||||
recursion_depth: self.recursion_depth,
|
||||
trait_ref: value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TraitObligation<'tcx> {
|
||||
pub fn self_ty(&self) -> Ty<'tcx> {
|
||||
self.trait_ref.self_ty()
|
||||
predicate: value }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +354,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
|||
VtableImpl(ref i) => i.iter_nested(),
|
||||
VtableFnPointer(..) => (&[]).iter(),
|
||||
VtableUnboxedClosure(..) => (&[]).iter(),
|
||||
VtableParam(_) => (&[]).iter(),
|
||||
VtableParam => (&[]).iter(),
|
||||
VtableBuiltin(ref i) => i.iter_nested(),
|
||||
}
|
||||
}
|
||||
|
|
@ -325,7 +364,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
|||
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
|
||||
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
|
||||
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
|
||||
VtableParam(ref p) => VtableParam((*p).clone()),
|
||||
VtableParam => VtableParam,
|
||||
VtableBuiltin(ref b) => VtableBuiltin(b.map_nested(op)),
|
||||
}
|
||||
}
|
||||
|
|
@ -337,7 +376,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
|||
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
|
||||
VtableFnPointer(sig) => VtableFnPointer(sig),
|
||||
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
|
||||
VtableParam(p) => VtableParam(p),
|
||||
VtableParam => VtableParam,
|
||||
VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)),
|
||||
}
|
||||
}
|
||||
|
|
@ -403,6 +442,13 @@ impl<'tcx> FulfillmentError<'tcx> {
|
|||
CodeAmbiguity => false,
|
||||
CodeSelectionError(Overflow) => true,
|
||||
CodeSelectionError(_) => false,
|
||||
CodeProjectionError(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TraitObligation<'tcx> {
|
||||
fn self_ty(&self) -> Ty<'tcx> {
|
||||
self.predicate.0.self_ty()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
414
src/librustc/middle/traits/project.rs
Normal file
414
src/librustc/middle/traits/project.rs
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
// 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.
|
||||
|
||||
//! Code for projecting associated types out of trait references.
|
||||
|
||||
use super::elaborate_predicates;
|
||||
use super::Obligation;
|
||||
use super::PredicateObligation;
|
||||
use super::SelectionContext;
|
||||
use super::SelectionError;
|
||||
use super::VtableImplData;
|
||||
|
||||
use middle::infer;
|
||||
use middle::subst::Subst;
|
||||
use middle::ty::{mod, AsPredicate, ToPolyTraitRef, Ty};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub type PolyProjectionObligation<'tcx> =
|
||||
Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
|
||||
|
||||
pub type ProjectionObligation<'tcx> =
|
||||
Obligation<'tcx, ty::ProjectionPredicate<'tcx>>;
|
||||
|
||||
pub type ProjectionTyObligation<'tcx> =
|
||||
Obligation<'tcx, ty::ProjectionTy<'tcx>>;
|
||||
|
||||
/// When attempting to resolve `<T as TraitRef>::Name == U`...
|
||||
pub enum ProjectionError<'tcx> {
|
||||
/// ...we could not find any helpful information on what `Name`
|
||||
/// might be. This could occur, for example, if there is a where
|
||||
/// clause `T : TraitRef` but not `T : TraitRef<Name=V>`. When
|
||||
/// normalizing, this case is where we opt to normalize back to
|
||||
/// the projection type `<T as TraitRef>::Name`.
|
||||
NoCandidate,
|
||||
|
||||
/// ...we found multiple sources of information and couldn't resolve the ambiguity.
|
||||
TooManyCandidates,
|
||||
|
||||
/// ...`<T as TraitRef::Name>` ws resolved to some type `V` that failed to unify with `U`
|
||||
MismatchedTypes(MismatchedProjectionTypes<'tcx>),
|
||||
|
||||
/// ...an error occurred matching `T : TraitRef`
|
||||
TraitSelectionError(SelectionError<'tcx>),
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct MismatchedProjectionTypes<'tcx> {
|
||||
pub err: ty::type_err<'tcx>
|
||||
}
|
||||
|
||||
pub type ProjectionResult<'tcx, T> = Result<T, ProjectionError<'tcx>>;
|
||||
|
||||
enum ProjectionTyCandidate<'tcx> {
|
||||
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
||||
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
|
||||
}
|
||||
|
||||
struct ProjectionTyCandidateSet<'tcx> {
|
||||
vec: Vec<ProjectionTyCandidate<'tcx>>,
|
||||
ambiguous: bool
|
||||
}
|
||||
|
||||
pub fn poly_project_and_unify_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &PolyProjectionObligation<'tcx>)
|
||||
-> ProjectionResult<'tcx, ()>
|
||||
{
|
||||
debug!("poly_project(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
|
||||
infcx.try(|snapshot| {
|
||||
let (skol_predicate, skol_map) =
|
||||
infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
|
||||
let skol_obligation = obligation.with(skol_predicate);
|
||||
let () = try!(project_and_unify_type(selcx, &skol_obligation));
|
||||
match infcx.leak_check(&skol_map, snapshot) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute result of projecting an associated type and unify it with
|
||||
/// `obligation.predicate.ty` (if we can).
|
||||
pub fn project_and_unify_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionObligation<'tcx>)
|
||||
-> ProjectionResult<'tcx, ()>
|
||||
{
|
||||
debug!("project_and_unify(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let ty_obligation = obligation.with(obligation.predicate.projection_ty.clone());
|
||||
let projected_ty = try!(project_type(selcx, &ty_obligation));
|
||||
let infcx = selcx.infcx();
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
debug!("project_and_unify_type: projected_ty = {}", projected_ty.repr(selcx.tcx()));
|
||||
match infer::mk_eqty(infcx, true, origin, projected_ty, obligation.predicate.ty) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(ProjectionError::MismatchedTypes(MismatchedProjectionTypes{err: e})),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the result of a projection type (if we can).
|
||||
pub fn project_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>)
|
||||
-> ProjectionResult<'tcx, Ty<'tcx>>
|
||||
{
|
||||
debug!("project(obligation={})",
|
||||
obligation.repr(selcx.tcx()));
|
||||
|
||||
let mut candidates = ProjectionTyCandidateSet {
|
||||
vec: Vec::new(),
|
||||
ambiguous: false,
|
||||
};
|
||||
|
||||
let () = assemble_candidates_from_param_env(selcx,
|
||||
obligation,
|
||||
&mut candidates);
|
||||
|
||||
let () = assemble_candidates_from_object_type(selcx,
|
||||
obligation,
|
||||
&mut candidates);
|
||||
|
||||
if candidates.vec.is_empty() {
|
||||
// FIXME(#20297) -- In `select.rs` there is similar logic that
|
||||
// gives precedence to where-clauses, but it's a bit more
|
||||
// fine-grained. I was lazy here and just always give
|
||||
// precedence to where-clauses or other such sources over
|
||||
// actually dredging through impls. This logic probably should
|
||||
// be tightened up.
|
||||
|
||||
let () = try!(assemble_candidates_from_impls(selcx,
|
||||
obligation,
|
||||
&mut candidates));
|
||||
}
|
||||
|
||||
debug!("{} candidates, ambiguous={}",
|
||||
candidates.vec.len(),
|
||||
candidates.ambiguous);
|
||||
|
||||
// We probably need some winnowing logic similar to select here.
|
||||
|
||||
if candidates.ambiguous || candidates.vec.len() > 1 {
|
||||
return Err(ProjectionError::TooManyCandidates);
|
||||
}
|
||||
|
||||
match candidates.vec.pop() {
|
||||
Some(candidate) => {
|
||||
Ok(try!(confirm_candidate(selcx, obligation, candidate)))
|
||||
}
|
||||
None => {
|
||||
Err(ProjectionError::NoCandidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The first thing we have to do is scan through the parameter
|
||||
/// environment to see whether there are any projection predicates
|
||||
/// there that can answer this question.
|
||||
fn assemble_candidates_from_param_env<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||
{
|
||||
let env_predicates = selcx.param_env().caller_bounds.predicates.clone();
|
||||
let env_predicates = env_predicates.iter().cloned().collect();
|
||||
assemble_candidates_from_predicates(selcx, obligation, candidate_set, env_predicates);
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_predicates<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||
env_predicates: Vec<ty::Predicate<'tcx>>)
|
||||
{
|
||||
debug!("assemble_candidates_from_predicates(obligation={}, env_predicates={})",
|
||||
obligation.repr(selcx.tcx()),
|
||||
env_predicates.repr(selcx.tcx()));
|
||||
let infcx = selcx.infcx();
|
||||
for predicate in elaborate_predicates(selcx.tcx(), env_predicates) {
|
||||
match predicate {
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
let is_match = infcx.probe(|_| {
|
||||
let origin = infer::Misc(obligation.cause.span);
|
||||
let obligation_poly_trait_ref =
|
||||
obligation.predicate.trait_ref.to_poly_trait_ref();
|
||||
let data_poly_trait_ref =
|
||||
data.to_poly_trait_ref();
|
||||
infcx.sub_poly_trait_refs(false,
|
||||
origin,
|
||||
obligation_poly_trait_ref,
|
||||
data_poly_trait_ref).is_ok()
|
||||
});
|
||||
|
||||
if is_match {
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::ParamEnv(data.clone()));
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_object_type<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||
{
|
||||
let infcx = selcx.infcx();
|
||||
let trait_ref = infcx.resolve_type_vars_if_possible(&obligation.predicate.trait_ref);
|
||||
debug!("assemble_candidates_from_object_type(trait_ref={})",
|
||||
trait_ref.repr(infcx.tcx));
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let data = match self_ty.sty {
|
||||
ty::ty_trait(ref data) => data,
|
||||
_ => { return; }
|
||||
};
|
||||
let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), self_ty);
|
||||
let env_predicates = projection_bounds.iter()
|
||||
.map(|p| p.as_predicate())
|
||||
.collect();
|
||||
assemble_candidates_from_predicates(selcx, obligation, candidate_set, env_predicates)
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_impls<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||
-> ProjectionResult<'tcx, ()>
|
||||
{
|
||||
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
||||
// start out by selecting the predicate `T as TraitRef<...>`:
|
||||
let trait_ref =
|
||||
obligation.predicate.trait_ref.to_poly_trait_ref();
|
||||
let trait_obligation =
|
||||
obligation.with(trait_ref.to_poly_trait_predicate());
|
||||
let vtable = match selcx.select(&trait_obligation) {
|
||||
Ok(Some(vtable)) => vtable,
|
||||
Ok(None) => {
|
||||
candidate_set.ambiguous = true;
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("assemble_candidates_from_impls: selection error {}",
|
||||
e.repr(selcx.tcx()));
|
||||
return Err(ProjectionError::TraitSelectionError(e));
|
||||
}
|
||||
};
|
||||
|
||||
match vtable {
|
||||
super::VtableImpl(data) => {
|
||||
candidate_set.vec.push(
|
||||
ProjectionTyCandidate::Impl(data));
|
||||
}
|
||||
super::VtableParam(..) => {
|
||||
// This case tell us nothing about the value of an
|
||||
// associated type. Consider:
|
||||
//
|
||||
// ```
|
||||
// trait SomeTrait { type Foo; }
|
||||
// fn foo<T:SomeTrait>(...) { }
|
||||
// ```
|
||||
//
|
||||
// If the user writes `<T as SomeTrait>::Foo`, then the `T
|
||||
// : SomeTrait` binding does not help us decide what the
|
||||
// type `Foo` is (at least, not more specifically than
|
||||
// what we already knew).
|
||||
//
|
||||
// But wait, you say! What about an example like this:
|
||||
//
|
||||
// ```
|
||||
// fn bar<T:SomeTrait<Foo=uint>>(...) { ... }
|
||||
// ```
|
||||
//
|
||||
// Doesn't the `T : Sometrait<Foo=uint>` predicate help
|
||||
// resolve `T::Foo`? And of course it does, but in fact
|
||||
// that single predicate is desugared into two predicates
|
||||
// in the compiler: a trait predicate (`T : SomeTrait`) and a
|
||||
// projection. And the projection where clause is handled
|
||||
// in `assemble_candidates_from_param_env`.
|
||||
}
|
||||
super::VtableBuiltin(..) |
|
||||
super::VtableUnboxedClosure(..) |
|
||||
super::VtableFnPointer(..) => {
|
||||
// These traits have no associated types.
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("Cannot project an associated type from `{}`",
|
||||
vtable.repr(selcx.tcx())).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn confirm_candidate<'cx,'tcx>(
|
||||
selcx: &mut SelectionContext<'cx,'tcx>,
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
candidate: ProjectionTyCandidate<'tcx>)
|
||||
-> ProjectionResult<'tcx, Ty<'tcx>>
|
||||
{
|
||||
let infcx = selcx.infcx();
|
||||
|
||||
debug!("confirm_candidate(candidate={}, obligation={})",
|
||||
candidate.repr(infcx.tcx),
|
||||
obligation.repr(infcx.tcx));
|
||||
|
||||
let projected_ty = match candidate {
|
||||
ProjectionTyCandidate::ParamEnv(poly_projection) => {
|
||||
let projection =
|
||||
infcx.replace_late_bound_regions_with_fresh_var(
|
||||
obligation.cause.span,
|
||||
infer::LateBoundRegionConversionTime::HigherRankedType,
|
||||
&poly_projection).0;
|
||||
|
||||
assert_eq!(projection.projection_ty.item_name,
|
||||
obligation.predicate.item_name);
|
||||
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
match infcx.sub_trait_refs(false,
|
||||
origin,
|
||||
obligation.predicate.trait_ref.clone(),
|
||||
projection.projection_ty.trait_ref.clone()) {
|
||||
Ok(()) => { }
|
||||
Err(e) => {
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("Failed to unify `{}` and `{}` in projection: {}",
|
||||
obligation.repr(selcx.tcx()),
|
||||
projection.repr(selcx.tcx()),
|
||||
ty::type_err_to_str(selcx.tcx(), &e)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
projection.ty
|
||||
}
|
||||
|
||||
ProjectionTyCandidate::Impl(impl_vtable) => {
|
||||
// there don't seem to be nicer accessors to these:
|
||||
let impl_items_map = selcx.tcx().impl_items.borrow();
|
||||
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
|
||||
|
||||
let impl_items = &impl_items_map[impl_vtable.impl_def_id];
|
||||
let mut impl_ty = None;
|
||||
for impl_item in impl_items.iter() {
|
||||
let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
|
||||
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
|
||||
ty::MethodTraitItem(..) => { continue; }
|
||||
};
|
||||
|
||||
if assoc_type.name != obligation.predicate.item_name {
|
||||
continue;
|
||||
}
|
||||
|
||||
let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
|
||||
impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
|
||||
break;
|
||||
}
|
||||
|
||||
match impl_ty {
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
selcx.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("impl `{}` did not contain projection for `{}`",
|
||||
impl_vtable.repr(selcx.tcx()),
|
||||
obligation.repr(selcx.tcx())).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(projected_ty)
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ProjectionError<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
ProjectionError::NoCandidate =>
|
||||
format!("NoCandidate"),
|
||||
ProjectionError::TooManyCandidates =>
|
||||
format!("NoCandidate"),
|
||||
ProjectionError::MismatchedTypes(ref m) =>
|
||||
format!("MismatchedTypes({})", m.repr(tcx)),
|
||||
ProjectionError::TraitSelectionError(ref e) =>
|
||||
format!("TraitSelectionError({})", e.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
ProjectionTyCandidate::ParamEnv(ref data) =>
|
||||
format!("ParamEnv({})", data.repr(tcx)),
|
||||
ProjectionTyCandidate::Impl(ref data) =>
|
||||
format!("Impl({})", data.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -13,23 +13,24 @@
|
|||
|
||||
pub use self::MethodMatchResult::*;
|
||||
pub use self::MethodMatchedData::*;
|
||||
use self::Candidate::*;
|
||||
use self::SelectionCandidate::*;
|
||||
use self::BuiltinBoundConditions::*;
|
||||
use self::EvaluationResult::*;
|
||||
|
||||
use super::{DerivedObligationCause};
|
||||
use super::{PredicateObligation, Obligation, TraitObligation, ObligationCause};
|
||||
use super::{ObligationCauseCode, BuiltinDerivedObligation};
|
||||
use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch};
|
||||
use super::{Selection};
|
||||
use super::{SelectionResult};
|
||||
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, VtableFnPointer};
|
||||
use super::{VtableImplData, VtableParamData, VtableBuiltinData};
|
||||
use super::{VtableImplData, VtableBuiltinData};
|
||||
use super::{util};
|
||||
|
||||
use middle::fast_reject;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||
use middle::ty::{mod, AsPredicate, RegionEscape, Ty};
|
||||
use middle::ty::{mod, AsPredicate, RegionEscape, ToPolyTraitRef, Ty};
|
||||
use middle::infer;
|
||||
use middle::infer::{InferCtxt, TypeFreshener};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
|
|
@ -75,15 +76,15 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> {
|
|||
|
||||
/// Trait ref from `obligation` but skolemized with the
|
||||
/// selection-context's freshener. Used to check for recursion.
|
||||
fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
fresh_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
||||
previous: Option<&'prev TraitObligationStack<'prev, 'tcx>>
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct SelectionCache<'tcx> {
|
||||
hashmap: RefCell<HashMap<Rc<ty::PolyTraitRef<'tcx>>,
|
||||
SelectionResult<'tcx, Candidate<'tcx>>>>,
|
||||
hashmap: RefCell<HashMap<Rc<ty::TraitRef<'tcx>>,
|
||||
SelectionResult<'tcx, SelectionCandidate<'tcx>>>>,
|
||||
}
|
||||
|
||||
pub enum MethodMatchResult {
|
||||
|
|
@ -128,11 +129,15 @@ pub enum MethodMatchedData {
|
|||
/// clauses can give additional information (like, the types of output
|
||||
/// parameters) that would have to be inferred from the impl.
|
||||
#[deriving(PartialEq,Eq,Show,Clone)]
|
||||
enum Candidate<'tcx> {
|
||||
enum SelectionCandidate<'tcx> {
|
||||
BuiltinCandidate(ty::BuiltinBound),
|
||||
ParamCandidate(VtableParamData<'tcx>),
|
||||
ParamCandidate(ty::PolyTraitRef<'tcx>),
|
||||
ImplCandidate(ast::DefId),
|
||||
|
||||
/// This is a trait matching with a projected type as `Self`, and
|
||||
/// we found an applicable bound in the trait definition.
|
||||
ProjectionCandidate,
|
||||
|
||||
/// Implementation of a `Fn`-family trait by one of the
|
||||
/// anonymous types generated for a `||` expression.
|
||||
UnboxedClosureCandidate(/* closure */ ast::DefId, Substs<'tcx>),
|
||||
|
|
@ -144,9 +149,16 @@ enum Candidate<'tcx> {
|
|||
ErrorCandidate,
|
||||
}
|
||||
|
||||
struct CandidateSet<'tcx> {
|
||||
vec: Vec<Candidate<'tcx>>,
|
||||
ambiguous: bool
|
||||
struct SelectionCandidateSet<'tcx> {
|
||||
// a list of candidates that definitely apply to the current
|
||||
// obligation (meaning: types unify).
|
||||
vec: Vec<SelectionCandidate<'tcx>>,
|
||||
|
||||
// if this is true, then there were candidates that might or might
|
||||
// not have applied, but we couldn't tell. This occurs when some
|
||||
// of the input types are type variables, in which case there are
|
||||
// various "builtin" rules that might or might not trigger.
|
||||
ambiguous: bool,
|
||||
}
|
||||
|
||||
enum BuiltinBoundConditions<'tcx> {
|
||||
|
|
@ -193,6 +205,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
self.infcx
|
||||
}
|
||||
|
||||
pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'tcx> {
|
||||
self.param_env
|
||||
}
|
||||
|
||||
pub fn tcx(&self) -> &'cx ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
|
@ -218,7 +234,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
pub fn select(&mut self, obligation: &TraitObligation<'tcx>)
|
||||
-> SelectionResult<'tcx, Selection<'tcx>> {
|
||||
debug!("select({})", obligation.repr(self.tcx()));
|
||||
assert!(!obligation.trait_ref.has_escaping_regions());
|
||||
assert!(!obligation.predicate.has_escaping_regions());
|
||||
|
||||
let stack = self.push_stack(None, obligation);
|
||||
match try!(self.candidate_from_obligation(&stack)) {
|
||||
|
|
@ -280,7 +296,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
debug!("evaluate_predicate_recursively({})",
|
||||
obligation.repr(self.tcx()));
|
||||
|
||||
match obligation.trait_ref {
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref t) => {
|
||||
assert!(!t.has_escaping_regions());
|
||||
let obligation = obligation.with(t.clone());
|
||||
|
|
@ -302,6 +318,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// evaluating trait matches
|
||||
EvaluatedToOk
|
||||
}
|
||||
|
||||
ty::Predicate::Projection(..) => {
|
||||
// FIXME(#20296) -- we should be able to give a more precise answer here
|
||||
EvaluatedToAmbig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -411,9 +432,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
self.infcx.probe(|snapshot| {
|
||||
let (skol_obligation_trait_ref, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot);
|
||||
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
match self.match_impl(impl_def_id, obligation, snapshot,
|
||||
&skol_map, Rc::new(skol_obligation_trait_ref)) {
|
||||
&skol_map, skol_obligation_trait_ref.trait_ref.clone()) {
|
||||
Ok(substs) => {
|
||||
let vtable_impl = self.vtable_impl(impl_def_id,
|
||||
substs,
|
||||
|
|
@ -439,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
fn candidate_from_obligation<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
-> SelectionResult<'tcx, Candidate<'tcx>>
|
||||
-> SelectionResult<'tcx, SelectionCandidate<'tcx>>
|
||||
{
|
||||
// Watch out for overflow. This intentionally bypasses (and does
|
||||
// not update) the cache.
|
||||
|
|
@ -455,17 +476,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// 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_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()),
|
||||
let cache_fresh_trait_pred =
|
||||
self.infcx.freshen(stack.obligation.predicate.clone());
|
||||
debug!("candidate_from_obligation(cache_fresh_trait_pred={}, obligation={})",
|
||||
cache_fresh_trait_pred.repr(self.tcx()),
|
||||
stack.repr(self.tcx()));
|
||||
assert!(!stack.obligation.trait_ref.has_escaping_regions());
|
||||
assert!(!stack.obligation.predicate.has_escaping_regions());
|
||||
|
||||
match self.check_candidate_cache(cache_fresh_trait_ref.clone()) {
|
||||
match self.check_candidate_cache(&cache_fresh_trait_pred) {
|
||||
Some(c) => {
|
||||
debug!("CACHE HIT: cache_fresh_trait_ref={}, candidate={}",
|
||||
cache_fresh_trait_ref.repr(self.tcx()),
|
||||
debug!("CACHE HIT: cache_fresh_trait_pred={}, candidate={}",
|
||||
cache_fresh_trait_pred.repr(self.tcx()),
|
||||
c.repr(self.tcx()));
|
||||
return c;
|
||||
}
|
||||
|
|
@ -474,17 +495,17 @@ 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_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());
|
||||
debug!("CACHE MISS: cache_fresh_trait_pred={}, candidate={}",
|
||||
cache_fresh_trait_pred.repr(self.tcx()), candidate.repr(self.tcx()));
|
||||
self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone());
|
||||
candidate
|
||||
}
|
||||
|
||||
fn candidate_from_obligation_no_cache<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
-> SelectionResult<'tcx, Candidate<'tcx>>
|
||||
-> SelectionResult<'tcx, SelectionCandidate<'tcx>>
|
||||
{
|
||||
if ty::type_is_error(stack.obligation.self_ty()) {
|
||||
if ty::type_is_error(stack.obligation.predicate.0.self_ty()) {
|
||||
return Ok(Some(ErrorCandidate));
|
||||
}
|
||||
|
||||
|
|
@ -497,8 +518,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
let mut candidates = candidate_set.vec;
|
||||
|
||||
debug!("assembled {} candidates for {}",
|
||||
candidates.len(), stack.repr(self.tcx()));
|
||||
debug!("assembled {} candidates for {}: {}",
|
||||
candidates.len(),
|
||||
stack.repr(self.tcx()),
|
||||
candidates.repr(self.tcx()));
|
||||
|
||||
// At this point, we know that each of the entries in the
|
||||
// candidate set is *individually* applicable. Now we have to
|
||||
|
|
@ -576,7 +599,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
fn pick_candidate_cache(&self,
|
||||
cache_fresh_trait_ref: &Rc<ty::PolyTraitRef<'tcx>>)
|
||||
cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>)
|
||||
-> &SelectionCache<'tcx>
|
||||
{
|
||||
// High-level idea: we have to decide whether to consult the
|
||||
|
|
@ -598,7 +621,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_fresh_trait_ref.0.input_types().iter().any(
|
||||
cache_fresh_trait_pred.0.input_types().iter().any(
|
||||
|&t| ty::type_has_self(t) || ty::type_has_params(t))
|
||||
{
|
||||
return &self.param_env.selection_cache;
|
||||
|
|
@ -611,7 +634,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_fresh_trait_ref.0.input_types().iter().any(
|
||||
cache_fresh_trait_pred.0.input_types().iter().any(
|
||||
|&t| ty::type_has_ty_infer(t))
|
||||
{
|
||||
return &self.param_env.selection_cache;
|
||||
|
|
@ -622,32 +645,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
fn check_candidate_cache(&mut self,
|
||||
cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
-> Option<SelectionResult<'tcx, Candidate<'tcx>>>
|
||||
cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>)
|
||||
-> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>>
|
||||
{
|
||||
let cache = self.pick_candidate_cache(&cache_fresh_trait_ref);
|
||||
let cache = self.pick_candidate_cache(cache_fresh_trait_pred);
|
||||
let hashmap = cache.hashmap.borrow();
|
||||
hashmap.get(&cache_fresh_trait_ref).map(|c| (*c).clone())
|
||||
hashmap.get(&cache_fresh_trait_pred.0.trait_ref).map(|c| (*c).clone())
|
||||
}
|
||||
|
||||
fn insert_candidate_cache(&mut self,
|
||||
cache_fresh_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
candidate: SelectionResult<'tcx, Candidate<'tcx>>)
|
||||
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>)
|
||||
{
|
||||
let cache = self.pick_candidate_cache(&cache_fresh_trait_ref);
|
||||
let cache = self.pick_candidate_cache(&cache_fresh_trait_pred);
|
||||
let mut hashmap = cache.hashmap.borrow_mut();
|
||||
hashmap.insert(cache_fresh_trait_ref, candidate);
|
||||
hashmap.insert(cache_fresh_trait_pred.0.trait_ref.clone(), candidate);
|
||||
}
|
||||
|
||||
fn assemble_candidates<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
-> Result<CandidateSet<'tcx>, SelectionError<'tcx>>
|
||||
-> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>>
|
||||
{
|
||||
// Check for overflow.
|
||||
|
||||
let TraitObligationStack { obligation, .. } = *stack;
|
||||
|
||||
let mut candidates = CandidateSet {
|
||||
let mut candidates = SelectionCandidateSet {
|
||||
vec: Vec::new(),
|
||||
ambiguous: false
|
||||
};
|
||||
|
|
@ -655,10 +678,10 @@ 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.predicate.def_id()) {
|
||||
Some(ty::BoundCopy) => {
|
||||
debug!("obligation self ty is {}",
|
||||
obligation.self_ty().repr(self.tcx()));
|
||||
obligation.predicate.0.self_ty().repr(self.tcx()));
|
||||
|
||||
// If the user has asked for the older, compatibility
|
||||
// behavior, ignore user-defined impls here. This will
|
||||
|
|
@ -696,18 +719,147 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
|
||||
try!(self.assemble_candidates_from_caller_bounds(obligation, &mut candidates));
|
||||
debug!("candidate list size: {}", candidates.vec.len());
|
||||
Ok(candidates)
|
||||
}
|
||||
|
||||
fn assemble_candidates_from_projected_tys(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
{
|
||||
let poly_trait_predicate =
|
||||
self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
|
||||
|
||||
debug!("assemble_candidates_for_projected_tys({},{})",
|
||||
obligation.repr(self.tcx()),
|
||||
poly_trait_predicate.repr(self.tcx()));
|
||||
|
||||
// FIXME(#20297) -- just examining the self-type is very simplistic
|
||||
|
||||
// before we go into the whole skolemization thing, just
|
||||
// quickly check if the self-type is a projection at all.
|
||||
let trait_def_id = match poly_trait_predicate.0.trait_ref.self_ty().sty {
|
||||
ty::ty_projection(ref data) => data.trait_ref.def_id,
|
||||
ty::ty_infer(ty::TyVar(_)) => {
|
||||
// If the self-type is an inference variable, then it MAY wind up
|
||||
// being a projected type, so induce an ambiguity.
|
||||
//
|
||||
// FIXME(#20297) -- being strict about this can cause
|
||||
// inference failures with BorrowFrom, which is
|
||||
// unfortunate. Can we do better here?
|
||||
candidates.ambiguous = true;
|
||||
return;
|
||||
}
|
||||
_ => { return; }
|
||||
};
|
||||
|
||||
debug!("assemble_candidates_for_projected_tys: trait_def_id={}",
|
||||
trait_def_id.repr(self.tcx()));
|
||||
|
||||
let result = self.infcx.probe(|snapshot| {
|
||||
self.match_projection_obligation_against_bounds_from_trait(obligation,
|
||||
snapshot)
|
||||
});
|
||||
|
||||
if result {
|
||||
candidates.vec.push(ProjectionCandidate);
|
||||
}
|
||||
}
|
||||
|
||||
fn match_projection_obligation_against_bounds_from_trait(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
snapshot: &infer::CombinedSnapshot)
|
||||
-> bool
|
||||
{
|
||||
let poly_trait_predicate =
|
||||
self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
|
||||
let (skol_trait_predicate, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&poly_trait_predicate, snapshot);
|
||||
debug!("match_projection_obligation_against_bounds_from_trait: \
|
||||
skol_trait_predicate={} skol_map={}",
|
||||
skol_trait_predicate.repr(self.tcx()),
|
||||
skol_map.repr(self.tcx()));
|
||||
|
||||
let projection_trait_ref = match skol_trait_predicate.trait_ref.self_ty().sty {
|
||||
ty::ty_projection(ref data) => &data.trait_ref,
|
||||
_ => {
|
||||
self.tcx().sess.span_bug(
|
||||
obligation.cause.span,
|
||||
format!("match_projection_obligation_against_bounds_from_trait() called \
|
||||
but self-ty not a projection: {}",
|
||||
skol_trait_predicate.trait_ref.self_ty().repr(self.tcx())).as_slice());
|
||||
}
|
||||
};
|
||||
debug!("match_projection_obligation_against_bounds_from_trait: \
|
||||
projection_trait_ref={}",
|
||||
projection_trait_ref.repr(self.tcx()));
|
||||
|
||||
let trait_def = ty::lookup_trait_def(self.tcx(), projection_trait_ref.def_id);
|
||||
let bounds = trait_def.generics.to_bounds(self.tcx(), projection_trait_ref.substs);
|
||||
debug!("match_projection_obligation_against_bounds_from_trait: \
|
||||
bounds={}",
|
||||
bounds.repr(self.tcx()));
|
||||
|
||||
let matching_bound =
|
||||
util::elaborate_predicates(self.tcx(), bounds.predicates.to_vec())
|
||||
.filter_to_traits()
|
||||
.find(
|
||||
|bound| self.infcx.probe(
|
||||
|_| self.match_projection(obligation,
|
||||
bound.clone(),
|
||||
skol_trait_predicate.trait_ref.clone(),
|
||||
&skol_map,
|
||||
snapshot)));
|
||||
|
||||
debug!("match_projection_obligation_against_bounds_from_trait: \
|
||||
matching_bound={}",
|
||||
matching_bound.repr(self.tcx()));
|
||||
match matching_bound {
|
||||
None => false,
|
||||
Some(bound) => {
|
||||
// Repeat the successful match, if any, this time outside of a probe.
|
||||
let result = self.match_projection(obligation,
|
||||
bound,
|
||||
skol_trait_predicate.trait_ref.clone(),
|
||||
&skol_map,
|
||||
snapshot);
|
||||
assert!(result);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn match_projection(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
trait_bound: ty::PolyTraitRef<'tcx>,
|
||||
skol_trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
skol_map: &infer::SkolemizationMap,
|
||||
snapshot: &infer::CombinedSnapshot)
|
||||
-> bool
|
||||
{
|
||||
assert!(!skol_trait_ref.has_escaping_regions());
|
||||
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
|
||||
match self.infcx.sub_poly_trait_refs(false,
|
||||
origin,
|
||||
trait_bound.clone(),
|
||||
ty::Binder(skol_trait_ref.clone())) {
|
||||
Ok(()) => { }
|
||||
Err(_) => { return false; }
|
||||
}
|
||||
|
||||
self.infcx.leak_check(skol_map, snapshot).is_ok()
|
||||
}
|
||||
|
||||
/// Given an obligation like `<SomeTrait for T>`, search the obligations that the caller
|
||||
/// supplied to find out whether it is listed among them.
|
||||
///
|
||||
/// Never affects inference environment.
|
||||
fn assemble_candidates_from_caller_bounds(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut CandidateSet<'tcx>)
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
{
|
||||
debug!("assemble_candidates_from_caller_bounds({})",
|
||||
|
|
@ -715,7 +867,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
let caller_trait_refs: Vec<_> =
|
||||
self.param_env.caller_bounds.predicates.iter()
|
||||
.filter_map(|o| o.to_trait())
|
||||
.filter_map(|o| o.to_opt_poly_trait_ref())
|
||||
.collect();
|
||||
|
||||
let all_bounds =
|
||||
|
|
@ -728,8 +880,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|_| self.match_where_clause(obligation, bound.clone())).is_ok());
|
||||
|
||||
let param_candidates =
|
||||
matching_bounds.map(
|
||||
|bound| ParamCandidate(VtableParamData { bound: bound }));
|
||||
matching_bounds.map(|bound| ParamCandidate(bound));
|
||||
|
||||
candidates.vec.extend(param_candidates);
|
||||
|
||||
|
|
@ -744,10 +895,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// unified during the confirmation step.
|
||||
fn assemble_unboxed_closure_candidates(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut CandidateSet<'tcx>)
|
||||
candidates: &mut SelectionCandidateSet<'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.predicate.0.def_id()) {
|
||||
Some(k) => k,
|
||||
None => { return Ok(()); }
|
||||
};
|
||||
|
|
@ -789,13 +940,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// Implement one of the `Fn()` family for a fn pointer.
|
||||
fn assemble_fn_pointer_candidates(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidates: &mut CandidateSet<'tcx>)
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'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.predicate.def_id()) != self.tcx().lang_items.fn_trait() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -827,16 +978,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// Search for impls that might apply to `obligation`.
|
||||
fn assemble_candidates_from_impls(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidate_vec: &mut Vec<Candidate<'tcx>>)
|
||||
candidate_vec: &mut Vec<SelectionCandidate<'tcx>>)
|
||||
-> Result<(), SelectionError<'tcx>>
|
||||
{
|
||||
let all_impls = self.all_impls(obligation.trait_ref.def_id());
|
||||
let all_impls = self.all_impls(obligation.predicate.def_id());
|
||||
for &impl_def_id in all_impls.iter() {
|
||||
self.infcx.probe(|snapshot| {
|
||||
let (skol_obligation_trait_ref, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&*obligation.trait_ref, snapshot);
|
||||
let (skol_obligation_trait_pred, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
match self.match_impl(impl_def_id, obligation, snapshot,
|
||||
&skol_map, Rc::new(skol_obligation_trait_ref)) {
|
||||
&skol_map, skol_obligation_trait_pred.trait_ref.clone()) {
|
||||
Ok(_) => {
|
||||
candidate_vec.push(ImplCandidate(impl_def_id));
|
||||
}
|
||||
|
|
@ -861,7 +1012,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// scrutiny.
|
||||
fn winnow_candidate<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
candidate: &Candidate<'tcx>)
|
||||
candidate: &SelectionCandidate<'tcx>)
|
||||
-> EvaluationResult<'tcx>
|
||||
{
|
||||
debug!("winnow_candidate: candidate={}", candidate.repr(self.tcx()));
|
||||
|
|
@ -918,12 +1069,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// a case where doing the opposite caused us harm.
|
||||
fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
candidate_i: &Candidate<'tcx>,
|
||||
candidate_j: &Candidate<'tcx>)
|
||||
candidate_i: &SelectionCandidate<'tcx>,
|
||||
candidate_j: &SelectionCandidate<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
match (candidate_i, candidate_j) {
|
||||
(&ImplCandidate(impl_def_id), &ParamCandidate(ref vt)) => {
|
||||
(&ImplCandidate(impl_def_id), &ParamCandidate(ref bound)) => {
|
||||
debug!("Considering whether to drop param {} in favor of impl {}",
|
||||
candidate_i.repr(self.tcx()),
|
||||
candidate_j.repr(self.tcx()));
|
||||
|
|
@ -931,23 +1082,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
self.infcx.probe(|snapshot| {
|
||||
let (skol_obligation_trait_ref, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(
|
||||
&*stack.obligation.trait_ref, snapshot);
|
||||
&stack.obligation.predicate, snapshot);
|
||||
let impl_substs =
|
||||
self.rematch_impl(impl_def_id, stack.obligation, snapshot,
|
||||
&skol_map, Rc::new(skol_obligation_trait_ref));
|
||||
&skol_map, skol_obligation_trait_ref.trait_ref.clone());
|
||||
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()));
|
||||
ty::Binder(impl_trait_ref);
|
||||
let origin =
|
||||
infer::RelateOutputImplTypes(stack.obligation.cause.span);
|
||||
self.infcx
|
||||
.sub_poly_trait_refs(false, origin, poly_impl_trait_ref, vt.bound.clone())
|
||||
.sub_poly_trait_refs(false, origin, poly_impl_trait_ref, bound.clone())
|
||||
.is_ok()
|
||||
})
|
||||
}
|
||||
(&ProjectionCandidate, &ParamCandidate(_)) => {
|
||||
// FIXME(#20297) -- this gives where clauses precedent
|
||||
// over projections. Really these are just two means
|
||||
// of deducing information (one based on the where
|
||||
// clauses on the trait definition; one based on those
|
||||
// on the enclosing scope), and it'd be better to
|
||||
// integrate them more intelligently. But for now this
|
||||
// seems ok. If we DON'T give where clauses
|
||||
// precedence, we run into trouble in default methods,
|
||||
// where both the projection bounds for `Self::A` and
|
||||
// the where clauses are in scope.
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
*candidate_i == *candidate_j
|
||||
}
|
||||
|
|
@ -966,7 +1130,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
fn assemble_builtin_bound_candidates<'o>(&mut self,
|
||||
bound: ty::BuiltinBound,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
candidates: &mut CandidateSet<'tcx>)
|
||||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
{
|
||||
match self.builtin_bound(bound, stack.obligation) {
|
||||
|
|
@ -987,7 +1151,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation: &TraitObligation<'tcx>)
|
||||
-> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>>
|
||||
{
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.trait_ref.self_ty());
|
||||
// Note: these tests operate on types that may contain bound
|
||||
// regions. To be proper, we ought to skolemize here, but we
|
||||
// forego the skolemization and defer it until the
|
||||
// confirmation step.
|
||||
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
|
||||
return match self_ty.sty {
|
||||
ty::ty_infer(ty::IntVar(_)) |
|
||||
ty::ty_infer(ty::FloatVar(_)) |
|
||||
|
|
@ -1100,11 +1269,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
} else {
|
||||
// Recursively check all supertraits to find out if any further
|
||||
// bounds are required and thus we must fulfill.
|
||||
let tmp_tr = data.principal_trait_ref_with_self_ty(self.tcx(),
|
||||
ty::mk_err());
|
||||
for tr in util::supertraits(self.tcx(), tmp_tr) {
|
||||
let principal =
|
||||
data.principal_trait_ref_with_self_ty(self.tcx(),
|
||||
self.tcx().types.err);
|
||||
for tr in util::supertraits(self.tcx(), principal) {
|
||||
let td = ty::lookup_trait_def(self.tcx(), tr.def_id());
|
||||
|
||||
if td.bounds.builtin_bounds.contains(&bound) {
|
||||
return Ok(If(Vec::new()))
|
||||
}
|
||||
|
|
@ -1268,6 +1437,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
nominal(self, bound, def_id, types)
|
||||
}
|
||||
|
||||
ty::ty_projection(_) |
|
||||
ty::ty_param(_) => {
|
||||
// Note: A type parameter is only considered to meet a
|
||||
// particular bound if there is a where clause telling
|
||||
|
|
@ -1359,7 +1529,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
fn confirm_candidate(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
candidate: Candidate<'tcx>)
|
||||
candidate: SelectionCandidate<'tcx>)
|
||||
-> Result<Selection<'tcx>,SelectionError<'tcx>>
|
||||
{
|
||||
debug!("confirm_candidate({}, {})",
|
||||
|
|
@ -1377,8 +1547,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
ParamCandidate(param) => {
|
||||
Ok(VtableParam(
|
||||
try!(self.confirm_param_candidate(obligation, param))))
|
||||
self.confirm_param_candidate(obligation, param);
|
||||
Ok(VtableParam)
|
||||
}
|
||||
|
||||
ImplCandidate(impl_def_id) => {
|
||||
|
|
@ -1397,14 +1567,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
try!(self.confirm_fn_pointer_candidate(obligation));
|
||||
Ok(VtableFnPointer(fn_type))
|
||||
}
|
||||
|
||||
ProjectionCandidate => {
|
||||
self.confirm_projection_candidate(obligation);
|
||||
Ok(VtableParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_projection_candidate(&mut self,
|
||||
obligation: &TraitObligation<'tcx>)
|
||||
{
|
||||
let _: Result<(),()> =
|
||||
self.infcx.try(|snapshot| {
|
||||
let result =
|
||||
self.match_projection_obligation_against_bounds_from_trait(obligation,
|
||||
snapshot);
|
||||
assert!(result);
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
fn confirm_param_candidate(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
param: VtableParamData<'tcx>)
|
||||
-> Result<VtableParamData<'tcx>,
|
||||
SelectionError<'tcx>>
|
||||
param: ty::PolyTraitRef<'tcx>)
|
||||
{
|
||||
debug!("confirm_param_candidate({},{})",
|
||||
obligation.repr(self.tcx()),
|
||||
|
|
@ -1415,13 +1601,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// trait-ref. Repeat that unification now without any
|
||||
// transactional boundary; it should not fail.
|
||||
match self.confirm_poly_trait_refs(obligation.cause.clone(),
|
||||
obligation.trait_ref.clone(),
|
||||
param.bound.clone()) {
|
||||
Ok(()) => Ok(param),
|
||||
obligation.predicate.to_poly_trait_ref(),
|
||||
param.clone()) {
|
||||
Ok(()) => { }
|
||||
Err(_) => {
|
||||
self.tcx().sess.bug(
|
||||
format!("Where clause `{}` was applicable to `{}` but now is not",
|
||||
param.bound.repr(self.tcx()),
|
||||
param.repr(self.tcx()),
|
||||
obligation.repr(self.tcx())).as_slice());
|
||||
}
|
||||
}
|
||||
|
|
@ -1454,13 +1640,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
-> VtableBuiltinData<PredicateObligation<'tcx>>
|
||||
{
|
||||
let derived_cause = self.derived_cause(obligation, BuiltinDerivedObligation);
|
||||
let obligations = nested.iter().map(|&t| {
|
||||
util::predicate_for_builtin_bound(
|
||||
self.tcx(),
|
||||
derived_cause.clone(),
|
||||
bound,
|
||||
obligation.recursion_depth + 1,
|
||||
t)
|
||||
let obligations = nested.iter().map(|&bound_ty| {
|
||||
// the obligation might be higher-ranked, e.g. for<'a> &'a
|
||||
// int : Copy. In that case, we will wind up with
|
||||
// late-bound regions in the `nested` vector. So for each
|
||||
// one we instantiate to a skolemized region, do our work
|
||||
// to produce something like `&'0 int : Copy`, and then
|
||||
// re-bind it. This is a bit of busy-work but preserves
|
||||
// the invariant that we only manipulate free regions, not
|
||||
// bound ones.
|
||||
self.infcx.try(|snapshot| {
|
||||
let (skol_ty, skol_map) =
|
||||
self.infcx().skolemize_late_bound_regions(&ty::Binder(bound_ty), snapshot);
|
||||
let skol_predicate =
|
||||
util::predicate_for_builtin_bound(
|
||||
self.tcx(),
|
||||
derived_cause.clone(),
|
||||
bound,
|
||||
obligation.recursion_depth + 1,
|
||||
skol_ty);
|
||||
match skol_predicate {
|
||||
Ok(skol_predicate) => Ok(self.infcx().plug_leaks(skol_map, snapshot,
|
||||
&skol_predicate)),
|
||||
Err(ErrorReported) => Err(ErrorReported)
|
||||
}
|
||||
})
|
||||
}).collect::<Result<_, _>>();
|
||||
let mut obligations = match obligations {
|
||||
Ok(o) => o,
|
||||
|
|
@ -1472,13 +1676,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligations.push(Obligation {
|
||||
cause: obligation.cause.clone(),
|
||||
recursion_depth: obligation.recursion_depth+1,
|
||||
trait_ref: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(),
|
||||
predicate: ty::Binder(ty::OutlivesPredicate(obligation.self_ty(),
|
||||
ty::ReStatic)).as_predicate(),
|
||||
});
|
||||
}
|
||||
|
||||
let obligations = VecPerParamSpace::new(obligations, Vec::new(),
|
||||
Vec::new(), Vec::new());
|
||||
let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new());
|
||||
|
||||
debug!("vtable_builtin_data: obligations={}",
|
||||
obligations.repr(self.tcx()));
|
||||
|
|
@ -1500,9 +1703,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// this time not in a probe.
|
||||
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));
|
||||
self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot);
|
||||
let substs =
|
||||
self.rematch_impl(impl_def_id, obligation,
|
||||
snapshot, &skol_map, skol_obligation_trait_ref.trait_ref);
|
||||
debug!("confirm_impl_candidate substs={}", substs);
|
||||
Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(),
|
||||
obligation.recursion_depth + 1, skol_map, snapshot))
|
||||
|
|
@ -1571,15 +1775,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
Substs::new_trait(
|
||||
vec![arguments_tuple, output_type],
|
||||
vec![],
|
||||
vec![],
|
||||
self_ty);
|
||||
let trait_ref = Rc::new(ty::Binder(ty::TraitRef {
|
||||
def_id: obligation.trait_ref.def_id(),
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef {
|
||||
def_id: obligation.predicate.def_id(),
|
||||
substs: self.tcx().mk_substs(substs),
|
||||
}));
|
||||
|
||||
try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
|
||||
obligation.trait_ref.clone(),
|
||||
obligation.predicate.to_poly_trait_ref(),
|
||||
trait_ref));
|
||||
Ok(self_ty)
|
||||
}
|
||||
|
|
@ -1612,10 +1815,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
vec![arguments_tuple.subst(self.tcx(), substs),
|
||||
closure_sig.0.output.unwrap().subst(self.tcx(), substs)],
|
||||
vec![],
|
||||
vec![],
|
||||
obligation.self_ty());
|
||||
let trait_ref = Rc::new(ty::Binder(ty::TraitRef {
|
||||
def_id: obligation.trait_ref.def_id(),
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef {
|
||||
def_id: obligation.predicate.def_id(),
|
||||
substs: self.tcx().mk_substs(substs),
|
||||
}));
|
||||
|
||||
|
|
@ -1624,7 +1826,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
trait_ref.repr(self.tcx()));
|
||||
|
||||
self.confirm_poly_trait_refs(obligation.cause.clone(),
|
||||
obligation.trait_ref.clone(),
|
||||
obligation.predicate.to_poly_trait_ref(),
|
||||
trait_ref)
|
||||
}
|
||||
|
||||
|
|
@ -1655,8 +1857,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// 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>>)
|
||||
obligation_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
expected_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Result<(), SelectionError<'tcx>>
|
||||
{
|
||||
let origin = infer::RelateOutputImplTypes(obligation_cause.span);
|
||||
|
|
@ -1769,7 +1971,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// substitution if we find that any of the input types, when
|
||||
// simplified, do not match.
|
||||
|
||||
obligation.trait_ref.input_types().iter()
|
||||
obligation.predicate.0.input_types().iter()
|
||||
.zip(impl_trait_ref.input_types().iter())
|
||||
.any(|(&obligation_ty, &impl_ty)| {
|
||||
let simplified_obligation_ty =
|
||||
|
|
@ -1785,7 +1987,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
fn match_where_clause(&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
where_clause_trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Result<(),()>
|
||||
{
|
||||
debug!("match_where_clause: obligation={} where_clause_trait_ref={}",
|
||||
|
|
@ -1796,7 +1998,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
match self.infcx.sub_poly_trait_refs(false,
|
||||
origin,
|
||||
where_clause_trait_ref,
|
||||
obligation.trait_ref.clone()) {
|
||||
obligation.predicate.to_poly_trait_ref()) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
|
|
@ -1878,7 +2080,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
obligation: &'o TraitObligation<'tcx>)
|
||||
-> TraitObligationStack<'o, 'tcx>
|
||||
{
|
||||
let fresh_trait_ref = obligation.trait_ref.fold_with(&mut self.freshener);
|
||||
let fresh_trait_ref =
|
||||
obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener);
|
||||
|
||||
TraitObligationStack {
|
||||
obligation: obligation,
|
||||
|
|
@ -1931,9 +2134,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
#[allow(unused_comparisons)]
|
||||
fn derived_cause(&self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
variant: fn(Rc<ty::Binder<ty::TraitRef<'tcx>>>,
|
||||
Rc<ObligationCauseCode<'tcx>>)
|
||||
-> ObligationCauseCode<'tcx>)
|
||||
variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>)
|
||||
-> ObligationCause<'tcx>
|
||||
{
|
||||
/*!
|
||||
|
|
@ -1950,29 +2151,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// chain. Ideally, we should have a way to configure this either
|
||||
// by using -Z verbose or just a CLI argument.
|
||||
if obligation.recursion_depth >= 0 {
|
||||
let derived_cause = DerivedObligationCause {
|
||||
parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
|
||||
parent_code: Rc::new(obligation.cause.code.clone()),
|
||||
};
|
||||
ObligationCause::new(obligation.cause.span,
|
||||
obligation.trait_ref.def_id().node,
|
||||
variant(obligation.trait_ref.clone(),
|
||||
Rc::new(obligation.cause.code.clone())))
|
||||
obligation.cause.body_id,
|
||||
variant(derived_cause))
|
||||
} else {
|
||||
obligation.cause.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
|
||||
impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
ErrorCandidate => format!("ErrorCandidate"),
|
||||
BuiltinCandidate(b) => format!("BuiltinCandidate({})", b),
|
||||
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
|
||||
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
|
||||
ProjectionCandidate => format!("ProjectionCandidate"),
|
||||
FnPointerCandidate => format!("FnPointerCandidate"),
|
||||
UnboxedClosureCandidate(c, ref s) => {
|
||||
format!("UnboxedClosureCandidate({},{})", c, s.repr(tcx))
|
||||
}
|
||||
FnPointerCandidate => {
|
||||
format!("FnPointerCandidate")
|
||||
}
|
||||
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
|
||||
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::subst::{Subst, Substs, VecPerParamSpace};
|
||||
use middle::subst::{Substs, VecPerParamSpace};
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, Ty, AsPredicate, ToPolyTraitRef};
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -20,7 +20,7 @@ use util::common::ErrorReported;
|
|||
use util::ppaux::Repr;
|
||||
|
||||
use super::{Obligation, ObligationCause, PredicateObligation,
|
||||
VtableImpl, VtableParam, VtableParamData, VtableImplData};
|
||||
VtableImpl, VtableParam, VtableImplData};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// `Elaboration` iterator
|
||||
|
|
@ -46,19 +46,19 @@ struct StackEntry<'tcx> {
|
|||
|
||||
pub fn elaborate_trait_ref<'cx, 'tcx>(
|
||||
tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Elaborator<'cx, 'tcx>
|
||||
{
|
||||
elaborate_predicates(tcx, vec![ty::Predicate::Trait(trait_ref)])
|
||||
elaborate_predicates(tcx, vec![trait_ref.as_predicate()])
|
||||
}
|
||||
|
||||
pub fn elaborate_trait_refs<'cx, 'tcx>(
|
||||
tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_refs: &[Rc<ty::PolyTraitRef<'tcx>>])
|
||||
trait_refs: &[ty::PolyTraitRef<'tcx>])
|
||||
-> Elaborator<'cx, 'tcx>
|
||||
{
|
||||
let predicates = trait_refs.iter()
|
||||
.map(|trait_ref| ty::Predicate::Trait((*trait_ref).clone()))
|
||||
.map(|trait_ref| trait_ref.as_predicate())
|
||||
.collect();
|
||||
elaborate_predicates(tcx, predicates)
|
||||
}
|
||||
|
|
@ -78,23 +78,34 @@ pub fn elaborate_predicates<'cx, 'tcx>(
|
|||
}
|
||||
|
||||
impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
|
||||
pub fn filter_to_traits(self) -> Supertraits<'cx, 'tcx> {
|
||||
Supertraits { elaborator: self }
|
||||
}
|
||||
|
||||
fn push(&mut self, predicate: &ty::Predicate<'tcx>) {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
let mut predicates =
|
||||
ty::predicates_for_trait_ref(self.tcx, &**trait_ref);
|
||||
ty::predicates_for_trait_ref(self.tcx,
|
||||
&data.to_poly_trait_ref());
|
||||
|
||||
// Only keep those bounds that we haven't already
|
||||
// seen. This is necessary to prevent infinite
|
||||
// recursion in some cases. One common case is when
|
||||
// people define `trait Sized { }` rather than `trait
|
||||
// Sized for Sized? { }`.
|
||||
predicates.retain(|r| self.visited.insert((*r).clone()));
|
||||
predicates.retain(|r| self.visited.insert(r.clone()));
|
||||
|
||||
self.stack.push(StackEntry { position: 0,
|
||||
predicates: predicates });
|
||||
}
|
||||
ty::Predicate::Equate(..) => {
|
||||
// Currently, we do not "elaborate" predicates like
|
||||
// `X == Y`, though conceivably we might. For example,
|
||||
// `&X == &Y` implies that `X == Y`.
|
||||
}
|
||||
ty::Predicate::Projection(..) => {
|
||||
// Nothing to elaborate in a projection predicate.
|
||||
}
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
|
|
@ -173,34 +184,30 @@ pub struct Supertraits<'cx, 'tcx:'cx> {
|
|||
}
|
||||
|
||||
pub fn supertraits<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
||||
trait_ref: Rc<ty::PolyTraitRef<'tcx>>)
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> Supertraits<'cx, 'tcx>
|
||||
{
|
||||
let elaborator = elaborate_trait_ref(tcx, trait_ref);
|
||||
Supertraits { elaborator: elaborator }
|
||||
elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
|
||||
}
|
||||
|
||||
pub fn transitive_bounds<'cx, 'tcx>(tcx: &'cx ty::ctxt<'tcx>,
|
||||
bounds: &[Rc<ty::PolyTraitRef<'tcx>>])
|
||||
bounds: &[ty::PolyTraitRef<'tcx>])
|
||||
-> Supertraits<'cx, 'tcx>
|
||||
{
|
||||
let elaborator = elaborate_trait_refs(tcx, bounds);
|
||||
Supertraits { elaborator: elaborator }
|
||||
elaborate_trait_refs(tcx, bounds).filter_to_traits()
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> Iterator<Rc<ty::PolyTraitRef<'tcx>>> for Supertraits<'cx, 'tcx> {
|
||||
fn next(&mut self) -> Option<Rc<ty::PolyTraitRef<'tcx>>> {
|
||||
impl<'cx, 'tcx> Iterator<ty::PolyTraitRef<'tcx>> for Supertraits<'cx, 'tcx> {
|
||||
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
|
||||
loop {
|
||||
match self.elaborator.next() {
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
Some(ty::Predicate::Trait(trait_ref)) => {
|
||||
return Some(trait_ref);
|
||||
Some(ty::Predicate::Trait(data)) => {
|
||||
return Some(data.to_poly_trait_ref());
|
||||
}
|
||||
Some(ty::Predicate::Equate(..)) |
|
||||
Some(ty::Predicate::RegionOutlives(..)) |
|
||||
Some(ty::Predicate::TypeOutlives(..)) => {
|
||||
Some(_) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -222,18 +229,7 @@ pub fn fresh_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
|||
{
|
||||
let tcx = infcx.tcx;
|
||||
let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics;
|
||||
let input_substs = infcx.fresh_substs_for_generics(span, &impl_generics);
|
||||
|
||||
// Add substs for the associated types bound in the impl.
|
||||
let ref items = tcx.impl_items.borrow()[impl_def_id];
|
||||
let mut assoc_tys = Vec::new();
|
||||
for item in items.iter() {
|
||||
if let &ty::ImplOrTraitItemId::TypeTraitItemId(id) = item {
|
||||
assoc_tys.push(tcx.tcache.borrow()[id].ty.subst(tcx, &input_substs));
|
||||
}
|
||||
}
|
||||
|
||||
input_substs.with_assoc_tys(assoc_tys)
|
||||
infcx.fresh_substs_for_generics(span, &impl_generics)
|
||||
}
|
||||
|
||||
impl<'tcx, N> fmt::Show for VtableImplData<'tcx, N> {
|
||||
|
|
@ -242,12 +238,6 @@ impl<'tcx, N> fmt::Show for VtableImplData<'tcx, N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Show for VtableParamData<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "VtableParam(...)")
|
||||
}
|
||||
}
|
||||
|
||||
/// See `super::obligations_for_generics`
|
||||
pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
|
|
@ -261,22 +251,22 @@ pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
generic_bounds.predicates.map(|predicate| {
|
||||
Obligation { cause: cause.clone(),
|
||||
recursion_depth: recursion_depth,
|
||||
trait_ref: predicate.clone() }
|
||||
predicate: predicate.clone() }
|
||||
})
|
||||
}
|
||||
|
||||
pub fn poly_trait_ref_for_builtin_bound<'tcx>(
|
||||
pub fn trait_ref_for_builtin_bound<'tcx>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
builtin_bound: ty::BuiltinBound,
|
||||
param_ty: Ty<'tcx>)
|
||||
-> Result<Rc<ty::PolyTraitRef<'tcx>>, ErrorReported>
|
||||
-> Result<Rc<ty::TraitRef<'tcx>>, ErrorReported>
|
||||
{
|
||||
match tcx.lang_items.from_builtin_kind(builtin_bound) {
|
||||
Ok(def_id) => {
|
||||
Ok(Rc::new(ty::Binder(ty::TraitRef {
|
||||
Ok(Rc::new(ty::TraitRef {
|
||||
def_id: def_id,
|
||||
substs: tcx.mk_substs(Substs::empty().with_self_ty(param_ty))
|
||||
})))
|
||||
}))
|
||||
}
|
||||
Err(e) => {
|
||||
tcx.sess.err(e.as_slice());
|
||||
|
|
@ -293,38 +283,18 @@ pub fn predicate_for_builtin_bound<'tcx>(
|
|||
param_ty: Ty<'tcx>)
|
||||
-> Result<PredicateObligation<'tcx>, ErrorReported>
|
||||
{
|
||||
let trait_ref = try!(poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty));
|
||||
let trait_ref = try!(trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty));
|
||||
Ok(Obligation {
|
||||
cause: cause,
|
||||
recursion_depth: recursion_depth,
|
||||
trait_ref: ty::Predicate::Trait(trait_ref),
|
||||
predicate: trait_ref.as_predicate(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Starting from a caller obligation `caller_bound` (which has coordinates `space`/`i` in the list
|
||||
/// of caller obligations), search through the trait and supertraits to find one where `test(d)` is
|
||||
/// true, where `d` is the def-id of the trait/supertrait. If any is found, return `Some(p)` where
|
||||
/// `p` is the path to that trait/supertrait. Else `None`.
|
||||
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()) {
|
||||
let vtable_param = VtableParamData { bound: bound };
|
||||
return Some(vtable_param);
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
format!("Obligation(trait_ref={},depth={})",
|
||||
self.trait_ref.repr(tcx),
|
||||
format!("Obligation(predicate={},depth={})",
|
||||
self.predicate.repr(tcx),
|
||||
self.recursion_depth)
|
||||
}
|
||||
}
|
||||
|
|
@ -344,8 +314,8 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
|
|||
format!("VtableFnPointer({})",
|
||||
d.repr(tcx)),
|
||||
|
||||
super::VtableParam(ref v) =>
|
||||
format!("VtableParam({})", v.repr(tcx)),
|
||||
super::VtableParam =>
|
||||
format!("VtableParam"),
|
||||
|
||||
super::VtableBuiltin(ref d) =>
|
||||
d.repr(tcx)
|
||||
|
|
@ -369,13 +339,6 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableBuiltinData<N> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for super::VtableParamData<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
format!("VtableParam(bound={})",
|
||||
self.bound.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
|
|
@ -406,6 +369,7 @@ impl<'tcx> Repr<'tcx> for super::FulfillmentErrorCode<'tcx> {
|
|||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
super::CodeSelectionError(ref o) => o.repr(tcx),
|
||||
super::CodeProjectionError(ref o) => o.repr(tcx),
|
||||
super::CodeAmbiguity => format!("Ambiguity")
|
||||
}
|
||||
}
|
||||
|
|
@ -415,13 +379,22 @@ impl<'tcx> fmt::Show for super::FulfillmentErrorCode<'tcx> {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
super::CodeSelectionError(ref e) => write!(f, "{}", e),
|
||||
super::CodeProjectionError(ref e) => write!(f, "{}", e),
|
||||
super::CodeAmbiguity => write!(f, "Ambiguity")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::type_err<'tcx> {
|
||||
impl<'tcx> Repr<'tcx> for super::MismatchedProjectionTypes<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
ty::type_err_to_str(tcx, self)
|
||||
self.err.repr(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Show for super::MismatchedProjectionTypes<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "MismatchedProjectionTypes(..)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -121,8 +121,8 @@ pub trait TypeFolder<'tcx> {
|
|||
super_fold_trait_store(self, s)
|
||||
}
|
||||
|
||||
fn fold_existential_bounds(&mut self, s: ty::ExistentialBounds)
|
||||
-> ty::ExistentialBounds {
|
||||
fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>)
|
||||
-> ty::ExistentialBounds<'tcx> {
|
||||
super_fold_existential_bounds(self, s)
|
||||
}
|
||||
|
||||
|
|
@ -170,6 +170,13 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Box<T> {
|
||||
let content: T = (**self).fold_with(folder);
|
||||
box content
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Vec<T> {
|
||||
self.iter().map(|t| t.fold_with(folder)).collect()
|
||||
|
|
@ -342,9 +349,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ExistentialBounds {
|
||||
folder.fold_existential_bounds(*self)
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ExistentialBounds<'tcx> {
|
||||
folder.fold_existential_bounds(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -354,6 +361,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ParamBounds<'tcx> {
|
|||
region_bounds: self.region_bounds.fold_with(folder),
|
||||
builtin_bounds: self.builtin_bounds.fold_with(folder),
|
||||
trait_bounds: self.trait_bounds.fold_with(folder),
|
||||
projection_bounds: self.projection_bounds.fold_with(folder),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -365,7 +373,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
|
|||
def_id: self.def_id,
|
||||
space: self.space,
|
||||
index: self.index,
|
||||
associated_with: self.associated_with,
|
||||
bounds: self.bounds.fold_with(folder),
|
||||
default: self.default.fold_with(folder),
|
||||
}
|
||||
|
|
@ -405,6 +412,26 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
|
|||
ty::Predicate::RegionOutlives(binder.fold_with(folder)),
|
||||
ty::Predicate::TypeOutlives(ref binder) =>
|
||||
ty::Predicate::TypeOutlives(binder.fold_with(folder)),
|
||||
ty::Predicate::Projection(ref binder) =>
|
||||
ty::Predicate::Projection(binder.fold_with(folder)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionPredicate<'tcx> {
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: self.projection_ty.fold_with(folder),
|
||||
ty: self.ty.fold_with(folder),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ProjectionTy<'tcx> {
|
||||
ty::ProjectionTy {
|
||||
trait_ref: self.trait_ref.fold_with(folder),
|
||||
item_name: self.item_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -422,7 +449,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> {
|
|||
match *self {
|
||||
ty::UnsizeLength(len) => ty::UnsizeLength(len),
|
||||
ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n),
|
||||
ty::UnsizeVtable(ty::TyTrait{ref principal, bounds}, self_ty) => {
|
||||
ty::UnsizeVtable(ty::TyTrait{ref principal, ref bounds}, self_ty) => {
|
||||
ty::UnsizeVtable(
|
||||
ty::TyTrait {
|
||||
principal: principal.fold_with(folder),
|
||||
|
|
@ -441,7 +468,7 @@ impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O>
|
|||
traits::Obligation {
|
||||
cause: self.cause.clone(),
|
||||
recursion_depth: self.recursion_depth,
|
||||
trait_ref: self.trait_ref.fold_with(folder),
|
||||
predicate: self.predicate.fold_with(folder),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -474,20 +501,12 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
|
|||
traits::VtableFnPointer(ref d) => {
|
||||
traits::VtableFnPointer(d.fold_with(folder))
|
||||
}
|
||||
traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)),
|
||||
traits::VtableParam => traits::VtableParam,
|
||||
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for traits::VtableParamData<'tcx> {
|
||||
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableParamData<'tcx> {
|
||||
traits::VtableParamData {
|
||||
bound: self.bound.fold_with(folder),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
|
|
@ -495,6 +514,14 @@ impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitPredicate<'tcx> {
|
||||
ty::TraitPredicate {
|
||||
trait_ref: self.trait_ref.fold_with(folder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
|
||||
where T : TypeFoldable<'tcx>,
|
||||
U : TypeFoldable<'tcx>,
|
||||
|
|
@ -530,9 +557,9 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
|||
let substs = substs.fold_with(this);
|
||||
ty::ty_enum(tid, this.tcx().mk_substs(substs))
|
||||
}
|
||||
ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
|
||||
ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
|
||||
ty::ty_trait(box ty::TyTrait {
|
||||
principal: (*principal).fold_with(this),
|
||||
principal: principal.fold_with(this),
|
||||
bounds: bounds.fold_with(this),
|
||||
})
|
||||
}
|
||||
|
|
@ -544,7 +571,7 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
|||
ty::ty_bare_fn(opt_def_id, this.tcx().mk_bare_fn(bfn))
|
||||
}
|
||||
ty::ty_closure(ref f) => {
|
||||
ty::ty_closure(box f.fold_with(this))
|
||||
ty::ty_closure(f.fold_with(this))
|
||||
}
|
||||
ty::ty_rptr(r, ref tm) => {
|
||||
let r = r.fold_with(this);
|
||||
|
|
@ -559,6 +586,9 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
|||
let s = substs.fold_with(this);
|
||||
ty::ty_unboxed_closure(did, this.tcx().mk_region(r), this.tcx().mk_substs(s))
|
||||
}
|
||||
ty::ty_projection(ref data) => {
|
||||
ty::ty_projection(data.fold_with(this))
|
||||
}
|
||||
ty::ty_bool | ty::ty_char | ty::ty_str |
|
||||
ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
|
||||
ty::ty_err | ty::ty_infer(_) |
|
||||
|
|
@ -655,12 +685,15 @@ pub fn super_fold_trait_store<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
||||
bounds: ty::ExistentialBounds)
|
||||
-> ty::ExistentialBounds {
|
||||
pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>(
|
||||
this: &mut T,
|
||||
bounds: &ty::ExistentialBounds<'tcx>)
|
||||
-> ty::ExistentialBounds<'tcx>
|
||||
{
|
||||
ty::ExistentialBounds {
|
||||
region_bound: bounds.region_bound.fold_with(this),
|
||||
builtin_bounds: bounds.builtin_bounds,
|
||||
projection_bounds: bounds.projection_bounds.fold_with(this),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -448,6 +448,12 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
|
|||
bound_sep,
|
||||
bound_str)
|
||||
}
|
||||
ty::ty_projection(ref data) => {
|
||||
format!("<{} as {}>::{}",
|
||||
data.trait_ref.self_ty().user_string(cx),
|
||||
data.trait_ref.user_string(cx),
|
||||
data.item_name.user_string(cx))
|
||||
}
|
||||
ty_str => "str".to_string(),
|
||||
ty_unboxed_closure(ref did, _, substs) => {
|
||||
let unboxed_closures = cx.unboxed_closures.borrow();
|
||||
|
|
@ -695,10 +701,9 @@ impl<'tcx> Repr<'tcx> for subst::Substs<'tcx> {
|
|||
|
||||
impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for subst::VecPerParamSpace<T> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("[{};{};{};{}]",
|
||||
format!("[{};{};{}]",
|
||||
self.get_slice(subst::TypeSpace).repr(tcx),
|
||||
self.get_slice(subst::SelfSpace).repr(tcx),
|
||||
self.get_slice(subst::AssocSpace).repr(tcx),
|
||||
self.get_slice(subst::FnSpace).repr(tcx))
|
||||
}
|
||||
}
|
||||
|
|
@ -733,8 +738,8 @@ impl<'tcx> Repr<'tcx> for ty::BuiltinBounds {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::ExistentialBounds {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
self.user_string(tcx)
|
||||
}
|
||||
}
|
||||
|
|
@ -929,9 +934,9 @@ impl<'tcx> Repr<'tcx> for ast::DefId {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::Polytype<'tcx> {
|
||||
impl<'tcx> Repr<'tcx> for ty::TypeScheme<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("Polytype {{generics: {}, ty: {}}}",
|
||||
format!("TypeScheme {{generics: {}, ty: {}}}",
|
||||
self.generics.repr(tcx),
|
||||
self.ty.repr(tcx))
|
||||
}
|
||||
|
|
@ -1136,8 +1141,8 @@ impl<'tcx> UserString<'tcx> for ty::ParamBounds<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for ty::ExistentialBounds {
|
||||
fn user_string(&self, tcx: &ctxt) -> String {
|
||||
impl<'tcx> UserString<'tcx> for ty::ExistentialBounds<'tcx> {
|
||||
fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
if self.builtin_bounds.contains(&ty::BoundSend) &&
|
||||
self.region_bound == ty::ReStatic
|
||||
{ // Region bound is implied by builtin bounds:
|
||||
|
|
@ -1322,17 +1327,8 @@ impl<'tcx> Repr<'tcx> for ty::ExplicitSelfCategory {
|
|||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for ParamTy {
|
||||
fn user_string(&self, tcx: &ctxt) -> String {
|
||||
let id = self.idx;
|
||||
let did = self.def_id;
|
||||
let ident = match tcx.ty_param_defs.borrow().get(&did.node) {
|
||||
Some(def) => token::get_name(def.name).get().to_string(),
|
||||
|
||||
// This can only happen when a type mismatch error happens and
|
||||
// the actual type has more type parameters than the expected one.
|
||||
None => format!("<generic #{}>", id),
|
||||
};
|
||||
ident
|
||||
fn user_string(&self, _tcx: &ctxt) -> String {
|
||||
format!("{}", token::get_name(self.name))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1408,17 +1404,55 @@ impl<'tcx> UserString<'tcx> for ty::EquatePredicate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("TraitPredicate({})",
|
||||
self.trait_ref.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("{} : {}",
|
||||
self.trait_ref.self_ty().user_string(tcx),
|
||||
self.trait_ref.user_string(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("{} == {}",
|
||||
self.projection_ty.user_string(tcx),
|
||||
self.ty.user_string(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("<{} as {}>::{}",
|
||||
self.trait_ref.self_ty().repr(tcx),
|
||||
self.trait_ref.repr(tcx),
|
||||
self.item_name.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for ty::ProjectionTy<'tcx> {
|
||||
fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("<{} as {}>::{}",
|
||||
self.trait_ref.self_ty().user_string(tcx),
|
||||
self.trait_ref.user_string(tcx),
|
||||
self.item_name.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::Trait(ref data) => data.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),
|
||||
ty::Predicate::Projection(ref predicate) => predicate.user_string(tcx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
|||
{
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut clcx,
|
||||
bccx.tcx,
|
||||
param_env.clone());
|
||||
¶m_env);
|
||||
euv.walk_fn(decl, body);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
|||
{
|
||||
let mut euv = euv::ExprUseVisitor::new(&mut glcx,
|
||||
bccx.tcx,
|
||||
param_env);
|
||||
¶m_env);
|
||||
euv.walk_fn(decl, body);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ 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};
|
||||
use syntax::{abi, ast, ast_map};
|
||||
use syntax::codemap;
|
||||
use syntax::codemap::{Span, CodeMap, DUMMY_SP};
|
||||
use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help};
|
||||
|
|
@ -145,6 +145,10 @@ fn test_env<F>(source_string: &str,
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> Env<'a, 'tcx> {
|
||||
pub fn tcx(&self) -> &ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
pub fn create_region_hierarchy(&self, rh: &RH) {
|
||||
for child_rh in rh.sub.iter() {
|
||||
self.create_region_hierarchy(child_rh);
|
||||
|
|
@ -296,7 +300,8 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn t_param(&self, space: subst::ParamSpace, index: u32) -> Ty<'tcx> {
|
||||
ty::mk_param(self.infcx.tcx, space, index, ast_util::local_def(ast::DUMMY_NODE_ID))
|
||||
let name = format!("T{}", index);
|
||||
ty::mk_param(self.infcx.tcx, space, index, token::intern(name[]))
|
||||
}
|
||||
|
||||
pub fn re_early_bound(&self,
|
||||
|
|
@ -314,14 +319,16 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> {
|
||||
ty::mk_imm_rptr(self.infcx.tcx, self.infcx.tcx.mk_region(r), ty::mk_int())
|
||||
ty::mk_imm_rptr(self.infcx.tcx,
|
||||
self.infcx.tcx.mk_region(r),
|
||||
self.tcx().types.int)
|
||||
}
|
||||
|
||||
pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> {
|
||||
let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1));
|
||||
ty::mk_imm_rptr(self.infcx.tcx,
|
||||
self.infcx.tcx.mk_region(r),
|
||||
ty::mk_int())
|
||||
self.tcx().types.int)
|
||||
}
|
||||
|
||||
pub fn t_rptr_late_bound_with_debruijn(&self,
|
||||
|
|
@ -331,12 +338,13 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
|
|||
let r = self.re_late_bound_with_debruijn(id, debruijn);
|
||||
ty::mk_imm_rptr(self.infcx.tcx,
|
||||
self.infcx.tcx.mk_region(r),
|
||||
ty::mk_int())
|
||||
self.tcx().types.int)
|
||||
}
|
||||
|
||||
pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
|
||||
let r = ty::ReScope(CodeExtent::from_node_id(id));
|
||||
ty::mk_imm_rptr(self.infcx.tcx, self.infcx.tcx.mk_region(r), ty::mk_int())
|
||||
ty::mk_imm_rptr(self.infcx.tcx, self.infcx.tcx.mk_region(r),
|
||||
self.tcx().types.int)
|
||||
}
|
||||
|
||||
pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region {
|
||||
|
|
@ -346,15 +354,19 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
|
|||
|
||||
pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> {
|
||||
let r = self.re_free(nid, id);
|
||||
ty::mk_imm_rptr(self.infcx.tcx, self.infcx.tcx.mk_region(r), ty::mk_int())
|
||||
ty::mk_imm_rptr(self.infcx.tcx,
|
||||
self.infcx.tcx.mk_region(r),
|
||||
self.tcx().types.int)
|
||||
}
|
||||
|
||||
pub fn t_rptr_static(&self) -> Ty<'tcx> {
|
||||
ty::mk_imm_rptr(self.infcx.tcx, self.infcx.tcx.mk_region(ty::ReStatic), ty::mk_int())
|
||||
ty::mk_imm_rptr(self.infcx.tcx,
|
||||
self.infcx.tcx.mk_region(ty::ReStatic),
|
||||
self.tcx().types.int)
|
||||
}
|
||||
|
||||
pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
|
||||
infer::TypeTrace::dummy()
|
||||
infer::TypeTrace::dummy(self.tcx())
|
||||
}
|
||||
|
||||
pub fn sub(&self) -> Sub<'a, 'tcx> {
|
||||
|
|
@ -480,8 +492,8 @@ fn sub_free_bound_false() {
|
|||
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()));
|
||||
env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -496,8 +508,8 @@ fn sub_bound_free_true() {
|
|||
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()));
|
||||
env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -512,8 +524,8 @@ fn sub_free_bound_false_infer() {
|
|||
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()));
|
||||
env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -531,9 +543,9 @@ fn lub_free_bound_infer() {
|
|||
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()));
|
||||
env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.int));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -542,9 +554,9 @@ fn lub_bound_bound() {
|
|||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_bound2 = env.t_rptr_late_bound(2);
|
||||
env.check_lub(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_bound2], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_bound1], ty::mk_int()));
|
||||
env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound2], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -553,9 +565,9 @@ fn lub_bound_free() {
|
|||
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_lub(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_free1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_free1], ty::mk_int()));
|
||||
env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -564,9 +576,9 @@ fn lub_bound_static() {
|
|||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_static = env.t_rptr_static();
|
||||
env.check_lub(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_static], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_static], ty::mk_int()));
|
||||
env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_static], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_static], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -587,9 +599,9 @@ fn lub_free_free() {
|
|||
let t_rptr_free1 = env.t_rptr_free(0, 1);
|
||||
let t_rptr_free2 = env.t_rptr_free(0, 2);
|
||||
let t_rptr_static = env.t_rptr_static();
|
||||
env.check_lub(env.t_fn(&[t_rptr_free1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_free2], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_static], ty::mk_int()));
|
||||
env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_free2], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_static], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -612,9 +624,9 @@ fn glb_free_free_with_common_scope() {
|
|||
let t_rptr_free1 = env.t_rptr_free(0, 1);
|
||||
let t_rptr_free2 = env.t_rptr_free(0, 2);
|
||||
let t_rptr_scope = env.t_rptr_scope(0);
|
||||
env.check_glb(env.t_fn(&[t_rptr_free1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_free2], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_scope], ty::mk_int()));
|
||||
env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_free2], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_scope], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -623,9 +635,9 @@ fn glb_bound_bound() {
|
|||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_bound2 = env.t_rptr_late_bound(2);
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_bound2], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_bound1], ty::mk_int()));
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound2], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -634,9 +646,9 @@ fn glb_bound_free() {
|
|||
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_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_free1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_bound1], ty::mk_int()));
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_free1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -648,9 +660,9 @@ fn glb_bound_free_infer() {
|
|||
|
||||
// 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()));
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
|
||||
env.t_fn(&[t_infer1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
|
||||
|
||||
// as a side-effect, computing GLB should unify `_` with
|
||||
// `&'_ int`
|
||||
|
|
@ -667,9 +679,9 @@ fn glb_bound_static() {
|
|||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_static = env.t_rptr_static();
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_static], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_bound1], ty::mk_int()));
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_static], env.tcx().types.int),
|
||||
env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -790,7 +802,6 @@ fn escaping() {
|
|||
/// late-bound region.
|
||||
#[test]
|
||||
fn subst_region_renumber_region() {
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let re_bound1 = env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
|
||||
|
||||
|
|
|
|||
|
|
@ -3906,7 +3906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
// If the def is a ty param, and came from the parent
|
||||
// item, it's ok
|
||||
match def {
|
||||
DefTyParam(_, did, _) if {
|
||||
DefTyParam(_, _, did, _) if {
|
||||
self.def_map.borrow().get(&did.node).cloned()
|
||||
== Some(DefTyParamBinder(item_id))
|
||||
} => {} // ok
|
||||
|
|
@ -3959,7 +3959,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
// If the def is a ty param, and came from the parent
|
||||
// item, it's ok
|
||||
match def {
|
||||
DefTyParam(_, did, _) if {
|
||||
DefTyParam(_, _, did, _) if {
|
||||
self.def_map.borrow().get(&did.node).cloned()
|
||||
== Some(DefTyParamBinder(item_id))
|
||||
} => {} // ok
|
||||
|
|
@ -4265,8 +4265,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
seen_bindings.insert(name);
|
||||
|
||||
let def_like = DlDef(DefTyParam(space,
|
||||
index as u32,
|
||||
local_def(type_parameter.id),
|
||||
index as u32));
|
||||
name));
|
||||
// Associate this type parameter with
|
||||
// the item that bound it
|
||||
self.record_def(type_parameter.id,
|
||||
|
|
@ -5161,7 +5162,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
path.span) {
|
||||
Some((def, last_private)) => {
|
||||
match def {
|
||||
DefTyParam(_, did, _) => {
|
||||
DefTyParam(_, _, did, _) => {
|
||||
let def = DefAssociatedPath(TyParamProvenance::FromParam(did),
|
||||
path.segments.last()
|
||||
.unwrap().identifier);
|
||||
|
|
|
|||
|
|
@ -1122,7 +1122,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
let t = if kind == Compare {
|
||||
left_ty
|
||||
} else {
|
||||
ty::mk_uint() // vector length
|
||||
tcx.types.uint // vector length
|
||||
};
|
||||
let Result { bcx: after_cx, val: matches } = {
|
||||
match opt.trans(bcx) {
|
||||
|
|
@ -1263,7 +1263,7 @@ fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool
|
|||
};
|
||||
{
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx, param_env);
|
||||
let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx, ¶m_env);
|
||||
visitor.walk_expr(body);
|
||||
}
|
||||
rc.reassigned
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}).collect::<Vec<_>>();
|
||||
let packed = ty::lookup_packed(cx.tcx(), def_id);
|
||||
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
|
||||
if dtor { ftys.push(ty::mk_bool()); }
|
||||
if dtor { ftys.push(cx.tcx().types.bool); }
|
||||
|
||||
Univariant(mk_struct(cx, ftys[], packed, t), dtor)
|
||||
}
|
||||
|
|
@ -183,7 +183,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
// Uninhabitable; represent as unit
|
||||
// (Typechecking will reject discriminant-sizing attrs.)
|
||||
assert_eq!(hint, attr::ReprAny);
|
||||
let ftys = if dtor { vec!(ty::mk_bool()) } else { vec!() };
|
||||
let ftys = if dtor { vec!(cx.tcx().types.bool) } else { vec!() };
|
||||
return Univariant(mk_struct(cx, ftys[], false, t),
|
||||
dtor);
|
||||
}
|
||||
|
|
@ -215,7 +215,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
// (Typechecking will reject discriminant-sizing attrs.)
|
||||
assert_eq!(hint, attr::ReprAny);
|
||||
let mut ftys = cases[0].tys.clone();
|
||||
if dtor { ftys.push(ty::mk_bool()); }
|
||||
if dtor { ftys.push(cx.tcx().types.bool); }
|
||||
return Univariant(mk_struct(cx, ftys[], false, t),
|
||||
dtor);
|
||||
}
|
||||
|
|
@ -261,9 +261,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
// Create the set of structs that represent each variant
|
||||
// Use the minimum integer type we figured out above
|
||||
let fields : Vec<_> = cases.iter().map(|c| {
|
||||
let mut ftys = vec!(ty_of_inttype(min_ity));
|
||||
let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity));
|
||||
ftys.push_all(c.tys.as_slice());
|
||||
if dtor { ftys.push(ty::mk_bool()); }
|
||||
if dtor { ftys.push(cx.tcx().types.bool); }
|
||||
mk_struct(cx, ftys.as_slice(), false, t)
|
||||
}).collect();
|
||||
|
||||
|
|
@ -314,9 +314,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
};
|
||||
|
||||
let fields : Vec<_> = cases.iter().map(|c| {
|
||||
let mut ftys = vec!(ty_of_inttype(ity));
|
||||
let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity));
|
||||
ftys.push_all(c.tys[]);
|
||||
if dtor { ftys.push(ty::mk_bool()); }
|
||||
if dtor { ftys.push(cx.tcx().types.bool); }
|
||||
mk_struct(cx, ftys[], false, t)
|
||||
}).collect();
|
||||
|
||||
|
|
@ -343,7 +343,7 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
mut path: DiscrField) -> Option<DiscrField> {
|
||||
match ty.sty {
|
||||
// Fat &T/&mut T/Box<T> i.e. T is [T], str, or Trait
|
||||
ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) if !ty::type_is_sized(tcx, ty) => {
|
||||
ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) if !type_is_sized(tcx, ty) => {
|
||||
path.push(FAT_PTR_ADDR);
|
||||
Some(path)
|
||||
},
|
||||
|
|
@ -447,12 +447,12 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
tys: &[Ty<'tcx>], packed: bool,
|
||||
scapegoat: Ty<'tcx>)
|
||||
-> Struct<'tcx> {
|
||||
let sized = tys.iter().all(|&ty| ty::type_is_sized(cx.tcx(), ty));
|
||||
let sized = tys.iter().all(|&ty| type_is_sized(cx.tcx(), ty));
|
||||
let lltys : Vec<Type> = if sized {
|
||||
tys.iter()
|
||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
} else {
|
||||
tys.iter().filter(|&ty| ty::type_is_sized(cx.tcx(), *ty))
|
||||
tys.iter().filter(|&ty| type_is_sized(cx.tcx(), *ty))
|
||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
};
|
||||
|
||||
|
|
@ -553,11 +553,10 @@ fn bounds_usable(cx: &CrateContext, ity: IntType, bounds: &IntBounds) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(#17596) Ty<'tcx> is incorrectly invariant w.r.t 'tcx.
|
||||
pub fn ty_of_inttype<'tcx>(ity: IntType) -> Ty<'tcx> {
|
||||
pub fn ty_of_inttype<'tcx>(tcx: &ty::ctxt<'tcx>, ity: IntType) -> Ty<'tcx> {
|
||||
match ity {
|
||||
attr::SignedInt(t) => ty::mk_mach_int(t),
|
||||
attr::UnsignedInt(t) => ty::mk_mach_uint(t)
|
||||
attr::SignedInt(t) => ty::mk_mach_int(tcx, t),
|
||||
attr::UnsignedInt(t) => ty::mk_mach_uint(tcx, t)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -704,7 +703,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>,
|
||||
sizing: bool, dst: bool) -> Vec<Type> {
|
||||
if sizing {
|
||||
st.fields.iter().filter(|&ty| !dst || ty::type_is_sized(cx.tcx(), *ty))
|
||||
st.fields.iter().filter(|&ty| !dst || type_is_sized(cx.tcx(), *ty))
|
||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
} else {
|
||||
st.fields.iter().map(|&ty| type_of::type_of(cx, ty)).collect()
|
||||
|
|
@ -995,8 +994,10 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
|
||||
/// Access the struct drop flag, if present.
|
||||
pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef)
|
||||
-> datum::DatumBlock<'blk, 'tcx, datum::Expr> {
|
||||
let ptr_ty = ty::mk_imm_ptr(bcx.tcx(), ty::mk_bool());
|
||||
-> datum::DatumBlock<'blk, 'tcx, datum::Expr>
|
||||
{
|
||||
let tcx = bcx.tcx();
|
||||
let ptr_ty = ty::mk_imm_ptr(bcx.tcx(), tcx.types.bool);
|
||||
match *r {
|
||||
Univariant(ref st, true) => {
|
||||
let flag_ptr = GEPi(bcx, val, &[0, st.fields.len() - 1]);
|
||||
|
|
@ -1006,7 +1007,7 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx
|
|||
let fcx = bcx.fcx;
|
||||
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
|
||||
let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum(
|
||||
bcx, ty::mk_bool(), "drop_flag", false,
|
||||
bcx, tcx.types.bool, "drop_flag", false,
|
||||
cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| bcx
|
||||
));
|
||||
bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
|
||||
|
|
|
|||
|
|
@ -281,6 +281,8 @@ pub fn kind_for_unboxed_closure(ccx: &CrateContext, closure_id: ast::DefId)
|
|||
|
||||
pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
fn_ty: Ty<'tcx>, name: &str) -> ValueRef {
|
||||
let fn_ty = monomorphize::normalize_associated_type(ccx.tcx(), &fn_ty);
|
||||
|
||||
let (inputs, output, abi, env) = match fn_ty.sty {
|
||||
ty::ty_bare_fn(_, ref f) => {
|
||||
(f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None)
|
||||
|
|
@ -581,7 +583,7 @@ pub fn compare_scalar_types<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
|||
match t.sty {
|
||||
ty::ty_tup(ref tys) if tys.is_empty() => f(nil_type),
|
||||
ty::ty_bool | ty::ty_uint(_) | ty::ty_char => f(unsigned_int),
|
||||
ty::ty_ptr(mt) if ty::type_is_sized(cx.tcx(), mt.ty) => f(unsigned_int),
|
||||
ty::ty_ptr(mt) if common::type_is_sized(cx.tcx(), mt.ty) => f(unsigned_int),
|
||||
ty::ty_int(_) => f(signed_int),
|
||||
ty::ty_float(_) => f(floating_point),
|
||||
// Should never get here, because t is scalar.
|
||||
|
|
@ -719,7 +721,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
|||
return cx;
|
||||
}
|
||||
|
||||
let (data_ptr, info) = if ty::type_is_sized(cx.tcx(), t) {
|
||||
let (data_ptr, info) = if common::type_is_sized(cx.tcx(), t) {
|
||||
(av, None)
|
||||
} else {
|
||||
let data = GEPi(cx, av, &[0, abi::FAT_PTR_ADDR]);
|
||||
|
|
@ -736,7 +738,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
|||
let field_ty = field_ty.mt.ty;
|
||||
let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, discr, i);
|
||||
|
||||
let val = if ty::type_is_sized(cx.tcx(), field_ty) {
|
||||
let val = if common::type_is_sized(cx.tcx(), field_ty) {
|
||||
llfld_a
|
||||
} else {
|
||||
let boxed_ty = ty::mk_open(cx.tcx(), field_ty);
|
||||
|
|
@ -786,7 +788,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
|||
substs, f);
|
||||
}
|
||||
(_match::Switch, Some(lldiscrim_a)) => {
|
||||
cx = f(cx, lldiscrim_a, ty::mk_int());
|
||||
cx = f(cx, lldiscrim_a, cx.tcx().types.int);
|
||||
let unr_cx = fcx.new_temp_block("enum-iter-unr");
|
||||
Unreachable(unr_cx);
|
||||
let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb,
|
||||
|
|
@ -1453,7 +1455,8 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
|||
|
||||
let uses_outptr = match output_type {
|
||||
ty::FnConverging(output_type) => {
|
||||
let substd_output_type = output_type.subst(ccx.tcx(), param_substs);
|
||||
let substd_output_type =
|
||||
monomorphize::apply_param_substs(ccx.tcx(), param_substs, &output_type);
|
||||
type_of::return_uses_outptr(ccx, substd_output_type)
|
||||
}
|
||||
ty::FnDiverging => false
|
||||
|
|
@ -1512,7 +1515,7 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>,
|
|||
if let ty::FnConverging(output_type) = output {
|
||||
// This shouldn't need to recompute the return type,
|
||||
// as new_fn_ctxt did it already.
|
||||
let substd_output_type = output_type.subst(fcx.ccx.tcx(), fcx.param_substs);
|
||||
let substd_output_type = fcx.monomorphize(&output_type);
|
||||
if !return_type_is_void(fcx.ccx, substd_output_type) {
|
||||
// If the function returns nil/bot, there is no real return
|
||||
// value, so do not set `llretslotptr`.
|
||||
|
|
@ -1732,7 +1735,7 @@ pub fn finish_fn<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>,
|
|||
|
||||
// This shouldn't need to recompute the return type,
|
||||
// as new_fn_ctxt did it already.
|
||||
let substd_retty = retty.subst(fcx.ccx.tcx(), fcx.param_substs);
|
||||
let substd_retty = fcx.monomorphize(&retty);
|
||||
build_return_block(fcx, ret_cx, substd_retty);
|
||||
|
||||
debuginfo::clear_source_location(fcx);
|
||||
|
|
@ -1765,7 +1768,7 @@ pub fn build_return_block<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>,
|
|||
retptr.erase_from_parent();
|
||||
}
|
||||
|
||||
let retval = if retty == ty::FnConverging(ty::mk_bool()) {
|
||||
let retval = if retty == ty::FnConverging(fcx.ccx.tcx().types.bool) {
|
||||
Trunc(ret_cx, retval, Type::i1(fcx.ccx))
|
||||
} else {
|
||||
retval
|
||||
|
|
@ -2074,7 +2077,7 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx
|
|||
param_substs: &Substs<'tcx>,
|
||||
llfndecl: ValueRef) {
|
||||
let ctor_ty = ty::node_id_to_type(ccx.tcx(), ctor_id);
|
||||
let ctor_ty = ctor_ty.subst(ccx.tcx(), param_substs);
|
||||
let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty);
|
||||
|
||||
let result_ty = match ctor_ty.sty {
|
||||
ty::ty_bare_fn(_, ref bft) => bft.sig.0.output,
|
||||
|
|
@ -2522,7 +2525,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
|
|||
match ret_ty.sty {
|
||||
// `~` pointer return values never alias because ownership
|
||||
// is transferred
|
||||
ty::ty_uniq(it) if !ty::type_is_sized(ccx.tcx(), it) => {}
|
||||
ty::ty_uniq(it) if !common::type_is_sized(ccx.tcx(), it) => {}
|
||||
ty::ty_uniq(_) => {
|
||||
attrs.ret(llvm::NoAliasAttribute);
|
||||
}
|
||||
|
|
@ -2533,7 +2536,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
|
|||
match ret_ty.sty {
|
||||
// These are not really pointers but pairs, (pointer, len)
|
||||
ty::ty_uniq(it) |
|
||||
ty::ty_rptr(_, ty::mt { ty: it, .. }) if !ty::type_is_sized(ccx.tcx(), it) => {}
|
||||
ty::ty_rptr(_, ty::mt { ty: it, .. }) if !common::type_is_sized(ccx.tcx(), it) => {}
|
||||
ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => {
|
||||
let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner));
|
||||
attrs.ret(llvm::DereferenceableAttribute(llret_sz));
|
||||
|
|
@ -2764,6 +2767,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
|||
}
|
||||
|
||||
let item = ccx.tcx().map.get(id);
|
||||
debug!("get_item_val: id={} item={}", id, item);
|
||||
let val = match item {
|
||||
ast_map::NodeItem(i) => {
|
||||
let ty = ty::node_id_to_type(ccx.tcx(), i.id);
|
||||
|
|
|
|||
|
|
@ -514,8 +514,9 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
|
|||
return val;
|
||||
}
|
||||
|
||||
// Polytype of the function item (may have type params)
|
||||
let fn_tpt = ty::lookup_item_type(tcx, def_id);
|
||||
// Type scheme of the function item (may have type params)
|
||||
let fn_type_scheme = ty::lookup_item_type(tcx, def_id);
|
||||
let fn_type = monomorphize::normalize_associated_type(tcx, &fn_type_scheme.ty);
|
||||
|
||||
// Find the actual function pointer.
|
||||
let mut val = {
|
||||
|
|
@ -524,7 +525,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
|
|||
get_item_val(ccx, def_id.node)
|
||||
} else {
|
||||
// External reference.
|
||||
trans_external_path(ccx, def_id, fn_tpt.ty)
|
||||
trans_external_path(ccx, def_id, fn_type)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -551,7 +552,7 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
|
|||
// This can occur on either a crate-local or crate-external
|
||||
// reference. It also occurs when testing libcore and in some
|
||||
// other weird situations. Annoying.
|
||||
let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
|
||||
let llty = type_of::type_of_fn_from_ty(ccx, fn_type);
|
||||
let llptrty = llty.ptr_to();
|
||||
if val_ty(val) != llptrty {
|
||||
debug!("trans_fn_ref_with_vtables(): casting pointer!");
|
||||
|
|
@ -722,7 +723,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
};
|
||||
if !is_rust_fn ||
|
||||
type_of::return_uses_outptr(ccx, ret_ty) ||
|
||||
ty::type_needs_drop(bcx.tcx(), ret_ty) {
|
||||
type_needs_drop(bcx.tcx(), ret_ty) {
|
||||
// Push the out-pointer if we use an out-pointer for this
|
||||
// return type, otherwise push "undef".
|
||||
if type_is_zero_size(ccx, ret_ty) {
|
||||
|
|
|
|||
|
|
@ -279,10 +279,10 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
|
|||
cleanup_scope: ScopeId,
|
||||
val: ValueRef,
|
||||
ty: Ty<'tcx>) {
|
||||
if !ty::type_needs_drop(self.ccx.tcx(), ty) { return; }
|
||||
if !common::type_needs_drop(self.ccx.tcx(), ty) { return; }
|
||||
let drop = box DropValue {
|
||||
is_immediate: false,
|
||||
must_unwind: ty::type_needs_unwind_cleanup(self.ccx.tcx(), ty),
|
||||
must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
|
||||
val: val,
|
||||
ty: ty,
|
||||
zero: false
|
||||
|
|
@ -301,10 +301,10 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
|
|||
cleanup_scope: ScopeId,
|
||||
val: ValueRef,
|
||||
ty: Ty<'tcx>) {
|
||||
if !ty::type_needs_drop(self.ccx.tcx(), ty) { return; }
|
||||
if !common::type_needs_drop(self.ccx.tcx(), ty) { return; }
|
||||
let drop = box DropValue {
|
||||
is_immediate: false,
|
||||
must_unwind: ty::type_needs_unwind_cleanup(self.ccx.tcx(), ty),
|
||||
must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
|
||||
val: val,
|
||||
ty: ty,
|
||||
zero: true
|
||||
|
|
@ -325,10 +325,10 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
|
|||
val: ValueRef,
|
||||
ty: Ty<'tcx>) {
|
||||
|
||||
if !ty::type_needs_drop(self.ccx.tcx(), ty) { return; }
|
||||
if !common::type_needs_drop(self.ccx.tcx(), ty) { return; }
|
||||
let drop = box DropValue {
|
||||
is_immediate: true,
|
||||
must_unwind: ty::type_needs_unwind_cleanup(self.ccx.tcx(), ty),
|
||||
must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
|
||||
val: val,
|
||||
ty: ty,
|
||||
zero: false
|
||||
|
|
@ -736,7 +736,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
|
|||
let f = base::decl_cdecl_fn(self.ccx,
|
||||
"rust_eh_personality",
|
||||
fty,
|
||||
ty::mk_i32());
|
||||
self.ccx.tcx().types.i32);
|
||||
*personality = Some(f);
|
||||
f
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,8 +133,8 @@ pub fn mk_closure_tys<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
}
|
||||
|
||||
fn tuplify_box_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let ptr = ty::mk_imm_ptr(tcx, ty::mk_i8());
|
||||
ty::mk_tup(tcx, vec!(ty::mk_uint(), ty::mk_nil_ptr(tcx), ptr, ptr, t))
|
||||
let ptr = ty::mk_imm_ptr(tcx, tcx.types.i8);
|
||||
ty::mk_tup(tcx, vec!(tcx.types.uint, ty::mk_nil_ptr(tcx), ptr, ptr, t))
|
||||
}
|
||||
|
||||
fn allocate_cbox<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
|
|
|
|||
|
|
@ -24,20 +24,20 @@ use middle::infer;
|
|||
use middle::lang_items::LangItem;
|
||||
use middle::mem_categorization as mc;
|
||||
use middle::region;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::subst::{mod, Subst, Substs};
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::cleanup;
|
||||
use trans::datum;
|
||||
use trans::debuginfo;
|
||||
use trans::machine;
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
use middle::traits;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, HasProjectionTypes, Ty};
|
||||
use middle::ty_fold;
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
||||
use util::ppaux::Repr;
|
||||
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
|
||||
|
||||
|
|
@ -45,7 +45,6 @@ use arena::TypedArena;
|
|||
use libc::{c_uint, c_char};
|
||||
use std::c_str::ToCStr;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::vec::Vec;
|
||||
use syntax::ast::Ident;
|
||||
use syntax::ast;
|
||||
|
|
@ -53,9 +52,110 @@ use syntax::ast_map::{PathElem, PathName};
|
|||
use syntax::codemap::Span;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::parse::token;
|
||||
use util::common::memoized;
|
||||
use util::nodemap::FnvHashSet;
|
||||
|
||||
pub use trans::context::CrateContext;
|
||||
|
||||
// Is the type's representation size known at compile time?
|
||||
pub fn type_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
ty::type_contents(cx, ty).is_sized(cx)
|
||||
}
|
||||
|
||||
pub fn lltype_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
match ty.sty {
|
||||
ty::ty_open(_) => true,
|
||||
_ => type_is_sized(cx, ty),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
match ty.sty {
|
||||
ty::ty_ptr(ty::mt{ty, ..}) |
|
||||
ty::ty_rptr(_, ty::mt{ty, ..}) |
|
||||
ty::ty_uniq(ty) => {
|
||||
!type_is_sized(cx, ty)
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized.
|
||||
// 'Smallest' here means component of the static representation of the type; not
|
||||
// the size of an object at runtime.
|
||||
pub fn unsized_part_of_type<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match ty.sty {
|
||||
ty::ty_str | ty::ty_trait(..) | ty::ty_vec(..) => ty,
|
||||
ty::ty_struct(def_id, substs) => {
|
||||
let unsized_fields: Vec<_> =
|
||||
ty::struct_fields(cx, def_id, substs)
|
||||
.iter()
|
||||
.map(|f| f.mt.ty)
|
||||
.filter(|ty| !type_is_sized(cx, *ty))
|
||||
.collect();
|
||||
|
||||
// Exactly one of the fields must be unsized.
|
||||
assert!(unsized_fields.len() == 1);
|
||||
|
||||
unsized_part_of_type(cx, unsized_fields[0])
|
||||
}
|
||||
_ => {
|
||||
assert!(type_is_sized(cx, ty),
|
||||
"unsized_part_of_type failed even though ty is unsized");
|
||||
panic!("called unsized_part_of_type with sized ty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Some things don't need cleanups during unwinding because the
|
||||
// task can free them all at once later. Currently only things
|
||||
// that only contain scalars and shared boxes can avoid unwind
|
||||
// cleanups.
|
||||
pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
return memoized(ccx.needs_unwind_cleanup_cache(), ty, |ty| {
|
||||
type_needs_unwind_cleanup_(ccx.tcx(), ty, &mut FnvHashSet::new())
|
||||
});
|
||||
|
||||
fn type_needs_unwind_cleanup_<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
tycache: &mut FnvHashSet<Ty<'tcx>>)
|
||||
-> bool
|
||||
{
|
||||
// Prevent infinite recursion
|
||||
if !tycache.insert(ty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut needs_unwind_cleanup = false;
|
||||
ty::maybe_walk_ty(ty, |ty| {
|
||||
needs_unwind_cleanup |= match ty.sty {
|
||||
ty::ty_bool | ty::ty_int(_) | ty::ty_uint(_) |
|
||||
ty::ty_float(_) | ty::ty_tup(_) | ty::ty_ptr(_) => false,
|
||||
|
||||
ty::ty_enum(did, substs) =>
|
||||
ty::enum_variants(tcx, did).iter().any(|v|
|
||||
v.args.iter().any(|&aty| {
|
||||
let t = aty.subst(tcx, substs);
|
||||
type_needs_unwind_cleanup_(tcx, t, tycache)
|
||||
})
|
||||
),
|
||||
|
||||
_ => true
|
||||
};
|
||||
!needs_unwind_cleanup
|
||||
});
|
||||
needs_unwind_cleanup
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>,
|
||||
ty: Ty<'tcx>)
|
||||
-> bool {
|
||||
ty::type_contents(cx, ty).needs_drop(cx)
|
||||
}
|
||||
|
||||
fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ty: Ty<'tcx>) -> bool {
|
||||
match ty.sty {
|
||||
|
|
@ -79,10 +179,10 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
|
|||
ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) ||
|
||||
type_is_newtype_immediate(ccx, ty) ||
|
||||
ty::type_is_simd(tcx, ty);
|
||||
if simple && !ty::type_is_fat_ptr(tcx, ty) {
|
||||
if simple && !type_is_fat_ptr(tcx, ty) {
|
||||
return true;
|
||||
}
|
||||
if !ty::type_is_sized(tcx, ty) {
|
||||
if !type_is_sized(tcx, ty) {
|
||||
return false;
|
||||
}
|
||||
match ty.sty {
|
||||
|
|
@ -364,6 +464,14 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
|
|||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
pub fn monomorphize<T>(&self, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
monomorphize::apply_param_substs(self.ccx.tcx(),
|
||||
self.param_substs,
|
||||
value)
|
||||
}
|
||||
}
|
||||
|
||||
// Basic block context. We create a block context for each basic block
|
||||
|
|
@ -456,6 +564,14 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
|
|||
pub fn to_str(&self) -> String {
|
||||
format!("[block {:p}]", self)
|
||||
}
|
||||
|
||||
pub fn monomorphize<T>(&self, value: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
monomorphize::apply_param_substs(self.tcx(),
|
||||
self.fcx.param_substs,
|
||||
value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> {
|
||||
|
|
@ -758,7 +874,7 @@ pub fn is_null(val: ValueRef) -> bool {
|
|||
}
|
||||
|
||||
pub fn monomorphize_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
t.subst(bcx.tcx(), bcx.fcx.param_substs)
|
||||
bcx.fcx.monomorphize(&t)
|
||||
}
|
||||
|
||||
pub fn node_id_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, id: ast::NodeId) -> Ty<'tcx> {
|
||||
|
|
@ -780,7 +896,7 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &ast::Expr) ->
|
|||
/// 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::PolyTraitRef<'tcx>>)
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> traits::Vtable<'tcx, ()>
|
||||
{
|
||||
let tcx = ccx.tcx();
|
||||
|
|
@ -810,7 +926,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// shallow result we are looking for -- that is, what specific impl.
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx);
|
||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||
trait_ref.clone());
|
||||
trait_ref.to_poly_trait_predicate());
|
||||
let selection = match selcx.select(&obligation) {
|
||||
Ok(Some(selection)) => selection,
|
||||
Ok(None) => {
|
||||
|
|
@ -844,7 +960,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// iterating early.
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
||||
let vtable = selection.map_move_nested(|predicate| {
|
||||
fulfill_cx.register_predicate(infcx.tcx, predicate);
|
||||
fulfill_cx.register_predicate(&infcx, predicate);
|
||||
});
|
||||
match fulfill_cx.select_all_or_error(&infcx, ¶m_env, tcx) {
|
||||
Ok(()) => { }
|
||||
|
|
@ -890,7 +1006,8 @@ pub enum ExprOrMethodCall {
|
|||
|
||||
pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
node: ExprOrMethodCall)
|
||||
-> subst::Substs<'tcx> {
|
||||
-> subst::Substs<'tcx>
|
||||
{
|
||||
let tcx = bcx.tcx();
|
||||
|
||||
let substs = match node {
|
||||
|
|
@ -911,7 +1028,7 @@ pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
|
||||
let substs = substs.erase_regions();
|
||||
substs.subst(tcx, bcx.fcx.param_substs)
|
||||
bcx.monomorphize(&substs)
|
||||
}
|
||||
|
||||
pub fn langcall(bcx: Block,
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, v: ValueRef,
|
|||
Some(ref mt) => {
|
||||
match t.sty {
|
||||
ty::ty_ptr(mt) | ty::ty_rptr(_, mt) => {
|
||||
if ty::type_is_sized(cx.tcx(), mt.ty) {
|
||||
if type_is_sized(cx.tcx(), mt.ty) {
|
||||
(const_deref_ptr(cx, v), mt.ty)
|
||||
} else {
|
||||
// Derefing a fat pointer does not change the representation,
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ pub struct LocalCrateContext<'tcx> {
|
|||
tn: TypeNames,
|
||||
externs: RefCell<ExternMap>,
|
||||
item_vals: RefCell<NodeMap<ValueRef>>,
|
||||
needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
|
||||
fn_pointer_shims: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
|
||||
drop_glues: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
|
||||
tydescs: RefCell<FnvHashMap<Ty<'tcx>, Rc<tydesc_info<'tcx>>>>,
|
||||
|
|
@ -99,7 +100,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::PolyTraitRef<'tcx>>), ValueRef>>,
|
||||
vtables: RefCell<FnvHashMap<(Ty<'tcx>, ty::PolyTraitRef<'tcx>), ValueRef>>,
|
||||
/// Cache of constant strings,
|
||||
const_cstr_cache: RefCell<FnvHashMap<InternedString, ValueRef>>,
|
||||
|
||||
|
|
@ -150,7 +151,7 @@ pub struct LocalCrateContext<'tcx> {
|
|||
/// contexts around the same size.
|
||||
n_llvm_insns: Cell<uint>,
|
||||
|
||||
trait_cache: RefCell<FnvHashMap<Rc<ty::PolyTraitRef<'tcx>>,
|
||||
trait_cache: RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>,
|
||||
traits::Vtable<'tcx, ()>>>,
|
||||
}
|
||||
|
||||
|
|
@ -389,6 +390,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
|
|||
tn: TypeNames::new(),
|
||||
externs: RefCell::new(FnvHashMap::new()),
|
||||
item_vals: RefCell::new(NodeMap::new()),
|
||||
needs_unwind_cleanup_cache: RefCell::new(FnvHashMap::new()),
|
||||
fn_pointer_shims: RefCell::new(FnvHashMap::new()),
|
||||
drop_glues: RefCell::new(FnvHashMap::new()),
|
||||
tydescs: RefCell::new(FnvHashMap::new()),
|
||||
|
|
@ -569,6 +571,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
|||
&self.shared.link_meta
|
||||
}
|
||||
|
||||
pub fn needs_unwind_cleanup_cache(&self) -> &RefCell<FnvHashMap<Ty<'tcx>, bool>> {
|
||||
&self.local.needs_unwind_cleanup_cache
|
||||
}
|
||||
|
||||
pub fn fn_pointer_shims(&self) -> &RefCell<FnvHashMap<Ty<'tcx>, ValueRef>> {
|
||||
&self.local.fn_pointer_shims
|
||||
}
|
||||
|
|
@ -601,7 +607,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
|||
&self.local.monomorphizing
|
||||
}
|
||||
|
||||
pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<(Ty<'tcx>, Rc<ty::PolyTraitRef<'tcx>>),
|
||||
pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<(Ty<'tcx>, ty::PolyTraitRef<'tcx>),
|
||||
ValueRef>> {
|
||||
&self.local.vtables
|
||||
}
|
||||
|
|
@ -699,7 +705,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::PolyTraitRef<'tcx>>,
|
||||
pub fn trait_cache(&self) -> &RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>,
|
||||
traits::Vtable<'tcx, ()>>> {
|
||||
&self.local.trait_cache
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr)
|
|||
-> Block<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("trans_stmt_semi");
|
||||
let ty = expr_ty(cx, e);
|
||||
if ty::type_needs_drop(cx.tcx(), ty) {
|
||||
if type_needs_drop(cx.tcx(), ty) {
|
||||
expr::trans_to_lvalue(cx, e, "stmt").bcx
|
||||
} else {
|
||||
expr::trans_into(cx, e, expr::Ignore)
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ impl KindOps for Lvalue {
|
|||
val: ValueRef,
|
||||
ty: Ty<'tcx>)
|
||||
-> Block<'blk, 'tcx> {
|
||||
if ty::type_needs_drop(bcx.tcx(), ty) {
|
||||
if type_needs_drop(bcx.tcx(), ty) {
|
||||
// cancel cleanup of affine values by zeroing out
|
||||
let () = zero_mem(bcx, val, ty);
|
||||
bcx
|
||||
|
|
@ -398,7 +398,7 @@ impl<'tcx> Datum<'tcx, Expr> {
|
|||
-> DatumBlock<'blk, 'tcx, Lvalue> {
|
||||
debug!("to_lvalue_datum self: {}", self.to_string(bcx.ccx()));
|
||||
|
||||
assert!(ty::lltype_is_sized(bcx.tcx(), self.ty),
|
||||
assert!(lltype_is_sized(bcx.tcx(), self.ty),
|
||||
"Trying to convert unsized value to lval");
|
||||
self.match_kind(
|
||||
|l| DatumBlock::new(bcx, l),
|
||||
|
|
@ -456,7 +456,7 @@ impl<'tcx> Datum<'tcx, Lvalue> {
|
|||
F: FnOnce(ValueRef) -> ValueRef,
|
||||
{
|
||||
let val = match self.ty.sty {
|
||||
_ if ty::type_is_sized(bcx.tcx(), self.ty) => gep(self.val),
|
||||
_ if type_is_sized(bcx.tcx(), self.ty) => gep(self.val),
|
||||
ty::ty_open(_) => {
|
||||
let base = Load(bcx, expr::get_dataptr(bcx, self.val));
|
||||
gep(base)
|
||||
|
|
@ -567,7 +567,7 @@ impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> {
|
|||
/// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is
|
||||
/// naturally passed around by value, and not by reference.
|
||||
pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef {
|
||||
assert!(!ty::type_needs_drop(bcx.tcx(), self.ty));
|
||||
assert!(!type_needs_drop(bcx.tcx(), self.ty));
|
||||
assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue);
|
||||
if self.kind.is_by_ref() {
|
||||
load_ty(bcx, self.val, self.ty)
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ use middle::subst::{mod, Subst, Substs};
|
|||
use trans::{mod, adt, machine, type_of};
|
||||
use trans::common::*;
|
||||
use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::pat_util;
|
||||
|
|
@ -426,8 +427,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.0.substs,
|
||||
&mut unique_type_id);
|
||||
},
|
||||
ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
|
||||
|
|
@ -1438,7 +1439,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
assert_type_for_node_id(cx, fn_ast_id, error_reporting_span);
|
||||
|
||||
let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id);
|
||||
let return_type = return_type.subst(cx.tcx(), param_substs);
|
||||
let return_type = monomorphize::apply_param_substs(cx.tcx(),
|
||||
param_substs,
|
||||
&return_type);
|
||||
signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP));
|
||||
}
|
||||
}
|
||||
|
|
@ -1447,7 +1450,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
for arg in fn_decl.inputs.iter() {
|
||||
assert_type_for_node_id(cx, arg.pat.id, arg.pat.span);
|
||||
let arg_type = ty::node_id_to_type(cx.tcx(), arg.pat.id);
|
||||
let arg_type = arg_type.subst(cx.tcx(), param_substs);
|
||||
let arg_type = monomorphize::apply_param_substs(cx.tcx(),
|
||||
param_substs,
|
||||
&arg_type);
|
||||
signature.push(type_metadata(cx, arg_type, codemap::DUMMY_SP));
|
||||
}
|
||||
|
||||
|
|
@ -1459,8 +1464,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
param_substs: &Substs<'tcx>,
|
||||
file_metadata: DIFile,
|
||||
name_to_append_suffix_to: &mut String)
|
||||
-> DIArray {
|
||||
-> DIArray
|
||||
{
|
||||
let self_type = param_substs.self_ty();
|
||||
let self_type = monomorphize::normalize_associated_type(cx.tcx(), &self_type);
|
||||
|
||||
// Only true for static default methods:
|
||||
let has_self_type = self_type.is_some();
|
||||
|
|
@ -2487,9 +2494,10 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
let discriminant_llvm_type = adt::ll_inttype(cx, inttype);
|
||||
let (discriminant_size, discriminant_align) =
|
||||
size_and_align_of(cx, discriminant_llvm_type);
|
||||
let discriminant_base_type_metadata = type_metadata(cx,
|
||||
adt::ty_of_inttype(inttype),
|
||||
codemap::DUMMY_SP);
|
||||
let discriminant_base_type_metadata =
|
||||
type_metadata(cx,
|
||||
adt::ty_of_inttype(cx.tcx(), inttype),
|
||||
codemap::DUMMY_SP);
|
||||
let discriminant_name = get_enum_discriminant_name(cx, enum_def_id);
|
||||
|
||||
let discriminant_type_metadata = discriminant_name.get().with_c_str(|name| {
|
||||
|
|
@ -2797,7 +2805,7 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
MemberDescription {
|
||||
name: "length".to_string(),
|
||||
llvm_type: member_llvm_types[1],
|
||||
type_metadata: type_metadata(cx, ty::mk_uint(), span),
|
||||
type_metadata: type_metadata(cx, cx.tcx().types.uint, span),
|
||||
offset: ComputedMemberOffset,
|
||||
flags: FLAGS_NONE
|
||||
},
|
||||
|
|
@ -2877,7 +2885,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(ref data) => data.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 \
|
||||
|
|
@ -2963,7 +2971,7 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
// FIXME Can we do better than this for unsized vec/str fields?
|
||||
ty::ty_vec(typ, None) => fixed_vec_metadata(cx, unique_type_id, typ, 0, usage_site_span),
|
||||
ty::ty_str => fixed_vec_metadata(cx, unique_type_id, ty::mk_i8(), 0, usage_site_span),
|
||||
ty::ty_str => fixed_vec_metadata(cx, unique_type_id, cx.tcx().types.i8, 0, usage_site_span),
|
||||
ty::ty_trait(..) => {
|
||||
MetadataCreationResult::new(
|
||||
trait_pointer_metadata(cx, t, None, unique_type_id),
|
||||
|
|
@ -2975,7 +2983,7 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)
|
||||
}
|
||||
ty::ty_str => {
|
||||
vec_slice_metadata(cx, t, ty::mk_u8(), unique_type_id, usage_site_span)
|
||||
vec_slice_metadata(cx, t, cx.tcx().types.u8, unique_type_id, usage_site_span)
|
||||
}
|
||||
ty::ty_trait(..) => {
|
||||
MetadataCreationResult::new(
|
||||
|
|
@ -3810,8 +3818,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.0.substs, output);
|
||||
},
|
||||
ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
|
||||
if unsafety == ast::Unsafety::Unsafe {
|
||||
|
|
@ -3919,9 +3927,10 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
ty::ty_unboxed_closure(..) => {
|
||||
output.push_str("closure");
|
||||
}
|
||||
ty::ty_err |
|
||||
ty::ty_err |
|
||||
ty::ty_infer(_) |
|
||||
ty::ty_open(_) |
|
||||
ty::ty_projection(..) |
|
||||
ty::ty_param(_) => {
|
||||
cx.sess().bug(format!("debuginfo: Trying to create type name for \
|
||||
unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t))[]);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ use back::abi;
|
|||
use llvm::{mod, ValueRef};
|
||||
use middle::def;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst::{mod, Subst, Substs};
|
||||
use middle::subst::{mod, Substs};
|
||||
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
|
|
@ -280,7 +280,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
expr.repr(bcx.tcx()),
|
||||
datum.to_string(bcx.ccx()));
|
||||
|
||||
if !ty::type_is_sized(bcx.tcx(), datum.ty) {
|
||||
if !type_is_sized(bcx.tcx(), datum.ty) {
|
||||
debug!("Taking address of unsized type {}",
|
||||
bcx.ty_to_string(datum.ty));
|
||||
ref_fat_ptr(bcx, expr, datum)
|
||||
|
|
@ -319,11 +319,13 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
bcx.ty_to_string(unadjusted_ty))[])
|
||||
},
|
||||
&ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => {
|
||||
let substs = principal.substs().with_self_ty(unadjusted_ty).erase_regions();
|
||||
// Note that we preserve binding levels here:
|
||||
let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions();
|
||||
let substs = bcx.tcx().mk_substs(substs);
|
||||
let trait_ref =
|
||||
Rc::new(ty::Binder(ty::TraitRef { def_id: principal.def_id(),
|
||||
substs: bcx.tcx().mk_substs(substs) }));
|
||||
let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs);
|
||||
ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(),
|
||||
substs: substs }));
|
||||
let trait_ref = bcx.monomorphize(&trait_ref);
|
||||
let box_ty = mk_ty(unadjusted_ty);
|
||||
PointerCast(bcx,
|
||||
meth::get_vtable(bcx, box_ty, trait_ref),
|
||||
|
|
@ -693,7 +695,7 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
|||
field_tys[ix].mt.ty,
|
||||
|srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
|
||||
|
||||
if ty::type_is_sized(bcx.tcx(), d.ty) {
|
||||
if type_is_sized(bcx.tcx(), d.ty) {
|
||||
DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
|
||||
} else {
|
||||
let scratch = rvalue_scratch_datum(bcx, ty::mk_open(bcx.tcx(), d.ty), "");
|
||||
|
|
@ -773,7 +775,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
Some(SaveIn(scratch.val)),
|
||||
true));
|
||||
let datum = scratch.to_expr_datum();
|
||||
if ty::type_is_sized(bcx.tcx(), elt_ty) {
|
||||
if type_is_sized(bcx.tcx(), elt_ty) {
|
||||
Datum::new(datum.to_llscalarish(bcx), elt_ty, LvalueExpr)
|
||||
} else {
|
||||
Datum::new(datum.val, ty::mk_open(bcx.tcx(), elt_ty), LvalueExpr)
|
||||
|
|
@ -976,7 +978,7 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
|
||||
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign"));
|
||||
|
||||
if ty::type_needs_drop(bcx.tcx(), dst_datum.ty) {
|
||||
if type_needs_drop(bcx.tcx(), dst_datum.ty) {
|
||||
// If there are destructors involved, make sure we
|
||||
// are copying from an rvalue, since that cannot possible
|
||||
// alias an lvalue. We are concerned about code like:
|
||||
|
|
@ -1204,7 +1206,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
.get(&expr.id)
|
||||
.map(|t| (*t).clone())
|
||||
.unwrap();
|
||||
let trait_ref = trait_ref.subst(bcx.tcx(), bcx.fcx.param_substs);
|
||||
let trait_ref = bcx.monomorphize(&trait_ref);
|
||||
let datum = unpack_datum!(bcx, trans(bcx, &**val));
|
||||
meth::trans_trait_cast(bcx, datum, expr.id,
|
||||
trait_ref, dest)
|
||||
|
|
@ -1513,7 +1515,7 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
assert_eq!(discr, 0);
|
||||
|
||||
match ty::expr_kind(bcx.tcx(), &*base.expr) {
|
||||
ty::RvalueDpsExpr | ty::RvalueDatumExpr if !ty::type_needs_drop(bcx.tcx(), ty) => {
|
||||
ty::RvalueDpsExpr | ty::RvalueDatumExpr if !type_needs_drop(bcx.tcx(), ty) => {
|
||||
bcx = trans_into(bcx, &*base.expr, SaveIn(addr));
|
||||
},
|
||||
ty::RvalueStmtExpr => bcx.tcx().sess.bug("unexpected expr kind for struct base expr"),
|
||||
|
|
@ -1522,7 +1524,7 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
for &(i, t) in base.fields.iter() {
|
||||
let datum = base_datum.get_element(
|
||||
bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
|
||||
assert!(ty::type_is_sized(bcx.tcx(), datum.ty));
|
||||
assert!(type_is_sized(bcx.tcx(), datum.ty));
|
||||
let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
|
||||
bcx = datum.store_to(bcx, dest);
|
||||
}
|
||||
|
|
@ -1650,7 +1652,7 @@ fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
-> DatumBlock<'blk, 'tcx, Expr> {
|
||||
let _icx = push_ctxt("trans_uniq_expr");
|
||||
let fcx = bcx.fcx;
|
||||
assert!(ty::type_is_sized(bcx.tcx(), contents_ty));
|
||||
assert!(type_is_sized(bcx.tcx(), contents_ty));
|
||||
let llty = type_of::type_of(bcx.ccx(), contents_ty);
|
||||
let size = llsize_of(bcx.ccx(), llty);
|
||||
let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty));
|
||||
|
|
@ -1985,7 +1987,7 @@ pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind {
|
|||
ty::ty_char => cast_integral,
|
||||
ty::ty_float(..) => cast_float,
|
||||
ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => {
|
||||
if ty::type_is_sized(tcx, mt.ty) {
|
||||
if type_is_sized(tcx, mt.ty) {
|
||||
cast_pointer
|
||||
} else {
|
||||
cast_other
|
||||
|
|
@ -2117,7 +2119,7 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
|
||||
// Evaluate LHS (destination), which should be an lvalue
|
||||
let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op"));
|
||||
assert!(!ty::type_needs_drop(bcx.tcx(), dst_datum.ty));
|
||||
assert!(!type_needs_drop(bcx.tcx(), dst_datum.ty));
|
||||
let dst_ty = dst_datum.ty;
|
||||
let dst = load_ty(bcx, dst_datum.val, dst_datum.ty);
|
||||
|
||||
|
|
@ -2217,7 +2219,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
|
||||
let r = match datum.ty.sty {
|
||||
ty::ty_uniq(content_ty) => {
|
||||
if ty::type_is_sized(bcx.tcx(), content_ty) {
|
||||
if type_is_sized(bcx.tcx(), content_ty) {
|
||||
deref_owned_pointer(bcx, expr, datum, content_ty)
|
||||
} else {
|
||||
// A fat pointer and an opened DST value have the same
|
||||
|
|
@ -2236,7 +2238,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
|
||||
ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
|
||||
ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
|
||||
if ty::type_is_sized(bcx.tcx(), content_ty) {
|
||||
if type_is_sized(bcx.tcx(), content_ty) {
|
||||
let ptr = datum.to_llscalarish(bcx);
|
||||
|
||||
// Always generate an lvalue datum, even if datum.mode is
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@ use trans::build::*;
|
|||
use trans::cabi;
|
||||
use trans::common::*;
|
||||
use trans::machine;
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of::*;
|
||||
use trans::type_of;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::subst::{Substs};
|
||||
use std::cmp;
|
||||
use libc::c_uint;
|
||||
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
|
||||
|
|
@ -525,7 +526,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
let _icx = push_ctxt("foreign::build_foreign_fn");
|
||||
|
||||
let fnty = ty::node_id_to_type(ccx.tcx(), id);
|
||||
let mty = fnty.subst(ccx.tcx(), param_substs);
|
||||
let mty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fnty);
|
||||
let tys = foreign_types_for_fn_ty(ccx, mty);
|
||||
|
||||
unsafe { // unsafe because we call LLVM operations
|
||||
|
|
@ -543,10 +544,12 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
attrs: &[ast::Attribute],
|
||||
id: ast::NodeId,
|
||||
hash: Option<&str>)
|
||||
-> ValueRef {
|
||||
-> ValueRef
|
||||
{
|
||||
let _icx = push_ctxt("foreign::foreign::build_rust_fn");
|
||||
let tcx = ccx.tcx();
|
||||
let t = ty::node_id_to_type(tcx, id).subst(ccx.tcx(), param_substs);
|
||||
let t = ty::node_id_to_type(tcx, id);
|
||||
let t = monomorphize::apply_param_substs(tcx, param_substs, &t);
|
||||
|
||||
let ps = ccx.tcx().map.with_path(id, |path| {
|
||||
let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name));
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef,
|
|||
|
||||
pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef,
|
||||
content_ty: Ty<'tcx>) -> Block<'blk, 'tcx> {
|
||||
assert!(ty::type_is_sized(bcx.ccx().tcx(), content_ty));
|
||||
assert!(type_is_sized(bcx.ccx().tcx(), content_ty));
|
||||
let sizing_type = sizing_type_of(bcx.ccx(), content_ty);
|
||||
let content_size = llsize_of_alloc(bcx.ccx(), sizing_type);
|
||||
|
||||
|
|
@ -81,19 +81,19 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
let tcx = ccx.tcx();
|
||||
// Even if there is no dtor for t, there might be one deeper down and we
|
||||
// might need to pass in the vtable ptr.
|
||||
if !ty::type_is_sized(tcx, t) {
|
||||
if !type_is_sized(tcx, t) {
|
||||
return t
|
||||
}
|
||||
if !ty::type_needs_drop(tcx, t) {
|
||||
return ty::mk_i8();
|
||||
if !type_needs_drop(tcx, t) {
|
||||
return tcx.types.i8;
|
||||
}
|
||||
match t.sty {
|
||||
ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ)
|
||||
&& ty::type_is_sized(tcx, typ) => {
|
||||
ty::ty_uniq(typ) if !type_needs_drop(tcx, typ)
|
||||
&& type_is_sized(tcx, typ) => {
|
||||
let llty = sizing_type_of(ccx, typ);
|
||||
// `Box<ZeroSizeType>` does not allocate.
|
||||
if llsize_of_alloc(ccx, llty) == 0 {
|
||||
ty::mk_i8()
|
||||
tcx.types.i8
|
||||
} else {
|
||||
t
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
// NB: v is an *alias* of type t here, not a direct value.
|
||||
debug!("drop_ty(t={})", t.repr(bcx.tcx()));
|
||||
let _icx = push_ctxt("drop_ty");
|
||||
if ty::type_needs_drop(bcx.tcx(), t) {
|
||||
if type_needs_drop(bcx.tcx(), t) {
|
||||
let ccx = bcx.ccx();
|
||||
let glue = get_drop_glue(ccx, t);
|
||||
let glue_type = get_drop_glue_type(ccx, t);
|
||||
|
|
@ -150,7 +150,7 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val
|
|||
_ => { }
|
||||
}
|
||||
|
||||
let llty = if ty::type_is_sized(ccx.tcx(), t) {
|
||||
let llty = if type_is_sized(ccx.tcx(), t) {
|
||||
type_of(ccx, t).ptr_to()
|
||||
} else {
|
||||
type_of(ccx, ty::mk_uniq(ccx.tcx(), t)).ptr_to()
|
||||
|
|
@ -193,14 +193,14 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
substs: &subst::Substs<'tcx>)
|
||||
-> Block<'blk, 'tcx> {
|
||||
let repr = adt::represent_type(bcx.ccx(), t);
|
||||
let struct_data = if ty::type_is_sized(bcx.tcx(), t) {
|
||||
let struct_data = if type_is_sized(bcx.tcx(), t) {
|
||||
v0
|
||||
} else {
|
||||
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
|
||||
Load(bcx, llval)
|
||||
};
|
||||
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
|
||||
with_cond(bcx, load_ty(bcx, drop_flag.val, ty::mk_bool()), |cx| {
|
||||
with_cond(bcx, load_ty(bcx, drop_flag.val, bcx.tcx().types.bool), |cx| {
|
||||
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
|
||||
})
|
||||
}
|
||||
|
|
@ -234,7 +234,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
bcx.ty_to_string(fty))[])
|
||||
};
|
||||
|
||||
let (struct_data, info) = if ty::type_is_sized(bcx.tcx(), t) {
|
||||
let (struct_data, info) = if type_is_sized(bcx.tcx(), t) {
|
||||
(v0, None)
|
||||
} else {
|
||||
let data = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
|
||||
|
|
@ -251,7 +251,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
// Class dtors have no explicit args, so the params should
|
||||
// just consist of the environment (self).
|
||||
assert_eq!(params.len(), 1);
|
||||
let self_arg = if ty::type_is_fat_ptr(bcx.tcx(), self_ty) {
|
||||
let self_arg = if type_is_fat_ptr(bcx.tcx(), self_ty) {
|
||||
// The dtor expects a fat pointer, so make one, even if we have to fake it.
|
||||
let boxed_ty = ty::mk_open(bcx.tcx(), t);
|
||||
let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_self");
|
||||
|
|
@ -275,7 +275,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
for (i, ty) in st.fields.iter().enumerate().rev() {
|
||||
let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
|
||||
|
||||
let val = if ty::type_is_sized(bcx.tcx(), *ty) {
|
||||
let val = if type_is_sized(bcx.tcx(), *ty) {
|
||||
llfld_a
|
||||
} else {
|
||||
let boxed_ty = ty::mk_open(bcx.tcx(), *ty);
|
||||
|
|
@ -303,7 +303,7 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info:
|
|||
-> (ValueRef, ValueRef) {
|
||||
debug!("calculate size of DST: {}; with lost info: {}",
|
||||
bcx.ty_to_string(t), bcx.val_to_string(info));
|
||||
if ty::type_is_sized(bcx.tcx(), t) {
|
||||
if type_is_sized(bcx.tcx(), t) {
|
||||
let sizing_type = sizing_type_of(bcx.ccx(), t);
|
||||
let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type));
|
||||
let align = C_uint(bcx.ccx(), align_of(bcx.ccx(), t));
|
||||
|
|
@ -383,7 +383,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
|
|||
bcx
|
||||
})
|
||||
}
|
||||
ty::ty_struct(..) if !ty::type_is_sized(bcx.tcx(), content_ty) => {
|
||||
ty::ty_struct(..) if !type_is_sized(bcx.tcx(), content_ty) => {
|
||||
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
|
||||
let llbox = Load(bcx, llval);
|
||||
let not_null = IsNotNull(bcx, llbox);
|
||||
|
|
@ -396,7 +396,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
|
|||
})
|
||||
}
|
||||
_ => {
|
||||
assert!(ty::type_is_sized(bcx.tcx(), content_ty));
|
||||
assert!(type_is_sized(bcx.tcx(), content_ty));
|
||||
let llval = v0;
|
||||
let llbox = Load(bcx, llval);
|
||||
let not_null = IsNotNull(bcx, llbox);
|
||||
|
|
@ -415,7 +415,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
|
|||
// find the drop flag (which is at the end of the struct).
|
||||
// Lets just ignore the flag and pretend everything will be
|
||||
// OK.
|
||||
if ty::type_is_sized(bcx.tcx(), t) {
|
||||
if type_is_sized(bcx.tcx(), t) {
|
||||
trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
|
||||
} else {
|
||||
// Give the user a heads up that we are doing something
|
||||
|
|
@ -468,8 +468,8 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
|
|||
}
|
||||
ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty, false),
|
||||
_ => {
|
||||
assert!(ty::type_is_sized(bcx.tcx(), t));
|
||||
if ty::type_needs_drop(bcx.tcx(), t) &&
|
||||
assert!(type_is_sized(bcx.tcx(), t));
|
||||
if type_needs_drop(bcx.tcx(), t) &&
|
||||
ty::type_is_structural(t) {
|
||||
iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ use middle::ty::{mod, Ty};
|
|||
use syntax::abi::RustIntrinsic;
|
||||
use syntax::ast;
|
||||
use syntax::parse::token;
|
||||
use util::ppaux::ty_to_string;
|
||||
use util::ppaux::{Repr, ty_to_string};
|
||||
|
||||
pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Option<ValueRef> {
|
||||
let name = match token::get_ident(item.ident).get() {
|
||||
|
|
@ -90,46 +90,53 @@ pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Opti
|
|||
/// Performs late verification that intrinsics are used correctly. At present,
|
||||
/// the only intrinsic that needs such verification is `transmute`.
|
||||
pub fn check_intrinsics(ccx: &CrateContext) {
|
||||
for transmute_restriction in ccx.tcx()
|
||||
.transmute_restrictions
|
||||
.borrow()
|
||||
.iter() {
|
||||
let mut last_failing_id = None;
|
||||
for transmute_restriction in ccx.tcx().transmute_restrictions.borrow().iter() {
|
||||
// Sometimes, a single call to transmute will push multiple
|
||||
// type pairs to test in order to exhaustively test the
|
||||
// possibility around a type parameter. If one of those fails,
|
||||
// there is no sense reporting errors on the others.
|
||||
if last_failing_id == Some(transmute_restriction.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
debug!("transmute_restriction: {}", transmute_restriction.repr(ccx.tcx()));
|
||||
|
||||
assert!(!ty::type_has_params(transmute_restriction.substituted_from));
|
||||
assert!(!ty::type_has_params(transmute_restriction.substituted_to));
|
||||
|
||||
let llfromtype = type_of::sizing_type_of(ccx,
|
||||
transmute_restriction.from);
|
||||
transmute_restriction.substituted_from);
|
||||
let lltotype = type_of::sizing_type_of(ccx,
|
||||
transmute_restriction.to);
|
||||
transmute_restriction.substituted_to);
|
||||
let from_type_size = machine::llbitsize_of_real(ccx, llfromtype);
|
||||
let to_type_size = machine::llbitsize_of_real(ccx, lltotype);
|
||||
if from_type_size != to_type_size {
|
||||
ccx.sess()
|
||||
.span_err(transmute_restriction.span,
|
||||
format!("transmute called on types with different sizes: \
|
||||
{} ({} bit{}) to {} ({} bit{})",
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.from),
|
||||
from_type_size as uint,
|
||||
if from_type_size == 1 {
|
||||
""
|
||||
} else {
|
||||
"s"
|
||||
},
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.to),
|
||||
to_type_size as uint,
|
||||
if to_type_size == 1 {
|
||||
""
|
||||
} else {
|
||||
"s"
|
||||
})[]);
|
||||
}
|
||||
if ty::type_is_fat_ptr(ccx.tcx(), transmute_restriction.to) ||
|
||||
ty::type_is_fat_ptr(ccx.tcx(), transmute_restriction.from) {
|
||||
ccx.sess()
|
||||
.add_lint(::lint::builtin::FAT_PTR_TRANSMUTES,
|
||||
transmute_restriction.id,
|
||||
transmute_restriction.span,
|
||||
format!("Transmuting fat pointer types; {} to {}.\
|
||||
Beware of relying on the compiler's representation",
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.from),
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.to)));
|
||||
last_failing_id = Some(transmute_restriction.id);
|
||||
|
||||
if transmute_restriction.original_from != transmute_restriction.substituted_from {
|
||||
ccx.sess().span_err(
|
||||
transmute_restriction.span,
|
||||
format!("transmute called on types with potentially different sizes: \
|
||||
{} (could be {} bit{}) to {} (could be {} bit{})",
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.original_from),
|
||||
from_type_size as uint,
|
||||
if from_type_size == 1 {""} else {"s"},
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.original_to),
|
||||
to_type_size as uint,
|
||||
if to_type_size == 1 {""} else {"s"}).as_slice());
|
||||
} else {
|
||||
ccx.sess().span_err(
|
||||
transmute_restriction.span,
|
||||
format!("transmute called on types with different sizes: \
|
||||
{} ({} bit{}) to {} ({} bit{})",
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.original_from),
|
||||
from_type_size as uint,
|
||||
if from_type_size == 1 {""} else {"s"},
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.original_to),
|
||||
to_type_size as uint,
|
||||
if to_type_size == 1 {""} else {"s"}).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
ccx.sess().abort_if_errors();
|
||||
|
|
@ -365,7 +372,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
(_, "needs_drop") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
C_bool(ccx, ty::type_needs_drop(ccx.tcx(), tp_ty))
|
||||
C_bool(ccx, type_needs_drop(ccx.tcx(), tp_ty))
|
||||
}
|
||||
(_, "owns_managed") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use back::abi;
|
|||
use llvm;
|
||||
use llvm::ValueRef;
|
||||
use metadata::csearch;
|
||||
use middle::subst::{Subst,Substs};
|
||||
use middle::subst::{Substs};
|
||||
use middle::subst::VecPerParamSpace;
|
||||
use middle::subst;
|
||||
use middle::traits;
|
||||
|
|
@ -132,8 +132,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
ref trait_ref,
|
||||
method_num
|
||||
}) => {
|
||||
let trait_ref =
|
||||
Rc::new(ty::Binder((**trait_ref).subst(bcx.tcx(), bcx.fcx.param_substs)));
|
||||
let trait_ref = ty::Binder(bcx.monomorphize(trait_ref));
|
||||
let span = bcx.tcx().map.span(method_call.expr_id);
|
||||
debug!("method_call={} trait_ref={}",
|
||||
method_call,
|
||||
|
|
@ -142,8 +141,11 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
span,
|
||||
trait_ref.clone());
|
||||
debug!("origin = {}", origin.repr(bcx.tcx()));
|
||||
trans_monomorphized_callee(bcx, method_call, trait_ref.def_id(),
|
||||
method_num, origin)
|
||||
trans_monomorphized_callee(bcx,
|
||||
method_call,
|
||||
trait_ref.def_id(),
|
||||
method_num,
|
||||
origin)
|
||||
}
|
||||
|
||||
ty::MethodTraitObject(ref mt) => {
|
||||
|
|
@ -207,7 +209,6 @@ pub fn trans_static_method_callee(bcx: Block,
|
|||
let subst::SeparateVecsPerParamSpace {
|
||||
types: rcvr_type,
|
||||
selfs: rcvr_self,
|
||||
assocs: rcvr_assoc,
|
||||
fns: rcvr_method
|
||||
} = rcvr_substs.types.split();
|
||||
|
||||
|
|
@ -236,11 +237,11 @@ pub fn trans_static_method_callee(bcx: Block,
|
|||
let trait_substs =
|
||||
Substs::erased(VecPerParamSpace::new(rcvr_type,
|
||||
rcvr_self,
|
||||
rcvr_assoc,
|
||||
Vec::new()));
|
||||
let trait_substs = bcx.tcx().mk_substs(trait_substs);
|
||||
debug!("trait_substs={}", trait_substs.repr(bcx.tcx()));
|
||||
let trait_ref = Rc::new(ty::Binder(ty::TraitRef { def_id: trait_id,
|
||||
substs: bcx.tcx().mk_substs(trait_substs) }));
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
|
||||
substs: trait_substs }));
|
||||
let vtbl = fulfill_obligation(bcx.ccx(),
|
||||
DUMMY_SP,
|
||||
trait_ref);
|
||||
|
|
@ -273,13 +274,11 @@ pub fn trans_static_method_callee(bcx: Block,
|
|||
let subst::SeparateVecsPerParamSpace {
|
||||
types: impl_type,
|
||||
selfs: impl_self,
|
||||
assocs: impl_assoc,
|
||||
fns: _
|
||||
} = impl_substs.types.split();
|
||||
let callee_substs =
|
||||
Substs::erased(VecPerParamSpace::new(impl_type,
|
||||
impl_self,
|
||||
impl_assoc,
|
||||
rcvr_method));
|
||||
|
||||
let mth_id = method_with_name(ccx, impl_did, mname);
|
||||
|
|
@ -408,13 +407,12 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let subst::SeparateVecsPerParamSpace {
|
||||
types: rcvr_type,
|
||||
selfs: rcvr_self,
|
||||
assocs: rcvr_assoc,
|
||||
fns: rcvr_method
|
||||
} = rcvr_substs.types.clone().split();
|
||||
assert!(rcvr_method.is_empty());
|
||||
subst::Substs {
|
||||
regions: subst::ErasedRegions,
|
||||
types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, rcvr_assoc, node_method)
|
||||
types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -436,7 +434,7 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let self_datum = unpack_datum!(
|
||||
bcx, expr::trans(bcx, self_expr));
|
||||
|
||||
let llval = if ty::type_needs_drop(bcx.tcx(), self_datum.ty) {
|
||||
let llval = if type_needs_drop(bcx.tcx(), self_datum.ty) {
|
||||
let self_datum = unpack_datum!(
|
||||
bcx, self_datum.to_rvalue_datum(bcx, "trait_callee"));
|
||||
|
||||
|
|
@ -515,7 +513,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::PolyTraitRef<'tcx>>)
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> ValueRef
|
||||
{
|
||||
debug!("get_vtable(box_ty={}, trait_ref={})",
|
||||
|
|
@ -562,7 +560,7 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let llfn = vec![trans_fn_pointer_shim(bcx.ccx(), bare_fn_ty)];
|
||||
llfn.into_iter()
|
||||
}
|
||||
traits::VtableParam(..) => {
|
||||
traits::VtableParam => {
|
||||
bcx.sess().bug(
|
||||
format!("resolved vtable for {} to bad vtable {} in trans",
|
||||
trait_ref.repr(bcx.tcx()),
|
||||
|
|
@ -671,7 +669,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::PolyTraitRef<'tcx>>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
dest: expr::Dest)
|
||||
-> Block<'blk, 'tcx> {
|
||||
let mut bcx = bcx;
|
||||
|
|
|
|||
|
|
@ -12,15 +12,18 @@ use back::link::exported_name;
|
|||
use session;
|
||||
use llvm::ValueRef;
|
||||
use llvm;
|
||||
use middle::infer;
|
||||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::traits;
|
||||
use middle::ty_fold::{mod, TypeFolder, TypeFoldable};
|
||||
use trans::base::{set_llvm_fn_attrs, set_inline_hint};
|
||||
use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
|
||||
use trans::base::{trans_fn, decl_internal_rust_fn};
|
||||
use trans::base;
|
||||
use trans::common::*;
|
||||
use trans::foreign;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, HasProjectionTypes, Ty};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use syntax::abi;
|
||||
|
|
@ -29,6 +32,7 @@ use syntax::ast_map;
|
|||
use syntax::ast_util::{local_def, PostExpansionMethod};
|
||||
use syntax::attr;
|
||||
use std::hash::{sip, Hash};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
fn_id: ast::DefId,
|
||||
|
|
@ -92,7 +96,12 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
|
||||
debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx()));
|
||||
|
||||
let mono_ty = llitem_ty.subst(ccx.tcx(), psubsts);
|
||||
debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx()));
|
||||
|
||||
let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
|
||||
debug!("mono_ty = {} (post-normalization)", mono_ty.repr(ccx.tcx()));
|
||||
|
||||
ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
|
||||
|
||||
|
|
@ -282,3 +291,85 @@ pub struct MonoId<'tcx> {
|
|||
pub def: ast::DefId,
|
||||
pub params: subst::VecPerParamSpace<Ty<'tcx>>
|
||||
}
|
||||
|
||||
/// Monomorphizes a type from the AST by first applying the in-scope
|
||||
/// substitutions and then normalizing any associated types.
|
||||
pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
|
||||
param_substs: &Substs<'tcx>,
|
||||
value: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
assert!(param_substs.regions.is_erased());
|
||||
|
||||
let substituted = value.subst(tcx, param_substs);
|
||||
normalize_associated_type(tcx, &substituted)
|
||||
}
|
||||
|
||||
/// Removes associated types, if any. Since this during
|
||||
/// monomorphization, we know that only concrete types are involved,
|
||||
/// and hence we can be sure that all associated types will be
|
||||
/// completely normalized away.
|
||||
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, t: &T) -> T
|
||||
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
debug!("normalize_associated_type(t={})", t.repr(tcx));
|
||||
|
||||
if !t.has_projection_types() {
|
||||
return t.clone();
|
||||
}
|
||||
|
||||
// FIXME(#20304) -- cache
|
||||
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
let param_env = ty::empty_parameter_environment();
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env, tcx);
|
||||
let mut normalizer = AssociatedTypeNormalizer { selcx: &mut selcx };
|
||||
let result = t.fold_with(&mut normalizer);
|
||||
|
||||
debug!("normalize_associated_type: t={} result={}",
|
||||
t.repr(tcx),
|
||||
result.repr(tcx));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
struct AssociatedTypeNormalizer<'a,'tcx:'a> {
|
||||
selcx: &'a mut traits::SelectionContext<'a,'tcx>,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> { self.selcx.tcx() }
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match ty.sty {
|
||||
ty::ty_projection(ref data) => {
|
||||
debug!("ty_projection({})", data.repr(self.tcx()));
|
||||
|
||||
let tcx = self.selcx.tcx();
|
||||
let substs = data.trait_ref.substs.clone().erase_regions();
|
||||
let substs = self.tcx().mk_substs(substs);
|
||||
assert!(substs.types.iter().all(|&t| (!ty::type_has_params(t) &&
|
||||
!ty::type_has_self(t))));
|
||||
let trait_ref = Rc::new(ty::TraitRef::new(data.trait_ref.def_id, substs));
|
||||
let projection_ty = ty::ProjectionTy { trait_ref: trait_ref.clone(),
|
||||
item_name: data.item_name };
|
||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||
projection_ty);
|
||||
match traits::project_type(self.selcx, &obligation) {
|
||||
Ok(ty) => ty,
|
||||
Err(errors) => {
|
||||
tcx.sess.bug(
|
||||
format!("Encountered error(s) `{}` selecting `{}` during trans",
|
||||
errors.repr(tcx),
|
||||
trait_ref.repr(tcx)).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
|
||||
|
||||
let dataptr = get_dataptr(bcx, vptr);
|
||||
let bcx = if ty::type_needs_drop(tcx, unit_ty) {
|
||||
let bcx = if type_needs_drop(tcx, unit_ty) {
|
||||
let len = get_len(bcx, vptr);
|
||||
iter_vec_raw(bcx, dataptr, unit_ty, len, |bb, vv, tt| glue::drop_ty(bb, vv, tt, None))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
|
|||
}
|
||||
|
||||
let llsizingty = match t.sty {
|
||||
_ if !ty::lltype_is_sized(cx.tcx(), t) => {
|
||||
_ if !lltype_is_sized(cx.tcx(), t) => {
|
||||
cx.sess().bug(format!("trying to take the sizing type of {}, an unsized type",
|
||||
ppaux::ty_to_string(cx.tcx(), t))[])
|
||||
}
|
||||
|
|
@ -199,7 +199,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
|
|||
ty::ty_float(t) => Type::float_from_ty(cx, t),
|
||||
|
||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
|
||||
if ty::type_is_sized(cx.tcx(), ty) {
|
||||
if type_is_sized(cx.tcx(), ty) {
|
||||
Type::i8p(cx)
|
||||
} else {
|
||||
Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
|
||||
|
|
@ -241,7 +241,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
|
|||
Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
|
||||
}
|
||||
|
||||
ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
|
||||
ty::ty_projection(..) | ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
|
||||
cx.sess().bug(format!("fictitious type {} in sizing_type_of()",
|
||||
ppaux::ty_to_string(cx.tcx(), t))[])
|
||||
}
|
||||
|
|
@ -267,11 +267,11 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
|
|||
// struct which might be unsized, but is monomorphised to a sized type.
|
||||
// In this case we'll fake a fat pointer with no unsize info (we use 0).
|
||||
// However, its still a fat pointer, so we need some type use.
|
||||
if ty::type_is_sized(cx.tcx(), t) {
|
||||
if type_is_sized(cx.tcx(), t) {
|
||||
return Type::i8p(cx);
|
||||
}
|
||||
|
||||
match ty::unsized_part_of_type(cx.tcx(), t).sty {
|
||||
match unsized_part_of_type(cx.tcx(), t).sty {
|
||||
ty::ty_str | ty::ty_vec(..) => Type::uint_from_ty(cx, ast::TyU),
|
||||
ty::ty_trait(_) => Type::vtable_ptr(cx),
|
||||
_ => panic!("Unexpected type returned from unsized_part_of_type : {}",
|
||||
|
|
@ -342,7 +342,7 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
|
|||
cx.tn().find_type("str_slice").unwrap()
|
||||
}
|
||||
ty::ty_trait(..) => Type::opaque_trait(cx),
|
||||
_ if !ty::type_is_sized(cx.tcx(), ty) => {
|
||||
_ if !type_is_sized(cx.tcx(), ty) => {
|
||||
let p_ty = type_of(cx, ty).ptr_to();
|
||||
Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, ty)], false)
|
||||
}
|
||||
|
|
@ -414,6 +414,7 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
|
|||
},
|
||||
|
||||
ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
|
||||
ty::ty_projection(..) => cx.sess().bug("type_of with ty_projection"),
|
||||
ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
|
||||
ty::ty_err(..) => cx.sess().bug("type_of with ty_err"),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@
|
|||
//! somewhat differently during the collect and check phases,
|
||||
//! particularly with respect to looking up the types of top-level
|
||||
//! items. In the collect phase, the crate context is used as the
|
||||
//! `AstConv` instance; in this phase, the `get_item_ty()` function
|
||||
//! `AstConv` instance; in this phase, the `get_item_type_scheme()` function
|
||||
//! triggers a recursive call to `ty_of_item()` (note that
|
||||
//! `ast_ty_to_ty()` will detect recursive types and report an error).
|
||||
//! In the check phase, when the FnCtxt is used as the `AstConv`,
|
||||
//! `get_item_ty()` just looks up the item type in `tcx.tcache`.
|
||||
//! `get_item_type_scheme()` just looks up the item type in `tcx.tcache`.
|
||||
//!
|
||||
//! The `RegionScope` trait controls what happens when the user does
|
||||
//! not specify a region in some location where a region is required
|
||||
|
|
@ -51,7 +51,7 @@ use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGION
|
|||
use middle::const_eval;
|
||||
use middle::def;
|
||||
use middle::resolve_lifetime as rl;
|
||||
use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs};
|
||||
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
|
||||
use middle::subst::{VecPerParamSpace};
|
||||
use middle::ty::{mod, RegionEscape, Ty};
|
||||
use rscope::{mod, UnelidableRscope, RegionScope, SpecificRscope,
|
||||
|
|
@ -70,7 +70,7 @@ use syntax::print::pprust;
|
|||
|
||||
pub trait AstConv<'tcx> {
|
||||
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
|
||||
fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx>;
|
||||
fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx>;
|
||||
fn get_trait_def(&self, id: ast::DefId) -> Rc<ty::TraitDef<'tcx>>;
|
||||
|
||||
/// Return an (optional) substitution to convert bound type parameters that
|
||||
|
|
@ -84,25 +84,45 @@ pub trait AstConv<'tcx> {
|
|||
/// What type should we use when a type is omitted?
|
||||
fn ty_infer(&self, span: Span) -> Ty<'tcx>;
|
||||
|
||||
/// Returns true if associated types from the given trait and type are
|
||||
/// allowed to be used here and false otherwise.
|
||||
fn associated_types_of_trait_are_valid(&self,
|
||||
ty: Ty<'tcx>,
|
||||
trait_id: ast::DefId)
|
||||
-> bool;
|
||||
/// Projecting an associated type from a (potentially)
|
||||
/// higher-ranked trait reference is more complicated, because of
|
||||
/// the possibility of late-bound regions appearing in the
|
||||
/// associated type binding. This is not legal in function
|
||||
/// signatures for that reason. In a function body, we can always
|
||||
/// handle it because we can use inference variables to remove the
|
||||
/// late-bound regions.
|
||||
fn projected_ty_from_poly_trait_ref(&self,
|
||||
span: Span,
|
||||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
item_name: ast::Name)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
if ty::binds_late_bound_regions(self.tcx(), &poly_trait_ref) {
|
||||
self.tcx().sess.span_err(
|
||||
span,
|
||||
"cannot extract an associated type from a higher-ranked trait bound \
|
||||
in this context");
|
||||
self.tcx().types.err
|
||||
} else {
|
||||
// no late-bound regions, we can just ignore the binder
|
||||
self.projected_ty(span, poly_trait_ref.0.clone(), item_name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the concrete type bound to the given associated type (indicated
|
||||
/// by associated_type_id) in the current context. For example,
|
||||
/// in `trait Foo { type A; }` looking up `A` will give a type variable;
|
||||
/// in `impl Foo for ... { type A = int; ... }` looking up `A` will give `int`.
|
||||
fn associated_type_binding(&self,
|
||||
span: Span,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
// DefId for the declaration of the trait
|
||||
// in which the associated type is declared.
|
||||
trait_id: ast::DefId,
|
||||
associated_type_id: ast::DefId)
|
||||
-> Option<Ty<'tcx>>;
|
||||
/// Project an associated type from a non-higher-ranked trait reference.
|
||||
/// This is fairly straightforward and can be accommodated in any context.
|
||||
fn projected_ty(&self,
|
||||
span: Span,
|
||||
_trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
_item_name: ast::Name)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
self.tcx().sess.span_err(
|
||||
span,
|
||||
"associated types are not accepted in this context");
|
||||
|
||||
self.tcx().types.err
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
|
||||
|
|
@ -224,7 +244,6 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
|||
fn ast_path_substs_for_ty<'tcx,AC,RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
decl_def_id: ast::DefId,
|
||||
decl_generics: &ty::Generics<'tcx>,
|
||||
path: &ast::Path)
|
||||
-> Substs<'tcx>
|
||||
|
|
@ -255,28 +274,26 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>(
|
|||
}
|
||||
};
|
||||
|
||||
prohibit_projections(this.tcx(), assoc_bindings.as_slice());
|
||||
|
||||
create_substs_for_ast_path(this,
|
||||
rscope,
|
||||
path.span,
|
||||
decl_def_id,
|
||||
decl_generics,
|
||||
None,
|
||||
types,
|
||||
regions,
|
||||
assoc_bindings)
|
||||
regions)
|
||||
}
|
||||
|
||||
fn create_substs_for_ast_path<'tcx,AC,RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
decl_def_id: ast::DefId,
|
||||
decl_generics: &ty::Generics<'tcx>,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
types: Vec<Ty<'tcx>>,
|
||||
regions: Vec<ty::Region>,
|
||||
assoc_bindings: Vec<(ast::Ident, Ty<'tcx>)>)
|
||||
-> Substs<'tcx>
|
||||
regions: Vec<ty::Region>)
|
||||
-> Substs<'tcx>
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
|
|
@ -382,52 +399,21 @@ fn create_substs_for_ast_path<'tcx,AC,RS>(
|
|||
}
|
||||
}
|
||||
|
||||
for formal_assoc in decl_generics.types.get_slice(AssocSpace).iter() {
|
||||
let mut found = false;
|
||||
for &(ident, ty) in assoc_bindings.iter() {
|
||||
if formal_assoc.name.ident() == ident {
|
||||
substs.types.push(AssocSpace, ty);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
match this.associated_type_binding(span,
|
||||
self_ty,
|
||||
decl_def_id,
|
||||
formal_assoc.def_id) {
|
||||
Some(ty) => {
|
||||
substs.types.push(AssocSpace, ty);
|
||||
}
|
||||
None => {
|
||||
substs.types.push(AssocSpace, ty::mk_err());
|
||||
span_err!(this.tcx().sess, span, E0171,
|
||||
"missing type for associated type `{}`",
|
||||
token::get_ident(formal_assoc.name.ident()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for &(ident, _) in assoc_bindings.iter() {
|
||||
let mut formal_idents = decl_generics.types.get_slice(AssocSpace)
|
||||
.iter().map(|t| t.name.ident());
|
||||
if !formal_idents.any(|i| i == ident) {
|
||||
span_err!(this.tcx().sess, span, E0177,
|
||||
"associated type `{}` does not exist",
|
||||
token::get_ident(ident));
|
||||
}
|
||||
}
|
||||
|
||||
return substs;
|
||||
}
|
||||
|
||||
struct ConvertedBinding<'tcx> {
|
||||
item_name: ast::Name,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
|
||||
rscope: &RS,
|
||||
data: &ast::AngleBracketedParameterData)
|
||||
-> (Vec<ty::Region>,
|
||||
Vec<Ty<'tcx>>,
|
||||
Vec<(ast::Ident, Ty<'tcx>)>)
|
||||
Vec<ConvertedBinding<'tcx>>)
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
let regions: Vec<_> =
|
||||
|
|
@ -442,7 +428,9 @@ fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
|
|||
|
||||
let assoc_bindings: Vec<_> =
|
||||
data.bindings.iter()
|
||||
.map(|b| (b.ident, ast_ty_to_ty(this, rscope, &*b.ty)))
|
||||
.map(|b| ConvertedBinding { item_name: b.ident.name,
|
||||
ty: ast_ty_to_ty(this, rscope, &*b.ty),
|
||||
span: b.span })
|
||||
.collect();
|
||||
|
||||
(regions, types, assoc_bindings)
|
||||
|
|
@ -534,38 +522,47 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>(
|
|||
rscope: &RS,
|
||||
ast_trait_ref: &ast::PolyTraitRef,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
allow_eq: AllowEqConstraints)
|
||||
-> Rc<ty::PolyTraitRef<'tcx>>
|
||||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
let mut projections = Vec::new();
|
||||
|
||||
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.
|
||||
instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref,
|
||||
self_ty, Some(&mut projections));
|
||||
|
||||
for projection in projections.into_iter() {
|
||||
poly_projections.push(ty::Binder(projection));
|
||||
}
|
||||
|
||||
ty::Binder(trait_ref)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// Fails if the type is a type other than a trait type.
|
||||
pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
rscope: &RS,
|
||||
ast_trait_ref: &ast::TraitRef,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
allow_eq: AllowEqConstraints)
|
||||
-> Rc<ty::TraitRef<'tcx>>
|
||||
where AC: AstConv<'tcx>,
|
||||
RS: RegionScope
|
||||
///
|
||||
/// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
|
||||
/// are disallowed. Otherwise, they are pushed onto the vector given.
|
||||
pub fn instantiate_trait_ref<'tcx,AC,RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
ast_trait_ref: &ast::TraitRef,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
|
||||
-> Rc<ty::TraitRef<'tcx>>
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
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,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
&ast_trait_ref.path,
|
||||
allow_eq));
|
||||
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
|
||||
trait_ref.clone());
|
||||
let trait_ref = ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
&ast_trait_ref.path,
|
||||
projections);
|
||||
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, trait_ref.clone());
|
||||
trait_ref
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -576,20 +573,14 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
|
|||
}
|
||||
}
|
||||
|
||||
#[deriving(PartialEq,Show)]
|
||||
pub enum AllowEqConstraints {
|
||||
Allow,
|
||||
DontAllow
|
||||
}
|
||||
|
||||
fn ast_path_to_trait_ref<'tcx,AC,RS>(
|
||||
fn ast_path_to_trait_ref<'a,'tcx,AC,RS>(
|
||||
this: &AC,
|
||||
rscope: &RS,
|
||||
trait_def_id: ast::DefId,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
path: &ast::Path,
|
||||
allow_eq: AllowEqConstraints)
|
||||
-> ty::TraitRef<'tcx>
|
||||
mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
|
||||
-> Rc<ty::TraitRef<'tcx>>
|
||||
where AC: AstConv<'tcx>, RS: RegionScope
|
||||
{
|
||||
debug!("ast_path_to_trait_ref {}", path);
|
||||
|
|
@ -624,22 +615,75 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>(
|
|||
}
|
||||
};
|
||||
|
||||
if allow_eq == AllowEqConstraints::DontAllow && assoc_bindings.len() > 0 {
|
||||
span_err!(this.tcx().sess, path.span, E0173,
|
||||
"equality constraints are not allowed in this position");
|
||||
}
|
||||
|
||||
let substs = create_substs_for_ast_path(this,
|
||||
&shifted_rscope,
|
||||
path.span,
|
||||
trait_def_id,
|
||||
&trait_def.generics,
|
||||
self_ty,
|
||||
types,
|
||||
regions,
|
||||
assoc_bindings);
|
||||
regions);
|
||||
let substs = this.tcx().mk_substs(substs);
|
||||
|
||||
ty::TraitRef::new(trait_def_id, this.tcx().mk_substs(substs))
|
||||
let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs));
|
||||
|
||||
match projections {
|
||||
None => {
|
||||
prohibit_projections(this.tcx(), assoc_bindings.as_slice());
|
||||
}
|
||||
Some(ref mut v) => {
|
||||
for binding in assoc_bindings.iter() {
|
||||
match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), binding) {
|
||||
Ok(pp) => { v.push(pp); }
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait_ref
|
||||
}
|
||||
|
||||
pub fn ast_type_binding_to_projection_predicate<'tcx,AC>(
|
||||
this: &AC,
|
||||
trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
binding: &ConvertedBinding<'tcx>)
|
||||
-> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
|
||||
where AC : AstConv<'tcx>
|
||||
{
|
||||
// Given something like `U : SomeTrait<T=X>`, we want to produce a
|
||||
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
|
||||
// subtle in the event that `T` is defined in a supertrait of
|
||||
// `SomeTrait`, because in that case we need to upcast.
|
||||
//
|
||||
// That is, consider this case:
|
||||
//
|
||||
// ```
|
||||
// trait SubTrait : SuperTrait<int> { }
|
||||
// trait SuperTrait<A> { type T; }
|
||||
//
|
||||
// ... B : SubTrait<T=foo> ...
|
||||
// ```
|
||||
//
|
||||
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||
|
||||
// FIXME(#19541): supertrait upcasting not actually impl'd :)
|
||||
|
||||
if !trait_defines_associated_type_named(this, trait_ref.def_id, binding.item_name) {
|
||||
this.tcx().sess.span_err(
|
||||
binding.span,
|
||||
format!("no associated type `{}` defined in `{}`",
|
||||
token::get_name(binding.item_name),
|
||||
trait_ref.user_string(this.tcx())).as_slice());
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
Ok(ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy {
|
||||
trait_ref: trait_ref,
|
||||
item_name: binding.item_name,
|
||||
},
|
||||
ty: binding.ty,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
|
|
@ -650,14 +694,13 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
|||
-> TypeAndSubsts<'tcx>
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
let ty::Polytype {
|
||||
let ty::TypeScheme {
|
||||
generics,
|
||||
ty: decl_ty
|
||||
} = this.get_item_ty(did);
|
||||
} = this.get_item_type_scheme(did);
|
||||
|
||||
let substs = ast_path_substs_for_ty(this,
|
||||
rscope,
|
||||
did,
|
||||
&generics,
|
||||
path);
|
||||
let ty = decl_ty.subst(tcx, &substs);
|
||||
|
|
@ -678,10 +721,10 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
|
|||
where AC : AstConv<'tcx>, RS : RegionScope
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
let ty::Polytype {
|
||||
let ty::TypeScheme {
|
||||
generics,
|
||||
ty: decl_ty
|
||||
} = this.get_item_ty(did);
|
||||
} = this.get_item_type_scheme(did);
|
||||
|
||||
let wants_params =
|
||||
generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
|
||||
|
|
@ -699,7 +742,7 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
|
|||
Substs::new(VecPerParamSpace::params_from_type(type_params),
|
||||
VecPerParamSpace::params_from_type(region_params))
|
||||
} else {
|
||||
ast_path_substs_for_ty(this, rscope, did, &generics, path)
|
||||
ast_path_substs_for_ty(this, rscope, &generics, path)
|
||||
};
|
||||
|
||||
let ty = decl_ty.subst(tcx, &substs);
|
||||
|
|
@ -762,11 +805,13 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
|||
}
|
||||
}
|
||||
|
||||
type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>);
|
||||
|
||||
fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC,
|
||||
rscope: &RS,
|
||||
ty: &ast::Ty,
|
||||
bounds: &[ast::TyParamBound])
|
||||
-> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
|
||||
-> Result<TraitAndProjections<'tcx>, ErrorReported>
|
||||
where AC : AstConv<'tcx>, RS : RegionScope
|
||||
{
|
||||
/*!
|
||||
|
|
@ -784,12 +829,17 @@ 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(ty::Binder(ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
AllowEqConstraints::Allow)));
|
||||
let mut projection_bounds = Vec::new();
|
||||
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
Some(&mut projection_bounds)));
|
||||
let projection_bounds = projection_bounds.into_iter()
|
||||
.map(ty::Binder)
|
||||
.collect();
|
||||
Ok((trait_ref, projection_bounds))
|
||||
}
|
||||
_ => {
|
||||
span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait");
|
||||
|
|
@ -832,6 +882,7 @@ fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC,
|
|||
rscope: &RS,
|
||||
span: Span,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
|
||||
bounds: &[ast::TyParamBound])
|
||||
-> Ty<'tcx>
|
||||
where AC : AstConv<'tcx>, RS : RegionScope
|
||||
|
|
@ -839,7 +890,8 @@ fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC,
|
|||
let existential_bounds = conv_existential_bounds(this,
|
||||
rscope,
|
||||
span,
|
||||
Some(&trait_ref),
|
||||
Some(trait_ref.clone()),
|
||||
projection_bounds,
|
||||
bounds);
|
||||
|
||||
let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds);
|
||||
|
|
@ -849,6 +901,68 @@ fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC,
|
|||
result
|
||||
}
|
||||
|
||||
fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
|
||||
ast_ty: &ast::Ty,
|
||||
provenance: def::TyParamProvenance,
|
||||
assoc_name: ast::Name)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
let ty_param_def_id = provenance.def_id();
|
||||
let mut suitable_bounds: Vec<_>;
|
||||
let ty_param_name: ast::Name;
|
||||
{ // contain scope of refcell:
|
||||
let ty_param_defs = tcx.ty_param_defs.borrow();
|
||||
let ty_param_def = &ty_param_defs[ty_param_def_id.node];
|
||||
ty_param_name = ty_param_def.name;
|
||||
|
||||
// FIXME(#19541): we should consider associated types in
|
||||
// super-traits. Probably by elaborating the bounds.
|
||||
|
||||
suitable_bounds =
|
||||
ty_param_def.bounds.trait_bounds // FIXME(#20300) -- search where clauses, not bounds
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|b| trait_defines_associated_type_named(this, b.def_id(), assoc_name))
|
||||
.collect();
|
||||
}
|
||||
|
||||
if suitable_bounds.len() == 0 {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
format!("associated type `{}` not found for type parameter `{}`",
|
||||
token::get_name(assoc_name),
|
||||
token::get_name(ty_param_name)).as_slice());
|
||||
return this.tcx().types.err;
|
||||
}
|
||||
|
||||
if suitable_bounds.len() > 1 {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
format!("ambiguous associated type `{}` in bounds of `{}`",
|
||||
token::get_name(assoc_name),
|
||||
token::get_name(ty_param_name)).as_slice());
|
||||
|
||||
for suitable_bound in suitable_bounds.iter() {
|
||||
span_note!(this.tcx().sess, ast_ty.span,
|
||||
"associated type `{}` could derive from `{}`",
|
||||
token::get_name(ty_param_name),
|
||||
suitable_bound.user_string(this.tcx()));
|
||||
}
|
||||
}
|
||||
|
||||
let suitable_bound = suitable_bounds.pop().unwrap().clone();
|
||||
return this.projected_ty_from_poly_trait_ref(ast_ty.span, suitable_bound, assoc_name);
|
||||
}
|
||||
|
||||
fn trait_defines_associated_type_named(this: &AstConv,
|
||||
trait_def_id: ast::DefId,
|
||||
assoc_name: ast::Name)
|
||||
-> bool
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
|
||||
trait_def.associated_type_names.contains(&assoc_name)
|
||||
}
|
||||
|
||||
fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
|
||||
rscope: &RS,
|
||||
ast_ty: &ast::Ty, // the TyQPath
|
||||
|
|
@ -867,33 +981,13 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
|
|||
rscope,
|
||||
&*qpath.trait_ref,
|
||||
Some(self_type),
|
||||
AllowEqConstraints::DontAllow);
|
||||
None);
|
||||
|
||||
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
|
||||
|
||||
if let Some(ty) = find_assoc_ty(this, &*trait_ref, qpath.item_name) {
|
||||
return ty;
|
||||
}
|
||||
|
||||
this.tcx().sess.span_bug(ast_ty.span,
|
||||
"this associated type didn't get added \
|
||||
as a parameter for some reason")
|
||||
}
|
||||
|
||||
fn find_assoc_ty<'tcx, AC>(this: &AC,
|
||||
trait_ref: &ty::TraitRef<'tcx>,
|
||||
type_name: ast::Ident)
|
||||
-> Option<Ty<'tcx>>
|
||||
where AC: AstConv<'tcx> {
|
||||
let trait_def = this.get_trait_def(trait_ref.def_id);
|
||||
|
||||
for ty_param_def in trait_def.generics.types.get_slice(AssocSpace).iter() {
|
||||
if ty_param_def.name == type_name.name {
|
||||
return Some(trait_ref.substs.type_for_def(ty_param_def));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
return this.projected_ty(ast_ty.span,
|
||||
trait_ref,
|
||||
qpath.item_name.name);
|
||||
}
|
||||
|
||||
// Parses the programmer's textual representation of a type into our
|
||||
|
|
@ -927,12 +1021,12 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
|||
}
|
||||
ast::TyObjectSum(ref ty, ref bounds) => {
|
||||
match ast_ty_to_trait_ref(this, rscope, &**ty, bounds[]) {
|
||||
Ok(trait_ref) => {
|
||||
Ok((trait_ref, projection_bounds)) => {
|
||||
trait_ref_to_object_type(this, rscope, ast_ty.span,
|
||||
trait_ref, bounds[])
|
||||
trait_ref, projection_bounds, bounds[])
|
||||
}
|
||||
Err(ErrorReported) => {
|
||||
ty::mk_err()
|
||||
this.tcx().types.err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -970,13 +1064,15 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
|||
rscope,
|
||||
ast_ty.span,
|
||||
None,
|
||||
Vec::new(),
|
||||
f.bounds.as_slice());
|
||||
let region_bound = bounds.region_bound;
|
||||
let fn_decl = ty_of_closure(this,
|
||||
f.unsafety,
|
||||
f.onceness,
|
||||
bounds,
|
||||
ty::RegionTraitStore(
|
||||
bounds.region_bound,
|
||||
region_bound,
|
||||
ast::MutMutable),
|
||||
&*f.decl,
|
||||
abi::Rust,
|
||||
|
|
@ -1000,28 +1096,33 @@ 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 = 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, &[])
|
||||
let mut projection_bounds = Vec::new();
|
||||
let trait_ref = ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
Some(&mut projection_bounds));
|
||||
let trait_ref = ty::Binder(trait_ref);
|
||||
let projection_bounds = projection_bounds.into_iter()
|
||||
.map(ty::Binder)
|
||||
.collect();
|
||||
trait_ref_to_object_type(this, rscope, path.span,
|
||||
trait_ref, projection_bounds, &[])
|
||||
}
|
||||
def::DefTy(did, _) | def::DefStruct(did) => {
|
||||
ast_path_to_ty(this, rscope, did, path).ty
|
||||
}
|
||||
def::DefTyParam(space, id, n) => {
|
||||
def::DefTyParam(space, index, _, name) => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
ty::mk_param(tcx, space, n, id)
|
||||
ty::mk_param(tcx, space, index, name)
|
||||
}
|
||||
def::DefSelfTy(id) => {
|
||||
def::DefSelfTy(_) => {
|
||||
// n.b.: resolve guarantees that the this type only appears in a
|
||||
// trait, which we rely upon in various places when creating
|
||||
// substs
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
let did = ast_util::local_def(id);
|
||||
ty::mk_self_type(tcx, did)
|
||||
ty::mk_self_type(tcx)
|
||||
}
|
||||
def::DefMod(id) => {
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
|
|
@ -1046,46 +1147,10 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
|||
.unwrap()
|
||||
.identifier)
|
||||
.get())[]);
|
||||
ty::mk_err()
|
||||
this.tcx().types.err
|
||||
}
|
||||
def::DefAssociatedPath(typ, assoc_ident) => {
|
||||
// FIXME(#19541): in both branches we should consider
|
||||
// associated types in super-traits.
|
||||
let (assoc_tys, tp_name): (Vec<_>, _) = match typ {
|
||||
def::TyParamProvenance::FromParam(did) |
|
||||
def::TyParamProvenance::FromSelf(did) => {
|
||||
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.0, assoc_ident))
|
||||
.collect();
|
||||
(assoc_tys, token::get_name(tp_def.name).to_string())
|
||||
}
|
||||
};
|
||||
|
||||
if assoc_tys.len() == 0 {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
format!("associated type `{}` not \
|
||||
found for type parameter `{}`",
|
||||
token::get_ident(assoc_ident),
|
||||
tp_name).as_slice());
|
||||
return ty::mk_err()
|
||||
}
|
||||
|
||||
if assoc_tys.len() > 1 {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
format!("ambiguous associated type \
|
||||
`{}` in bounds of `{}`",
|
||||
token::get_ident(assoc_ident),
|
||||
tp_name).as_slice());
|
||||
}
|
||||
|
||||
let mut result_ty = assoc_tys[0];
|
||||
if let Some(substs) = this.get_free_substs() {
|
||||
result_ty = result_ty.subst(tcx, substs);
|
||||
}
|
||||
|
||||
result_ty
|
||||
def::DefAssociatedPath(provenance, assoc_ident) => {
|
||||
associated_path_def_to_ty(this, ast_ty, provenance, assoc_ident.name)
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
|
|
@ -1378,7 +1443,7 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
|
|||
this: &AC,
|
||||
unsafety: ast::Unsafety,
|
||||
onceness: ast::Onceness,
|
||||
bounds: ty::ExistentialBounds,
|
||||
bounds: ty::ExistentialBounds<'tcx>,
|
||||
store: ty::TraitStore,
|
||||
decl: &ast::FnDecl,
|
||||
abi: abi::Abi,
|
||||
|
|
@ -1440,15 +1505,16 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
|
|||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
|
||||
ast_bounds: &[ast::TyParamBound])
|
||||
-> ty::ExistentialBounds
|
||||
-> ty::ExistentialBounds<'tcx>
|
||||
{
|
||||
let partitioned_bounds =
|
||||
partition_bounds(this.tcx(), span, ast_bounds);
|
||||
|
||||
conv_existential_bounds_from_partitioned_bounds(
|
||||
this, rscope, span, principal_trait_ref, partitioned_bounds)
|
||||
this, rscope, span, principal_trait_ref, projection_bounds, partitioned_bounds)
|
||||
}
|
||||
|
||||
fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
|
||||
|
|
@ -1461,13 +1527,15 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
|
|||
{
|
||||
let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]);
|
||||
|
||||
let mut projection_bounds = Vec::new();
|
||||
let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) {
|
||||
Some(trait_bound) => {
|
||||
Some(instantiate_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_bound,
|
||||
None,
|
||||
AllowEqConstraints::Allow))
|
||||
let ptr = instantiate_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_bound,
|
||||
None,
|
||||
&mut projection_bounds);
|
||||
Some(ptr)
|
||||
}
|
||||
None => {
|
||||
this.tcx().sess.span_err(
|
||||
|
|
@ -1481,12 +1549,13 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
|
|||
conv_existential_bounds_from_partitioned_bounds(this,
|
||||
rscope,
|
||||
span,
|
||||
main_trait_bound.as_ref().map(|tr| &**tr),
|
||||
main_trait_bound.clone(),
|
||||
projection_bounds,
|
||||
partitioned_bounds);
|
||||
|
||||
match main_trait_bound {
|
||||
None => ty::mk_err(),
|
||||
Some(principal) => ty::mk_trait(this.tcx(), (*principal).clone(), bounds)
|
||||
None => this.tcx().types.err,
|
||||
Some(principal) => ty::mk_trait(this.tcx(), principal, bounds)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1494,9 +1563,10 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>(
|
|||
this: &AC,
|
||||
rscope: &RS,
|
||||
span: Span,
|
||||
principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
mut projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures
|
||||
partitioned_bounds: PartitionedBounds)
|
||||
-> ty::ExistentialBounds
|
||||
-> ty::ExistentialBounds<'tcx>
|
||||
where AC: AstConv<'tcx>, RS:RegionScope
|
||||
{
|
||||
let PartitionedBounds { builtin_bounds,
|
||||
|
|
@ -1519,9 +1589,12 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx, AC, RS>(
|
|||
principal_trait_ref,
|
||||
builtin_bounds);
|
||||
|
||||
ty::sort_bounds_list(projection_bounds.as_mut_slice());
|
||||
|
||||
ty::ExistentialBounds {
|
||||
region_bound: region_bound,
|
||||
builtin_bounds: builtin_bounds,
|
||||
projection_bounds: projection_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1532,7 +1605,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::PolyTraitRef<'tcx>>,
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> Option<ty::Region>
|
||||
{
|
||||
|
|
@ -1557,7 +1630,7 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
// No explicit region bound specified. Therefore, examine trait
|
||||
// bounds and see if we can derive region bounds from those.
|
||||
let derived_region_bounds =
|
||||
ty::object_region_bounds(tcx, principal_trait_ref, builtin_bounds);
|
||||
ty::object_region_bounds(tcx, principal_trait_ref.as_ref(), builtin_bounds);
|
||||
|
||||
// If there are no derived region bounds, then report back that we
|
||||
// can find no region bound.
|
||||
|
|
@ -1592,7 +1665,7 @@ fn compute_region_bound<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
|
|||
rscope: &RS,
|
||||
span: Span,
|
||||
region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: Option<&ty::PolyTraitRef<'tcx>>, // None for closures
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for closures
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> ty::Region
|
||||
{
|
||||
|
|
@ -1660,6 +1733,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
|||
if ty::try_add_builtin_trait(tcx,
|
||||
trait_did,
|
||||
&mut builtin_bounds) {
|
||||
// FIXME(#20302) -- we should check for things like Copy<T>
|
||||
continue; // success
|
||||
}
|
||||
}
|
||||
|
|
@ -1683,3 +1757,13 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt,
|
|||
region_bounds: region_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn prohibit_projections<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
bindings: &[ConvertedBinding<'tcx>])
|
||||
{
|
||||
for binding in bindings.iter().take(1) {
|
||||
tcx.sess.span_err(
|
||||
binding.span,
|
||||
"associated type bindings are not allowed here");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
use middle::def;
|
||||
use middle::infer;
|
||||
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::subst::{Substs};
|
||||
use middle::ty::{mod, Ty};
|
||||
use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
|
||||
use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
|
||||
|
|
@ -79,9 +79,9 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
}
|
||||
ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
|
||||
let const_did = tcx.def_map.borrow()[pat.id].clone().def_id();
|
||||
let const_pty = ty::lookup_item_type(tcx, const_did);
|
||||
fcx.write_ty(pat.id, const_pty.ty);
|
||||
demand::suptype(fcx, pat.span, expected, const_pty.ty);
|
||||
let const_scheme = ty::lookup_item_type(tcx, const_did);
|
||||
fcx.write_ty(pat.id, const_scheme.ty);
|
||||
demand::suptype(fcx, pat.span, expected, const_scheme.ty);
|
||||
}
|
||||
ast::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => {
|
||||
let typ = fcx.local_ty(pat.span, pat.id);
|
||||
|
|
@ -142,7 +142,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
check_pat(pcx, &**inner, inner_ty);
|
||||
} else {
|
||||
fcx.write_error(pat.id);
|
||||
check_pat(pcx, &**inner, ty::mk_err());
|
||||
check_pat(pcx, &**inner, tcx.types.err);
|
||||
}
|
||||
}
|
||||
ast::PatRegion(ref inner) => {
|
||||
|
|
@ -162,7 +162,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
check_pat(pcx, &**inner, inner_ty);
|
||||
} else {
|
||||
fcx.write_error(pat.id);
|
||||
check_pat(pcx, &**inner, ty::mk_err());
|
||||
check_pat(pcx, &**inner, tcx.types.err);
|
||||
}
|
||||
}
|
||||
ast::PatVec(ref before, ref slice, ref after) => {
|
||||
|
|
@ -285,11 +285,11 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
};
|
||||
|
||||
if let Some(ref e) = arm.guard {
|
||||
check_expr_has_type(fcx, &**e, ty::mk_bool());
|
||||
check_expr_has_type(fcx, &**e, tcx.types.bool);
|
||||
}
|
||||
|
||||
if ty::type_is_error(result_ty) || ty::type_is_error(bty) {
|
||||
ty::mk_err()
|
||||
tcx.types.err
|
||||
} else {
|
||||
let (origin, expected, found) = match match_src {
|
||||
/* if-let construct without an else block */
|
||||
|
|
@ -339,7 +339,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
|
|||
fcx.write_error(pat.id);
|
||||
|
||||
for field in fields.iter() {
|
||||
check_pat(pcx, &*field.node.pat, ty::mk_err());
|
||||
check_pat(pcx, &*field.node.pat, tcx.types.err);
|
||||
}
|
||||
return;
|
||||
},
|
||||
|
|
@ -358,7 +358,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
|
|||
fcx.write_error(pat.id);
|
||||
|
||||
for field in fields.iter() {
|
||||
check_pat(pcx, &*field.node.pat, ty::mk_err());
|
||||
check_pat(pcx, &*field.node.pat, tcx.types.err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -395,32 +395,39 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
|
|||
let enum_def = def.variant_def_ids()
|
||||
.map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
|
||||
|
||||
let ctor_pty = ty::lookup_item_type(tcx, enum_def);
|
||||
let path_ty = if ty::is_fn_ty(ctor_pty.ty) {
|
||||
ty::Polytype {
|
||||
ty: ty::ty_fn_ret(ctor_pty.ty).unwrap(),
|
||||
..ctor_pty
|
||||
let ctor_scheme = ty::lookup_item_type(tcx, enum_def);
|
||||
let path_scheme = if ty::is_fn_ty(ctor_scheme.ty) {
|
||||
ty::TypeScheme {
|
||||
ty: ty::ty_fn_ret(ctor_scheme.ty).unwrap(),
|
||||
..ctor_scheme
|
||||
}
|
||||
} else {
|
||||
ctor_pty
|
||||
ctor_scheme
|
||||
};
|
||||
instantiate_path(pcx.fcx, path, path_ty, def, pat.span, pat.id);
|
||||
instantiate_path(pcx.fcx, path, path_scheme, def, pat.span, pat.id);
|
||||
|
||||
let pat_ty = fcx.node_ty(pat.id);
|
||||
demand::eqtype(fcx, pat.span, expected, pat_ty);
|
||||
|
||||
let real_path_ty = fcx.node_ty(pat.id);
|
||||
let (arg_tys, kind_name) = match real_path_ty.sty {
|
||||
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
|
||||
ty::ty_enum(enum_def_id, expected_substs)
|
||||
if def == def::DefVariant(enum_def_id, def.def_id(), false) => {
|
||||
if def == def::DefVariant(enum_def_id, def.def_id(), false) =>
|
||||
{
|
||||
let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id());
|
||||
(variant.args.iter().map(|t| t.subst(tcx, expected_substs)).collect::<Vec<_>>(),
|
||||
"variant")
|
||||
(variant.args.iter()
|
||||
.map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t))
|
||||
.collect(),
|
||||
"variant")
|
||||
}
|
||||
ty::ty_struct(struct_def_id, expected_substs) => {
|
||||
let struct_fields = ty::struct_fields(tcx, struct_def_id, expected_substs);
|
||||
(struct_fields.iter().map(|field| field.mt.ty).collect::<Vec<_>>(),
|
||||
"struct")
|
||||
(struct_fields.iter()
|
||||
.map(|field| fcx.instantiate_type_scheme(pat.span,
|
||||
expected_substs,
|
||||
&field.mt.ty))
|
||||
.collect(),
|
||||
"struct")
|
||||
}
|
||||
_ => {
|
||||
let name = pprust::path_to_string(path);
|
||||
|
|
@ -430,7 +437,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
|
|||
|
||||
if let Some(ref subpats) = *subpats {
|
||||
for pat in subpats.iter() {
|
||||
check_pat(pcx, &**pat, ty::mk_err());
|
||||
check_pat(pcx, &**pat, tcx.types.err);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -448,7 +455,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
|
|||
subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name);
|
||||
|
||||
for pat in subpats.iter() {
|
||||
check_pat(pcx, &**pat, ty::mk_err());
|
||||
check_pat(pcx, &**pat, tcx.types.err);
|
||||
}
|
||||
} else {
|
||||
span_err!(tcx.sess, pat.span, E0023,
|
||||
|
|
@ -458,7 +465,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
|
|||
arg_tys.len(), if arg_tys.len() == 1 {""} else {"s"});
|
||||
|
||||
for pat in subpats.iter() {
|
||||
check_pat(pcx, &**pat, ty::mk_err());
|
||||
check_pat(pcx, &**pat, tcx.types.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -496,7 +503,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
span_note!(tcx.sess, *occupied.get(),
|
||||
"field `{}` previously bound here",
|
||||
token::get_ident(field.ident));
|
||||
ty::mk_err()
|
||||
tcx.types.err
|
||||
}
|
||||
Vacant(vacant) => {
|
||||
vacant.set(span);
|
||||
|
|
@ -506,7 +513,7 @@ pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
"struct `{}` does not have a field named `{}`",
|
||||
ty::item_path_str(tcx, struct_id),
|
||||
token::get_ident(field.ident));
|
||||
ty::mk_err()
|
||||
tcx.types.err
|
||||
})
|
||||
}
|
||||
};
|
||||
|
|
|
|||
93
src/librustc_typeck/check/assoc.rs
Normal file
93
src/librustc_typeck/check/assoc.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
// 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.
|
||||
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::traits::{ObligationCause, ObligationCauseCode, FulfillmentContext};
|
||||
use middle::ty::{mod, RegionEscape, HasProjectionTypes, Ty};
|
||||
use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
fulfillment_cx: &mut FulfillmentContext<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
value: &T)
|
||||
-> T
|
||||
where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone
|
||||
{
|
||||
let value = infcx.resolve_type_vars_if_possible(value);
|
||||
|
||||
if !value.has_projection_types() {
|
||||
return value.clone();
|
||||
}
|
||||
|
||||
let mut normalizer = AssociatedTypeNormalizer { span: span,
|
||||
body_id: body_id,
|
||||
infcx: infcx,
|
||||
fulfillment_cx: fulfillment_cx };
|
||||
value.fold_with(&mut normalizer)
|
||||
}
|
||||
|
||||
struct AssociatedTypeNormalizer<'a,'tcx:'a> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
fulfillment_cx: &'a mut FulfillmentContext<'tcx>,
|
||||
span: Span,
|
||||
body_id: ast::NodeId,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// We don't want to normalize associated types that occur inside of region
|
||||
// binders, because they may contain bound regions, and we can't cope with that.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> fn(<T as Foo<&'a>>::A)
|
||||
//
|
||||
// Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
|
||||
// normalize it when we instantiate those bound regions (which
|
||||
// should occur eventually).
|
||||
|
||||
match ty.sty {
|
||||
ty::ty_projection(ref data) if !data.has_escaping_regions() => { // (*)
|
||||
|
||||
// (*) This is kind of hacky -- we need to be able to
|
||||
// handle normalization within binders because
|
||||
// otherwise we wind up a need to normalize when doing
|
||||
// trait matching (since you can have a trait
|
||||
// obligation like `for<'a> T::B : Fn(&'a int)`), but
|
||||
// we can't normalize with bound regions in scope. So
|
||||
// far now we just ignore binders but only normalize
|
||||
// if all bound regions are gone (and then we still
|
||||
// have to renormalize whenever we instantiate a
|
||||
// binder). It would be better to normalize in a
|
||||
// binding-aware fashion.
|
||||
|
||||
let cause =
|
||||
ObligationCause::new(
|
||||
self.span,
|
||||
self.body_id,
|
||||
ObligationCauseCode::MiscObligation);
|
||||
self.fulfillment_cx
|
||||
.normalize_projection_type(self.infcx,
|
||||
data.clone(),
|
||||
cause)
|
||||
}
|
||||
_ => {
|
||||
ty_fold::super_fold_ty(self, ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,8 +14,9 @@ use super::{check_fn, Expectation, FnCtxt};
|
|||
|
||||
use astconv;
|
||||
use middle::infer;
|
||||
use middle::region::CodeExtent;
|
||||
use middle::subst;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, ToPolyTraitRef, Ty};
|
||||
use rscope::RegionScope;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
|
|
@ -47,7 +48,7 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
|||
match expected_sig_and_kind {
|
||||
None => { // doesn't look like an unboxed closure
|
||||
let region = astconv::opt_ast_region_to_region(fcx,
|
||||
fcx.infcx(),
|
||||
fcx,
|
||||
expr.span,
|
||||
&None);
|
||||
|
||||
|
|
@ -116,7 +117,7 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
|||
abi::RustCall,
|
||||
expected_sig);
|
||||
|
||||
let region = match fcx.infcx().anon_regions(expr.span, 1) {
|
||||
let region = match fcx.anon_regions(expr.span, 1) {
|
||||
Err(_) => {
|
||||
fcx.ccx.tcx.sess.span_bug(expr.span,
|
||||
"can't make anon regions here?!")
|
||||
|
|
@ -132,10 +133,13 @@ fn check_unboxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
|||
|
||||
fcx.write_ty(expr.id, closure_type);
|
||||
|
||||
let fn_sig =
|
||||
ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
|
||||
|
||||
check_fn(fcx.ccx,
|
||||
ast::Unsafety::Normal,
|
||||
expr.id,
|
||||
&fn_ty.sig,
|
||||
&fn_sig,
|
||||
decl,
|
||||
expr.id,
|
||||
&*body,
|
||||
|
|
@ -168,7 +172,10 @@ fn deduce_unboxed_closure_expectations_from_expected_type<'a,'tcx>(
|
|||
{
|
||||
match expected_ty.sty {
|
||||
ty::ty_trait(ref object_type) => {
|
||||
deduce_unboxed_closure_expectations_from_trait_ref(fcx, &object_type.principal)
|
||||
let trait_ref =
|
||||
object_type.principal_trait_ref_with_self_ty(fcx.tcx(),
|
||||
fcx.tcx().types.err);
|
||||
deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref)
|
||||
}
|
||||
ty::ty_infer(ty::TyVar(vid)) => {
|
||||
deduce_unboxed_closure_expectations_from_obligations(fcx, vid)
|
||||
|
|
@ -227,23 +234,21 @@ fn deduce_unboxed_closure_expectations_from_obligations<'a,'tcx>(
|
|||
{
|
||||
// Here `expected_ty` is known to be a type inference variable.
|
||||
for obligation in fcx.inh.fulfillment_cx.borrow().pending_obligations().iter() {
|
||||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
let trait_ref = trait_predicate.to_poly_trait_ref();
|
||||
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
|
||||
match self_ty.sty {
|
||||
ty::ty_infer(ty::TyVar(v)) if expected_vid == v => { }
|
||||
_ => { continue; }
|
||||
}
|
||||
|
||||
match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &**trait_ref) {
|
||||
match deduce_unboxed_closure_expectations_from_trait_ref(fcx, &trait_ref) {
|
||||
Some(e) => { return Some(e); }
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +295,7 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
|||
(&ty::UniqTraitStore, _) => ast::Once,
|
||||
(&ty::RegionTraitStore(..), _) => ast::Many,
|
||||
};
|
||||
(Some(sig), onceness, cenv.bounds)
|
||||
(Some(sig), onceness, cenv.bounds.clone())
|
||||
}
|
||||
_ => {
|
||||
// Not an error! Means we're inferring the closure type
|
||||
|
|
@ -311,7 +316,7 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
|||
decl,
|
||||
abi::Rust,
|
||||
expected_sig);
|
||||
let fty_sig = fn_ty.sig.clone();
|
||||
let fn_sig = fn_ty.sig.clone();
|
||||
let fty = ty::mk_closure(tcx, fn_ty);
|
||||
debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
|
||||
|
||||
|
|
@ -326,10 +331,13 @@ fn check_boxed_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
|||
ty::UniqTraitStore => (ast::Unsafety::Normal, expr.id)
|
||||
};
|
||||
|
||||
let fn_sig =
|
||||
ty::liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), &fn_sig);
|
||||
|
||||
check_fn(fcx.ccx,
|
||||
inherited_style,
|
||||
inherited_style_id,
|
||||
&fty_sig,
|
||||
&fn_sig,
|
||||
&*decl,
|
||||
expr.id,
|
||||
&*body,
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
use super::probe;
|
||||
|
||||
use check::{mod, FnCtxt, NoPreference, PreferMutLvalue, callee};
|
||||
use middle::subst::{mod, Subst};
|
||||
use check::{mod, FnCtxt, NoPreference, PreferMutLvalue, callee, demand};
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst::{mod};
|
||||
use middle::traits;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{MethodCall, MethodCallee, MethodObject, MethodOrigin,
|
||||
|
|
@ -41,12 +42,6 @@ struct InstantiatedMethodSig<'tcx> {
|
|||
/// the method.
|
||||
all_substs: subst::Substs<'tcx>,
|
||||
|
||||
/// Substitution to use when adding obligations from the method
|
||||
/// bounds. Normally equal to `all_substs` except for object
|
||||
/// receivers. See FIXME in instantiate_method_sig() for
|
||||
/// explanation.
|
||||
method_bounds_substs: subst::Substs<'tcx>,
|
||||
|
||||
/// Generic bounds on the method's parameters which must be added
|
||||
/// as pending obligations.
|
||||
method_bounds: ty::GenericBounds<'tcx>,
|
||||
|
|
@ -102,7 +97,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
|
||||
// Create the final signature for the method, replacing late-bound regions.
|
||||
let InstantiatedMethodSig {
|
||||
method_sig, all_substs, method_bounds_substs, method_bounds
|
||||
method_sig, all_substs, method_bounds
|
||||
} = self.instantiate_method_sig(&pick, all_substs);
|
||||
let method_self_ty = method_sig.inputs[0];
|
||||
|
||||
|
|
@ -110,7 +105,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
self.unify_receivers(self_ty, method_self_ty);
|
||||
|
||||
// Add any trait/regions obligations specified on the method's type parameters.
|
||||
self.add_obligations(&pick, &method_bounds_substs, &method_bounds);
|
||||
self.add_obligations(&pick, &all_substs, &method_bounds);
|
||||
|
||||
// Create the final `MethodCallee`.
|
||||
let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy {
|
||||
|
|
@ -227,14 +222,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
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);
|
||||
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: Rc::new(upcast_trait_ref),
|
||||
trait_ref: upcast_trait_ref,
|
||||
object_trait_id: trait_def_id,
|
||||
method_num: method_num,
|
||||
real_index: real_index,
|
||||
|
|
@ -254,9 +249,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
// parameters from the trait ([$A,$B]), not those from
|
||||
// the impl ([$A,$B,$C]) not the receiver type ([$C]).
|
||||
let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
|
||||
let impl_trait_ref = ty::impl_trait_ref(self.tcx(), impl_def_id)
|
||||
.unwrap()
|
||||
.subst(self.tcx(), &impl_polytype.substs);
|
||||
let impl_trait_ref =
|
||||
self.fcx.instantiate_type_scheme(
|
||||
self.span,
|
||||
&impl_polytype.substs,
|
||||
&ty::impl_trait_ref(self.tcx(), impl_def_id).unwrap());
|
||||
let origin = MethodTypeParam(MethodParam { trait_ref: impl_trait_ref.clone(),
|
||||
method_num: method_num });
|
||||
(impl_trait_ref.substs.clone(), origin)
|
||||
|
|
@ -284,9 +281,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
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 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),
|
||||
let origin = MethodTypeParam(MethodParam { trait_ref: trait_ref,
|
||||
method_num: method_num });
|
||||
(substs, origin)
|
||||
}
|
||||
|
|
@ -342,7 +339,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
} else if num_supplied_types != num_method_types {
|
||||
span_err!(self.tcx().sess, self.span, E0036,
|
||||
"incorrect number of type parameters given for this method");
|
||||
Vec::from_elem(num_method_types, ty::mk_err())
|
||||
Vec::from_elem(num_method_types, self.tcx().types.err)
|
||||
} else {
|
||||
supplied_method_types
|
||||
}
|
||||
|
|
@ -400,52 +397,49 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
// type `Trait`, this leads to an obligation
|
||||
// `Trait:Trait`. Until such time we DST is fully implemented,
|
||||
// that obligation is not necessarily satisfied. (In the
|
||||
// future, it would be.)
|
||||
//
|
||||
// To sidestep this, we overwrite the binding for `Self` with
|
||||
// `err` (just for trait objects) when we generate the
|
||||
// obligations. This causes us to generate the obligation
|
||||
// `err:Trait`, and the error type is considered to implement
|
||||
// all traits, so we're all good. Hack hack hack.
|
||||
let method_bounds_substs = match pick.kind {
|
||||
// future, it would be.) But we know that the true `Self` DOES implement
|
||||
// the trait. So we just delete this requirement. Hack hack hack.
|
||||
let mut method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &all_substs);
|
||||
match pick.kind {
|
||||
probe::ObjectPick(..) => {
|
||||
let mut temp_substs = all_substs.clone();
|
||||
temp_substs.types.get_mut_slice(subst::SelfSpace)[0] = ty::mk_err();
|
||||
temp_substs
|
||||
assert_eq!(method_bounds.predicates.get_slice(subst::SelfSpace).len(), 1);
|
||||
method_bounds.predicates.pop(subst::SelfSpace);
|
||||
}
|
||||
_ => {
|
||||
all_substs.clone()
|
||||
}
|
||||
};
|
||||
let method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &method_bounds_substs);
|
||||
_ => { }
|
||||
}
|
||||
let method_bounds = self.fcx.normalize_associated_types_in(self.span, &method_bounds);
|
||||
|
||||
debug!("method_bounds after subst = {}",
|
||||
method_bounds.repr(self.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 = pick.method_ty.fty.sig.subst(self.tcx(), &all_substs);
|
||||
let method_sig = self.replace_late_bound_regions_with_fresh_var(&method_sig);
|
||||
|
||||
// Instantiate late-bound regions and substitute the trait
|
||||
// parameters into the method type to get the actual method type.
|
||||
//
|
||||
// NB: Instantiate late-bound regions first so that
|
||||
// `instantiate_type_scheme` can normalize associated types that
|
||||
// may reference those regions.
|
||||
let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.method_ty.fty.sig);
|
||||
debug!("late-bound lifetimes from method instantiated, method_sig={}",
|
||||
method_sig.repr(self.tcx()));
|
||||
|
||||
let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig);
|
||||
debug!("type scheme substituted, method_sig={}",
|
||||
method_sig.repr(self.tcx()));
|
||||
|
||||
InstantiatedMethodSig {
|
||||
method_sig: method_sig,
|
||||
all_substs: all_substs,
|
||||
method_bounds_substs: method_bounds_substs,
|
||||
method_bounds: method_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_obligations(&mut self,
|
||||
pick: &probe::Pick<'tcx>,
|
||||
method_bounds_substs: &subst::Substs<'tcx>,
|
||||
all_substs: &subst::Substs<'tcx>,
|
||||
method_bounds: &ty::GenericBounds<'tcx>) {
|
||||
debug!("add_obligations: pick={} method_bounds_substs={} method_bounds={}",
|
||||
debug!("add_obligations: pick={} all_substs={} method_bounds={}",
|
||||
pick.repr(self.tcx()),
|
||||
method_bounds_substs.repr(self.tcx()),
|
||||
all_substs.repr(self.tcx()),
|
||||
method_bounds.repr(self.tcx()));
|
||||
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
|
|
@ -453,7 +447,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
method_bounds);
|
||||
|
||||
self.fcx.add_default_region_param_bounds(
|
||||
method_bounds_substs,
|
||||
all_substs,
|
||||
self.call_expr);
|
||||
}
|
||||
|
||||
|
|
@ -533,7 +527,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
// Don't retry the first one or we might infinite loop!
|
||||
if i != 0 {
|
||||
match expr.node {
|
||||
ast::ExprIndex(ref base_expr, _) => {
|
||||
ast::ExprIndex(ref base_expr, ref index_expr) => {
|
||||
let mut base_adjustment =
|
||||
match self.fcx.inh.adjustments.borrow().get(&base_expr.id) {
|
||||
Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(),
|
||||
|
|
@ -569,7 +563,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
&**base_expr,
|
||||
Some(&ty::AdjustDerefRef(base_adjustment.clone())));
|
||||
|
||||
check::try_index_step(
|
||||
let result = check::try_index_step(
|
||||
self.fcx,
|
||||
MethodCall::expr(expr.id),
|
||||
*expr,
|
||||
|
|
@ -577,6 +571,14 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
adjusted_base_ty,
|
||||
base_adjustment,
|
||||
PreferMutLvalue);
|
||||
|
||||
if let Some((input_ty, return_ty)) = result {
|
||||
let index_expr_ty = self.fcx.expr_ty(&**index_expr);
|
||||
demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty);
|
||||
|
||||
let expr_ty = self.fcx.expr_ty(&**expr);
|
||||
demand::suptype(self.fcx, expr.span, expr_ty, return_ty);
|
||||
}
|
||||
}
|
||||
ast::ExprUnary(ast::UnDeref, ref base_expr) => {
|
||||
// if this is an overloaded deref, then re-evaluate with
|
||||
|
|
@ -626,9 +628,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
}
|
||||
|
||||
fn upcast(&mut self,
|
||||
source_trait_ref: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
source_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
target_trait_def_id: ast::DefId)
|
||||
-> Rc<ty::PolyTraitRef<'tcx>>
|
||||
-> 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 {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ use check::{impl_self_ty};
|
|||
use check::vtable;
|
||||
use check::vtable::select_new_fcx_obligations;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst};
|
||||
use middle::traits;
|
||||
use middle::ty::*;
|
||||
use middle::ty;
|
||||
|
|
@ -156,18 +155,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
};
|
||||
|
||||
let number_assoc_types = trait_def.generics.types.len(subst::AssocSpace);
|
||||
let assoc_types = fcx.inh.infcx.next_ty_vars(number_assoc_types);
|
||||
|
||||
assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0);
|
||||
assert!(trait_def.generics.regions.is_empty());
|
||||
|
||||
// Construct a trait-reference `self_ty : Trait<input_tys>`
|
||||
let substs = subst::Substs::new_trait(input_types, Vec::new(), assoc_types, self_ty);
|
||||
let substs = subst::Substs::new_trait(input_types, Vec::new(), self_ty);
|
||||
let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs)));
|
||||
|
||||
// Construct an obligation
|
||||
let poly_trait_ref = Rc::new(ty::Binder((*trait_ref).clone()));
|
||||
let poly_trait_ref = trait_ref.to_poly_trait_ref();
|
||||
let obligation = traits::Obligation::misc(span,
|
||||
fcx.body_id,
|
||||
poly_trait_ref.as_predicate());
|
||||
|
|
@ -191,18 +187,21 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
|
|||
debug!("lookup_in_trait_adjusted: method_num={} method_ty={}",
|
||||
method_num, method_ty.repr(fcx.tcx()));
|
||||
|
||||
// Substitute the trait parameters into the method type and
|
||||
// instantiate late-bound regions to get the actual method type.
|
||||
let ref bare_fn_ty = method_ty.fty;
|
||||
let fn_sig = bare_fn_ty.sig.subst(tcx, trait_ref.substs);
|
||||
// Instantiate late-bound regions and substitute the trait
|
||||
// parameters into the method type to get the actual method type.
|
||||
//
|
||||
// NB: Instantiate late-bound regions first so that
|
||||
// `instantiate_type_scheme` can normalize associated types that
|
||||
// may reference those regions.
|
||||
let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span,
|
||||
infer::FnCall,
|
||||
&fn_sig).0;
|
||||
&method_ty.fty.sig).0;
|
||||
let fn_sig = fcx.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
|
||||
let transformed_self_ty = fn_sig.inputs[0];
|
||||
let fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(ty::BareFnTy {
|
||||
sig: ty::Binder(fn_sig),
|
||||
unsafety: bare_fn_ty.unsafety,
|
||||
abi: bare_fn_ty.abi.clone(),
|
||||
unsafety: method_ty.fty.unsafety,
|
||||
abi: method_ty.fty.abi.clone(),
|
||||
}));
|
||||
|
||||
debug!("lookup_in_trait_adjusted: matched method fty={} obligation={}",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use middle::fast_reject;
|
|||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use middle::traits;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, Ty, ToPolyTraitRef};
|
||||
use middle::ty_fold::TypeFoldable;
|
||||
use middle::infer;
|
||||
use middle::infer::InferCtxt;
|
||||
|
|
@ -61,7 +61,7 @@ enum CandidateKind<'tcx> {
|
|||
ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::TraitRef<'tcx>>,
|
||||
subst::Substs<'tcx>, MethodIndex),
|
||||
UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
|
||||
WhereClauseCandidate(Rc<ty::PolyTraitRef<'tcx>>, MethodIndex),
|
||||
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, MethodIndex),
|
||||
}
|
||||
|
||||
pub struct Pick<'tcx> {
|
||||
|
|
@ -76,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::PolyTraitRef<'tcx>>, MethodIndex),
|
||||
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, MethodIndex),
|
||||
}
|
||||
|
||||
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
|
||||
|
|
@ -235,7 +235,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
match self_ty.sty {
|
||||
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());
|
||||
self.assemble_inherent_impl_candidates_for_type(data.principal_def_id());
|
||||
}
|
||||
ty::ty_enum(did, _) |
|
||||
ty::ty_struct(did, _) |
|
||||
|
|
@ -308,7 +308,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), 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());
|
||||
|
||||
|
|
@ -330,13 +330,16 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
.iter()
|
||||
.filter_map(|predicate| {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
match trait_ref.self_ty().sty {
|
||||
ty::ty_param(ref p) if *p == param_ty => Some(trait_ref.clone()),
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
match trait_predicate.0.trait_ref.self_ty().sty {
|
||||
ty::ty_param(ref p) if *p == param_ty => {
|
||||
Some(trait_predicate.to_poly_trait_ref())
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
None
|
||||
|
|
@ -381,10 +384,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
// create the candidates.
|
||||
fn elaborate_bounds(
|
||||
&mut self,
|
||||
bounds: &[Rc<ty::PolyTraitRef<'tcx>>],
|
||||
bounds: &[ty::PolyTraitRef<'tcx>],
|
||||
num_includes_types: bool,
|
||||
mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>,
|
||||
tr: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
tr: ty::PolyTraitRef<'tcx>,
|
||||
m: Rc<ty::Method<'tcx>>,
|
||||
method_num: uint|)
|
||||
{
|
||||
|
|
@ -996,7 +999,7 @@ fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
// to a trait and its supertraits.
|
||||
fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
subtrait: Rc<ty::PolyTraitRef<'tcx>>,
|
||||
subtrait: 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
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -768,7 +768,7 @@ fn constrain_cast(rcx: &mut Rcx,
|
|||
}
|
||||
|
||||
/*From:*/ (_,
|
||||
/*To: */ &ty::ty_trait(box ty::TyTrait { bounds, .. })) => {
|
||||
/*To: */ &ty::ty_trait(box ty::TyTrait { ref bounds, .. })) => {
|
||||
// When T is existentially quantified as a trait
|
||||
// `Foo+'to`, it must outlive the region bound `'to`.
|
||||
type_must_outlive(rcx, infer::RelateObjectBound(cast_expr.span),
|
||||
|
|
@ -851,7 +851,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
}
|
||||
|
||||
match function_type.sty {
|
||||
ty::ty_closure(box ty::ClosureTy {bounds, ..}) => {
|
||||
ty::ty_closure(box ty::ClosureTy {ref bounds, ..}) => {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars);
|
||||
})
|
||||
|
|
@ -859,7 +859,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
ty::ty_unboxed_closure(_, region, _) => {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
let bounds = ty::region_existential_bound(*region);
|
||||
ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars);
|
||||
ensure_free_variable_types_outlive_closure_bound(rcx, &bounds, expr, freevars);
|
||||
})
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -870,7 +870,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
|||
/// over values outliving the object's lifetime bound.
|
||||
fn ensure_free_variable_types_outlive_closure_bound(
|
||||
rcx: &mut Rcx,
|
||||
bounds: ty::ExistentialBounds,
|
||||
bounds: &ty::ExistentialBounds,
|
||||
expr: &ast::Expr,
|
||||
freevars: &[ty::Freevar])
|
||||
{
|
||||
|
|
@ -1848,11 +1848,9 @@ fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
|
|||
// well-formed, then, A must be lower-bounded by `'a`, but we
|
||||
// don't know that this holds from first principles.
|
||||
for &(ref r, ref p) in rcx.region_param_pairs.iter() {
|
||||
debug!("param_ty={}/{} p={}/{}",
|
||||
debug!("param_ty={} p={}",
|
||||
param_ty.repr(rcx.tcx()),
|
||||
param_ty.def_id,
|
||||
p.repr(rcx.tcx()),
|
||||
p.def_id);
|
||||
p.repr(rcx.tcx()));
|
||||
if param_ty == *p {
|
||||
param_bounds.push(*r);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,8 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
|||
|
||||
ty::ty_enum(def_id, substs) |
|
||||
ty::ty_struct(def_id, substs) => {
|
||||
self.accumulate_from_adt(ty, def_id, substs)
|
||||
let item_scheme = ty::lookup_item_type(self.tcx, def_id);
|
||||
self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
|
||||
}
|
||||
|
||||
ty::ty_vec(t, _) |
|
||||
|
|
@ -121,6 +122,18 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
|||
self.push_param_constraint_from_top(p);
|
||||
}
|
||||
|
||||
ty::ty_projection(ref data) => {
|
||||
// `<T as TraitRef<..>>::Name`
|
||||
|
||||
// FIXME(#20303) -- gain ability to require that ty_projection : in-scope region,
|
||||
// like a type parameter
|
||||
|
||||
// this seems like a minimal requirement:
|
||||
let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id);
|
||||
self.accumulate_from_adt(ty, data.trait_ref.def_id,
|
||||
&trait_def.generics, data.trait_ref.substs)
|
||||
}
|
||||
|
||||
ty::ty_tup(ref tuptys) => {
|
||||
for &tupty in tuptys.iter() {
|
||||
self.accumulate_from_ty(tupty);
|
||||
|
|
@ -213,14 +226,12 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
|||
fn accumulate_from_adt(&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
def_id: ast::DefId,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
substs: &Substs<'tcx>)
|
||||
{
|
||||
// The generic declarations from the type, appropriately
|
||||
// substituted for the actual substitutions.
|
||||
let generics =
|
||||
ty::lookup_item_type(self.tcx, def_id)
|
||||
.generics
|
||||
.subst(self.tcx, substs);
|
||||
let generics = generics.subst(self.tcx, substs);
|
||||
|
||||
// Variance of each type/region parameter.
|
||||
let variances = ty::item_variances(self.tcx, def_id);
|
||||
|
|
|
|||
|
|
@ -9,16 +9,16 @@
|
|||
// except according to those terms.
|
||||
|
||||
use check::{FnCtxt, structurally_resolved_type};
|
||||
use middle::subst::{FnSpace};
|
||||
use middle::subst::{FnSpace, SelfSpace};
|
||||
use middle::traits;
|
||||
use middle::traits::{Obligation, ObligationCause};
|
||||
use middle::traits::report_fulfillment_errors;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::{mod, Ty, AsPredicate};
|
||||
use middle::infer;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use util::ppaux::{Repr, ty_to_string};
|
||||
use util::nodemap::FnvHashSet;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
cast_expr: &ast::Expr,
|
||||
|
|
@ -133,22 +133,46 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
object_trait: &ty::TyTrait<'tcx>,
|
||||
span: Span)
|
||||
{
|
||||
let object_trait_ref = object_trait.principal_trait_ref_with_self_ty(tcx, ty::mk_err());
|
||||
for tr in traits::supertraits(tcx, object_trait_ref) {
|
||||
check_object_safety_inner(tcx, &*tr, span);
|
||||
// Also check that the type `object_trait` specifies all
|
||||
// associated types for all supertraits.
|
||||
let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> = FnvHashSet::new();
|
||||
|
||||
let object_trait_ref =
|
||||
object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
|
||||
for tr in traits::supertraits(tcx, object_trait_ref.clone()) {
|
||||
check_object_safety_inner(tcx, &tr, span);
|
||||
|
||||
let trait_def = ty::lookup_trait_def(tcx, object_trait_ref.def_id());
|
||||
for &associated_type_name in trait_def.associated_type_names.iter() {
|
||||
associated_types.insert((object_trait_ref.def_id(), associated_type_name));
|
||||
}
|
||||
}
|
||||
|
||||
for projection_bound in object_trait.bounds.projection_bounds.iter() {
|
||||
let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
|
||||
projection_bound.0.projection_ty.item_name);
|
||||
associated_types.remove(&pair);
|
||||
}
|
||||
|
||||
for (trait_def_id, name) in associated_types.into_iter() {
|
||||
tcx.sess.span_err(
|
||||
span,
|
||||
format!("the value of the associated type `{}` (from the trait `{}`) must be specified",
|
||||
name.user_string(tcx),
|
||||
ty::item_path_str(tcx, trait_def_id)).as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
object_trait: &ty::PolyTraitRef<'tcx>,
|
||||
span: Span) {
|
||||
object_trait: &ty::PolyTraitRef<'tcx>,
|
||||
span: Span) {
|
||||
let trait_items = ty::trait_items(tcx, object_trait.def_id());
|
||||
|
||||
let mut errors = Vec::new();
|
||||
for item in trait_items.iter() {
|
||||
match *item {
|
||||
ty::MethodTraitItem(ref m) => {
|
||||
errors.push(check_object_safety_of_method(tcx, &**m))
|
||||
errors.push(check_object_safety_of_method(tcx, object_trait, &**m))
|
||||
}
|
||||
ty::TypeTraitItem(_) => {}
|
||||
}
|
||||
|
|
@ -172,6 +196,7 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
/// type is not known (that's the whole point of a trait instance, after all, to obscure the
|
||||
/// self type) and (b) the call must go through a vtable and hence cannot be monomorphized.
|
||||
fn check_object_safety_of_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
object_trait: &ty::PolyTraitRef<'tcx>,
|
||||
method: &ty::Method<'tcx>)
|
||||
-> Vec<String> {
|
||||
let mut msgs = Vec::new();
|
||||
|
|
@ -195,11 +220,11 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
|
||||
// reason (a) above
|
||||
let check_for_self_ty = |ty| {
|
||||
if ty::type_has_self(ty) {
|
||||
if contains_illegal_self_type_reference(tcx, object_trait.def_id(), ty) {
|
||||
Some(format!(
|
||||
"cannot call a method (`{}`) whose type contains \
|
||||
a self-type (`{}`) through a trait object",
|
||||
method_name, ty_to_string(tcx, ty)))
|
||||
method_name, ty.user_string(tcx)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -224,13 +249,105 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
|
||||
msgs
|
||||
}
|
||||
|
||||
fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
trait_def_id: ast::DefId,
|
||||
ty: Ty<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
// This is somewhat subtle. In general, we want to forbid
|
||||
// references to `Self` in the argument and return types,
|
||||
// since the value of `Self` is erased. However, there is one
|
||||
// exception: it is ok to reference `Self` in order to access
|
||||
// an associated type of the current trait, since we retain
|
||||
// the value of those associated types in the object type
|
||||
// itself.
|
||||
//
|
||||
// ```rust
|
||||
// trait SuperTrait {
|
||||
// type X;
|
||||
// }
|
||||
//
|
||||
// trait Trait : SuperTrait {
|
||||
// type Y;
|
||||
// fn foo(&self, x: Self) // bad
|
||||
// fn foo(&self) -> Self // bad
|
||||
// fn foo(&self) -> Option<Self> // bad
|
||||
// fn foo(&self) -> Self::Y // OK, desugars to next example
|
||||
// fn foo(&self) -> <Self as Trait>::Y // OK
|
||||
// fn foo(&self) -> Self::X // OK, desugars to next example
|
||||
// fn foo(&self) -> <Self as SuperTrait>::X // OK
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// However, it is not as simple as allowing `Self` in a projected
|
||||
// type, because there are illegal ways to use `Self` as well:
|
||||
//
|
||||
// ```rust
|
||||
// trait Trait : SuperTrait {
|
||||
// ...
|
||||
// fn foo(&self) -> <Self as SomeOtherTrait>::X;
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Here we will not have the type of `X` recorded in the
|
||||
// object type, and we cannot resolve `Self as SomeOtherTrait`
|
||||
// without knowing what `Self` is.
|
||||
|
||||
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
|
||||
let mut error = false;
|
||||
ty::maybe_walk_ty(ty, |ty| {
|
||||
match ty.sty {
|
||||
ty::ty_param(ref param_ty) => {
|
||||
if param_ty.space == SelfSpace {
|
||||
error = true;
|
||||
}
|
||||
|
||||
false // no contained types to walk
|
||||
}
|
||||
|
||||
ty::ty_projection(ref data) => {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
|
||||
// Compute supertraits of current trait lazilly.
|
||||
if supertraits.is_none() {
|
||||
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
|
||||
let trait_ref = ty::Binder(trait_def.trait_ref.clone());
|
||||
supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
|
||||
}
|
||||
|
||||
// Determine whether the trait reference `Foo as
|
||||
// SomeTrait` is in fact a supertrait of the
|
||||
// current trait. In that case, this type is
|
||||
// legal, because the type `X` will be specified
|
||||
// in the object type. Note that we can just use
|
||||
// direct equality here because all of these types
|
||||
// are part of the formal parameter listing, and
|
||||
// hence there should be no inference variables.
|
||||
let projection_trait_ref = ty::Binder(data.trait_ref.clone());
|
||||
let is_supertrait_of_current_trait =
|
||||
supertraits.as_ref().unwrap().contains(&projection_trait_ref);
|
||||
|
||||
if is_supertrait_of_current_trait {
|
||||
false // do not walk contained types, do not report error, do collect $200
|
||||
} else {
|
||||
true // DO walk contained types, POSSIBLY reporting an error
|
||||
}
|
||||
}
|
||||
|
||||
_ => true, // walk contained types, if any
|
||||
}
|
||||
});
|
||||
|
||||
error
|
||||
}
|
||||
}
|
||||
|
||||
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::PolyTraitRef<'tcx>>
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
// We can only make objects from sized types.
|
||||
fcx.register_builtin_bound(
|
||||
|
|
@ -243,21 +360,21 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
let object_trait_ty =
|
||||
ty::mk_trait(fcx.tcx(),
|
||||
object_trait.principal.clone(),
|
||||
object_trait.bounds);
|
||||
object_trait.bounds.clone());
|
||||
|
||||
debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
|
||||
referent_ty.repr(fcx.tcx()),
|
||||
object_trait_ty.repr(fcx.tcx()));
|
||||
|
||||
let cause = ObligationCause::new(span,
|
||||
fcx.body_id,
|
||||
traits::ObjectCastObligation(object_trait_ty));
|
||||
|
||||
// Create the obligation for casting from T to Trait.
|
||||
let object_trait_ref =
|
||||
object_trait.principal_trait_ref_with_self_ty(fcx.tcx(), referent_ty);
|
||||
let object_obligation =
|
||||
Obligation::new(
|
||||
ObligationCause::new(span,
|
||||
fcx.body_id,
|
||||
traits::ObjectCastObligation(object_trait_ty)),
|
||||
ty::Predicate::Trait(object_trait_ref.clone()));
|
||||
Obligation::new(cause.clone(), object_trait_ref.as_predicate());
|
||||
fcx.register_predicate(object_obligation);
|
||||
|
||||
// Create additional obligations for all the various builtin
|
||||
|
|
@ -268,7 +385,16 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
fcx.register_builtin_bound(
|
||||
referent_ty,
|
||||
builtin_bound,
|
||||
ObligationCause::new(span, fcx.body_id, traits::ObjectCastObligation(object_trait_ty)));
|
||||
cause.clone());
|
||||
}
|
||||
|
||||
// Finally, create obligations for the projection predicates.
|
||||
let projection_bounds =
|
||||
object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty);
|
||||
for projection_bound in projection_bounds.iter() {
|
||||
let projection_obligation =
|
||||
Obligation::new(cause.clone(), projection_bound.as_predicate());
|
||||
fcx.register_predicate(projection_obligation);
|
||||
}
|
||||
|
||||
object_trait_ref
|
||||
|
|
@ -313,3 +439,4 @@ pub fn select_new_fcx_obligations(fcx: &FnCtxt) {
|
|||
Err(errors) => { report_fulfillment_errors(fcx.infcx(), &errors); }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck};
|
|||
use CrateCtxt;
|
||||
use middle::region;
|
||||
use middle::subst;
|
||||
use middle::subst::{Subst};
|
||||
use middle::traits;
|
||||
use middle::ty::{mod, Ty};
|
||||
use middle::ty::liberate_late_bound_regions;
|
||||
|
|
@ -147,8 +146,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
item.span,
|
||||
region::CodeExtent::from_node_id(item.id),
|
||||
Some(&mut this.cache));
|
||||
let polytype = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
|
||||
let item_ty = polytype.ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
|
||||
let item_ty = fcx.instantiate_type_scheme(item.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&type_scheme.ty);
|
||||
bounds_checker.check_traits_in_ty(item_ty);
|
||||
});
|
||||
}
|
||||
|
|
@ -168,7 +169,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
// that is, with all type parameters converted from bound
|
||||
// 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 = fcx.instantiate_type_scheme(item.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&self_ty);
|
||||
|
||||
bounds_checker.check_traits_in_ty(self_ty);
|
||||
|
||||
|
|
@ -178,7 +181,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
None => { return; }
|
||||
Some(t) => { t }
|
||||
};
|
||||
let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
let trait_ref = fcx.instantiate_type_scheme(item.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&trait_ref);
|
||||
|
||||
// There are special rules that apply to drop.
|
||||
if
|
||||
|
|
@ -209,7 +214,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
|
|||
// trait reference. Instead, this is done at the impl site.
|
||||
// Arguably this is wrong and we should treat the trait-reference
|
||||
// the same way as we treat the self-type.
|
||||
bounds_checker.check_trait_ref(&trait_ref);
|
||||
bounds_checker.check_trait_ref(&*trait_ref);
|
||||
|
||||
let cause =
|
||||
traits::ObligationCause::new(
|
||||
|
|
@ -313,14 +318,14 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
|||
match t.sty{
|
||||
ty::ty_struct(type_id, substs) |
|
||||
ty::ty_enum(type_id, substs) => {
|
||||
let polytype = ty::lookup_item_type(self.fcx.tcx(), type_id);
|
||||
let type_scheme = ty::lookup_item_type(self.fcx.tcx(), type_id);
|
||||
|
||||
if self.binding_count == 0 {
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(self.span,
|
||||
self.fcx.body_id,
|
||||
traits::ItemObligation(type_id)),
|
||||
&polytype.generics.to_bounds(self.tcx(), substs));
|
||||
&type_scheme.generics.to_bounds(self.tcx(), substs));
|
||||
} else {
|
||||
// There are two circumstances in which we ignore
|
||||
// region obligations.
|
||||
|
|
@ -344,7 +349,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
|
|||
//
|
||||
// (I believe we should do the same for traits, but
|
||||
// that will require an RFC. -nmatsakis)
|
||||
let bounds = polytype.generics.to_bounds(self.tcx(), substs);
|
||||
let bounds = type_scheme.generics.to_bounds(self.tcx(), substs);
|
||||
let bounds = filter_to_trait_obligations(bounds);
|
||||
self.fcx.add_obligations_for_parameters(
|
||||
traits::ObligationCause::new(self.span,
|
||||
|
|
@ -397,7 +402,9 @@ fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
.iter()
|
||||
.map(|field| {
|
||||
let field_ty = ty::node_id_to_type(fcx.tcx(), field.node.id);
|
||||
let field_ty = field_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
let field_ty = fcx.instantiate_type_scheme(field.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&field_ty);
|
||||
AdtField { ty: field_ty, span: field.span }
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -416,7 +423,10 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
AdtVariant {
|
||||
fields: args.iter().enumerate().map(|(index, arg)| {
|
||||
let arg_ty = arg_tys[index];
|
||||
let arg_ty = arg_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
|
||||
let arg_ty =
|
||||
fcx.instantiate_type_scheme(variant.span,
|
||||
&fcx.inh.param_env.free_substs,
|
||||
&arg_ty);
|
||||
AdtField {
|
||||
ty: arg_ty,
|
||||
span: arg.ty.span
|
||||
|
|
@ -443,7 +453,8 @@ fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>)
|
|||
let mut result = ty::GenericBounds::empty();
|
||||
for (space, _, predicate) in bounds.predicates.iter_enumerated() {
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(..) => {
|
||||
ty::Predicate::Trait(..) |
|
||||
ty::Predicate::Projection(..) => {
|
||||
result.predicates.push(space, predicate.clone())
|
||||
}
|
||||
ty::Predicate::Equate(..) |
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
|
|||
match t.node {
|
||||
ast::TyFixedLengthVec(ref ty, ref count_expr) => {
|
||||
self.visit_ty(&**ty);
|
||||
write_ty_to_tcx(self.tcx(), count_expr.id, ty::mk_uint());
|
||||
write_ty_to_tcx(self.tcx(), count_expr.id, self.tcx().types.uint);
|
||||
}
|
||||
_ => visit::walk_ty(self, t)
|
||||
}
|
||||
|
|
@ -441,7 +441,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
|
|||
debug!("Resolver::fold_ty: input type `{}` not fully resolvable",
|
||||
t.repr(self.tcx));
|
||||
self.report_error(e);
|
||||
ty::mk_err()
|
||||
self.tcx().types.err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,10 +23,11 @@ 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};
|
||||
use middle::ty::{ty_param, Polytype, ty_ptr};
|
||||
use middle::ty::{ty_param, TypeScheme, 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::{ty_projection};
|
||||
use middle::ty;
|
||||
use CrateCtxt;
|
||||
use middle::infer::combine::Combine;
|
||||
|
|
@ -64,13 +65,13 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
|
|||
}
|
||||
|
||||
ty_trait(ref t) => {
|
||||
Some(t.principal.def_id())
|
||||
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_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
|
||||
ty_ptr(_) | ty_rptr(_, _) => {
|
||||
ty_ptr(_) | ty_rptr(_, _) | ty_projection(..) => {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +207,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
debug!("instantiate_default_methods(impl_id={}, trait_ref={})",
|
||||
impl_id, trait_ref.repr(tcx));
|
||||
|
||||
let impl_poly_type = ty::lookup_item_type(tcx, impl_id);
|
||||
let impl_type_scheme = ty::lookup_item_type(tcx, impl_id);
|
||||
|
||||
let prov = ty::provided_trait_methods(tcx, trait_ref.def_id);
|
||||
for trait_method in prov.iter() {
|
||||
|
|
@ -221,7 +222,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
Rc::new(subst_receiver_types_in_method_ty(
|
||||
tcx,
|
||||
impl_id,
|
||||
&impl_poly_type,
|
||||
&impl_type_scheme,
|
||||
trait_ref,
|
||||
new_did,
|
||||
&**trait_method,
|
||||
|
|
@ -233,7 +234,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
// construct the polytype for the method based on the
|
||||
// method_ty. it will have all the generics from the
|
||||
// impl, plus its own.
|
||||
let new_polytype = ty::Polytype {
|
||||
let new_polytype = ty::TypeScheme {
|
||||
generics: new_method_ty.generics.clone(),
|
||||
ty: ty::mk_bare_fn(tcx, Some(new_did),
|
||||
tcx.mk_bare_fn(new_method_ty.fty.clone()))
|
||||
|
|
@ -275,7 +276,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn get_self_type_for_implementation(&self, impl_did: DefId)
|
||||
-> Polytype<'tcx> {
|
||||
-> TypeScheme<'tcx> {
|
||||
self.crate_context.tcx.tcache.borrow()[impl_did].clone()
|
||||
}
|
||||
|
||||
|
|
@ -535,7 +536,7 @@ fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id:
|
|||
|
||||
fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
impl_id: ast::DefId,
|
||||
impl_poly_type: &ty::Polytype<'tcx>,
|
||||
impl_type_scheme: &ty::TypeScheme<'tcx>,
|
||||
trait_ref: &ty::TraitRef<'tcx>,
|
||||
new_def_id: ast::DefId,
|
||||
method: &ty::Method<'tcx>,
|
||||
|
|
@ -554,10 +555,10 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
for &space in [subst::TypeSpace, subst::SelfSpace].iter() {
|
||||
method_generics.types.replace(
|
||||
space,
|
||||
impl_poly_type.generics.types.get_slice(space).to_vec());
|
||||
impl_type_scheme.generics.types.get_slice(space).to_vec());
|
||||
method_generics.regions.replace(
|
||||
space,
|
||||
impl_poly_type.generics.regions.get_slice(space).to_vec());
|
||||
impl_type_scheme.generics.regions.get_slice(space).to_vec());
|
||||
}
|
||||
|
||||
debug!("subst_receiver_types_in_method_ty: method_generics={}",
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
|
|||
ty::ty_struct(def_id, _) => {
|
||||
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());
|
||||
ty::ty_trait(ref data) => {
|
||||
self.check_def_id(item.span, data.principal_def_id());
|
||||
}
|
||||
_ => {
|
||||
span_err!(self.tcx.sess, item.span, E0118,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -159,8 +159,8 @@ fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId)
|
|||
lookup_def_tcx(ccx.tcx, sp, id)
|
||||
}
|
||||
|
||||
fn no_params<'tcx>(t: Ty<'tcx>) -> ty::Polytype<'tcx> {
|
||||
ty::Polytype {
|
||||
fn no_params<'tcx>(t: Ty<'tcx>) -> ty::TypeScheme<'tcx> {
|
||||
ty::TypeScheme {
|
||||
generics: ty::Generics {
|
||||
types: VecPerParamSpace::empty(),
|
||||
regions: VecPerParamSpace::empty(),
|
||||
|
|
@ -278,11 +278,11 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
|
|||
abi: abi::Rust,
|
||||
sig: ty::Binder(ty::FnSig {
|
||||
inputs: vec!(
|
||||
ty::mk_int(),
|
||||
ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8()))
|
||||
tcx.types.int,
|
||||
ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, tcx.types.u8))
|
||||
),
|
||||
output: ty::FnConverging(ty::mk_int()),
|
||||
variadic: false
|
||||
output: ty::FnConverging(tcx.types.int),
|
||||
variadic: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -479,8 +479,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
|
|||
let did = ast_util::local_def(item.id);
|
||||
let tcx = self.terms_cx.tcx;
|
||||
|
||||
debug!("visit_item item={}",
|
||||
item.repr(tcx));
|
||||
|
||||
match item.node {
|
||||
ast::ItemEnum(ref enum_definition, _) => {
|
||||
let generics = &ty::lookup_item_type(tcx, did).generics;
|
||||
|
||||
// Hack: If we directly call `ty::enum_variants`, it
|
||||
// annoyingly takes it upon itself to run off and
|
||||
// evaluate the discriminants eagerly (*grumpy* that's
|
||||
|
|
@ -497,17 +502,18 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
|
|||
&**ast_variant,
|
||||
/*discriminant*/ 0);
|
||||
for arg_ty in variant.args.iter() {
|
||||
self.add_constraints_from_ty(*arg_ty, self.covariant);
|
||||
self.add_constraints_from_ty(generics, *arg_ty, self.covariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast::ItemStruct(..) => {
|
||||
let generics = &ty::lookup_item_type(tcx, did).generics;
|
||||
let struct_fields = ty::lookup_struct_fields(tcx, did);
|
||||
for field_info in struct_fields.iter() {
|
||||
assert_eq!(field_info.id.krate, ast::LOCAL_CRATE);
|
||||
let field_ty = ty::node_id_to_type(tcx, field_info.id.node);
|
||||
self.add_constraints_from_ty(field_ty, self.covariant);
|
||||
self.add_constraints_from_ty(generics, field_ty, self.covariant);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -516,7 +522,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
|
|||
for trait_item in trait_items.iter() {
|
||||
match *trait_item {
|
||||
ty::MethodTraitItem(ref method) => {
|
||||
self.add_constraints_from_sig(&method.fty.sig,
|
||||
self.add_constraints_from_sig(&method.generics,
|
||||
&method.fty.sig,
|
||||
self.covariant);
|
||||
}
|
||||
ty::TypeTraitItem(_) => {}
|
||||
|
|
@ -713,8 +720,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Adds constraints appropriate for an instance of `ty` appearing
|
||||
/// in a context with ambient variance `variance`
|
||||
/// in a context with the generics defined in `generics` and
|
||||
/// ambient variance `variance`
|
||||
fn add_constraints_from_ty(&mut self,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
variance: VarianceTermPtr<'a>) {
|
||||
debug!("add_constraints_from_ty(ty={})", ty.repr(self.tcx()));
|
||||
|
|
@ -732,75 +741,82 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
|
||||
ty::ty_rptr(region, ref mt) => {
|
||||
let contra = self.contravariant(variance);
|
||||
self.add_constraints_from_region(*region, contra);
|
||||
self.add_constraints_from_mt(mt, variance);
|
||||
self.add_constraints_from_region(generics, *region, contra);
|
||||
self.add_constraints_from_mt(generics, mt, variance);
|
||||
}
|
||||
|
||||
ty::ty_uniq(typ) | ty::ty_vec(typ, _) | ty::ty_open(typ) => {
|
||||
self.add_constraints_from_ty(typ, variance);
|
||||
self.add_constraints_from_ty(generics, typ, variance);
|
||||
}
|
||||
|
||||
ty::ty_ptr(ref mt) => {
|
||||
self.add_constraints_from_mt(mt, variance);
|
||||
self.add_constraints_from_mt(generics, mt, variance);
|
||||
}
|
||||
|
||||
ty::ty_tup(ref subtys) => {
|
||||
for &subty in subtys.iter() {
|
||||
self.add_constraints_from_ty(subty, variance);
|
||||
self.add_constraints_from_ty(generics, subty, variance);
|
||||
}
|
||||
}
|
||||
|
||||
ty::ty_enum(def_id, substs) |
|
||||
ty::ty_struct(def_id, substs) => {
|
||||
let item_type = ty::lookup_item_type(self.tcx(), def_id);
|
||||
let generics = &item_type.generics;
|
||||
|
||||
// All type parameters on enums and structs should be
|
||||
// in the TypeSpace.
|
||||
assert!(generics.types.is_empty_in(subst::SelfSpace));
|
||||
assert!(generics.types.is_empty_in(subst::FnSpace));
|
||||
assert!(generics.regions.is_empty_in(subst::SelfSpace));
|
||||
assert!(generics.regions.is_empty_in(subst::FnSpace));
|
||||
assert!(item_type.generics.types.is_empty_in(subst::SelfSpace));
|
||||
assert!(item_type.generics.types.is_empty_in(subst::FnSpace));
|
||||
assert!(item_type.generics.regions.is_empty_in(subst::SelfSpace));
|
||||
assert!(item_type.generics.regions.is_empty_in(subst::FnSpace));
|
||||
|
||||
self.add_constraints_from_substs(
|
||||
generics,
|
||||
def_id,
|
||||
generics.types.get_slice(subst::TypeSpace),
|
||||
generics.regions.get_slice(subst::TypeSpace),
|
||||
item_type.generics.types.get_slice(subst::TypeSpace),
|
||||
item_type.generics.regions.get_slice(subst::TypeSpace),
|
||||
substs,
|
||||
variance);
|
||||
}
|
||||
|
||||
ty::ty_trait(box ty::TyTrait { ref principal, bounds }) => {
|
||||
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));
|
||||
|
||||
// Traits never declare region parameters in the self
|
||||
// space.
|
||||
assert!(generics.regions.is_empty_in(subst::SelfSpace));
|
||||
|
||||
// Traits never declare type/region parameters in the
|
||||
// fn space.
|
||||
assert!(generics.types.is_empty_in(subst::FnSpace));
|
||||
assert!(generics.regions.is_empty_in(subst::FnSpace));
|
||||
|
||||
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
|
||||
let contra = self.contravariant(variance);
|
||||
self.add_constraints_from_region(bounds.region_bound, contra);
|
||||
|
||||
ty::ty_projection(ref data) => {
|
||||
let trait_ref = &data.trait_ref;
|
||||
let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id);
|
||||
self.add_constraints_from_substs(
|
||||
principal.def_id(),
|
||||
generics.types.get_slice(subst::TypeSpace),
|
||||
generics.regions.get_slice(subst::TypeSpace),
|
||||
principal.substs(),
|
||||
generics,
|
||||
trait_ref.def_id,
|
||||
trait_def.generics.types.as_slice(),
|
||||
trait_def.generics.regions.as_slice(),
|
||||
trait_ref.substs,
|
||||
variance);
|
||||
}
|
||||
|
||||
ty::ty_param(ty::ParamTy { ref def_id, .. }) => {
|
||||
ty::ty_trait(ref data) => {
|
||||
let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(),
|
||||
self.tcx().types.err);
|
||||
let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id());
|
||||
|
||||
// Traits never declare region parameters in the self
|
||||
// space nor anything in the fn space.
|
||||
assert!(trait_def.generics.regions.is_empty_in(subst::SelfSpace));
|
||||
assert!(trait_def.generics.types.is_empty_in(subst::FnSpace));
|
||||
assert!(trait_def.generics.regions.is_empty_in(subst::FnSpace));
|
||||
|
||||
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
|
||||
let contra = self.contravariant(variance);
|
||||
self.add_constraints_from_region(generics, data.bounds.region_bound, contra);
|
||||
|
||||
self.add_constraints_from_substs(
|
||||
generics,
|
||||
trait_ref.def_id(),
|
||||
trait_def.generics.types.get_slice(subst::TypeSpace),
|
||||
trait_def.generics.regions.get_slice(subst::TypeSpace),
|
||||
trait_ref.substs(),
|
||||
variance);
|
||||
}
|
||||
|
||||
ty::ty_param(ref data) => {
|
||||
let def_id = generics.types.get(data.space, data.idx as uint).def_id;
|
||||
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
|
||||
match self.terms_cx.inferred_map.get(&def_id.node) {
|
||||
Some(&index) => {
|
||||
|
|
@ -821,14 +837,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
..
|
||||
}) =>
|
||||
{
|
||||
self.add_constraints_from_sig(sig, variance);
|
||||
self.add_constraints_from_sig(generics, sig, variance);
|
||||
}
|
||||
|
||||
ty::ty_closure(box ty::ClosureTy { ref sig,
|
||||
store: ty::RegionTraitStore(region, _), .. }) => {
|
||||
let contra = self.contravariant(variance);
|
||||
self.add_constraints_from_region(region, contra);
|
||||
self.add_constraints_from_sig(sig, variance);
|
||||
self.add_constraints_from_region(generics, region, contra);
|
||||
self.add_constraints_from_sig(generics, sig, variance);
|
||||
}
|
||||
|
||||
ty::ty_infer(..) | ty::ty_err => {
|
||||
|
|
@ -844,6 +860,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
/// Adds constraints appropriate for a nominal type (enum, struct,
|
||||
/// object, etc) appearing in a context with ambient variance `variance`
|
||||
fn add_constraints_from_substs(&mut self,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
def_id: ast::DefId,
|
||||
type_param_defs: &[ty::TypeParameterDef<'tcx>],
|
||||
region_param_defs: &[ty::RegionParameterDef],
|
||||
|
|
@ -857,7 +874,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
p.space, p.index as uint);
|
||||
let variance_i = self.xform(variance, variance_decl);
|
||||
let substs_ty = *substs.types.get(p.space, p.index as uint);
|
||||
self.add_constraints_from_ty(substs_ty, variance_i);
|
||||
self.add_constraints_from_ty(generics, substs_ty, variance_i);
|
||||
}
|
||||
|
||||
for p in region_param_defs.iter() {
|
||||
|
|
@ -866,27 +883,29 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
RegionParam, p.space, p.index as uint);
|
||||
let variance_i = self.xform(variance, variance_decl);
|
||||
let substs_r = *substs.regions().get(p.space, p.index as uint);
|
||||
self.add_constraints_from_region(substs_r, variance_i);
|
||||
self.add_constraints_from_region(generics, substs_r, variance_i);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds constraints appropriate for a function with signature
|
||||
/// `sig` appearing in a context with ambient variance `variance`
|
||||
fn add_constraints_from_sig(&mut self,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
sig: &ty::PolyFnSig<'tcx>,
|
||||
variance: VarianceTermPtr<'a>) {
|
||||
let contra = self.contravariant(variance);
|
||||
for &input in sig.0.inputs.iter() {
|
||||
self.add_constraints_from_ty(input, contra);
|
||||
self.add_constraints_from_ty(generics, input, contra);
|
||||
}
|
||||
if let ty::FnConverging(result_type) = sig.0.output {
|
||||
self.add_constraints_from_ty(result_type, variance);
|
||||
self.add_constraints_from_ty(generics, result_type, variance);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds constraints appropriate for a region appearing in a
|
||||
/// context with ambient variance `variance`
|
||||
fn add_constraints_from_region(&mut self,
|
||||
_generics: &ty::Generics<'tcx>,
|
||||
region: ty::Region,
|
||||
variance: VarianceTermPtr<'a>) {
|
||||
match region {
|
||||
|
|
@ -920,16 +939,17 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
/// Adds constraints appropriate for a mutability-type pair
|
||||
/// appearing in a context with ambient variance `variance`
|
||||
fn add_constraints_from_mt(&mut self,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
mt: &ty::mt<'tcx>,
|
||||
variance: VarianceTermPtr<'a>) {
|
||||
match mt.mutbl {
|
||||
ast::MutMutable => {
|
||||
let invar = self.invariant(variance);
|
||||
self.add_constraints_from_ty(mt.ty, invar);
|
||||
self.add_constraints_from_ty(generics, mt.ty, invar);
|
||||
}
|
||||
|
||||
ast::MutImmutable => {
|
||||
self.add_constraints_from_ty(mt.ty, variance);
|
||||
self.add_constraints_from_ty(generics, mt.ty, variance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@ use syntax::ast_util::PostExpansionMethod;
|
|||
use syntax::attr;
|
||||
use syntax::attr::{AttributeMethods, AttrMetaMethods};
|
||||
use syntax::codemap::{DUMMY_SP, Pos, Spanned};
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::parse::token;
|
||||
use syntax::parse::token::{mod, InternedString, special_idents};
|
||||
use syntax::ptr::P;
|
||||
|
||||
use rustc_trans::back::link;
|
||||
|
|
@ -500,13 +499,16 @@ impl Clean<TyParamBound> for ast::TyParamBound {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clean<Vec<TyParamBound>> for ty::ExistentialBounds {
|
||||
impl<'tcx> Clean<Vec<TyParamBound>> for ty::ExistentialBounds<'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
|
||||
let mut vec = vec![];
|
||||
self.region_bound.clean(cx).map(|b| vec.push(RegionBound(b)));
|
||||
for bb in self.builtin_bounds.iter() {
|
||||
vec.push(bb.clean(cx));
|
||||
}
|
||||
|
||||
// FIXME(#20299) -- should do something with projection bounds
|
||||
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
|
@ -1199,11 +1201,9 @@ pub enum Type {
|
|||
},
|
||||
// I have no idea how to usefully use this.
|
||||
TyParamBinder(ast::NodeId),
|
||||
/// For parameterized types, so the consumer of the JSON don't go looking
|
||||
/// for types which don't exist anywhere.
|
||||
Generic(ast::DefId),
|
||||
/// For references to self
|
||||
Self(ast::DefId),
|
||||
/// For parameterized types, so the consumer of the JSON don't go
|
||||
/// looking for types which don't exist anywhere.
|
||||
Generic(String),
|
||||
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
|
||||
Primitive(PrimitiveType),
|
||||
Closure(Box<ClosureDecl>),
|
||||
|
|
@ -1441,18 +1441,11 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
|
|||
}
|
||||
}
|
||||
ty::ty_struct(did, substs) |
|
||||
ty::ty_enum(did, substs) |
|
||||
ty::ty_trait(box ty::TyTrait {
|
||||
principal: ty::Binder(ty::TraitRef { def_id: did, substs }),
|
||||
.. }) =>
|
||||
{
|
||||
ty::ty_enum(did, substs) => {
|
||||
let fqn = csearch::get_item_path(cx.tcx(), did);
|
||||
let fqn: Vec<String> = fqn.into_iter().map(|i| {
|
||||
i.to_string()
|
||||
}).collect();
|
||||
let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
|
||||
let kind = match self.sty {
|
||||
ty::ty_struct(..) => TypeStruct,
|
||||
ty::ty_trait(..) => TypeTrait,
|
||||
_ => TypeEnum,
|
||||
};
|
||||
let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
|
||||
|
|
@ -1464,15 +1457,34 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
|
|||
did: did,
|
||||
}
|
||||
}
|
||||
ty::ty_tup(ref t) => Tuple(t.clean(cx)),
|
||||
|
||||
ty::ty_param(ref p) => {
|
||||
if p.space == subst::SelfSpace {
|
||||
Self(p.def_id)
|
||||
} else {
|
||||
Generic(p.def_id)
|
||||
ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
|
||||
let did = principal.def_id();
|
||||
let fqn = csearch::get_item_path(cx.tcx(), did);
|
||||
let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
|
||||
let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
|
||||
Some(did), principal.substs());
|
||||
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
|
||||
ResolvedPath {
|
||||
path: path,
|
||||
typarams: Some(bounds.clean(cx)),
|
||||
did: did,
|
||||
}
|
||||
}
|
||||
ty::ty_tup(ref t) => Tuple(t.clean(cx)),
|
||||
|
||||
ty::ty_projection(ref data) => {
|
||||
let trait_ref = match data.trait_ref.clean(cx) {
|
||||
TyParamBound::TraitBound(t, _) => t.trait_,
|
||||
TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
|
||||
};
|
||||
Type::QPath {
|
||||
name: data.item_name.clean(cx),
|
||||
self_type: box data.trait_ref.self_ty().clean(cx),
|
||||
trait_: box trait_ref,
|
||||
}
|
||||
}
|
||||
|
||||
ty::ty_param(ref p) => Generic(token::get_name(p.name).to_string()),
|
||||
|
||||
ty::ty_unboxed_closure(..) => Tuple(vec![]), // FIXME(pcwalton)
|
||||
|
||||
|
|
@ -2257,7 +2269,9 @@ fn resolve_type(cx: &DocContext,
|
|||
};
|
||||
|
||||
match def {
|
||||
def::DefSelfTy(i) => return Self(ast_util::local_def(i)),
|
||||
def::DefSelfTy(..) => {
|
||||
return Generic(token::get_name(special_idents::type_self.name).to_string());
|
||||
}
|
||||
def::DefPrimTy(p) => match p {
|
||||
ast::TyStr => return Primitive(Str),
|
||||
ast::TyBool => return Primitive(Bool),
|
||||
|
|
@ -2275,7 +2289,7 @@ fn resolve_type(cx: &DocContext,
|
|||
ast::TyFloat(ast::TyF32) => return Primitive(F32),
|
||||
ast::TyFloat(ast::TyF64) => return Primitive(F64),
|
||||
},
|
||||
def::DefTyParam(_, i, _) => return Generic(i),
|
||||
def::DefTyParam(_, _, _, n) => return Generic(token::get_name(n).to_string()),
|
||||
def::DefTyParamBinder(i) => return TyParamBinder(i),
|
||||
_ => {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -435,15 +435,14 @@ impl fmt::Show for clean::Type {
|
|||
clean::TyParamBinder(id) => {
|
||||
f.write(cache().typarams[ast_util::local_def(id)].as_bytes())
|
||||
}
|
||||
clean::Generic(did) => {
|
||||
f.write(cache().typarams[did].as_bytes())
|
||||
clean::Generic(ref name) => {
|
||||
f.write(name.as_bytes())
|
||||
}
|
||||
clean::ResolvedPath{ did, ref typarams, ref path } => {
|
||||
try!(resolved_path(f, did, path, false));
|
||||
tybounds(f, typarams)
|
||||
}
|
||||
clean::Infer => write!(f, "_"),
|
||||
clean::Self(..) => f.write("Self".as_bytes()),
|
||||
clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()),
|
||||
clean::Closure(ref decl) => {
|
||||
write!(f, "{style}{lifetimes}|{args}|{bounds}{arrow}",
|
||||
|
|
|
|||
|
|
@ -764,7 +764,7 @@ pub enum Expr_ {
|
|||
pub struct QPath {
|
||||
pub self_type: P<Ty>,
|
||||
pub trait_ref: P<TraitRef>,
|
||||
pub item_name: Ident,
|
||||
pub item_name: Ident, // FIXME(#20301) -- should use Name
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show, Copy)]
|
||||
|
|
|
|||
|
|
@ -133,6 +133,9 @@ pub trait Visitor<'v> {
|
|||
fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) {
|
||||
walk_path_parameters(self, path_span, path_parameters)
|
||||
}
|
||||
fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) {
|
||||
walk_assoc_type_binding(self, type_binding)
|
||||
}
|
||||
fn visit_attribute(&mut self, _attr: &'v Attribute) {}
|
||||
}
|
||||
|
||||
|
|
@ -467,6 +470,9 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
|
|||
for lifetime in data.lifetimes.iter() {
|
||||
visitor.visit_lifetime_ref(lifetime);
|
||||
}
|
||||
for binding in data.bindings.iter() {
|
||||
visitor.visit_assoc_type_binding(&**binding);
|
||||
}
|
||||
}
|
||||
ast::ParenthesizedParameters(ref data) => {
|
||||
for typ in data.inputs.iter() {
|
||||
|
|
@ -479,6 +485,12 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
|
||||
type_binding: &'v TypeBinding) {
|
||||
visitor.visit_ident(type_binding.span, type_binding.ident);
|
||||
visitor.visit_ty(&*type_binding.ty);
|
||||
}
|
||||
|
||||
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
||||
match pattern.node {
|
||||
PatEnum(ref path, ref children) => {
|
||||
|
|
|
|||
27
src/test/auxiliary/associated-types-cc-lib.rs
Normal file
27
src/test/auxiliary/associated-types-cc-lib.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// 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.
|
||||
|
||||
// Helper for test issue-18048, which tests associated types in a
|
||||
// cross-crate scenario.
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait Bar {
|
||||
type T;
|
||||
|
||||
fn get(x: Option<Self>) -> <Self as Bar>::T;
|
||||
}
|
||||
|
||||
impl Bar for int {
|
||||
type T = uint;
|
||||
|
||||
fn get(_: Option<int>) -> uint { 22 }
|
||||
}
|
||||
39
src/test/compile-fail/associated-types-bound-failure.rs
Normal file
39
src/test/compile-fail/associated-types-bound-failure.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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 equality constraints on associated types in a where clause.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait ToInt {
|
||||
fn to_int(&self) -> int;
|
||||
}
|
||||
|
||||
pub trait GetToInt
|
||||
{
|
||||
type R;
|
||||
|
||||
fn get(&self) -> <Self as GetToInt>::R;
|
||||
}
|
||||
|
||||
fn foo<G>(g: G) -> int
|
||||
where G : GetToInt
|
||||
{
|
||||
ToInt::to_int(&g.get()) //~ ERROR not implemented
|
||||
}
|
||||
|
||||
fn bar<G : GetToInt>(g: G) -> int
|
||||
where G::R : ToInt
|
||||
{
|
||||
ToInt::to_int(&g.get()) // OK
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ impl Foo for int {
|
|||
fn boo(&self) -> uint { 42 }
|
||||
}
|
||||
|
||||
fn baz<I: Foo>(x: &<I as Foo<A=Bar>>::A) {} //~ERROR equality constraints are not allowed in this
|
||||
fn baz<I: Foo>(x: &<I as Foo<A=Bar>>::A) {}
|
||||
//~^ ERROR associated type bindings are not allowed here
|
||||
|
||||
pub fn main() {}
|
||||
|
|
@ -43,6 +43,6 @@ pub fn baz(x: &Foo<A=Bar>) {
|
|||
|
||||
pub fn main() {
|
||||
let a = 42i;
|
||||
foo1(a); //~ERROR the trait `Foo` is not implemented for the type `int`
|
||||
baz(&a); //~ERROR the trait `Foo` is not implemented for the type `int`
|
||||
foo1(a); //~ERROR expected uint, found struct Bar
|
||||
baz(&a); //~ERROR expected uint, found struct Bar
|
||||
}
|
||||
72
src/test/compile-fail/associated-types-eq-hr.rs
Normal file
72
src/test/compile-fail/associated-types-eq-hr.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// 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.
|
||||
|
||||
// Check testing of equality constraints in a higher-ranked context.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait TheTrait<T> {
|
||||
type A;
|
||||
|
||||
fn get(&self, t: T) -> Self::A;
|
||||
}
|
||||
|
||||
struct IntStruct {
|
||||
x: int
|
||||
}
|
||||
|
||||
impl<'a> TheTrait<&'a int> for IntStruct {
|
||||
type A = &'a int;
|
||||
|
||||
fn get(&self, t: &'a int) -> &'a int {
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
struct UintStruct {
|
||||
x: int
|
||||
}
|
||||
|
||||
impl<'a> TheTrait<&'a int> for UintStruct {
|
||||
type A = &'a uint;
|
||||
|
||||
fn get(&self, t: &'a int) -> &'a uint {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
|
||||
fn foo<T>()
|
||||
where T : for<'x> TheTrait<&'x int, A = &'x int>
|
||||
{
|
||||
// ok for IntStruct, but not UintStruct
|
||||
}
|
||||
|
||||
fn bar<T>()
|
||||
where T : for<'x> TheTrait<&'x int, A = &'x uint>
|
||||
{
|
||||
// ok for UintStruct, but not IntStruct
|
||||
}
|
||||
|
||||
fn baz<T>()
|
||||
where T : for<'x,'y> TheTrait<&'x int, A = &'y int>
|
||||
{
|
||||
// not ok for either struct, due to the use of two lifetimes
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
foo::<IntStruct>();
|
||||
foo::<UintStruct>(); //~ ERROR type mismatch
|
||||
|
||||
bar::<IntStruct>(); //~ ERROR type mismatch
|
||||
bar::<UintStruct>();
|
||||
|
||||
baz::<IntStruct>(); //~ ERROR type mismatch
|
||||
baz::<UintStruct>(); //~ ERROR type mismatch
|
||||
}
|
||||
25
src/test/compile-fail/associated-types-for-unimpl-trait.rs
Normal file
25
src/test/compile-fail/associated-types-for-unimpl-trait.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
trait Get {
|
||||
type Value;
|
||||
fn get(&self) -> <Self as Get>::Value;
|
||||
}
|
||||
|
||||
trait Other {
|
||||
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
|
||||
//~^ ERROR the trait `Get` is not implemented for the type `Self`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
||||
|
|
@ -18,16 +18,6 @@ trait Get {
|
|||
fn get<T:Get,U:Get>(x: T, y: U) -> Get::Value {}
|
||||
//~^ ERROR ambiguous associated type
|
||||
|
||||
trait Other {
|
||||
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
|
||||
//~^ ERROR no suitable bound on `Self`
|
||||
}
|
||||
|
||||
impl<T:Get> Other for T {
|
||||
fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
|
||||
//~^ ERROR currently unsupported
|
||||
}
|
||||
|
||||
trait Grab {
|
||||
type Value;
|
||||
fn grab(&self) -> Grab::Value;
|
||||
|
|
|
|||
44
src/test/compile-fail/associated-types-incomplete-object.rs
Normal file
44
src/test/compile-fail/associated-types-incomplete-object.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// 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.
|
||||
|
||||
// Check that the user gets an errror if they omit a binding from an
|
||||
// object type.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait Foo {
|
||||
type A;
|
||||
type B;
|
||||
fn boo(&self) -> <Self as Foo>::A;
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Foo for int {
|
||||
type A = uint;
|
||||
type B = char;
|
||||
fn boo(&self) -> uint {
|
||||
42
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let a = &42i as &Foo<A=uint, B=char>;
|
||||
|
||||
let b = &42i as &Foo<A=uint>;
|
||||
//~^ ERROR the value of the associated type `B` (from the trait `Foo`) must be specified
|
||||
|
||||
let c = &42i as &Foo<B=char>;
|
||||
//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
|
||||
|
||||
let d = &42i as &Foo;
|
||||
//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
|
||||
//~| ERROR the value of the associated type `B` (from the trait `Foo`) must be specified
|
||||
}
|
||||
|
|
@ -15,16 +15,13 @@ trait Get {
|
|||
fn get(&self) -> <Self as Get>::Value;
|
||||
}
|
||||
|
||||
fn get(x: int) -> <int as Get>::Value {}
|
||||
//~^ ERROR unsupported
|
||||
|
||||
struct Struct {
|
||||
x: int,
|
||||
}
|
||||
|
||||
impl Struct {
|
||||
fn uhoh<T>(foo: <T as Get>::Value) {}
|
||||
//~^ ERROR no suitable bound on `T`
|
||||
//~^ ERROR the trait `Get` is not implemented for the type `T`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
// Check that we get an error when you use `<Self as Get>::Value` in
|
||||
// the trait definition but `Self` does not, in fact, implement `Get`.
|
||||
|
||||
trait Get {
|
||||
type Value;
|
||||
}
|
||||
|
||||
trait Other {
|
||||
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
|
||||
//~^ ERROR the trait `Get` is not implemented for the type `Self`
|
||||
}
|
||||
|
||||
impl<T:Get> Other for T {
|
||||
fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
|
||||
//~^ ERROR the trait `Get` is not implemented for the type `(T, U)`
|
||||
//~| ERROR the trait `Get` is not implemented for the type `(T, U)`
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
@ -26,9 +26,10 @@ pub fn f2<T: Foo>(a: T) -> T::A {
|
|||
}
|
||||
|
||||
pub fn main() {
|
||||
f1(2i, 4i); //~ERROR the trait `Foo` is not implemented
|
||||
f1(2u, 4u); //~ERROR the trait `Foo` is not implemented
|
||||
f1(2u, 4i); //~ERROR the trait `Foo` is not implemented
|
||||
f1(2i, 4i); //~ ERROR expected uint, found int
|
||||
f1(2i, 4u);
|
||||
f1(2u, 4u); //~ ERROR the trait `Foo` is not implemented
|
||||
f1(2u, 4i); //~ ERROR the trait `Foo` is not implemented
|
||||
|
||||
let _: int = f2(2i); //~ERROR mismatched types: expected `int`, found `uint`
|
||||
let _: int = f2(2i); //~ERROR expected `int`, found `uint`
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// 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 you can't use a higher-ranked trait bound inside of a qualified
|
||||
// path (just won't parse).
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait Foo<T> {
|
||||
type A;
|
||||
|
||||
fn get(&self, t: T) -> Self::A;
|
||||
}
|
||||
|
||||
fn foo2<I>(x: <I as for<'x> Foo<&'x int>>::A)
|
||||
//~^ ERROR expected identifier, found keyword `for`
|
||||
//~| ERROR expected one of `::` or `>`
|
||||
{
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
|
|
@ -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.
|
||||
|
||||
// Check projection of an associated type out of a higher-ranked
|
||||
// trait-bound in the context of a function body.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait Foo<T> {
|
||||
type A;
|
||||
|
||||
fn get(&self, t: T) -> Self::A;
|
||||
}
|
||||
|
||||
fn foo<'a, I : for<'x> Foo<&'x int>>(
|
||||
x: <I as Foo<&'a int>>::A)
|
||||
{
|
||||
let y: I::A = x;
|
||||
}
|
||||
|
||||
fn bar<'a, 'b, I : for<'x> Foo<&'x int>>(
|
||||
x: <I as Foo<&'a int>>::A,
|
||||
y: <I as Foo<&'b int>>::A,
|
||||
cond: bool)
|
||||
{ //~ ERROR cannot infer
|
||||
// x and y here have two distinct lifetimes:
|
||||
let z: I::A = if cond { x } else { y };
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// 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.
|
||||
|
||||
// Check projection of an associated type out of a higher-ranked trait-bound
|
||||
// in the context of a function signature.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait Foo<T> {
|
||||
type A;
|
||||
|
||||
fn get(&self, t: T) -> Self::A;
|
||||
}
|
||||
|
||||
fn foo2<I : for<'x> Foo<&'x int>>(
|
||||
x: I::A)
|
||||
//~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
|
||||
{
|
||||
// This case is illegal because we have to instantiate `'x`, and
|
||||
// we don't know what region to instantiate it with.
|
||||
//
|
||||
// This could perhaps be made equivalent to the examples below,
|
||||
// specifically for fn signatures.
|
||||
}
|
||||
|
||||
fn foo3<I : for<'x> Foo<&'x int>>(
|
||||
x: <I as Foo<&int>>::A)
|
||||
{
|
||||
// OK, in this case we spelled out the precise regions involved, though we left one of
|
||||
// them anonymous.
|
||||
}
|
||||
|
||||
fn foo4<'a, I : for<'x> Foo<&'x int>>(
|
||||
x: <I as Foo<&'a int>>::A)
|
||||
{
|
||||
// OK, in this case we spelled out the precise regions involved.
|
||||
}
|
||||
|
||||
|
||||
pub fn main() {}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// 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.
|
||||
|
||||
// Check projection of an associated type out of a higher-ranked trait-bound
|
||||
// in the context of a struct definition.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait Foo<T> {
|
||||
type A;
|
||||
|
||||
fn get(&self, t: T) -> Self::A;
|
||||
}
|
||||
|
||||
struct SomeStruct<I : for<'x> Foo<&'x int>> {
|
||||
field: I::A
|
||||
//~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
|
||||
}
|
||||
|
||||
struct AnotherStruct<I : for<'x> Foo<&'x int>> {
|
||||
field: <I as Foo<&int>>::A
|
||||
//~^ ERROR missing lifetime specifier
|
||||
}
|
||||
|
||||
struct YetAnotherStruct<'a, I : for<'x> Foo<&'x int>> {
|
||||
field: <I as Foo<&'a int>>::A
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// 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.
|
||||
|
||||
// Check projection of an associated type out of a higher-ranked trait-bound
|
||||
// in the context of a method definition in a trait.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
pub trait Foo<T> {
|
||||
type A;
|
||||
|
||||
fn get(&self, t: T) -> Self::A;
|
||||
}
|
||||
|
||||
trait SomeTrait<I : for<'x> Foo<&'x int>> {
|
||||
fn some_method(&self, arg: I::A);
|
||||
//~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
|
||||
}
|
||||
|
||||
trait AnotherTrait<I : for<'x> Foo<&'x int>> {
|
||||
fn some_method(&self, arg: <I as Foo<&int>>::A);
|
||||
}
|
||||
|
||||
trait YetAnotherTrait<I : for<'x> Foo<&'x int>> {
|
||||
fn some_method<'a>(&self, arg: <I as Foo<&'a int>>::A);
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue