test.rs 27.7 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 18 19 20 21 22 23 24 25 26 27
use rustc_typeck::middle::lang_items;
use rustc_typeck::middle::region::{mod, CodeExtent};
use rustc_typeck::middle::resolve_lifetime;
use rustc_typeck::middle::stability;
use rustc_typeck::middle::subst;
use rustc_typeck::middle::subst::Subst;
use rustc_typeck::middle::ty::{mod, Ty};
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 30
use rustc_typeck::util::ppaux::{ty_to_string, Repr, UserString};
use rustc::session::{mod,config};
31
use syntax::{abi, ast, ast_map, ast_util};
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 39 40
use arena::TypedArena;

struct Env<'a, 'tcx: 'a> {
    infcx: &'a infer::InferCtxt<'a, 'tcx>,
41 42 43 44 45
}

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

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

struct ExpectErrorEmitter {
    messages: Vec<String>
52 53
}

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

    debug!("Error: {}", msg);
    match e.messages.iter().position(|m| msg.contains(m.as_slice())) {
        Some(i) => {
            e.messages.remove(i);
        }
        None => {
S
Steve Klabnik 已提交
66
            panic!("Unexpected error: {} Expected: {}",
67 68 69
                  msg, e.messages);
        }
    }
70 71
}

72 73 74 75
impl Emitter for ExpectErrorEmitter {
    fn emit(&mut self,
            _cmsp: Option<(&codemap::CodeMap, Span)>,
            msg: &str,
76
            _: Option<&str>,
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
            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) {
93
    let v = msgs.iter().map(|m| m.to_string()).collect();
94 95 96
    (box ExpectErrorEmitter { messages: v } as Box<Emitter+Send>, msgs.len())
}

97 98 99 100 101
fn test_env<F>(source_string: &str,
               (emitter, expected_err_count): (Box<Emitter+Send>, uint),
               body: F) where
    F: FnOnce(Env),
{
102
    let mut options =
103
        config::basic_options();
104
    options.debugging_opts |= config::VERBOSE;
105 106 107 108 109 110 111 112 113
    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();
114
    let input = config::Input::Str(source_string.to_string());
115
    let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
116 117 118 119 120 121
    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();
122 123

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

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

161
    pub fn create_simple_region_hierarchy(&self) {
162 163 164 165 166 167 168 169 170 171
        // 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: &[]}]});
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    pub fn t_closure(&self,
283 284
                     input_tys: &[Ty<'tcx>],
                     output_ty: Ty<'tcx>,
285
                     region_bound: ty::Region)
286
                     -> Ty<'tcx>
287 288
    {
        ty::mk_closure(self.infcx.tcx, ty::ClosureTy {
N
Niko Matsakis 已提交
289
            unsafety: ast::Unsafety::Normal,
290 291 292
            onceness: ast::Many,
            store: ty::RegionTraitStore(region_bound, ast::MutMutable),
            bounds: ty::region_existential_bound(region_bound),
293
            sig: ty::Binder(ty::FnSig {
294 295 296
                inputs: input_tys.to_vec(),
                output: ty::FnConverging(output_ty),
                variadic: false,
297
            }),
298 299 300 301
            abi: abi::Rust,
        })
    }

302
    pub fn t_param(&self, space: subst::ParamSpace, index: uint) -> Ty<'tcx> {
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
        ty::mk_param(self.infcx.tcx, space, index, ast_util::local_def(ast::DUMMY_NODE_ID))
    }

    pub fn re_early_bound(&self,
                          space: subst::ParamSpace,
                          index: uint,
                          name: &'static str)
                          -> ty::Region
    {
        let name = token::intern(name);
        ty::ReEarlyBound(ast::DUMMY_NODE_ID, space, index, name)
    }

    pub fn re_late_bound_with_debruijn(&self, id: uint, debruijn: ty::DebruijnIndex) -> ty::Region {
        ty::ReLateBound(debruijn, ty::BrAnon(id))
    }

320
    pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> {
321
        ty::mk_imm_rptr(self.infcx.tcx, r, ty::mk_int())
322 323
    }

324
    pub fn t_rptr_late_bound(&self, id: uint) -> Ty<'tcx> {
325 326 327
        ty::mk_imm_rptr(self.infcx.tcx,
                        self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1)),
                        ty::mk_int())
328 329
    }

330 331 332 333
    pub fn t_rptr_late_bound_with_debruijn(&self,
                                           id: uint,
                                           debruijn: ty::DebruijnIndex)
                                           -> Ty<'tcx> {
334 335 336
        ty::mk_imm_rptr(self.infcx.tcx,
                        self.re_late_bound_with_debruijn(id, debruijn),
                        ty::mk_int())
337 338
    }

339
    pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
340
        ty::mk_imm_rptr(self.infcx.tcx, ty::ReScope(CodeExtent::from_node_id(id)), ty::mk_int())
