test.rs 29.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

S
Steve Klabnik 已提交
11
//! # Standalone Tests for the Inference Module
12

13 14 15
use diagnostic;
use diagnostic::Emitter;
use driver;
16
use rustc_resolve as resolve;
17
use rustc_typeck::middle::lang_items;
18
use rustc_typeck::middle::region::{self, CodeExtent};
19 20 21 22
use rustc_typeck::middle::resolve_lifetime;
use rustc_typeck::middle::stability;
use rustc_typeck::middle::subst;
use rustc_typeck::middle::subst::Subst;
23
use rustc_typeck::middle::ty::{self, Ty};
24 25 26 27
use rustc_typeck::middle::infer::combine::Combine;
use rustc_typeck::middle::infer;
use rustc_typeck::middle::infer::lub::Lub;
use rustc_typeck::middle::infer::glb::Glb;
28
use rustc_typeck::middle::infer::sub::Sub;
29
use rustc_typeck::util::ppaux::{ty_to_string, Repr, UserString};
30
use rustc::session::{self,config};
31
use syntax::{abi, ast, ast_map};
32 33
use syntax::codemap;
use syntax::codemap::{Span, CodeMap, DUMMY_SP};
P
P1start 已提交
34
use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help};
35
use syntax::parse::token;
36

37 38
struct Env<'a, 'tcx: 'a> {
    infcx: &'a infer::InferCtxt<'a, 'tcx>,
39 40 41 42 43
}

struct RH<'a> {
    id: ast::NodeId,
    sub: &'a [RH<'a>]
44 45
}

46 47 48 49
static EMPTY_SOURCE_STR: &'static str = "#![no_std]";

struct ExpectErrorEmitter {
    messages: Vec<String>
50 51
}

52 53 54
fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
    match lvl {
        Bug | Fatal | Error => { }
P
P1start 已提交
55
        Warning | Note | Help => { return; }
56 57 58 59 60 61 62 63
    }

    debug!("Error: {}", msg);
    match e.messages.iter().position(|m| msg.contains(m.as_slice())) {
        Some(i) => {
            e.messages.remove(i);
        }
        None => {
A
Alex Crichton 已提交
64
            panic!("Unexpected error: {} Expected: {:?}",
65 66 67
                  msg, e.messages);
        }
    }
68 69
}

70 71 72 73
impl Emitter for ExpectErrorEmitter {
    fn emit(&mut self,
            _cmsp: Option<(&codemap::CodeMap, Span)>,
            msg: &str,
74
            _: Option<&str>,
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
            lvl: Level)
    {
        remove_message(self, msg, lvl);
    }

    fn custom_emit(&mut self,
                   _cm: &codemap::CodeMap,
                   _sp: RenderSpan,
                   msg: &str,
                   lvl: Level)
    {
        remove_message(self, msg, lvl);
    }
}

fn errors(msgs: &[&str]) -> (Box<Emitter+Send>, uint) {
91
    let v = msgs.iter().map(|m| m.to_string()).collect();
92 93 94
    (box ExpectErrorEmitter { messages: v } as Box<Emitter+Send>, msgs.len())
}

95 96 97 98 99
fn test_env<F>(source_string: &str,
               (emitter, expected_err_count): (Box<Emitter+Send>, uint),
               body: F) where
    F: FnOnce(Env),
{
100
    let mut options =
101
        config::basic_options();
102
    options.debugging_opts.verbose = true;
103 104 105 106 107 108 109 110 111
    let codemap =
        CodeMap::new();
    let diagnostic_handler =
        diagnostic::mk_handler(emitter);
    let span_diagnostic_handler =
        diagnostic::mk_span_handler(diagnostic_handler, codemap);

    let sess = session::build_session_(options, None, span_diagnostic_handler);
    let krate_config = Vec::new();
112
    let input = config::Input::Str(source_string.to_string());
113
    let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
114 115 116 117 118 119
    let krate = driver::phase_2_configure_and_expand(&sess, krate, "test", None)
                    .expect("phase 2 aborted");

    let mut forest = ast_map::Forest::new(krate);
    let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);
    let krate = ast_map.krate();
120 121

    // run just enough stuff to build a tcx:
122
    let lang_items = lang_items::collect_language_items(krate, &sess);
