test.rs 27.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 16 17 18 19 20 21 22 23 24 25 26 27
use diagnostic;
use diagnostic::Emitter;
use driver;
use rustc_typeck::middle::lang_items;
use rustc_typeck::middle::region::{mod, CodeExtent};
use rustc_typeck::middle::resolve;
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, &lang_items, krate);
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
    let tcx = ty::mk_ctxt(sess,
132
                          &type_arena,
133 134 135
                          def_map,
                          named_region_map,
                          ast_map,
136 137
                          freevars,
                          capture_mode_map,
138 139 140
                          region_map,
                          lang_items,
                          stability_index);
141
    let infcx = infer::new_infer_ctxt(&tcx);
142
    body(Env { infcx: &infcx });
A
Alex Crichton 已提交
143
    infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);
144 145 146
    assert_eq!(tcx.sess.err_count(), expected_err_count);
}

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

157
    pub fn create_simple_region_hierarchy(&self) {
158 159 160 161 162 163 164 165 166 167
        // 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: &[]}]});
    }

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

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

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

            return match it.node {
201
                ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemFn(..) |
202
                ast::ItemForeignMod(..) | ast::ItemTy(..) => {
203 204 205
                    None
                }

206 207 208
                ast::ItemEnum(..) | ast::ItemStruct(..) |
                ast::ItemTrait(..) | ast::ItemImpl(..) |
                ast::ItemMac(..) => {
209 210 211
                    None
                }

212
                ast::ItemMod(ref m) => {
213
                    search_mod(this, m, idx, names)
214 215 216 217 218
                }
            };
        }
    }

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

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

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

242
    pub fn assert_eq(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
243 244 245 246
        self.assert_subtype(a, b);
        self.assert_subtype(b, a);
    }

247
    pub fn ty_to_string(&self, a: Ty<'tcx>) -> String {
248
        ty_to_string(self.infcx.tcx, a)
249 250
    }

251
    pub fn t_fn(&self,
252 253 254
                input_tys: &[Ty<'tcx>],
                output_ty: Ty<'tcx>)
                -> Ty<'tcx>
255
    {
256 257 258
        ty::mk_ctor_fn(self.infcx.tcx, input_tys, output_ty)
    }

259
    pub fn t_nil(&self) -> Ty<'tcx> {
260 261 262
        ty::mk_nil(self.infcx.tcx)
    }

263
    pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> {
264 265 266 267
        ty::mk_tup(self.infcx.tcx, vec![ty1, ty2])
    }

    pub fn t_closure(&self,
268 269
                     input_tys: &[Ty<'tcx>],
                     output_ty: Ty<'tcx>,
270
                     region_bound: ty::Region)
271
                     -> Ty<'tcx>
272 273
    {
        ty::mk_closure(self.infcx.tcx, ty::ClosureTy {
N
Niko Matsakis 已提交
274
            unsafety: ast::Unsafety::Normal,
275 276 277
            onceness: ast::Many,
            store: ty::RegionTraitStore(region_bound, ast::MutMutable),
            bounds: ty::region_existential_bound(region_bound),
278
            sig: ty::Binder(ty::FnSig {
279 280 281
                inputs: input_tys.to_vec(),
                output: ty::FnConverging(output_ty),
                variadic: false,
282
            }),
283 284 285 286
            abi: abi::Rust,
        })
    }

287
    pub fn t_param(&self, space: subst::ParamSpace, index: uint) -> Ty<'tcx> {
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
        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))
    }

305
    pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> {
306
        ty::mk_imm_rptr(self.infcx.tcx, r, ty::mk_int())
307 308
    }

309
    pub fn t_rptr_late_bound(&self, id: uint) -> Ty<'tcx> {
310 311 312
        ty::mk_imm_rptr(self.infcx.tcx,
                        self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1)),
                        ty::mk_int())
313 314
    }

315 316 317 318
    pub fn t_rptr_late_bound_with_debruijn(&self,
                                           id: uint,
                                           debruijn: ty::DebruijnIndex)
                                           -> Ty<'tcx> {
319 320 321
        ty::mk_imm_rptr(self.infcx.tcx,
                        self.re_late_bound_with_debruijn(id, debruijn),
                        ty::mk_int())
322 323
    }

324
    pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
325
        ty::mk_imm_rptr(self.infcx.tcx, ty::ReScope(CodeExtent::from_node_id(id)), ty::mk_int())
326 327 328
    }

    pub fn re_free(&self, nid: ast::NodeId, id: uint) -> ty::Region {
329 330
        ty::ReFree(ty::FreeRegion { scope: CodeExtent::from_node_id(nid),
                                    bound_region: ty::BrAnon(id)})
331 332
    }

333
    pub fn t_rptr_free(&self, nid: ast::NodeId, id: uint) -> Ty<'tcx> {
334
        ty::mk_imm_rptr(self.infcx.tcx, self.re_free(nid, id), ty::mk_int())
335 336
    }

337
    pub fn t_rptr_static(&self) -> Ty<'tcx> {
338
        ty::mk_imm_rptr(self.infcx.tcx, ty::ReStatic, ty::mk_int())
339 340
    }

341
    pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
342
        infer::TypeTrace::dummy()
343 344
    }

345 346 347 348 349
    pub fn sub(&self) -> Sub<'a, 'tcx> {
        let trace = self.dummy_type_trace();
        Sub(self.infcx.combine_fields(true, trace))
    }

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

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

360
    pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
