]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! # Standalone Tests for the Inference Module | |
12 | ||
13 | use diagnostic; | |
14 | use diagnostic::Emitter; | |
15 | use driver; | |
c34b1796 | 16 | use rustc_lint; |
1a4d82fc JJ |
17 | use rustc_resolve as resolve; |
18 | use rustc_typeck::middle::lang_items; | |
bd371182 | 19 | use rustc_typeck::middle::free_region::FreeRegionMap; |
e9174d1e SL |
20 | use rustc_typeck::middle::region::{self, CodeExtent}; |
21 | use rustc_typeck::middle::region::CodeExtentData; | |
1a4d82fc JJ |
22 | use rustc_typeck::middle::resolve_lifetime; |
23 | use rustc_typeck::middle::stability; | |
24 | use rustc_typeck::middle::subst; | |
25 | use rustc_typeck::middle::subst::Subst; | |
c1a9b12d | 26 | use rustc_typeck::middle::ty::{self, Ty, RegionEscape}; |
e9174d1e | 27 | use rustc_typeck::middle::ty::relate::TypeRelation; |
92a42be0 | 28 | use rustc_typeck::middle::infer::{self, TypeOrigin}; |
1a4d82fc JJ |
29 | use rustc_typeck::middle::infer::lub::Lub; |
30 | use rustc_typeck::middle::infer::glb::Glb; | |
31 | use rustc_typeck::middle::infer::sub::Sub; | |
92a42be0 | 32 | use rustc_metadata::cstore::CStore; |
e9174d1e | 33 | use rustc::front::map as hir_map; |
92a42be0 SL |
34 | use rustc::session::{self, config}; |
35 | use std::rc::Rc; | |
62682a34 | 36 | use syntax::{abi, ast}; |
1a4d82fc JJ |
37 | use syntax::codemap; |
38 | use syntax::codemap::{Span, CodeMap, DUMMY_SP}; | |
39 | use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help}; | |
40 | use syntax::parse::token; | |
62682a34 | 41 | use syntax::feature_gate::UnstableFeatures; |
1a4d82fc | 42 | |
b039eaaf | 43 | use rustc_front::lowering::{lower_crate, LoweringContext}; |
e9174d1e SL |
44 | use rustc_front::hir; |
45 | ||
1a4d82fc JJ |
46 | struct Env<'a, 'tcx: 'a> { |
47 | infcx: &'a infer::InferCtxt<'a, 'tcx>, | |
48 | } | |
49 | ||
50 | struct RH<'a> { | |
51 | id: ast::NodeId, | |
92a42be0 | 52 | sub: &'a [RH<'a>], |
1a4d82fc JJ |
53 | } |
54 | ||
e9174d1e | 55 | const EMPTY_SOURCE_STR: &'static str = "#![feature(no_core)] #![no_core]"; |
1a4d82fc JJ |
56 | |
57 | struct ExpectErrorEmitter { | |
92a42be0 | 58 | messages: Vec<String>, |
1a4d82fc JJ |
59 | } |
60 | ||
61 | fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) { | |
62 | match lvl { | |
92a42be0 SL |
63 | Bug | Fatal | Error => {} |
64 | Warning | Note | Help => { | |
65 | return; | |
66 | } | |
1a4d82fc JJ |
67 | } |
68 | ||
69 | debug!("Error: {}", msg); | |
85aaf69f | 70 | match e.messages.iter().position(|m| msg.contains(m)) { |
1a4d82fc JJ |
71 | Some(i) => { |
72 | e.messages.remove(i); | |
73 | } | |
74 | None => { | |
92a42be0 | 75 | panic!("Unexpected error: {} Expected: {:?}", msg, e.messages); |
1a4d82fc JJ |
76 | } |
77 | } | |
78 | } | |
79 | ||
80 | impl Emitter for ExpectErrorEmitter { | |
81 | fn emit(&mut self, | |
82 | _cmsp: Option<(&codemap::CodeMap, Span)>, | |
83 | msg: &str, | |
84 | _: Option<&str>, | |
92a42be0 | 85 | lvl: Level) { |
1a4d82fc JJ |
86 | remove_message(self, msg, lvl); |
87 | } | |
88 | ||
92a42be0 | 89 | fn custom_emit(&mut self, _cm: &codemap::CodeMap, _sp: RenderSpan, msg: &str, lvl: Level) { |
1a4d82fc JJ |
90 | remove_message(self, msg, lvl); |
91 | } | |
92 | } | |
93 | ||
92a42be0 | 94 | fn errors(msgs: &[&str]) -> (Box<Emitter + Send>, usize) { |
1a4d82fc | 95 | let v = msgs.iter().map(|m| m.to_string()).collect(); |
92a42be0 SL |
96 | (box ExpectErrorEmitter { messages: v } as Box<Emitter + Send>, |
97 | msgs.len()) | |
1a4d82fc JJ |
98 | } |
99 | ||
100 | fn test_env<F>(source_string: &str, | |
92a42be0 SL |
101 | (emitter, expected_err_count): (Box<Emitter + Send>, usize), |
102 | body: F) | |
103 | where F: FnOnce(Env) | |
1a4d82fc | 104 | { |
92a42be0 | 105 | let mut options = config::basic_options(); |
1a4d82fc | 106 | options.debugging_opts.verbose = true; |
62682a34 | 107 | options.unstable_features = UnstableFeatures::Allow; |
92a42be0 SL |
108 | let codemap = CodeMap::new(); |
109 | let diagnostic_handler = diagnostic::Handler::with_emitter(true, emitter); | |
110 | let span_diagnostic_handler = diagnostic::SpanHandler::new(diagnostic_handler, codemap); | |
111 | ||
112 | let cstore = Rc::new(CStore::new(token::get_ident_interner())); | |
113 | let sess = session::build_session_(options, None, span_diagnostic_handler, | |
114 | cstore.clone()); | |
c34b1796 | 115 | rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); |
1a4d82fc JJ |
116 | let krate_config = Vec::new(); |
117 | let input = config::Input::Str(source_string.to_string()); | |
118 | let krate = driver::phase_1_parse_input(&sess, krate_config, &input); | |
92a42be0 | 119 | let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None) |
1a4d82fc JJ |
120 | .expect("phase 2 aborted"); |
121 | ||
e9174d1e | 122 | let krate = driver::assign_node_ids(&sess, krate); |
b039eaaf SL |
123 | let lcx = LoweringContext::new(&sess, Some(&krate)); |
124 | let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate)); | |
85aaf69f | 125 | let arenas = ty::CtxtArenas::new(); |
e9174d1e | 126 | let ast_map = driver::make_map(&sess, &mut hir_forest); |
1a4d82fc JJ |
127 | let krate = ast_map.krate(); |
128 | ||
129 | // run just enough stuff to build a tcx: | |
b039eaaf | 130 | let lang_items = lang_items::collect_language_items(&sess, &ast_map); |
85aaf69f | 131 | let resolve::CrateMap { def_map, freevars, .. } = |
62682a34 | 132 | resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No); |
92a42be0 | 133 | let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map.borrow()); |
1a4d82fc | 134 | let region_map = region::resolve_crate(&sess, krate); |
b039eaaf | 135 | ty::ctxt::create_and_enter(&sess, |
c1a9b12d SL |
136 | &arenas, |
137 | def_map, | |
138 | named_region_map, | |
139 | ast_map, | |
140 | freevars, | |
141 | region_map, | |
142 | lang_items, | |
143 | stability::Index::new(krate), | |
144 | |tcx| { | |
92a42be0 SL |
145 | let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); |
146 | body(Env { infcx: &infcx }); | |
147 | let free_regions = FreeRegionMap::new(); | |
148 | infcx.resolve_regions_and_report_errors(&free_regions, | |
149 | ast::CRATE_NODE_ID); | |
150 | assert_eq!(tcx.sess.err_count(), expected_err_count); | |
151 | }); | |
1a4d82fc JJ |
152 | } |
153 | ||
154 | impl<'a, 'tcx> Env<'a, 'tcx> { | |
155 | pub fn tcx(&self) -> &ty::ctxt<'tcx> { | |
156 | self.infcx.tcx | |
157 | } | |
158 | ||
e9174d1e SL |
159 | pub fn create_region_hierarchy(&self, rh: &RH, parent: CodeExtent) { |
160 | let me = self.infcx.tcx.region_maps.intern_node(rh.id, parent); | |
85aaf69f | 161 | for child_rh in rh.sub { |
e9174d1e | 162 | self.create_region_hierarchy(child_rh, me); |
1a4d82fc JJ |
163 | } |
164 | } | |
165 | ||
166 | pub fn create_simple_region_hierarchy(&self) { | |
167 | // creates a region hierarchy where 1 is root, 10 and 11 are | |
168 | // children of 1, etc | |
92a42be0 SL |
169 | let dscope = self.infcx |
170 | .tcx | |
171 | .region_maps | |
172 | .intern_code_extent(CodeExtentData::DestructionScope(1), | |
173 | region::ROOT_CODE_EXTENT); | |
174 | self.create_region_hierarchy(&RH { | |
175 | id: 1, | |
176 | sub: &[RH { id: 10, sub: &[] }, RH { id: 11, sub: &[] }], | |
177 | }, | |
178 | dscope); | |
1a4d82fc JJ |
179 | } |
180 | ||
181 | #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now | |
182 | pub fn lookup_item(&self, names: &[String]) -> ast::NodeId { | |
183 | return match search_mod(self, &self.infcx.tcx.map.krate().module, 0, names) { | |
184 | Some(id) => id, | |
185 | None => { | |
c1a9b12d | 186 | panic!("no item found: `{}`", names.join("::")); |
1a4d82fc JJ |
187 | } |
188 | }; | |
189 | ||
190 | fn search_mod(this: &Env, | |
e9174d1e | 191 | m: &hir::Mod, |
c34b1796 | 192 | idx: usize, |
1a4d82fc JJ |
193 | names: &[String]) |
194 | -> Option<ast::NodeId> { | |
195 | assert!(idx < names.len()); | |
92a42be0 SL |
196 | for item in &m.item_ids { |
197 | let item = this.infcx.tcx.map.expect_item(item.id); | |
b039eaaf | 198 | if item.name.to_string() == names[idx] { |
92a42be0 | 199 | return search(this, item, idx + 1, names); |
1a4d82fc JJ |
200 | } |
201 | } | |
202 | return None; | |
203 | } | |
204 | ||
92a42be0 | 205 | fn search(this: &Env, it: &hir::Item, idx: usize, names: &[String]) -> Option<ast::NodeId> { |
1a4d82fc JJ |
206 | if idx == names.len() { |
207 | return Some(it.id); | |
208 | } | |
209 | ||
210 | return match it.node { | |
92a42be0 SL |
211 | hir::ItemUse(..) | |
212 | hir::ItemExternCrate(..) | | |
213 | hir::ItemConst(..) | | |
214 | hir::ItemStatic(..) | | |
215 | hir::ItemFn(..) | | |
216 | hir::ItemForeignMod(..) | | |
217 | hir::ItemTy(..) => { | |
1a4d82fc JJ |
218 | None |
219 | } | |
220 | ||
92a42be0 SL |
221 | hir::ItemEnum(..) | |
222 | hir::ItemStruct(..) | | |
223 | hir::ItemTrait(..) | | |
224 | hir::ItemImpl(..) | | |
e9174d1e | 225 | hir::ItemDefaultImpl(..) => { |
1a4d82fc JJ |
226 | None |
227 | } | |
228 | ||
e9174d1e | 229 | hir::ItemMod(ref m) => { |
1a4d82fc JJ |
230 | search_mod(this, m, idx, names) |
231 | } | |
232 | }; | |
233 | } | |
234 | } | |
235 | ||
236 | pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { | |
92a42be0 | 237 | match infer::mk_subty(self.infcx, true, TypeOrigin::Misc(DUMMY_SP), a, b) { |
1a4d82fc | 238 | Ok(_) => true, |
92a42be0 | 239 | Err(ref e) => panic!("Encountered error: {}", e), |
1a4d82fc JJ |
240 | } |
241 | } | |
242 | ||
243 | pub fn is_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { | |
244 | match infer::can_mk_subty(self.infcx, a, b) { | |
245 | Ok(_) => true, | |
92a42be0 | 246 | Err(_) => false, |
1a4d82fc JJ |
247 | } |
248 | } | |
249 | ||
250 | pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) { | |
251 | if !self.is_subtype(a, b) { | |
62682a34 | 252 | panic!("{} is not a subtype of {}, but it should be", a, b); |
1a4d82fc JJ |
253 | } |
254 | } | |
255 | ||
256 | pub fn assert_eq(&self, a: Ty<'tcx>, b: Ty<'tcx>) { | |
257 | self.assert_subtype(a, b); | |
258 | self.assert_subtype(b, a); | |
259 | } | |
260 | ||
92a42be0 | 261 | pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> { |
85aaf69f | 262 | let input_args = input_tys.iter().cloned().collect(); |
c1a9b12d | 263 | self.infcx.tcx.mk_fn(None, |
92a42be0 SL |
264 | self.infcx.tcx.mk_bare_fn(ty::BareFnTy { |
265 | unsafety: hir::Unsafety::Normal, | |
266 | abi: abi::Rust, | |
267 | sig: ty::Binder(ty::FnSig { | |
268 | inputs: input_args, | |
269 | output: ty::FnConverging(output_ty), | |
270 | variadic: false, | |
271 | }), | |
272 | })) | |
1a4d82fc JJ |
273 | } |
274 | ||
275 | pub fn t_nil(&self) -> Ty<'tcx> { | |
c1a9b12d | 276 | self.infcx.tcx.mk_nil() |
1a4d82fc JJ |
277 | } |
278 | ||
279 | pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> { | |
c1a9b12d | 280 | self.infcx.tcx.mk_tup(vec![ty1, ty2]) |
1a4d82fc JJ |
281 | } |
282 | ||
283 | pub fn t_param(&self, space: subst::ParamSpace, index: u32) -> Ty<'tcx> { | |
284 | let name = format!("T{}", index); | |
c1a9b12d | 285 | self.infcx.tcx.mk_param(space, index, token::intern(&name[..])) |
1a4d82fc JJ |
286 | } |
287 | ||
288 | pub fn re_early_bound(&self, | |
289 | space: subst::ParamSpace, | |
290 | index: u32, | |
291 | name: &'static str) | |
92a42be0 | 292 | -> ty::Region { |
1a4d82fc | 293 | let name = token::intern(name); |
9346a6ac | 294 | ty::ReEarlyBound(ty::EarlyBoundRegion { |
b039eaaf | 295 | def_id: self.infcx.tcx.map.local_def_id(ast::DUMMY_NODE_ID), |
9346a6ac AL |
296 | space: space, |
297 | index: index, | |
92a42be0 | 298 | name: name, |
9346a6ac | 299 | }) |
1a4d82fc JJ |
300 | } |
301 | ||
302 | pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) -> ty::Region { | |
303 | ty::ReLateBound(debruijn, ty::BrAnon(id)) | |
304 | } | |
305 | ||
306 | pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> { | |
92a42be0 | 307 | self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) |
1a4d82fc JJ |
308 | } |
309 | ||
310 | pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> { | |
311 | let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1)); | |
92a42be0 | 312 | self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) |
1a4d82fc JJ |
313 | } |
314 | ||
315 | pub fn t_rptr_late_bound_with_debruijn(&self, | |
316 | id: u32, | |
317 | debruijn: ty::DebruijnIndex) | |
318 | -> Ty<'tcx> { | |
319 | let r = self.re_late_bound_with_debruijn(id, debruijn); | |
92a42be0 | 320 | self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) |
1a4d82fc JJ |
321 | } |
322 | ||
323 | pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> { | |
e9174d1e | 324 | let r = ty::ReScope(self.tcx().region_maps.node_extent(id)); |
92a42be0 | 325 | self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) |
1a4d82fc JJ |
326 | } |
327 | ||
328 | pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region { | |
e9174d1e SL |
329 | ty::ReFree(ty::FreeRegion { |
330 | scope: self.tcx().region_maps.item_extent(nid), | |
92a42be0 | 331 | bound_region: ty::BrAnon(id), |
e9174d1e | 332 | }) |
1a4d82fc JJ |
333 | } |
334 | ||
335 | pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> { | |
336 | let r = self.re_free(nid, id); | |
92a42be0 | 337 | self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) |
1a4d82fc JJ |
338 | } |
339 | ||
340 | pub fn t_rptr_static(&self) -> Ty<'tcx> { | |
c1a9b12d | 341 | self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReStatic), |
92a42be0 | 342 | self.tcx().types.isize) |
1a4d82fc JJ |
343 | } |
344 | ||
b039eaaf SL |
345 | pub fn t_rptr_empty(&self) -> Ty<'tcx> { |
346 | self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty), | |
92a42be0 | 347 | self.tcx().types.isize) |
b039eaaf SL |
348 | } |
349 | ||
1a4d82fc JJ |
350 | pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> { |
351 | infer::TypeTrace::dummy(self.tcx()) | |
352 | } | |
353 | ||
354 | pub fn sub(&self) -> Sub<'a, 'tcx> { | |
355 | let trace = self.dummy_type_trace(); | |
c34b1796 | 356 | self.infcx.sub(true, trace) |
1a4d82fc JJ |
357 | } |
358 | ||
359 | pub fn lub(&self) -> Lub<'a, 'tcx> { | |
360 | let trace = self.dummy_type_trace(); | |
c34b1796 | 361 | self.infcx.lub(true, trace) |
1a4d82fc JJ |
362 | } |
363 | ||
364 | pub fn glb(&self) -> Glb<'a, 'tcx> { | |
365 | let trace = self.dummy_type_trace(); | |
c34b1796 | 366 | self.infcx.glb(true, trace) |
1a4d82fc JJ |
367 | } |
368 | ||
369 | pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> { | |
c34b1796 | 370 | match self.lub().relate(&t1, &t2) { |
1a4d82fc | 371 | Ok(t) => t, |
92a42be0 | 372 | Err(ref e) => panic!("unexpected error computing LUB: {}", e), |
1a4d82fc JJ |
373 | } |
374 | } | |
375 | ||
376 | /// Checks that `t1 <: t2` is true (this may register additional | |
377 | /// region checks). | |
378 | pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { | |
c34b1796 | 379 | match self.sub().relate(&t1, &t2) { |
92a42be0 | 380 | Ok(_) => {} |
1a4d82fc | 381 | Err(ref e) => { |
92a42be0 | 382 | panic!("unexpected error computing sub({:?},{:?}): {}", t1, t2, e); |
1a4d82fc JJ |
383 | } |
384 | } | |
385 | } | |
386 | ||
387 | /// Checks that `t1 <: t2` is false (this may register additional | |
388 | /// region checks). | |
389 | pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { | |
c34b1796 | 390 | match self.sub().relate(&t1, &t2) { |
92a42be0 | 391 | Err(_) => {} |
1a4d82fc | 392 | Ok(_) => { |
92a42be0 | 393 | panic!("unexpected success computing sub({:?},{:?})", t1, t2); |
1a4d82fc JJ |
394 | } |
395 | } | |
396 | } | |
397 | ||
398 | /// Checks that `LUB(t1,t2) == t_lub` | |
399 | pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { | |
c34b1796 | 400 | match self.lub().relate(&t1, &t2) { |
1a4d82fc JJ |
401 | Ok(t) => { |
402 | self.assert_eq(t, t_lub); | |
403 | } | |
404 | Err(ref e) => { | |
62682a34 | 405 | panic!("unexpected error in LUB: {}", e) |
1a4d82fc JJ |
406 | } |
407 | } | |
408 | } | |
409 | ||
410 | /// Checks that `GLB(t1,t2) == t_glb` | |
411 | pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) { | |
62682a34 | 412 | debug!("check_glb(t1={}, t2={}, t_glb={})", t1, t2, t_glb); |
c34b1796 | 413 | match self.glb().relate(&t1, &t2) { |
1a4d82fc JJ |
414 | Err(e) => { |
415 | panic!("unexpected error computing LUB: {:?}", e) | |
416 | } | |
417 | Ok(t) => { | |
418 | self.assert_eq(t, t_glb); | |
419 | ||
420 | // sanity check for good measure: | |
421 | self.assert_subtype(t, t1); | |
422 | self.assert_subtype(t, t2); | |
423 | } | |
424 | } | |
425 | } | |
426 | } | |
427 | ||
428 | #[test] | |
429 | fn contravariant_region_ptr_ok() { | |
430 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
431 | env.create_simple_region_hierarchy(); | |
432 | let t_rptr1 = env.t_rptr_scope(1); | |
433 | let t_rptr10 = env.t_rptr_scope(10); | |
434 | env.assert_eq(t_rptr1, t_rptr1); | |
435 | env.assert_eq(t_rptr10, t_rptr10); | |
436 | env.make_subtype(t_rptr1, t_rptr10); | |
437 | }) | |
438 | } | |
439 | ||
440 | #[test] | |
441 | fn contravariant_region_ptr_err() { | |
92a42be0 SL |
442 | test_env(EMPTY_SOURCE_STR, errors(&["lifetime mismatch"]), |env| { |
443 | env.create_simple_region_hierarchy(); | |
444 | let t_rptr1 = env.t_rptr_scope(1); | |
445 | let t_rptr10 = env.t_rptr_scope(10); | |
446 | env.assert_eq(t_rptr1, t_rptr1); | |
447 | env.assert_eq(t_rptr10, t_rptr10); | |
448 | ||
449 | // will cause an error when regions are resolved | |
450 | env.make_subtype(t_rptr10, t_rptr1); | |
451 | }) | |
1a4d82fc JJ |
452 | } |
453 | ||
454 | #[test] | |
455 | fn sub_free_bound_false() { | |
456 | //! Test that: | |
457 | //! | |
c34b1796 | 458 | //! fn(&'a isize) <: for<'b> fn(&'b isize) |
1a4d82fc JJ |
459 | //! |
460 | //! does NOT hold. | |
461 | ||
462 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
e9174d1e SL |
463 | env.create_simple_region_hierarchy(); |
464 | let t_rptr_free1 = env.t_rptr_free(1, 1); | |
1a4d82fc | 465 | let t_rptr_bound1 = env.t_rptr_late_bound(1); |
c34b1796 AL |
466 | env.check_not_sub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), |
467 | env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); | |
1a4d82fc JJ |
468 | }) |
469 | } | |
470 | ||
471 | #[test] | |
472 | fn sub_bound_free_true() { | |
473 | //! Test that: | |
474 | //! | |
c34b1796 | 475 | //! for<'a> fn(&'a isize) <: fn(&'b isize) |
1a4d82fc JJ |
476 | //! |
477 | //! DOES hold. | |
478 | ||
479 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
e9174d1e | 480 | env.create_simple_region_hierarchy(); |
1a4d82fc | 481 | let t_rptr_bound1 = env.t_rptr_late_bound(1); |
e9174d1e | 482 | let t_rptr_free1 = env.t_rptr_free(1, 1); |
c34b1796 AL |
483 | env.check_sub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), |
484 | env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); | |
1a4d82fc JJ |
485 | }) |
486 | } | |
487 | ||
488 | #[test] | |
489 | fn sub_free_bound_false_infer() { | |
490 | //! Test that: | |
491 | //! | |
c34b1796 | 492 | //! fn(_#1) <: for<'b> fn(&'b isize) |
1a4d82fc JJ |
493 | //! |
494 | //! does NOT hold for any instantiation of `_#1`. | |
495 | ||
496 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
497 | let t_infer1 = env.infcx.next_ty_var(); | |
498 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
c34b1796 AL |
499 | env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize), |
500 | env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); | |
1a4d82fc JJ |
501 | }) |
502 | } | |
503 | ||
504 | #[test] | |
505 | fn lub_free_bound_infer() { | |
506 | //! Test result of: | |
507 | //! | |
c34b1796 | 508 | //! LUB(fn(_#1), for<'b> fn(&'b isize)) |
1a4d82fc | 509 | //! |
c34b1796 AL |
510 | //! This should yield `fn(&'_ isize)`. We check |
511 | //! that it yields `fn(&'x isize)` for some free `'x`, | |
1a4d82fc JJ |
512 | //! anyhow. |
513 | ||
514 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
e9174d1e | 515 | env.create_simple_region_hierarchy(); |
1a4d82fc JJ |
516 | let t_infer1 = env.infcx.next_ty_var(); |
517 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
e9174d1e | 518 | let t_rptr_free1 = env.t_rptr_free(1, 1); |
c34b1796 AL |
519 | env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize), |
520 | env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), | |
521 | env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); | |
1a4d82fc JJ |
522 | }); |
523 | } | |
524 | ||
525 | #[test] | |
526 | fn lub_bound_bound() { | |
527 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
528 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
529 | let t_rptr_bound2 = env.t_rptr_late_bound(2); | |
c34b1796 AL |
530 | env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), |
531 | env.t_fn(&[t_rptr_bound2], env.tcx().types.isize), | |
532 | env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); | |
1a4d82fc JJ |
533 | }) |
534 | } | |
535 | ||
536 | #[test] | |
537 | fn lub_bound_free() { | |
538 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
e9174d1e | 539 | env.create_simple_region_hierarchy(); |
1a4d82fc | 540 | let t_rptr_bound1 = env.t_rptr_late_bound(1); |
e9174d1e | 541 | let t_rptr_free1 = env.t_rptr_free(1, 1); |
c34b1796 AL |
542 | env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), |
543 | env.t_fn(&[t_rptr_free1], env.tcx().types.isize), | |
544 | env.t_fn(&[t_rptr_free1], env.tcx().types.isize)); | |
1a4d82fc JJ |
545 | }) |
546 | } | |
547 | ||
548 | #[test] | |
549 | fn lub_bound_static() { | |
550 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
551 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
552 | let t_rptr_static = env.t_rptr_static(); | |
c34b1796 AL |
553 | env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), |
554 | env.t_fn(&[t_rptr_static], env.tcx().types.isize), | |
555 | env.t_fn(&[t_rptr_static], env.tcx().types.isize)); | |
1a4d82fc JJ |
556 | }) |
557 | } | |
558 | ||
559 | #[test] | |
560 | fn lub_bound_bound_inverse_order() { | |
561 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
562 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
563 | let t_rptr_bound2 = env.t_rptr_late_bound(2); | |
564 | env.check_lub(env.t_fn(&[t_rptr_bound1, t_rptr_bound2], t_rptr_bound1), | |
565 | env.t_fn(&[t_rptr_bound2, t_rptr_bound1], t_rptr_bound1), | |
566 | env.t_fn(&[t_rptr_bound1, t_rptr_bound1], t_rptr_bound1)); | |
567 | }) | |
568 | } | |
569 | ||
570 | #[test] | |
571 | fn lub_free_free() { | |
572 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
e9174d1e SL |
573 | env.create_simple_region_hierarchy(); |
574 | let t_rptr_free1 = env.t_rptr_free(1, 1); | |
575 | let t_rptr_free2 = env.t_rptr_free(1, 2); | |
1a4d82fc | 576 | let t_rptr_static = env.t_rptr_static(); |
c34b1796 AL |
577 | env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), |
578 | env.t_fn(&[t_rptr_free2], env.tcx().types.isize), | |
579 | env.t_fn(&[t_rptr_static], env.tcx().types.isize)); | |
1a4d82fc JJ |
580 | }) |
581 | } | |
582 | ||
583 | #[test] | |
584 | fn lub_returning_scope() { | |
b039eaaf SL |
585 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { |
586 | env.create_simple_region_hierarchy(); | |
587 | let t_rptr_scope10 = env.t_rptr_scope(10); | |
588 | let t_rptr_scope11 = env.t_rptr_scope(11); | |
589 | let t_rptr_empty = env.t_rptr_empty(); | |
590 | env.check_lub(env.t_fn(&[t_rptr_scope10], env.tcx().types.isize), | |
591 | env.t_fn(&[t_rptr_scope11], env.tcx().types.isize), | |
592 | env.t_fn(&[t_rptr_empty], env.tcx().types.isize)); | |
593 | }); | |
1a4d82fc JJ |
594 | } |
595 | ||
596 | #[test] | |
597 | fn glb_free_free_with_common_scope() { | |
598 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
e9174d1e SL |
599 | env.create_simple_region_hierarchy(); |
600 | let t_rptr_free1 = env.t_rptr_free(1, 1); | |
601 | let t_rptr_free2 = env.t_rptr_free(1, 2); | |
602 | let t_rptr_scope = env.t_rptr_scope(1); | |
c34b1796 AL |
603 | env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.isize), |
604 | env.t_fn(&[t_rptr_free2], env.tcx().types.isize), | |
605 | env.t_fn(&[t_rptr_scope], env.tcx().types.isize)); | |
1a4d82fc JJ |
606 | }) |
607 | } | |
608 | ||
609 | #[test] | |
610 | fn glb_bound_bound() { | |
611 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
612 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
613 | let t_rptr_bound2 = env.t_rptr_late_bound(2); | |
c34b1796 AL |
614 | env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), |
615 | env.t_fn(&[t_rptr_bound2], env.tcx().types.isize), | |
616 | env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); | |
1a4d82fc JJ |
617 | }) |
618 | } | |
619 | ||
620 | #[test] | |
621 | fn glb_bound_free() { | |
622 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
e9174d1e | 623 | env.create_simple_region_hierarchy(); |
1a4d82fc | 624 | let t_rptr_bound1 = env.t_rptr_late_bound(1); |
e9174d1e | 625 | let t_rptr_free1 = env.t_rptr_free(1, 1); |
c34b1796 AL |
626 | env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), |
627 | env.t_fn(&[t_rptr_free1], env.tcx().types.isize), | |
628 | env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); | |
1a4d82fc JJ |
629 | }) |
630 | } | |
631 | ||
632 | #[test] | |
633 | fn glb_bound_free_infer() { | |
634 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
635 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
636 | let t_infer1 = env.infcx.next_ty_var(); | |
637 | ||
c34b1796 AL |
638 | // compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize), |
639 | // which should yield for<'b> fn(&'b isize) -> isize | |
640 | env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), | |
641 | env.t_fn(&[t_infer1], env.tcx().types.isize), | |
642 | env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); | |
1a4d82fc JJ |
643 | |
644 | // as a side-effect, computing GLB should unify `_` with | |
c34b1796 | 645 | // `&'_ isize` |
1a4d82fc JJ |
646 | let t_resolve1 = env.infcx.shallow_resolve(t_infer1); |
647 | match t_resolve1.sty { | |
92a42be0 SL |
648 | ty::TyRef(..) => {} |
649 | _ => { | |
650 | panic!("t_resolve1={:?}", t_resolve1); | |
651 | } | |
1a4d82fc JJ |
652 | } |
653 | }) | |
654 | } | |
655 | ||
656 | #[test] | |
657 | fn glb_bound_static() { | |
658 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
659 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
660 | let t_rptr_static = env.t_rptr_static(); | |
c34b1796 AL |
661 | env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize), |
662 | env.t_fn(&[t_rptr_static], env.tcx().types.isize), | |
663 | env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); | |
1a4d82fc JJ |
664 | }) |
665 | } | |
666 | ||
667 | /// Test substituting a bound region into a function, which introduces another level of binding. | |
668 | /// This requires adjusting the Debruijn index. | |
669 | #[test] | |
670 | fn subst_ty_renumber_bound() { | |
671 | ||
672 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
673 | // Situation: | |
674 | // Theta = [A -> &'a foo] | |
675 | ||
676 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
677 | ||
678 | // t_source = fn(A) | |
679 | let t_source = { | |
680 | let t_param = env.t_param(subst::TypeSpace, 0); | |
681 | env.t_fn(&[t_param], env.t_nil()) | |
682 | }; | |
683 | ||
684 | let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]); | |
685 | let t_substituted = t_source.subst(env.infcx.tcx, &substs); | |
686 | ||
c34b1796 | 687 | // t_expected = fn(&'a isize) |
1a4d82fc JJ |
688 | let t_expected = { |
689 | let t_ptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2)); | |
690 | env.t_fn(&[t_ptr_bound2], env.t_nil()) | |
691 | }; | |
692 | ||
62682a34 SL |
693 | debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}", |
694 | t_source, | |
695 | substs, | |
696 | t_substituted, | |
697 | t_expected); | |
1a4d82fc JJ |
698 | |
699 | assert_eq!(t_substituted, t_expected); | |
700 | }) | |
701 | } | |
702 | ||
703 | /// Test substituting a bound region into a function, which introduces another level of binding. | |
704 | /// This requires adjusting the Debruijn index. | |
705 | #[test] | |
706 | fn subst_ty_renumber_some_bounds() { | |
707 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
708 | // Situation: | |
709 | // Theta = [A -> &'a foo] | |
710 | ||
711 | let t_rptr_bound1 = env.t_rptr_late_bound(1); | |
712 | ||
713 | // t_source = (A, fn(A)) | |
714 | let t_source = { | |
715 | let t_param = env.t_param(subst::TypeSpace, 0); | |
716 | env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil())) | |
717 | }; | |
718 | ||
719 | let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]); | |
720 | let t_substituted = t_source.subst(env.infcx.tcx, &substs); | |
721 | ||
c34b1796 | 722 | // t_expected = (&'a isize, fn(&'a isize)) |
1a4d82fc JJ |
723 | // |
724 | // but not that the Debruijn index is different in the different cases. | |
725 | let t_expected = { | |
726 | let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2)); | |
727 | env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil())) | |
728 | }; | |
729 | ||
62682a34 SL |
730 | debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}", |
731 | t_source, | |
732 | substs, | |
733 | t_substituted, | |
734 | t_expected); | |
1a4d82fc JJ |
735 | |
736 | assert_eq!(t_substituted, t_expected); | |
737 | }) | |
738 | } | |
739 | ||
740 | /// Test that we correctly compute whether a type has escaping regions or not. | |
741 | #[test] | |
742 | fn escaping() { | |
743 | ||
744 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
745 | // Situation: | |
746 | // Theta = [A -> &'a foo] | |
e9174d1e | 747 | env.create_simple_region_hierarchy(); |
1a4d82fc | 748 | |
c1a9b12d | 749 | assert!(!env.t_nil().has_escaping_regions()); |
1a4d82fc | 750 | |
e9174d1e | 751 | let t_rptr_free1 = env.t_rptr_free(1, 1); |
c1a9b12d | 752 | assert!(!t_rptr_free1.has_escaping_regions()); |
1a4d82fc JJ |
753 | |
754 | let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)); | |
c1a9b12d | 755 | assert!(t_rptr_bound1.has_escaping_regions()); |
1a4d82fc JJ |
756 | |
757 | let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2)); | |
c1a9b12d | 758 | assert!(t_rptr_bound2.has_escaping_regions()); |
1a4d82fc JJ |
759 | |
760 | // t_fn = fn(A) | |
761 | let t_param = env.t_param(subst::TypeSpace, 0); | |
c1a9b12d | 762 | assert!(!t_param.has_escaping_regions()); |
1a4d82fc | 763 | let t_fn = env.t_fn(&[t_param], env.t_nil()); |
c1a9b12d | 764 | assert!(!t_fn.has_escaping_regions()); |
1a4d82fc JJ |
765 | }) |
766 | } | |
767 | ||
768 | /// Test applying a substitution where the value being substituted for an early-bound region is a | |
769 | /// late-bound region. | |
770 | #[test] | |
771 | fn subst_region_renumber_region() { | |
772 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
773 | let re_bound1 = env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)); | |
774 | ||
c34b1796 | 775 | // type t_source<'a> = fn(&'a isize) |
1a4d82fc JJ |
776 | let t_source = { |
777 | let re_early = env.re_early_bound(subst::TypeSpace, 0, "'a"); | |
778 | env.t_fn(&[env.t_rptr(re_early)], env.t_nil()) | |
779 | }; | |
780 | ||
781 | let substs = subst::Substs::new_type(vec![], vec![re_bound1]); | |
782 | let t_substituted = t_source.subst(env.infcx.tcx, &substs); | |
783 | ||
c34b1796 | 784 | // t_expected = fn(&'a isize) |
1a4d82fc JJ |
785 | // |
786 | // but not that the Debruijn index is different in the different cases. | |
787 | let t_expected = { | |
788 | let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2)); | |
789 | env.t_fn(&[t_rptr_bound2], env.t_nil()) | |
790 | }; | |
791 | ||
62682a34 SL |
792 | debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}", |
793 | t_source, | |
794 | substs, | |
795 | t_substituted, | |
796 | t_expected); | |
1a4d82fc JJ |
797 | |
798 | assert_eq!(t_substituted, t_expected); | |
799 | }) | |
800 | } | |
801 | ||
802 | #[test] | |
803 | fn walk_ty() { | |
804 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
805 | let tcx = env.infcx.tcx; | |
c34b1796 AL |
806 | let int_ty = tcx.types.isize; |
807 | let uint_ty = tcx.types.usize; | |
92a42be0 SL |
808 | let tup1_ty = tcx.mk_tup(vec![int_ty, uint_ty, int_ty, uint_ty]); |
809 | let tup2_ty = tcx.mk_tup(vec![tup1_ty, tup1_ty, uint_ty]); | |
c1a9b12d | 810 | let uniq_ty = tcx.mk_box(tup2_ty); |
1a4d82fc | 811 | let walked: Vec<_> = uniq_ty.walk().collect(); |
92a42be0 SL |
812 | assert_eq!(walked, |
813 | [uniq_ty, tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty, | |
814 | uint_ty, int_ty, uint_ty, uint_ty]); | |
1a4d82fc JJ |
815 | }) |
816 | } | |
817 | ||
818 | #[test] | |
819 | fn walk_ty_skip_subtree() { | |
820 | test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { | |
821 | let tcx = env.infcx.tcx; | |
c34b1796 AL |
822 | let int_ty = tcx.types.isize; |
823 | let uint_ty = tcx.types.usize; | |
92a42be0 SL |
824 | let tup1_ty = tcx.mk_tup(vec![int_ty, uint_ty, int_ty, uint_ty]); |
825 | let tup2_ty = tcx.mk_tup(vec![tup1_ty, tup1_ty, uint_ty]); | |
c1a9b12d | 826 | let uniq_ty = tcx.mk_box(tup2_ty); |
1a4d82fc JJ |
827 | |
828 | // types we expect to see (in order), plus a boolean saying | |
829 | // whether to skip the subtree. | |
92a42be0 | 830 | let mut expected = vec![(uniq_ty, false), |
1a4d82fc JJ |
831 | (tup2_ty, false), |
832 | (tup1_ty, false), | |
833 | (int_ty, false), | |
834 | (uint_ty, false), | |
835 | (int_ty, false), | |
836 | (uint_ty, false), | |
c34b1796 | 837 | (tup1_ty, true), // skip the isize/usize/isize/usize |
92a42be0 | 838 | (uint_ty, false)]; |
1a4d82fc JJ |
839 | expected.reverse(); |
840 | ||
841 | let mut walker = uniq_ty.walk(); | |
842 | while let Some(t) = walker.next() { | |
843 | debug!("walked to {:?}", t); | |
844 | let (expected_ty, skip) = expected.pop().unwrap(); | |
845 | assert_eq!(t, expected_ty); | |
92a42be0 SL |
846 | if skip { |
847 | walker.skip_current_subtree(); | |
848 | } | |
1a4d82fc JJ |
849 | } |
850 | ||
851 | assert!(expected.is_empty()); | |
852 | }) | |
853 | } |