diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 03e436e98df46..2a58da8cb3be7 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -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; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 51cebbfb52c58..0cbc94f379d80 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -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, } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 4447af809e4b2..a168ac7fa9a78 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -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> { 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> { 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 { + 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") diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 2a670b308b6b2..db29d0111f446 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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 { // Pull the cnums and name,vers,hash out of cstore diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 9b008f36a9646..88c7ccf1b1e36 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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> { 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> { 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; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 3e9eaf7eea207..30746f51a8fe7 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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); +} diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index 060e2f67faf98..b1b4fd831a0fa 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -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)) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index e8627dfa64b0b..6efc80ed8d343 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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>; fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> Rc>; + -> ty::PolyTraitRef<'tcx>; fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::TypeParameterDef<'tcx>; fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> 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,7 @@ 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> { - Rc::new(self.read_opaque(|this, doc| { + self.read_opaque(|this, doc| { let ty = tydecode::parse_trait_ref_data( doc.data, dcx.cdata.cnum, @@ -1554,12 +1555,12 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { dcx.tcx, |s, a| this.convert_def_id(dcx, s, a)); Ok(ty) - }).unwrap()) + }).unwrap() } fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> Rc> { - Rc::new(ty::Binder(self.read_opaque(|this, doc| { + -> ty::PolyTraitRef<'tcx> { + ty::Binder(self.read_opaque(|this, doc| { let ty = tydecode::parse_trait_ref_data( doc.data, dcx.cdata.cnum, @@ -1567,7 +1568,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { dcx.tcx, |s, a| this.convert_def_id(dcx, s, a)); Ok(ty) - }).unwrap())) + }).unwrap()) } fn read_type_param_def<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) @@ -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); diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index c2992a81d2083..b7e67ea469059 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -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); } diff --git a/src/librustc/middle/check_rvalues.rs b/src/librustc/middle/check_rvalues.rs index a14307b90ee83..3b4ea5234f43f 100644 --- a/src/librustc/middle/check_rvalues.rs +++ b/src/librustc/middle/check_rvalues.rs @@ -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)); diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 14f927f5b1ecb..fb20df020acf8 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -31,7 +31,6 @@ use middle::infer; use middle::traits; use middle::mem_categorization as mc; use middle::expr_use_visitor as euv; -use util::common::ErrorReported; use util::nodemap::NodeSet; use syntax::ast; @@ -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) => { } } } } diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 023182df33652..ff1ee39496626 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -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), _) => { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index b7cfb22b85f8c..059f38f0930d1 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -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); } } diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 62cf47da68701..dcbd94b8482fd 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -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) diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs index 13017da508d28..11ca202971e1d 100644 --- a/src/librustc/middle/infer/coercion.rs +++ b/src/librustc/middle/infer/coercion.rs @@ -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, diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 04ae0a5a60432..e0bcdfc6d8d93 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -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>, + b: &Vec>) + -> cres<'tcx, Vec>> + { + // 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>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; } +impl<'tcx,T> Combineable<'tcx> for Rc + where T : Combineable<'tcx> +{ + fn combine>(combiner: &C, + a: &Rc, + b: &Rc) + -> cres<'tcx, Rc> + { + Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b)))) + } +} + impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> { fn combine>(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>(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>(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), diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 3d3eac7b6ed9f..e38b721ce2d0d 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -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> { } } -impl<'tcx> Resolvable<'tcx> for Rc> { - fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) - -> Rc> { - 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) } } diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index d8455b8db71ed..33174409f899b 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -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) } diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 07823779216d9..386768bd9d6f7 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -139,7 +139,7 @@ pub enum TypeOrigin { pub enum ValuePairs<'tcx> { Types(ty::expected_found>), TraitRefs(ty::expected_found>>), - PolyTraitRefs(ty::expected_found>>), + PolyTraitRefs(ty::expected_found>), } /// 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>, - b: Rc>) + 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>, - b: Rc>) + 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, }) } } diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs index 12400de31ed9e..ca2ae25e6c63a 100644 --- a/src/librustc/middle/infer/resolve.rs +++ b/src/librustc/middle/infer/resolve.rs @@ -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( diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 2b8adfb7c1eeb..4bd3308728c10 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -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) } _ => { diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index dcf70263c0a43..3127ef5d8a5f5 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -225,7 +225,7 @@ impl sv::SnapshotVecDelegate,()> 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) -> ty::type_err<'tcx>; } @@ -337,7 +337,7 @@ impl<'a,'tcx,V:SimplyUnifiable<'tcx>,K:UnifyKey<'tcx, Option>> 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> 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 { } 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) -> ty::type_err<'tcx> { diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index ba18c02f52dc1..df06b3b7789c9 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -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>, + + // 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) { + // 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; + } + + // 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=int, U=int + // } + // + // fn bar() { + // // T=int, U=int + // // T=[int], U=int + // } + // + // fn baz() { + // // 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 from a type that contains type parameters"); + "cannot transmute to or from a type that contains \ + type parameters in its interior"); + return; } - 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"); + + 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>, + 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); + } } + } - let restriction = TransmuteRestriction { - span: span, - from: from, - to: to, - id: id, - }; + 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)) + } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5d3134b9629b2..c15001af68d96 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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( diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index abacad7d37c90..3066ae5b479ef 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -55,18 +55,17 @@ impl<'tcx> Substs<'tcx> { r: Vec) -> 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>, r: Vec, - a: Vec>, 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>) -> Substs<'tcx> @@ -123,13 +122,6 @@ impl<'tcx> Substs<'tcx> { s } - pub fn with_assoc_tys(&self, assoc_tys: Vec>) -> 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 { // // 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, } @@ -248,7 +235,6 @@ pub struct VecPerParamSpace { pub struct SeparateVecsPerParamSpace { pub types: Vec, pub selfs: Vec, - pub assocs: Vec, pub fns: Vec, } @@ -268,8 +254,7 @@ impl VecPerParamSpace { 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 VecPerParamSpace { VecPerParamSpace { type_limit: 0, self_limit: 0, - assoc_limit: 0, content: Vec::new() } } @@ -290,31 +274,27 @@ impl VecPerParamSpace { /// `s` is the self space. /// `a` is the assoc space. /// `f` is the fn space. - pub fn new(t: Vec, s: Vec, a: Vec, f: Vec) -> VecPerParamSpace { + pub fn new(t: Vec, s: Vec, f: Vec) -> VecPerParamSpace { 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, type_limit: uint, self_limit: uint, assoc_limit: uint) + fn new_internal(content: Vec, type_limit: uint, self_limit: uint) -> VecPerParamSpace { VecPerParamSpace { type_limit: type_limit, self_limit: self_limit, - assoc_limit: assoc_limit, content: content, } } @@ -326,9 +306,8 @@ impl VecPerParamSpace { 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 VecPerParamSpace { 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 VecPerParamSpace { self.content.as_slice() } + pub fn to_vec(self) -> Vec { + self.content + } + pub fn all_vecs

