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 rustc
::dep_graph
::DepGraph
;
16 use rustc_resolve
as resolve
;
17 use rustc
::middle
::lang_items
;
18 use rustc
::middle
::free_region
::FreeRegionMap
;
19 use rustc
::middle
::region
::{self, CodeExtent}
;
20 use rustc
::middle
::region
::CodeExtentData
;
21 use rustc
::middle
::resolve_lifetime
;
22 use rustc
::middle
::stability
;
24 use rustc
::ty
::subst
::Subst
;
25 use rustc
::traits
::ProjectionMode
;
26 use rustc
::ty
::{self, Ty, TyCtxt, TypeFoldable}
;
27 use rustc
::ty
::relate
::TypeRelation
;
28 use rustc
::infer
::{self, InferOk, InferResult, TypeOrigin}
;
29 use rustc_metadata
::cstore
::CStore
;
30 use rustc
::hir
::map
as hir_map
;
31 use rustc
::session
::{self, config}
;
35 use syntax
::codemap
::{MultiSpan, CodeMap, DUMMY_SP}
;
37 use syntax
::errors
::emitter
::Emitter
;
38 use syntax
::errors
::{Level, RenderSpan}
;
39 use syntax
::parse
::token
;
40 use syntax
::feature_gate
::UnstableFeatures
;
42 use rustc
::hir
::lowering
::{lower_crate, LoweringContext}
;
45 struct Env
<'a
, 'tcx
: 'a
> {
46 infcx
: &'a infer
::InferCtxt
<'a
, 'tcx
>,
54 const EMPTY_SOURCE_STR
: &'
static str = "#![feature(no_core)] #![no_core]";
56 struct ExpectErrorEmitter
{
57 messages
: Vec
<String
>,
60 fn remove_message(e
: &mut ExpectErrorEmitter
, msg
: &str, lvl
: Level
) {
62 Level
::Bug
| Level
::Fatal
| Level
::Error
=> {}
68 debug
!("Error: {}", msg
);
69 match e
.messages
.iter().position(|m
| msg
.contains(m
)) {
74 panic
!("Unexpected error: {} Expected: {:?}", msg
, e
.messages
);
79 impl Emitter
for ExpectErrorEmitter
{
81 _sp
: Option
<&MultiSpan
>,
85 remove_message(self, msg
, lvl
);
88 fn custom_emit(&mut self, _sp
: &RenderSpan
, msg
: &str, lvl
: Level
) {
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
>,
99 fn test_env
<F
>(source_string
: &str,
100 (emitter
, expected_err_count
): (Box
<Emitter
+ Send
>, usize),
104 let mut options
= config
::basic_options();
105 options
.debugging_opts
.verbose
= true;
106 options
.unstable_features
= UnstableFeatures
::Allow
;
107 let diagnostic_handler
= errors
::Handler
::with_emitter(true, false, emitter
);
109 let cstore
= Rc
::new(CStore
::new(token
::get_ident_interner()));
110 let sess
= session
::build_session_(options
, None
, diagnostic_handler
,
111 Rc
::new(CodeMap
::new()), cstore
.clone());
112 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
113 let krate_config
= Vec
::new();
114 let input
= config
::Input
::Str
{
115 name
: driver
::anon_src(),
116 input
: source_string
.to_string(),
118 let krate
= driver
::phase_1_parse_input(&sess
, krate_config
, &input
).unwrap();
119 let krate
= driver
::phase_2_configure_and_expand(&sess
, &cstore
, krate
, "test", None
)
120 .expect("phase 2 aborted");
122 let krate
= driver
::assign_node_ids(&sess
, krate
);
123 let lcx
= LoweringContext
::new(&sess
, Some(&krate
));
124 let dep_graph
= DepGraph
::new(false);
125 let _ignore
= dep_graph
.in_ignore();
126 let mut hir_forest
= hir_map
::Forest
::new(lower_crate(&lcx
, &krate
), dep_graph
.clone());
127 let arenas
= ty
::CtxtArenas
::new();
128 let ast_map
= driver
::make_map(&sess
, &mut hir_forest
);
130 // run just enough stuff to build a tcx:
131 let lang_items
= lang_items
::collect_language_items(&sess
, &ast_map
);
132 let resolve
::CrateMap { def_map, freevars, .. }
=
133 resolve
::resolve_crate(&sess
, &ast_map
, resolve
::MakeGlobMap
::No
);
134 let named_region_map
= resolve_lifetime
::krate(&sess
, &ast_map
, &def_map
.borrow());
135 let region_map
= region
::resolve_crate(&sess
, &ast_map
);
136 let index
= stability
::Index
::new(&ast_map
);
137 TyCtxt
::create_and_enter(&sess
,
140 named_region_map
.unwrap(),
148 let infcx
= infer
::new_infer_ctxt(tcx
,
151 ProjectionMode
::AnyFinal
);
152 body(Env { infcx: &infcx }
);
153 let free_regions
= FreeRegionMap
::new();
154 infcx
.resolve_regions_and_report_errors(&free_regions
,
156 assert_eq
!(tcx
.sess
.err_count(), expected_err_count
);
160 impl<'a
, 'tcx
> Env
<'a
, 'tcx
> {
161 pub fn tcx(&self) -> &TyCtxt
<'tcx
> {
165 pub fn create_region_hierarchy(&self, rh
: &RH
, parent
: CodeExtent
) {
166 let me
= self.infcx
.tcx
.region_maps
.intern_node(rh
.id
, parent
);
167 for child_rh
in rh
.sub
{
168 self.create_region_hierarchy(child_rh
, me
);
172 pub fn create_simple_region_hierarchy(&self) {
173 // creates a region hierarchy where 1 is root, 10 and 11 are
174 // children of 1, etc
175 let dscope
= self.infcx
178 .intern_code_extent(CodeExtentData
::DestructionScope(1),
179 region
::ROOT_CODE_EXTENT
);
180 self.create_region_hierarchy(&RH
{
182 sub
: &[RH { id: 10, sub: &[] }
, RH { id: 11, sub: &[] }
],
187 #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
188 pub fn lookup_item(&self, names
: &[String
]) -> ast
::NodeId
{
189 return match search_mod(self, &self.infcx
.tcx
.map
.krate().module
, 0, names
) {
192 panic
!("no item found: `{}`", names
.join("::"));
196 fn search_mod(this
: &Env
,
200 -> Option
<ast
::NodeId
> {
201 assert
!(idx
< names
.len());
202 for item
in &m
.item_ids
{
203 let item
= this
.infcx
.tcx
.map
.expect_item(item
.id
);
204 if item
.name
.to_string() == names
[idx
] {
205 return search(this
, item
, idx
+ 1, names
);
211 fn search(this
: &Env
, it
: &hir
::Item
, idx
: usize, names
: &[String
]) -> Option
<ast
::NodeId
> {
212 if idx
== names
.len() {
216 return match it
.node
{
218 hir
::ItemExternCrate(..) |
220 hir
::ItemStatic(..) |
222 hir
::ItemForeignMod(..) |
228 hir
::ItemStruct(..) |
231 hir
::ItemDefaultImpl(..) => {
235 hir
::ItemMod(ref m
) => {
236 search_mod(this
, m
, idx
, names
)
242 pub fn make_subtype(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> bool
{
243 match infer
::mk_subty(self.infcx
, true, TypeOrigin
::Misc(DUMMY_SP
), a
, b
) {
245 Err(ref e
) => panic
!("Encountered error: {}", e
),
249 pub fn is_subtype(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> bool
{
250 match infer
::can_mk_subty(self.infcx
, a
, b
) {
256 pub fn assert_subtype(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) {
257 if !self.is_subtype(a
, b
) {
258 panic
!("{} is not a subtype of {}, but it should be", a
, b
);
262 pub fn assert_eq(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) {
263 self.assert_subtype(a
, b
);
264 self.assert_subtype(b
, a
);
267 pub fn t_fn(&self, input_tys
: &[Ty
<'tcx
>], output_ty
: Ty
<'tcx
>) -> Ty
<'tcx
> {
268 let input_args
= input_tys
.iter().cloned().collect();
269 self.infcx
.tcx
.mk_fn_ptr(ty
::BareFnTy
{
270 unsafety
: hir
::Unsafety
::Normal
,
272 sig
: ty
::Binder(ty
::FnSig
{
274 output
: ty
::FnConverging(output_ty
),
280 pub fn t_nil(&self) -> Ty
<'tcx
> {
281 self.infcx
.tcx
.mk_nil()
284 pub fn t_pair(&self, ty1
: Ty
<'tcx
>, ty2
: Ty
<'tcx
>) -> Ty
<'tcx
> {
285 self.infcx
.tcx
.mk_tup(vec
![ty1
, ty2
])
288 pub fn t_param(&self, space
: subst
::ParamSpace
, index
: u32) -> Ty
<'tcx
> {
289 let name
= format
!("T{}", index
);
290 self.infcx
.tcx
.mk_param(space
, index
, token
::intern(&name
[..]))
293 pub fn re_early_bound(&self,
294 space
: subst
::ParamSpace
,
298 let name
= token
::intern(name
);
299 ty
::ReEarlyBound(ty
::EarlyBoundRegion
{
306 pub fn re_late_bound_with_debruijn(&self, id
: u32, debruijn
: ty
::DebruijnIndex
) -> ty
::Region
{
307 ty
::ReLateBound(debruijn
, ty
::BrAnon(id
))
310 pub fn t_rptr(&self, r
: ty
::Region
) -> Ty
<'tcx
> {
311 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(r
), self.tcx().types
.isize)
314 pub fn t_rptr_late_bound(&self, id
: u32) -> Ty
<'tcx
> {
315 let r
= self.re_late_bound_with_debruijn(id
, ty
::DebruijnIndex
::new(1));
316 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(r
), self.tcx().types
.isize)
319 pub fn t_rptr_late_bound_with_debruijn(&self,
321 debruijn
: ty
::DebruijnIndex
)
323 let r
= self.re_late_bound_with_debruijn(id
, debruijn
);
324 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(r
), self.tcx().types
.isize)
327 pub fn t_rptr_scope(&self, id
: ast
::NodeId
) -> Ty
<'tcx
> {
328 let r
= ty
::ReScope(self.tcx().region_maps
.node_extent(id
));
329 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(r
), self.tcx().types
.isize)
332 pub fn re_free(&self, nid
: ast
::NodeId
, id
: u32) -> ty
::Region
{
333 ty
::ReFree(ty
::FreeRegion
{
334 scope
: self.tcx().region_maps
.item_extent(nid
),
335 bound_region
: ty
::BrAnon(id
),
339 pub fn t_rptr_free(&self, nid
: ast
::NodeId
, id
: u32) -> Ty
<'tcx
> {
340 let r
= self.re_free(nid
, id
);
341 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(r
), self.tcx().types
.isize)
344 pub fn t_rptr_static(&self) -> Ty
<'tcx
> {
345 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(ty
::ReStatic
),
346 self.tcx().types
.isize)
349 pub fn t_rptr_empty(&self) -> Ty
<'tcx
> {
350 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(ty
::ReEmpty
),
351 self.tcx().types
.isize)
354 pub fn dummy_type_trace(&self) -> infer
::TypeTrace
<'tcx
> {
355 infer
::TypeTrace
::dummy(self.tcx())
358 pub fn sub(&self, t1
: &Ty
<'tcx
>, t2
: &Ty
<'tcx
>) -> InferResult
<'tcx
, Ty
<'tcx
>> {
359 let trace
= self.dummy_type_trace();
360 self.infcx
.sub(true, trace
, t1
, t2
)
363 pub fn lub(&self, t1
: &Ty
<'tcx
>, t2
: &Ty
<'tcx
>) -> InferResult
<'tcx
, Ty
<'tcx
>> {
364 let trace
= self.dummy_type_trace();
365 self.infcx
.lub(true, trace
, t1
, t2
)
368 pub fn glb(&self, t1
: &Ty
<'tcx
>, t2
: &Ty
<'tcx
>) -> InferResult
<'tcx
, Ty
<'tcx
>> {
369 let trace
= self.dummy_type_trace();
370 self.infcx
.glb(true, trace
, t1
, t2
)
373 /// Checks that `t1 <: t2` is true (this may register additional
375 pub fn check_sub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) {
376 match self.sub(&t1
, &t2
) {
377 Ok(InferOk { obligations, .. }
) => {
378 // FIXME(#32730) once obligations are being propagated, assert the right thing.
379 assert
!(obligations
.is_empty());
382 panic
!("unexpected error computing sub({:?},{:?}): {}", t1
, t2
, e
);
387 /// Checks that `t1 <: t2` is false (this may register additional
389 pub fn check_not_sub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) {
390 match self.sub(&t1
, &t2
) {
393 panic
!("unexpected success computing sub({:?},{:?})", t1
, t2
);
398 /// Checks that `LUB(t1,t2) == t_lub`
399 pub fn check_lub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>, t_lub
: Ty
<'tcx
>) {
400 match self.lub(&t1
, &t2
) {
401 Ok(InferOk { obligations, value: t }
) => {
402 // FIXME(#32730) once obligations are being propagated, assert the right thing.
403 assert
!(obligations
.is_empty());
405 self.assert_eq(t
, t_lub
);
408 panic
!("unexpected error in LUB: {}", e
)
413 /// Checks that `GLB(t1,t2) == t_glb`
414 pub fn check_glb(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>, t_glb
: Ty
<'tcx
>) {
415 debug
!("check_glb(t1={}, t2={}, t_glb={})", t1
, t2
, t_glb
);
416 match self.glb(&t1
, &t2
) {
418 panic
!("unexpected error computing LUB: {:?}", e
)
420 Ok(InferOk { obligations, value: t }
) => {
421 // FIXME(#32730) once obligations are being propagated, assert the right thing.
422 assert
!(obligations
.is_empty());
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
, errors(&["lifetime mismatch"]), |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
);
455 // will cause an error when regions are resolved
456 env
.make_subtype(t_rptr10
, t_rptr1
);
461 fn sub_free_bound_false() {
464 //! fn(&'a isize) <: for<'b> fn(&'b isize)
468 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
469 env
.create_simple_region_hierarchy();
470 let t_rptr_free1
= env
.t_rptr_free(1, 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));
478 fn sub_bound_free_true() {
481 //! for<'a> fn(&'a isize) <: fn(&'b isize)
485 test_env(EMPTY_SOURCE_STR
, errors(&[]), |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, 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 env
.create_simple_region_hierarchy();
522 let t_infer1
= env
.infcx
.next_ty_var();
523 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
524 let t_rptr_free1
= env
.t_rptr_free(1, 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));
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));
543 fn lub_bound_free() {
544 test_env(EMPTY_SOURCE_STR
, errors(&[]), |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, 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));
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));
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
));
578 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
579 env
.create_simple_region_hierarchy();
580 let t_rptr_free1
= env
.t_rptr_free(1, 1);
581 let t_rptr_free2
= env
.t_rptr_free(1, 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));
590 fn lub_returning_scope() {
591 test_env(EMPTY_SOURCE_STR
, errors(&[]), |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));
603 fn glb_free_free_with_common_scope() {
604 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
605 env
.create_simple_region_hierarchy();
606 let t_rptr_free1
= env
.t_rptr_free(1, 1);
607 let t_rptr_free2
= env
.t_rptr_free(1, 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));
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));
627 fn glb_bound_free() {
628 test_env(EMPTY_SOURCE_STR
, errors(&[]), |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, 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));
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();
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));
650 // as a side-effect, computing GLB should unify `_` with
652 let t_resolve1
= env
.infcx
.shallow_resolve(t_infer1
);
653 match t_resolve1
.sty
{
656 panic
!("t_resolve1={:?}", t_resolve1
);
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));
673 /// Test substituting a bound region into a function, which introduces another level of binding.
674 /// This requires adjusting the Debruijn index.
676 fn subst_ty_renumber_bound() {
678 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
680 // Theta = [A -> &'a foo]
682 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
686 let t_param
= env
.t_param(subst
::TypeSpace
, 0);
687 env
.t_fn(&[t_param
], env
.t_nil())
690 let substs
= subst
::Substs
::new_type(vec
![t_rptr_bound1
], vec
![]);
691 let t_substituted
= t_source
.subst(env
.infcx
.tcx
, &substs
);
693 // t_expected = fn(&'a isize)
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())
699 debug
!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
705 assert_eq
!(t_substituted
, t_expected
);
709 /// Test substituting a bound region into a function, which introduces another level of binding.
710 /// This requires adjusting the Debruijn index.
712 fn subst_ty_renumber_some_bounds() {
713 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
715 // Theta = [A -> &'a foo]
717 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
719 // t_source = (A, fn(A))
721 let t_param
= env
.t_param(subst
::TypeSpace
, 0);
722 env
.t_pair(t_param
, env
.t_fn(&[t_param
], env
.t_nil()))
725 let substs
= subst
::Substs
::new_type(vec
![t_rptr_bound1
], vec
![]);
726 let t_substituted
= t_source
.subst(env
.infcx
.tcx
, &substs
);
728 // t_expected = (&'a isize, fn(&'a isize))
730 // but not that the Debruijn index is different in the different cases.
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()))
736 debug
!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
742 assert_eq
!(t_substituted
, t_expected
);
746 /// Test that we correctly compute whether a type has escaping regions or not.
750 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
752 // Theta = [A -> &'a foo]
753 env
.create_simple_region_hierarchy();
755 assert
!(!env
.t_nil().has_escaping_regions());
757 let t_rptr_free1
= env
.t_rptr_free(1, 1);
758 assert
!(!t_rptr_free1
.has_escaping_regions());
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());
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());
767 let t_param
= env
.t_param(subst
::TypeSpace
, 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());
774 /// Test applying a substitution where the value being substituted for an early-bound region is a
775 /// late-bound region.
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));
781 // type t_source<'a> = fn(&'a isize)
783 let re_early
= env
.re_early_bound(subst
::TypeSpace
, 0, "'a");
784 env
.t_fn(&[env
.t_rptr(re_early
)], env
.t_nil())
787 let substs
= subst
::Substs
::new_type(vec
![], vec
![re_bound1
]);
788 let t_substituted
= t_source
.subst(env
.infcx
.tcx
, &substs
);
790 // t_expected = fn(&'a isize)
792 // but not that the Debruijn index is different in the different cases.
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())
798 debug
!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
804 assert_eq
!(t_substituted
, t_expected
);
810 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
811 let tcx
= env
.infcx
.tcx
;
812 let int_ty
= tcx
.types
.isize;
813 let uint_ty
= tcx
.types
.usize;
814 let tup1_ty
= tcx
.mk_tup(vec
![int_ty
, uint_ty
, int_ty
, uint_ty
]);
815 let tup2_ty
= tcx
.mk_tup(vec
![tup1_ty
, tup1_ty
, uint_ty
]);
816 let uniq_ty
= tcx
.mk_box(tup2_ty
);
817 let walked
: Vec
<_
> = uniq_ty
.walk().collect();
819 [uniq_ty
, tup2_ty
, tup1_ty
, int_ty
, uint_ty
, int_ty
, uint_ty
, tup1_ty
, int_ty
,
820 uint_ty
, int_ty
, uint_ty
, uint_ty
]);
825 fn walk_ty_skip_subtree() {
826 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
827 let tcx
= env
.infcx
.tcx
;
828 let int_ty
= tcx
.types
.isize;
829 let uint_ty
= tcx
.types
.usize;
830 let tup1_ty
= tcx
.mk_tup(vec
![int_ty
, uint_ty
, int_ty
, uint_ty
]);
831 let tup2_ty
= tcx
.mk_tup(vec
![tup1_ty
, tup1_ty
, uint_ty
]);
832 let uniq_ty
= tcx
.mk_box(tup2_ty
);
834 // types we expect to see (in order), plus a boolean saying
835 // whether to skip the subtree.
836 let mut expected
= vec
![(uniq_ty
, false),
843 (tup1_ty
, true), // skip the isize/usize/isize/usize
847 let mut walker
= uniq_ty
.walk();
848 while let Some(t
) = walker
.next() {
849 debug
!("walked to {:?}", t
);
850 let (expected_ty
, skip
) = expected
.pop().unwrap();
851 assert_eq
!(t
, expected_ty
);
853 walker
.skip_current_subtree();
857 assert
!(expected
.is_empty());