123
    let resolve::CrateMap { def_map, freevars, capture_mode_map, .. } =
124
        resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
125
    let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
126
    let region_map = region::resolve_crate(&sess, krate);
127
    let stability_index = stability::Index::build(&sess, krate);
128
    let arenas = ty::CtxtArenas::new();
129
    let tcx = ty::mk_ctxt(sess,
130
                          &arenas,
131 132 133
                          def_map,
                          named_region_map,
                          ast_map,
134 135
                          freevars,
                          capture_mode_map,
136 137 138
                          region_map,
                          lang_items,
                          stability_index);
139
    let infcx = infer::new_infer_ctxt(&tcx);
140
    body(Env { infcx: &infcx });
A
Alex Crichton 已提交
141
    infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);
142 143 144
    assert_eq!(tcx.sess.err_count(), expected_err_count);
}

145
impl<'a, 'tcx> Env<'a, 'tcx> {
146 147 148 149
    pub fn tcx(&self) -> &ty::ctxt<'tcx> {
        self.infcx.tcx
    }

150
    pub fn create_region_hierarchy(&self, rh: &RH) {
D
Daniel Micay 已提交
151
        for child_rh in rh.sub.iter() {
152
            self.create_region_hierarchy(child_rh);
153 154 155
            self.infcx.tcx.region_maps.record_encl_scope(
                CodeExtent::from_node_id(child_rh.id),
                CodeExtent::from_node_id(rh.id));
156 157 158
        }
    }

159
    pub fn create_simple_region_hierarchy(&self) {
160 161 162 163 164 165 166 167 168 169
        // creates a region hierarchy where 1 is root, 10 and 11 are
        // children of 1, etc
        self.create_region_hierarchy(
            &RH {id: 1,
                 sub: &[RH {id: 10,
                            sub: &[]},
                        RH {id: 11,
                            sub: &[]}]});
    }

170
    #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
171
    pub fn lookup_item(&self, names: &[String]) -> ast::NodeId {
172
        return match search_mod(self, &self.infcx.tcx.map.krate().module, 0, names) {
173 174
            Some(id) => id,
            None => {
S
Steve Klabnik 已提交
175
                panic!("no item found: `{}`", names.connect("::"));
176 177 178
            }
        };

179
        fn search_mod(this: &Env,
180
                      m: &ast::Mod,
181
                      idx: uint,
182 183
                      names: &[String])
                      -> Option<ast::NodeId> {
P
Patrick Walton 已提交
184
            assert!(idx < names.len());
D
Daniel Micay 已提交
185
            for item in m.items.iter() {
186
                if item.ident.user_string(this.infcx.tcx) == names[idx] {
187
                    return search(this, &**item, idx+1, names);
188 189 190 191 192
                }
            }
            return None;
        }

193 194
        fn search(this: &Env,
                  it: &ast::Item,
195
                  idx: uint,
196 197
                  names: &[String])
                  -> Option<ast::NodeId> {
198 199 200 201 202
            if idx == names.len() {
                return Some(it.id);
            }

            return match it.node {
203
                ast::ItemUse(..) | ast::ItemExternCrate(..) |
204
                ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemFn(..) |
205
                ast::ItemForeignMod(..) | ast::ItemTy(..) => {
206 207 208
                    None
                }

209 210 211
                ast::ItemEnum(..) | ast::ItemStruct(..) |
                ast::ItemTrait(..) | ast::ItemImpl(..) |
                ast::ItemMac(..) => {
212 213 214
                    None
                }

215
                ast::ItemMod(ref m) => {
216
                    search_mod(this, m, idx, names)
217 218 219 220 221
                }
            };
        }
    }

222
    pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
223 224
        match infer::mk_subty(self.infcx, true, infer::Misc(DUMMY_SP), a, b) {
            Ok(_) => true,
S
Steve Klabnik 已提交
225
            Err(ref e) => panic!("Encountered error: {}",
226
                                ty::type_err_to_str(self.infcx.tcx, e))
227 228 229
        }
    }

230
    pub fn is_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
231 232 233 234 235 236
        match infer::can_mk_subty(self.infcx, a, b) {
            Ok(_) => true,
            Err(_) => false
        }
    }

237
    pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