341 342 343
    }

    pub fn re_free(&self, nid: ast::NodeId, id: uint) -> ty::Region {
344 345
        ty::ReFree(ty::FreeRegion { scope: CodeExtent::from_node_id(nid),
                                    bound_region: ty::BrAnon(id)})
346 347
    }

348
    pub fn t_rptr_free(&self, nid: ast::NodeId, id: uint) -> Ty<'tcx> {
349
        ty::mk_imm_rptr(self.infcx.tcx, self.re_free(nid, id), ty::mk_int())
350 351
    }

352
    pub fn t_rptr_static(&self) -> Ty<'tcx> {
353
        ty::mk_imm_rptr(self.infcx.tcx, ty::ReStatic, ty::mk_int())
354 355
    }

356
    pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
357
        infer::TypeTrace::dummy()
358 359
    }

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

365
    pub fn lub(&self) -> Lub<'a, 'tcx> {
366 367 368
        let trace = self.dummy_type_trace();
        Lub(self.infcx.combine_fields(true, trace))
    }
369

370
    pub fn glb(&self) -> Glb<'a, 'tcx> {
371 372 373
        let trace = self.dummy_type_trace();
        Glb(self.infcx.combine_fields(true, trace))
    }
374

375
    pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
376 377
        match self.lub().tys(t1, t2) {
            Ok(t) => t,
S
Steve Klabnik 已提交
378
            Err(ref e) => panic!("unexpected error computing LUB: {}",
379
                                ty::type_err_to_str(self.infcx.tcx, e))
380 381 382
        }
    }

383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
    /// 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));
            }
        }
    }

410
    /// Checks that `LUB(t1,t2) == t_lub`
411
    pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
412 413 414
        match self.lub().tys(t1, t2) {
            Ok(t) => {
                self.assert_eq(t, t_lub);
415 416
            }
            Err(ref e) => {
S
Steve Klabnik 已提交
417
                panic!("unexpected error in LUB: {}",
418
                      ty::type_err_to_str(self.infcx.tcx, e))
419 420 421 422 423
            }
        }
    }

    /// Checks that `GLB(t1,t2) == t_glb`
424
    pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
425
        debug!("check_glb(t1={}, t2={}, t_glb={})",
426 427 428
               self.ty_to_string(t1),
               self.ty_to_string(t2),
               self.ty_to_string(t_glb));
429 430
        match self.glb().tys(t1, t2) {
            Err(e) => {
S
Steve Klabnik 已提交
431
                panic!("unexpected error computing LUB: {}", e)
432 433 434 435 436 437 438
            }
            Ok(t) => {
                self.assert_eq(t, t_glb);

                // sanity check for good measure:
                self.assert_subtype(t, t1);
                self.assert_subtype(t, t2);
439 440 441 442 443 444
            }
        }
    }
}

#[test]
445
fn contravariant_region_ptr_ok() {
446
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
447 448 449 450 451 452 453 454 455 456 457
        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() {
458
    test_env(EMPTY_SOURCE_STR,
N
Nick Cameron 已提交
459
             errors(&["lifetime mismatch"]),
460 461 462 463 464 465 466 467 468 469
             |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);
             })
470 471
}

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
#[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);
        env.check_not_sub(env.t_fn(&[t_rptr_free1], ty::mk_int()),
                          env.t_fn(&[t_rptr_bound1], ty::mk_int()));
    })
}

#[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);
        env.check_sub(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
                      env.t_fn(&[t_rptr_free1], ty::mk_int()));
    })
}

#[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);
        env.check_not_sub(env.t_fn(&[t_infer1], ty::mk_int()),
                          env.t_fn(&[t_rptr_bound1], ty::mk_int()));
    })
}

520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
#[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);
        env.check_lub(env.t_fn(&[t_infer1], ty::mk_int()),
                      env.t_fn(&[t_rptr_bound1], ty::mk_int()),
                      env.t_fn(&[t_rptr_free1], ty::mk_int()));
    });
}

540 541
#[test]
fn lub_bound_bound() {
542 543 544 545 546 547
    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], ty::mk_int()),
                      env.t_fn(&[t_rptr_bound2], ty::mk_int()),
                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));
548
    })
549 550 551 552
}

#[test]
fn lub_bound_free() {
553 554
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
555
        let t_rptr_free1 = env.t_rptr_free(0, 1);
556 557 558
        env.check_lub(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
                      env.t_fn(&[t_rptr_free1], ty::mk_int()),
                      env.t_fn(&[t_rptr_free1], ty::mk_int()));
559
    })
560 561 562 563
}

#[test]
fn lub_bound_static() {
564 565
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
566
        let t_rptr_static = env.t_rptr_static();
567 568 569
        env.check_lub(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
                      env.t_fn(&[t_rptr_static], ty::mk_int()),
                      env.t_fn(&[t_rptr_static], ty::mk_int()));
570
    })
