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
::MakeGlobMap
;
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
;
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
::session
::{self, config}
;
34 use syntax
::codemap
::CodeMap
;
36 use errors
::emitter
::Emitter
;
37 use errors
::{Level, DiagnosticBuilder}
;
38 use syntax
::feature_gate
::UnstableFeatures
;
39 use syntax
::symbol
::Symbol
;
40 use syntax_pos
::DUMMY_SP
;
44 struct Env
<'a
, 'gcx
: 'a
+ 'tcx
, 'tcx
: 'a
> {
45 infcx
: &'a infer
::InferCtxt
<'a
, 'gcx
, 'tcx
>,
53 const EMPTY_SOURCE_STR
: &'
static str = "#![feature(no_core)] #![no_core]";
55 struct ExpectErrorEmitter
{
56 messages
: Vec
<String
>,
59 fn remove_message(e
: &mut ExpectErrorEmitter
, msg
: &str, lvl
: Level
) {
61 Level
::Bug
| Level
::Fatal
| Level
::Error
=> {}
67 debug
!("Error: {}", msg
);
68 match e
.messages
.iter().position(|m
| msg
.contains(m
)) {
73 debug
!("Unexpected error: {} Expected: {:?}", msg
, e
.messages
);
74 panic
!("Unexpected error: {} Expected: {:?}", msg
, e
.messages
);
79 impl Emitter
for ExpectErrorEmitter
{
80 fn emit(&mut self, db
: &DiagnosticBuilder
) {
81 remove_message(self, &db
.message
, db
.level
);
82 for child
in &db
.children
{
83 remove_message(self, &child
.message
, child
.level
);
88 fn errors(msgs
: &[&str]) -> (Box
<Emitter
+ Send
>, usize) {
89 let v
= msgs
.iter().map(|m
| m
.to_string()).collect();
90 (box ExpectErrorEmitter { messages: v }
as Box
<Emitter
+ Send
>, msgs
.len())
93 fn test_env
<F
>(source_string
: &str,
94 (emitter
, expected_err_count
): (Box
<Emitter
+ Send
>, usize),
98 let mut options
= config
::basic_options();
99 options
.debugging_opts
.verbose
= true;
100 options
.unstable_features
= UnstableFeatures
::Allow
;
101 let diagnostic_handler
= errors
::Handler
::with_emitter(true, false, emitter
);
103 let dep_graph
= DepGraph
::new(false);
104 let _ignore
= dep_graph
.in_ignore();
105 let cstore
= Rc
::new(CStore
::new(&dep_graph
));
106 let sess
= session
::build_session_(options
,
110 Rc
::new(CodeMap
::new()),
112 rustc_lint
::register_builtins(&mut sess
.lint_store
.borrow_mut(), Some(&sess
));
113 let input
= config
::Input
::Str
{
114 name
: driver
::anon_src(),
115 input
: source_string
.to_string(),
117 let krate
= driver
::phase_1_parse_input(&sess
, &input
).unwrap();
118 let driver
::ExpansionResult { defs, resolutions, mut hir_forest, .. }
= {
119 driver
::phase_2_configure_and_expand(&sess
,
127 .expect("phase 2 aborted")
129 let _ignore
= dep_graph
.in_ignore();
131 let arenas
= ty
::CtxtArenas
::new();
132 let ast_map
= hir_map
::map_crate(&mut hir_forest
, defs
);
134 // run just enough stuff to build a tcx:
135 let lang_items
= lang_items
::collect_language_items(&sess
, &ast_map
);
136 let named_region_map
= resolve_lifetime
::krate(&sess
, &ast_map
);
137 let region_map
= region
::resolve_crate(&sess
, &ast_map
);
138 let index
= stability
::Index
::new(&ast_map
);
139 TyCtxt
::create_and_enter(&sess
,
141 resolutions
.trait_map
,
142 named_region_map
.unwrap(),
144 resolutions
.freevars
,
145 resolutions
.maybe_unused_trait_imports
,
151 tcx
.infer_ctxt(None
, None
, Reveal
::NotSpecializable
).enter(|infcx
| {
153 body(Env { infcx: &infcx }
);
154 let free_regions
= FreeRegionMap
::new();
155 infcx
.resolve_regions_and_report_errors(&free_regions
, ast
::CRATE_NODE_ID
);
156 assert_eq
!(tcx
.sess
.err_count(), expected_err_count
);
161 impl<'a
, 'gcx
, 'tcx
> Env
<'a
, 'gcx
, 'tcx
> {
162 pub fn tcx(&self) -> TyCtxt
<'a
, 'gcx
, 'tcx
> {
166 pub fn create_region_hierarchy(&self, rh
: &RH
, parent
: CodeExtent
) {
167 let me
= self.infcx
.tcx
.region_maps
.intern_node(rh
.id
, parent
);
168 for child_rh
in rh
.sub
{
169 self.create_region_hierarchy(child_rh
, me
);
173 pub fn create_simple_region_hierarchy(&self) {
174 // creates a region hierarchy where 1 is root, 10 and 11 are
175 // children of 1, etc
177 let node
= ast
::NodeId
::from_u32
;
178 let dscope
= self.infcx
181 .intern_code_extent(CodeExtentData
::DestructionScope(node(1)),
182 region
::ROOT_CODE_EXTENT
);
183 self.create_region_hierarchy(&RH
{
197 #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
198 pub fn lookup_item(&self, names
: &[String
]) -> ast
::NodeId
{
199 return match search_mod(self, &self.infcx
.tcx
.map
.krate().module
, 0, names
) {
202 panic
!("no item found: `{}`", names
.join("::"));
206 fn search_mod(this
: &Env
,
210 -> Option
<ast
::NodeId
> {
211 assert
!(idx
< names
.len());
212 for item
in &m
.item_ids
{
213 let item
= this
.infcx
.tcx
.map
.expect_item(item
.id
);
214 if item
.name
.to_string() == names
[idx
] {
215 return search(this
, item
, idx
+ 1, names
);
221 fn search(this
: &Env
, it
: &hir
::Item
, idx
: usize, names
: &[String
]) -> Option
<ast
::NodeId
> {
222 if idx
== names
.len() {
226 return match it
.node
{
228 hir
::ItemExternCrate(..) |
230 hir
::ItemStatic(..) |
232 hir
::ItemForeignMod(..) |
233 hir
::ItemTy(..) => None
,
236 hir
::ItemStruct(..) |
240 hir
::ItemDefaultImpl(..) => None
,
242 hir
::ItemMod(ref m
) => search_mod(this
, m
, idx
, names
),
247 pub fn make_subtype(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> bool
{
248 match self.infcx
.sub_types(true, &ObligationCause
::dummy(), a
, b
) {
250 Err(ref e
) => panic
!("Encountered error: {}", e
),
254 pub fn is_subtype(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) -> bool
{
255 self.infcx
.can_sub_types(a
, b
).is_ok()
258 pub fn assert_subtype(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) {
259 if !self.is_subtype(a
, b
) {
260 panic
!("{} is not a subtype of {}, but it should be", a
, b
);
264 pub fn assert_eq(&self, a
: Ty
<'tcx
>, b
: Ty
<'tcx
>) {
265 self.assert_subtype(a
, b
);
266 self.assert_subtype(b
, a
);
269 pub fn t_fn(&self, input_tys
: &[Ty
<'tcx
>], output_ty
: Ty
<'tcx
>) -> Ty
<'tcx
> {
270 self.infcx
.tcx
.mk_fn_ptr(self.infcx
.tcx
.mk_bare_fn(ty
::BareFnTy
{
271 unsafety
: hir
::Unsafety
::Normal
,
273 sig
: ty
::Binder(self.infcx
.tcx
.mk_fn_sig(input_tys
.iter().cloned(), output_ty
, false)),
277 pub fn t_nil(&self) -> Ty
<'tcx
> {
278 self.infcx
.tcx
.mk_nil()
281 pub fn t_pair(&self, ty1
: Ty
<'tcx
>, ty2
: Ty
<'tcx
>) -> Ty
<'tcx
> {
282 self.infcx
.tcx
.intern_tup(&[ty1
, ty2
])
285 pub fn t_param(&self, index
: u32) -> Ty
<'tcx
> {
286 let name
= format
!("T{}", index
);
287 self.infcx
.tcx
.mk_param(index
, Symbol
::intern(&name
[..]))
290 pub fn re_early_bound(&self, index
: u32, name
: &'
static str) -> &'tcx ty
::Region
{
291 let name
= Symbol
::intern(name
);
292 self.infcx
.tcx
.mk_region(ty
::ReEarlyBound(ty
::EarlyBoundRegion
{
298 pub fn re_late_bound_with_debruijn(&self,
300 debruijn
: ty
::DebruijnIndex
)
301 -> &'tcx ty
::Region
{
302 self.infcx
.tcx
.mk_region(ty
::ReLateBound(debruijn
, ty
::BrAnon(id
)))
305 pub fn t_rptr(&self, r
: &'tcx ty
::Region
) -> Ty
<'tcx
> {
306 self.infcx
.tcx
.mk_imm_ref(r
, self.tcx().types
.isize)
309 pub fn t_rptr_late_bound(&self, id
: u32) -> Ty
<'tcx
> {
310 let r
= self.re_late_bound_with_debruijn(id
, ty
::DebruijnIndex
::new(1));
311 self.infcx
.tcx
.mk_imm_ref(r
, self.tcx().types
.isize)
314 pub fn t_rptr_late_bound_with_debruijn(&self,
316 debruijn
: ty
::DebruijnIndex
)
318 let r
= self.re_late_bound_with_debruijn(id
, debruijn
);
319 self.infcx
.tcx
.mk_imm_ref(r
, self.tcx().types
.isize)
322 pub fn t_rptr_scope(&self, id
: u32) -> Ty
<'tcx
> {
323 let r
= ty
::ReScope(self.tcx().region_maps
.node_extent(ast
::NodeId
::from_u32(id
)));
324 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(r
), self.tcx().types
.isize)
327 pub fn re_free(&self, nid
: ast
::NodeId
, id
: u32) -> &'tcx ty
::Region
{
328 self.infcx
.tcx
.mk_region(ty
::ReFree(ty
::FreeRegion
{
329 scope
: self.tcx().region_maps
.item_extent(nid
),
330 bound_region
: ty
::BrAnon(id
),
334 pub fn t_rptr_free(&self, nid
: u32, id
: u32) -> Ty
<'tcx
> {
335 let r
= self.re_free(ast
::NodeId
::from_u32(nid
), id
);
336 self.infcx
.tcx
.mk_imm_ref(r
, self.tcx().types
.isize)
339 pub fn t_rptr_static(&self) -> Ty
<'tcx
> {
340 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(ty
::ReStatic
),
341 self.tcx().types
.isize)
344 pub fn t_rptr_empty(&self) -> Ty
<'tcx
> {
345 self.infcx
.tcx
.mk_imm_ref(self.infcx
.tcx
.mk_region(ty
::ReEmpty
),
346 self.tcx().types
.isize)
349 pub fn dummy_type_trace(&self) -> infer
::TypeTrace
<'tcx
> {
350 infer
::TypeTrace
::dummy(self.tcx())
353 pub fn sub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) -> InferResult
<'tcx
, Ty
<'tcx
>> {
354 let trace
= self.dummy_type_trace();
355 self.infcx
.sub(true, trace
, &t1
, &t2
)
358 pub fn lub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) -> InferResult
<'tcx
, Ty
<'tcx
>> {
359 let trace
= self.dummy_type_trace();
360 self.infcx
.lub(true, trace
, &t1
, &t2
)
363 pub fn glb(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) -> InferResult
<'tcx
, Ty
<'tcx
>> {
364 let trace
= self.dummy_type_trace();
365 self.infcx
.glb(true, trace
, &t1
, &t2
)
368 /// Checks that `t1 <: t2` is true (this may register additional
370 pub fn check_sub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) {
371 match self.sub(t1
, t2
) {
372 Ok(InferOk { obligations, .. }
) => {
373 // FIXME(#32730) once obligations are being propagated, assert the right thing.
374 assert
!(obligations
.is_empty());
377 panic
!("unexpected error computing sub({:?},{:?}): {}", t1
, t2
, e
);
382 /// Checks that `t1 <: t2` is false (this may register additional
384 pub fn check_not_sub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>) {
385 match self.sub(t1
, t2
) {
388 panic
!("unexpected success computing sub({:?},{:?})", t1
, t2
);
393 /// Checks that `LUB(t1,t2) == t_lub`
394 pub fn check_lub(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>, t_lub
: Ty
<'tcx
>) {
395 match self.lub(t1
, t2
) {
396 Ok(InferOk { obligations, value: t }
) => {
397 // FIXME(#32730) once obligations are being propagated, assert the right thing.
398 assert
!(obligations
.is_empty());
400 self.assert_eq(t
, t_lub
);
402 Err(ref e
) => panic
!("unexpected error in LUB: {}", e
),
406 /// Checks that `GLB(t1,t2) == t_glb`
407 pub fn check_glb(&self, t1
: Ty
<'tcx
>, t2
: Ty
<'tcx
>, t_glb
: Ty
<'tcx
>) {
408 debug
!("check_glb(t1={}, t2={}, t_glb={})", t1
, t2
, t_glb
);
409 match self.glb(t1
, t2
) {
410 Err(e
) => panic
!("unexpected error computing LUB: {:?}", e
),
411 Ok(InferOk { obligations, value: t }
) => {
412 // FIXME(#32730) once obligations are being propagated, assert the right thing.
413 assert
!(obligations
.is_empty());
415 self.assert_eq(t
, t_glb
);
417 // sanity check for good measure:
418 self.assert_subtype(t
, t1
);
419 self.assert_subtype(t
, t2
);
426 fn contravariant_region_ptr_ok() {
427 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
428 env
.create_simple_region_hierarchy();
429 let t_rptr1
= env
.t_rptr_scope(1);
430 let t_rptr10
= env
.t_rptr_scope(10);
431 env
.assert_eq(t_rptr1
, t_rptr1
);
432 env
.assert_eq(t_rptr10
, t_rptr10
);
433 env
.make_subtype(t_rptr1
, t_rptr10
);
438 fn contravariant_region_ptr_err() {
439 test_env(EMPTY_SOURCE_STR
, errors(&["mismatched types"]), |env
| {
440 env
.create_simple_region_hierarchy();
441 let t_rptr1
= env
.t_rptr_scope(1);
442 let t_rptr10
= env
.t_rptr_scope(10);
443 env
.assert_eq(t_rptr1
, t_rptr1
);
444 env
.assert_eq(t_rptr10
, t_rptr10
);
446 // will cause an error when regions are resolved
447 env
.make_subtype(t_rptr10
, t_rptr1
);
452 fn sub_free_bound_false() {
455 //! fn(&'a isize) <: for<'b> fn(&'b isize)
459 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
460 env
.create_simple_region_hierarchy();
461 let t_rptr_free1
= env
.t_rptr_free(1, 1);
462 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
463 env
.check_not_sub(env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
464 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
469 fn sub_bound_free_true() {
472 //! for<'a> fn(&'a isize) <: fn(&'b isize)
476 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
477 env
.create_simple_region_hierarchy();
478 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
479 let t_rptr_free1
= env
.t_rptr_free(1, 1);
480 env
.check_sub(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
481 env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize));
486 fn sub_free_bound_false_infer() {
489 //! fn(_#1) <: for<'b> fn(&'b isize)
491 //! does NOT hold for any instantiation of `_#1`.
493 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
494 let t_infer1
= env
.infcx
.next_ty_var(TypeVariableOrigin
::MiscVariable(DUMMY_SP
));
495 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
496 env
.check_not_sub(env
.t_fn(&[t_infer1
], env
.tcx().types
.isize),
497 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
502 fn lub_free_bound_infer() {
505 //! LUB(fn(_#1), for<'b> fn(&'b isize))
507 //! This should yield `fn(&'_ isize)`. We check
508 //! that it yields `fn(&'x isize)` for some free `'x`,
511 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
512 env
.create_simple_region_hierarchy();
513 let t_infer1
= env
.infcx
.next_ty_var(TypeVariableOrigin
::MiscVariable(DUMMY_SP
));
514 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
515 let t_rptr_free1
= env
.t_rptr_free(1, 1);
516 env
.check_lub(env
.t_fn(&[t_infer1
], env
.tcx().types
.isize),
517 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
518 env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize));
523 fn lub_bound_bound() {
524 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
525 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
526 let t_rptr_bound2
= env
.t_rptr_late_bound(2);
527 env
.check_lub(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
528 env
.t_fn(&[t_rptr_bound2
], env
.tcx().types
.isize),
529 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
534 fn lub_bound_free() {
535 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
536 env
.create_simple_region_hierarchy();
537 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
538 let t_rptr_free1
= env
.t_rptr_free(1, 1);
539 env
.check_lub(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
540 env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
541 env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize));
546 fn lub_bound_static() {
547 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
548 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
549 let t_rptr_static
= env
.t_rptr_static();
550 env
.check_lub(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
551 env
.t_fn(&[t_rptr_static
], env
.tcx().types
.isize),
552 env
.t_fn(&[t_rptr_static
], env
.tcx().types
.isize));
557 fn lub_bound_bound_inverse_order() {
558 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
559 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
560 let t_rptr_bound2
= env
.t_rptr_late_bound(2);
561 env
.check_lub(env
.t_fn(&[t_rptr_bound1
, t_rptr_bound2
], t_rptr_bound1
),
562 env
.t_fn(&[t_rptr_bound2
, t_rptr_bound1
], t_rptr_bound1
),
563 env
.t_fn(&[t_rptr_bound1
, t_rptr_bound1
], t_rptr_bound1
));
569 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
570 env
.create_simple_region_hierarchy();
571 let t_rptr_free1
= env
.t_rptr_free(1, 1);
572 let t_rptr_free2
= env
.t_rptr_free(1, 2);
573 let t_rptr_static
= env
.t_rptr_static();
574 env
.check_lub(env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
575 env
.t_fn(&[t_rptr_free2
], env
.tcx().types
.isize),
576 env
.t_fn(&[t_rptr_static
], env
.tcx().types
.isize));
581 fn lub_returning_scope() {
582 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
583 env
.create_simple_region_hierarchy();
584 let t_rptr_scope10
= env
.t_rptr_scope(10);
585 let t_rptr_scope11
= env
.t_rptr_scope(11);
586 let t_rptr_empty
= env
.t_rptr_empty();
587 env
.check_lub(env
.t_fn(&[t_rptr_scope10
], env
.tcx().types
.isize),
588 env
.t_fn(&[t_rptr_scope11
], env
.tcx().types
.isize),
589 env
.t_fn(&[t_rptr_empty
], env
.tcx().types
.isize));
594 fn glb_free_free_with_common_scope() {
595 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
596 env
.create_simple_region_hierarchy();
597 let t_rptr_free1
= env
.t_rptr_free(1, 1);
598 let t_rptr_free2
= env
.t_rptr_free(1, 2);
599 let t_rptr_scope
= env
.t_rptr_scope(1);
600 env
.check_glb(env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
601 env
.t_fn(&[t_rptr_free2
], env
.tcx().types
.isize),
602 env
.t_fn(&[t_rptr_scope
], env
.tcx().types
.isize));
607 fn glb_bound_bound() {
608 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
609 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
610 let t_rptr_bound2
= env
.t_rptr_late_bound(2);
611 env
.check_glb(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
612 env
.t_fn(&[t_rptr_bound2
], env
.tcx().types
.isize),
613 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
618 fn glb_bound_free() {
619 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
620 env
.create_simple_region_hierarchy();
621 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
622 let t_rptr_free1
= env
.t_rptr_free(1, 1);
623 env
.check_glb(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
624 env
.t_fn(&[t_rptr_free1
], env
.tcx().types
.isize),
625 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
630 fn glb_bound_free_infer() {
631 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
632 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
633 let t_infer1
= env
.infcx
.next_ty_var(TypeVariableOrigin
::MiscVariable(DUMMY_SP
));
635 // compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize),
636 // which should yield for<'b> fn(&'b isize) -> isize
637 env
.check_glb(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
638 env
.t_fn(&[t_infer1
], env
.tcx().types
.isize),
639 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
641 // as a side-effect, computing GLB should unify `_` with
643 let t_resolve1
= env
.infcx
.shallow_resolve(t_infer1
);
644 match t_resolve1
.sty
{
647 panic
!("t_resolve1={:?}", t_resolve1
);
654 fn glb_bound_static() {
655 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
656 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
657 let t_rptr_static
= env
.t_rptr_static();
658 env
.check_glb(env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize),
659 env
.t_fn(&[t_rptr_static
], env
.tcx().types
.isize),
660 env
.t_fn(&[t_rptr_bound1
], env
.tcx().types
.isize));
664 /// Test substituting a bound region into a function, which introduces another level of binding.
665 /// This requires adjusting the Debruijn index.
667 fn subst_ty_renumber_bound() {
669 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
671 // Theta = [A -> &'a foo]
673 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
677 let t_param
= env
.t_param(0);
678 env
.t_fn(&[t_param
], env
.t_nil())
681 let substs
= env
.infcx
.tcx
.intern_substs(&[Kind
::from(t_rptr_bound1
)]);
682 let t_substituted
= t_source
.subst(env
.infcx
.tcx
, substs
);
684 // t_expected = fn(&'a isize)
686 let t_ptr_bound2
= env
.t_rptr_late_bound_with_debruijn(1, ty
::DebruijnIndex
::new(2));
687 env
.t_fn(&[t_ptr_bound2
], env
.t_nil())
690 debug
!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
696 assert_eq
!(t_substituted
, t_expected
);
700 /// Test substituting a bound region into a function, which introduces another level of binding.
701 /// This requires adjusting the Debruijn index.
703 fn subst_ty_renumber_some_bounds() {
704 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
706 // Theta = [A -> &'a foo]
708 let t_rptr_bound1
= env
.t_rptr_late_bound(1);
710 // t_source = (A, fn(A))
712 let t_param
= env
.t_param(0);
713 env
.t_pair(t_param
, env
.t_fn(&[t_param
], env
.t_nil()))
716 let substs
= env
.infcx
.tcx
.intern_substs(&[Kind
::from(t_rptr_bound1
)]);
717 let t_substituted
= t_source
.subst(env
.infcx
.tcx
, substs
);
719 // t_expected = (&'a isize, fn(&'a isize))
721 // but not that the Debruijn index is different in the different cases.
723 let t_rptr_bound2
= env
.t_rptr_late_bound_with_debruijn(1, ty
::DebruijnIndex
::new(2));
724 env
.t_pair(t_rptr_bound1
, env
.t_fn(&[t_rptr_bound2
], env
.t_nil()))
727 debug
!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
733 assert_eq
!(t_substituted
, t_expected
);
737 /// Test that we correctly compute whether a type has escaping regions or not.
741 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
743 // Theta = [A -> &'a foo]
744 env
.create_simple_region_hierarchy();
746 assert
!(!env
.t_nil().has_escaping_regions());
748 let t_rptr_free1
= env
.t_rptr_free(1, 1);
749 assert
!(!t_rptr_free1
.has_escaping_regions());
751 let t_rptr_bound1
= env
.t_rptr_late_bound_with_debruijn(1, ty
::DebruijnIndex
::new(1));
752 assert
!(t_rptr_bound1
.has_escaping_regions());
754 let t_rptr_bound2
= env
.t_rptr_late_bound_with_debruijn(1, ty
::DebruijnIndex
::new(2));
755 assert
!(t_rptr_bound2
.has_escaping_regions());
758 let t_param
= env
.t_param(0);
759 assert
!(!t_param
.has_escaping_regions());
760 let t_fn
= env
.t_fn(&[t_param
], env
.t_nil());
761 assert
!(!t_fn
.has_escaping_regions());
765 /// Test applying a substitution where the value being substituted for an early-bound region is a
766 /// late-bound region.
768 fn subst_region_renumber_region() {
769 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
770 let re_bound1
= env
.re_late_bound_with_debruijn(1, ty
::DebruijnIndex
::new(1));
772 // type t_source<'a> = fn(&'a isize)
774 let re_early
= env
.re_early_bound(0, "'a");
775 env
.t_fn(&[env
.t_rptr(re_early
)], env
.t_nil())
778 let substs
= env
.infcx
.tcx
.intern_substs(&[Kind
::from(re_bound1
)]);
779 let t_substituted
= t_source
.subst(env
.infcx
.tcx
, substs
);
781 // t_expected = fn(&'a isize)
783 // but not that the Debruijn index is different in the different cases.
785 let t_rptr_bound2
= env
.t_rptr_late_bound_with_debruijn(1, ty
::DebruijnIndex
::new(2));
786 env
.t_fn(&[t_rptr_bound2
], env
.t_nil())
789 debug
!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
795 assert_eq
!(t_substituted
, t_expected
);
801 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
802 let tcx
= env
.infcx
.tcx
;
803 let int_ty
= tcx
.types
.isize;
804 let uint_ty
= tcx
.types
.usize;
805 let tup1_ty
= tcx
.intern_tup(&[int_ty
, uint_ty
, int_ty
, uint_ty
]);
806 let tup2_ty
= tcx
.intern_tup(&[tup1_ty
, tup1_ty
, uint_ty
]);
807 let uniq_ty
= tcx
.mk_box(tup2_ty
);
808 let walked
: Vec
<_
> = uniq_ty
.walk().collect();
810 [uniq_ty
, tup2_ty
, tup1_ty
, int_ty
, uint_ty
, int_ty
, uint_ty
, tup1_ty
, int_ty
,
811 uint_ty
, int_ty
, uint_ty
, uint_ty
]);
816 fn walk_ty_skip_subtree() {
817 test_env(EMPTY_SOURCE_STR
, errors(&[]), |env
| {
818 let tcx
= env
.infcx
.tcx
;
819 let int_ty
= tcx
.types
.isize;
820 let uint_ty
= tcx
.types
.usize;
821 let tup1_ty
= tcx
.intern_tup(&[int_ty
, uint_ty
, int_ty
, uint_ty
]);
822 let tup2_ty
= tcx
.intern_tup(&[tup1_ty
, tup1_ty
, uint_ty
]);
823 let uniq_ty
= tcx
.mk_box(tup2_ty
);
825 // types we expect to see (in order), plus a boolean saying
826 // whether to skip the subtree.
827 let mut expected
= vec
![(uniq_ty
, false),
834 (tup1_ty
, true), // skip the isize/usize/isize/usize
838 let mut walker
= uniq_ty
.walk();
839 while let Some(t
) = walker
.next() {
840 debug
!("walked to {:?}", t
);
841 let (expected_ty
, skip
) = expected
.pop().unwrap();
842 assert_eq
!(t
, expected_ty
);
844 walker
.skip_current_subtree();
848 assert
!(expected
.is_empty());