1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! # Standalone Tests for the Inference Module
14 use diagnostic::Emitter;
16 use rustc_resolve as resolve;
17 use rustc_typeck::middle::lang_items;
18 use rustc_typeck::middle::region::{mod, CodeExtent};
19 use rustc_typeck::middle::resolve_lifetime;
20 use rustc_typeck::middle::stability;
21 use rustc_typeck::middle::subst;
22 use rustc_typeck::middle::subst::Subst;
23 use rustc_typeck::middle::ty::{mod, Ty};
24 use rustc_typeck::middle::infer::combine::Combine;
25 use rustc_typeck::middle::infer;
26 use rustc_typeck::middle::infer::lub::Lub;
27 use rustc_typeck::middle::infer::glb::Glb;
28 use rustc_typeck::middle::infer::sub::Sub;
29 use rustc_typeck::util::ppaux::{ty_to_string, Repr, UserString};
30 use rustc::session::{mod,config};
31 use syntax::{abi, ast, ast_map};
33 use syntax::codemap::{Span, CodeMap, DUMMY_SP};
34 use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help};
35 use syntax::parse::token;
37 struct Env<'a, 'tcx: 'a> {
38 infcx: &'a infer::InferCtxt<'a, 'tcx>,
46 static EMPTY_SOURCE_STR: &'static str = "#![no_std]";
48 struct ExpectErrorEmitter {
52 fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
54 Bug | Fatal | Error => { }
55 Warning | Note | Help => { return; }
58 debug!("Error: {}", msg);
59 match e.messages.iter().position(|m| msg.contains(m.as_slice())) {
64 panic!("Unexpected error: {} Expected: {}",
70 impl Emitter for ExpectErrorEmitter {
72 _cmsp: Option<(&codemap::CodeMap, Span)>,
77 remove_message(self, msg, lvl);
80 fn custom_emit(&mut self,
81 _cm: &codemap::CodeMap,
86 remove_message(self, msg, lvl);
90 fn errors(msgs: &[&str]) -> (Box<Emitter+Send>, uint) {
91 let v = msgs.iter().map(|m| m.to_string()).collect();
92 (box ExpectErrorEmitter { messages: v } as Box<Emitter+Send>, msgs.len())
95 fn test_env<F>(source_string: &str,
96 (emitter, expected_err_count): (Box<Emitter+Send>, uint),
101 config::basic_options();
102 options.debugging_opts |= config::VERBOSE;
105 let diagnostic_handler =
106 diagnostic::mk_handler(emitter);
107 let span_diagnostic_handler =
108 diagnostic::mk_span_handler(diagnostic_handler, codemap);
110 let sess = session::build_session_(options, None, span_diagnostic_handler);
111 let krate_config = Vec::new();
112 let input = config::Input::Str(source_string.to_string());
113 let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
114 let krate = driver::phase_2_configure_and_expand(&sess, krate, "test", None)
115 .expect("phase 2 aborted");
117 let mut forest = ast_map::Forest::new(krate);
118 let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);
119 let krate = ast_map.krate();
121 // run just enough stuff to build a tcx:
122 let lang_items = lang_items::collect_language_items(krate, &sess);
123 let resolve::CrateMap { def_map, freevars, capture_mode_map, .. } =
124 resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
125 let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
126 let region_map = region::resolve_crate(&sess, krate);
127 let stability_index = stability::Index::build(krate);
128 let arenas = ty::CtxtArenas::new();
129 let tcx = ty::mk_ctxt(sess,
139 let infcx = infer::new_infer_ctxt(&tcx);
140 body(Env { infcx: &infcx });
141 infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);
142 assert_eq!(tcx.sess.err_count(), expected_err_count);
145 impl<'a, 'tcx> Env<'a, 'tcx> {
146 pub fn tcx(&self) -> &ty::ctxt<'tcx> {
150 pub fn create_region_hierarchy(&self, rh: &RH) {
151 for child_rh in rh.sub.iter() {
152 self.create_region_hierarchy(child_rh);
153 self.infcx.tcx.region_maps.record_encl_scope(
154 CodeExtent::from_node_id(child_rh.id),
155 CodeExtent::from_node_id(rh.id));
159 pub fn create_simple_region_hierarchy(&self) {
160 // creates a region hierarchy where 1 is root, 10 and 11 are
161 // children of 1, etc
162 self.create_region_hierarchy(
170 #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
171 pub fn lookup_item(&self, names: &[String]) -> ast::NodeId {
172 return match search_mod(self, &self.infcx.tcx.map.krate().module, 0, names) {
175 panic!("no item found: `{}`", names.connect("::"));
179 fn search_mod(this: &Env,
183 -> Option<ast::NodeId> {
184 assert!(idx < names.len());
185 for item in m.items.iter() {
186 if item.ident.user_string(this.infcx.tcx) == names[idx] {
187 return search(this, &**item, idx+1, names);
193 fn search(this: &Env,
197 -> Option<ast::NodeId> {
198 if idx == names.len() {
202 return match it.node {
203 ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemFn(..) |
204 ast::ItemForeignMod(..) | ast::ItemTy(..) => {
208 ast::ItemEnum(..) | ast::ItemStruct(..) |
209 ast::ItemTrait(..) | ast::ItemImpl(..) |
210 ast::ItemMac(..) => {
214 ast::ItemMod(ref m) => {
215 search_mod(this, m, idx, names)
221 pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
222 match infer::mk_subty(self.infcx, true, infer::Misc(DUMMY_SP), a, b) {
224 Err(ref e) => panic!("Encountered error: {}",
225 ty::type_err_to_str(self.infcx.tcx, e))
229 pub fn is_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
230 match infer::can_mk_subty(self.infcx, a, b) {
236 pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
237 if !self.is_subtype(a, b) {
238 panic!("{} is not a subtype of {}, but it should be",
239 self.ty_to_string(a),
240 self.ty_to_string(b));
244 pub fn assert_eq(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
245 self.assert_subtype(a, b);
246 self.assert_subtype(b, a);
249 pub fn ty_to_string(&self, a: Ty<'tcx>) -> String {
250 ty_to_string(self.infcx.tcx, a)
254 input_tys: &[Ty<'tcx>],
258 let input_args = input_tys.iter().map(|ty| *ty).collect();
259 ty::mk_bare_fn(self.infcx.tcx,
261 self.infcx.tcx.mk_bare_fn(ty::BareFnTy {
262 unsafety: ast::Unsafety::Normal,
264 sig: ty::Binder(ty::FnSig {
266 output: ty::FnConverging(output_ty),
272 pub fn t_nil(&self) -> Ty<'tcx> {
273 ty::mk_nil(self.infcx.tcx)
276 pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> {
277 ty::mk_tup(self.infcx.tcx, vec![ty1, ty2])
280 pub fn t_closure(&self,
281 input_tys: &[Ty<'tcx>],
283 region_bound: ty::Region)
286 ty::mk_closure(self.infcx.tcx, ty::ClosureTy {
287 unsafety: ast::Unsafety::Normal,
289 store: ty::RegionTraitStore(region_bound, ast::MutMutable),
290 bounds: ty::region_existential_bound(region_bound),
291 sig: ty::Binder(ty::FnSig {
292 inputs: input_tys.to_vec(),
293 output: ty::FnConverging(output_ty),
300 pub fn t_param(&self, space: subst::ParamSpace, index: u32) -> Ty<'tcx> {
301 let name = format!("T{}", index);
302 ty::mk_param(self.infcx.tcx, space, index, token::intern(name[]))
305 pub fn re_early_bound(&self,
306 space: subst::ParamSpace,
311 let name = token::intern(name);
312 ty::ReEarlyBound(ast::DUMMY_NODE_ID, space, index, name)
315 pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) -> ty::Region {
316 ty::ReLateBound(debruijn, ty::BrAnon(id))
319 pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> {
320 ty::mk_imm_rptr(self.infcx.tcx,
321 self.infcx.tcx.mk_region(r),
322 self.tcx().types.int)
325 pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> {
326 let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1));
327 ty::mk_imm_rptr(self.infcx.tcx,
328 self.infcx.tcx.mk_region(r),
329 self.tcx().types.int)
332 pub fn t_rptr_late_bound_with_debruijn(&self,
334 debruijn: ty::DebruijnIndex)
336 let r = self.re_late_bound_with_debruijn(id, debruijn);
337 ty::mk_imm_rptr(self.infcx.tcx,
338 self.infcx.tcx.mk_region(r),
339 self.tcx().types.int)
342 pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
343 let r = ty::ReScope(CodeExtent::from_node_id(id));
344 ty::mk_imm_rptr(self.infcx.tcx, self.infcx.tcx.mk_region(r),
345 self.tcx().types.int)
348 pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region {
349 ty::ReFree(ty::FreeRegion { scope: CodeExtent::from_node_id(nid),
350 bound_region: ty::BrAnon(id)})
353 pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> {
354 let r = self.re_free(nid, id);
355 ty::mk_imm_rptr(self.infcx.tcx,
356 self.infcx.tcx.mk_region(r),
357 self.tcx().types.int)
360 pub fn t_rptr_static(&self) -> Ty<'tcx> {
361 ty::mk_imm_rptr(self.infcx.tcx,
362 self.infcx.tcx.mk_region(ty::ReStatic),
363 self.tcx().types.int)
366 pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
367 infer::TypeTrace::dummy(self.tcx())
370 pub fn sub(&self) -> Sub<'a, 'tcx> {
371 let trace = self.dummy_type_trace();
372 Sub(self.infcx.combine_fields(true, trace))
375 pub fn lub(&self) -> Lub<'a, 'tcx> {
376 let trace = self.dummy_type_trace();
377 Lub(self.infcx.combine_fields(true, trace))
380 pub fn glb(&self) -> Glb<'a, 'tcx> {
381 let trace = self.dummy_type_trace();
382 Glb(self.infcx.combine_fields(true, trace))
385 pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
386 match self.lub().tys(t1, t2) {
388 Err(ref e) => panic!("unexpected error computing LUB: {}",
389 ty::type_err_to_str(self.infcx.tcx, e))
393 /// Checks that `t1 <: t2` is true (this may register additional
395 pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
396 match self.sub().tys(t1, t2) {
399 panic!("unexpected error computing sub({},{}): {}",
400 t1.repr(self.infcx.tcx),
401 t2.repr(self.infcx.tcx),
402 ty::type_err_to_str(self.infcx.tcx, e));
407 /// Checks that `t1 <: t2` is false (this may register additional
409 pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
410 match self.sub().tys(t1, t2) {
413 panic!("unexpected success computing sub({},{})",
414 t1.repr(self.infcx.tcx),
415 t2.repr(self.infcx.tcx));
420 /// Checks that `LUB(t1,t2) == t_lub`
421 pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
422 match self.lub().tys(t1, t2) {
424 self.assert_eq(t, t_lub);
427 panic!("unexpected error in LUB: {}",
428 ty::type_err_to_str(self.infcx.tcx, e))
433 /// Checks that `GLB(t1,t2) == t_glb`
434 pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
435 debug!("check_glb(t1={}, t2={}, t_glb={})",
436 self.ty_to_string(t1),
437 self.ty_to_string(t2),
438 self.ty_to_string(t_glb));
439 match self.glb().tys(t1, t2) {
441 panic!("unexpected error computing LUB: {}", e)
444 self.assert_eq(t, t_glb);
446 // sanity check for good measure:
447 self.assert_subtype(t, t1);
448 self.assert_subtype(t, t2);
455 fn contravariant_region_ptr_ok() {
456 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
457 env.create_simple_region_hierarchy();
458 let t_rptr1 = env.t_rptr_scope(1);
459 let t_rptr10 = env.t_rptr_scope(10);
460 env.assert_eq(t_rptr1, t_rptr1);
461 env.assert_eq(t_rptr10, t_rptr10);
462 env.make_subtype(t_rptr1, t_rptr10);
467 fn contravariant_region_ptr_err() {
468 test_env(EMPTY_SOURCE_STR,
469 errors(&["lifetime mismatch"]),
471 env.create_simple_region_hierarchy();
472 let t_rptr1 = env.t_rptr_scope(1);
473 let t_rptr10 = env.t_rptr_scope(10);
474 env.assert_eq(t_rptr1, t_rptr1);
475 env.assert_eq(t_rptr10, t_rptr10);
477 // will cause an error when regions are resolved
478 env.make_subtype(t_rptr10, t_rptr1);
483 fn sub_free_bound_false() {
486 //! fn(&'a int) <: for<'b> fn(&'b int)
490 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
491 let t_rptr_free1 = env.t_rptr_free(0, 1);
492 let t_rptr_bound1 = env.t_rptr_late_bound(1);
493 env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.int),
494 env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
499 fn sub_bound_free_true() {
502 //! for<'a> fn(&'a int) <: fn(&'b int)
506 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
507 let t_rptr_bound1 = env.t_rptr_late_bound(1);
508 let t_rptr_free1 = env.t_rptr_free(0, 1);
509 env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
510 env.t_fn(&[t_rptr_free1], env.tcx().types.int));
515 fn sub_free_bound_false_infer() {
518 //! fn(_#1) <: for<'b> fn(&'b int)
520 //! does NOT hold for any instantiation of `_#1`.
522 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
523 let t_infer1 = env.infcx.next_ty_var();
524 let t_rptr_bound1 = env.t_rptr_late_bound(1);
525 env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.int),
526 env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
531 fn lub_free_bound_infer() {
534 //! LUB(fn(_#1), for<'b> fn(&'b int))
536 //! This should yield `fn(&'_ int)`. We check
537 //! that it yields `fn(&'x int)` for some free `'x`,
540 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
541 let t_infer1 = env.infcx.next_ty_var();
542 let t_rptr_bound1 = env.t_rptr_late_bound(1);
543 let t_rptr_free1 = env.t_rptr_free(0, 1);
544 env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.int),
545 env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
546 env.t_fn(&[t_rptr_free1], env.tcx().types.int));
551 fn lub_bound_bound() {
552 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
553 let t_rptr_bound1 = env.t_rptr_late_bound(1);
554 let t_rptr_bound2 = env.t_rptr_late_bound(2);
555 env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
556 env.t_fn(&[t_rptr_bound2], env.tcx().types.int),
557 env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
562 fn lub_bound_free() {
563 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
564 let t_rptr_bound1 = env.t_rptr_late_bound(1);
565 let t_rptr_free1 = env.t_rptr_free(0, 1);
566 env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
567 env.t_fn(&[t_rptr_free1], env.tcx().types.int),
568 env.t_fn(&[t_rptr_free1], env.tcx().types.int));
573 fn lub_bound_static() {
574 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
575 let t_rptr_bound1 = env.t_rptr_late_bound(1);
576 let t_rptr_static = env.t_rptr_static();
577 env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
578 env.t_fn(&[t_rptr_static], env.tcx().types.int),
579 env.t_fn(&[t_rptr_static], env.tcx().types.int));
584 fn lub_bound_bound_inverse_order() {
585 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
586 let t_rptr_bound1 = env.t_rptr_late_bound(1);
587 let t_rptr_bound2 = env.t_rptr_late_bound(2);
588 env.check_lub(env.t_fn(&[t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
589 env.t_fn(&[t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
590 env.t_fn(&[t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
596 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
597 let t_rptr_free1 = env.t_rptr_free(0, 1);
598 let t_rptr_free2 = env.t_rptr_free(0, 2);
599 let t_rptr_static = env.t_rptr_static();
600 env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.int),
601 env.t_fn(&[t_rptr_free2], env.tcx().types.int),
602 env.t_fn(&[t_rptr_static], env.tcx().types.int));
607 fn lub_returning_scope() {
608 test_env(EMPTY_SOURCE_STR,
609 errors(&["cannot infer an appropriate lifetime"]), |env| {
610 let t_rptr_scope10 = env.t_rptr_scope(10);
611 let t_rptr_scope11 = env.t_rptr_scope(11);
613 // this should generate an error when regions are resolved
614 env.make_lub_ty(env.t_fn(&[], t_rptr_scope10),
615 env.t_fn(&[], t_rptr_scope11));
620 fn glb_free_free_with_common_scope() {
621 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
622 let t_rptr_free1 = env.t_rptr_free(0, 1);
623 let t_rptr_free2 = env.t_rptr_free(0, 2);
624 let t_rptr_scope = env.t_rptr_scope(0);
625 env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.int),
626 env.t_fn(&[t_rptr_free2], env.tcx().types.int),
627 env.t_fn(&[t_rptr_scope], env.tcx().types.int));
632 fn glb_bound_bound() {
633 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
634 let t_rptr_bound1 = env.t_rptr_late_bound(1);
635 let t_rptr_bound2 = env.t_rptr_late_bound(2);
636 env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
637 env.t_fn(&[t_rptr_bound2], env.tcx().types.int),
638 env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
643 fn glb_bound_free() {
644 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
645 let t_rptr_bound1 = env.t_rptr_late_bound(1);
646 let t_rptr_free1 = env.t_rptr_free(0, 1);
647 env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
648 env.t_fn(&[t_rptr_free1], env.tcx().types.int),
649 env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
654 fn glb_bound_free_infer() {
655 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
656 let t_rptr_bound1 = env.t_rptr_late_bound(1);
657 let t_infer1 = env.infcx.next_ty_var();
659 // compute GLB(fn(_) -> int, for<'b> fn(&'b int) -> int),
660 // which should yield for<'b> fn(&'b int) -> int
661 env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
662 env.t_fn(&[t_infer1], env.tcx().types.int),
663 env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
665 // as a side-effect, computing GLB should unify `_` with
667 let t_resolve1 = env.infcx.shallow_resolve(t_infer1);
668 match t_resolve1.sty {
669 ty::ty_rptr(..) => { }
670 _ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); }
676 fn glb_bound_static() {
677 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
678 let t_rptr_bound1 = env.t_rptr_late_bound(1);
679 let t_rptr_static = env.t_rptr_static();
680 env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
681 env.t_fn(&[t_rptr_static], env.tcx().types.int),
682 env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
686 /// Test substituting a bound region into a function, which introduces another level of binding.
687 /// This requires adjusting the Debruijn index.
689 fn subst_ty_renumber_bound() {
691 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
693 // Theta = [A -> &'a foo]
695 let t_rptr_bound1 = env.t_rptr_late_bound(1);
699 let t_param = env.t_param(subst::TypeSpace, 0);
700 env.t_fn(&[t_param], env.t_nil())
703 let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
704 let t_substituted = t_source.subst(env.infcx.tcx, &substs);
706 // t_expected = fn(&'a int)
708 let t_ptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
709 env.t_fn(&[t_ptr_bound2], env.t_nil())
712 debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
713 t_source.repr(env.infcx.tcx),
714 substs.repr(env.infcx.tcx),
715 t_substituted.repr(env.infcx.tcx),
716 t_expected.repr(env.infcx.tcx));
718 assert_eq!(t_substituted, t_expected);
722 /// Test substituting a bound region into a function, which introduces another level of binding.
723 /// This requires adjusting the Debruijn index.
725 fn subst_ty_renumber_some_bounds() {
726 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
728 // Theta = [A -> &'a foo]
730 let t_rptr_bound1 = env.t_rptr_late_bound(1);
732 // t_source = (A, fn(A))
734 let t_param = env.t_param(subst::TypeSpace, 0);
735 env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
738 let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
739 let t_substituted = t_source.subst(env.infcx.tcx, &substs);
741 // t_expected = (&'a int, fn(&'a int))
743 // but not that the Debruijn index is different in the different cases.
745 let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
746 env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
749 debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
750 t_source.repr(env.infcx.tcx),
751 substs.repr(env.infcx.tcx),
752 t_substituted.repr(env.infcx.tcx),
753 t_expected.repr(env.infcx.tcx));
755 assert_eq!(t_substituted, t_expected);
759 /// Test that we correctly compute whether a type has escaping regions or not.
763 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
765 // Theta = [A -> &'a foo]
767 assert!(!ty::type_has_escaping_regions(env.t_nil()));
769 let t_rptr_free1 = env.t_rptr_free(0, 1);
770 assert!(!ty::type_has_escaping_regions(t_rptr_free1));
772 let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
773 assert!(ty::type_has_escaping_regions(t_rptr_bound1));
775 let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
776 assert!(ty::type_has_escaping_regions(t_rptr_bound2));
779 let t_param = env.t_param(subst::TypeSpace, 0);
780 assert!(!ty::type_has_escaping_regions(t_param));
781 let t_fn = env.t_fn(&[t_param], env.t_nil());
782 assert!(!ty::type_has_escaping_regions(t_fn));
785 let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(), env.re_free(0, 1));
786 assert!(!ty::type_has_escaping_regions(t_fn));
788 // t_fn = |&int|+'a (where &int has depth 2)
789 let t_fn = env.t_closure(&[t_rptr_bound2], env.t_nil(), env.re_free(0, 1));
790 assert!(ty::type_has_escaping_regions(t_fn));
792 // t_fn = |&int|+&int
793 let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(),
794 env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)));
795 assert!(ty::type_has_escaping_regions(t_fn));
799 /// Test applying a substitution where the value being substituted for an early-bound region is a
800 /// late-bound region.
802 fn subst_region_renumber_region() {
803 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
804 let re_bound1 = env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
806 // type t_source<'a> = fn(&'a int)
808 let re_early = env.re_early_bound(subst::TypeSpace, 0, "'a");
809 env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
812 let substs = subst::Substs::new_type(vec![], vec![re_bound1]);
813 let t_substituted = t_source.subst(env.infcx.tcx, &substs);
815 // t_expected = fn(&'a int)
817 // but not that the Debruijn index is different in the different cases.
819 let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
820 env.t_fn(&[t_rptr_bound2], env.t_nil())
823 debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
824 t_source.repr(env.infcx.tcx),
825 substs.repr(env.infcx.tcx),
826 t_substituted.repr(env.infcx.tcx),
827 t_expected.repr(env.infcx.tcx));
829 assert_eq!(t_substituted, t_expected);
835 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
836 let tcx = env.infcx.tcx;
837 let int_ty = tcx.types.int;
838 let uint_ty = tcx.types.uint;
839 let tup1_ty = ty::mk_tup(tcx, vec!(int_ty, uint_ty, int_ty, uint_ty));
840 let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty));
841 let uniq_ty = ty::mk_uniq(tcx, tup2_ty);
842 let walked: Vec<_> = uniq_ty.walk().collect();
843 assert_eq!(vec!(uniq_ty,
845 tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
846 tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
853 fn walk_ty_skip_subtree() {
854 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
855 let tcx = env.infcx.tcx;
856 let int_ty = tcx.types.int;
857 let uint_ty = tcx.types.uint;
858 let tup1_ty = ty::mk_tup(tcx, vec!(int_ty, uint_ty, int_ty, uint_ty));
859 let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty));
860 let uniq_ty = ty::mk_uniq(tcx, tup2_ty);
862 // types we expect to see (in order), plus a boolean saying
863 // whether to skip the subtree.
864 let mut expected = vec!((uniq_ty, false),
871 (tup1_ty, true), // skip the int/uint/int/uint
875 let mut walker = uniq_ty.walk();
876 while let Some(t) = walker.next() {
877 debug!("walked to {}", t);
878 let (expected_ty, skip) = expected.pop().unwrap();
879 assert_eq!(t, expected_ty);
880 if skip { walker.skip_current_subtree(); }
883 assert!(expected.is_empty());