(&self, mut pred: P) -> bool where P: FnMut(&[T]) -> bool, { @@ -435,8 +417,7 @@ impl VecPerParamSpace { 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(&self, pred: P) -> VecPerParamSpace where @@ -445,8 +426,7 @@ impl VecPerParamSpace { 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(self, mut pred: F) -> VecPerParamSpace where @@ -455,25 +435,22 @@ impl VecPerParamSpace { 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 { - 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 VecPerParamSpace { } } +#[deriving(Clone)] pub struct EnumeratedItems<'a,T:'a> { vec: &'a VecPerParamSpace, space_index: uint, diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index d48685ce27d89..d8b39d92c692f 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -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 => { diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 462857de1d4f8..a3d92c698a2ad 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -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,37 @@ 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!( + "the requirement `{}` is not satisfied (`{}`)", + predicate.user_string(infcx.tcx), + ty::type_err_to_str(infcx.tcx, &err)).as_slice()); + } + 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!( @@ -116,9 +127,10 @@ 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::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); } } } + diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index e9e80ed8c18c9..7ec221fcfa903 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -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 `::X` by + /// creating a fresh type variable `$0` as well as a projection + /// predicate `::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); - } - Err(ErrorReported) => { } - } + 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_trait_ref<'a>(&mut self, - tcx: &ty::ctxt<'tcx>, - trait_ref: Rc>, - cause: ObligationCause<'tcx>) + pub fn register_builtin_bound<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>, + ty: Ty<'tcx>, + builtin_bound: ty::BuiltinBound, + 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) + match predicate_for_builtin_bound(infcx.tcx, cause, builtin_bound, 0, ty) { + Ok(predicate) => { + self.register_predicate(infcx, predicate); + } + Err(ErrorReported) => { } + } } - pub fn register_region_obligation(&mut self, - tcx: &ty::ctxt<'tcx>, - t_a: Ty<'tcx>, - r_b: ty::Region, - 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>) { - 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>, + obligation: &PredicateObligation<'tcx>, + new_obligations: &mut Vec>, errors: &mut Vec>, region_obligations: &mut NodeMap>>) -> 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 `::name = U` but we couldn't find any more + // information. This could just be that we're in a + // function like: + // + // fn foo(...) + // + // 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 `::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 `::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> 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 `::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 + } + } + } } } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 6597730846ded..d4fa0c98ad5d1 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -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>>; +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>, Rc>), + BuiltinDerivedObligation(DerivedObligationCause<'tcx>), + + ImplDerivedObligation(DerivedObligationCause<'tcx>), +} - ImplDerivedObligation(Rc>, Rc>), +#[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> } pub type Obligations<'tcx, O> = subst::VecPerParamSpace>; @@ -121,8 +137,8 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; pub enum SelectionError<'tcx> { Unimplemented, Overflow, - OutputTypeParameterMismatch(Rc>, - Rc>, + 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, 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), @@ -228,15 +245,6 @@ pub struct VtableBuiltinData { pub nested: subst::VecPerParamSpace } -/// A vtable provided as a parameter by the caller. For example, in a -/// function like `fn foo(...)`, if the `eq()` method is invoked -/// on an instance of `T`, the vtable would be of type `VtableParam`. -#[deriving(PartialEq,Eq,Clone)] -pub struct VtableParamData<'tcx> { - // In the above example, this would `Eq` - pub bound: Rc>, -} - /// 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

(&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() + } +} diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs new file mode 100644 index 0000000000000..435babf168e86 --- /dev/null +++ b/src/librustc/middle/traits/project.rs @@ -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 or the MIT license +// , 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 `::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`. When + /// normalizing, this case is where we opt to normalize back to + /// the projection type `::Name`. + NoCandidate, + + /// ...we found multiple sources of information and couldn't resolve the ambiguity. + TooManyCandidates, + + /// ...`` 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>; + +enum ProjectionTyCandidate<'tcx> { + ParamEnv(ty::PolyProjectionPredicate<'tcx>), + Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>), +} + +struct ProjectionTyCandidateSet<'tcx> { + vec: Vec>, + 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>) +{ + 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 `>::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(...) { } + // ``` + // + // If the user writes `::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>(...) { ... } + // ``` + // + // Doesn't the `T : Sometrait` 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)) + } + } +} + diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index b10b1ce35c436..ce5337a58e10c 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -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>, + fresh_trait_ref: ty::PolyTraitRef<'tcx>, previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> } #[deriving(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell>, - SelectionResult<'tcx, Candidate<'tcx>>>>, + hashmap: RefCell>, + 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>, - ambiguous: bool +struct SelectionCandidateSet<'tcx> { + // a list of candidates that definitely apply to the current + // obligation (meaning: types unify). + vec: Vec>, + + // 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>) + 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>) - -> Option>> + cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>) + -> Option>> { - 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>, - 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, SelectionError<'tcx>> + -> Result, 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>, + 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 ``, 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_vec: &mut Vec>) -> 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,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,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, - 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> { 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::>(); 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>, - expected_trait_ref: Rc>) + 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>) + 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>>, - Rc>) - -> 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)), } } } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index e75478b32438f..109810fc7eec3 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -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>) + 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>]) + 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>) + 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>]) + 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>> for Supertraits<'cx, 'tcx> { - fn next(&mut self) -> Option>> { +impl<'cx, 'tcx> Iterator> for Supertraits<'cx, 'tcx> { + fn next(&mut self) -> Option> { loop { match self.elaborator.next() { None => { 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>, ErrorReported> + -> Result>, 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, 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>, - mut test: F) - -> Option> - 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 { } } -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(..)") + } +} + + diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 617be82701a09..ab39c761a3861 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -56,16 +56,15 @@ use middle::resolve_lifetime; use middle::infer; use middle::stability; use middle::subst::{mod, Subst, Substs, VecPerParamSpace}; -use middle::traits::ObligationCause; use middle::traits; use middle::ty; use middle::ty_fold::{mod, TypeFoldable, TypeFolder}; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; use util::ppaux::{trait_store_to_string, ty_to_string}; use util::ppaux::{Repr, UserString}; -use util::common::{indenter, memoized, ErrorReported}; +use util::common::{memoized, ErrorReported}; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; -use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::nodemap::{FnvHashMap}; use arena::TypedArena; use std::borrow::BorrowFrom; @@ -80,14 +79,14 @@ use collections::enum_set::{EnumSet, CLike}; use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::abi; -use syntax::ast::{CrateNum, DefId, DUMMY_NODE_ID, Ident, ItemTrait, LOCAL_CRATE}; +use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE}; use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; use syntax::ast::{Onceness, StmtExpr, StmtSemi, StructField, UnnamedField}; use syntax::ast::{Visibility}; use syntax::ast_util::{mod, is_local, lit_is_str, local_def, PostExpansionMethod}; use syntax::attr::{mod, AttrMetaMethods}; -use syntax::codemap::{DUMMY_SP, Span}; -use syntax::parse::token::{mod, InternedString}; +use syntax::codemap::Span; +use syntax::parse::token::{mod, InternedString, special_idents}; use syntax::{ast, ast_map}; pub type Disr = u64; @@ -397,14 +396,14 @@ pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Opti fn type_of_autoref<'tcx>(cx: &ctxt<'tcx>, autoref: &AutoRef<'tcx>) -> Option> { match autoref { &AutoUnsize(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, bounds }, _) => { - Some(mk_trait(cx, (*principal).clone(), bounds)) + &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { + Some(mk_trait(cx, principal.clone(), bounds.clone())) } _ => None }, &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, bounds }, _) => { - Some(mk_uniq(cx, mk_trait(cx, (*principal).clone(), bounds))) + &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { + Some(mk_uniq(cx, mk_trait(cx, principal.clone(), bounds.clone()))) } _ => None }, @@ -588,19 +587,36 @@ pub enum vtable_origin<'tcx> { // For every explicit cast into an object type, maps from the cast // expr to the associated trait ref. -pub type ObjectCastMap<'tcx> = RefCell>>>; +pub type ObjectCastMap<'tcx> = RefCell>>; /// A restriction that certain types must be the same size. The use of -/// `transmute` gives rise to these restrictions. +/// `transmute` gives rise to these restrictions. These generally +/// cannot be checked until trans; therefore, each call to `transmute` +/// will push one or more such restriction into the +/// `transmute_restrictions` vector during `intrinsicck`. They are +/// then checked during `trans` by the fn `check_intrinsics`. #[deriving(Copy)] pub struct TransmuteRestriction<'tcx> { - /// The span from whence the restriction comes. + /// The span whence the restriction comes. pub span: Span, + /// The type being transmuted from. - pub from: Ty<'tcx>, + pub original_from: Ty<'tcx>, + /// The type being transmuted to. - pub to: Ty<'tcx>, - /// NodeIf of the transmute intrinsic. + pub original_to: Ty<'tcx>, + + /// The type being transmuted from, with all type parameters + /// substituted for an arbitrary representative. Not to be shown + /// to the end user. + pub substituted_from: Ty<'tcx>, + + /// The type being transmuted to, with all type parameters + /// substituted for an arbitrary representative. Not to be shown + /// to the end user. + pub substituted_to: Ty<'tcx>, + + /// NodeId of the transmute intrinsic. pub id: ast::NodeId, } @@ -623,6 +639,24 @@ impl<'tcx> CtxtArenas<'tcx> { } } +pub struct CommonTypes<'tcx> { + pub bool: Ty<'tcx>, + pub char: Ty<'tcx>, + pub int: Ty<'tcx>, + pub i8: Ty<'tcx>, + pub i16: Ty<'tcx>, + pub i32: Ty<'tcx>, + pub i64: Ty<'tcx>, + pub uint: Ty<'tcx>, + pub u8: Ty<'tcx>, + pub u16: Ty<'tcx>, + pub u32: Ty<'tcx>, + pub u64: Ty<'tcx>, + pub f32: Ty<'tcx>, + pub f64: Ty<'tcx>, + pub err: Ty<'tcx>, +} + /// The data structure to keep track of all the information that typechecker /// generates so that so that it can be reused and doesn't have to be redone /// later on. @@ -635,11 +669,15 @@ pub struct ctxt<'tcx> { // FIXME(eddyb) use a FnvHashSet> when equivalent keys can // queried from a HashSet. interner: RefCell, Ty<'tcx>>>, + // FIXME as above, use a hashset if equivalent elements can be queried. substs_interner: RefCell, &'tcx Substs<'tcx>>>, bare_fn_interner: RefCell, &'tcx BareFnTy<'tcx>>>, region_interner: RefCell>, + /// Common types, pre-interned for your convenience. + pub types: CommonTypes<'tcx>, + pub sess: Session, pub def_map: DefMap, @@ -679,10 +717,9 @@ pub struct ctxt<'tcx> { pub map: ast_map::Map<'tcx>, pub intrinsic_defs: RefCell>>, pub freevars: RefCell, - pub tcache: RefCell>>, + pub tcache: RefCell>>, pub rcache: RefCell>>, pub short_names_cache: RefCell, String>>, - pub needs_unwind_cleanup_cache: RefCell, bool>>, pub tc_cache: RefCell, TypeContents>>, pub ast_ty_to_ty_cache: RefCell>>, pub enum_var_cache: RefCell>>>>>, @@ -781,8 +818,15 @@ pub struct ctxt<'tcx> { /// Caches the representation hints for struct definitions. pub repr_hint_cache: RefCell>>>, - /// Caches whether types move by default. - pub type_moves_by_default_cache: RefCell,bool>>, + /// Caches whether types are known to impl Copy. Note that type + /// parameters are never placed into this cache, because their + /// results are dependent on the parameter environment. + pub type_impls_copy_cache: RefCell,bool>>, + + /// Caches whether types are known to impl Sized. Note that type + /// parameters are never placed into this cache, because their + /// results are dependent on the parameter environment. + pub type_impls_sized_cache: RefCell,bool>>, } // Flags that we track on types. These flags are propagated upwards @@ -799,6 +843,7 @@ bitflags! { const HAS_RE_LATE_BOUND = 0b10000, const HAS_REGIONS = 0b100000, const HAS_TY_ERR = 0b1000000, + const HAS_PROJECTION = 0b10000000, const NEEDS_SUBST = HAS_PARAMS.bits | HAS_SELF.bits | HAS_REGIONS.bits, } } @@ -869,7 +914,7 @@ impl<'tcx> ctxt<'tcx> { sty_debug_print!( self, ty_enum, ty_uniq, ty_vec, ty_ptr, ty_rptr, ty_bare_fn, ty_closure, ty_trait, - ty_struct, ty_unboxed_closure, ty_tup, ty_param, ty_open, ty_infer); + ty_struct, ty_unboxed_closure, ty_tup, ty_param, ty_open, ty_infer, ty_projection); println!("Substs interner: #{}", self.substs_interner.borrow().len()); println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len()); @@ -945,6 +990,9 @@ pub fn type_has_ty_infer(ty: Ty) -> bool { pub fn type_needs_infer(ty: Ty) -> bool { ty.flags.intersects(HAS_TY_INFER | HAS_RE_INFER) } +pub fn type_has_projection(ty: Ty) -> bool { + ty.flags.intersects(HAS_PROJECTION) +} pub fn type_has_late_bound_regions(ty: Ty) -> bool { ty.flags.intersects(HAS_RE_LATE_BOUND) @@ -992,7 +1040,7 @@ pub struct ClosureTy<'tcx> { pub unsafety: ast::Unsafety, pub onceness: ast::Onceness, pub store: TraitStore, - pub bounds: ExistentialBounds, + pub bounds: ExistentialBounds<'tcx>, pub sig: PolyFnSig<'tcx>, pub abi: abi::Abi, } @@ -1031,7 +1079,7 @@ pub type PolyFnSig<'tcx> = Binder>; pub struct ParamTy { pub space: subst::ParamSpace, pub idx: u32, - pub def_id: DefId + pub name: ast::Name, } /// A [De Bruijn index][dbi] is a standard means of representing @@ -1275,54 +1323,6 @@ pub enum BoundRegion { BrEnv } -#[inline] -pub fn mk_prim_t<'tcx>(primitive: &'tcx TyS<'static>) -> Ty<'tcx> { - // FIXME(#17596) Ty<'tcx> is incorrectly invariant w.r.t 'tcx. - unsafe { &*(primitive as *const _ as *const TyS<'tcx>) } -} - -// Do not change these from static to const, interning types requires -// the primitives to have a significant address. -macro_rules! def_prim_tys { - ($($name:ident -> $sty:expr;)*) => ( - $(#[inline] pub fn $name<'tcx>() -> Ty<'tcx> { - static PRIM_TY: TyS<'static> = TyS { - sty: $sty, - flags: NO_TYPE_FLAGS, - region_depth: 0, - }; - mk_prim_t(&PRIM_TY) - })* - ) -} - -def_prim_tys!{ - mk_bool -> ty_bool; - mk_char -> ty_char; - mk_int -> ty_int(ast::TyI); - mk_i8 -> ty_int(ast::TyI8); - mk_i16 -> ty_int(ast::TyI16); - mk_i32 -> ty_int(ast::TyI32); - mk_i64 -> ty_int(ast::TyI64); - mk_uint -> ty_uint(ast::TyU); - mk_u8 -> ty_uint(ast::TyU8); - mk_u16 -> ty_uint(ast::TyU16); - mk_u32 -> ty_uint(ast::TyU32); - mk_u64 -> ty_uint(ast::TyU64); - mk_f32 -> ty_float(ast::TyF32); - mk_f64 -> ty_float(ast::TyF64); -} - -#[inline] -pub fn mk_err<'tcx>() -> Ty<'tcx> { - static TY_ERR: TyS<'static> = TyS { - sty: ty_err, - flags: HAS_TY_ERR, - region_depth: 0, - }; - mk_prim_t(&TY_ERR) -} - // NB: If you change this, you'll probably want to change the corresponding // AST structure in libsyntax/ast.rs as well. #[deriving(Clone, PartialEq, Eq, Hash, Show)] @@ -1358,7 +1358,9 @@ pub enum sty<'tcx> { ty_tup(Vec>), + ty_projection(ProjectionTy<'tcx>), ty_param(ParamTy), // type parameter + ty_open(Ty<'tcx>), // A deref'ed fat pointer, i.e., a dynamically sized value // and its size. Only ever used in trans. It is not necessary // earlier since we don't need to distinguish a DST with its @@ -1373,25 +1375,59 @@ pub enum sty<'tcx> { #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct TyTrait<'tcx> { - // Principal trait reference. - pub principal: PolyTraitRef<'tcx>, - pub bounds: ExistentialBounds + pub principal: ty::PolyTraitRef<'tcx>, + pub bounds: ExistentialBounds<'tcx>, } impl<'tcx> TyTrait<'tcx> { + pub fn principal_def_id(&self) -> ast::DefId { + self.principal.0.def_id + } + /// Object types don't have a self-type specified. Therefore, when /// we convert the principal trait-ref into a normal trait-ref, /// you must give *some* self-type. A common choice is `mk_err()` /// or some skolemized type. pub fn principal_trait_ref_with_self_ty(&self, - tcx: &ctxt<'tcx>, self_ty: Ty<'tcx>) - -> Rc> + tcx: &ctxt<'tcx>, + self_ty: Ty<'tcx>) + -> ty::PolyTraitRef<'tcx> { - Rc::new(ty::Binder(ty::TraitRef { - def_id: self.principal.def_id(), - substs: tcx.mk_substs(self.principal.substs().with_self_ty(self_ty)), + // otherwise the escaping regions would be captured by the binder + assert!(!self_ty.has_escaping_regions()); + + ty::Binder(Rc::new(ty::TraitRef { + def_id: self.principal.0.def_id, + substs: tcx.mk_substs(self.principal.0.substs.with_self_ty(self_ty)), })) } + + pub fn projection_bounds_with_self_ty(&self, + tcx: &ctxt<'tcx>, + self_ty: Ty<'tcx>) + -> Vec> + { + // otherwise the escaping regions would be captured by the binders + assert!(!self_ty.has_escaping_regions()); + + self.bounds.projection_bounds.iter() + .map(|in_poly_projection_predicate| { + let in_projection_ty = &in_poly_projection_predicate.0.projection_ty; + let substs = tcx.mk_substs(in_projection_ty.trait_ref.substs.with_self_ty(self_ty)); + let trait_ref = + Rc::new(ty::TraitRef::new(in_projection_ty.trait_ref.def_id, + substs)); + let projection_ty = ty::ProjectionTy { + trait_ref: trait_ref, + item_name: in_projection_ty.item_name + }; + ty::Binder(ty::ProjectionPredicate { + projection_ty: projection_ty, + ty: in_poly_projection_predicate.0.ty + }) + }) + .collect() + } } /// A complete reference to a trait. These take numerous guises in syntax, @@ -1415,7 +1451,7 @@ pub struct TraitRef<'tcx> { pub substs: &'tcx Substs<'tcx>, } -pub type PolyTraitRef<'tcx> = Binder>; +pub type PolyTraitRef<'tcx> = Binder>>; impl<'tcx> PolyTraitRef<'tcx> { pub fn self_ty(&self) -> Ty<'tcx> { @@ -1433,6 +1469,11 @@ impl<'tcx> PolyTraitRef<'tcx> { pub fn input_types(&self) -> &[Ty<'tcx>] { self.0.input_types() } + + pub fn to_poly_trait_predicate(&self) -> PolyTraitPredicate<'tcx> { + // Note that we preserve binding levels + Binder(TraitPredicate { trait_ref: self.0.clone() }) + } } /// Binder is a binder for higher-ranked lifetimes. It is part of the @@ -1496,7 +1537,9 @@ pub enum type_err<'tcx> { terr_builtin_bounds(expected_found), terr_variadic_mismatch(expected_found), terr_cyclic_ty, - terr_convergence_mismatch(expected_found) + terr_convergence_mismatch(expected_found), + terr_projection_name_mismatched(expected_found), + terr_projection_bounds_length(expected_found), } /// Bounds suitable for a named type parameter like `A` in `fn foo` @@ -1505,7 +1548,8 @@ pub enum type_err<'tcx> { pub struct ParamBounds<'tcx> { pub region_bounds: Vec, pub builtin_bounds: BuiltinBounds, - pub trait_bounds: Vec>> + pub trait_bounds: Vec>, + pub projection_bounds: Vec>, } /// Bounds suitable for an existentially quantified type parameter @@ -1513,10 +1557,11 @@ pub struct ParamBounds<'tcx> { /// major difference between this case and `ParamBounds` is that /// general purpose trait bounds are omitted and there must be /// *exactly one* region. -#[deriving(Copy, PartialEq, Eq, Hash, Clone, Show)] -pub struct ExistentialBounds { +#[deriving(PartialEq, Eq, Hash, Clone, Show)] +pub struct ExistentialBounds<'tcx> { pub region_bound: ty::Region, - pub builtin_bounds: BuiltinBounds + pub builtin_bounds: BuiltinBounds, + pub projection_bounds: Vec>, } pub type BuiltinBounds = EnumSet; @@ -1544,9 +1589,10 @@ pub fn all_builtin_bounds() -> BuiltinBounds { } /// An existential bound that does not implement any traits. -pub fn region_existential_bound(r: ty::Region) -> ExistentialBounds { +pub fn region_existential_bound<'tcx>(r: ty::Region) -> ExistentialBounds<'tcx> { ty::ExistentialBounds { region_bound: r, - builtin_bounds: empty_builtin_bounds() } + builtin_bounds: empty_builtin_bounds(), + projection_bounds: Vec::new() } } impl CLike for BuiltinBound { @@ -1676,7 +1722,6 @@ pub struct TypeParameterDef<'tcx> { pub def_id: ast::DefId, pub space: subst::ParamSpace, pub index: u32, - pub associated_with: Option, pub bounds: ParamBounds<'tcx>, pub default: Option>, } @@ -1735,7 +1780,7 @@ pub enum Predicate<'tcx> { /// Corresponds to `where Foo : Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the parameters in the `TypeSpace`. - Trait(Rc>), + Trait(PolyTraitPredicate<'tcx>), /// where `T1 == T2`. Equate(PolyEquatePredicate<'tcx>), @@ -1745,6 +1790,36 @@ pub enum Predicate<'tcx> { /// where T : 'a TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), + + /// where ::Name == X, approximately. + /// See `ProjectionPredicate` struct for details. + Projection(PolyProjectionPredicate<'tcx>), +} + +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct TraitPredicate<'tcx> { + pub trait_ref: Rc> +} +pub type PolyTraitPredicate<'tcx> = ty::Binder>; + +impl<'tcx> TraitPredicate<'tcx> { + pub fn def_id(&self) -> ast::DefId { + self.trait_ref.def_id + } + + pub fn input_types(&self) -> &[Ty<'tcx>] { + self.trait_ref.substs.types.as_slice() + } + + pub fn self_ty(&self) -> Ty<'tcx> { + self.trait_ref.self_ty() + } +} + +impl<'tcx> PolyTraitPredicate<'tcx> { + pub fn def_id(&self) -> ast::DefId { + self.0.def_id() + } } #[deriving(Clone, PartialEq, Eq, Hash, Show)] @@ -1757,13 +1832,98 @@ pub type PolyOutlivesPredicate = ty::Binder>; pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; +/// This kind of predicate has no *direct* correspondent in the +/// syntax, but it roughly corresponds to the syntactic forms: +/// +/// 1. `T : TraitRef<..., Item=Type>` +/// 2. `>::Item == Type` (NYI) +/// +/// In particular, form #1 is "desugared" to the combination of a +/// normal trait predicate (`T : TraitRef<...>`) and one of these +/// predicates. Form #2 is a broader form in that it also permits +/// equality between arbitrary types. Processing an instance of Form +/// #2 eventually yields one of these `ProjectionPredicate` +/// instances to normalize the LHS. +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct ProjectionPredicate<'tcx> { + pub projection_ty: ProjectionTy<'tcx>, + pub ty: Ty<'tcx>, +} + +pub type PolyProjectionPredicate<'tcx> = Binder>; + +impl<'tcx> PolyProjectionPredicate<'tcx> { + pub fn sort_key(&self) -> (ast::DefId, ast::Name) { + self.0.projection_ty.sort_key() + } +} + +/// Represents the projection of an associated type. In explicit UFCS +/// form this would be written `>::N`. +#[deriving(Clone, PartialEq, Eq, Hash, Show)] +pub struct ProjectionTy<'tcx> { + /// The trait reference `T as Trait<..>`. + pub trait_ref: Rc>, + + /// The name `N` of the associated type. + pub item_name: ast::Name, +} + +impl<'tcx> ProjectionTy<'tcx> { + pub fn sort_key(&self) -> (ast::DefId, ast::Name) { + (self.trait_ref.def_id, self.item_name) + } +} + +pub trait ToPolyTraitRef<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; +} + +impl<'tcx> ToPolyTraitRef<'tcx> for Rc> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + assert!(!self.has_escaping_regions()); + ty::Binder(self.clone()) + } +} + +impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + // We are just preserving the binder levels here + ty::Binder(self.0.trait_ref.clone()) + } +} + +impl<'tcx> ToPolyTraitRef<'tcx> for PolyProjectionPredicate<'tcx> { + fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { + // Note: unlike with TraitRef::to_poly_trait_ref(), + // self.0.trait_ref is permitted to have escaping regions. + // This is because here `self` has a `Binder` and so does our + // return value, so we are preserving the number of binding + // levels. + ty::Binder(self.0.projection_ty.trait_ref.clone()) + } +} + pub trait AsPredicate<'tcx> { fn as_predicate(&self) -> Predicate<'tcx>; } -impl<'tcx> AsPredicate<'tcx> for Rc> { +impl<'tcx> AsPredicate<'tcx> for Rc> { + fn as_predicate(&self) -> Predicate<'tcx> { + // we're about to add a binder, so let's check that we don't + // accidentally capture anything, or else that might be some + // weird debruijn accounting. + assert!(!self.has_escaping_regions()); + + ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { + trait_ref: self.clone() + })) + } +} + +impl<'tcx> AsPredicate<'tcx> for PolyTraitRef<'tcx> { fn as_predicate(&self) -> Predicate<'tcx> { - Predicate::Trait(self.clone()) + ty::Predicate::Trait(self.to_poly_trait_predicate()) } } @@ -1785,6 +1945,12 @@ impl<'tcx> AsPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { } } +impl<'tcx> AsPredicate<'tcx> for PolyProjectionPredicate<'tcx> { + fn as_predicate(&self) -> Predicate<'tcx> { + Predicate::Projection(self.clone()) + } +} + impl<'tcx> Predicate<'tcx> { pub fn has_escaping_regions(&self) -> bool { match *self { @@ -1792,14 +1958,16 @@ impl<'tcx> Predicate<'tcx> { Predicate::Equate(ref p) => p.has_escaping_regions(), Predicate::RegionOutlives(ref p) => p.has_escaping_regions(), Predicate::TypeOutlives(ref p) => p.has_escaping_regions(), + Predicate::Projection(ref p) => p.has_escaping_regions(), } } - pub fn to_trait(&self) -> Option>> { + pub fn to_opt_poly_trait_ref(&self) -> Option> { match *self { Predicate::Trait(ref t) => { - Some(t.clone()) + Some(t.to_poly_trait_ref()) } + Predicate::Projection(..) | Predicate::Equate(..) | Predicate::RegionOutlives(..) | Predicate::TypeOutlives(..) => { @@ -2007,18 +2175,29 @@ impl<'tcx> ParameterEnvironment<'tcx> { } } -/// A polytype. +/// A "type scheme", in ML terminology, is a type combined with some +/// set of generic types that the type is, well, generic over. In Rust +/// terms, it is the "type" of a fn item or struct -- this type will +/// include various generic parameters that must be substituted when +/// the item/struct is referenced. That is called converting the type +/// scheme to a monotype. /// /// - `generics`: the set of type parameters and their bounds /// - `ty`: the base types, which may reference the parameters defined /// in `generics` +/// +/// Note that TypeSchemes are also sometimes called "polytypes" (and +/// in fact this struct used to carry that name, so you may find some +/// stray references in a comment or something). We try to reserve the +/// "poly" prefix to refer to higher-ranked things, as in +/// `PolyTraitRef`. #[deriving(Clone, Show)] -pub struct Polytype<'tcx> { +pub struct TypeScheme<'tcx> { pub generics: Generics<'tcx>, pub ty: Ty<'tcx> } -/// As `Polytype` but for a trait ref. +/// As `TypeScheme` but for a trait ref. pub struct TraitDef<'tcx> { pub unsafety: ast::Unsafety, @@ -2031,7 +2210,12 @@ pub struct TraitDef<'tcx> { /// The "supertrait" bounds. pub bounds: ParamBounds<'tcx>, + pub trait_ref: Rc>, + + /// A list of the associated types defined in this trait. Useful + /// for resolving `X::Foo` type markers. + pub associated_type_names: Vec, } /// Records the substitutions used to translate the polytype for an @@ -2075,6 +2259,31 @@ impl UnboxedClosureKind { } } +impl<'tcx> CommonTypes<'tcx> { + fn new(arena: &'tcx TypedArena>, + interner: &mut FnvHashMap, Ty<'tcx>>) + -> CommonTypes<'tcx> + { + CommonTypes { + bool: intern_ty(arena, interner, ty_bool), + char: intern_ty(arena, interner, ty_char), + err: intern_ty(arena, interner, ty_err), + int: intern_ty(arena, interner, ty_int(ast::TyI)), + i8: intern_ty(arena, interner, ty_int(ast::TyI8)), + i16: intern_ty(arena, interner, ty_int(ast::TyI16)), + i32: intern_ty(arena, interner, ty_int(ast::TyI32)), + i64: intern_ty(arena, interner, ty_int(ast::TyI64)), + uint: intern_ty(arena, interner, ty_uint(ast::TyU)), + u8: intern_ty(arena, interner, ty_uint(ast::TyU8)), + u16: intern_ty(arena, interner, ty_uint(ast::TyU16)), + u32: intern_ty(arena, interner, ty_uint(ast::TyU32)), + u64: intern_ty(arena, interner, ty_uint(ast::TyU64)), + f32: intern_ty(arena, interner, ty_float(ast::TyF32)), + f64: intern_ty(arena, interner, ty_float(ast::TyF64)), + } + } +} + pub fn mk_ctxt<'tcx>(s: Session, arenas: &'tcx CtxtArenas<'tcx>, dm: DefMap, @@ -2084,13 +2293,18 @@ pub fn mk_ctxt<'tcx>(s: Session, capture_modes: RefCell, region_maps: middle::region::RegionMaps, lang_items: middle::lang_items::LanguageItems, - stability: stability::Index) -> ctxt<'tcx> { + stability: stability::Index) -> ctxt<'tcx> +{ + let mut interner = FnvHashMap::new(); + let common_types = CommonTypes::new(&arenas.type_, &mut interner); + ctxt { arenas: arenas, - interner: RefCell::new(FnvHashMap::new()), + interner: RefCell::new(interner), substs_interner: RefCell::new(FnvHashMap::new()), bare_fn_interner: RefCell::new(FnvHashMap::new()), region_interner: RefCell::new(FnvHashMap::new()), + types: common_types, named_region_map: named_region_map, item_variance_map: RefCell::new(DefIdMap::new()), variance_computed: Cell::new(false), @@ -2108,7 +2322,6 @@ pub fn mk_ctxt<'tcx>(s: Session, tcache: RefCell::new(DefIdMap::new()), rcache: RefCell::new(FnvHashMap::new()), short_names_cache: RefCell::new(FnvHashMap::new()), - needs_unwind_cleanup_cache: RefCell::new(FnvHashMap::new()), tc_cache: RefCell::new(FnvHashMap::new()), ast_ty_to_ty_cache: RefCell::new(NodeMap::new()), enum_var_cache: RefCell::new(DefIdMap::new()), @@ -2144,7 +2357,8 @@ pub fn mk_ctxt<'tcx>(s: Session, associated_types: RefCell::new(DefIdMap::new()), selection_cache: traits::SelectionCache::new(), repr_hint_cache: RefCell::new(DefIdMap::new()), - type_moves_by_default_cache: RefCell::new(HashMap::new()), + type_impls_copy_cache: RefCell::new(HashMap::new()), + type_impls_sized_cache: RefCell::new(HashMap::new()), } } @@ -2185,31 +2399,32 @@ impl<'tcx> ctxt<'tcx> { // Interns a type/name combination, stores the resulting box in cx.interner, // and returns the box as cast to an unsafe ptr (see comments for Ty above). pub fn mk_t<'tcx>(cx: &ctxt<'tcx>, st: sty<'tcx>) -> Ty<'tcx> { - // Check for primitive types. - match st { - ty_err => return mk_err(), - ty_bool => return mk_bool(), - ty_int(i) => return mk_mach_int(i), - ty_uint(u) => return mk_mach_uint(u), - ty_float(f) => return mk_mach_float(f), - ty_char => return mk_char(), - _ => {} - }; + let mut interner = cx.interner.borrow_mut(); + intern_ty(&cx.arenas.type_, &mut *interner, st) +} - match cx.interner.borrow().get(&st) { +fn intern_ty<'tcx>(type_arena: &'tcx TypedArena>, + interner: &mut FnvHashMap, Ty<'tcx>>, + st: sty<'tcx>) + -> Ty<'tcx> +{ + match interner.get(&st) { Some(ty) => return *ty, _ => () } let flags = FlagComputation::for_sty(&st); - let ty = cx.arenas.type_.alloc(TyS { + let ty = type_arena.alloc(TyS { sty: st, flags: flags.flags, region_depth: flags.depth, }); - cx.interner.borrow_mut().insert(InternedTy { ty: ty }, ty); + debug!("Interned type: {} Pointer: {}", + ty, ty as *const _); + + interner.insert(InternedTy { ty: ty }, ty); ty } @@ -2298,9 +2513,14 @@ impl FlagComputation { self.add_substs(substs); } + &ty_projection(ref data) => { + self.add_flags(HAS_PROJECTION); + self.add_substs(data.trait_ref.substs); + } + &ty_trait(box TyTrait { ref principal, ref bounds }) => { let mut computation = FlagComputation::new(); - computation.add_substs(principal.substs()); + computation.add_substs(principal.0.substs); self.add_bound_computation(&computation); self.add_bounds(bounds); @@ -2389,30 +2609,30 @@ impl FlagComputation { } } -pub fn mk_mach_int<'tcx>(tm: ast::IntTy) -> Ty<'tcx> { +pub fn mk_mach_int<'tcx>(tcx: &ctxt<'tcx>, tm: ast::IntTy) -> Ty<'tcx> { match tm { - ast::TyI => mk_int(), - ast::TyI8 => mk_i8(), - ast::TyI16 => mk_i16(), - ast::TyI32 => mk_i32(), - ast::TyI64 => mk_i64(), + ast::TyI => tcx.types.int, + ast::TyI8 => tcx.types.i8, + ast::TyI16 => tcx.types.i16, + ast::TyI32 => tcx.types.i32, + ast::TyI64 => tcx.types.i64, } } -pub fn mk_mach_uint<'tcx>(tm: ast::UintTy) -> Ty<'tcx> { +pub fn mk_mach_uint<'tcx>(tcx: &ctxt<'tcx>, tm: ast::UintTy) -> Ty<'tcx> { match tm { - ast::TyU => mk_uint(), - ast::TyU8 => mk_u8(), - ast::TyU16 => mk_u16(), - ast::TyU32 => mk_u32(), - ast::TyU64 => mk_u64(), + ast::TyU => tcx.types.uint, + ast::TyU8 => tcx.types.u8, + ast::TyU16 => tcx.types.u16, + ast::TyU32 => tcx.types.u32, + ast::TyU64 => tcx.types.u64, } } -pub fn mk_mach_float<'tcx>(tm: ast::FloatTy) -> Ty<'tcx> { +pub fn mk_mach_float<'tcx>(tcx: &ctxt<'tcx>, tm: ast::FloatTy) -> Ty<'tcx> { match tm { - ast::TyF32 => mk_f32(), - ast::TyF64 => mk_f64(), + ast::TyF32 => tcx.types.f32, + ast::TyF64 => tcx.types.f64, } } @@ -2508,12 +2728,13 @@ pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>, })) } - pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, principal: ty::PolyTraitRef<'tcx>, - bounds: ExistentialBounds) - -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside + bounds: ExistentialBounds<'tcx>) + -> Ty<'tcx> +{ + assert!(bound_list_is_sorted(bounds.projection_bounds.as_slice())); + let inner = box TyTrait { principal: principal, bounds: bounds @@ -2521,6 +2742,25 @@ pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, mk_t(cx, ty_trait(inner)) } +fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool { + bounds.len() == 0 || + bounds[1..].iter().enumerate().all( + |(index, bound)| bounds[index].sort_key() <= bound.sort_key()) +} + +pub fn sort_bounds_list(bounds: &mut [ty::PolyProjectionPredicate]) { + bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())) +} + +pub fn mk_projection<'tcx>(cx: &ctxt<'tcx>, + trait_ref: Rc>, + item_name: ast::Name) + -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name }; + mk_t(cx, ty_projection(inner)) +} + pub fn mk_struct<'tcx>(cx: &ctxt<'tcx>, struct_id: ast::DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside @@ -2549,17 +2789,19 @@ pub fn mk_infer<'tcx>(cx: &ctxt<'tcx>, it: InferTy) -> Ty<'tcx> { mk_t(cx, ty_infer(it)) } -pub fn mk_param<'tcx>(cx: &ctxt<'tcx>, space: subst::ParamSpace, - n: u32, k: DefId) -> Ty<'tcx> { - mk_t(cx, ty_param(ParamTy { space: space, idx: n, def_id: k })) +pub fn mk_param<'tcx>(cx: &ctxt<'tcx>, + space: subst::ParamSpace, + index: u32, + name: ast::Name) -> Ty<'tcx> { + mk_t(cx, ty_param(ParamTy { space: space, idx: index, name: name })) } -pub fn mk_self_type<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) -> Ty<'tcx> { - mk_param(cx, subst::SelfSpace, 0, did) +pub fn mk_self_type<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> { + mk_param(cx, subst::SelfSpace, 0, special_idents::type_self.name) } pub fn mk_param_from_def<'tcx>(cx: &ctxt<'tcx>, def: &TypeParameterDef) -> Ty<'tcx> { - mk_param(cx, def.space, def.index, def.def_id) + mk_param(cx, def.space, def.index, def.name) } pub fn mk_open<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { mk_t(cx, ty_open(ty)) } @@ -2583,7 +2825,12 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) { maybe_walk_ty(tm.ty, f); } ty_trait(box TyTrait { ref principal, .. }) => { - for subty in principal.substs().types.iter() { + for subty in principal.0.substs.types.iter() { + maybe_walk_ty(*subty, |x| f(x)); + } + } + ty_projection(ProjectionTy { ref trait_ref, .. }) => { + for subty in trait_ref.substs.types.iter() { maybe_walk_ty(*subty, |x| f(x)); } } @@ -2623,21 +2870,21 @@ pub fn fold_ty<'tcx, F>(cx: &ctxt<'tcx>, t0: Ty<'tcx>, impl ParamTy { pub fn new(space: subst::ParamSpace, index: u32, - def_id: ast::DefId) + name: ast::Name) -> ParamTy { - ParamTy { space: space, idx: index, def_id: def_id } + ParamTy { space: space, idx: index, name: name } } - pub fn for_self(trait_def_id: ast::DefId) -> ParamTy { - ParamTy::new(subst::SelfSpace, 0, trait_def_id) + pub fn for_self() -> ParamTy { + ParamTy::new(subst::SelfSpace, 0, special_idents::type_self.name) } pub fn for_def(def: &TypeParameterDef) -> ParamTy { - ParamTy::new(def.space, def.index, def.def_id) + ParamTy::new(def.space, def.index, def.name) } pub fn to_ty<'tcx>(self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { - ty::mk_param(tcx, self.space, self.idx, self.def_id) + ty::mk_param(tcx, self.space, self.idx, self.name) } pub fn is_self(&self) -> bool { @@ -2661,6 +2908,7 @@ impl<'tcx> ParamBounds<'tcx> { builtin_bounds: empty_builtin_bounds(), trait_bounds: Vec::new(), region_bounds: Vec::new(), + projection_bounds: Vec::new(), } } } @@ -2742,7 +2990,7 @@ pub fn type_is_simd(cx: &ctxt, ty: Ty) -> bool { pub fn sequence_element_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { match ty.sty { ty_vec(ty, _) => ty, - ty_str => mk_mach_uint(ast::TyU8), + ty_str => mk_mach_uint(cx, ast::TyU8), ty_open(ty) => sequence_element_type(cx, ty), _ => cx.sess.bug(format!("sequence_element_type called on non-sequence value: {}", ty_to_string(cx, ty))[]), @@ -2793,14 +3041,6 @@ pub fn type_is_unique(ty: Ty) -> bool { } } -pub fn type_is_fat_ptr<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.sty { - ty_ptr(mt{ty, ..}) | ty_rptr(_, mt{ty, ..}) - | ty_uniq(ty) if !type_is_sized(cx, ty) => true, - _ => false, - } -} - /* A scalar type is one that denotes an atomic datum, with no sub-components. (A ty_ptr is scalar because it represents a non-managed pointer, so its @@ -2824,48 +3064,6 @@ pub fn type_is_floating_point(ty: Ty) -> bool { } } -pub fn type_needs_drop<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - type_contents(cx, ty).needs_drop(cx) -} - -// 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<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - return memoized(&cx.needs_unwind_cleanup_cache, ty, |ty| { - type_needs_unwind_cleanup_(cx, ty, &mut FnvHashSet::new()) - }); - - fn type_needs_unwind_cleanup_<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>, - tycache: &mut FnvHashSet>) -> bool { - // Prevent infinite recursion - if !tycache.insert(ty) { - return false; - } - - let mut needs_unwind_cleanup = false; - maybe_walk_ty(ty, |ty| { - needs_unwind_cleanup |= match ty.sty { - ty_bool | ty_int(_) | ty_uint(_) | - ty_float(_) | ty_tup(_) | ty_ptr(_) => false, - - ty_enum(did, substs) => - enum_variants(cx, did).iter().any(|v| - v.args.iter().any(|aty| { - let t = aty.subst(cx, substs); - type_needs_unwind_cleanup_(cx, t, tycache) - }) - ), - - _ => true - }; - !needs_unwind_cleanup - }); - needs_unwind_cleanup - } -} - /// Type contents is how the type checker reasons about kinds. /// They track what kinds of things are found within a type. You can /// think of them as kind of an "anti-kind". They track the kinds of values @@ -2901,6 +3099,7 @@ def_type_content_sets! { // Things that are interior to the value (first nibble): InteriorUnsized = 0b0000_0000__0000_0000__0001, InteriorUnsafe = 0b0000_0000__0000_0000__0010, + InteriorParam = 0b0000_0000__0000_0000__0100, // InteriorAll = 0b00000000__00000000__1111, // Things that are owned by the value (second and third nibbles): @@ -2955,6 +3154,10 @@ impl TypeContents { !self.intersects(TC::Nonsized) } + pub fn interior_param(&self) -> bool { + self.intersects(TC::InteriorParam) + } + pub fn interior_unsafe(&self) -> bool { self.intersects(TC::InteriorUnsafe) } @@ -3083,7 +3286,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } ty_closure(ref c) => { - closure_contents(cx, &**c) | TC::ReachesFfiUnsafe + closure_contents(&**c) | TC::ReachesFfiUnsafe } ty_uniq(typ) => { @@ -3093,8 +3296,8 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { } } - ty_trait(box TyTrait { bounds, .. }) => { - object_contents(cx, bounds) | TC::ReachesFfiUnsafe | TC::Nonsized + ty_trait(box TyTrait { ref bounds, .. }) => { + object_contents(bounds) | TC::ReachesFfiUnsafe | TC::Nonsized } ty_ptr(ref mt) => { @@ -3204,26 +3407,8 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { apply_lang_items(cx, did, res) } - ty_param(p) => { - // We only ever ask for the kind of types that are defined in - // the current crate; therefore, the only type parameters that - // could be in scope are those defined in the current crate. - // If this assertion fails, it is likely because of a - // failure of the cross-crate inlining code to translate a - // def-id. - assert_eq!(p.def_id.krate, ast::LOCAL_CRATE); - - let ty_param_defs = cx.ty_param_defs.borrow(); - let tp_def = &(*ty_param_defs)[p.def_id.node]; - kind_bounds_to_contents( - cx, - tp_def.bounds.builtin_bounds, - tp_def.bounds.trait_bounds[]) - } - - ty_infer(_) => { - // This occurs during coherence, but shouldn't occur at other - // times. + ty_projection(..) | + ty_param(_) => { TC::All } @@ -3233,6 +3418,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { result.unsafe_pointer() | TC::Nonsized } + ty_infer(_) | ty_err => { cx.sess.bug("asked to compute contents of error type"); } @@ -3272,10 +3458,10 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { b | (TC::ReachesBorrowed).when(region != ty::ReStatic) } - fn closure_contents(cx: &ctxt, cty: &ClosureTy) -> TypeContents { + fn closure_contents(cty: &ClosureTy) -> TypeContents { // Closure contents are just like trait contents, but with potentially // even more stuff. - let st = object_contents(cx, cty.bounds); + let st = object_contents(&cty.bounds); let st = match cty.store { UniqTraitStore => { @@ -3289,61 +3475,37 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { st } - fn object_contents(cx: &ctxt, - bounds: ExistentialBounds) - -> TypeContents { - // These are the type contents of the (opaque) interior - kind_bounds_to_contents(cx, bounds.builtin_bounds, &[]) - } - - fn kind_bounds_to_contents<'tcx>(cx: &ctxt<'tcx>, - bounds: BuiltinBounds, - traits: &[Rc>]) - -> TypeContents { - let _i = indenter(); - let mut tc = TC::All; - each_inherited_builtin_bound(cx, bounds, traits, |bound| { + fn object_contents(bounds: &ExistentialBounds) -> TypeContents { + // These are the type contents of the (opaque) interior. We + // make no assumptions (other than that it cannot have an + // in-scope type parameter within, which makes no sense). + let mut tc = TC::All - TC::InteriorParam; + for bound in bounds.builtin_bounds.iter() { tc = tc - match bound { BoundSync | BoundSend | BoundCopy => TC::None, BoundSized => TC::Nonsized, }; - }); - return tc; - - // Iterates over all builtin bounds on the type parameter def, including - // those inherited from traits with builtin-kind-supertraits. - fn each_inherited_builtin_bound<'tcx, F>(cx: &ctxt<'tcx>, - bounds: BuiltinBounds, - traits: &[Rc>], - mut f: F) where - F: FnMut(BuiltinBound), - { - for bound in bounds.iter() { - f(bound); - } - - each_bound_trait_and_supertraits(cx, traits, |trait_ref| { - let trait_def = lookup_trait_def(cx, trait_ref.def_id()); - for bound in trait_def.bounds.builtin_bounds.iter() { - f(bound); - } - true - }); } + return tc; } } -pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>, - ty: Ty<'tcx>, - param_env: &ParameterEnvironment<'tcx>) - -> bool +fn type_impls_bound<'tcx>(cx: &ctxt<'tcx>, + cache: &RefCell,bool>>, + param_env: &ParameterEnvironment<'tcx>, + ty: Ty<'tcx>, + bound: ty::BuiltinBound) + -> bool { + assert!(!ty::type_needs_infer(ty)); + if !type_has_params(ty) && !type_has_self(ty) { - match cx.type_moves_by_default_cache.borrow().get(&ty) { + match cache.borrow().get(&ty) { None => {} Some(&result) => { - debug!("determined whether {} moves by default (cached): {}", + debug!("type_impls_bound({}, {}) = {} (cached)", ty_to_string(cx, ty), + bound, result); return result } @@ -3351,27 +3513,35 @@ pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>, } let infcx = infer::new_infer_ctxt(cx); - let mut fulfill_cx = traits::FulfillmentContext::new(); + let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound); - // 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, DUMMY_NODE_ID); + debug!("type_impls_bound({}, {}) = {}", + ty_to_string(cx, ty), + bound, + is_impld); - fulfill_cx.register_builtin_bound(cx, ty, ty::BoundCopy, cause); + if !type_has_params(ty) && !type_has_self(ty) { + let old_value = cache.borrow_mut().insert(ty, is_impld); + assert!(old_value.is_none()); + } - // Note: we only assuming something is `Copy` if we can - // *definitively* show that it implements `Copy`. Otherwise, - // assume it is move; linear is always ok. - let is_copy = fulfill_cx.select_all_or_error(&infcx, param_env, cx).is_ok(); - let is_move = !is_copy; + is_impld +} - debug!("determined whether {} moves by default: {}", - ty_to_string(cx, ty), - is_move); +pub fn type_moves_by_default<'tcx>(cx: &ctxt<'tcx>, + ty: Ty<'tcx>, + param_env: &ParameterEnvironment<'tcx>) + -> bool +{ + !type_impls_bound(cx, &cx.type_impls_copy_cache, param_env, ty, ty::BoundCopy) +} - cx.type_moves_by_default_cache.borrow_mut().insert(ty, is_move); - is_move +pub fn type_is_sized<'tcx>(cx: &ctxt<'tcx>, + ty: Ty<'tcx>, + param_env: &ParameterEnvironment<'tcx>) + -> bool +{ + type_impls_bound(cx, &cx.type_impls_sized_cache, param_env, ty, ty::BoundSized) } pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool { @@ -3419,6 +3589,7 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool { ty_infer(_) | ty_err | ty_param(_) | + ty_projection(_) | ty_vec(_, None) => { false } @@ -3743,40 +3914,6 @@ pub fn type_is_machine(ty: Ty) -> bool { } } -// Is the type's representation size known at compile time? -pub fn type_is_sized<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - type_contents(cx, ty).is_sized(cx) -} - -pub fn lltype_is_sized<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.sty { - ty_open(_) => true, - _ => type_contents(cx, ty).is_sized(cx) - } -} - -// 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: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { - ty_str | ty_trait(..) | ty_vec(..) => ty, - ty_struct(def_id, substs) => { - let unsized_fields: Vec<_> = 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"); - } - } -} - // Whether a type is enum like, that is an enum type with only nullary // constructors pub fn type_is_c_like_enum(cx: &ctxt, ty: Ty) -> bool { @@ -3846,10 +3983,10 @@ pub fn index<'tcx>(ty: Ty<'tcx>) -> Option> { // Returns the type of elements contained within an 'array-like' type. // This is exactly the same as the above, except it supports strings, // which can't actually be indexed. -pub fn array_element_ty<'tcx>(ty: Ty<'tcx>) -> Option> { +pub fn array_element_ty<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Option> { match ty.sty { ty_vec(ty, _) => Some(ty), - ty_str => Some(mk_u8()), + ty_str => Some(tcx.types.u8), _ => None } } @@ -4138,6 +4275,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, let bounds = ty::ExistentialBounds { region_bound: ReStatic, builtin_bounds: all_builtin_bounds(), + projection_bounds: vec!(), }; ty::mk_closure( @@ -4272,8 +4410,8 @@ pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>, format!("UnsizeStruct with bad sty: {}", ty_to_string(cx, ty))[]) }, - &UnsizeVtable(TyTrait { ref principal, bounds }, _) => { - mk_trait(cx, (*principal).clone(), bounds) + &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { + mk_trait(cx, principal.clone(), bounds.clone()) } } } @@ -4529,7 +4667,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_bare_fn(None, _) => "fn pointer".to_string(), ty_closure(_) => "fn".to_string(), ty_trait(ref inner) => { - format!("trait {}", item_path_str(cx, inner.principal.def_id())) + format!("trait {}", item_path_str(cx, inner.principal_def_id())) } ty_struct(id, _) => { format!("struct {}", item_path_str(cx, id)) @@ -4541,6 +4679,7 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { ty_infer(FloatVar(_)) => "floating-point variable".to_string(), ty_infer(FreshTy(_)) => "skolemized type".to_string(), ty_infer(FreshIntTy(_)) => "skolemized integral type".to_string(), + ty_projection(_) => "associated type".to_string(), ty_param(ref p) => { if p.space == subst::SelfSpace { "Self".to_string() @@ -4553,6 +4692,12 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String { } } +impl<'tcx> Repr<'tcx> for ty::type_err<'tcx> { + fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { + ty::type_err_to_str(tcx, self) + } +} + /// Explains the source of a type err in a short, human readable way. This is meant to be placed /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` /// afterwards to present additional details, particularly when it comes to lifetime-related @@ -4692,6 +4837,16 @@ pub fn type_err_to_str<'tcx>(cx: &ctxt<'tcx>, err: &type_err<'tcx>) -> String { if values.expected { "converging" } else { "diverging" }, if values.found { "converging" } else { "diverging" }) } + terr_projection_name_mismatched(ref values) => { + format!("expected {}, found {}", + token::get_name(values.expected), + token::get_name(values.found)) + } + terr_projection_bounds_length(ref values) => { + format!("expected {} associated type bindings, found {}", + values.expected, + values.found) + } } } @@ -4952,7 +5107,7 @@ pub fn try_add_builtin_trait( pub fn ty_to_def_id(ty: Ty) -> Option { match ty.sty { ty_trait(ref tt) => - Some(tt.principal.def_id()), + Some(tt.principal_def_id()), ty_struct(id, _) | ty_enum(id, _) | ty_unboxed_closure(id, _, _) => @@ -5193,7 +5348,7 @@ pub fn enum_variant_with_id<'tcx>(cx: &ctxt<'tcx>, // the type cache. Returns the type parameters and type. pub fn lookup_item_type<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) - -> Polytype<'tcx> { + -> TypeScheme<'tcx> { lookup_locally_or_in_crate_store( "tcache", did, &mut *cx.tcache.borrow_mut(), || csearch::get_type(cx, did)) @@ -5209,7 +5364,12 @@ pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId) } /// Given a reference to a trait, returns the "superbounds" declared -/// on the trait, with appropriate substitutions applied. +/// on the trait, with appropriate substitutions applied. Basically, +/// this applies a filter to the where clauses on the trait, returning +/// those that have the form: +/// +/// Self : SuperTrait<...> +/// Self : 'region pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, trait_ref: &PolyTraitRef<'tcx>) -> Vec> @@ -5286,13 +5446,7 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, let trait_bounds: Vec<_> = trait_def.bounds.trait_bounds .iter() - .map(|bound_trait_ref| { - let substs = tcx.mk_substs(bound_trait_ref.substs().subst(tcx, trait_ref.substs())); - ty::Binder( - ty::TraitRef::new(bound_trait_ref.def_id(), - substs)) - }) - .map(|bound_trait_ref| Rc::new(bound_trait_ref)) + .map(|poly_trait_ref| ty::Binder(poly_trait_ref.0.subst(tcx, trait_ref.substs()))) .collect(); debug!("bounds_for_trait_ref: trait_bounds={}", @@ -5309,6 +5463,11 @@ pub fn predicates_for_trait_ref<'tcx>(tcx: &ctxt<'tcx>, trait_bounds: trait_bounds, region_bounds: region_bounds, builtin_bounds: builtin_bounds, + + // FIXME(#19451) -- if a trait has a bound like `trait Foo : + // Bar`, we should probably be returning that, but this + // code here will just ignore it. + projection_bounds: Vec::new(), }; predicates(tcx, trait_ref.self_ty(), &bounds) @@ -5323,7 +5482,7 @@ pub fn predicates<'tcx>( let mut vec = Vec::new(); for builtin_bound in bounds.builtin_bounds.iter() { - match traits::poly_trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { + match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) { Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); } Err(ErrorReported) => { } } @@ -5340,6 +5499,10 @@ pub fn predicates<'tcx>( vec.push(bound_trait_ref.as_predicate()); } + for projection in bounds.projection_bounds.iter() { + vec.push(projection.as_predicate()); + } + vec } @@ -5675,10 +5838,10 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint { // relation on the supertraits from each bounded trait's constraint // list. pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, - bounds: &[Rc>], + bounds: &[PolyTraitRef<'tcx>], mut f: F) -> bool where - F: FnMut(Rc>) -> bool, + F: FnMut(PolyTraitRef<'tcx>) -> bool, { for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { if !f(bound_trait_ref) { @@ -5688,10 +5851,11 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>, return true; } -pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, - opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures - others: BuiltinBounds) - -> Vec +pub fn object_region_bounds<'tcx>( + tcx: &ctxt<'tcx>, + opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures + others: BuiltinBounds) + -> Vec { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically @@ -5699,14 +5863,17 @@ pub fn object_region_bounds<'tcx>(tcx: &ctxt<'tcx>, let open_ty = ty::mk_infer(tcx, FreshTy(0)); let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| { - let substs = principal.substs().with_self_ty(open_ty); - vec!(Rc::new(ty::Binder(ty::TraitRef::new(principal.def_id(), tcx.mk_substs(substs))))) + // Note that we preserve the overall binding levels here. + assert!(!open_ty.has_escaping_regions()); + let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty)); + vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs)))) }); let param_bounds = ty::ParamBounds { region_bounds: Vec::new(), builtin_bounds: others, trait_bounds: opt_trait_ref, + projection_bounds: Vec::new(), // not relevant to computing region bounds }; let predicates = ty::predicates(tcx, open_ty, ¶m_bounds); @@ -5737,6 +5904,7 @@ pub fn required_region_bounds<'tcx>(tcx: &ctxt<'tcx>, traits::elaborate_predicates(tcx, predicates) .filter_map(|predicate| { match predicate { + ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) => { @@ -6088,12 +6256,12 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - return false; } - ty_trait(box TyTrait { ref principal, bounds }) => { + ty_trait(ref data) => { byte!(17); - did(state, principal.def_id()); - hash!(bounds); + did(state, data.principal_def_id()); + hash!(data.bounds); - let principal = anonymize_late_bound_regions(tcx, principal); + let principal = anonymize_late_bound_regions(tcx, &data.principal); for subty in principal.substs.types.iter() { helper(tcx, *subty, svh, state); } @@ -6110,8 +6278,9 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - } ty_param(p) => { byte!(20); + hash!(p.space); hash!(p.idx); - did(state, p.def_id); + hash!(token::get_name(p.name)); } ty_open(_) => byte!(22), ty_infer(_) => unreachable!(), @@ -6121,6 +6290,11 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - did(state, d); region(state, *r); } + ty_projection(ref data) => { + byte!(25); + did(state, data.trait_ref.def_id); + hash!(token::get_name(data.item_name)); + } } true }); @@ -6161,17 +6335,11 @@ pub fn construct_parameter_environment<'tcx>( // map T => T let mut types = VecPerParamSpace::empty(); - for &space in subst::ParamSpace::all().iter() { - push_types_from_defs(tcx, &mut types, space, - generics.types.get_slice(space)); - } + push_types_from_defs(tcx, &mut types, generics.types.as_slice()); // map bound 'a => free 'a let mut regions = VecPerParamSpace::empty(); - for &space in subst::ParamSpace::all().iter() { - push_region_params(&mut regions, space, free_id, - generics.regions.get_slice(space)); - } + push_region_params(&mut regions, free_id, generics.regions.as_slice()); let free_substs = Substs { types: types, @@ -6208,27 +6376,22 @@ pub fn construct_parameter_environment<'tcx>( }; fn push_region_params(regions: &mut VecPerParamSpace, - space: subst::ParamSpace, free_id: ast::NodeId, region_params: &[RegionParameterDef]) { for r in region_params.iter() { - regions.push(space, ty::free_region_from_def(free_id, r)); + regions.push(r.space, ty::free_region_from_def(free_id, r)); } } fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>, types: &mut subst::VecPerParamSpace>, - space: subst::ParamSpace, defs: &[TypeParameterDef<'tcx>]) { - for (i, def) in defs.iter().enumerate() { - debug!("construct_parameter_environment(): push_types_from_defs: \ - space={} def={} index={}", - space, - def.repr(tcx), - i); - let ty = ty::mk_param(tcx, space, i as u32, def.def_id); - types.push(space, ty); + for def in defs.iter() { + debug!("construct_parameter_environment(): push_types_from_defs: def={}", + def.repr(tcx)); + let ty = ty::mk_param_from_def(tcx, def); + types.push(def.space, ty); } } @@ -6237,7 +6400,10 @@ pub fn construct_parameter_environment<'tcx>( for predicate in bounds.predicates.iter() { match *predicate { - Predicate::Trait(..) | Predicate::Equate(..) | Predicate::TypeOutlives(..) => { + Predicate::Projection(..) | + Predicate::Trait(..) | + Predicate::Equate(..) | + Predicate::TypeOutlives(..) => { // No region bounds here } Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { @@ -6364,7 +6530,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, accumulator.push(*region) } ty_trait(ref t) => { - accumulator.push_all(t.principal.substs().regions().as_slice()); + accumulator.push_all(t.principal.0.substs.regions().as_slice()); } ty_enum(_, substs) | ty_struct(_, substs) => { @@ -6391,6 +6557,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, ty_ptr(_) | ty_bare_fn(..) | ty_tup(_) | + ty_projection(_) | ty_param(_) | ty_infer(_) | ty_open(_) | @@ -6481,6 +6648,15 @@ pub fn count_late_bound_regions<'tcx, T>( skol_map.len() } +pub fn binds_late_bound_regions<'tcx, T>( + tcx: &ty::ctxt<'tcx>, + value: &Binder) + -> bool + where T : TypeFoldable<'tcx> + Repr<'tcx> +{ + count_late_bound_regions(tcx, value) > 0 +} + /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also /// method lookup and a few other places where precise region relationships are not required. pub fn erase_late_bound_regions<'tcx, T>( @@ -6621,9 +6797,10 @@ impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { Predicate::Trait(ref a) => a.repr(tcx), - Predicate::Equate(ref pair) => format!("Equate({})", pair.repr(tcx)), - Predicate::RegionOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), - Predicate::TypeOutlives(ref pair) => format!("Outlives({})", pair.repr(tcx)), + Predicate::Equate(ref pair) => pair.repr(tcx), + Predicate::RegionOutlives(ref pair) => pair.repr(tcx), + Predicate::TypeOutlives(ref pair) => pair.repr(tcx), + Predicate::Projection(ref pair) => pair.repr(tcx), } } } @@ -6719,6 +6896,11 @@ pub fn can_type_implement_copy<'tcx>(tcx: &ctxt<'tcx>, Ok(()) } +// FIXME(#20298) -- all of these types basically walk various +// structures to test whether types/regions are reachable with various +// properties. It should be possible to express them in terms of one +// common "walker" trait or something. + pub trait RegionEscape { fn has_escaping_regions(&self) -> bool { self.has_regions_escaping_depth(0) @@ -6741,8 +6923,19 @@ impl RegionEscape for Region { impl<'tcx> RegionEscape for TraitRef<'tcx> { fn has_regions_escaping_depth(&self, depth: u32) -> bool { - self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) && - self.substs.regions().iter().any(|t| t.has_regions_escaping_depth(depth)) + self.substs.types.iter().any(|t| t.has_regions_escaping_depth(depth)) || + self.substs.regions.has_regions_escaping_depth(depth) + } +} + +impl<'tcx> RegionEscape for subst::RegionSubsts { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + match *self { + subst::ErasedRegions => false, + subst::NonerasedRegions(ref r) => { + r.iter().any(|t| t.has_regions_escaping_depth(depth)) + } + } } } @@ -6758,8 +6951,239 @@ impl<'tcx> RegionEscape for EquatePredicate<'tcx> { } } +impl<'tcx> RegionEscape for TraitPredicate<'tcx> { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.trait_ref.has_regions_escaping_depth(depth) + } +} + impl RegionEscape for OutlivesPredicate { fn has_regions_escaping_depth(&self, depth: u32) -> bool { self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth) } } + +impl<'tcx> RegionEscape for ProjectionPredicate<'tcx> { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.projection_ty.has_regions_escaping_depth(depth) || + self.ty.has_regions_escaping_depth(depth) + } +} + +impl<'tcx> RegionEscape for ProjectionTy<'tcx> { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.trait_ref.has_regions_escaping_depth(depth) + } +} + +impl<'tcx> Repr<'tcx> for ty::ProjectionPredicate<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("ProjectionPredicate({}, {})", + self.projection_ty.repr(tcx), + self.ty.repr(tcx)) + } +} + +pub trait HasProjectionTypes { + fn has_projection_types(&self) -> bool; +} + +impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> { + fn has_projection_types(&self) -> bool { + self.predicates.iter().any(|p| p.has_projection_types()) + } +} + +impl<'tcx> HasProjectionTypes for Predicate<'tcx> { + fn has_projection_types(&self) -> bool { + match *self { + Predicate::Trait(ref data) => data.has_projection_types(), + Predicate::Equate(ref data) => data.has_projection_types(), + Predicate::RegionOutlives(ref data) => data.has_projection_types(), + Predicate::TypeOutlives(ref data) => data.has_projection_types(), + Predicate::Projection(ref data) => data.has_projection_types(), + } + } +} + +impl<'tcx> HasProjectionTypes for TraitPredicate<'tcx> { + fn has_projection_types(&self) -> bool { + self.trait_ref.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for EquatePredicate<'tcx> { + fn has_projection_types(&self) -> bool { + self.0.has_projection_types() || self.1.has_projection_types() + } +} + +impl HasProjectionTypes for Region { + fn has_projection_types(&self) -> bool { + false + } +} + +impl HasProjectionTypes for OutlivesPredicate { + fn has_projection_types(&self) -> bool { + self.0.has_projection_types() || self.1.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for ProjectionPredicate<'tcx> { + fn has_projection_types(&self) -> bool { + self.projection_ty.has_projection_types() || self.ty.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for ProjectionTy<'tcx> { + fn has_projection_types(&self) -> bool { + self.trait_ref.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for Ty<'tcx> { + fn has_projection_types(&self) -> bool { + ty::type_has_projection(*self) + } +} + +impl<'tcx> HasProjectionTypes for TraitRef<'tcx> { + fn has_projection_types(&self) -> bool { + self.substs.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for subst::Substs<'tcx> { + fn has_projection_types(&self) -> bool { + self.types.iter().any(|t| t.has_projection_types()) + } +} + +impl<'tcx,T> HasProjectionTypes for Option + where T : HasProjectionTypes +{ + fn has_projection_types(&self) -> bool { + self.iter().any(|t| t.has_projection_types()) + } +} + +impl<'tcx,T> HasProjectionTypes for Rc + where T : HasProjectionTypes +{ + fn has_projection_types(&self) -> bool { + (**self).has_projection_types() + } +} + +impl<'tcx,T> HasProjectionTypes for Box + where T : HasProjectionTypes +{ + fn has_projection_types(&self) -> bool { + (**self).has_projection_types() + } +} + +impl HasProjectionTypes for Binder + where T : HasProjectionTypes +{ + fn has_projection_types(&self) -> bool { + self.0.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for FnOutput<'tcx> { + fn has_projection_types(&self) -> bool { + match *self { + FnConverging(t) => t.has_projection_types(), + FnDiverging => false, + } + } +} + +impl<'tcx> HasProjectionTypes for FnSig<'tcx> { + fn has_projection_types(&self) -> bool { + self.inputs.iter().any(|t| t.has_projection_types()) || + self.output.has_projection_types() + } +} + +impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> { + fn has_projection_types(&self) -> bool { + self.sig.has_projection_types() + } +} + +pub trait ReferencesError { + fn references_error(&self) -> bool; +} + +impl ReferencesError for Binder { + fn references_error(&self) -> bool { + self.0.references_error() + } +} + +impl ReferencesError for Rc { + fn references_error(&self) -> bool { + (&*self).references_error() + } +} + +impl<'tcx> ReferencesError for TraitPredicate<'tcx> { + fn references_error(&self) -> bool { + self.trait_ref.references_error() + } +} + +impl<'tcx> ReferencesError for ProjectionPredicate<'tcx> { + fn references_error(&self) -> bool { + self.projection_ty.trait_ref.references_error() || self.ty.references_error() + } +} + +impl<'tcx> ReferencesError for TraitRef<'tcx> { + fn references_error(&self) -> bool { + self.input_types().iter().any(|t| t.references_error()) + } +} + +impl<'tcx> ReferencesError for Ty<'tcx> { + fn references_error(&self) -> bool { + type_is_error(*self) + } +} + +impl<'tcx> ReferencesError for Predicate<'tcx> { + fn references_error(&self) -> bool { + match *self { + Predicate::Trait(ref data) => data.references_error(), + Predicate::Equate(ref data) => data.references_error(), + Predicate::RegionOutlives(ref data) => data.references_error(), + Predicate::TypeOutlives(ref data) => data.references_error(), + Predicate::Projection(ref data) => data.references_error(), + } + } +} + +impl ReferencesError for OutlivesPredicate + where A : ReferencesError, B : ReferencesError +{ + fn references_error(&self) -> bool { + self.0.references_error() || self.1.references_error() + } +} + +impl<'tcx> ReferencesError for EquatePredicate<'tcx> +{ + fn references_error(&self) -> bool { + self.0.references_error() || self.1.references_error() + } +} + +impl ReferencesError for Region +{ + fn references_error(&self) -> bool { + false + } +} diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 782b464ed96d5..1e7605c0f171c 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -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 { } } +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box { + fn fold_with>(&self, folder: &mut F) -> Box { + let content: T = (**self).fold_with(folder); + box content + } +} + impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec { fn fold_with>(&self, folder: &mut F) -> Vec { 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>(&self, folder: &mut F) -> ty::ExistentialBounds { - folder.fold_existential_bounds(*self) +impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialBounds<'tcx> { + fn fold_with>(&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>(&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>(&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>(&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>(&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>(&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 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), } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3a383dd5a3b7c..9639af5ca1cd5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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 { 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!("", 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), } } } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index fdb13ecabde81..2062685f4c866 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -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); } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index c0e892cdd2798..7854c8acb4796 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -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); } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 941155ac5e7e3..6329acfb57805 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -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(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)); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7f01bf087381b..52bd096eb83de 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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); diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index a798d09872ca2..0e37cd0f3b8d6 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -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 diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 595d252a0b1a0..d01047c53b955 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -163,7 +163,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }).collect::>(); 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 { match ty.sty { // Fat &T/&mut T/Box 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 = 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 { 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| { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f0d738d839d7a..c5d3ad805d934 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -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); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index a159cda9fbaed..169e52bcfe5be 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -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) { diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index f96aa484ffc95..b4deea4c72fc8 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -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 } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 0ae9de8c89183..ed3c820f2faf4 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -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>, diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index b15b75c6715b7..06819aac5bc04 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -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>) + -> 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(&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(&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>) + 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, diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index bc386dc96a469..0fd6d286e8b2d 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -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, diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 2c71dd831fbcb..9ceb0c6399093 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -84,6 +84,7 @@ pub struct LocalCrateContext<'tcx> { tn: TypeNames, externs: RefCell, item_vals: RefCell>, + needs_unwind_cleanup_cache: RefCell, bool>>, fn_pointer_shims: RefCell, ValueRef>>, drop_glues: RefCell, ValueRef>>, tydescs: RefCell, Rc>>>, @@ -99,7 +100,7 @@ pub struct LocalCrateContext<'tcx> { monomorphized: RefCell, ValueRef>>, monomorphizing: RefCell>, /// Cache generated vtables - vtables: RefCell, Rc>), ValueRef>>, + vtables: RefCell, ty::PolyTraitRef<'tcx>), ValueRef>>, /// Cache of constant strings, const_cstr_cache: RefCell>, @@ -150,7 +151,7 @@ pub struct LocalCrateContext<'tcx> { /// contexts around the same size. n_llvm_insns: Cell, - trait_cache: RefCell>, + trait_cache: RefCell, 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, bool>> { + &self.local.needs_unwind_cleanup_cache + } + pub fn fn_pointer_shims(&self) -> &RefCell, 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, Rc>), + pub fn vtables<'a>(&'a self) -> &'a RefCell, 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>, + pub fn trait_cache(&self) -> &RefCell, traits::Vtable<'tcx, ()>>> { &self.local.trait_cache } diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 3b24ded6717cc..768de89d5935d 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -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) diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 9ab4e92b51131..83bf06383a89c 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -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) diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 56c42c7afdeb8..b5b1c6ff86479 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -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))[]); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index f49769ba0d9c6..5a20a297fdb09 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -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 diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 1bad476863fdb..e234d77914b64 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -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)); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index e0a878c8261ef..ab5c670ef5a2d 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -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` 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 { diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index fff89999d99b5..d49018e00c1cb 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -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 { 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); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 553613a8eac0e..9535ffaec0e6a 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -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>) + 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>, + trait_ref: ty::PolyTraitRef<'tcx>, dest: expr::Dest) -> Block<'blk, 'tcx> { let mut bcx = bcx; diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 2a6aff56513a1..3b7043e4f40f0 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -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> } + +/// 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) + } + } + } +} diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index e09032ac2d04f..688a0d0725058 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -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 { diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 499195b51b9ce..0bc35390cd7c0 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -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"), }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d6f1f5fedc581..587a85cfcbac4 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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>; /// 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; - - /// 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>, - // DefId for the declaration of the trait - // in which the associated type is declared. - trait_id: ast::DefId, - associated_type_id: ast::DefId) - -> Option>; + /// 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) + } + } + + /// 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>, + _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>, types: Vec>, - regions: Vec, - assoc_bindings: Vec<(ast::Ident, Ty<'tcx>)>) - -> Substs<'tcx> + regions: Vec) + -> 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, Vec>, - Vec<(ast::Ident, Ty<'tcx>)>) + Vec>) 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>, - allow_eq: AllowEqConstraints) - -> Rc> + poly_projections: &mut Vec>) + -> 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>, - allow_eq: AllowEqConstraints) - -> Rc> - where AC: AstConv<'tcx>, - RS: RegionScope +/// +/// If the `projections` argument is `None`, then assoc type bindings like `Foo` +/// 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>, + projections: Option<&mut Vec>>) + -> Rc> + 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>, path: &ast::Path, - allow_eq: AllowEqConstraints) - -> ty::TraitRef<'tcx> + mut projections: Option<&mut Vec>>) + -> Rc> 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); + + 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) => { } + } + } + } + } - ty::TraitRef::new(trait_def_id, this.tcx().mk_substs(substs)) + trait_ref +} + +pub fn ast_type_binding_to_projection_predicate<'tcx,AC>( + this: &AC, + trait_ref: Rc>, + binding: &ConvertedBinding<'tcx>) + -> Result, ErrorReported> + where AC : AstConv<'tcx> +{ + // Given something like `U : SomeTrait`, we want to produce a + // predicate like `::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 { } + // trait SuperTrait { type T; } + // + // ... B : SubTrait ... + // ``` + // + // We want to produce `>::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>); + fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, rscope: &RS, ty: &ast::Ty, bounds: &[ast::TyParamBound]) - -> Result, ErrorReported> + -> Result, ErrorReported> where AC : AstConv<'tcx>, RS : RegionScope { /*! @@ -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>, 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> -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>, // None for boxed closures + projection_bounds: Vec>, 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>, // None for boxed closures + mut projection_bounds: Vec>, // 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>, builtin_bounds: ty::BuiltinBounds) -> Option { @@ -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>, // 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 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"); + } +} diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 09a5dd521f882..0e8b5b373f144 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -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::>(), - "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::>(), - "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 }) } }; diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs new file mode 100644 index 0000000000000..081959a4efa4a --- /dev/null +++ b/src/librustc_typeck/check/assoc.rs @@ -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 or the MIT license +// , 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(>::A) + // + // Instead of normalizing `>::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) + } + } + } +} diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index c8a8a0ff55908..eba040e7ea8b6 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -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, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index cf6715e2d7320..a189f780b0c27 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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>, + source_trait_ref: ty::PolyTraitRef<'tcx>, target_trait_def_id: ast::DefId) - -> Rc> + -> ty::PolyTraitRef<'tcx> { for super_trait_ref in traits::supertraits(self.tcx(), source_trait_ref.clone()) { if super_trait_ref.def_id() == target_trait_def_id { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 0c094823a7575..1971be117605c 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -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` - 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={}", diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 3ecd2007ff13c..1a9e124521e0f 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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>, subst::Substs<'tcx>, MethodIndex), UnboxedClosureCandidate(/* Trait */ ast::DefId, MethodIndex), - WhereClauseCandidate(Rc>, 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>, MethodIndex), + WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, MethodIndex), } pub type PickResult<'tcx> = Result, 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>], + bounds: &[ty::PolyTraitRef<'tcx>], num_includes_types: bool, mk_cand: for<'b> |this: &mut ProbeContext<'b, 'tcx>, - tr: Rc>, + tr: ty::PolyTraitRef<'tcx>, m: Rc>, 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>, + 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 diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c8c8211f29253..8069d00dda826 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -91,12 +91,12 @@ use middle::pat_util::{mod, pat_id_map}; use middle::region::CodeExtent; use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace}; use middle::traits; -use middle::ty::{FnSig, VariantInfo, Polytype}; +use middle::ty::{FnSig, VariantInfo, TypeScheme}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; -use middle::ty::{mod, Ty}; +use middle::ty::{mod, HasProjectionTypes, Ty}; use middle::ty::liberate_late_bound_regions; use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap}; -use middle::ty_fold::TypeFolder; +use middle::ty_fold::{TypeFolder, TypeFoldable}; use rscope::RegionScope; use session::Session; use {CrateCtxt, lookup_def_ccx, no_params, require_same_types}; @@ -120,6 +120,7 @@ use syntax::print::pprust; use syntax::ptr::P; use syntax::visit::{mod, Visitor}; +mod assoc; pub mod _match; pub mod vtable; pub mod writeback; @@ -348,6 +349,17 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), } } + + fn normalize_associated_types_in(&self, span: Span, body_id: ast::NodeId, value: &T) -> T + where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + { + let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); + assoc::normalize_associated_types_in(&self.infcx, + &mut *fulfillment_cx, span, + body_id, + value) + } + } // Used by check_const and check_enum_variants @@ -386,7 +398,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemTypesVisitor<'a, 'tcx> { fn visit_ty(&mut self, t: &ast::Ty) { match t.node { ast::TyFixedLengthVec(_, ref expr) => { - check_const_in_type(self.ccx, &**expr, ty::mk_uint()); + check_const_in_type(self.ccx, &**expr, self.ccx.tcx.types.uint); } _ => {} } @@ -414,16 +426,21 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, id: ast::NodeId, - fty: Ty<'tcx>, + raw_fty: Ty<'tcx>, param_env: ty::ParameterEnvironment<'tcx>) { - // Compute the fty from point of view of inside fn - // (replace any type-scheme with a type) - let fty = fty.subst(ccx.tcx, ¶m_env.free_substs); - - match fty.sty { + match raw_fty.sty { ty::ty_bare_fn(_, ref fn_ty) => { let inh = Inherited::new(ccx.tcx, param_env); - let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_ty.sig, + + // Compute the fty from point of view of inside fn. + let fn_sig = + fn_ty.sig.subst(ccx.tcx, &inh.param_env.free_substs); + let fn_sig = + liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig); + let fn_sig = + inh.normalize_associated_types_in(body.span, body.id, &fn_sig); + + let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_sig, decl, id, body, &inh); vtable::select_all_fcx_obligations_or_error(&fcx); @@ -505,7 +522,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> { match t.node { ast::TyFixedLengthVec(ref ty, ref count_expr) => { self.visit_ty(&**ty); - check_expr_with_hint(self.fcx, &**count_expr, ty::mk_uint()); + check_expr_with_hint(self.fcx, &**count_expr, self.fcx.tcx().types.uint); } _ => visit::walk_ty(self, t) } @@ -527,19 +544,16 @@ impl<'a, 'tcx, 'v> Visitor<'v> for GatherLocalsVisitor<'a, 'tcx> { fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, unsafety: ast::Unsafety, unsafety_id: ast::NodeId, - fn_sig: &ty::PolyFnSig<'tcx>, + fn_sig: &ty::FnSig<'tcx>, decl: &ast::FnDecl, fn_id: ast::NodeId, body: &ast::Block, inherited: &'a Inherited<'a, 'tcx>) - -> FnCtxt<'a, 'tcx> { + -> FnCtxt<'a, 'tcx> +{ let tcx = ccx.tcx; let err_count_on_creation = tcx.sess.err_count(); - // First, we have to replace any bound regions in the fn type with free ones. - // The free region references will be bound the node_id of the body block. - let fn_sig = liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), fn_sig); - let arg_tys = fn_sig.inputs[]; let ret_ty = fn_sig.output; @@ -771,9 +785,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // corresponding method definition in the trait. let opt_trait_method_ty = trait_items.iter() - .find(|ti| { - ti.name() == impl_item_ty.name() - }); + .find(|ti| ti.name() == impl_item_ty.name()); match opt_trait_method_ty { Some(trait_method_ty) => { match (trait_method_ty, &impl_item_ty) { @@ -917,6 +929,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, impl_trait_ref.repr(tcx)); let infcx = infer::new_infer_ctxt(tcx); + let mut fulfillment_cx = traits::FulfillmentContext::new(); let trait_to_impl_substs = &impl_trait_ref.substs; @@ -1034,21 +1047,15 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, // this kind of equivalency just fine. // Create mapping from impl to skolemized. - let skol_tps = - impl_m.generics.types.map( - |d| ty::mk_param_from_def(tcx, d)); - let skol_regions = - impl_m.generics.regions.map( - |l| ty::free_region_from_def(impl_m_body_id, l)); - let impl_to_skol_substs = - subst::Substs::new(skol_tps.clone(), skol_regions.clone()); + let impl_param_env = ty::construct_parameter_environment(tcx, &impl_m.generics, impl_m_body_id); + let impl_to_skol_substs = &impl_param_env.free_substs; // Create mapping from trait to skolemized. let trait_to_skol_substs = trait_to_impl_substs - .subst(tcx, &impl_to_skol_substs) - .with_method(skol_tps.get_slice(subst::FnSpace).to_vec(), - skol_regions.get_slice(subst::FnSpace).to_vec()); + .subst(tcx, impl_to_skol_substs) + .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(), + impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec()); // Check region bounds. if !check_region_bounds_on_impl_method(tcx, @@ -1057,7 +1064,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, &trait_m.generics, &impl_m.generics, &trait_to_skol_substs, - &impl_to_skol_substs) { + impl_to_skol_substs) { return; } @@ -1120,7 +1127,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, for impl_trait_bound in impl_param_bounds.trait_bounds.iter() { debug!("compare_impl_method(): impl-trait-bound subst"); let impl_trait_bound = - impl_trait_bound.subst(tcx, &impl_to_skol_substs); + impl_trait_bound.subst(tcx, impl_to_skol_substs); // There may be late-bound regions from the impl in the // impl's bound, so "liberate" those. Note that the @@ -1134,7 +1141,6 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method(): trait-bound subst"); let trait_bound = trait_bound.subst(tcx, &trait_to_skol_substs); - let infcx = infer::new_infer_ctxt(tcx); infer::mk_sub_poly_trait_refs(&infcx, true, infer::Misc(impl_m_span), @@ -1153,33 +1159,95 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, } } + // We now need to check that the signature of the impl method is + // compatible with that of the trait method. We do this by + // checking that `impl_fty <: trait_fty`. + // + // FIXME. Unfortunately, this doesn't quite work right now because + // associated type normalization is not integrated into subtype + // checks. For the comparison to be valid, we need to + // normalize the associated types in the impl/trait methods + // first. However, because function types bind regions, just + // calling `normalize_associated_types_in` would have no effect on + // any associated types appearing in the fn arguments or return + // type. + + // Compute skolemized form of impl and trait method tys. let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone())); - let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs); + let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs); let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone())); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); - // Check the impl method type IM is a subtype of the trait method - // type TM. To see why this makes sense, think of a vtable. The - // expected type of the function pointers in the vtable is the - // type TM of the trait method. The actual type will be the type - // IM of the impl method. Because we know that IM <: TM, that - // means that anywhere a TM is expected, a IM will do instead. In - // other words, anyone expecting to call a method with the type - // from the trait, can safely call a method with the type from the - // impl instead. - debug!("checking trait method for compatibility: impl ty {}, trait ty {}", - impl_fty.repr(tcx), - trait_fty.repr(tcx)); - match infer::mk_subty(&infcx, false, infer::MethodCompatCheck(impl_m_span), - impl_fty, trait_fty) { - Ok(()) => {} - Err(ref terr) => { + let err = infcx.try(|snapshot| { + let origin = infer::MethodCompatCheck(impl_m_span); + + let (impl_sig, _) = + infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, + infer::HigherRankedType, + &impl_m.fty.sig); + let impl_sig = + impl_sig.subst(tcx, impl_to_skol_substs); + let impl_sig = + assoc::normalize_associated_types_in(&infcx, + &mut fulfillment_cx, + impl_m_span, + impl_m_body_id, + &impl_sig); + let impl_fty = + ty::mk_bare_fn(tcx, + None, + tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety, + abi: impl_m.fty.abi, + sig: ty::Binder(impl_sig) })); + debug!("compare_impl_method: impl_fty={}", + impl_fty.repr(tcx)); + + let (trait_sig, skol_map) = + infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot); + let trait_sig = + trait_sig.subst(tcx, &trait_to_skol_substs); + let trait_sig = + assoc::normalize_associated_types_in(&infcx, + &mut fulfillment_cx, + impl_m_span, + impl_m_body_id, + &trait_sig); + let trait_fty = + ty::mk_bare_fn(tcx, + None, + tcx.mk_bare_fn(ty::BareFnTy { unsafety: trait_m.fty.unsafety, + abi: trait_m.fty.abi, + sig: ty::Binder(trait_sig) })); + + debug!("compare_impl_method: trait_fty={}", + trait_fty.repr(tcx)); + + try!(infer::mk_subty(&infcx, false, origin, impl_fty, trait_fty)); + + infcx.leak_check(&skol_map, snapshot) + }); + + match err { + Ok(()) => { } + Err(terr) => { + debug!("checking trait method for compatibility: impl ty {}, trait ty {}", + impl_fty.repr(tcx), + trait_fty.repr(tcx)); span_err!(tcx.sess, impl_m_span, E0053, - "method `{}` has an incompatible type for trait: {}", - token::get_name(trait_m.name), - ty::type_err_to_str(tcx, terr)); - ty::note_and_explain_type_err(tcx, terr); + "method `{}` has an incompatible type for trait: {}", + token::get_name(trait_m.name), + ty::type_err_to_str(tcx, &terr)); + return; + } + } + + // Run the fulfillment context to completion to accommodate any + // associated type normalizations that may have occurred. + match fulfillment_cx.select_all_or_error(&infcx, &impl_param_env, tcx) { + Ok(()) => { } + Err(errors) => { + traits::report_fulfillment_errors(&infcx, &errors); } } @@ -1356,7 +1424,7 @@ fn check_cast(fcx: &FnCtxt, return } - if !ty::type_is_sized(fcx.tcx(), t_1) { + if !fcx.type_is_known_to_be_sized(t_1) { let tstr = fcx.infcx().ty_to_string(t_1); fcx.type_error_message(span, |actual| { format!("cast to unsized type: `{}` as `{}`", actual, tstr) @@ -1510,7 +1578,7 @@ fn check_cast(fcx: &FnCtxt, impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx } - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { + fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> { ty::lookup_item_type(self.tcx(), id) } @@ -1526,29 +1594,42 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.infcx().next_ty_var() } - fn associated_types_of_trait_are_valid(&self, _: Ty, _: ast::DefId) - -> bool { - false + fn projected_ty_from_poly_trait_ref(&self, + span: Span, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + item_name: ast::Name) + -> Ty<'tcx> + { + let (trait_ref, _) = + self.infcx().replace_late_bound_regions_with_fresh_var( + span, + infer::LateBoundRegionConversionTime::AssocTypeProjection(item_name), + &poly_trait_ref); + + self.normalize_associated_type(span, trait_ref, item_name) } - fn associated_type_binding(&self, - span: Span, - _: Option>, - _: ast::DefId, - _: ast::DefId) - -> Option> { - self.tcx().sess.span_err(span, "unsupported associated type binding"); - Some(ty::mk_err()) + fn projected_ty(&self, + span: Span, + trait_ref: Rc>, + item_name: ast::Name) + -> Ty<'tcx> + { + self.normalize_associated_type(span, trait_ref, item_name) } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx } - pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a, 'tcx> { + pub fn infcx(&self) -> &infer::InferCtxt<'a, 'tcx> { &self.inh.infcx } + pub fn param_env(&self) -> &ty::ParameterEnvironment<'tcx> { + &self.inh.param_env + } + pub fn sess(&self) -> &Session { &self.tcx().sess } @@ -1556,22 +1637,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn err_count_since_creation(&self) -> uint { self.ccx.tcx.sess.err_count() - self.err_count_on_creation } -} - -impl<'a, 'tcx> RegionScope for infer::InferCtxt<'a, 'tcx> { - fn default_region_bound(&self, span: Span) -> Option { - Some(self.next_region_var(infer::MiscVariable(span))) - } - - fn anon_regions(&self, span: Span, count: uint) - -> Result, Option>> { - Ok(Vec::from_fn(count, |_| { - self.next_region_var(infer::MiscVariable(span)) - })) - } -} -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn tag(&self) -> String { format!("{}", self as *const FnCtxt) } @@ -1605,7 +1671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_object_cast(&self, key: ast::NodeId, - trait_ref: Rc>) { + trait_ref: ty::PolyTraitRef<'tcx>) { debug!("write_object_cast key={} trait_ref={}", key, trait_ref.repr(self.tcx())); self.inh.object_cast_map.borrow_mut().insert(key, trait_ref); @@ -1656,6 +1722,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.inh.adjustments.borrow_mut().insert(node_id, adj); } + /// Basically whenever we are converting from a type scheme into + /// the fn body space, we always want to normalize associated + /// types as well. This function combines the two. + fn instantiate_type_scheme(&self, + span: Span, + substs: &Substs<'tcx>, + value: &T) + -> T + where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx> + { + let value = value.subst(self.tcx(), substs); + let result = self.normalize_associated_types_in(span, &value); + debug!("instantiate_type_scheme(value={}, substs={}) = {}", + value.repr(self.tcx()), + substs.repr(self.tcx()), + result.repr(self.tcx())); + result + } + + fn normalize_associated_types_in(&self, span: Span, value: &T) -> T + where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + { + self.inh.normalize_associated_types_in(span, self.body_id, value) + } + + fn normalize_associated_type(&self, + span: Span, + trait_ref: Rc>, + item_name: ast::Name) + -> Ty<'tcx> + { + let cause = traits::ObligationCause::new(span, + self.body_id, + traits::ObligationCauseCode::MiscObligation); + self.inh.fulfillment_cx + .borrow_mut() + .normalize_projection_type(self.infcx(), + ty::ProjectionTy { + trait_ref: trait_ref, + item_name: item_name, + }, + cause) + } + fn register_adjustment_obligations(&self, span: Span, adj: &ty::AutoAdjustment<'tcx>) { @@ -1728,21 +1838,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Also returns the substitution from the type parameters on `def_id` to the fresh variables. /// Registers any trait obligations specified on `def_id` at the same time. /// - /// Note that function is only intended to be used with types (notably, not impls). This is + /// Note that function is only intended to be used with types (notably, not fns). This is /// because it doesn't do any instantiation of late-bound regions. pub fn instantiate_type(&self, span: Span, def_id: ast::DefId) -> TypeAndSubsts<'tcx> { - let polytype = + let type_scheme = ty::lookup_item_type(self.tcx(), def_id); let substs = self.infcx().fresh_substs_for_generics( span, - &polytype.generics); + &type_scheme.generics); let bounds = - polytype.generics.to_bounds(self.tcx(), &substs); + type_scheme.generics.to_bounds(self.tcx(), &substs); self.add_obligations_for_parameters( traits::ObligationCause::new( span, @@ -1750,7 +1860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { traits::ItemObligation(def_id)), &bounds); let monotype = - polytype.ty.subst(self.tcx(), &substs); + self.instantiate_type_scheme(span, &substs, &type_scheme.ty); TypeAndSubsts { ty: monotype, @@ -1762,7 +1872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.write_ty(node_id, ty::mk_nil(self.tcx())); } pub fn write_error(&self, node_id: ast::NodeId) { - self.write_ty(node_id, ty::mk_err()); + self.write_ty(node_id, self.tcx().types.err); } pub fn require_type_meets(&self, @@ -1792,13 +1902,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(self.expr_ty(expr), expr.span, code); } + pub fn type_is_known_to_be_sized(&self, + ty: Ty<'tcx>) + -> bool + { + traits::type_known_to_meet_builtin_bound(self.infcx(), + self.param_env(), + ty, + ty::BoundSized) + } + pub fn register_builtin_bound(&self, ty: Ty<'tcx>, builtin_bound: ty::BuiltinBound, cause: traits::ObligationCause<'tcx>) { self.inh.fulfillment_cx.borrow_mut() - .register_builtin_bound(self.tcx(), ty, builtin_bound, cause); + .register_builtin_bound(self.infcx(), ty, builtin_bound, cause); } pub fn register_predicate(&self, @@ -1809,11 +1929,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.inh.fulfillment_cx .borrow_mut() - .register_predicate(self.tcx(), obligation); + .register_predicate(self.infcx(), obligation); } pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> { - let t = ast_ty_to_ty(self, self.infcx(), ast_t); + let t = ast_ty_to_ty(self, self, ast_t); let mut bounds_checker = wf::BoundsChecker::new(self, ast_t.span, @@ -1953,7 +2073,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: traits::ObligationCause<'tcx>) { let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); - fulfillment_cx.register_region_obligation(self.tcx(), ty, region, cause); + fulfillment_cx.register_region_obligation(self.infcx(), ty, region, cause); } pub fn add_default_region_param_bounds(&self, @@ -2003,7 +2123,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -#[deriving(Copy, Show,PartialEq,Eq)] +impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { + fn default_region_bound(&self, span: Span) -> Option { + Some(self.infcx().next_region_var(infer::MiscVariable(span))) + } + + fn anon_regions(&self, span: Span, count: uint) + -> Result, Option>> { + Ok(Vec::from_fn(count, |_| { + self.infcx().next_region_var(infer::MiscVariable(span)) + })) + } +} + +#[deriving(Copy, Show, PartialEq, Eq)] pub enum LvaluePreference { PreferMutLvalue, NoPreference @@ -2058,7 +2191,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, span_err!(fcx.tcx().sess, sp, E0055, "reached the recursion limit while auto-dereferencing {}", base_ty.repr(fcx.tcx())); - (ty::mk_err(), 0, None) + (fcx.tcx().types.err, 0, None) } /// Attempts to resolve a call expression as an overloaded call. @@ -2214,7 +2347,6 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, } } - /// Checks for a `Slice` (or `SliceMut`) impl at the relevant level of autoderef. If it finds one, /// installs method info and returns type of method (else None). fn try_overloaded_slice_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -2322,7 +2454,7 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match ty::index(adjusted_ty) { Some(ty) => { fcx.write_adjustment(base_expr.id, base_expr.span, ty::AdjustDerefRef(adjustment)); - return Some((ty::mk_uint(), ty)); + return Some((fcx.tcx().types.uint, ty)); } None => { } @@ -2384,7 +2516,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Err(ref err_string) => { fcx.tcx().sess.span_err(iterator_expr.span, err_string[]); - return ty::mk_err() + return fcx.tcx().types.err } }; @@ -2412,7 +2544,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, maybe try .iter()", ty_string)[]); } - ty::mk_err() + fcx.tcx().types.err } }; let return_type = check_method_argument_types(fcx, @@ -2433,7 +2565,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let return_type = match return_type { ty::FnConverging(return_type) => structurally_resolved_type(fcx, iterator_expr.span, return_type), - ty::FnDiverging => ty::mk_err() + ty::FnDiverging => fcx.tcx().types.err }; match return_type.sty { ty::ty_enum(_, ref substs) @@ -2441,7 +2573,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, *substs.types.get(subst::TypeSpace, 0) } ty::ty_err => { - ty::mk_err() + fcx.tcx().types.err } _ => { fcx.tcx().sess.span_err(iterator_expr.span, @@ -2449,11 +2581,11 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, trait has an unexpected type `{}`", fcx.infcx().ty_to_string(return_type)) []); - ty::mk_err() + fcx.tcx().types.err } } } - None => ty::mk_err() + None => fcx.tcx().types.err } } @@ -2466,7 +2598,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, tuple_arguments: TupleArgumentsFlag) -> ty::FnOutput<'tcx> { if ty::type_is_error(method_fn_ty) { - let err_inputs = err_args(args_no_rcvr.len()); + let err_inputs = err_args(fcx.tcx(), args_no_rcvr.len()); let err_inputs = match tuple_arguments { DontTupleArguments => err_inputs, @@ -2481,7 +2613,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, autoref_args, false, tuple_arguments); - ty::FnConverging(ty::mk_err()) + ty::FnConverging(fcx.tcx().types.err) } else { match method_fn_ty.sty { ty::ty_bare_fn(_, ref fty) => { @@ -2536,7 +2668,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if arg_types.len() == 1 {""} else {"s"}, args.len(), if args.len() == 1 {" was"} else {"s were"}); - err_args(args.len()) + err_args(fcx.tcx(), args.len()) } else { (*arg_types).clone() } @@ -2545,7 +2677,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span_err!(tcx.sess, sp, E0059, "cannot use call notation; the first type parameter \ for the function trait is neither a tuple nor unit"); - err_args(args.len()) + err_args(fcx.tcx(), args.len()) } } } else if expected_arg_count == supplied_arg_count { @@ -2561,7 +2693,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if expected_arg_count == 1 {""} else {"s"}, supplied_arg_count, if supplied_arg_count == 1 {" was"} else {"s were"}); - err_args(supplied_arg_count) + err_args(fcx.tcx(), supplied_arg_count) } } else { span_err!(tcx.sess, sp, E0061, @@ -2570,7 +2702,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if expected_arg_count == 1 {""} else {"s"}, supplied_arg_count, if supplied_arg_count == 1 {" was"} else {"s were"}); - err_args(supplied_arg_count) + err_args(fcx.tcx(), supplied_arg_count) }; debug!("check_argument_types: formal_tys={}", @@ -2626,7 +2758,7 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // mismatch impl/trait method phase no need to // ICE here. // See: #11450 - formal_ty = ty::mk_err(); + formal_ty = tcx.types.err; } } } @@ -2677,8 +2809,8 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } // FIXME(#17596) Ty<'tcx> is incorrectly invariant w.r.t 'tcx. -fn err_args<'tcx>(len: uint) -> Vec> { - Vec::from_fn(len, |_| ty::mk_err()) +fn err_args<'tcx>(tcx: &ty::ctxt<'tcx>, len: uint) -> Vec> { + Vec::from_fn(len, |_| tcx.types.err) } fn write_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -2701,27 +2833,28 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match lit.node { ast::LitStr(..) => ty::mk_str_slice(tcx, tcx.mk_region(ty::ReStatic), ast::MutImmutable), ast::LitBinary(..) => { - ty::mk_slice(tcx, tcx.mk_region(ty::ReStatic), - ty::mt{ ty: ty::mk_u8(), mutbl: ast::MutImmutable }) - } - ast::LitByte(_) => ty::mk_u8(), - ast::LitChar(_) => ty::mk_char(), - ast::LitInt(_, ast::SignedIntLit(t, _)) => ty::mk_mach_int(t), - ast::LitInt(_, ast::UnsignedIntLit(t)) => ty::mk_mach_uint(t), + ty::mk_slice(tcx, + tcx.mk_region(ty::ReStatic), + ty::mt{ ty: tcx.types.u8, mutbl: ast::MutImmutable }) + } + ast::LitByte(_) => tcx.types.u8, + ast::LitChar(_) => tcx.types.char, + ast::LitInt(_, ast::SignedIntLit(t, _)) => ty::mk_mach_int(tcx, t), + ast::LitInt(_, ast::UnsignedIntLit(t)) => ty::mk_mach_uint(tcx, t), ast::LitInt(_, ast::UnsuffixedIntLit(_)) => { let opt_ty = expected.map_to_option(fcx, |ty| { match ty.sty { ty::ty_int(_) | ty::ty_uint(_) => Some(ty), - ty::ty_char => Some(ty::mk_mach_uint(ast::TyU8)), - ty::ty_ptr(..) => Some(ty::mk_mach_uint(ast::TyU)), - ty::ty_bare_fn(..) => Some(ty::mk_mach_uint(ast::TyU)), + ty::ty_char => Some(tcx.types.u8), + ty::ty_ptr(..) => Some(tcx.types.uint), + ty::ty_bare_fn(..) => Some(tcx.types.uint), _ => None } }); opt_ty.unwrap_or_else( || ty::mk_int_var(tcx, fcx.infcx().next_int_var_id())) } - ast::LitFloat(_, t) => ty::mk_mach_float(t), + ast::LitFloat(_, t) => ty::mk_mach_float(tcx, t), ast::LitFloatUnsuffixed(_) => { let opt_ty = expected.map_to_option(fcx, |ty| { match ty.sty { @@ -2732,7 +2865,7 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, opt_ty.unwrap_or_else( || ty::mk_float_var(tcx, fcx.infcx().next_float_var_id())) } - ast::LitBool(_) => ty::mk_bool() + ast::LitBool(_) => tcx.types.bool } } @@ -2813,7 +2946,7 @@ pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let rps = fcx.inh.infcx.region_vars_for_defs(span, rps); let tps = fcx.inh.infcx.next_ty_vars(n_tps); let substs = subst::Substs::new_type(tps, rps); - let substd_ty = raw_ty.subst(tcx, &substs); + let substd_ty = fcx.instantiate_type_scheme(span, &substs, &raw_ty); TypeAndSubsts { substs: substs, ty: substd_ty } } @@ -2907,8 +3040,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // In that case, we check each argument against "error" in order to // set up all the node type bindings. let error_fn_sig = ty::Binder(FnSig { - inputs: err_args(args.len()), - output: ty::FnConverging(ty::mk_err()), + inputs: err_args(fcx.tcx(), args.len()), + output: ty::FnConverging(fcx.tcx().types.err), variadic: false }); @@ -2923,12 +3056,18 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } }; - // Replace any bound regions that appear in the function - // signature with region variables + // Replace any late-bound regions that appear in the function + // signature with region variables. We also have to + // renormalize the associated types at this point, since they + // previously appeared within a `Binder<>` and hence would not + // have been normalized before. let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, fn_sig).0; + let fn_sig = + fcx.normalize_associated_types_in(call_expr.span, + &fn_sig); // Call the generic checker. check_argument_types(fcx, @@ -2975,7 +3114,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, Err(error) => { method::report_error(fcx, method_name.span, expr_t, method_name.node.name, error); fcx.write_error(expr.id); - ty::mk_err() + fcx.tcx().types.err } }; @@ -3001,7 +3140,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, id: ast::NodeId, sp: Span, expected: Expectation<'tcx>) { - check_expr_has_type(fcx, cond_expr, ty::mk_bool()); + check_expr_has_type(fcx, cond_expr, fcx.tcx().types.bool); let expected = expected.adjust_for_branches(fcx); check_block_with_expected(fcx, then_blk, expected); @@ -3028,7 +3167,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let cond_ty = fcx.expr_ty(cond_expr); let if_ty = if ty::type_is_error(cond_ty) { - ty::mk_err() + fcx.tcx().types.err } else { branches_ty }; @@ -3100,14 +3239,14 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, autoref_args, DontTupleArguments) { ty::FnConverging(result_type) => result_type, - ty::FnDiverging => ty::mk_err() + ty::FnDiverging => fcx.tcx().types.err } } None => { unbound_method(); // Check the args anyway // so we get all the error messages - let expected_ty = ty::mk_err(); + let expected_ty = fcx.tcx().types.err; check_method_argument_types(fcx, op_ex.span, expected_ty, @@ -3115,7 +3254,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, args.as_slice(), autoref_args, DontTupleArguments); - ty::mk_err() + fcx.tcx().types.err } } } @@ -3141,7 +3280,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) { // Shift is a special case: rhs must be uint, no matter what lhs is - check_expr_has_type(fcx, &**rhs, ty::mk_uint()); + check_expr_has_type(fcx, &**rhs, fcx.tcx().types.uint); fcx.write_ty(expr.id, lhs_t); return; } @@ -3168,12 +3307,12 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lhs_t, None ); - ty::mk_err() + fcx.tcx().types.err } else { lhs_t } } else { - ty::mk_bool() + fcx.tcx().types.bool } }, _ => lhs_t, @@ -3215,7 +3354,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, lhs_t, None); check_expr(fcx, &**rhs); - ty::mk_err() + fcx.tcx().types.err }; fcx.write_ty(expr.id, result_t); @@ -3251,7 +3390,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast::BiNe => ("ne", lang.eq_trait()), ast::BiAnd | ast::BiOr => { check_expr(fcx, &**rhs); - return ty::mk_err(); + return tcx.types.err; } }; lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name), @@ -3424,7 +3563,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Typecheck each field. for field in ast_fields.iter() { - let mut expected_field_type = ty::mk_err(); + let mut expected_field_type = tcx.types.err; let pair = class_field_map.get(&field.ident.node.name).map(|x| *x); match pair { @@ -3531,7 +3670,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, base_expr.is_none(), None); if ty::type_is_error(fcx.node_ty(id)) { - struct_type = ty::mk_err(); + struct_type = tcx.types.err; } // Check the base expression if necessary. @@ -3620,7 +3759,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, if !checked { span_err!(tcx.sess, expr.span, E0066, "only the managed heap and exchange heap are currently supported"); - fcx.write_ty(id, ty::mk_err()); + fcx.write_ty(id, tcx.types.err); } } @@ -3720,7 +3859,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, dereferenced", actual) }, oprnd_t, None); } - ty::mk_err() + tcx.types.err } } }; @@ -3777,7 +3916,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let tm = ty::mt { ty: fcx.expr_ty(&**oprnd), mutbl: mutbl }; let oprnd_t = if ty::type_is_error(tm.ty) { - ty::mk_err() + tcx.types.err } else { // Note: at this point, we cannot say what the best lifetime // is to use for resulting pointer. We want to use the @@ -3815,7 +3954,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } ast::ExprPath(ref pth) => { let defn = lookup_def(fcx, pth.span, id); - let pty = polytype_for_def(fcx, expr.span, defn); + let pty = type_scheme_for_def(fcx, expr.span, defn); instantiate_path(fcx, pth, pty, defn, expr.span, expr.id); // We always require that the type provided as the value for @@ -3895,7 +4034,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet"); } ast::ExprWhile(ref cond, ref body, _) => { - check_expr_has_type(fcx, &**cond, ty::mk_bool()); + check_expr_has_type(fcx, &**cond, tcx.types.bool); check_block_no_value(fcx, &**body); let cond_ty = fcx.expr_ty(&**cond); let body_ty = fcx.node_ty(body.id); @@ -3975,7 +4114,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } ast::ExprCast(ref e, ref t) => { if let ast::TyFixedLengthVec(_, ref count_expr) = t.node { - check_expr_with_hint(fcx, &**count_expr, ty::mk_uint()); + check_expr_with_hint(fcx, &**count_expr, tcx.types.uint); } check_cast(fcx, expr, &**e, &**t); } @@ -4006,7 +4145,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.write_ty(id, typ); } ast::ExprRepeat(ref element, ref count_expr) => { - check_expr_has_type(fcx, &**count_expr, ty::mk_uint()); + check_expr_has_type(fcx, &**count_expr, tcx.types.uint); let count = ty::eval_repeat_count(fcx.tcx(), &**count_expr); let uty = match expected { @@ -4136,7 +4275,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let actual_structure_type = fcx.expr_ty(&*expr); if !ty::type_is_error(actual_structure_type) { let type_and_substs = astconv::ast_path_to_ty_relaxed(fcx, - fcx.infcx(), + fcx, struct_id, path); match fcx.mk_subty(false, @@ -4219,8 +4358,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }, base_t, None); - fcx.write_ty(idx.id, ty::mk_err()); - fcx.write_ty(id, ty::mk_err()) + fcx.write_ty(idx.id, fcx.tcx().types.err); + fcx.write_ty(id, fcx.tcx().types.err); } } } @@ -4249,7 +4388,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.write_ty(id, element_ty); } _ => { - check_expr_has_type(fcx, &**idx, ty::mk_err()); + check_expr_has_type(fcx, &**idx, fcx.tcx().types.err); fcx.type_error_message( expr.span, |actual| { @@ -4258,7 +4397,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }, base_t, None); - fcx.write_ty(id, ty::mk_err()) + fcx.write_ty(id, fcx.tcx().types.err); } } } @@ -4277,19 +4416,21 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }); let idx_type = match (t_start, t_end) { - (Some(ty), None) | (None, Some(ty)) => Some(ty), - (Some(t_start), Some(t_end)) - if ty::type_is_error(t_start) || ty::type_is_error(t_end) => { - Some(ty::mk_err()) - } - (Some(t_start), Some(t_end)) => { - Some(infer::common_supertype(fcx.infcx(), - infer::RangeExpression(expr.span), - true, - t_start, - t_end)) - } - _ => None + (Some(ty), None) | (None, Some(ty)) => { + Some(ty) + } + (Some(t_start), Some(t_end)) if (ty::type_is_error(t_start) || + ty::type_is_error(t_end)) => { + Some(fcx.tcx().types.err) + } + (Some(t_start), Some(t_end)) => { + Some(infer::common_supertype(fcx.infcx(), + infer::RangeExpression(expr.span), + true, + t_start, + t_end)) + } + _ => None }; // Note that we don't check the type of start/end satisfy any @@ -4298,7 +4439,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let range_type = match idx_type { Some(idx_type) if ty::type_is_error(idx_type) => { - ty::mk_err() + fcx.tcx().types.err } Some(idx_type) => { // Find the did from the appropriate lang item. @@ -4324,7 +4465,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ty::mk_struct(tcx, did, tcx.mk_substs(substs)) } else { tcx.sess.span_err(expr.span, "No lang item for range syntax"); - ty::mk_err() + fcx.tcx().types.err } } None => { @@ -4334,7 +4475,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ty::mk_struct(tcx, did, tcx.mk_substs(substs)) } else { tcx.sess.span_err(expr.span, "No lang item for range syntax"); - ty::mk_err() + fcx.tcx().types.err } } }; @@ -4810,12 +4951,12 @@ pub fn check_enum_variants(ccx: &CrateCtxt, let inh = static_inherited_fields(ccx); let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id); let declty = match hint { - attr::ReprAny | attr::ReprPacked | attr::ReprExtern => ty::mk_int(), + attr::ReprAny | attr::ReprPacked | attr::ReprExtern => fcx.tcx().types.int, attr::ReprInt(_, attr::SignedInt(ity)) => { - ty::mk_mach_int(ity) + ty::mk_mach_int(fcx.tcx(), ity) } attr::ReprInt(_, attr::UnsignedInt(ity)) => { - ty::mk_mach_uint(ity) + ty::mk_mach_uint(fcx.tcx(), ity) }, }; check_const_with_ty(&fcx, e.span, &**e, declty); @@ -4908,10 +5049,10 @@ pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> def::Def { } // Returns the type parameter count and the type for the given definition. -pub fn polytype_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - defn: def::Def) - -> Polytype<'tcx> { +pub fn type_scheme_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + sp: Span, + defn: def::Def) + -> TypeScheme<'tcx> { match defn { def::DefLocal(nid) | def::DefUpvar(nid, _, _) => { let typ = fcx.local_ty(sp, nid); @@ -4927,7 +5068,7 @@ pub fn polytype_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, def::DefAssociatedTy(..) | def::DefAssociatedPath(..) | def::DefPrimTy(_) | - def::DefTyParam(..)=> { + def::DefTyParam(..) => { fcx.ccx.tcx.sess.span_bug(sp, "expected value, found type"); } def::DefMod(..) | def::DefForeignMod(..) => { @@ -4955,15 +5096,15 @@ pub fn polytype_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // number of type parameters and type. pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, path: &ast::Path, - polytype: Polytype<'tcx>, + type_scheme: TypeScheme<'tcx>, def: def::Def, span: Span, node_id: ast::NodeId) { - debug!("instantiate_path(path={}, def={}, node_id={}, polytype={})", + debug!("instantiate_path(path={}, def={}, node_id={}, type_scheme={})", path.repr(fcx.tcx()), def.repr(fcx.tcx()), node_id, - polytype.repr(fcx.tcx())); + type_scheme.repr(fcx.tcx())); // We need to extract the type parameters supplied by the user in // the path `path`. Due to the current setup, this is a bit of a @@ -5088,8 +5229,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Next, examine the definition, and determine how many type // parameters we expect from each space. - let type_defs = &polytype.generics.types; - let region_defs = &polytype.generics.regions; + let type_defs = &type_scheme.generics.types; + let region_defs = &type_scheme.generics.regions; // Now that we have categorized what space the parameters for each // segment belong to, let's sort out the parameters that the user @@ -5137,12 +5278,12 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // the fn itself). Those should be replaced with fresh variables // now. These can appear either on the type being referenced, or // on the associated bounds. - let bounds = polytype.generics.to_bounds(fcx.tcx(), &substs); + let bounds = type_scheme.generics.to_bounds(fcx.tcx(), &substs); let (ty_late_bound, bounds) = fcx.infcx().replace_late_bound_regions_with_fresh_var( span, infer::FnCall, - &ty::Binder((polytype.ty, bounds))).0; + &ty::Binder((type_scheme.ty, bounds))).0; debug!("after late-bounds have been replaced: ty_late_bound={}", ty_late_bound.repr(fcx.tcx())); debug!("after late-bounds have been replaced: bounds={}", bounds.repr(fcx.tcx())); @@ -5153,9 +5294,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // Substitute the values for the type parameters into the type of // the referenced item. - let ty_substituted = ty_late_bound.subst(fcx.tcx(), &substs); - - debug!("ty_substituted: ty_substituted={}", ty_substituted.repr(fcx.tcx())); + let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &ty_late_bound); fcx.write_ty(node_id, ty_substituted); fcx.write_substs(node_id, ty::ItemSubsts { substs: substs }); @@ -5243,7 +5382,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span_err!(fcx.tcx().sess, data.bindings[0].span, E0182, "unexpected binding of associated item in expression path \ (only allowed in type paths)"); - substs.types.truncate(subst::ParamSpace::AssocSpace, 0); } { @@ -5352,7 +5490,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, , found {} parameter(s)", qualifier, required_len, provided_len); substs.types.replace(space, - Vec::from_elem(desired.len(), ty::mk_err())); + Vec::from_elem(desired.len(), fcx.tcx().types.err)); return; } @@ -5436,8 +5574,8 @@ pub fn structurally_resolved_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, "the type of this value must be known in this \ context".to_string() }, ty, None); - demand::suptype(fcx, sp, ty::mk_err(), ty); - ty = ty::mk_err(); + demand::suptype(fcx, sp, fcx.tcx().types.err, ty); + ty = fcx.tcx().types.err; } ty @@ -5499,7 +5637,8 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> { - ty::mk_param(ccx.tcx, subst::FnSpace, n, local_def(0)) + let name = token::intern(format!("P{}", n).as_slice()); + ty::mk_param(ccx.tcx, subst::FnSpace, n, name) } let tcx = ccx.tcx; @@ -5540,7 +5679,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { let (n_tps, inputs, output) = match name.get() { "breakpoint" => (0, Vec::new(), ty::mk_nil(tcx)), "size_of" | - "pref_align_of" | "min_align_of" => (1u, Vec::new(), ty::mk_uint()), + "pref_align_of" | "min_align_of" => (1u, Vec::new(), ccx.tcx.types.uint), "init" => (1u, Vec::new(), param(ccx, 0)), "uninit" => (1u, Vec::new(), param(ccx, 0)), "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil(tcx)), @@ -5556,8 +5695,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { ), ty::mk_nil(tcx)) } - "needs_drop" => (1u, Vec::new(), ty::mk_bool()), - "owns_managed" => (1u, Vec::new(), ty::mk_bool()), + "needs_drop" => (1u, Vec::new(), ccx.tcx.types.bool), + "owns_managed" => (1u, Vec::new(), ccx.tcx.types.bool), "get_tydesc" => { let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) { @@ -5589,7 +5728,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { ty: param(ccx, 0), mutbl: ast::MutImmutable }), - ty::mk_int() + ccx.tcx.types.int ), ty::mk_ptr(tcx, ty::mt { ty: param(ccx, 0), @@ -5608,7 +5747,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { ty: param(ccx, 0), mutbl: ast::MutImmutable }), - ty::mk_uint() + tcx.types.uint, ), ty::mk_nil(tcx)) } @@ -5619,88 +5758,88 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { ty: param(ccx, 0), mutbl: ast::MutMutable }), - ty::mk_u8(), - ty::mk_uint() + tcx.types.u8, + tcx.types.uint, ), ty::mk_nil(tcx)) } - "sqrtf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "sqrtf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), + "sqrtf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "sqrtf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), "powif32" => { (0, - vec!( ty::mk_f32(), ty::mk_i32() ), - ty::mk_f32()) + vec!( tcx.types.f32, tcx.types.i32 ), + tcx.types.f32) } "powif64" => { (0, - vec!( ty::mk_f64(), ty::mk_i32() ), - ty::mk_f64()) + vec!( tcx.types.f64, tcx.types.i32 ), + tcx.types.f64) } - "sinf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "sinf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "cosf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "cosf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), + "sinf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "sinf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "cosf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "cosf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), "powf32" => { (0, - vec!( ty::mk_f32(), ty::mk_f32() ), - ty::mk_f32()) + vec!( tcx.types.f32, tcx.types.f32 ), + tcx.types.f32) } "powf64" => { (0, - vec!( ty::mk_f64(), ty::mk_f64() ), - ty::mk_f64()) - } - "expf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "expf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "exp2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "exp2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "logf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "logf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "log10f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "log10f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "log2f32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "log2f64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), + vec!( tcx.types.f64, tcx.types.f64 ), + tcx.types.f64) + } + "expf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "expf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "exp2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "exp2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "logf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "logf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "log10f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "log10f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "log2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "log2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), "fmaf32" => { (0, - vec!( ty::mk_f32(), ty::mk_f32(), ty::mk_f32() ), - ty::mk_f32()) + vec!( tcx.types.f32, tcx.types.f32, tcx.types.f32 ), + tcx.types.f32) } "fmaf64" => { (0, - vec!( ty::mk_f64(), ty::mk_f64(), ty::mk_f64() ), - ty::mk_f64()) - } - "fabsf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "fabsf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "copysignf32" => (0, vec!( ty::mk_f32(), ty::mk_f32() ), ty::mk_f32()), - "copysignf64" => (0, vec!( ty::mk_f64(), ty::mk_f64() ), ty::mk_f64()), - "floorf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "floorf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "ceilf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "ceilf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "truncf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "truncf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "rintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "rintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "nearbyintf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "nearbyintf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "roundf32" => (0, vec!( ty::mk_f32() ), ty::mk_f32()), - "roundf64" => (0, vec!( ty::mk_f64() ), ty::mk_f64()), - "ctpop8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()), - "ctpop16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()), - "ctpop32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()), - "ctpop64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()), - "ctlz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()), - "ctlz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()), - "ctlz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()), - "ctlz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()), - "cttz8" => (0, vec!( ty::mk_u8() ), ty::mk_u8()), - "cttz16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()), - "cttz32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()), - "cttz64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()), - "bswap16" => (0, vec!( ty::mk_u16() ), ty::mk_u16()), - "bswap32" => (0, vec!( ty::mk_u32() ), ty::mk_u32()), - "bswap64" => (0, vec!( ty::mk_u64() ), ty::mk_u64()), + vec!( tcx.types.f64, tcx.types.f64, tcx.types.f64 ), + tcx.types.f64) + } + "fabsf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "fabsf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "copysignf32" => (0, vec!( tcx.types.f32, tcx.types.f32 ), tcx.types.f32), + "copysignf64" => (0, vec!( tcx.types.f64, tcx.types.f64 ), tcx.types.f64), + "floorf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "floorf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "ceilf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "ceilf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "truncf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "truncf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "rintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "rintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "nearbyintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "nearbyintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "roundf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), + "roundf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "ctpop8" => (0, vec!( tcx.types.u8 ), tcx.types.u8), + "ctpop16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), + "ctpop32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), + "ctpop64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), + "ctlz8" => (0, vec!( tcx.types.u8 ), tcx.types.u8), + "ctlz16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), + "ctlz32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), + "ctlz64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), + "cttz8" => (0, vec!( tcx.types.u8 ), tcx.types.u8), + "cttz16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), + "cttz32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), + "cttz64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), + "bswap16" => (0, vec!( tcx.types.u16 ), tcx.types.u16), + "bswap32" => (0, vec!( tcx.types.u32 ), tcx.types.u32), + "bswap64" => (0, vec!( tcx.types.u64 ), tcx.types.u64), "volatile_load" => (1, vec!( ty::mk_imm_ptr(tcx, param(ccx, 0)) ), param(ccx, 0)), @@ -5708,40 +5847,40 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { (1, vec!( ty::mk_mut_ptr(tcx, param(ccx, 0)), param(ccx, 0) ), ty::mk_nil(tcx)), "i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" => - (0, vec!(ty::mk_i8(), ty::mk_i8()), - ty::mk_tup(tcx, vec!(ty::mk_i8(), ty::mk_bool()))), + (0, vec!(tcx.types.i8, tcx.types.i8), + ty::mk_tup(tcx, vec!(tcx.types.i8, tcx.types.bool))), "i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" => - (0, vec!(ty::mk_i16(), ty::mk_i16()), - ty::mk_tup(tcx, vec!(ty::mk_i16(), ty::mk_bool()))), + (0, vec!(tcx.types.i16, tcx.types.i16), + ty::mk_tup(tcx, vec!(tcx.types.i16, tcx.types.bool))), "i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" => - (0, vec!(ty::mk_i32(), ty::mk_i32()), - ty::mk_tup(tcx, vec!(ty::mk_i32(), ty::mk_bool()))), + (0, vec!(tcx.types.i32, tcx.types.i32), + ty::mk_tup(tcx, vec!(tcx.types.i32, tcx.types.bool))), "i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" => - (0, vec!(ty::mk_i64(), ty::mk_i64()), - ty::mk_tup(tcx, vec!(ty::mk_i64(), ty::mk_bool()))), + (0, vec!(tcx.types.i64, tcx.types.i64), + ty::mk_tup(tcx, vec!(tcx.types.i64, tcx.types.bool))), "u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" => - (0, vec!(ty::mk_u8(), ty::mk_u8()), - ty::mk_tup(tcx, vec!(ty::mk_u8(), ty::mk_bool()))), + (0, vec!(tcx.types.u8, tcx.types.u8), + ty::mk_tup(tcx, vec!(tcx.types.u8, tcx.types.bool))), "u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" => - (0, vec!(ty::mk_u16(), ty::mk_u16()), - ty::mk_tup(tcx, vec!(ty::mk_u16(), ty::mk_bool()))), + (0, vec!(tcx.types.u16, tcx.types.u16), + ty::mk_tup(tcx, vec!(tcx.types.u16, tcx.types.bool))), "u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=> - (0, vec!(ty::mk_u32(), ty::mk_u32()), - ty::mk_tup(tcx, vec!(ty::mk_u32(), ty::mk_bool()))), + (0, vec!(tcx.types.u32, tcx.types.u32), + ty::mk_tup(tcx, vec!(tcx.types.u32, tcx.types.bool))), "u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" => - (0, vec!(ty::mk_u64(), ty::mk_u64()), - ty::mk_tup(tcx, vec!(ty::mk_u64(), ty::mk_bool()))), + (0, vec!(tcx.types.u64, tcx.types.u64), + ty::mk_tup(tcx, vec!(tcx.types.u64, tcx.types.bool))), - "return_address" => (0, vec![], ty::mk_imm_ptr(tcx, ty::mk_u8())), + "return_address" => (0, vec![], ty::mk_imm_ptr(tcx, tcx.types.u8)), - "assume" => (0, vec![ty::mk_bool()], ty::mk_nil(tcx)), + "assume" => (0, vec![tcx.types.bool], ty::mk_nil(tcx)), ref other => { span_err!(tcx.sess, it.span, E0093, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b8cf215f89eec..d01b79068aa2c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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); } diff --git a/src/librustc_typeck/check/regionmanip.rs b/src/librustc_typeck/check/regionmanip.rs index ea70b9d9e2ef1..bb051ab15250c 100644 --- a/src/librustc_typeck/check/regionmanip.rs +++ b/src/librustc_typeck/check/regionmanip.rs @@ -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) => { + // `>::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); diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index ff16568aa63fc..23a8643aadcf5 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -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 { 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 // bad + // fn foo(&self) -> Self::Y // OK, desugars to next example + // fn foo(&self) -> ::Y // OK + // fn foo(&self) -> Self::X // OK, desugars to next example + // fn foo(&self) -> ::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) -> ::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>> = 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 `::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> { // 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); } } } + diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 258177bb72096..2a3f528809cfd 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -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(..) | diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b123d97d8970c..5ef9757b91ac2 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -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 } } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index f92c7764a69b0..79e1efa618f53 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -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={}", diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index bb8efd2991070..79443200ddf0e 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -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, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8d07f1e435503..9e184db3b84fe 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -23,31 +23,25 @@ Unlike most of the types that are present in Rust, the types computed for each item are in fact polytypes. In "layman's terms", this means that they are generic types that may have type parameters (more mathematically phrased, they are universally quantified over a set of -type parameters). Polytypes are represented by an instance of -`ty::Polytype`. This combines the core type along with a list of the +type parameters). TypeSchemes are represented by an instance of +`ty::TypeScheme`. This combines the core type along with a list of the bounds for each parameter. Type parameters themselves are represented as `ty_param()` instances. */ -use self::ConvertMethodContext::*; -use self::CreateTypeParametersForAssociatedTypesFlag::*; - -use astconv::{AstConv, ty_of_arg, AllowEqConstraints}; -use astconv::{ast_ty_to_ty, ast_region_to_region}; -use astconv; +use astconv::{mod, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region}; use metadata::csearch; -use middle::def; use middle::lang_items::SizedTraitLangItem; use middle::region; use middle::resolve_lifetime; use middle::subst; use middle::subst::{Substs}; use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use middle::ty::{mod, RegionEscape, Ty, Polytype}; +use middle::ty::{mod, RegionEscape, Ty, TypeScheme}; use middle::ty_fold::{mod, TypeFolder, TypeFoldable}; use middle::infer; use rscope::*; -use {CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; +use {CrateCtxt, no_params, write_ty_to_tcx}; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux; use util::ppaux::{Repr,UserString}; @@ -70,8 +64,8 @@ use syntax::visit; pub fn collect_item_types(ccx: &CrateCtxt) { fn collect_intrinsic_type(ccx: &CrateCtxt, lang_item: ast::DefId) { - let ty::Polytype { ty, .. } = - ccx.get_item_ty(lang_item); + let ty::TypeScheme { ty, .. } = + ccx.get_item_type_scheme(lang_item); ccx.tcx.intrinsic_defs.borrow_mut().insert(lang_item, ty); } @@ -139,12 +133,6 @@ pub trait ToTy<'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx>; } -impl<'a,'tcx> ToTy<'tcx> for ImplCtxt<'a,'tcx> { - fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> { - ast_ty_to_ty(self, rs, ast_ty) - } -} - impl<'a,'tcx> ToTy<'tcx> for CrateCtxt<'a,'tcx> { fn to_ty(&self, rs: &RS, ast_ty: &ast::Ty) -> Ty<'tcx> { ast_ty_to_ty(self, rs, ast_ty) @@ -154,7 +142,7 @@ impl<'a,'tcx> ToTy<'tcx> for CrateCtxt<'a,'tcx> { impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx } - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { + fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> { if id.krate != ast::LOCAL_CRATE { return csearch::get_type(self.tcx, id) } @@ -165,13 +153,10 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { let abi = self.tcx.map.get_foreign_abi(id.node); ty_of_foreign_item(self, &*foreign_item, abi) } - Some(ast_map::NodeTraitItem(trait_item)) => { - ty_of_trait_item(self, &*trait_item) - } x => { self.tcx.sess.bug(format!("unexpected sort of node \ - in get_item_ty(): {}", - x)[]); + in get_item_type_scheme(): {}", + x).as_slice()); } } } @@ -183,23 +168,16 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> { fn ty_infer(&self, span: Span) -> Ty<'tcx> { span_err!(self.tcx.sess, span, E0121, "the type placeholder `_` is not allowed within types on item signatures"); - ty::mk_err() + self.tcx().types.err } - fn associated_types_of_trait_are_valid(&self, _: Ty<'tcx>, _: ast::DefId) - -> bool { - false - } - - fn associated_type_binding(&self, - span: Span, - _: Option>, - _: ast::DefId, - _: ast::DefId) - -> Option> { - self.tcx().sess.span_err(span, "associated types may not be \ - referenced here"); - Some(ty::mk_err()) + fn projected_ty(&self, + _span: Span, + trait_ref: Rc>, + item_name: ast::Name) + -> Ty<'tcx> + { + ty::mk_projection(self.tcx, trait_ref, item_name) } } @@ -227,28 +205,22 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } ast::StructVariantKind(ref struct_def) => { - let pty = Polytype { - generics: ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes), + let scheme = TypeScheme { + generics: ty_generics_for_type_or_impl(ccx, generics), ty: enum_ty }; - convert_struct(ccx, &**struct_def, pty, variant.node.id); + convert_struct(ccx, &**struct_def, scheme, variant.node.id); enum_ty } }; - let pty = Polytype { - generics: ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes), + let scheme = TypeScheme { + generics: ty_generics_for_type_or_impl(ccx, generics), ty: result_ty }; - tcx.tcache.borrow_mut().insert(variant_def_id, pty); + tcx.tcache.borrow_mut().insert(variant_def_id, scheme); write_ty_to_tcx(tcx, variant.node.id, result_ty); } @@ -353,7 +325,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn make_method_ty<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, m: &ty::Method<'tcx>) { ccx.tcx.tcache.borrow_mut().insert( m.def_id, - Polytype { + TypeScheme { generics: m.generics.clone(), ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), ccx.tcx.mk_bare_fn(m.fty.clone())) }); } @@ -361,7 +333,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, trait_generics: &ty::Generics<'tcx>, - trait_items: &[ast::TraitItem], + _trait_items: &[ast::TraitItem], m_id: &ast::NodeId, m_name: &ast::Name, m_explicit_self: &ast::ExplicitSelf, @@ -374,19 +346,11 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty_generics_for_fn_or_method( ccx, m_generics, - (*trait_generics).clone(), - DontCreateTypeParametersForAssociatedTypes); + (*trait_generics).clone()); let (fty, explicit_self_category) = { - let tmcx = TraitMethodCtxt { - ccx: ccx, - trait_id: local_def(trait_id), - trait_items: trait_items[], - method_generics: &ty_generics, - }; - let trait_self_ty = ty::mk_self_type(tmcx.tcx(), - local_def(trait_id)); - astconv::ty_of_method(&tmcx, + let trait_self_ty = ty::mk_self_type(ccx.tcx); + astconv::ty_of_method(ccx, *m_unsafety, trait_self_ty, m_explicit_self, @@ -416,7 +380,7 @@ pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, write_ty_to_tcx(ccx.tcx, v.node.id, tt); /* add the field to the tcache */ ccx.tcx.tcache.borrow_mut().insert(local_def(v.node.id), - ty::Polytype { + ty::TypeScheme { generics: struct_generics.clone(), ty: tt }); @@ -444,36 +408,7 @@ pub fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_def: &ty::TraitDef<'tcx>, associated_type: &ast::AssociatedType) - -> ty::Polytype<'tcx> { - // Find the type parameter ID corresponding to this - // associated type. - let type_parameter_def = trait_def.generics - .types - .get_slice(subst::AssocSpace) - .iter() - .find(|def| { - def.def_id == local_def(associated_type.ty_param.id) - }); - let type_parameter_def = match type_parameter_def { - Some(type_parameter_def) => type_parameter_def, - None => { - ccx.tcx().sess.span_bug(associated_type.ty_param.span, - "`convert_associated_type()` didn't find \ - a type parameter ID corresponding to \ - this type") - } - }; - let param_type = ty::mk_param(ccx.tcx, - type_parameter_def.space, - type_parameter_def.index, - local_def(associated_type.ty_param.id)); - ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.ty_param.id), - Polytype { - generics: ty::Generics::empty(), - ty: param_type, - }); - write_ty_to_tcx(ccx.tcx, associated_type.ty_param.id, param_type); - +{ let associated_type = Rc::new(ty::AssociatedType { name: associated_type.ty_param.ident.name, vis: ast::Public, @@ -485,32 +420,16 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .borrow_mut() .insert(associated_type.def_id, ty::TypeTraitItem(associated_type)); - - Polytype { - generics: ty::Generics::empty(), - ty: param_type, - } -} - -#[deriving(Copy)] -enum ConvertMethodContext<'a> { - /// Used when converting implementation methods. - ImplConvertMethodContext, - /// Used when converting method signatures. The def ID is the def ID of - /// the trait we're translating. - TraitConvertMethodContext(ast::DefId, &'a [ast::TraitItem]), } fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, - convert_method_context: ConvertMethodContext, container: ImplOrTraitItemContainer, mut ms: I, untransformed_rcvr_ty: Ty<'tcx>, rcvr_ty_generics: &ty::Generics<'tcx>, rcvr_visibility: ast::Visibility) where I: Iterator<&'i ast::Method> { - debug!("convert_methods(untransformed_rcvr_ty={}, \ - rcvr_ty_generics={})", + debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={})", untransformed_rcvr_ty.repr(ccx.tcx), rcvr_ty_generics.repr(ccx.tcx)); @@ -523,7 +442,6 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, let m_def_id = local_def(m.id); let mty = Rc::new(ty_of_method(ccx, - convert_method_context, container, m, untransformed_rcvr_ty, @@ -536,7 +454,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, fty.repr(tcx)); tcx.tcache.borrow_mut().insert( m_def_id, - Polytype { + TypeScheme { generics: mty.generics.clone(), ty: fty }); @@ -552,7 +470,6 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, } fn ty_of_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - convert_method_context: ConvertMethodContext, container: ImplOrTraitItemContainer, m: &ast::Method, untransformed_rcvr_ty: Ty<'tcx>, @@ -563,37 +480,14 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>, ty_generics_for_fn_or_method( ccx, m.pe_generics(), - (*rcvr_ty_generics).clone(), - CreateTypeParametersForAssociatedTypes); - - let (fty, explicit_self_category) = match convert_method_context { - ImplConvertMethodContext => { - let imcx = ImplMethodCtxt { - ccx: ccx, - method_generics: &m_ty_generics, - }; - astconv::ty_of_method(&imcx, - m.pe_unsafety(), - untransformed_rcvr_ty, - m.pe_explicit_self(), - &*m.pe_fn_decl(), - m.pe_abi()) - } - TraitConvertMethodContext(trait_id, trait_items) => { - let tmcx = TraitMethodCtxt { - ccx: ccx, - trait_id: trait_id, - trait_items: trait_items, - method_generics: &m_ty_generics, - }; - astconv::ty_of_method(&tmcx, - m.pe_unsafety(), - untransformed_rcvr_ty, - m.pe_explicit_self(), - &*m.pe_fn_decl(), - m.pe_abi()) - } - }; + (*rcvr_ty_generics).clone()); + + let (fty, explicit_self_category) = astconv::ty_of_method(ccx, + m.pe_unsafety(), + untransformed_rcvr_ty, + m.pe_explicit_self(), + &*m.pe_fn_decl(), + m.pe_abi()); // if the method specifies a visibility, use that, otherwise // inherit the visibility from the impl (so `foo` in `pub impl @@ -641,392 +535,6 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, } } -fn is_associated_type_valid_for_param(ty: Ty, - trait_id: ast::DefId, - generics: &ty::Generics) - -> bool { - if let ty::ty_param(param_ty) = ty.sty { - let type_parameter = generics.types.get(param_ty.space, param_ty.idx as uint); - for trait_bound in type_parameter.bounds.trait_bounds.iter() { - if trait_bound.def_id() == trait_id { - return true - } - } - } - - false -} - -fn find_associated_type_in_generics<'tcx>(tcx: &ty::ctxt<'tcx>, - span: Span, - self_ty: Option>, - associated_type_id: ast::DefId, - generics: &ty::Generics<'tcx>) - -> Option> -{ - debug!("find_associated_type_in_generics(ty={}, associated_type_id={}, generics={}", - self_ty.repr(tcx), associated_type_id.repr(tcx), generics.repr(tcx)); - - let self_ty = match self_ty { - None => { - return None; - } - Some(ty) => ty, - }; - - match self_ty.sty { - ty::ty_param(ref param_ty) => { - let param_id = param_ty.def_id; - for type_parameter in generics.types.iter() { - if type_parameter.def_id == associated_type_id - && type_parameter.associated_with == Some(param_id) { - return Some(ty::mk_param_from_def(tcx, type_parameter)); - } - } - - tcx.sess.span_err( - span, - format!("no suitable bound on `{}`", - self_ty.user_string(tcx))[]); - Some(ty::mk_err()) - } - _ => { - tcx.sess.span_err( - span, - "it is currently unsupported to access associated types except \ - through a type parameter; this restriction will be lifted in time"); - Some(ty::mk_err()) - } - } -} - -fn type_is_self(ty: Ty) -> bool { - match ty.sty { - ty::ty_param(ref param_ty) if param_ty.is_self() => true, - _ => false, - } -} - -struct ImplCtxt<'a,'tcx:'a> { - ccx: &'a CrateCtxt<'a,'tcx>, - opt_trait_ref_id: Option, - impl_items: &'a [ast::ImplItem], - impl_generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.ccx.tcx - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.ccx.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.ccx.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.ccx.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - // OK if the trait with the associated type is the trait we're - // implementing. - match self.opt_trait_ref_id { - Some(trait_ref_id) if trait_ref_id == trait_id => { - if type_is_self(ty) { - return true - } - } - Some(_) | None => {} - } - - // OK if the trait with the associated type is one of the traits in - // our bounds. - is_associated_type_valid_for_param(ty, trait_id, self.impl_generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - trait_id: ast::DefId, - associated_type_id: ast::DefId) - -> Option> - { - match self.opt_trait_ref_id { - // It's an associated type on the trait that we're - // implementing. - Some(trait_ref_id) if trait_ref_id == trait_id => { - let trait_def = ty::lookup_trait_def(self.tcx(), trait_id); - assert!(trait_def.generics.types - .get_slice(subst::AssocSpace) - .iter() - .any(|type_param_def| type_param_def.def_id == associated_type_id)); - let associated_type = ty::impl_or_trait_item(self.ccx.tcx, associated_type_id); - for impl_item in self.impl_items.iter() { - match *impl_item { - ast::MethodImplItem(_) => {} - ast::TypeImplItem(ref typedef) => { - if associated_type.name() == typedef.ident.name { - return Some(self.ccx.to_ty(&ExplicitRscope, &*typedef.typ)) - } - } - } - } - self.ccx - .tcx - .sess - .span_bug(span, - "ImplCtxt::associated_type_binding(): didn't \ - find associated type") - } - Some(_) | None => {} - } - - // OK then, it should be an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.ccx.tcx, - span, - self_ty, - associated_type_id, - self.impl_generics) - } -} - -struct FnCtxt<'a,'tcx:'a> { - ccx: &'a CrateCtxt<'a,'tcx>, - generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx> AstConv<'tcx> for FnCtxt<'a,'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.ccx.tcx - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.ccx.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.ccx.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.ccx.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - // OK if the trait with the associated type is one of the traits in - // our bounds. - is_associated_type_valid_for_param(ty, trait_id, self.generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - _: ast::DefId, - associated_type_id: ast::DefId) - -> Option> { - debug!("collect::FnCtxt::associated_type_binding()"); - - // The ID should map to an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.ccx.tcx, - span, - self_ty, - associated_type_id, - self.generics) - } -} - -struct ImplMethodCtxt<'a,'tcx:'a> { - ccx: &'a CrateCtxt<'a,'tcx>, - method_generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx> AstConv<'tcx> for ImplMethodCtxt<'a,'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.ccx.tcx - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.ccx.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.ccx.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.ccx.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - is_associated_type_valid_for_param(ty, trait_id, self.method_generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - _: ast::DefId, - associated_type_id: ast::DefId) - -> Option> { - debug!("collect::ImplMethodCtxt::associated_type_binding()"); - - // The ID should map to an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.ccx.tcx, - span, - self_ty, - associated_type_id, - self.method_generics) - } -} - -struct TraitMethodCtxt<'a,'tcx:'a> { - ccx: &'a CrateCtxt<'a,'tcx>, - trait_id: ast::DefId, - trait_items: &'a [ast::TraitItem], - method_generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.ccx.tcx - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.ccx.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.ccx.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.ccx.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - // OK if the trait with the associated type is this trait. - if self.trait_id == trait_id && type_is_self(ty) { - return true - } - - // OK if the trait with the associated type is one of the traits in - // our bounds. - is_associated_type_valid_for_param(ty, trait_id, self.method_generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - trait_id: ast::DefId, - associated_type_id: ast::DefId) - -> Option> { - debug!("collect::TraitMethodCtxt::associated_type_binding()"); - - // If this is one of our own associated types, return it. - if trait_id == self.trait_id { - let mut index = 0; - for item in self.trait_items.iter() { - match *item { - ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} - ast::TypeTraitItem(ref item) => { - if local_def(item.ty_param.id) == associated_type_id { - return Some(ty::mk_param(self.tcx(), - subst::AssocSpace, - index, - associated_type_id)) - } - index += 1; - } - } - } - self.ccx - .tcx - .sess - .span_bug(span, - "TraitMethodCtxt::associated_type_binding(): \ - didn't find associated type anywhere in the item \ - list") - } - - // The ID should map to an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.ccx.tcx, - span, - self_ty, - associated_type_id, - self.method_generics) - } -} - -struct GenericsCtxt<'a,'tcx:'a,AC:'a> { - chain: &'a AC, - associated_types_generics: &'a ty::Generics<'tcx>, -} - -impl<'a,'tcx,AC:AstConv<'tcx>> AstConv<'tcx> for GenericsCtxt<'a,'tcx,AC> { - fn tcx(&self) -> &ty::ctxt<'tcx> { - self.chain.tcx() - } - - fn get_item_ty(&self, id: ast::DefId) -> ty::Polytype<'tcx> { - self.chain.get_item_ty(id) - } - - fn get_trait_def(&self, id: ast::DefId) -> Rc> { - self.chain.get_trait_def(id) - } - - fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.chain.ty_infer(span) - } - - fn associated_types_of_trait_are_valid(&self, - ty: Ty<'tcx>, - trait_id: ast::DefId) - -> bool { - // OK if the trait with the associated type is one of the traits in - // our bounds. - is_associated_type_valid_for_param(ty, - trait_id, - self.associated_types_generics) - } - - fn associated_type_binding(&self, - span: Span, - self_ty: Option>, - _: ast::DefId, - associated_type_id: ast::DefId) - -> Option> { - debug!("collect::GenericsCtxt::associated_type_binding()"); - - // The ID should map to an associated type on one of the traits in - // our bounds. - find_associated_type_in_generics(self.chain.tcx(), - span, - self_ty, - associated_type_id, - self.associated_types_generics) - } -} - pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { let tcx = ccx.tcx; debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id); @@ -1034,11 +542,11 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { // These don't define types. ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {} ast::ItemEnum(ref enum_definition, ref generics) => { - let pty = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, pty.ty); + let scheme = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, scheme.ty); get_enum_variant_types(ccx, - pty.ty, - enum_definition.variants[], + scheme.ty, + enum_definition.variants.as_slice(), generics); }, ast::ItemImpl(_, @@ -1047,10 +555,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ref selfty, ref impl_items) => { // Create generics from the generics specified in the impl head. - let ty_generics = ty_generics_for_type_or_impl( - ccx, - generics, - CreateTypeParametersForAssociatedTypes); + let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let selfty = ccx.to_ty(&ExplicitRscope, &**selfty); write_ty_to_tcx(tcx, it.id, selfty); @@ -1058,7 +563,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { tcx.tcache .borrow_mut() .insert(local_def(it.id), - Polytype { + TypeScheme { generics: ty_generics.clone(), ty: selfty, }); @@ -1074,20 +579,6 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { it.vis }; - let icx = ImplCtxt { - ccx: ccx, - opt_trait_ref_id: match *opt_trait_ref { - None => None, - Some(ref ast_trait_ref) => { - Some(lookup_def_tcx(tcx, - ast_trait_ref.path.span, - ast_trait_ref.ref_id).def_id()) - } - }, - impl_items: impl_items[], - impl_generics: &ty_generics, - }; - let mut methods = Vec::new(); for impl_item in impl_items.iter() { match *impl_item { @@ -1101,11 +592,11 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { methods.push(&**method); } ast::TypeImplItem(ref typedef) => { - let typ = icx.to_ty(&ExplicitRscope, &*typedef.typ); + let typ = ccx.to_ty(&ExplicitRscope, &*typedef.typ); tcx.tcache .borrow_mut() .insert(local_def(typedef.id), - Polytype { + TypeScheme { generics: ty::Generics::empty(), ty: typ, }); @@ -1126,7 +617,6 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { } convert_methods(ccx, - ImplConvertMethodContext, ImplContainer(local_def(it.id)), methods.into_iter(), selfty, @@ -1134,11 +624,11 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { parent_visibility); for trait_ref in opt_trait_ref.iter() { - astconv::instantiate_trait_ref(&icx, + astconv::instantiate_trait_ref(ccx, &ExplicitRscope, trait_ref, Some(selfty), - AllowEqConstraints::DontAllow); + None); } }, ast::ItemTrait(_, _, _, ref trait_methods) => { @@ -1149,10 +639,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { trait_def.repr(ccx.tcx())); for trait_method in trait_methods.iter() { - let self_type = ty::mk_param(ccx.tcx, - subst::SelfSpace, - 0, - local_def(it.id)); + let self_type = ty::mk_self_type(tcx); match *trait_method { ast::RequiredMethod(ref type_method) => { let rscope = BindingRscope::new(); @@ -1178,13 +665,8 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { } // Run convert_methods on the provided methods. - let untransformed_rcvr_ty = ty::mk_self_type(tcx, - local_def(it.id)); - let convert_method_context = - TraitConvertMethodContext(local_def(it.id), - trait_methods[]); + let untransformed_rcvr_ty = ty::mk_self_type(tcx); convert_methods(ccx, - convert_method_context, TraitContainer(local_def(it.id)), trait_methods.iter().filter_map(|m| match *m { ast::RequiredMethod(_) => None, @@ -1202,12 +684,12 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { }, ast::ItemStruct(ref struct_def, _) => { // Write the class type. - let pty = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, pty.ty); + let scheme = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, scheme.ty); - tcx.tcache.borrow_mut().insert(local_def(it.id), pty.clone()); + tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); - convert_struct(ccx, &**struct_def, pty, it.id); + convert_struct(ccx, &**struct_def, scheme, it.id); }, ast::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); @@ -1218,22 +700,22 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { // This call populates the type cache with the converted type // of the item in passing. All we have to do here is to write // it into the node type table. - let pty = ty_of_item(ccx, it); - write_ty_to_tcx(tcx, it.id, pty.ty); + let scheme = ty_of_item(ccx, it); + write_ty_to_tcx(tcx, it.id, scheme.ty); }, } } pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_def: &ast::StructDef, - pty: ty::Polytype<'tcx>, + scheme: ty::TypeScheme<'tcx>, id: ast::NodeId) { let tcx = ccx.tcx; // Write the type of each of the members and check for duplicate fields. let mut seen_fields: FnvHashMap = FnvHashMap::new(); let field_tys = struct_def.fields.iter().map(|f| { - let result = convert_field(ccx, &pty.generics, f, local_def(id)); + let result = convert_field(ccx, &scheme.generics, f, local_def(id)); if result.name != special_idents::unnamed_field.name { let dup = match seen_fields.get(&result.name) { @@ -1258,7 +740,7 @@ pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, tcx.struct_fields.borrow_mut().insert(local_def(id), Rc::new(field_tys)); - let substs = mk_item_substs(ccx, &pty.generics); + let substs = mk_item_substs(ccx, &scheme.generics); let selfty = ty::mk_struct(tcx, local_def(id), tcx.mk_substs(substs)); // If this struct is enum-like or tuple-like, create the type of its @@ -1270,7 +752,7 @@ pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Enum-like. write_ty_to_tcx(tcx, ctor_id, selfty); - tcx.tcache.borrow_mut().insert(local_def(ctor_id), pty); + tcx.tcache.borrow_mut().insert(local_def(ctor_id), scheme); } else if struct_def.fields[0].node.kind.is_unnamed() { // Tuple-like. let inputs: Vec<_> = struct_def.fields.iter().map( @@ -1282,8 +764,8 @@ pub fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, selfty); write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); tcx.tcache.borrow_mut().insert(local_def(ctor_id), - Polytype { - generics: pty.generics, + TypeScheme { + generics: scheme.generics, ty: ctor_fn_ty }); } @@ -1302,10 +784,10 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: &ast::ForeignItem) { // convenient way to extract the ABI. - ndm let abi = ccx.tcx.map.get_foreign_abi(i.id); - let pty = ty_of_foreign_item(ccx, i, abi); - write_ty_to_tcx(ccx.tcx, i.id, pty.ty); + let scheme = ty_of_foreign_item(ccx, i, abi); + write_ty_to_tcx(ccx.tcx, i.id, scheme.ty); - ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), pty); + ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), scheme); } fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -1326,7 +808,8 @@ fn get_trait_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) - -> Rc> { + -> Rc> +{ let def_id = local_def(it.id); let tcx = ccx.tcx; if let Some(def) = tcx.trait_defs.borrow().get(&def_id) { @@ -1347,7 +830,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }; - let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, it.id, generics, items)); + let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, generics)); let ty_generics = ty_generics_for_trait(ccx, it.id, @@ -1355,32 +838,41 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics, items); - let self_param_ty = ty::ParamTy::for_self(def_id); + let self_param_ty = ty::ParamTy::for_self(); let bounds = compute_bounds(ccx, - token::SELF_KEYWORD_NAME, - self_param_ty, + self_param_ty.to_ty(ccx.tcx), bounds.as_slice(), it.span); - let substs = mk_item_substs(ccx, &ty_generics); + let associated_type_names: Vec<_> = + items.iter() + .filter_map(|item| { + match *item { + ast::RequiredMethod(_) | ast::ProvidedMethod(_) => None, + ast::TypeTraitItem(ref data) => Some(data.ty_param.ident.name), + } + }) + .collect(); + + let trait_ref = Rc::new(ty::TraitRef { + def_id: def_id, + substs: substs + }); + let trait_def = Rc::new(ty::TraitDef { unsafety: unsafety, generics: ty_generics, bounds: bounds, - trait_ref: Rc::new(ty::TraitRef { - def_id: def_id, - substs: ccx.tcx.mk_substs(substs) - }) + trait_ref: trait_ref, + associated_type_names: associated_type_names, }); tcx.trait_defs.borrow_mut().insert(def_id, trait_def.clone()); return trait_def; fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - trait_id: ast::NodeId, - generics: &ast::Generics, - items: &[ast::TraitItem]) + generics: &ast::Generics) -> subst::Substs<'tcx> { // Creates a no-op substitution for the trait's type parameters. @@ -1400,127 +892,92 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .iter() .enumerate() .map(|(i, def)| ty::mk_param(ccx.tcx, subst::TypeSpace, - i as u32, local_def(def.id))) + i as u32, def.ident.name)) .collect(); - // ...and also create generics synthesized from the associated types. - let mut index = 0; - let assoc_types: Vec<_> = - items.iter() - .flat_map(|item| match *item { - ast::TypeTraitItem(ref trait_item) => { - index += 1; - Some(ty::mk_param(ccx.tcx, - subst::AssocSpace, - index - 1, - local_def(trait_item.ty_param.id))).into_iter() - } - ast::RequiredMethod(_) | ast::ProvidedMethod(_) => { - None.into_iter() - } - }) - .collect(); - - let self_ty = - ty::mk_param(ccx.tcx, subst::SelfSpace, 0, local_def(trait_id)); + // ...and also create the `Self` parameter. + let self_ty = ty::mk_self_type(ccx.tcx); - subst::Substs::new_trait(types, regions, assoc_types, self_ty) + subst::Substs::new_trait(types, regions, self_ty) } } pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) - -> ty::Polytype<'tcx> { + -> ty::TypeScheme<'tcx> { let def_id = local_def(it.id); let tcx = ccx.tcx; - if let Some(pty) = tcx.tcache.borrow().get(&def_id) { - return pty.clone(); + if let Some(scheme) = tcx.tcache.borrow().get(&def_id) { + return scheme.clone(); } match it.node { ast::ItemStatic(ref t, _, _) | ast::ItemConst(ref t, _) => { let typ = ccx.to_ty(&ExplicitRscope, &**t); - let pty = no_params(typ); + let scheme = no_params(typ); - tcx.tcache.borrow_mut().insert(local_def(it.id), pty.clone()); - return pty; + tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); + return scheme; } ast::ItemFn(ref decl, unsafety, abi, ref generics, _) => { - let ty_generics = ty_generics_for_fn_or_method( - ccx, - generics, - ty::Generics::empty(), - CreateTypeParametersForAssociatedTypes); - let tofd = { - let fcx = FnCtxt { - ccx: ccx, - generics: &ty_generics, - }; - astconv::ty_of_bare_fn(&fcx, unsafety, abi, &**decl) - }; - let pty = Polytype { + let ty_generics = ty_generics_for_fn_or_method(ccx, + generics, + ty::Generics::empty()); + let tofd = astconv::ty_of_bare_fn(ccx, unsafety, abi, &**decl); + let scheme = TypeScheme { generics: ty_generics, ty: ty::mk_bare_fn(ccx.tcx, Some(local_def(it.id)), ccx.tcx.mk_bare_fn(tofd)) }; debug!("type of {} (id {}) is {}", token::get_ident(it.ident), it.id, - pty.repr(tcx)); + scheme.repr(tcx)); - ccx.tcx.tcache.borrow_mut().insert(local_def(it.id), pty.clone()); - return pty; + ccx.tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); + return scheme; } ast::ItemTy(ref t, ref generics) => { match tcx.tcache.borrow_mut().get(&local_def(it.id)) { - Some(pty) => return pty.clone(), + Some(scheme) => return scheme.clone(), None => { } } - let pty = { + let scheme = { let ty = ccx.to_ty(&ExplicitRscope, &**t); - Polytype { - generics: ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes), + TypeScheme { + generics: ty_generics_for_type_or_impl(ccx, generics), ty: ty } }; - tcx.tcache.borrow_mut().insert(local_def(it.id), pty.clone()); - return pty; + tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); + return scheme; } ast::ItemEnum(_, ref generics) => { // Create a new generic polytype. - let ty_generics = ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes); + let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); let t = ty::mk_enum(tcx, local_def(it.id), tcx.mk_substs(substs)); - let pty = Polytype { + let scheme = TypeScheme { generics: ty_generics, ty: t }; - tcx.tcache.borrow_mut().insert(local_def(it.id), pty.clone()); - return pty; + tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); + return scheme; } ast::ItemTrait(..) => { tcx.sess.span_bug(it.span, "invoked ty_of_item on trait"); } ast::ItemStruct(_, ref generics) => { - let ty_generics = ty_generics_for_type_or_impl( - ccx, - generics, - DontCreateTypeParametersForAssociatedTypes); + let ty_generics = ty_generics_for_type_or_impl(ccx, generics); let substs = mk_item_substs(ccx, &ty_generics); let t = ty::mk_struct(tcx, local_def(it.id), tcx.mk_substs(substs)); - let pty = Polytype { + let scheme = TypeScheme { generics: ty_generics, ty: t }; - tcx.tcache.borrow_mut().insert(local_def(it.id), pty.clone()); - return pty; + tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone()); + return scheme; } ast::ItemImpl(..) | ast::ItemMod(_) | ast::ItemForeignMod(_) | ast::ItemMac(_) => panic!(), @@ -1529,7 +986,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::ForeignItem, - abi: abi::Abi) -> ty::Polytype<'tcx> + abi: abi::Abi) -> ty::TypeScheme<'tcx> { match it.node { ast::ForeignItemFn(ref fn_decl, ref generics) => { @@ -1540,7 +997,7 @@ pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, abi) } ast::ForeignItemStatic(ref t, _) => { - ty::Polytype { + ty::TypeScheme { generics: ty::Generics::empty(), ty: ast_ty_to_ty(ccx, &ExplicitRscope, &**t) } @@ -1548,81 +1005,34 @@ pub fn ty_of_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn ty_of_trait_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - trait_item: &ast::TraitItem) - -> ty::Polytype<'tcx> { - match *trait_item { - ast::RequiredMethod(ref m) => { - ccx.tcx.sess.span_bug(m.span, - "ty_of_trait_item() on required method") - } - ast::ProvidedMethod(ref m) => { - ccx.tcx.sess.span_bug(m.span, - "ty_of_trait_item() on provided method") - } - ast::TypeTraitItem(ref associated_type) => { - let parent = ccx.tcx.map.get_parent(associated_type.ty_param.id); - let trait_def = match ccx.tcx.map.get(parent) { - ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item), - _ => { - ccx.tcx.sess.span_bug(associated_type.ty_param.span, - "associated type's parent wasn't \ - an item?!") - } - }; - convert_associated_type(ccx, &*trait_def, &**associated_type) - } - } -} - fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &ast::Generics, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) + generics: &ast::Generics) -> ty::Generics<'tcx> { ty_generics(ccx, subst::TypeSpace, generics.lifetimes[], generics.ty_params[], ty::Generics::empty(), - &generics.where_clause, - create_type_parameters_for_associated_types) + &generics.where_clause) } fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_id: ast::NodeId, substs: &'tcx subst::Substs<'tcx>, ast_generics: &ast::Generics, - items: &[ast::TraitItem]) + trait_items: &[ast::TraitItem]) -> ty::Generics<'tcx> { + debug!("ty_generics_for_trait(trait_id={}, substs={})", + local_def(trait_id).repr(ccx.tcx), substs.repr(ccx.tcx)); + let mut generics = ty_generics(ccx, subst::TypeSpace, ast_generics.lifetimes[], ast_generics.ty_params[], ty::Generics::empty(), - &ast_generics.where_clause, - DontCreateTypeParametersForAssociatedTypes); - - // Add in type parameters for any associated types. - for item in items.iter() { - match *item { - ast::TypeTraitItem(ref associated_type) => { - let def = - get_or_create_type_parameter_def( - ccx, - subst::AssocSpace, - &associated_type.ty_param, - generics.types.len(subst::AssocSpace) as u32, - Some(local_def(trait_id))); - ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id, - def.clone()); - generics.types.push(subst::AssocSpace, def); - } - ast::ProvidedMethod(_) | ast::RequiredMethod(_) => {} - } - } + &ast_generics.where_clause); // Add in the self type parameter. // @@ -1631,8 +1041,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let param_id = trait_id; let self_trait_ref = - Rc::new(ty::Binder(ty::TraitRef { def_id: local_def(trait_id), - substs: substs })); + Rc::new(ty::TraitRef { def_id: local_def(trait_id), + substs: substs }); let def = ty::TypeParameterDef { space: subst::SelfSpace, @@ -1642,9 +1052,9 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, bounds: ty::ParamBounds { region_bounds: vec!(), builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: vec!(self_trait_ref.clone()), + trait_bounds: vec!(ty::Binder(self_trait_ref.clone())), + projection_bounds: vec!(), }, - associated_with: None, default: None }; @@ -1652,18 +1062,54 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics.types.push(subst::SelfSpace, def); - generics.predicates.push(subst::SelfSpace, - ty::Predicate::Trait(self_trait_ref)); + generics.predicates.push(subst::SelfSpace, self_trait_ref.as_predicate()); - generics + let assoc_predicates = predicates_for_associated_types(ccx, + &self_trait_ref, + trait_items); + + debug!("ty_generics_for_trait: assoc_predicates={}", assoc_predicates.repr(ccx.tcx)); + + for assoc_predicate in assoc_predicates.into_iter() { + generics.predicates.push(subst::TypeSpace, assoc_predicate); + } + + return generics; + + fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + self_trait_ref: &Rc>, + trait_items: &[ast::TraitItem]) + -> Vec> + { + trait_items + .iter() + .flat_map(|trait_item| { + let assoc_type_def = match *trait_item { + ast::TypeTraitItem(ref assoc_type) => &assoc_type.ty_param, + ast::RequiredMethod(..) | ast::ProvidedMethod(..) => { + return vec!().into_iter(); + } + }; + + let assoc_ty = ty::mk_projection(ccx.tcx, + self_trait_ref.clone(), + assoc_type_def.ident.name); + + let bounds = compute_bounds(ccx, + assoc_ty, + assoc_type_def.bounds.as_slice(), + assoc_type_def.span); + + ty::predicates(ccx.tcx, assoc_ty, &bounds).into_iter() + }) + .collect() + } } fn ty_generics_for_fn_or_method<'tcx,AC>( this: &AC, generics: &ast::Generics, - base_generics: ty::Generics<'tcx>, - create_type_parameters_for_associated_types: - CreateTypeParametersForAssociatedTypesFlag) + base_generics: ty::Generics<'tcx>) -> ty::Generics<'tcx> where AC: AstConv<'tcx> { let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics); @@ -1672,8 +1118,7 @@ fn ty_generics_for_fn_or_method<'tcx,AC>( early_lifetimes[], generics.ty_params[], base_generics, - &generics.where_clause, - create_type_parameters_for_associated_types) + &generics.where_clause) } // Add the Sized bound, unless the type parameter is marked as `?Sized`. @@ -1722,20 +1167,12 @@ fn add_unsized_bound<'tcx,AC>(this: &AC, } } -#[deriving(Clone, PartialEq, Eq)] -enum CreateTypeParametersForAssociatedTypesFlag { - DontCreateTypeParametersForAssociatedTypes, - CreateTypeParametersForAssociatedTypes, -} - fn ty_generics<'tcx,AC>(this: &AC, space: subst::ParamSpace, lifetime_defs: &[ast::LifetimeDef], types: &[ast::TyParam], base_generics: ty::Generics<'tcx>, - where_clause: &ast::WhereClause, - create_type_parameters_for_associated_types_flag: - CreateTypeParametersForAssociatedTypesFlag) + where_clause: &ast::WhereClause) -> ty::Generics<'tcx> where AC: AstConv<'tcx> { @@ -1756,46 +1193,18 @@ fn ty_generics<'tcx,AC>(this: &AC, assert!(result.types.is_empty_in(space)); - // First, create the virtual type parameters for associated types if - // necessary. - let mut associated_types_generics = ty::Generics::empty(); - match create_type_parameters_for_associated_types_flag { - DontCreateTypeParametersForAssociatedTypes => {} - CreateTypeParametersForAssociatedTypes => { - create_type_parameters_for_associated_types(this, space, types, - &mut associated_types_generics); - } - } - // Now create the real type parameters. - let gcx = GenericsCtxt { - chain: this, - associated_types_generics: &associated_types_generics, - }; for (i, param) in types.iter().enumerate() { - let def = get_or_create_type_parameter_def(&gcx, + let def = get_or_create_type_parameter_def(this, space, param, - i as u32, - None); + i as u32); debug!("ty_generics: def for type param: {}, {}", def.repr(this.tcx()), space); result.types.push(space, def); } - // Append the associated types to the result. - for associated_type_param in associated_types_generics.types - .get_slice(space) - .iter() { - assert!(result.types.get_slice(space).len() == - associated_type_param.index as uint); - debug!("ty_generics: def for associated type: {}, {}", - associated_type_param.repr(this.tcx()), - space); - result.types.push(space, (*associated_type_param).clone()); - } - // Just for fun, also push the bounds from the type parameters // into the predicates list. This is currently kind of non-DRY. create_predicates(this.tcx(), &mut result, space); @@ -1809,16 +1218,21 @@ fn ty_generics<'tcx,AC>(this: &AC, for bound in bound_pred.bounds.iter() { match bound { &ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => { + let mut projections = Vec::new(); + let trait_ref = astconv::instantiate_poly_trait_ref( this, &ExplicitRscope, - //@jroesch: for now trait_ref, poly_trait_ref? poly_trait_ref, Some(ty), - AllowEqConstraints::Allow + &mut projections, ); - result.predicates.push(space, ty::Predicate::Trait(trait_ref)); + result.predicates.push(space, trait_ref.as_predicate()); + + for projection in projections.iter() { + result.predicates.push(space, projection.as_predicate()); + } } &ast::TyParamBound::RegionTyParamBound(ref lifetime) => { @@ -1850,91 +1264,6 @@ fn ty_generics<'tcx,AC>(this: &AC, return result; - fn create_type_parameters_for_associated_types<'tcx, AC>( - this: &AC, - space: subst::ParamSpace, - types: &[ast::TyParam], - associated_types_generics: &mut ty::Generics<'tcx>) - where AC: AstConv<'tcx> - { - // The idea here is roughly as follows. We start with - // an item that is paramerized by various type parameters - // with bounds: - // - // fn foo(t: T) { ... } - // - // The traits in those bounds declare associated types: - // - // trait Iterator { type Elem; ... } - // - // And we rewrite the original function so that every associated - // type is bound to some fresh type parameter: - // - // fn foo>(t: T) { ... } - - // Number of synthetic type parameters created thus far - let mut index = 0; - - // Iterate over the each type parameter `T` (from the example) - for param in types.iter() { - // Iterate over the bound `Iterator` - for bound in param.bounds.iter() { - // In the above example, `ast_trait_ref` is `Iterator`. - let ast_trait_ref = match *bound { - ast::TraitTyParamBound(ref r, _) => r, - ast::RegionTyParamBound(..) => { continue; } - }; - - let trait_def_id = - match lookup_def_tcx(this.tcx(), - ast_trait_ref.trait_ref.path.span, - ast_trait_ref.trait_ref.ref_id) { - def::DefTrait(trait_def_id) => trait_def_id, - _ => { - this.tcx().sess.span_bug(ast_trait_ref.trait_ref.path.span, - "not a trait?!") - } - }; - - // trait_def_id is def-id of `Iterator` - let trait_def = ty::lookup_trait_def(this.tcx(), trait_def_id); - let associated_type_defs = trait_def.generics.types.get_slice(subst::AssocSpace); - - // Find any associated type bindings in the bound. - let ref segments = ast_trait_ref.trait_ref.path.segments; - let bindings = segments[segments.len() -1].parameters.bindings(); - - // Iterate over each associated type `Elem` - for associated_type_def in associated_type_defs.iter() { - if bindings.iter().any(|b| associated_type_def.name.ident() == b.ident) { - // Don't add a variable for a bound associated type. - continue; - } - - // Create the fresh type parameter `A` - let def = ty::TypeParameterDef { - name: associated_type_def.name, - def_id: associated_type_def.def_id, - space: space, - index: types.len() as u32 + index, - bounds: ty::ParamBounds { - builtin_bounds: associated_type_def.bounds.builtin_bounds, - - // FIXME(#18178) -- we should add the other bounds, but - // that requires subst and more logic - trait_bounds: Vec::new(), - region_bounds: Vec::new(), - }, - associated_with: Some(local_def(param.id)), - default: None, - }; - associated_types_generics.types.push(space, def); - index += 1; - } - } - } - } - fn create_predicates<'tcx>( tcx: &ty::ctxt<'tcx>, result: &mut ty::Generics<'tcx>, @@ -1964,8 +1293,7 @@ fn ty_generics<'tcx,AC>(this: &AC, fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, space: subst::ParamSpace, param: &ast::TyParam, - index: u32, - associated_with: Option) + index: u32) -> ty::TypeParameterDef<'tcx> where AC: AstConv<'tcx> { @@ -1974,10 +1302,9 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, None => { } } - let param_ty = ty::ParamTy::new(space, index, local_def(param.id)); + let param_ty = ty::ParamTy::new(space, index, param.ident.name); let bounds = compute_bounds(this, - param.ident.name, - param_ty, + param_ty.to_ty(this.tcx()), param.bounds[], param.span); let default = match param.default { @@ -2006,7 +1333,6 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, index: index, name: param.ident.name, def_id: local_def(param.id), - associated_with: associated_with, bounds: bounds, default: default }; @@ -2020,8 +1346,7 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the /// built-in trait (formerly known as kind): Send. fn compute_bounds<'tcx,AC>(this: &AC, - name_of_bounded_thing: ast::Name, - param_ty: ty::ParamTy, + param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound], span: Span) -> ty::ParamBounds<'tcx> @@ -2037,7 +1362,7 @@ fn compute_bounds<'tcx,AC>(this: &AC, span); check_bounds_compatible(this.tcx(), - name_of_bounded_thing, + param_ty, ¶m_bounds, span); @@ -2047,7 +1372,7 @@ fn compute_bounds<'tcx,AC>(this: &AC, } fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, - name_of_bounded_thing: ast::Name, + param_ty: Ty<'tcx>, param_bounds: &ty::ParamBounds<'tcx>, span: Span) { // Currently the only bound which is incompatible with other bounds is @@ -2060,9 +1385,9 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id()); if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) { span_err!(tcx.sess, span, E0129, - "incompatible bounds on type parameter `{}`, \ + "incompatible bounds on `{}`, \ bound `{}` does not allow unsized type", - name_of_bounded_thing.user_string(tcx), + param_ty.user_string(tcx), trait_ref.user_string(tcx)); } true @@ -2072,7 +1397,7 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>, fn conv_param_bounds<'tcx,AC>(this: &AC, span: Span, - param_ty: ty::ParamTy, + param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound]) -> ty::ParamBounds<'tcx> where AC: AstConv<'tcx> @@ -2081,14 +1406,17 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, trait_bounds, region_bounds } = astconv::partition_bounds(this.tcx(), span, ast_bounds.as_slice()); - let trait_bounds: Vec> = + + let mut projection_bounds = Vec::new(); + + let trait_bounds: Vec = trait_bounds.into_iter() .map(|bound| { astconv::instantiate_poly_trait_ref(this, &ExplicitRscope, bound, - Some(param_ty.to_ty(this.tcx())), - AllowEqConstraints::Allow) + Some(param_ty), + &mut projection_bounds) }) .collect(); let region_bounds: Vec = @@ -2099,6 +1427,7 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, region_bounds: region_bounds, builtin_bounds: builtin_bounds, trait_bounds: trait_bounds, + projection_bounds: projection_bounds, } } @@ -2107,7 +1436,7 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: ast::DefId, ast_generics: &ast::Generics, abi: abi::Abi) - -> ty::Polytype<'tcx> { + -> ty::TypeScheme<'tcx> { for i in decl.inputs.iter() { match (*i).pat.node { ast::PatIdent(_, _, _) => (), @@ -2119,11 +1448,9 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } - let ty_generics_for_fn_or_method = ty_generics_for_fn_or_method( - ccx, - ast_generics, - ty::Generics::empty(), - DontCreateTypeParametersForAssociatedTypes); + let ty_generics_for_fn_or_method = ty_generics_for_fn_or_method(ccx, + ast_generics, + ty::Generics::empty()); let rb = BindingRscope::new(); let input_tys = decl.inputs .iter() @@ -2144,16 +1471,16 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, abi: abi, unsafety: ast::Unsafety::Unsafe, sig: ty::Binder(ty::FnSig {inputs: input_tys, - output: output, - variadic: decl.variadic}) + output: output, + variadic: decl.variadic}), })); - let pty = Polytype { + let scheme = TypeScheme { generics: ty_generics_for_fn_or_method, ty: t_fn }; - ccx.tcx.tcache.borrow_mut().insert(def_id, pty.clone()); - return pty; + ccx.tcx.tcache.borrow_mut().insert(def_id, scheme.clone()); + return scheme; } pub fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 3418cded022c9..353db82eb027d 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -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, }), })); diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 30869186ba5e9..c4c33f24f87e2 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -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; + 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( + generics, + trait_ref.def_id, + trait_def.generics.types.as_slice(), + trait_def.generics.regions.as_slice(), + trait_ref.substs, + variance); + } - // 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)); + 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. - 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)); + // 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` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); - self.add_constraints_from_region(bounds.region_bound, contra); + self.add_constraints_from_region(generics, data.bounds.region_bound, contra); 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.get_slice(subst::TypeSpace), + trait_def.generics.regions.get_slice(subst::TypeSpace), + trait_ref.substs(), variance); } - ty::ty_param(ty::ParamTy { ref def_id, .. }) => { + 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); } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b7845f23be298..1fbfbe7eb1ab5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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 for ast::TyParamBound { } } -impl Clean> for ty::ExistentialBounds { +impl<'tcx> Clean> for ty::ExistentialBounds<'tcx> { fn clean(&self, cx: &DocContext) -> Vec { 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), @@ -1441,18 +1441,11 @@ impl<'tcx> Clean 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 = 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,16 +1457,35 @@ impl<'tcx> Clean for ty::Ty<'tcx> { did: did, } } + 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_param(ref p) => { - if p.space == subst::SelfSpace { - Self(p.def_id) - } else { - Generic(p.def_id) + 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) ty::ty_infer(..) => panic!("ty_infer"), @@ -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), _ => {} }; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 585183e2af75e..dc264a5b5aa05 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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}", diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f253943943dcc..12432c8c78f2c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -764,7 +764,7 @@ pub enum Expr_ { pub struct QPath { pub self_type: P, pub trait_ref: P, - pub item_name: Ident, + pub item_name: Ident, // FIXME(#20301) -- should use Name } #[deriving(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show, Copy)] diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 1cd21ccac7a0e..40ca6354ca6d1 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -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) => { diff --git a/src/test/auxiliary/associated-types-cc-lib.rs b/src/test/auxiliary/associated-types-cc-lib.rs new file mode 100644 index 0000000000000..17b2a0751fe29 --- /dev/null +++ b/src/test/auxiliary/associated-types-cc-lib.rs @@ -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 or the MIT license +// , 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) -> ::T; +} + +impl Bar for int { + type T = uint; + + fn get(_: Option) -> uint { 22 } +} diff --git a/src/test/compile-fail/associated-types-bound-failure.rs b/src/test/compile-fail/associated-types-bound-failure.rs new file mode 100644 index 0000000000000..7981fe3182712 --- /dev/null +++ b/src/test/compile-fail/associated-types-bound-failure.rs @@ -0,0 +1,39 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// 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) -> ::R; +} + +fn foo(g: G) -> int + where G : GetToInt +{ + ToInt::to_int(&g.get()) //~ ERROR not implemented +} + +fn bar(g: G) -> int + where G::R : ToInt +{ + ToInt::to_int(&g.get()) // OK +} + +pub fn main() { +} diff --git a/src/test/compile-fail/assoc-eq-1.rs b/src/test/compile-fail/associated-types-eq-1.rs similarity index 100% rename from src/test/compile-fail/assoc-eq-1.rs rename to src/test/compile-fail/associated-types-eq-1.rs diff --git a/src/test/compile-fail/assoc-eq-2.rs b/src/test/compile-fail/associated-types-eq-2.rs similarity index 88% rename from src/test/compile-fail/assoc-eq-2.rs rename to src/test/compile-fail/associated-types-eq-2.rs index 652bf4fb57753..b89cdd8c0eed7 100644 --- a/src/test/compile-fail/assoc-eq-2.rs +++ b/src/test/compile-fail/associated-types-eq-2.rs @@ -25,6 +25,7 @@ impl Foo for int { fn boo(&self) -> uint { 42 } } -fn baz(x: &>::A) {} //~ERROR equality constraints are not allowed in this +fn baz(x: &>::A) {} +//~^ ERROR associated type bindings are not allowed here pub fn main() {} diff --git a/src/test/compile-fail/assoc-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs similarity index 86% rename from src/test/compile-fail/assoc-eq-3.rs rename to src/test/compile-fail/associated-types-eq-3.rs index 880b2e9cc4a77..e5974925d7370 100644 --- a/src/test/compile-fail/assoc-eq-3.rs +++ b/src/test/compile-fail/associated-types-eq-3.rs @@ -43,6 +43,6 @@ pub fn baz(x: &Foo) { 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 } diff --git a/src/test/compile-fail/assoc-eq-expr-path.rs b/src/test/compile-fail/associated-types-eq-expr-path.rs similarity index 100% rename from src/test/compile-fail/assoc-eq-expr-path.rs rename to src/test/compile-fail/associated-types-eq-expr-path.rs diff --git a/src/test/compile-fail/associated-types-eq-hr.rs b/src/test/compile-fail/associated-types-eq-hr.rs new file mode 100644 index 0000000000000..aad55745c25df --- /dev/null +++ b/src/test/compile-fail/associated-types-eq-hr.rs @@ -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 or the MIT license +// , 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 { + 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() + where T : for<'x> TheTrait<&'x int, A = &'x int> +{ + // ok for IntStruct, but not UintStruct +} + +fn bar() + where T : for<'x> TheTrait<&'x int, A = &'x uint> +{ + // ok for UintStruct, but not IntStruct +} + +fn baz() + 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::(); + foo::(); //~ ERROR type mismatch + + bar::(); //~ ERROR type mismatch + bar::(); + + baz::(); //~ ERROR type mismatch + baz::(); //~ ERROR type mismatch +} diff --git a/src/test/compile-fail/associated-types-for-unimpl-trait.rs b/src/test/compile-fail/associated-types-for-unimpl-trait.rs new file mode 100644 index 0000000000000..2c6ee502fca3e --- /dev/null +++ b/src/test/compile-fail/associated-types-for-unimpl-trait.rs @@ -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 or the MIT license +// , 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) -> ::Value; +} + +trait Other { + fn uhoh(&self, foo: U, bar: ::Value) {} + //~^ ERROR the trait `Get` is not implemented for the type `Self` +} + +fn main() { +} + diff --git a/src/test/compile-fail/associated-types-in-ambiguous-context.rs b/src/test/compile-fail/associated-types-in-ambiguous-context.rs index 24de1fa2f7844..fcd3e4d163646 100644 --- a/src/test/compile-fail/associated-types-in-ambiguous-context.rs +++ b/src/test/compile-fail/associated-types-in-ambiguous-context.rs @@ -18,16 +18,6 @@ trait Get { fn get(x: T, y: U) -> Get::Value {} //~^ ERROR ambiguous associated type -trait Other { - fn uhoh(&self, foo: U, bar: ::Value) {} - //~^ ERROR no suitable bound on `Self` -} - -impl Other for T { - fn uhoh(&self, foo: U, bar: <(T, U) as Get>::Value) {} - //~^ ERROR currently unsupported -} - trait Grab { type Value; fn grab(&self) -> Grab::Value; diff --git a/src/test/compile-fail/associated-types-incomplete-object.rs b/src/test/compile-fail/associated-types-incomplete-object.rs new file mode 100644 index 0000000000000..7e4e1315110af --- /dev/null +++ b/src/test/compile-fail/associated-types-incomplete-object.rs @@ -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 or the MIT license +// , 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) -> ::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; + + let b = &42i as &Foo; + //~^ ERROR the value of the associated type `B` (from the trait `Foo`) must be specified + + let c = &42i as &Foo; + //~^ 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 +} diff --git a/src/test/compile-fail/associated-types-in-wrong-context.rs b/src/test/compile-fail/associated-types-no-suitable-bound.rs similarity index 86% rename from src/test/compile-fail/associated-types-in-wrong-context.rs rename to src/test/compile-fail/associated-types-no-suitable-bound.rs index 8cab2759ad55a..6b85620409151 100644 --- a/src/test/compile-fail/associated-types-in-wrong-context.rs +++ b/src/test/compile-fail/associated-types-no-suitable-bound.rs @@ -15,16 +15,13 @@ trait Get { fn get(&self) -> ::Value; } -fn get(x: int) -> ::Value {} -//~^ ERROR unsupported - struct Struct { x: int, } impl Struct { fn uhoh(foo: ::Value) {} - //~^ ERROR no suitable bound on `T` + //~^ ERROR the trait `Get` is not implemented for the type `T` } fn main() { diff --git a/src/test/compile-fail/associated-types-no-suitable-supertrait.rs b/src/test/compile-fail/associated-types-no-suitable-supertrait.rs new file mode 100644 index 0000000000000..5a4ebeac41eef --- /dev/null +++ b/src/test/compile-fail/associated-types-no-suitable-supertrait.rs @@ -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 or the MIT license +// , 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 `::Value` in +// the trait definition but `Self` does not, in fact, implement `Get`. + +trait Get { + type Value; +} + +trait Other { + fn uhoh(&self, foo: U, bar: ::Value) {} + //~^ ERROR the trait `Get` is not implemented for the type `Self` +} + +impl Other for T { + fn uhoh(&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() { } diff --git a/src/test/compile-fail/assoc-path-1.rs b/src/test/compile-fail/associated-types-path-1.rs similarity index 100% rename from src/test/compile-fail/assoc-path-1.rs rename to src/test/compile-fail/associated-types-path-1.rs diff --git a/src/test/compile-fail/assoc-path-2.rs b/src/test/compile-fail/associated-types-path-2.rs similarity index 74% rename from src/test/compile-fail/assoc-path-2.rs rename to src/test/compile-fail/associated-types-path-2.rs index caf8ab3695d1c..486d3d38c60af 100644 --- a/src/test/compile-fail/assoc-path-2.rs +++ b/src/test/compile-fail/associated-types-path-2.rs @@ -26,9 +26,10 @@ pub fn f2(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` } diff --git a/src/test/compile-fail/associated-types-project-from-hrtb-explicit.rs b/src/test/compile-fail/associated-types-project-from-hrtb-explicit.rs new file mode 100644 index 0000000000000..1f0f044a4c0c3 --- /dev/null +++ b/src/test/compile-fail/associated-types-project-from-hrtb-explicit.rs @@ -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 or the MIT license +// , 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 { + type A; + + fn get(&self, t: T) -> Self::A; +} + +fn foo2(x: Foo<&'x int>>::A) + //~^ ERROR expected identifier, found keyword `for` + //~| ERROR expected one of `::` or `>` +{ +} + +pub fn main() {} diff --git a/src/test/compile-fail/associated-types-project-from-hrtb-in-fn-body.rs b/src/test/compile-fail/associated-types-project-from-hrtb-in-fn-body.rs new file mode 100644 index 0000000000000..8cdca50d9b6bd --- /dev/null +++ b/src/test/compile-fail/associated-types-project-from-hrtb-in-fn-body.rs @@ -0,0 +1,37 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// 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 { + type A; + + fn get(&self, t: T) -> Self::A; +} + +fn foo<'a, I : for<'x> Foo<&'x int>>( + x: >::A) +{ + let y: I::A = x; +} + +fn bar<'a, 'b, I : for<'x> Foo<&'x int>>( + x: >::A, + y: >::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() {} diff --git a/src/test/compile-fail/associated-types-project-from-hrtb-in-fn.rs b/src/test/compile-fail/associated-types-project-from-hrtb-in-fn.rs new file mode 100644 index 0000000000000..0d5c69591423b --- /dev/null +++ b/src/test/compile-fail/associated-types-project-from-hrtb-in-fn.rs @@ -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 or the MIT license +// , 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 { + type A; + + fn get(&self, t: T) -> Self::A; +} + +fn foo2 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 Foo<&'x int>>( + x: >::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: >::A) +{ + // OK, in this case we spelled out the precise regions involved. +} + + +pub fn main() {} diff --git a/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs b/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs new file mode 100644 index 0000000000000..5016c6448a50e --- /dev/null +++ b/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs @@ -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 or the MIT license +// , 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 { + type A; + + fn get(&self, t: T) -> Self::A; +} + +struct SomeStruct Foo<&'x int>> { + field: I::A + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context +} + +struct AnotherStruct Foo<&'x int>> { + field: >::A + //~^ ERROR missing lifetime specifier +} + +struct YetAnotherStruct<'a, I : for<'x> Foo<&'x int>> { + field: >::A +} + +pub fn main() {} diff --git a/src/test/compile-fail/associated-types-project-from-hrtb-in-trait-method.rs b/src/test/compile-fail/associated-types-project-from-hrtb-in-trait-method.rs new file mode 100644 index 0000000000000..a92d4ec04cb20 --- /dev/null +++ b/src/test/compile-fail/associated-types-project-from-hrtb-in-trait-method.rs @@ -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 or the MIT license +// , 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 { + type A; + + fn get(&self, t: T) -> Self::A; +} + +trait SomeTrait 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 Foo<&'x int>> { + fn some_method(&self, arg: >::A); +} + +trait YetAnotherTrait Foo<&'x int>> { + fn some_method<'a>(&self, arg: >::A); +} + +pub fn main() {} diff --git a/src/test/run-pass/issue-12028.rs b/src/test/compile-fail/issue-12028.rs similarity index 79% rename from src/test/run-pass/issue-12028.rs rename to src/test/compile-fail/issue-12028.rs index dbfa330d33d9e..78502efdec520 100644 --- a/src/test/run-pass/issue-12028.rs +++ b/src/test/compile-fail/issue-12028.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test an example where we fail to infer the type parameter H. This +// is because there is really nothing constraining it. At one time, we +// would infer based on the where clauses in scope, but that no longer +// works. + trait Hash { fn hash2(&self, hasher: &H) -> u64; } @@ -30,7 +35,7 @@ trait StreamHash>: Hash { impl> Hash for u8 { fn hash2(&self, hasher: &H) -> u64 { let mut stream = hasher.stream(); - self.input_stream(&mut stream); + self.input_stream(&mut stream); //~ ERROR type annotations required stream.result() } } diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index f3636edeaa589..08b896f387bbe 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -12,8 +12,6 @@ fn main() { return { return () } //~^ ERROR the type of this value must be known in this context -//~| ERROR this function takes 1 parameter -//~| ERROR mismatched types () ; } diff --git a/src/test/compile-fail/issue-18345.rs b/src/test/compile-fail/issue-18345.rs index c8b3463b0911d..e93acb3f064af 100644 --- a/src/test/compile-fail/issue-18345.rs +++ b/src/test/compile-fail/issue-18345.rs @@ -15,7 +15,6 @@ fn mapping<'f, R, T, U>(f: |T|: 'f -> U) -> &'f Transducer<'f, R, T, U> { |step| |r, x| step(r, f(x)) //~^ ERROR the type of this value must be known in this context - //~| ERROR this function takes 1 parameter but 2 parameters were supplied } fn main() {} diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index ec44ab7b27705..9cf922ae99002 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -17,5 +17,4 @@ fn main() { (return)((),()); //~^ ERROR the type of this value must be known - //~| ERROR this function takes 1 parameter } diff --git a/src/test/compile-fail/issue-18611.rs b/src/test/compile-fail/issue-18611.rs index b2f204d747671..49eeccb2b0cf1 100644 --- a/src/test/compile-fail/issue-18611.rs +++ b/src/test/compile-fail/issue-18611.rs @@ -10,10 +10,9 @@ #![feature(associated_types)] -fn add_state(op: - ::State -//~^ ERROR it is currently unsupported to access associated types except through a type parameter -) {} +fn add_state(op: ::State) { +//~^ ERROR the trait `HasState` is not implemented for the type `int` +} trait HasState { type State; diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs index 5fe8e435e6806..c11b5d2287855 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs @@ -41,14 +41,14 @@ enum Boo { Quux(Bar), } -struct Badness { +struct Badness { //~^ ERROR not implemented - b: Foo, + b: Foo, } -enum MoreBadness { +enum MoreBadness { //~^ ERROR not implemented - EvenMoreBadness(Bar), + EvenMoreBadness(Bar), } trait PolyTrait { diff --git a/src/test/run-pass/trait-static-method-generic-inference.rs b/src/test/compile-fail/trait-static-method-generic-inference.rs similarity index 69% rename from src/test/run-pass/trait-static-method-generic-inference.rs rename to src/test/compile-fail/trait-static-method-generic-inference.rs index 4151ad6530ef4..651f663fc9913 100644 --- a/src/test/run-pass/trait-static-method-generic-inference.rs +++ b/src/test/compile-fail/trait-static-method-generic-inference.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Issue #3902. We are (at least currently) unable to infer `Self` +// based on `T`, even though there is only a single impl, because of +// the possibility of associated types and other things (basically: no +// constraints on `Self` here at all). + mod base { pub trait HasNew { fn new() -> T; @@ -22,19 +27,11 @@ mod base { Foo { dummy: () } } } - - pub struct Bar { - dummy: (), - } - - impl HasNew for Bar { - fn new() -> Bar { - Bar { dummy: () } - } - } } -pub fn main() { +pub fn foo() { let _f: base::Foo = base::HasNew::new(); - let _b: base::Bar = base::HasNew::new(); + //~^ ERROR type annotations required } + +fn main() { } diff --git a/src/test/compile-fail/transmute-different-sizes.rs b/src/test/compile-fail/transmute-different-sizes.rs index abdfe983e3a8f..5c61212a7f5a5 100644 --- a/src/test/compile-fail/transmute-different-sizes.rs +++ b/src/test/compile-fail/transmute-different-sizes.rs @@ -21,7 +21,7 @@ unsafe fn f() { unsafe fn g(x: &T) { let _: i8 = transmute(x); - //~^ ERROR transmute called on types with different sizes + //~^ ERROR transmute called on types with potentially different sizes } fn main() {} diff --git a/src/test/compile-fail/transmute-fat-pointers.rs b/src/test/compile-fail/transmute-fat-pointers.rs new file mode 100644 index 0000000000000..5e81a4cec2284 --- /dev/null +++ b/src/test/compile-fail/transmute-fat-pointers.rs @@ -0,0 +1,41 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that are conservative around thin/fat pointer mismatches. + +#![allow(dead_code)] + +use std::mem::transmute; + +fn a(x: &[T]) -> &U { + unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes +} + +fn b(x: &T) -> &U { + unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes +} + +fn c(x: &T) -> &U { + unsafe { transmute(x) } +} + +fn d(x: &[T]) -> &[U] { + unsafe { transmute(x) } +} + +fn e(x: &T) -> &U { + unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes +} + +fn f(x: &T) -> &U { + unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes +} + +fn main() { } diff --git a/src/test/compile-fail/transmute-impl.rs b/src/test/compile-fail/transmute-impl.rs new file mode 100644 index 0000000000000..8b5a8c679b245 --- /dev/null +++ b/src/test/compile-fail/transmute-impl.rs @@ -0,0 +1,33 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that are conservative around thin/fat pointer mismatches. + +#![allow(dead_code)] + +use std::mem::transmute; + +struct Foo { + t: Box +} + +impl Foo { + fn m(x: &T) -> &int where T : Sized { + // OK here, because T : Sized is in scope. + unsafe { transmute(x) } + } + + fn n(x: &T) -> &int { + // Not OK here, because T : Sized is not in scope. + unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes + } +} + +fn main() { } diff --git a/src/test/compile-fail/unsized-inherent-impl-self-type.rs b/src/test/compile-fail/unsized-inherent-impl-self-type.rs new file mode 100644 index 0000000000000..2c8a2b361d596 --- /dev/null +++ b/src/test/compile-fail/unsized-inherent-impl-self-type.rs @@ -0,0 +1,20 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test sized-ness checking in substitution in impls. + +// impl - struct + +struct S5; + +impl S5 { //~ ERROR not implemented +} + +fn main() { } diff --git a/src/test/compile-fail/unsized-trait-impl-self-type.rs b/src/test/compile-fail/unsized-trait-impl-self-type.rs new file mode 100644 index 0000000000000..0f0a97fab4d75 --- /dev/null +++ b/src/test/compile-fail/unsized-trait-impl-self-type.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test sized-ness checking in substitution in impls. + +// impl - struct +trait T3 { +} + +struct S5; + +impl T3 for S5 { //~ ERROR not implemented +} + +fn main() { } diff --git a/src/test/compile-fail/unsized-trait-impl-trait-arg.rs b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs new file mode 100644 index 0000000000000..bdb652b168a8c --- /dev/null +++ b/src/test/compile-fail/unsized-trait-impl-trait-arg.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test sized-ness checking in substitution in impls. + +// impl - unbounded +trait T2 { +} +struct S4; +impl T2 for S4 { + //~^ ERROR `core::kinds::Sized` is not implemented for the type `X` +} + +fn main() { } diff --git a/src/test/compile-fail/unsized4.rs b/src/test/compile-fail/unsized4.rs index a66c1d85009c3..0537fc1f94ad7 100644 --- a/src/test/compile-fail/unsized4.rs +++ b/src/test/compile-fail/unsized4.rs @@ -11,8 +11,9 @@ // Test that bounds are sized-compatible. trait T {} + fn f() { -//~^ERROR incompatible bounds on type parameter `Y`, bound `T` does not allow unsized type +//~^ERROR incompatible bounds on `Y`, bound `T` does not allow unsized type } pub fn main() { diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs index fd9dffe00d2d5..c0e6ae1db92c4 100644 --- a/src/test/compile-fail/unsized7.rs +++ b/src/test/compile-fail/unsized7.rs @@ -21,23 +21,4 @@ impl T1 for S3 { //~^ ERROR `core::kinds::Sized` is not implemented for the type `X` } -// impl - unbounded -trait T2 { -} -struct S4; -impl T2 for S4 { - //~^ ERROR `core::kinds::Sized` is not implemented for the type `X` -} - -// impl - struct -trait T3 { -} -struct S5; -impl T3 for S5 { //~ ERROR not implemented -} - -impl S5 { //~ ERROR not implemented -} - - fn main() { } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index 48813ff142c18..fa38482b21c50 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -14,7 +14,7 @@ // Regions that just appear in normal spots are contravariant: #[rustc_variance] -struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[];[]] +struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]] x: &'a int, y: &'b [int], c: &'c str @@ -23,7 +23,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[];[]] // Those same annotations in function arguments become covariant: #[rustc_variance] -struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[];[]] +struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]] x: extern "Rust" fn(&'a int), y: extern "Rust" fn(&'b [int]), c: extern "Rust" fn(&'c str), @@ -32,7 +32,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[];[]] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[];[]] +struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] x: &'a mut &'b int, } @@ -40,7 +40,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[];[]] // contravariant context: #[rustc_variance] -struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[];[]] +struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]] x: extern "Rust" fn(&'a mut &'b int), } @@ -50,21 +50,21 @@ struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[];[]] // argument list occurs in an invariant context. #[rustc_variance] -struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[];[]] +struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[]] x: &'a mut extern "Rust" fn(&'b int), } // No uses at all is bivariant: #[rustc_variance] -struct Test7<'a> { //~ ERROR regions=[[*];[];[];[]] +struct Test7<'a> { //~ ERROR regions=[[*];[];[]] x: int } // Try enums too. #[rustc_variance] -enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[];[]] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]] Test8A(extern "Rust" fn(&'a int)), Test8B(&'b [int]), Test8C(&'b mut &'c str), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index 0e8e52df456af..c049fbc0fedbc 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -13,29 +13,29 @@ // Try enums too. #[rustc_variance] -enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[];[]] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]] Test8A(extern "Rust" fn(&'a int)), Test8B(&'b [int]), Test8C(&'b mut &'c str), } #[rustc_variance] -struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[];[]] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]] f: Base<'z, 'y, 'x, 'w> } #[rustc_variance] // Combine - and + to yield o -struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[];[]] +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[]] f: Base<'a, 'a, 'b, 'c> } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[];[]] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]] f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[];[]] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]] f: Base<'a, 'b, 'c, 'a> } diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index c576c5e2edd64..c61f2ff79c019 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -19,7 +19,7 @@ use std::mem; trait T { fn foo(); } #[rustc_variance] -struct TOption<'a> { //~ ERROR regions=[[-];[];[];[]] +struct TOption<'a> { //~ ERROR regions=[[-];[];[]] v: Option>, } diff --git a/src/test/run-pass/associated-types-basic.rs b/src/test/run-pass/associated-types-basic.rs new file mode 100644 index 0000000000000..fcfcce3ff1b78 --- /dev/null +++ b/src/test/run-pass/associated-types-basic.rs @@ -0,0 +1,26 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Foo { + type T; +} + +impl Foo for i32 { + type T = int; +} + +fn main() { + let x: ::T = 22; + let y: int = 44; + assert_eq!(x * 2, y); +} + diff --git a/src/test/run-pass/associated-types-binding-in-where-clause.rs b/src/test/run-pass/associated-types-binding-in-where-clause.rs new file mode 100644 index 0000000000000..c3300c5293575 --- /dev/null +++ b/src/test/run-pass/associated-types-binding-in-where-clause.rs @@ -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 or the MIT license +// , 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 Foo { + type A; + fn boo(&self) -> ::A; +} + +#[deriving(PartialEq)] +struct Bar; + +impl Foo for int { + type A = uint; + fn boo(&self) -> uint { 42 } +} + +impl Foo for char { + type A = Bar; + fn boo(&self) -> Bar { Bar } +} + +fn foo_bar>(x: I) -> Bar { + x.boo() +} + +fn foo_uint>(x: I) -> uint { + x.boo() +} + +pub fn main() { + let a = 42i; + foo_uint(a); + + let a = 'a'; + foo_bar(a); +} diff --git a/src/test/run-pass/associated-types-bound.rs b/src/test/run-pass/associated-types-bound.rs new file mode 100644 index 0000000000000..db5119132cc3f --- /dev/null +++ b/src/test/run-pass/associated-types-bound.rs @@ -0,0 +1,53 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test equality constraints on associated types in a where clause. + +#![feature(associated_types)] + +pub trait ToInt { + fn to_int(&self) -> int; +} + +impl ToInt for int { + fn to_int(&self) -> int { *self } +} + +impl ToInt for uint { + fn to_int(&self) -> int { *self as int } +} + +pub trait GetToInt +{ + type R : ToInt; + + fn get(&self) -> ::R; +} + +impl GetToInt for int { + type R = int; + fn get(&self) -> int { *self } +} + +impl GetToInt for uint { + type R = uint; + fn get(&self) -> uint { *self } +} + +fn foo(g: G) -> int + where G : GetToInt +{ + ToInt::to_int(&g.get()) +} + +pub fn main() { + assert_eq!(foo(22i), 22i); + assert_eq!(foo(22u), 22i); +} diff --git a/src/test/run-pass/associated-types-cc.rs b/src/test/run-pass/associated-types-cc.rs new file mode 100644 index 0000000000000..c0cf917aa4117 --- /dev/null +++ b/src/test/run-pass/associated-types-cc.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:associated-types-cc-lib.rs + +// Test that we are able to reference cross-crate traits that employ +// associated types. + +#![feature(associated_types)] + +extern crate "associated-types-cc-lib" as bar; + +use bar::Bar; + +fn foo(b: B) -> ::T { + Bar::get(None::) +} + +fn main() { + println!("{}", foo(3i)); +} diff --git a/src/test/run-pass/multidispatch-infer-from-single-impl.rs b/src/test/run-pass/associated-types-constant-type.rs similarity index 52% rename from src/test/run-pass/multidispatch-infer-from-single-impl.rs rename to src/test/run-pass/associated-types-constant-type.rs index f4ca67548fd53..ea2cf84b757c3 100644 --- a/src/test/run-pass/multidispatch-infer-from-single-impl.rs +++ b/src/test/run-pass/associated-types-constant-type.rs @@ -8,25 +8,35 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that we correctly infer that `E` must be `()` here. This is -// known because there is just one impl that could apply where -// `Self=()`. +#![feature(associated_types)] -pub trait FromError { - fn from_error(err: E) -> Self; +trait SignedUnsigned { + type Opposite; + fn convert(self) -> Self::Opposite; } -impl FromError for E { - fn from_error(err: E) -> E { - err +impl SignedUnsigned for int { + type Opposite = uint; + + fn convert(self) -> uint { + self as uint + } +} + +impl SignedUnsigned for uint { + type Opposite = int; + + fn convert(self) -> int { + self as int } } -fn test() -> Result<(), ()> { - Err(FromError::from_error(())) +fn get(x: int) -> ::Opposite { + x.convert() } fn main() { - let result = (|| Err(FromError::from_error(())))(); - let foo: () = result.unwrap_or(()); + let x = get(22); + assert_eq!(22u, x); } + diff --git a/src/test/run-pass/associated-types-eq-obj.rs b/src/test/run-pass/associated-types-eq-obj.rs new file mode 100644 index 0000000000000..f0343a743cb50 --- /dev/null +++ b/src/test/run-pass/associated-types-eq-obj.rs @@ -0,0 +1,34 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test equality constraints on associated types inside of an object type + +#![feature(associated_types)] + +pub trait Foo { + type A; + fn boo(&self) -> ::A; +} + +struct Bar; + +impl Foo for char { + type A = Bar; + fn boo(&self) -> Bar { Bar } +} + +fn baz(x: &Foo) -> Bar { + x.boo() +} + +pub fn main() { + let a = 'a'; + baz(&a); +} diff --git a/src/test/run-pass/associated-types-normalize-in-bounds.rs b/src/test/run-pass/associated-types-normalize-in-bounds.rs new file mode 100644 index 0000000000000..f09c27029d7fa --- /dev/null +++ b/src/test/run-pass/associated-types-normalize-in-bounds.rs @@ -0,0 +1,41 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we normalize associated types that appear in bounds; if +// we didn't, the call to `self.split2()` fails to type check. + +#![feature(associated_types)] + +struct Splits<'a, T, P>; +struct SplitsN; + +trait SliceExt2 for Sized? { + type Item; + + fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P> + where P: FnMut(&Self::Item) -> bool; + fn splitn2<'a, P>(&'a self, n: uint, pred: P) -> SplitsN> + where P: FnMut(&Self::Item) -> bool; +} + +impl SliceExt2 for [T] { + type Item = T; + + fn split2

(&self, pred: P) -> Splits where P: FnMut(&T) -> bool { + loop {} + } + + fn splitn2

(&self, n: uint, pred: P) -> SplitsN> where P: FnMut(&T) -> bool { + self.split2(pred); + loop {} + } +} + +fn main() { } diff --git a/src/test/run-pass/assoc-eq.rs b/src/test/run-pass/associated-types-return.rs similarity index 89% rename from src/test/run-pass/assoc-eq.rs rename to src/test/run-pass/associated-types-return.rs index f1ba382b42dad..d8e277510ed10 100644 --- a/src/test/run-pass/assoc-eq.rs +++ b/src/test/run-pass/associated-types-return.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test equality constraints on associated types. +// Test equality constraints on associated types in a where clause. #![feature(associated_types)] @@ -17,16 +17,19 @@ pub trait Foo { fn boo(&self) -> ::A; } +#[deriving(PartialEq)] struct Bar; impl Foo for int { type A = uint; fn boo(&self) -> uint { 42 } } + impl Foo for Bar { type A = int; fn boo(&self) -> int { 43 } } + impl Foo for char { type A = Bar; fn boo(&self) -> Bar { Bar } @@ -35,12 +38,10 @@ impl Foo for char { fn foo1>(x: I) -> Bar { x.boo() } + fn foo2(x: I) -> ::A { x.boo() } -fn baz(x: &Foo) -> Bar { - x.boo() -} pub fn main() { let a = 42i; @@ -51,5 +52,5 @@ pub fn main() { let a = 'a'; foo1(a); - baz(&a); + assert!(foo2(a) == Bar); } diff --git a/src/test/run-pass/assoc-sugar-path.rs b/src/test/run-pass/associated-types-sugar-path.rs similarity index 100% rename from src/test/run-pass/assoc-sugar-path.rs rename to src/test/run-pass/associated-types-sugar-path.rs diff --git a/src/test/compile-fail/issue-19081.rs b/src/test/run-pass/issue-19081.rs similarity index 78% rename from src/test/compile-fail/issue-19081.rs rename to src/test/run-pass/issue-19081.rs index 613ec8acd4131..57724ba91b02f 100644 --- a/src/test/compile-fail/issue-19081.rs +++ b/src/test/run-pass/issue-19081.rs @@ -8,17 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-pretty -- FIXME(#17362) pretty prints as `Hash<::State //~ ERROR no suitable bound on `Self` + ::State >>(&self, value: &T) -> u64; } -trait Hash { +pub trait Hash { fn hash(&self, state: &mut S); } diff --git a/src/test/compile-fail/issue-19121.rs b/src/test/run-pass/issue-19121.rs similarity index 83% rename from src/test/compile-fail/issue-19121.rs rename to src/test/run-pass/issue-19121.rs index 998c6a8253539..79afb856be26f 100644 --- a/src/test/compile-fail/issue-19121.rs +++ b/src/test/run-pass/issue-19121.rs @@ -17,6 +17,8 @@ trait Foo { type A; } -fn bar(x: &Foo) {} //~ERROR missing type for associated type `A` +fn bar(x: &Foo) {} +// FIXME(#19482) -- `Foo` should specify `A`, but this is not +// currently enforced except at object creation pub fn main() {}