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
;
17 use rustc_resolve
as resolve
;
18 use rustc_typeck
::middle
::lang_items
;
19 use rustc_typeck
::middle
::free_region
::FreeRegionMap
;
20 use rustc_typeck
::middle
::region
::{self, CodeExtent, DestructionScopeData}
;
21 use rustc_typeck
::middle
::resolve_lifetime
;
22 use rustc_typeck
::middle
::stability
;
23 use rustc_typeck
::middle
::subst
;
24 use rustc_typeck
::middle
::subst
::Subst
;
25 use rustc_typeck
::middle
::ty
::{self, Ty}
;
26 use rustc_typeck
::middle
::ty_relate
::TypeRelation
;
27 use rustc_typeck
::middle
::infer
;
28 use rustc_typeck
::middle
::infer
::lub
::Lub
;
29 use rustc_typeck
::middle
::infer
::glb
::Glb
;
30 use rustc_typeck
::middle
::infer
::sub
::Sub
;
32 use rustc
::session
::{self,config}
;
33 use syntax
::{abi, ast}
;
35 use syntax
::codemap
::{Span, CodeMap, DUMMY_SP}
;
36 use syntax
::diagnostic
::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help}
;
37 use syntax
::parse
::token
;
38 use syntax
::feature_gate
::UnstableFeatures
;
40 struct Env
<'a
, 'tcx
: 'a
> {
41 infcx
: &'a infer
::InferCtxt
<'a
, 'tcx
>,
49 const EMPTY_SOURCE_STR
: &'
static str = "#![feature(no_std)] #![no_std]";
51 struct ExpectErrorEmitter
{
55 fn remove_message(e
: &mut ExpectErrorEmitter
, msg
: &str, lvl
: Level
) {
57 Bug
| Fatal
| Error
=> { }
58 Warning
| Note
| Help
=> { return; }
61 debug
!("Error: {}", msg
);
62 match e
.messages
.iter().position(|m
| msg
.contains(m
)) {
67 panic
!("Unexpected error: {} Expected: {:?}",
73 impl Emitter
for ExpectErrorEmitter
{
75 _cmsp
: Option
<(&codemap
::CodeMap
, Span
)>,
80 remove_message(self, msg
, lvl
);
83 fn custom_emit(&mut self,
84 _cm
: &codemap
::CodeMap
,
89 remove_message(self, msg
, lvl
);
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())
98 fn test_env
<F
>(source_string
: &str,
99 (emitter
, expected_err_count
): (Box
<Emitter
+Send
>, usize),
104 config
::basic_options();
105 options
.debugging_opts
.verbose
= true;
106 options
.unstable_features
= UnstableFeatures
::Allow
;
109 let diagnostic_handler
=
110 diagnostic
::Handler
::with_emitter(true, emitter
);
111 let span_diagnostic_handler
=
112 diagnostic
::SpanHandler
::new(diagnostic_handler
, codemap
);
114 let sess
= session
::build_session_(options
, None
, span_diagnostic_handler
);
115 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
116 let krate_config
= Vec
::new();
117 let input
= config
::Input
::Str(source_string
.to_string());
118 let krate
= driver
::phase_1_parse_input(&sess
, krate_config
, &input
);
119 let krate
= driver
::phase_2_configure_and_expand(&sess
, krate
, "test", None
)
120 .expect("phase 2 aborted");
122 let mut forest
= ast_map
::Forest
::new(krate
);
123 let arenas
= ty
::CtxtArenas
::new();
124 let ast_map
= driver
::assign_node_ids_and_map(&sess
, &mut forest
);
125 let krate
= ast_map
.krate();
127 // run just enough stuff to build a tcx:
128 let lang_items
= lang_items
::collect_language_items(krate
, &sess
);
129 let resolve
::CrateMap { def_map, freevars, .. }
=
130 resolve
::resolve_crate(&sess
, &ast_map
, resolve
::MakeGlobMap
::No
);
131 let named_region_map
= resolve_lifetime
::krate(&sess
, krate
, &def_map
);
132 let region_map
= region
::resolve_crate(&sess
, krate
);
141 stability
::Index
::new(krate
),
143 let infcx
= infer
::new_infer_ctxt(tcx
);
144 body(Env { infcx: &infcx }
);
145 let free_regions
= FreeRegionMap
::new();
146 infcx
.resolve_regions_and_report_errors(&free_regions
, ast
::CRATE_NODE_ID
);
147 assert_eq
!(tcx
.sess
.err_count(), expected_err_count
);
151 impl<'a
, 'tcx
> Env
<'a
, 'tcx
> {
152 pub fn tcx(&self) -> &ty
::ctxt
<'tcx
> {
156 pub fn create_region_hierarchy(&self, rh
: &RH
) {
157 for child_rh
in rh
.sub
{
158 self.create_region_hierarchy(child_rh
);
159 self.infcx
.tcx
.region_maps
.record_encl_scope(
160 CodeExtent
::from_node_id(child_rh
.id
),
161 CodeExtent
::from_node_id(rh
.id
));
165 pub fn create_simple_region_hierarchy(&self) {
166 // creates a region hierarchy where 1 is root, 10 and 11 are
167 // children of 1, etc
168 self.create_region_hierarchy(
176 #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
177 pub fn lookup_item(&self, names
: &[String
]) -> ast
::NodeId
{
178 return match search_mod(self, &self.infcx
.tcx
.map
.krate().module
, 0, names
) {
181 panic
!("no item found: `{}`", names
.connect("::"));
185 fn search_mod(this
: &Env
,
189 -> Option
<ast
::NodeId
> {
190 assert
!(idx
< names
.len());
191 for item
in &m
.items
{
192 if item
.ident
.to_string() == names
[idx
] {
193 return search(this
, &**item
, idx
+1, names
);
199 fn search(this
: &Env
,
203 -> Option
<ast
::NodeId
> {
204 if idx
== names
.len() {
208 return match it
.node
{
209 ast
::ItemUse(..) | ast
::ItemExternCrate(..) |
210 ast
::ItemConst(..) | ast
::ItemStatic(..) | ast
::ItemFn(..) |
211 ast
::ItemForeignMod(..) | ast
::ItemTy(..) => {
215 ast
::ItemEnum(..) | ast
::ItemStruct(..) |
216 ast
::ItemTrait(..) | ast
::ItemImpl(..) |
217 ast
::ItemMac(..) | ast
::ItemDefaultImpl(..) => {
221 ast
::ItemMod(ref m
) => {
222 search_mod(this
, m
, idx
, names
)
228 pub fn make_subtype(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> bool
{
229 match infer
::mk_subty(self.infcx
, true, infer
::Misc(DUMMY_SP
), a
, b
) {
231 Err(ref e
) => panic
!("Encountered error: {}", e
)
235 pub fn is_subtype(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> bool
{
236 match infer
::can_mk_subty(self.infcx
, a
, b
) {
242 pub fn assert_subtype(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) {
243 if !self.is_subtype(a
, b
) {
244 panic
!("{} is not a subtype of {}, but it should be", a
, b
);
248 pub fn assert_eq(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) {
249 self.assert_subtype(a
, b
);
250 self.assert_subtype(b
, a
);
254 input_tys
: &[Ty
<'tcx
>],
258 let input_args
= input_tys
.iter().cloned().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_param(&self, space
: subst
::ParamSpace
, index
: u32) -> Ty
<'tcx
> {
281 let name
= format
!("T{}", index
);
282 ty
::mk_param(self.infcx
.tcx
, space
, index
, token
::intern(&name
[..]))
285 pub fn re_early_bound(&self,
286 space
: subst
::ParamSpace
,
291 let name
= token
::intern(name
);
292 ty
::ReEarlyBound(ty
::EarlyBoundRegion
{
293 param_id
: ast
::DUMMY_NODE_ID
,
300 pub fn re_late_bound_with_debruijn(&self, id
: u32, debruijn
: ty
::DebruijnIndex
) -> ty
::Region
{
301 ty
::ReLateBound(debruijn
, ty
::BrAnon(id
))
304 pub fn t_rptr(&self, r
: ty
::Region
) -> Ty
<'tcx
> {
305 ty
::mk_imm_rptr(self.infcx
.tcx
,
306 self.infcx
.tcx
.mk_region(r
),
307 self.tcx().types
.isize)
310 pub fn t_rptr_late_bound(&self, id
: u32) -> Ty
<'tcx
> {
311 let r
= self.re_late_bound_with_debruijn(id
, ty
::DebruijnIndex
::new(1));
312 ty
::mk_imm_rptr(self.infcx
.tcx
,
313 self.infcx
.tcx
.mk_region(r
),
314 self.tcx().types
.isize)
317 pub fn t_rptr_late_bound_with_debruijn(&self,
319 debruijn
: ty
::DebruijnIndex
)
321 let r
= self.re_late_bound_with_debruijn(id
, debruijn
);
322 ty
::mk_imm_rptr(self.infcx
.tcx
,
323 self.infcx
.tcx
.mk_region(r
),
324 self.tcx().types
.isize)
327 pub fn t_rptr_scope(&self, id
: ast
::NodeId
) -> Ty
<'tcx
> {
328 let r
= ty
::ReScope(CodeExtent
::from_node_id(id
));
329 ty
::mk_imm_rptr(self.infcx
.tcx
, self.infcx
.tcx
.mk_region(r
),
330 self.tcx().types
.isize)
333 pub fn re_free(&self, nid
: ast
::NodeId
, id
: u32) -> ty
::Region
{
334 ty
::ReFree(ty
::FreeRegion
{ scope
: DestructionScopeData
::new(nid
),
335 bound_region
: ty
::BrAnon(id
)})
338 pub fn t_rptr_free(&self, nid
: ast
::NodeId
, id
: u32) -> Ty
<'tcx
> {
339 let r
= self.re_free(nid
, id
);
340 ty
::mk_imm_rptr(self.infcx
.tcx
,
341 self.infcx
.tcx
.mk_region(r
),
342 self.tcx().types
.isize)
345 pub fn t_rptr_static(&self) -> Ty
<'tcx
> {
346 ty
::mk_imm_rptr(self.infcx
.tcx
,
347 self.infcx
.tcx
.mk_region(ty
::ReStatic
),
348 self.tcx().types
.isize)
351 pub fn dummy_type_trace(&self) -> infer
::TypeTrace
<'tcx
> {
352 infer
::TypeTrace
::dummy(self.tcx())
355 pub fn sub(&self) -> Sub
<'a
, 'tcx
> {
356 let trace
= self.dummy_type_trace();
357 self.infcx
.sub(true, trace
)
360 pub fn lub(&self) -> Lub
<'a
, 'tcx
> {
361 let trace
= self.dummy_type_trace();
362 self.infcx
.lub(true, trace
)
365 pub fn glb(&self) -> Glb
<'a
, 'tcx
> {
366 let trace
= self.dummy_type_trace();
367 self.infcx
.glb(true, trace
)
370 pub fn make_lub_ty(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) -> Ty
<'tcx
> {
371 match self.lub().relate(&t1
, &t2
) {
373 Err(ref e
) => panic
!("unexpected error computing LUB: {}", e
)
377 /// Checks that `t1 <: t2` is true (this may register additional
379 pub fn check_sub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) {
380 match self.sub().relate(&t1
, &t2
) {
383 panic
!("unexpected error computing sub({:?},{:?}): {}",
391 /// Checks that `t1 <: t2` is false (this may register additional
393 pub fn check_not_sub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) {
394 match self.sub().relate(&t1
, &t2
) {
397 panic
!("unexpected success computing sub({:?},{:?})",
404 /// Checks that `LUB(t1,t2) == t_lub`
405 pub fn check_lub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>, t_lub
: Ty
<'tcx
>) {
406 match self.lub().relate(&t1
, &t2
) {
408 self.assert_eq(t
, t_lub
);
411 panic
!("unexpected error in LUB: {}", e
)
416 /// Checks that `GLB(t1,t2) == t_glb`
417 pub fn check_glb(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>, t_glb
: Ty
<'tcx
>) {
418 debug
!("check_glb(t1={}, t2={}, t_glb={})", t1
, t2
, t_glb
);
419 match self.glb().relate(&t1
, &t2
) {
421 panic
!("unexpected error computing LUB: {:?}", e
)
424 self.assert_eq(t
, t_glb
);
426 // sanity check for good measure:
427 self.assert_subtype(t
, t1
);
428 self.assert_subtype(t
, t2
);
435 fn contravariant_region_ptr_ok() {
436 test_env(EMPTY_SOURCE_STR
, errors(&[]), |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
);
447 fn contravariant_region_ptr_err() {
448 test_env(EMPTY_SOURCE_STR
,
449 errors(&["lifetime mismatch"]),
451 env
.create_simple_region_hierarchy();
452 let t_rptr1
= env
.t_rptr_scope(1);
453 let t_rptr10
= env
.t_rptr_scope(10);
454 env
.assert_eq(t_rptr1
, t_rptr1
);
455 env
.assert_eq(t_rptr10
, t_rptr10
);
457 // will cause an error when regions are resolved
458 env
.make_subtype(t_rptr10
, t_rptr1
);
463 fn sub_free_bound_false() {
466 //! fn(&'a isize) <: for<'b> fn(&'b isize)
470 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
471 let t_rptr_free1
= env
.t_rptr_free(0, 1);
472 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
473 env
.check_not_sub(env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
474 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
479 fn sub_bound_free_true() {
482 //! for<'a> fn(&'a isize) <: fn(&'b isize)
486 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
487 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
488 let t_rptr_free1
= env
.t_rptr_free(0, 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));
495 fn sub_free_bound_false_infer() {
498 //! fn(_#1) <: for<'b> fn(&'b isize)
500 //! does NOT hold for any instantiation of `_#1`.
502 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
503 let t_infer1
= env
.infcx
.next_ty_var();
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));
511 fn lub_free_bound_infer() {
514 //! LUB(fn(_#1), for<'b> fn(&'b isize))
516 //! This should yield `fn(&'_ isize)`. We check
517 //! that it yields `fn(&'x isize)` for some free `'x`,
520 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
521 let t_infer1
= env
.infcx
.next_ty_var();
522 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
523 let t_rptr_free1
= env
.t_rptr_free(0, 1);
524 env
.check_lub(env
.t_fn(&[t_infer1
], env
.tcx().types
.isize),
525 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
526 env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize));
531 fn lub_bound_bound() {
532 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
533 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
534 let t_rptr_bound2
= env
.t_rptr_late_bound(2);
535 env
.check_lub(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
536 env
.t_fn(&[t_rptr_bound2
], env
.tcx().types
.isize),
537 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
542 fn lub_bound_free() {
543 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
544 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
545 let t_rptr_free1
= env
.t_rptr_free(0, 1);
546 env
.check_lub(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
547 env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
548 env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize));
553 fn lub_bound_static() {
554 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
555 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
556 let t_rptr_static
= env
.t_rptr_static();
557 env
.check_lub(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
558 env
.t_fn(&[t_rptr_static
], env
.tcx().types
.isize),
559 env
.t_fn(&[t_rptr_static
], env
.tcx().types
.isize));
564 fn lub_bound_bound_inverse_order() {
565 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
566 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
567 let t_rptr_bound2
= env
.t_rptr_late_bound(2);
568 env
.check_lub(env
.t_fn(&[t_rptr_bound1
, t_rptr_bound2
], t_rptr_bound1
),
569 env
.t_fn(&[t_rptr_bound2
, t_rptr_bound1
], t_rptr_bound1
),
570 env
.t_fn(&[t_rptr_bound1
, t_rptr_bound1
], t_rptr_bound1
));
576 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
577 let t_rptr_free1
= env
.t_rptr_free(0, 1);
578 let t_rptr_free2
= env
.t_rptr_free(0, 2);
579 let t_rptr_static
= env
.t_rptr_static();
580 env
.check_lub(env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
581 env
.t_fn(&[t_rptr_free2
], env
.tcx().types
.isize),
582 env
.t_fn(&[t_rptr_static
], env
.tcx().types
.isize));
587 fn lub_returning_scope() {
588 test_env(EMPTY_SOURCE_STR
,
589 errors(&["cannot infer an appropriate lifetime"]), |env
| {
590 env
.create_simple_region_hierarchy();
591 let t_rptr_scope10
= env
.t_rptr_scope(10);
592 let t_rptr_scope11
= env
.t_rptr_scope(11);
594 // this should generate an error when regions are resolved
595 env
.make_lub_ty(env
.t_fn(&[], t_rptr_scope10
),
596 env
.t_fn(&[], t_rptr_scope11
));
601 fn glb_free_free_with_common_scope() {
602 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
603 let t_rptr_free1
= env
.t_rptr_free(0, 1);
604 let t_rptr_free2
= env
.t_rptr_free(0, 2);
605 let t_rptr_scope
= env
.t_rptr_scope(0);
606 env
.check_glb(env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
607 env
.t_fn(&[t_rptr_free2
], env
.tcx().types
.isize),
608 env
.t_fn(&[t_rptr_scope
], env
.tcx().types
.isize));
613 fn glb_bound_bound() {
614 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
615 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
616 let t_rptr_bound2
= env
.t_rptr_late_bound(2);
617 env
.check_glb(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
618 env
.t_fn(&[t_rptr_bound2
], env
.tcx().types
.isize),
619 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
624 fn glb_bound_free() {
625 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
626 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
627 let t_rptr_free1
= env
.t_rptr_free(0, 1);
628 env
.check_glb(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
629 env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
630 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
635 fn glb_bound_free_infer() {
636 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
637 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
638 let t_infer1
= env
.infcx
.next_ty_var();
640 // compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize),
641 // which should yield for<'b> fn(&'b isize) -> isize
642 env
.check_glb(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
643 env
.t_fn(&[t_infer1
], env
.tcx().types
.isize),
644 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
646 // as a side-effect, computing GLB should unify `_` with
648 let t_resolve1
= env
.infcx
.shallow_resolve(t_infer1
);
649 match t_resolve1
.sty
{
651 _
=> { panic!("t_resolve1={:?}
", t_resolve1); }
657 fn glb_bound_static() {
658 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
659 let t_rptr_bound1 = env.t_rptr_late_bound(1);
660 let t_rptr_static = env.t_rptr_static();
661 env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
662 env.t_fn(&[t_rptr_static], env.tcx().types.isize),
663 env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
667 /// Test substituting a bound region into a function, which introduces another level of binding.
668 /// This requires adjusting the Debruijn index.
670 fn subst_ty_renumber_bound() {
672 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
674 // Theta = [A -> &'a foo]
676 let t_rptr_bound1 = env.t_rptr_late_bound(1);
680 let t_param = env.t_param(subst::TypeSpace, 0);
681 env.t_fn(&[t_param], env.t_nil())
684 let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
685 let t_substituted = t_source.subst(env.infcx.tcx, &substs);
687 // t_expected = fn(&'a isize)
689 let t_ptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
690 env.t_fn(&[t_ptr_bound2], env.t_nil())
693 debug!("subst_bound
: t_source
={:?} substs
={:?} t_substituted
={:?} t_expected
={:?}
",
699 assert_eq!(t_substituted, t_expected);
703 /// Test substituting a bound region into a function, which introduces another level of binding.
704 /// This requires adjusting the Debruijn index.
706 fn subst_ty_renumber_some_bounds() {
707 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
709 // Theta = [A -> &'a foo]
711 let t_rptr_bound1 = env.t_rptr_late_bound(1);
713 // t_source = (A, fn(A))
715 let t_param = env.t_param(subst::TypeSpace, 0);
716 env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
719 let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
720 let t_substituted = t_source.subst(env.infcx.tcx, &substs);
722 // t_expected = (&'a isize, fn(&'a isize))
724 // but not that the Debruijn index is different in the different cases.
726 let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
727 env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
730 debug!("subst_bound
: t_source
={:?} substs
={:?} t_substituted
={:?} t_expected
={:?}
",
736 assert_eq!(t_substituted, t_expected);
740 /// Test that we correctly compute whether a type has escaping regions or not.
744 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
746 // Theta = [A -> &'a foo]
748 assert!(!ty::type_has_escaping_regions(env.t_nil()));
750 let t_rptr_free1 = env.t_rptr_free(0, 1);
751 assert!(!ty::type_has_escaping_regions(t_rptr_free1));
753 let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
754 assert!(ty::type_has_escaping_regions(t_rptr_bound1));
756 let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
757 assert!(ty::type_has_escaping_regions(t_rptr_bound2));
760 let t_param = env.t_param(subst::TypeSpace, 0);
761 assert!(!ty::type_has_escaping_regions(t_param));
762 let t_fn = env.t_fn(&[t_param], env.t_nil());
763 assert!(!ty::type_has_escaping_regions(t_fn));
767 /// Test applying a substitution where the value being substituted for an early-bound region is a
768 /// late-bound region.
770 fn subst_region_renumber_region() {
771 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
772 let re_bound1 = env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
774 // type t_source<'a> = fn(&'a isize)
776 let re_early = env.re_early_bound(subst::TypeSpace, 0, "'a
");
777 env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
780 let substs = subst::Substs::new_type(vec![], vec![re_bound1]);
781 let t_substituted = t_source.subst(env.infcx.tcx, &substs);
783 // t_expected = fn(&'a isize)
785 // but not that the Debruijn index is different in the different cases.
787 let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
788 env.t_fn(&[t_rptr_bound2], env.t_nil())
791 debug!("subst_bound
: t_source
={:?} substs
={:?} t_substituted
={:?} t_expected
={:?}
",
797 assert_eq!(t_substituted, t_expected);
803 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
804 let tcx = env.infcx.tcx;
805 let int_ty = tcx.types.isize;
806 let uint_ty = tcx.types.usize;
807 let tup1_ty = ty::mk_tup(tcx, vec!(int_ty, uint_ty, int_ty, uint_ty));
808 let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty));
809 let uniq_ty = ty::mk_uniq(tcx, tup2_ty);
810 let walked: Vec<_> = uniq_ty.walk().collect();
811 assert_eq!(walked, [uniq_ty,
813 tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
814 tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
820 fn walk_ty_skip_subtree() {
821 test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
822 let tcx = env.infcx.tcx;
823 let int_ty = tcx.types.isize;
824 let uint_ty = tcx.types.usize;
825 let tup1_ty = ty::mk_tup(tcx, vec!(int_ty, uint_ty, int_ty, uint_ty));
826 let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty));
827 let uniq_ty = ty::mk_uniq(tcx, tup2_ty);
829 // types we expect to see (in order), plus a boolean saying
830 // whether to skip the subtree.
831 let mut expected = vec!((uniq_ty, false),
838 (tup1_ty, true), // skip the isize/usize/isize/usize
842 let mut walker = uniq_ty.walk();
843 while let Some(t) = walker.next() {
844 debug!("walked to {:?}
", t);
845 let (expected_ty, skip) = expected.pop().unwrap();
846 assert_eq!(t, expected_ty);
847 if skip { walker.skip_current_subtree(); }
850 assert!(expected.is_empty());