238
        if !self.is_subtype(a, b) {
S
Steve Klabnik 已提交
239
            panic!("{} is not a subtype of {}, but it should be",
240 241
                  self.ty_to_string(a),
                  self.ty_to_string(b));
242 243 244
        }
    }

245
    pub fn assert_eq(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
246 247 248 249
        self.assert_subtype(a, b);
        self.assert_subtype(b, a);
    }

250
    pub fn ty_to_string(&self, a: Ty<'tcx>) -> String {
251
        ty_to_string(self.infcx.tcx, a)
252 253
    }

254
    pub fn t_fn(&self,
255 256 257
                input_tys: &[Ty<'tcx>],
                output_ty: Ty<'tcx>)
                -> Ty<'tcx>
258
    {
259 260 261
        let input_args = input_tys.iter().map(|ty| *ty).collect();
        ty::mk_bare_fn(self.infcx.tcx,
                       None,
H
Huon Wilson 已提交
262
                       self.infcx.tcx.mk_bare_fn(ty::BareFnTy {
263 264 265 266 267 268 269
                           unsafety: ast::Unsafety::Normal,
                           abi: abi::Rust,
                           sig: ty::Binder(ty::FnSig {
                               inputs: input_args,
                               output: ty::FnConverging(output_ty),
                               variadic: false
                           })
H
Huon Wilson 已提交
270
                       }))
271 272
    }

273
    pub fn t_nil(&self) -> Ty<'tcx> {
274 275 276
        ty::mk_nil(self.infcx.tcx)
    }

277
    pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> {
278 279 280
        ty::mk_tup(self.infcx.tcx, vec![ty1, ty2])
    }

H
Huon Wilson 已提交
281
    pub fn t_param(&self, space: subst::ParamSpace, index: u32) -> Ty<'tcx> {
282
        let name = format!("T{}", index);
J
Jorge Aparicio 已提交
283
        ty::mk_param(self.infcx.tcx, space, index, token::intern(&name[]))
284 285 286 287
    }

    pub fn re_early_bound(&self,
                          space: subst::ParamSpace,
H
Huon Wilson 已提交
288
                          index: u32,
289 290 291 292 293 294 295
                          name: &'static str)
                          -> ty::Region
    {
        let name = token::intern(name);
        ty::ReEarlyBound(ast::DUMMY_NODE_ID, space, index, name)
    }

H
Huon Wilson 已提交
296
    pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) -> ty::Region {
297 298 299
        ty::ReLateBound(debruijn, ty::BrAnon(id))
    }

300
    pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> {
301 302 303
        ty::mk_imm_rptr(self.infcx.tcx,
                        self.infcx.tcx.mk_region(r),
                        self.tcx().types.int)
304 305
    }

H
Huon Wilson 已提交
306 307
    pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> {
        let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1));
308
        ty::mk_imm_rptr(self.infcx.tcx,
H
Huon Wilson 已提交
309
                        self.infcx.tcx.mk_region(r),
310
                        self.tcx().types.int)
311 312
    }

313
    pub fn t_rptr_late_bound_with_debruijn(&self,
H
Huon Wilson 已提交
314
                                           id: u32,
315 316
                                           debruijn: ty::DebruijnIndex)
                                           -> Ty<'tcx> {
H
Huon Wilson 已提交
317
        let r = self.re_late_bound_with_debruijn(id, debruijn);
318
        ty::mk_imm_rptr(self.infcx.tcx,
H
Huon Wilson 已提交
319
                        self.infcx.tcx.mk_region(r),
320
                        self.tcx().types.int)
321 322
    }

323
    pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
H
Huon Wilson 已提交
324
        let r = ty::ReScope(CodeExtent::from_node_id(id));
325 326
        ty::mk_imm_rptr(self.infcx.tcx, self.infcx.tcx.mk_region(r),
                        self.tcx().types.int)
327 328
    }

H
Huon Wilson 已提交
329
    pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region {
330 331
        ty::ReFree(ty::FreeRegion { scope: CodeExtent::from_node_id(nid),
                                    bound_region: ty::BrAnon(id)})
332 333
    }