361 362
        match self.lub().tys(t1, t2) {
            Ok(t) => t,
S
Steve Klabnik 已提交
363
            Err(ref e) => panic!("unexpected error computing LUB: {}",
364
                                ty::type_err_to_str(self.infcx.tcx, e))
365 366 367
        }
    }

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
    /// 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));
            }
        }
    }

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

    /// Checks that `GLB(t1,t2) == t_glb`
409
    pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
410
        debug!("check_glb(t1={}, t2={}, t_glb={})",
411 412 413
               self.ty_to_string(t1),
               self.ty_to_string(t2),
               self.ty_to_string(t_glb));
414 415
        match self.glb().tys(t1, t2) {
            Err(e) => {
S
Steve Klabnik 已提交
416
                panic!("unexpected error computing LUB: {}", e)
417 418 419 420 421 422 423
            }
            Ok(t) => {
                self.assert_eq(t, t_glb);

                // sanity check for good measure:
                self.assert_subtype(t, t1);
                self.assert_subtype(t, t2);
424 425 426 427 428 429
            }
        }
    }
}

#[test]
430
fn contravariant_region_ptr_ok() {
431
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
432 433 434 435 436 437 438 439 440 441 442
        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() {
443
    test_env(EMPTY_SOURCE_STR,
N
Nick Cameron 已提交
444
             errors(&["lifetime mismatch"]),
445 446 447 448 449 450 451 452 453 454
             |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);
             })
455 456
}

457 458 459 460 461 462 463 464 465 466 467 468 469 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
#[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()));
    })
}

505 506 507 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);
        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()));
    });
}

525 526
#[test]
fn lub_bound_bound() {
527 528 529 530 531 532
    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()));
533
    })
534 535 536 537
}

#[test]
fn lub_bound_free() {
538 539
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
540
        let t_rptr_free1 = env.t_rptr_free(0, 1);
541 542 543
        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()));
544
    })
545 546 547 548
}

#[test]
fn lub_bound_static() {
549 550
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
551
        let t_rptr_static = env.t_rptr_static();
552 553 554
        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()));
555
    })
556 557 558 559
}

#[test]
fn lub_bound_bound_inverse_order() {
560 561 562 563 564 565
    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));
566
    })
567 568 569 570
}

#[test]
fn lub_free_free() {
571
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
572 573 574
        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();
575 576 577
        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()));
578
    })
579 580 581 582
}

#[test]
fn lub_returning_scope() {
583
    test_env(EMPTY_SOURCE_STR,
N
Nick Cameron 已提交
584
             errors(&["cannot infer an appropriate lifetime"]), |env| {
585 586 587 588
                 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
589 590
                 env.make_lub_ty(env.t_fn(&[], t_rptr_scope10),
                                 env.t_fn(&[], t_rptr_scope11));
591
             })
592 593
}

594 595
#[test]
fn glb_free_free_with_common_scope() {
596
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
597 598 599
        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);
600 601 602
        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()));
603
    })
604 605 606 607
}

#[test]
fn glb_bound_bound() {
608 609 610 611 612 613
    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()));
614
    })
615 616 617 618
}

#[test]
fn glb_bound_free() {
619 620
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
621
        let t_rptr_free1 = env.t_rptr_free(0, 1);
622 623 624
        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()));
625
    })
626 627
}

628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
#[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)); }
        }
    })
}

650 651
#[test]
fn glb_bound_static() {
652 653
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
        let t_rptr_bound1 = env.t_rptr_late_bound(1);
654
        let t_rptr_static = env.t_rptr_static();
655 656 657
        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()));
658
    })
659
}
660

S
Steve Klabnik 已提交
661 662
/// Test substituting a bound region into a function, which introduces another level of binding.
/// This requires adjusting the Debruijn index.
663 664 665
#[test]
fn subst_ty_renumber_bound() {

666
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
667 668 669 670 671 672 673 674
        // 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);
675
            env.t_fn(&[t_param], env.t_nil())
676 677 678 679 680 681 682 683
        };

        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));
684
            env.t_fn(&[t_ptr_bound2], env.t_nil())
685 686 687 688 689 690 691 692 693 694 695 696
        };

        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 已提交
697 698
/// Test substituting a bound region into a function, which introduces another level of binding.
/// This requires adjusting the Debruijn index.
699 700
#[test]
fn subst_ty_renumber_some_bounds() {
701
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
702 703 704 705 706 707 708 709
        // 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);
710
            env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
711 712 713 714 715 716 717 718 719 720
        };

        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));
721
            env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
722 723 724 725 726 727 728 729 730 731 732 733
        };

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

738
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
        // 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));
756
        let t_fn = env.t_fn(&[t_param], env.t_nil());
757 758 759
        assert!(!ty::type_has_escaping_regions(t_fn));

        // t_fn = |&int|+'a
760
        let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(), env.re_free(0, 1));
761 762 763
        assert!(!ty::type_has_escaping_regions(t_fn));

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

        // t_fn = |&int|+&int
768
        let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(),
769 770 771 772 773
                                 env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)));
        assert!(ty::type_has_escaping_regions(t_fn));
    })
}

S
Steve Klabnik 已提交
774 775
/// Test applying a substitution where the value being substituted for an early-bound region is a
/// late-bound region.
776 777 778
#[test]
fn subst_region_renumber_region() {

779
    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
780 781 782 783 784
        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");
785
            env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
786 787 788 789 790 791 792 793 794 795
        };

        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));
796
            env.t_fn(&[t_rptr_bound2], env.t_nil())
797 798 799 800 801 802 803 804 805 806 807 808
        };

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