2012-12-03 18:48:01 -06:00
|
|
|
// 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.
|
|
|
|
|
2014-06-20 05:35:06 -05:00
|
|
|
/*!
|
2012-11-01 17:16:46 -05:00
|
|
|
|
|
|
|
# Standalone Tests for the Inference Module
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2013-01-08 21:29:16 -06:00
|
|
|
use driver::diagnostic;
|
2014-06-20 05:35:06 -05:00
|
|
|
use driver::diagnostic::Emitter;
|
|
|
|
use driver::driver;
|
|
|
|
use middle::lang_items;
|
2014-11-18 07:22:59 -06:00
|
|
|
use middle::region::{mod, CodeExtent};
|
2014-06-20 05:35:06 -05:00
|
|
|
use middle::resolve;
|
|
|
|
use middle::resolve_lifetime;
|
|
|
|
use middle::stability;
|
2014-11-15 15:47:59 -06:00
|
|
|
use middle::subst;
|
|
|
|
use middle::subst::Subst;
|
2014-09-13 13:09:25 -05:00
|
|
|
use middle::ty::{mod, Ty};
|
2014-06-20 05:35:06 -05:00
|
|
|
use middle::typeck::infer::combine::Combine;
|
|
|
|
use middle::typeck::infer;
|
|
|
|
use middle::typeck::infer::lub::Lub;
|
|
|
|
use middle::typeck::infer::glb::Glb;
|
2014-11-15 15:47:59 -06:00
|
|
|
use session::{mod,config};
|
|
|
|
use syntax::{abi, ast, ast_map, ast_util};
|
2014-06-20 05:35:06 -05:00
|
|
|
use syntax::codemap;
|
|
|
|
use syntax::codemap::{Span, CodeMap, DUMMY_SP};
|
2014-08-29 01:55:35 -05:00
|
|
|
use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help};
|
2014-11-15 15:47:59 -06:00
|
|
|
use syntax::parse::token;
|
|
|
|
use util::ppaux::{ty_to_string, Repr, UserString};
|
2014-06-20 05:35:06 -05:00
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
use arena::TypedArena;
|
|
|
|
|
|
|
|
struct Env<'a, 'tcx: 'a> {
|
|
|
|
infcx: &'a infer::InferCtxt<'a, 'tcx>,
|
2014-06-20 05:35:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
struct RH<'a> {
|
|
|
|
id: ast::NodeId,
|
|
|
|
sub: &'a [RH<'a>]
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-06-20 05:35:06 -05:00
|
|
|
static EMPTY_SOURCE_STR: &'static str = "#![no_std]";
|
|
|
|
|
|
|
|
struct ExpectErrorEmitter {
|
|
|
|
messages: Vec<String>
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-06-20 05:35:06 -05:00
|
|
|
fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
|
|
|
|
match lvl {
|
|
|
|
Bug | Fatal | Error => { }
|
2014-08-29 01:55:35 -05:00
|
|
|
Warning | Note | Help => { return; }
|
2014-06-20 05:35:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
debug!("Error: {}", msg);
|
|
|
|
match e.messages.iter().position(|m| msg.contains(m.as_slice())) {
|
|
|
|
Some(i) => {
|
|
|
|
e.messages.remove(i);
|
|
|
|
}
|
|
|
|
None => {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("Unexpected error: {} Expected: {}",
|
2014-06-20 05:35:06 -05:00
|
|
|
msg, e.messages);
|
|
|
|
}
|
|
|
|
}
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-06-20 05:35:06 -05:00
|
|
|
impl Emitter for ExpectErrorEmitter {
|
|
|
|
fn emit(&mut self,
|
|
|
|
_cmsp: Option<(&codemap::CodeMap, Span)>,
|
|
|
|
msg: &str,
|
2014-07-01 11:39:41 -05:00
|
|
|
_: Option<&str>,
|
2014-06-20 05:35:06 -05:00
|
|
|
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) {
|
2014-07-16 15:37:28 -05:00
|
|
|
let v = msgs.iter().map(|m| m.to_string()).collect();
|
2014-06-20 05:35:06 -05:00
|
|
|
(box ExpectErrorEmitter { messages: v } as Box<Emitter+Send>, msgs.len())
|
|
|
|
}
|
|
|
|
|
2014-11-15 15:47:59 -06:00
|
|
|
fn test_env(source_string: &str,
|
2014-06-20 05:35:06 -05:00
|
|
|
(emitter, expected_err_count): (Box<Emitter+Send>, uint),
|
|
|
|
body: |Env|) {
|
2014-11-15 15:47:59 -06:00
|
|
|
let mut options =
|
2014-06-20 05:35:06 -05:00
|
|
|
config::basic_options();
|
2014-11-15 15:47:59 -06:00
|
|
|
options.debugging_opts |= config::VERBOSE;
|
2014-06-20 05:35:06 -05:00
|
|
|
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();
|
2014-07-16 15:37:28 -05:00
|
|
|
let input = driver::StrInput(source_string.to_string());
|
2014-06-20 05:35:06 -05:00
|
|
|
let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
|
2014-09-07 12:09:06 -05:00
|
|
|
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();
|
2014-06-20 05:35:06 -05:00
|
|
|
|
|
|
|
// run just enough stuff to build a tcx:
|
2014-09-07 12:09:06 -05:00
|
|
|
let lang_items = lang_items::collect_language_items(krate, &sess);
|
2014-09-17 21:45:21 -05:00
|
|
|
let resolve::CrateMap { def_map, freevars, capture_mode_map, .. } =
|
2014-09-07 12:09:06 -05:00
|
|
|
resolve::resolve_crate(&sess, &lang_items, krate);
|
2014-11-15 15:47:59 -06:00
|
|
|
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
|
2014-09-07 12:09:06 -05:00
|
|
|
let region_map = region::resolve_crate(&sess, krate);
|
|
|
|
let stability_index = stability::Index::build(krate);
|
2014-04-22 07:56:37 -05:00
|
|
|
let type_arena = TypedArena::new();
|
2014-07-23 14:43:29 -05:00
|
|
|
let tcx = ty::mk_ctxt(sess,
|
2014-04-22 07:56:37 -05:00
|
|
|
&type_arena,
|
2014-07-23 14:43:29 -05:00
|
|
|
def_map,
|
|
|
|
named_region_map,
|
|
|
|
ast_map,
|
2014-09-17 21:45:21 -05:00
|
|
|
freevars,
|
|
|
|
capture_mode_map,
|
2014-07-23 14:43:29 -05:00
|
|
|
region_map,
|
|
|
|
lang_items,
|
|
|
|
stability_index);
|
2014-06-20 05:35:06 -05:00
|
|
|
let infcx = infer::new_infer_ctxt(&tcx);
|
2014-09-07 12:09:06 -05:00
|
|
|
body(Env { infcx: &infcx });
|
2014-06-20 05:35:06 -05:00
|
|
|
infcx.resolve_regions_and_report_errors();
|
|
|
|
assert_eq!(tcx.sess.err_count(), expected_err_count);
|
|
|
|
}
|
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
impl<'a, 'tcx> Env<'a, 'tcx> {
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn create_region_hierarchy(&self, rh: &RH) {
|
2013-08-03 11:45:23 -05:00
|
|
|
for child_rh in rh.sub.iter() {
|
2012-11-01 17:16:46 -05:00
|
|
|
self.create_region_hierarchy(child_rh);
|
2014-11-18 07:22:59 -06:00
|
|
|
self.infcx.tcx.region_maps.record_encl_scope(
|
|
|
|
CodeExtent::from_node_id(child_rh.id),
|
|
|
|
CodeExtent::from_node_id(rh.id));
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-31 17:17:22 -05:00
|
|
|
pub fn create_simple_region_hierarchy(&self) {
|
2012-11-01 17:16:46 -05:00
|
|
|
// 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: &[]}]});
|
|
|
|
}
|
|
|
|
|
2014-11-15 15:47:59 -06:00
|
|
|
#[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
|
2014-06-20 05:35:06 -05:00
|
|
|
pub fn lookup_item(&self, names: &[String]) -> ast::NodeId {
|
2014-09-07 12:09:06 -05:00
|
|
|
return match search_mod(self, &self.infcx.tcx.map.krate().module, 0, names) {
|
2012-11-01 17:16:46 -05:00
|
|
|
Some(id) => id,
|
|
|
|
None => {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("no item found: `{}`", names.connect("::"));
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-06-20 05:35:06 -05:00
|
|
|
fn search_mod(this: &Env,
|
2014-01-09 07:05:33 -06:00
|
|
|
m: &ast::Mod,
|
2012-11-01 17:16:46 -05:00
|
|
|
idx: uint,
|
2014-06-20 05:35:06 -05:00
|
|
|
names: &[String])
|
|
|
|
-> Option<ast::NodeId> {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(idx < names.len());
|
2013-08-03 11:45:23 -05:00
|
|
|
for item in m.items.iter() {
|
2014-04-22 07:56:37 -05:00
|
|
|
if item.ident.user_string(this.infcx.tcx) == names[idx] {
|
2014-07-07 18:35:15 -05:00
|
|
|
return search(this, &**item, idx+1, names);
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2014-06-20 05:35:06 -05:00
|
|
|
fn search(this: &Env,
|
|
|
|
it: &ast::Item,
|
2012-11-01 17:16:46 -05:00
|
|
|
idx: uint,
|
2014-06-20 05:35:06 -05:00
|
|
|
names: &[String])
|
|
|
|
-> Option<ast::NodeId> {
|
2012-11-01 17:16:46 -05:00
|
|
|
if idx == names.len() {
|
|
|
|
return Some(it.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
return match it.node {
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 10:17:01 -05:00
|
|
|
ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemFn(..) |
|
2014-01-09 07:05:33 -06:00
|
|
|
ast::ItemForeignMod(..) | ast::ItemTy(..) => {
|
2012-11-01 17:16:46 -05:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
ast::ItemEnum(..) | ast::ItemStruct(..) |
|
|
|
|
ast::ItemTrait(..) | ast::ItemImpl(..) |
|
|
|
|
ast::ItemMac(..) => {
|
2012-11-01 17:16:46 -05:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
ast::ItemMod(ref m) => {
|
2014-06-20 05:35:06 -05:00
|
|
|
search_mod(this, m, idx, names)
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
2014-06-20 05:35:06 -05:00
|
|
|
match infer::mk_subty(self.infcx, true, infer::Misc(DUMMY_SP), a, b) {
|
|
|
|
Ok(_) => true,
|
2014-10-09 14:17:22 -05:00
|
|
|
Err(ref e) => panic!("Encountered error: {}",
|
2014-04-22 07:56:37 -05:00
|
|
|
ty::type_err_to_str(self.infcx.tcx, e))
|
2014-06-20 05:35:06 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn is_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
2012-11-01 17:16:46 -05:00
|
|
|
match infer::can_mk_subty(self.infcx, a, b) {
|
|
|
|
Ok(_) => true,
|
|
|
|
Err(_) => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
2012-11-01 17:16:46 -05:00
|
|
|
if !self.is_subtype(a, b) {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("{} is not a subtype of {}, but it should be",
|
2014-06-21 05:39:03 -05:00
|
|
|
self.ty_to_string(a),
|
|
|
|
self.ty_to_string(b));
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn assert_eq(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
2012-11-01 17:16:46 -05:00
|
|
|
self.assert_subtype(a, b);
|
|
|
|
self.assert_subtype(b, a);
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn ty_to_string(&self, a: Ty<'tcx>) -> String {
|
2014-04-22 07:56:37 -05:00
|
|
|
ty_to_string(self.infcx.tcx, a)
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-06-20 05:35:06 -05:00
|
|
|
pub fn t_fn(&self,
|
2014-09-29 14:11:30 -05:00
|
|
|
input_tys: &[Ty<'tcx>],
|
|
|
|
output_ty: Ty<'tcx>)
|
|
|
|
-> Ty<'tcx>
|
2014-06-20 05:35:06 -05:00
|
|
|
{
|
2014-11-15 15:47:59 -06:00
|
|
|
ty::mk_ctor_fn(self.infcx.tcx, input_tys, output_ty)
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn t_nil(&self) -> Ty<'tcx> {
|
2014-11-15 15:47:59 -06:00
|
|
|
ty::mk_nil(self.infcx.tcx)
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> {
|
2014-11-15 15:47:59 -06:00
|
|
|
ty::mk_tup(self.infcx.tcx, vec![ty1, ty2])
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn t_closure(&self,
|
2014-09-29 14:11:30 -05:00
|
|
|
input_tys: &[Ty<'tcx>],
|
|
|
|
output_ty: Ty<'tcx>,
|
2014-11-15 15:47:59 -06:00
|
|
|
region_bound: ty::Region)
|
2014-09-29 14:11:30 -05:00
|
|
|
-> Ty<'tcx>
|
2014-11-15 15:47:59 -06:00
|
|
|
{
|
|
|
|
ty::mk_closure(self.infcx.tcx, ty::ClosureTy {
|
|
|
|
fn_style: ast::NormalFn,
|
|
|
|
onceness: ast::Many,
|
|
|
|
store: ty::RegionTraitStore(region_bound, ast::MutMutable),
|
|
|
|
bounds: ty::region_existential_bound(region_bound),
|
|
|
|
sig: ty::FnSig {
|
|
|
|
inputs: input_tys.to_vec(),
|
|
|
|
output: ty::FnConverging(output_ty),
|
|
|
|
variadic: false,
|
|
|
|
},
|
|
|
|
abi: abi::Rust,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn t_param(&self, space: subst::ParamSpace, index: uint) -> Ty<'tcx> {
|
2014-11-15 15:47:59 -06:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> {
|
2014-11-15 15:47:59 -06:00
|
|
|
ty::mk_imm_rptr(self.infcx.tcx, r, ty::mk_int())
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn t_rptr_late_bound(&self, id: uint) -> Ty<'tcx> {
|
2014-11-15 15:47:59 -06:00
|
|
|
ty::mk_imm_rptr(self.infcx.tcx,
|
|
|
|
self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1)),
|
|
|
|
ty::mk_int())
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn t_rptr_late_bound_with_debruijn(&self,
|
|
|
|
id: uint,
|
|
|
|
debruijn: ty::DebruijnIndex)
|
|
|
|
-> Ty<'tcx> {
|
2014-11-15 15:47:59 -06:00
|
|
|
ty::mk_imm_rptr(self.infcx.tcx,
|
|
|
|
self.re_late_bound_with_debruijn(id, debruijn),
|
|
|
|
ty::mk_int())
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
|
2014-11-18 07:22:59 -06:00
|
|
|
ty::mk_imm_rptr(self.infcx.tcx, ty::ReScope(CodeExtent::from_node_id(id)), ty::mk_int())
|
2014-11-15 15:47:59 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn re_free(&self, nid: ast::NodeId, id: uint) -> ty::Region {
|
2014-11-18 07:22:59 -06:00
|
|
|
ty::ReFree(ty::FreeRegion { scope: CodeExtent::from_node_id(nid),
|
|
|
|
bound_region: ty::BrAnon(id)})
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn t_rptr_free(&self, nid: ast::NodeId, id: uint) -> Ty<'tcx> {
|
2014-11-15 15:47:59 -06:00
|
|
|
ty::mk_imm_rptr(self.infcx.tcx, self.re_free(nid, id), ty::mk_int())
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn t_rptr_static(&self) -> Ty<'tcx> {
|
2014-11-15 15:47:59 -06:00
|
|
|
ty::mk_imm_rptr(self.infcx.tcx, ty::ReStatic, ty::mk_int())
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
|
2014-11-15 19:30:33 -06:00
|
|
|
infer::TypeTrace::dummy()
|
2014-06-20 05:35:06 -05:00
|
|
|
}
|
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
pub fn lub(&self) -> Lub<'a, 'tcx> {
|
2014-06-20 05:35:06 -05:00
|
|
|
let trace = self.dummy_type_trace();
|
|
|
|
Lub(self.infcx.combine_fields(true, trace))
|
|
|
|
}
|
2012-11-01 17:16:46 -05:00
|
|
|
|
2014-04-22 07:56:37 -05:00
|
|
|
pub fn glb(&self) -> Glb<'a, 'tcx> {
|
2014-06-20 05:35:06 -05:00
|
|
|
let trace = self.dummy_type_trace();
|
|
|
|
Glb(self.infcx.combine_fields(true, trace))
|
|
|
|
}
|
2012-12-05 17:13:24 -06:00
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
|
2014-06-20 05:35:06 -05:00
|
|
|
match self.lub().tys(t1, t2) {
|
|
|
|
Ok(t) => t,
|
2014-10-09 14:17:22 -05:00
|
|
|
Err(ref e) => panic!("unexpected error computing LUB: {}",
|
2014-04-22 07:56:37 -05:00
|
|
|
ty::type_err_to_str(self.infcx.tcx, e))
|
2012-12-05 17:13:24 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-01 17:16:46 -05:00
|
|
|
/// Checks that `LUB(t1,t2) == t_lub`
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
|
2012-11-01 17:16:46 -05:00
|
|
|
match self.lub().tys(t1, t2) {
|
|
|
|
Ok(t) => {
|
|
|
|
self.assert_eq(t, t_lub);
|
2014-06-20 05:35:06 -05:00
|
|
|
}
|
|
|
|
Err(ref e) => {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("unexpected error in LUB: {}",
|
2014-04-22 07:56:37 -05:00
|
|
|
ty::type_err_to_str(self.infcx.tcx, e))
|
2012-12-05 17:13:24 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks that `GLB(t1,t2) == t_glb`
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
|
2014-06-20 05:35:06 -05:00
|
|
|
debug!("check_glb(t1={}, t2={}, t_glb={})",
|
2014-06-21 05:39:03 -05:00
|
|
|
self.ty_to_string(t1),
|
|
|
|
self.ty_to_string(t2),
|
|
|
|
self.ty_to_string(t_glb));
|
2012-12-05 17:13:24 -06:00
|
|
|
match self.glb().tys(t1, t2) {
|
|
|
|
Err(e) => {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("unexpected error computing LUB: {}", e)
|
2012-12-05 17:13:24 -06:00
|
|
|
}
|
|
|
|
Ok(t) => {
|
|
|
|
self.assert_eq(t, t_glb);
|
|
|
|
|
|
|
|
// sanity check for good measure:
|
|
|
|
self.assert_subtype(t, t1);
|
|
|
|
self.assert_subtype(t, t2);
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-06-20 05:35:06 -05:00
|
|
|
fn contravariant_region_ptr_ok() {
|
2014-11-15 15:47:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
2014-06-20 05:35:06 -05:00
|
|
|
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() {
|
2014-11-15 15:47:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR,
|
2014-11-17 02:39:01 -06:00
|
|
|
errors(&["lifetime mismatch"]),
|
2014-06-20 05:35:06 -05:00
|
|
|
|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);
|
|
|
|
})
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn lub_bound_bound() {
|
2014-11-15 15:47:59 -06:00
|
|
|
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()));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn lub_bound_free() {
|
2014-11-15 15:47:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
|
|
|
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
2014-06-20 05:35:06 -05:00
|
|
|
let t_rptr_free1 = env.t_rptr_free(0, 1);
|
2014-11-15 15:47:59 -06:00
|
|
|
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()));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn lub_bound_static() {
|
2014-11-15 15:47:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
|
|
|
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
2014-06-20 05:35:06 -05:00
|
|
|
let t_rptr_static = env.t_rptr_static();
|
2014-11-15 15:47:59 -06:00
|
|
|
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()));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn lub_bound_bound_inverse_order() {
|
2014-11-15 15:47:59 -06:00
|
|
|
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));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn lub_free_free() {
|
2014-11-15 15:47:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
2014-06-20 05:35:06 -05:00
|
|
|
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();
|
2014-11-15 15:47:59 -06:00
|
|
|
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()));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn lub_returning_scope() {
|
2014-11-15 15:47:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR,
|
2014-11-17 02:39:01 -06:00
|
|
|
errors(&["cannot infer an appropriate lifetime"]), |env| {
|
2014-06-20 05:35:06 -05:00
|
|
|
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
|
2014-11-15 15:47:59 -06:00
|
|
|
env.make_lub_ty(env.t_fn(&[], t_rptr_scope10),
|
|
|
|
env.t_fn(&[], t_rptr_scope11));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-11-01 17:16:46 -05:00
|
|
|
}
|
|
|
|
|
2012-12-05 17:13:24 -06:00
|
|
|
#[test]
|
|
|
|
fn glb_free_free_with_common_scope() {
|
2014-11-15 15:47:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
2014-06-20 05:35:06 -05:00
|
|
|
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);
|
2014-11-15 15:47:59 -06:00
|
|
|
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()));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-12-05 17:13:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn glb_bound_bound() {
|
2014-11-15 15:47:59 -06:00
|
|
|
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()));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-12-05 17:13:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn glb_bound_free() {
|
2014-11-15 15:47:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
|
|
|
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
2014-06-20 05:35:06 -05:00
|
|
|
let t_rptr_free1 = env.t_rptr_free(0, 1);
|
2014-11-15 15:47:59 -06:00
|
|
|
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()));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-12-05 17:13:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn glb_bound_static() {
|
2014-11-15 15:47:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
|
|
|
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
2014-06-20 05:35:06 -05:00
|
|
|
let t_rptr_static = env.t_rptr_static();
|
2014-11-15 15:47:59 -06:00
|
|
|
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()));
|
2014-06-20 05:35:06 -05:00
|
|
|
})
|
2012-12-05 17:13:24 -06:00
|
|
|
}
|
2014-11-15 15:47:59 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn subst_ty_renumber_bound() {
|
|
|
|
/*!
|
|
|
|
* Test substituting a bound region into a function, which introduces another
|
|
|
|
* level of binding. This requires adjusting the Debruijn index.
|
|
|
|
*/
|
|
|
|
|
2014-11-18 12:20:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
2014-11-15 15:47:59 -06:00
|
|
|
// 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);
|
2014-11-18 12:20:59 -06:00
|
|
|
env.t_fn(&[t_param], env.t_nil())
|
2014-11-15 15:47:59 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
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));
|
2014-11-18 12:20:59 -06:00
|
|
|
env.t_fn(&[t_ptr_bound2], env.t_nil())
|
2014-11-15 15:47:59 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn subst_ty_renumber_some_bounds() {
|
|
|
|
/*!
|
|
|
|
* Test substituting a bound region into a function, which introduces another
|
|
|
|
* level of binding. This requires adjusting the Debruijn index.
|
|
|
|
*/
|
|
|
|
|
2014-11-18 12:20:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
2014-11-15 15:47:59 -06:00
|
|
|
// 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);
|
2014-11-18 12:20:59 -06:00
|
|
|
env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
|
2014-11-15 15:47:59 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
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));
|
2014-11-18 12:20:59 -06:00
|
|
|
env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
|
2014-11-15 15:47:59 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn escaping() {
|
|
|
|
/*!
|
|
|
|
* Test that we correctly compute whether a type has escaping
|
|
|
|
* regions or not.
|
|
|
|
*/
|
|
|
|
|
2014-11-18 12:20:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
2014-11-15 15:47:59 -06:00
|
|
|
// 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));
|
2014-11-18 12:20:59 -06:00
|
|
|
let t_fn = env.t_fn(&[t_param], env.t_nil());
|
2014-11-15 15:47:59 -06:00
|
|
|
assert!(!ty::type_has_escaping_regions(t_fn));
|
|
|
|
|
|
|
|
// t_fn = |&int|+'a
|
2014-11-18 12:20:59 -06:00
|
|
|
let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(), env.re_free(0, 1));
|
2014-11-15 15:47:59 -06:00
|
|
|
assert!(!ty::type_has_escaping_regions(t_fn));
|
|
|
|
|
|
|
|
// t_fn = |&int|+'a (where &int has depth 2)
|
2014-11-18 12:20:59 -06:00
|
|
|
let t_fn = env.t_closure(&[t_rptr_bound2], env.t_nil(), env.re_free(0, 1));
|
2014-11-15 15:47:59 -06:00
|
|
|
assert!(ty::type_has_escaping_regions(t_fn));
|
|
|
|
|
|
|
|
// t_fn = |&int|+&int
|
2014-11-18 12:20:59 -06:00
|
|
|
let t_fn = env.t_closure(&[t_rptr_bound1], env.t_nil(),
|
2014-11-15 15:47:59 -06:00
|
|
|
env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)));
|
|
|
|
assert!(ty::type_has_escaping_regions(t_fn));
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn subst_region_renumber_region() {
|
|
|
|
/*!
|
|
|
|
* Test applying a substitution where the value being substituted
|
|
|
|
* for an early-bound region is a late-bound region.
|
|
|
|
*/
|
|
|
|
|
2014-11-18 12:20:59 -06:00
|
|
|
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
2014-11-15 15:47:59 -06:00
|
|
|
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");
|
2014-11-18 12:20:59 -06:00
|
|
|
env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
|
2014-11-15 15:47:59 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
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));
|
2014-11-18 12:20:59 -06:00
|
|
|
env.t_fn(&[t_rptr_bound2], env.t_nil())
|
2014-11-15 15:47:59 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|