H
Huon Wilson 已提交
334 335
    pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> {
        let r = self.re_free(nid, id);
336 337 338
        ty::mk_imm_rptr(self.infcx.tcx,
                        self.infcx.tcx.mk_region(r),
                        self.tcx().types.int)
339 340
    }

341
    pub fn t_rptr_static(&self) -> Ty<'tcx> {
342 343 344
        ty::mk_imm_rptr(self.infcx.tcx,
                        self.infcx.tcx.mk_region(ty::ReStatic),
                        self.tcx().types.int)
345 346
    }

347
    pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
348
        infer::TypeTrace::dummy(self.tcx())
349 350
    }

351 352 353 354 355
    pub fn sub(&self) -> Sub<'a, 'tcx> {
        let trace = self.dummy_type_trace();
        Sub(self.infcx.combine_fields(true, trace))
    }

356
    pub fn lub(&self) -> Lub<'a, 'tcx> {
357 358 359
        let trace = self.dummy_type_trace();
        Lub(self.infcx.combine_fields(true, trace))
    }
360

361
    pub fn glb(&self) -> Glb<'a, 'tcx> {
362 363 364
        let trace = self.dummy_type_trace();
        Glb(self.infcx.combine_fields(true, trace))
    }
365

366
    pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
367 368
        match self.lub().tys(t1, t2) {
            Ok(t) => t,
S
Steve Klabnik 已提交
369
            Err(ref e) => panic!("unexpected error computing LUB: {}",
370
                                ty::type_err_to_str(self.infcx.tcx, e))
371 372 373
        }
    }

374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
    /// Checks that `t1 <: t2` is true (this may register additional
    /// region checks).
    pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
        match self.sub().tys(t1, t2) {
            Ok(_) => { }
            Err(ref e) => {
                panic!("unexpected error computing sub({},{}): {}",
                       t1.repr(self.infcx.tcx),
                       t2.repr(self.infcx.tcx),
                       ty::type_err_to_str(self.infcx.tcx, e));
            }
        }
    }

    /// Checks that `t1 <: t2` is false (this may register additional
    /// region checks).
    pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
        match self.sub().tys(t1, t2) {
            Err(_) => { }
            Ok(_) => {
                panic!("unexpected success computing sub({},{})",
                       t1.repr(self.infcx.tcx),
                       t2.repr(self.infcx.tcx));
            }
        }
    }

401
    /// Checks that `LUB(t1,t2) == t_lub`
402
    pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
403 404 405
        match self.lub().tys(t1, t2) {
            Ok(t) => {
                self.assert_eq(t, t_lub);
406 407
            }
            Err(ref e) => {
S
Steve Klabnik 已提交
408
                panic!("unexpected error in LUB: {}",
409
                      ty::type_err_to_str(self.infcx.tcx, e))
410 411 412 413 414
            }
        }
    }

    /// Checks that `GLB(t1,t2) == t_glb`
415
    pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
416
        debug!("check_glb(t1={}, t2={}, t_glb={})",
417 418 419
               self.ty_to_string(t1),
               self.ty_to_string(t2),
               self.ty_to_string(t_glb));
420 421
        match self.glb().tys(t1, t2) {
            Err(e) => {
A
Alex Crichton 已提交
422
                panic!("unexpected error computing LUB: {:?}", e)
423 424 425 426 427 428 429
            }
            Ok(t) => {
                self.assert_eq(t, t_glb);

                // sanity check for good measure:
                self.assert_subtype(t, t1);
                self.assert_subtype(t, t2);
430 431 432 433 434 435
            }
        }
    }
}

#[test]
436
fn contravariant_region_ptr_ok() {
437
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
438 439 440 441 442 443 444 445 446 447 448
        env.create_simple_region_hierarchy();
        let t_rptr1 = env.t_rptr_scope(1);
        let t_rptr10 = env.t_rptr_scope(10);
        env.assert_eq(t_rptr1, t_rptr1);
        env.assert_eq(t_rptr10, t_rptr10);
        env.make_subtype(t_rptr1, t_rptr10);
    })
}

