]> git.lizzy.rs Git - rust.git/blob - src/librustc_driver/test.rs
incr.comp.: Add some comments.
[rust.git] / src / librustc_driver / test.rs
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.
4 //
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.
10
11 //! # Standalone Tests for the Inference Module
12
13 use std::path::PathBuf;
14 use std::sync::mpsc;
15
16 use driver;
17 use rustc_lint;
18 use rustc_resolve::MakeGlobMap;
19 use rustc_trans;
20 use rustc::middle::free_region::FreeRegionMap;
21 use rustc::middle::region;
22 use rustc::middle::resolve_lifetime;
23 use rustc::ty::subst::{Kind, Subst};
24 use rustc::traits::{ObligationCause, Reveal};
25 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
26 use rustc::infer::{self, InferOk, InferResult};
27 use rustc::infer::type_variable::TypeVariableOrigin;
28 use rustc_metadata::cstore::CStore;
29 use rustc::hir::map as hir_map;
30 use rustc::mir::transform::Passes;
31 use rustc::session::{self, config};
32 use rustc::session::config::{OutputFilenames, OutputTypes};
33 use std::rc::Rc;
34 use syntax::ast;
35 use syntax::abi::Abi;
36 use syntax::codemap::{CodeMap, FilePathMapping};
37 use errors;
38 use errors::emitter::Emitter;
39 use errors::{Level, DiagnosticBuilder};
40 use syntax::feature_gate::UnstableFeatures;
41 use syntax::symbol::Symbol;
42 use syntax_pos::DUMMY_SP;
43 use arena::DroplessArena;
44
45 use rustc::hir;
46
47 struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
48     infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>,
49     region_scope_tree: &'a mut region::ScopeTree,
50     param_env: ty::ParamEnv<'tcx>,
51 }
52
53 struct RH<'a> {
54     id: hir::ItemLocalId,
55     sub: &'a [RH<'a>],
56 }
57
58 const EMPTY_SOURCE_STR: &'static str = "#![feature(no_core)] #![no_core]";
59
60 struct ExpectErrorEmitter {
61     messages: Vec<String>,
62 }
63
64 fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
65     match lvl {
66         Level::Bug | Level::Fatal | Level::Error => {}
67         _ => {
68             return;
69         }
70     }
71
72     debug!("Error: {}", msg);
73     match e.messages.iter().position(|m| msg.contains(m)) {
74         Some(i) => {
75             e.messages.remove(i);
76         }
77         None => {
78             debug!("Unexpected error: {} Expected: {:?}", msg, e.messages);
79             panic!("Unexpected error: {} Expected: {:?}", msg, e.messages);
80         }
81     }
82 }
83
84 impl Emitter for ExpectErrorEmitter {
85     fn emit(&mut self, db: &DiagnosticBuilder) {
86         remove_message(self, &db.message(), db.level);
87         for child in &db.children {
88             remove_message(self, &child.message(), child.level);
89         }
90     }
91 }
92
93 fn errors(msgs: &[&str]) -> (Box<Emitter + Send>, usize) {
94     let v = msgs.iter().map(|m| m.to_string()).collect();
95     (box ExpectErrorEmitter { messages: v } as Box<Emitter + Send>, msgs.len())
96 }
97
98 fn test_env<F>(source_string: &str,
99                (emitter, expected_err_count): (Box<Emitter + Send>, usize),
100                body: F)
101     where F: FnOnce(Env)
102 {
103     let mut options = config::basic_options();
104     options.debugging_opts.verbose = true;
105     options.unstable_features = UnstableFeatures::Allow;
106     let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
107
108     let cstore = Rc::new(CStore::new(box ::MetadataLoader));
109     let sess = session::build_session_(options,
110                                        None,
111                                        diagnostic_handler,
112                                        Rc::new(CodeMap::new(FilePathMapping::empty())));
113     rustc_trans::init(&sess);
114     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
115     let input = config::Input::Str {
116         name: driver::anon_src(),
117         input: source_string.to_string(),
118     };
119     let krate = driver::phase_1_parse_input(&driver::CompileController::basic(),
120                                             &sess,
121                                             &input).unwrap();
122     let driver::ExpansionResult { defs, resolutions, mut hir_forest, .. } = {
123         driver::phase_2_configure_and_expand(&sess,
124                                              &cstore,
125                                              krate,
126                                              None,
127                                              "test",
128                                              None,
129                                              MakeGlobMap::No,
130                                              |_| Ok(()))
131             .expect("phase 2 aborted")
132     };
133
134     let arena = DroplessArena::new();
135     let arenas = ty::GlobalArenas::new();
136     let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
137
138     // run just enough stuff to build a tcx:
139     let named_region_map = resolve_lifetime::krate(&sess, &*cstore, &hir_map);
140     let (tx, _rx) = mpsc::channel();
141     let outputs = OutputFilenames {
142         out_directory: PathBuf::new(),
143         out_filestem: String::new(),
144         single_output_file: None,
145         extra: String::new(),
146         outputs: OutputTypes::new(&[]),
147     };
148     TyCtxt::create_and_enter(&sess,
149                              &*cstore,
150                              ty::maps::Providers::default(),
151                              ty::maps::Providers::default(),
152                              Rc::new(Passes::new()),
153                              &arenas,
154                              &arena,
155                              resolutions,
156                              named_region_map.unwrap(),
157                              hir_map,
158                              "test_crate",
159                              tx,
160                              &outputs,
161                              |tcx| {
162         tcx.infer_ctxt().enter(|infcx| {
163             let mut region_scope_tree = region::ScopeTree::default();
164             body(Env {
165                 infcx: &infcx,
166                 region_scope_tree: &mut region_scope_tree,
167                 param_env: ty::ParamEnv::empty(Reveal::UserFacing),
168             });
169             let free_regions = FreeRegionMap::new();
170             let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
171             infcx.resolve_regions_and_report_errors(def_id, &region_scope_tree, &free_regions);
172             assert_eq!(tcx.sess.err_count(), expected_err_count);
173         });
174     });
175 }
176
177 impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
178     pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
179         self.infcx.tcx
180     }
181
182     pub fn create_region_hierarchy(&mut self, rh: &RH, parent: region::Scope) {
183         let me = region::Scope::Node(rh.id);
184         self.region_scope_tree.record_scope_parent(me, Some(parent));
185         for child_rh in rh.sub {
186             self.create_region_hierarchy(child_rh, me);
187         }
188     }
189
190     pub fn create_simple_region_hierarchy(&mut self) {
191         // creates a region hierarchy where 1 is root, 10 and 11 are
192         // children of 1, etc
193
194         let dscope = region::Scope::Destruction(hir::ItemLocalId(1));
195         self.region_scope_tree.record_scope_parent(dscope, None);
196         self.create_region_hierarchy(&RH {
197             id: hir::ItemLocalId(1),
198             sub: &[RH {
199                 id: hir::ItemLocalId(10),
200                 sub: &[],
201             },
202             RH {
203                 id: hir::ItemLocalId(11),
204                 sub: &[],
205             }],
206         }, dscope);
207     }
208
209     #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
210     pub fn lookup_item(&self, names: &[String]) -> ast::NodeId {
211         return match search_mod(self, &self.infcx.tcx.hir.krate().module, 0, names) {
212             Some(id) => id,
213             None => {
214                 panic!("no item found: `{}`", names.join("::"));
215             }
216         };
217
218         fn search_mod(this: &Env,
219                       m: &hir::Mod,
220                       idx: usize,
221                       names: &[String])
222                       -> Option<ast::NodeId> {
223             assert!(idx < names.len());
224             for item in &m.item_ids {
225                 let item = this.infcx.tcx.hir.expect_item(item.id);
226                 if item.name.to_string() == names[idx] {
227                     return search(this, item, idx + 1, names);
228                 }
229             }
230             return None;
231         }
232
233         fn search(this: &Env, it: &hir::Item, idx: usize, names: &[String]) -> Option<ast::NodeId> {
234             if idx == names.len() {
235                 return Some(it.id);
236             }
237
238             return match it.node {
239                 hir::ItemUse(..) |
240                 hir::ItemExternCrate(..) |
241                 hir::ItemConst(..) |
242                 hir::ItemStatic(..) |
243                 hir::ItemFn(..) |
244                 hir::ItemForeignMod(..) |
245                 hir::ItemGlobalAsm(..) |
246                 hir::ItemTy(..) => None,
247
248                 hir::ItemEnum(..) |
249                 hir::ItemStruct(..) |
250                 hir::ItemUnion(..) |
251                 hir::ItemTrait(..) |
252                 hir::ItemImpl(..) |
253                 hir::ItemDefaultImpl(..) => None,
254
255                 hir::ItemMod(ref m) => search_mod(this, m, idx, names),
256             };
257         }
258     }
259
260     pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
261         match self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(a, b) {
262             Ok(_) => true,
263             Err(ref e) => panic!("Encountered error: {}", e),
264         }
265     }
266
267     pub fn is_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
268         self.infcx.can_sub(self.param_env, a, b).is_ok()
269     }
270
271     pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
272         if !self.is_subtype(a, b) {
273             panic!("{} is not a subtype of {}, but it should be", a, b);
274         }
275     }
276
277     pub fn assert_eq(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
278         self.assert_subtype(a, b);
279         self.assert_subtype(b, a);
280     }
281
282     pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
283         self.infcx.tcx.mk_fn_ptr(ty::Binder(self.infcx.tcx.mk_fn_sig(
284             input_tys.iter().cloned(),
285             output_ty,
286             false,
287             hir::Unsafety::Normal,
288             Abi::Rust
289         )))
290     }
291
292     pub fn t_nil(&self) -> Ty<'tcx> {
293         self.infcx.tcx.mk_nil()
294     }
295
296     pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> {
297         self.infcx.tcx.intern_tup(&[ty1, ty2], false)
298     }
299
300     pub fn t_param(&self, index: u32) -> Ty<'tcx> {
301         let name = format!("T{}", index);
302         self.infcx.tcx.mk_param(index, Symbol::intern(&name))
303     }
304
305     pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> {
306         let name = Symbol::intern(name);
307         self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
308             def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
309             index,
310             name,
311         }))
312     }
313
314     pub fn re_late_bound_with_debruijn(&self,
315                                        id: u32,
316                                        debruijn: ty::DebruijnIndex)
317                                        -> ty::Region<'tcx> {
318         self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id)))
319     }
320
321     pub fn t_rptr(&self, r: ty::Region<'tcx>) -> Ty<'tcx> {
322         self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
323     }
324
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         self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
328     }
329
330     pub fn t_rptr_late_bound_with_debruijn(&self,
331                                            id: u32,
332                                            debruijn: ty::DebruijnIndex)
333                                            -> Ty<'tcx> {
334         let r = self.re_late_bound_with_debruijn(id, debruijn);
335         self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
336     }
337
338     pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
339         let r = ty::ReScope(region::Scope::Node(hir::ItemLocalId(id)));
340         self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
341     }
342
343     pub fn re_free(&self, id: u32) -> ty::Region<'tcx> {
344         self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion {
345             scope: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
346             bound_region: ty::BrAnon(id),
347         }))
348     }
349
350     pub fn t_rptr_free(&self, id: u32) -> Ty<'tcx> {
351         let r = self.re_free(id);
352         self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
353     }
354
355     pub fn t_rptr_static(&self) -> Ty<'tcx> {
356         self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static,
357                                   self.tcx().types.isize)
358     }
359
360     pub fn t_rptr_empty(&self) -> Ty<'tcx> {
361         self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty,
362                                   self.tcx().types.isize)
363     }
364
365     pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> {
366         self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(t1, t2)
367     }
368
369     pub fn lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
370         self.infcx.at(&ObligationCause::dummy(), self.param_env).lub(t1, t2)
371     }
372
373     pub fn glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
374         self.infcx.at(&ObligationCause::dummy(), self.param_env).glb(t1, t2)
375     }
376
377     /// Checks that `t1 <: t2` is true (this may register additional
378     /// region checks).
379     pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
380         match self.sub(t1, t2) {
381             Ok(InferOk { obligations, value: () }) => {
382                 // None of these tests should require nested obligations:
383                 assert!(obligations.is_empty());
384             }
385             Err(ref e) => {
386                 panic!("unexpected error computing sub({:?},{:?}): {}", t1, t2, e);
387             }
388         }
389     }
390
391     /// Checks that `t1 <: t2` is false (this may register additional
392     /// region checks).
393     pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
394         match self.sub(t1, t2) {
395             Err(_) => {}
396             Ok(_) => {
397                 panic!("unexpected success computing sub({:?},{:?})", t1, t2);
398             }
399         }
400     }
401
402     /// Checks that `LUB(t1,t2) == t_lub`
403     pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
404         match self.lub(t1, t2) {
405             Ok(InferOk { obligations, value: t }) => {
406                 // None of these tests should require nested obligations:
407                 assert!(obligations.is_empty());
408
409                 self.assert_eq(t, t_lub);
410             }
411             Err(ref e) => panic!("unexpected error in LUB: {}", e),
412         }
413     }
414
415     /// Checks that `GLB(t1,t2) == t_glb`
416     pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
417         debug!("check_glb(t1={}, t2={}, t_glb={})", t1, t2, t_glb);
418         match self.glb(t1, t2) {
419             Err(e) => panic!("unexpected error computing LUB: {:?}", e),
420             Ok(InferOk { obligations, value: t }) => {
421                 // None of these tests should require nested obligations:
422                 assert!(obligations.is_empty());
423
424                 self.assert_eq(t, t_glb);
425
426                 // sanity check for good measure:
427                 self.assert_subtype(t, t1);
428                 self.assert_subtype(t, t2);
429             }
430         }
431     }
432 }
433
434 #[test]
435 fn contravariant_region_ptr_ok() {
436     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
437         env.create_simple_region_hierarchy();
438         let t_rptr1 = env.t_rptr_scope(1);
439         let t_rptr10 = env.t_rptr_scope(10);
440         env.assert_eq(t_rptr1, t_rptr1);
441         env.assert_eq(t_rptr10, t_rptr10);
442         env.make_subtype(t_rptr1, t_rptr10);
443     })
444 }
445
446 #[test]
447 fn contravariant_region_ptr_err() {
448     test_env(EMPTY_SOURCE_STR, errors(&["mismatched types"]), |mut env| {
449         env.create_simple_region_hierarchy();
450         let t_rptr1 = env.t_rptr_scope(1);
451         let t_rptr10 = env.t_rptr_scope(10);
452         env.assert_eq(t_rptr1, t_rptr1);
453         env.assert_eq(t_rptr10, t_rptr10);
454
455         // will cause an error when regions are resolved
456         env.make_subtype(t_rptr10, t_rptr1);
457     })
458 }
459
460 #[test]
461 fn sub_free_bound_false() {
462     //! Test that:
463     //!
464     //!     fn(&'a isize) <: for<'b> fn(&'b isize)
465     //!
466     //! does NOT hold.
467
468     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
469         env.create_simple_region_hierarchy();
470         let t_rptr_free1 = env.t_rptr_free(1);
471         let t_rptr_bound1 = env.t_rptr_late_bound(1);
472         env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
473                           env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
474     })
475 }
476
477 #[test]
478 fn sub_bound_free_true() {
479     //! Test that:
480     //!
481     //!     for<'a> fn(&'a isize) <: fn(&'b isize)
482     //!
483     //! DOES hold.
484
485     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
486         env.create_simple_region_hierarchy();
487         let t_rptr_bound1 = env.t_rptr_late_bound(1);
488         let t_rptr_free1 = env.t_rptr_free(1);
489         env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
490                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
491     })
492 }
493
494 #[test]
495 fn sub_free_bound_false_infer() {
496     //! Test that:
497     //!
498     //!     fn(_#1) <: for<'b> fn(&'b isize)
499     //!
500     //! does NOT hold for any instantiation of `_#1`.
501
502     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
503         let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
504         let t_rptr_bound1 = env.t_rptr_late_bound(1);
505         env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize),
506                           env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
507     })
508 }
509
510 #[test]
511 fn lub_free_bound_infer() {
512     //! Test result of:
513     //!
514     //!     LUB(fn(_#1), for<'b> fn(&'b isize))
515     //!
516     //! This should yield `fn(&'_ isize)`. We check
517     //! that it yields `fn(&'x isize)` for some free `'x`,
518     //! anyhow.
519
520     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
521         env.create_simple_region_hierarchy();
522         let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
523         let t_rptr_bound1 = env.t_rptr_late_bound(1);
524         let t_rptr_free1 = env.t_rptr_free(1);
525         env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize),
526                       env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
527                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
528     });
529 }
530
531 #[test]
532 fn lub_bound_bound() {
533     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
534         let t_rptr_bound1 = env.t_rptr_late_bound(1);
535         let t_rptr_bound2 = env.t_rptr_late_bound(2);
536         env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
537                       env.t_fn(&[t_rptr_bound2], env.tcx().types.isize),
538                       env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
539     })
540 }
541
542 #[test]
543 fn lub_bound_free() {
544     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
545         env.create_simple_region_hierarchy();
546         let t_rptr_bound1 = env.t_rptr_late_bound(1);
547         let t_rptr_free1 = env.t_rptr_free(1);
548         env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
549                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
550                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
551     })
552 }
553
554 #[test]
555 fn lub_bound_static() {
556     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
557         let t_rptr_bound1 = env.t_rptr_late_bound(1);
558         let t_rptr_static = env.t_rptr_static();
559         env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
560                       env.t_fn(&[t_rptr_static], env.tcx().types.isize),
561                       env.t_fn(&[t_rptr_static], env.tcx().types.isize));
562     })
563 }
564
565 #[test]
566 fn lub_bound_bound_inverse_order() {
567     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
568         let t_rptr_bound1 = env.t_rptr_late_bound(1);
569         let t_rptr_bound2 = env.t_rptr_late_bound(2);
570         env.check_lub(env.t_fn(&[t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
571                       env.t_fn(&[t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
572                       env.t_fn(&[t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
573     })
574 }
575
576 #[test]
577 fn lub_free_free() {
578     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
579         env.create_simple_region_hierarchy();
580         let t_rptr_free1 = env.t_rptr_free(1);
581         let t_rptr_free2 = env.t_rptr_free(2);
582         let t_rptr_static = env.t_rptr_static();
583         env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
584                       env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
585                       env.t_fn(&[t_rptr_static], env.tcx().types.isize));
586     })
587 }
588
589 #[test]
590 fn lub_returning_scope() {
591     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
592         env.create_simple_region_hierarchy();
593         let t_rptr_scope10 = env.t_rptr_scope(10);
594         let t_rptr_scope11 = env.t_rptr_scope(11);
595         let t_rptr_empty = env.t_rptr_empty();
596         env.check_lub(env.t_fn(&[t_rptr_scope10], env.tcx().types.isize),
597                       env.t_fn(&[t_rptr_scope11], env.tcx().types.isize),
598                       env.t_fn(&[t_rptr_empty], env.tcx().types.isize));
599     });
600 }
601
602 #[test]
603 fn glb_free_free_with_common_scope() {
604     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
605         env.create_simple_region_hierarchy();
606         let t_rptr_free1 = env.t_rptr_free(1);
607         let t_rptr_free2 = env.t_rptr_free(2);
608         let t_rptr_scope = env.t_rptr_scope(1);
609         env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
610                       env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
611                       env.t_fn(&[t_rptr_scope], env.tcx().types.isize));
612     })
613 }
614
615 #[test]
616 fn glb_bound_bound() {
617     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
618         let t_rptr_bound1 = env.t_rptr_late_bound(1);
619         let t_rptr_bound2 = env.t_rptr_late_bound(2);
620         env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
621                       env.t_fn(&[t_rptr_bound2], env.tcx().types.isize),
622                       env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
623     })
624 }
625
626 #[test]
627 fn glb_bound_free() {
628     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
629         env.create_simple_region_hierarchy();
630         let t_rptr_bound1 = env.t_rptr_late_bound(1);
631         let t_rptr_free1 = env.t_rptr_free(1);
632         env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
633                       env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
634                       env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
635     })
636 }
637
638 #[test]
639 fn glb_bound_free_infer() {
640     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
641         let t_rptr_bound1 = env.t_rptr_late_bound(1);
642         let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
643
644         // compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize),
645         // which should yield for<'b> fn(&'b isize) -> isize
646         env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
647                       env.t_fn(&[t_infer1], env.tcx().types.isize),
648                       env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
649
650         // as a side-effect, computing GLB should unify `_` with
651         // `&'_ isize`
652         let t_resolve1 = env.infcx.shallow_resolve(t_infer1);
653         match t_resolve1.sty {
654             ty::TyRef(..) => {}
655             _ => {
656                 panic!("t_resolve1={:?}", t_resolve1);
657             }
658         }
659     })
660 }
661
662 #[test]
663 fn glb_bound_static() {
664     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
665         let t_rptr_bound1 = env.t_rptr_late_bound(1);
666         let t_rptr_static = env.t_rptr_static();
667         env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
668                       env.t_fn(&[t_rptr_static], env.tcx().types.isize),
669                       env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
670     })
671 }
672
673 /// Test substituting a bound region into a function, which introduces another level of binding.
674 /// This requires adjusting the Debruijn index.
675 #[test]
676 fn subst_ty_renumber_bound() {
677
678     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
679         // Situation:
680         // Theta = [A -> &'a foo]
681
682         let t_rptr_bound1 = env.t_rptr_late_bound(1);
683
684         // t_source = fn(A)
685         let t_source = {
686             let t_param = env.t_param(0);
687             env.t_fn(&[t_param], env.t_nil())
688         };
689
690         let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
691         let t_substituted = t_source.subst(env.infcx.tcx, substs);
692
693         // t_expected = fn(&'a isize)
694         let t_expected = {
695             let t_ptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
696             env.t_fn(&[t_ptr_bound2], env.t_nil())
697         };
698
699         debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
700                t_source,
701                substs,
702                t_substituted,
703                t_expected);
704
705         assert_eq!(t_substituted, t_expected);
706     })
707 }
708
709 /// Test substituting a bound region into a function, which introduces another level of binding.
710 /// This requires adjusting the Debruijn index.
711 #[test]
712 fn subst_ty_renumber_some_bounds() {
713     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
714         // Situation:
715         // Theta = [A -> &'a foo]
716
717         let t_rptr_bound1 = env.t_rptr_late_bound(1);
718
719         // t_source = (A, fn(A))
720         let t_source = {
721             let t_param = env.t_param(0);
722             env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
723         };
724
725         let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
726         let t_substituted = t_source.subst(env.infcx.tcx, substs);
727
728         // t_expected = (&'a isize, fn(&'a isize))
729         //
730         // but not that the Debruijn index is different in the different cases.
731         let t_expected = {
732             let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
733             env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
734         };
735
736         debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
737                t_source,
738                substs,
739                t_substituted,
740                t_expected);
741
742         assert_eq!(t_substituted, t_expected);
743     })
744 }
745
746 /// Test that we correctly compute whether a type has escaping regions or not.
747 #[test]
748 fn escaping() {
749
750     test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
751         // Situation:
752         // Theta = [A -> &'a foo]
753         env.create_simple_region_hierarchy();
754
755         assert!(!env.t_nil().has_escaping_regions());
756
757         let t_rptr_free1 = env.t_rptr_free(1);
758         assert!(!t_rptr_free1.has_escaping_regions());
759
760         let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
761         assert!(t_rptr_bound1.has_escaping_regions());
762
763         let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
764         assert!(t_rptr_bound2.has_escaping_regions());
765
766         // t_fn = fn(A)
767         let t_param = env.t_param(0);
768         assert!(!t_param.has_escaping_regions());
769         let t_fn = env.t_fn(&[t_param], env.t_nil());
770         assert!(!t_fn.has_escaping_regions());
771     })
772 }
773
774 /// Test applying a substitution where the value being substituted for an early-bound region is a
775 /// late-bound region.
776 #[test]
777 fn subst_region_renumber_region() {
778     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
779         let re_bound1 = env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
780
781         // type t_source<'a> = fn(&'a isize)
782         let t_source = {
783             let re_early = env.re_early_bound(0, "'a");
784             env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
785         };
786
787         let substs = env.infcx.tcx.intern_substs(&[Kind::from(re_bound1)]);
788         let t_substituted = t_source.subst(env.infcx.tcx, substs);
789
790         // t_expected = fn(&'a isize)
791         //
792         // but not that the Debruijn index is different in the different cases.
793         let t_expected = {
794             let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
795             env.t_fn(&[t_rptr_bound2], env.t_nil())
796         };
797
798         debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
799                t_source,
800                substs,
801                t_substituted,
802                t_expected);
803
804         assert_eq!(t_substituted, t_expected);
805     })
806 }
807
808 #[test]
809 fn walk_ty() {
810     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
811         let tcx = env.infcx.tcx;
812         let int_ty = tcx.types.isize;
813         let usize_ty = tcx.types.usize;
814         let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false);
815         let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false);
816         let walked: Vec<_> = tup2_ty.walk().collect();
817         assert_eq!(walked,
818                    [tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty,
819                     usize_ty, int_ty, usize_ty, usize_ty]);
820     })
821 }
822
823 #[test]
824 fn walk_ty_skip_subtree() {
825     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
826         let tcx = env.infcx.tcx;
827         let int_ty = tcx.types.isize;
828         let usize_ty = tcx.types.usize;
829         let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false);
830         let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false);
831
832         // types we expect to see (in order), plus a boolean saying
833         // whether to skip the subtree.
834         let mut expected = vec![(tup2_ty, false),
835                                 (tup1_ty, false),
836                                 (int_ty, false),
837                                 (usize_ty, false),
838                                 (int_ty, false),
839                                 (usize_ty, false),
840                                 (tup1_ty, true), // skip the isize/usize/isize/usize
841                                 (usize_ty, false)];
842         expected.reverse();
843
844         let mut walker = tup2_ty.walk();
845         while let Some(t) = walker.next() {
846             debug!("walked to {:?}", t);
847             let (expected_ty, skip) = expected.pop().unwrap();
848             assert_eq!(t, expected_ty);
849             if skip {
850                 walker.skip_current_subtree();
851             }
852         }
853
854         assert!(expected.is_empty());
855     })
856 }