571 572 573 574
}

#[test]
fn lub_bound_bound_inverse_order() {
575 576 577 578 579 580
    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));
581
    })
582 583 584 585
}

#[test]
fn lub_free_free() {
586
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
587 588 589
        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();
590 591 592
        env.check_lub(env.t_fn(&[t_rptr_free1], ty::mk_int()),
                      env.t_fn(&[t_rptr_free2], ty::mk_int()),
                      env.t_fn(&[t_rptr_static], ty::mk_int()));
593
    })
594 595 596 597
}

#[test]
fn lub_returning_scope() {
598
    test_env(EMPTY_SOURCE_STR,
N
Nick Cameron 已提交
599
             errors(&["cannot infer an appropriate lifetime"]), |env| {
600 601 602 603
                 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
604 605
                 env.make_lub_ty(env.t_fn(&[], t_rptr_scope10),
                                 env.t_fn(&[], t_rptr_scope11));
606
             })
607 608
}

609 610
#[test]
fn glb_free_free_with_common_scope() {
611
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
612 613 614
        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);
615 616 617
        env.check_glb(env.t_fn(&[t_rptr_free1], ty::mk_int()),
                      env.t_fn(&[t_rptr_free2], ty::mk_int()),
                      env.t_fn(&[t_rptr_scope], ty::mk_int()));
618
    })
619 620 621 622
}

#[test]
fn glb_bound_bound() {
623 624 625 626 627 628
    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_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
                      env.t_fn(&[t_rptr_bound2], ty::mk_int()),
                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));
629
    })
630 631 632 633
}

#[test]
fn glb_bound_free() {
634 635
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
636
        let t_rptr_free1 = env.t_rptr_free(0, 1);
637 638 639
        env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
                      env.t_fn(&[t_rptr_free1], ty::mk_int()),
                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));
640
    })
641 642
}

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
#[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
        env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
                      env.t_fn(&[t_infer1], ty::mk_int()),
                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));

        // 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)); }
        }
    })
}

665 666
#[test]
fn glb_bound_static() {
667 668
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
669
        let t_rptr_static = env.t_rptr_static();
670 671 672
        env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
                      env.t_fn(&[t_rptr_static], ty::mk_int()),
                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));
673
    })
674
}
675

S
Steve Klabnik 已提交
676 677
/// Test substituting a bound region into a function, which introduces another level of binding.
/// This requires adjusting the Debruijn index.
678 679 680
#[test]
fn subst_ty_renumber_bound() {

681
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
682 683 684 685 686 687 688 689
        // 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);
690
            env.t_fn(&[t_param], env.t_nil())
691 692 693 694 695 696 697 698
        };

        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));
699
            env.t_fn(&[t_ptr_bound2], env.t_nil())
700 701 702 703 704 705 706 707 708 709 710 711
        };

        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 已提交
712 713
/// Test substituting a bound region into a function, which introduces another level of binding.
/// This requires adjusting the Debruijn index.
714 715
#[test]
fn subst_ty_renumber_some_bounds() {
716
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
717 718 719 720 721 722 723 724
        // 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);
725
            env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
726 727 728 729 730 731 732 733 734 735
        };

        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));
736
            env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
737 738 739 740 741 742 743 744 745 746 747 748
        };

        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 已提交
749
/// Test that we correctly compute whether a type has escaping regions or not.
750 751 752
#[test]
fn escaping() {

753
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
        // 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));
771
        let t_fn = env.t_fn(&[t_param], env.t_nil());
772 773 774
        assert!(!ty::type_has_escaping_regions(t_fn));

        // t_fn = |&int|+'a
775
        let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(), env.re_free(0, 1));
776 777 778
        assert!(!ty::type_has_escaping_regions(t_fn));

        // t_fn = |&int|+'a (where &int has depth 2)
779
        let t_fn = env.t_closure(&[t_rptr_bound2], env.t_nil(), env.re_free(0, 1));
780 781 782
        assert!(ty::type_has_escaping_regions(t_fn));

        // t_fn = |&int|+&int
783
        let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(),
784 785 786 787 788
                                 env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)));
        assert!(ty::type_has_escaping_regions(t_fn));
    })
}

S
Steve Klabnik 已提交
789 790
/// Test applying a substitution where the value being substituted for an early-bound region is a
/// late-bound region.
791 792 793
#[test]
fn subst_region_renumber_region() {

794
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
795 796 797 798 799
        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");
800
            env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
801 802 803 804 805 806 807 808 809 810
        };

        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));
811
            env.t_fn(&[t_rptr_bound2], env.t_nil())
812 813 814 815 816 817 818 819 820 821 822
        };

        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);
    })
}