#[test]
fn contravariant_region_ptr_err() {
449
    test_env(EMPTY_SOURCE_STR,
N
Nick Cameron 已提交
450
             errors(&["lifetime mismatch"]),
451 452 453 454 455 456 457 458 459 460
             |env| {
                 env.create_simple_region_hierarchy();
                 let t_rptr1 = env.t_rptr_scope(1);
                 let t_rptr10 = env.t_rptr_scope(10);
                 env.assert_eq(t_rptr1, t_rptr1);
                 env.assert_eq(t_rptr10, t_rptr10);

                 // will cause an error when regions are resolved
                 env.make_subtype(t_rptr10, t_rptr1);
             })
461 462
}

463 464 465 466 467 468 469 470 471 472 473
#[test]
fn sub_free_bound_false() {
    //! Test that:
    //!
    //!     fn(&'a int) <: for<'b> fn(&'b int)
    //!
    //! does NOT hold.

    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_free1 = env.t_rptr_free(0, 1);
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
474 475
        env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.int),
                          env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
476 477 478 479 480 481 482 483 484 485 486 487 488 489
    })
}

#[test]
fn sub_bound_free_true() {
    //! Test that:
    //!
    //!     for<'a> fn(&'a int) <: fn(&'b int)
    //!
    //! DOES hold.

    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
        let t_rptr_free1 = env.t_rptr_free(0, 1);
490 491
        env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_free1], env.tcx().types.int));
492 493 494 495 496 497 498 499 500 501 502 503 504 505
    })
}

#[test]
fn sub_free_bound_false_infer() {
    //! Test that:
    //!
    //!     fn(_#1) <: for<'b> fn(&'b int)
    //!
    //! does NOT hold for any instantiation of `_#1`.

    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_infer1 = env.infcx.next_ty_var();
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
506 507
        env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.int),
                          env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
508 509 510
    })
}

511 512 513 514 515 516 517 518 519 520 521 522 523 524
#[test]
fn lub_free_bound_infer() {
    //! Test result of:
    //!
    //!     LUB(fn(_#1), for<'b> fn(&'b int))
    //!
    //! This should yield `fn(&'_ int)`. We check
    //! that it yields `fn(&'x int)` for some free `'x`,
    //! anyhow.

    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_infer1 = env.infcx.next_ty_var();
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
        let t_rptr_free1 = env.t_rptr_free(0, 1);
525 526 527
        env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_free1], env.tcx().types.int));
528 529 530
    });
}

531 532
#[test]
fn lub_bound_bound() {
533 534 535
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
        let t_rptr_bound2 = env.t_rptr_late_bound(2);
536 537 538
        env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_bound2], env.tcx().types.int),
                      env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
539
    })
540 541 542 543
}

#[test]
fn lub_bound_free() {
544 545
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
546
        let t_rptr_free1 = env.t_rptr_free(0, 1);
547 548 549
        env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_free1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_free1], env.tcx().types.int));
550
    })
551 552 553 554
}

#[test]
fn lub_bound_static() {
555 556
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
557
        let t_rptr_static = env.t_rptr_static();
558 559 560
        env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_static], env.tcx().types.int),
                      env.t_fn(&[t_rptr_static], env.tcx().types.int));
561
    })
562 563 564 565
}

#[test]
fn lub_bound_bound_inverse_order() {
566 567 568 569 570 571
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
        let t_rptr_bound2 = env.t_rptr_late_bound(2);
        env.check_lub(env.t_fn(&[t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
                      env.t_fn(&[t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
                      env.t_fn(&[t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
572
    })
573 574 575 576
}

#[test]
fn lub_free_free() {
577
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
578 579 580
        let t_rptr_free1 = env.t_rptr_free(0, 1);
        let t_rptr_free2 = env.t_rptr_free(0, 2);
        let t_rptr_static = env.t_rptr_static();
581 582 583
        env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_free2], env.tcx().types.int),
                      env.t_fn(&[t_rptr_static], env.tcx().types.int));
584
    })
585 586 587 588
}

#[test]
fn lub_returning_scope() {
589
    test_env(EMPTY_SOURCE_STR,
N
Nick Cameron 已提交
590
             errors(&["cannot infer an appropriate lifetime"]), |env| {
591 592 593 594
                 let t_rptr_scope10 = env.t_rptr_scope(10);
                 let t_rptr_scope11 = env.t_rptr_scope(11);

                 // this should generate an error when regions are resolved
595 596
                 env.make_lub_ty(env.t_fn(&[], t_rptr_scope10),
                                 env.t_fn(&[], t_rptr_scope11));
597
             })
598 599
}

600 601
#[test]
fn glb_free_free_with_common_scope() {
602
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
603 604 605
        let t_rptr_free1 = env.t_rptr_free(0, 1);
        let t_rptr_free2 = env.t_rptr_free(0, 2);
        let t_rptr_scope = env.t_rptr_scope(0);
606 607 608
        env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_free2], env.tcx().types.int),
                      env.t_fn(&[t_rptr_scope], env.tcx().types.int));
609
    })
610 611 612 613
}

#[test]
fn glb_bound_bound() {
614 615 616
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
        let t_rptr_bound2 = env.t_rptr_late_bound(2);
617 618 619
        env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_bound2], env.tcx().types.int),
                      env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
620
    })
621 622 623 624
}

#[test]
fn glb_bound_free() {
625 626
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
627
        let t_rptr_free1 = env.t_rptr_free(0, 1);
628 629 630
        env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_free1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
631
    })
632 633
}

634 635 636 637 638 639 640 641
#[test]
fn glb_bound_free_infer() {
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
        let t_infer1 = env.infcx.next_ty_var();

        // compute GLB(fn(_) -> int, for<'b> fn(&'b int) -> int),
        // which should yield for<'b> fn(&'b int) -> int
642 643 644
        env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
                      env.t_fn(&[t_infer1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
645 646 647 648 649 650 651 652 653 654 655

        // as a side-effect, computing GLB should unify `_` with
        // `&'_ int`
        let t_resolve1 = env.infcx.shallow_resolve(t_infer1);
        match t_resolve1.sty {
            ty::ty_rptr(..) => { }
            _ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); }
        }
    })
}

656 657
#[test]
fn glb_bound_static() {
658 659
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
660
        let t_rptr_static = env.t_rptr_static();
661 662 663
        env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.int),
                      env.t_fn(&[t_rptr_static], env.tcx().types.int),
                      env.t_fn(&[t_rptr_bound1], env.tcx().types.int));
664
    })
665
}
666

S
Steve Klabnik 已提交
667 668
/// Test substituting a bound region into a function, which introduces another level of binding.
/// This requires adjusting the Debruijn index.
669 670 671
#[test]
fn subst_ty_renumber_bound() {

672
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
673 674 675 676 677 678 679 680
        // Situation:
        // Theta = [A -> &'a foo]

        let t_rptr_bound1 = env.t_rptr_late_bound(1);

        // t_source = fn(A)
        let t_source = {
            let t_param = env.t_param(subst::TypeSpace, 0);
681
            env.t_fn(&[t_param], env.t_nil())
682 683 684 685 686 687 688 689
        };

        let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
        let t_substituted = t_source.subst(env.infcx.tcx, &substs);

        // t_expected = fn(&'a int)
        let t_expected = {
            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())
691 692 693 694 695 696 697 698 699 700 701 702
        };

        debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
               t_source.repr(env.infcx.tcx),
               substs.repr(env.infcx.tcx),
               t_substituted.repr(env.infcx.tcx),
               t_expected.repr(env.infcx.tcx));

        assert_eq!(t_substituted, t_expected);
    })
}

S
Steve Klabnik 已提交
703 704
/// Test substituting a bound region into a function, which introduces another level of binding.
/// This requires adjusting the Debruijn index.
705 706
#[test]
fn subst_ty_renumber_some_bounds() {
707
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
708 709 710 711 712 713 714 715
        // Situation:
        // Theta = [A -> &'a foo]

        let t_rptr_bound1 = env.t_rptr_late_bound(1);

        // t_source = (A, fn(A))
        let t_source = {
            let t_param = env.t_param(subst::TypeSpace, 0);
716
            env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
717 718 719 720 721 722 723 724 725 726
        };

        let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
        let t_substituted = t_source.subst(env.infcx.tcx, &substs);

        // t_expected = (&'a int, fn(&'a int))
        //
        // but not that the Debruijn index is different in the different cases.
        let t_expected = {
            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()))
728 729 730 731 732 733 734 735 736 737 738 739
        };

        debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
               t_source.repr(env.infcx.tcx),
               substs.repr(env.infcx.tcx),
               t_substituted.repr(env.infcx.tcx),
               t_expected.repr(env.infcx.tcx));

        assert_eq!(t_substituted, t_expected);
    })
}

S
Steve Klabnik 已提交
740
/// Test that we correctly compute whether a type has escaping regions or not.
741 742 743
#[test]
fn escaping() {

744
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
        // Situation:
        // Theta = [A -> &'a foo]

        assert!(!ty::type_has_escaping_regions(env.t_nil()));

        let t_rptr_free1 = env.t_rptr_free(0, 1);
        assert!(!ty::type_has_escaping_regions(t_rptr_free1));

        let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
        assert!(ty::type_has_escaping_regions(t_rptr_bound1));

        let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
        assert!(ty::type_has_escaping_regions(t_rptr_bound2));

        // t_fn = fn(A)
        let t_param = env.t_param(subst::TypeSpace, 0);
        assert!(!ty::type_has_escaping_regions(t_param));
762
        let t_fn = env.t_fn(&[t_param], env.t_nil());
763 764 765 766
        assert!(!ty::type_has_escaping_regions(t_fn));
    })
}

S
Steve Klabnik 已提交
767 768
/// Test applying a substitution where the value being substituted for an early-bound region is a
/// late-bound region.
769 770
#[test]
fn subst_region_renumber_region() {
771
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
772 773 774 775 776
        let re_bound1 = env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));

        // type t_source<'a> = fn(&'a int)
        let t_source = {
            let re_early = env.re_early_bound(subst::TypeSpace, 0, "'a");
777
            env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
778 779 780 781 782 783 784 785 786 787
        };

        let substs = subst::Substs::new_type(vec![], vec![re_bound1]);
        let t_substituted = t_source.subst(env.infcx.tcx, &substs);

        // t_expected = fn(&'a int)
        //
        // but not that the Debruijn index is different in the different cases.
        let t_expected = {
            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())
789 790 791 792 793 794 795 796 797 798 799
        };

        debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
               t_source.repr(env.infcx.tcx),
               substs.repr(env.infcx.tcx),
               t_substituted.repr(env.infcx.tcx),
               t_expected.repr(env.infcx.tcx));

        assert_eq!(t_substituted, t_expected);
    })
}
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844

#[test]
fn walk_ty() {
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let tcx = env.infcx.tcx;
        let int_ty = tcx.types.int;
        let uint_ty = tcx.types.uint;
        let tup1_ty = ty::mk_tup(tcx, vec!(int_ty, uint_ty, int_ty, uint_ty));
        let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty));
        let uniq_ty = ty::mk_uniq(tcx, tup2_ty);
        let walked: Vec<_> = uniq_ty.walk().collect();
        assert_eq!(vec!(uniq_ty,
                        tup2_ty,
                        tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
                        tup1_ty, int_ty, uint_ty, int_ty, uint_ty,
                        uint_ty),
                   walked);
    })
}

#[test]
fn walk_ty_skip_subtree() {
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let tcx = env.infcx.tcx;
        let int_ty = tcx.types.int;
        let uint_ty = tcx.types.uint;
        let tup1_ty = ty::mk_tup(tcx, vec!(int_ty, uint_ty, int_ty, uint_ty));
        let tup2_ty = ty::mk_tup(tcx, vec!(tup1_ty, tup1_ty, uint_ty));
        let uniq_ty = ty::mk_uniq(tcx, tup2_ty);

        // types we expect to see (in order), plus a boolean saying
        // whether to skip the subtree.
        let mut expected = vec!((uniq_ty, false),
                                (tup2_ty, false),
                                (tup1_ty, false),
                                (int_ty, false),
                                (uint_ty, false),
                                (int_ty, false),
                                (uint_ty, false),
                                (tup1_ty, true), // skip the int/uint/int/uint
                                (uint_ty, false));
        expected.reverse();

        let mut walker = uniq_ty.walk();
        while let Some(t) = walker.next() {
A
Alex Crichton 已提交
845
            debug!("walked to {:?}", t);
846 847 848 849 850 851 852 853
            let (expected_ty, skip) = expected.pop().unwrap();
            assert_eq!(t, expected_ty);
            if skip { walker.skip_current_subtree(); }
        }

        assert!(expected.is_empty());
    })
}