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.
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.
13 # Standalone Tests for the Inference Module
17 // This is only used by tests, hence allow dead code.
21 use driver::diagnostic;
22 use driver::diagnostic::Emitter;
25 use middle::lang_items;
28 use middle::resolve_lifetime;
29 use middle::stability;
31 use middle::typeck::infer::combine::Combine;
32 use middle::typeck::infer;
33 use middle::typeck::infer::lub::Lub;
34 use middle::typeck::infer::glb::Glb;
36 use syntax::codemap::{Span, CodeMap, DUMMY_SP};
37 use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note};
38 use syntax::{ast, ast_map};
39 use util::ppaux::{ty_to_string, UserString};
41 use arena::TypedArena;
43 struct Env<'a, 'tcx: 'a> {
44 infcx: &'a infer::InferCtxt<'a, 'tcx>,
52 static EMPTY_SOURCE_STR: &'static str = "#![no_std]";
54 struct ExpectErrorEmitter {
58 fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
60 Bug | Fatal | Error => { }
61 Warning | Note => { return; }
64 debug!("Error: {}", msg);
65 match e.messages.iter().position(|m| msg.contains(m.as_slice())) {
70 fail!("Unexpected error: {} Expected: {}",
76 impl Emitter for ExpectErrorEmitter {
78 _cmsp: Option<(&codemap::CodeMap, Span)>,
83 remove_message(self, msg, lvl);
86 fn custom_emit(&mut self,
87 _cm: &codemap::CodeMap,
92 remove_message(self, msg, lvl);
96 fn errors(msgs: &[&str]) -> (Box<Emitter+Send>, uint) {
97 let v = msgs.iter().map(|m| m.to_string()).collect();
98 (box ExpectErrorEmitter { messages: v } as Box<Emitter+Send>, msgs.len())
101 fn test_env(_test_name: &str,
103 (emitter, expected_err_count): (Box<Emitter+Send>, uint),
106 config::basic_options();
109 let diagnostic_handler =
110 diagnostic::mk_handler(emitter);
111 let span_diagnostic_handler =
112 diagnostic::mk_span_handler(diagnostic_handler, codemap);
114 let sess = session::build_session_(options, None, span_diagnostic_handler);
115 let krate_config = Vec::new();
116 let input = driver::StrInput(source_string.to_string());
117 let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
118 let krate = driver::phase_2_configure_and_expand(&sess, krate, "test", None)
119 .expect("phase 2 aborted");
121 let mut forest = ast_map::Forest::new(krate);
122 let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);
123 let krate = ast_map.krate();
125 // run just enough stuff to build a tcx:
126 let lang_items = lang_items::collect_language_items(krate, &sess);
127 let resolve::CrateMap { def_map, freevars, capture_mode_map, .. } =
128 resolve::resolve_crate(&sess, &lang_items, krate);
129 let named_region_map = resolve_lifetime::krate(&sess, krate);
130 let region_map = region::resolve_crate(&sess, krate);
131 let stability_index = stability::Index::build(krate);
132 let type_arena = TypedArena::new();
133 let tcx = ty::mk_ctxt(sess,
143 let infcx = infer::new_infer_ctxt(&tcx);
144 body(Env { infcx: &infcx });
145 infcx.resolve_regions_and_report_errors();
146 assert_eq!(tcx.sess.err_count(), expected_err_count);
149 impl<'a, 'tcx> Env<'a, 'tcx> {
150 pub fn create_region_hierarchy(&self, rh: &RH) {
151 for child_rh in rh.sub.iter() {
152 self.create_region_hierarchy(child_rh);
153 self.infcx.tcx.region_maps.record_encl_scope(child_rh.id, rh.id);
157 pub fn create_simple_region_hierarchy(&self) {
158 // creates a region hierarchy where 1 is root, 10 and 11 are
159 // children of 1, etc
160 self.create_region_hierarchy(
168 pub fn lookup_item(&self, names: &[String]) -> ast::NodeId {
169 return match search_mod(self, &self.infcx.tcx.map.krate().module, 0, names) {
172 fail!("no item found: `{}`", names.connect("::"));
176 fn search_mod(this: &Env,
180 -> Option<ast::NodeId> {
181 assert!(idx < names.len());
182 for item in m.items.iter() {
183 if item.ident.user_string(this.infcx.tcx) == names[idx] {
184 return search(this, &**item, idx+1, names);
190 fn search(this: &Env,
194 -> Option<ast::NodeId> {
195 if idx == names.len() {
199 return match it.node {
200 ast::ItemStatic(..) | ast::ItemFn(..) |
201 ast::ItemForeignMod(..) | ast::ItemTy(..) => {
205 ast::ItemEnum(..) | ast::ItemStruct(..) |
206 ast::ItemTrait(..) | ast::ItemImpl(..) |
207 ast::ItemMac(..) => {
211 ast::ItemMod(ref m) => {
212 search_mod(this, m, idx, names)
218 pub fn make_subtype(&self, a: ty::t, b: ty::t) -> bool {
219 match infer::mk_subty(self.infcx, true, infer::Misc(DUMMY_SP), a, b) {
221 Err(ref e) => fail!("Encountered error: {}",
222 ty::type_err_to_str(self.infcx.tcx, e))
226 pub fn is_subtype(&self, a: ty::t, b: ty::t) -> bool {
227 match infer::can_mk_subty(self.infcx, a, b) {
233 pub fn assert_subtype(&self, a: ty::t, b: ty::t) {
234 if !self.is_subtype(a, b) {
235 fail!("{} is not a subtype of {}, but it should be",
236 self.ty_to_string(a),
237 self.ty_to_string(b));
241 pub fn assert_not_subtype(&self, a: ty::t, b: ty::t) {
242 if self.is_subtype(a, b) {
243 fail!("{} is a subtype of {}, but it shouldn't be",
244 self.ty_to_string(a),
245 self.ty_to_string(b));
249 pub fn assert_eq(&self, a: ty::t, b: ty::t) {
250 self.assert_subtype(a, b);
251 self.assert_subtype(b, a);
254 pub fn ty_to_string(&self, a: ty::t) -> String {
255 ty_to_string(self.infcx.tcx, a)
259 binder_id: ast::NodeId,
264 ty::mk_ctor_fn(self.infcx.tcx, binder_id, input_tys, output_ty)
267 pub fn t_int(&self) -> ty::t {
271 pub fn t_rptr_late_bound(&self, binder_id: ast::NodeId, id: uint) -> ty::t {
272 ty::mk_imm_rptr(self.infcx.tcx, ty::ReLateBound(binder_id, ty::BrAnon(id)),
276 pub fn t_rptr_scope(&self, id: ast::NodeId) -> ty::t {
277 ty::mk_imm_rptr(self.infcx.tcx, ty::ReScope(id), self.t_int())
280 pub fn t_rptr_free(&self, nid: ast::NodeId, id: uint) -> ty::t {
281 ty::mk_imm_rptr(self.infcx.tcx,
282 ty::ReFree(ty::FreeRegion {scope_id: nid,
283 bound_region: ty::BrAnon(id)}),
287 pub fn t_rptr_static(&self) -> ty::t {
288 ty::mk_imm_rptr(self.infcx.tcx, ty::ReStatic, self.t_int())
291 pub fn dummy_type_trace(&self) -> infer::TypeTrace {
293 origin: infer::Misc(DUMMY_SP),
294 values: infer::Types(ty::expected_found {
295 expected: ty::mk_err(),
301 pub fn lub(&self) -> Lub<'a, 'tcx> {
302 let trace = self.dummy_type_trace();
303 Lub(self.infcx.combine_fields(true, trace))
306 pub fn glb(&self) -> Glb<'a, 'tcx> {
307 let trace = self.dummy_type_trace();
308 Glb(self.infcx.combine_fields(true, trace))
311 pub fn resolve_regions(&self) {
312 self.infcx.resolve_regions_and_report_errors();
315 pub fn make_lub_ty(&self, t1: ty::t, t2: ty::t) -> ty::t {
316 match self.lub().tys(t1, t2) {
318 Err(ref e) => fail!("unexpected error computing LUB: {:?}",
319 ty::type_err_to_str(self.infcx.tcx, e))
323 /// Checks that `LUB(t1,t2) == t_lub`
324 pub fn check_lub(&self, t1: ty::t, t2: ty::t, t_lub: ty::t) {
325 match self.lub().tys(t1, t2) {
327 self.assert_eq(t, t_lub);
330 fail!("unexpected error in LUB: {}",
331 ty::type_err_to_str(self.infcx.tcx, e))
336 /// Checks that `GLB(t1,t2) == t_glb`
337 pub fn check_glb(&self, t1: ty::t, t2: ty::t, t_glb: ty::t) {
338 debug!("check_glb(t1={}, t2={}, t_glb={})",
339 self.ty_to_string(t1),
340 self.ty_to_string(t2),
341 self.ty_to_string(t_glb));
342 match self.glb().tys(t1, t2) {
344 fail!("unexpected error computing LUB: {:?}", e)
347 self.assert_eq(t, t_glb);
349 // sanity check for good measure:
350 self.assert_subtype(t, t1);
351 self.assert_subtype(t, t2);
356 /// Checks that `LUB(t1,t2)` is undefined
357 pub fn check_no_lub(&self, t1: ty::t, t2: ty::t) {
358 match self.lub().tys(t1, t2) {
361 fail!("unexpected success computing LUB: {}", self.ty_to_string(t))
366 /// Checks that `GLB(t1,t2)` is undefined
367 pub fn check_no_glb(&self, t1: ty::t, t2: ty::t) {
368 match self.glb().tys(t1, t2) {
371 fail!("unexpected success computing GLB: {}", self.ty_to_string(t))
378 fn contravariant_region_ptr_ok() {
379 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
380 env.create_simple_region_hierarchy();
381 let t_rptr1 = env.t_rptr_scope(1);
382 let t_rptr10 = env.t_rptr_scope(10);
383 env.assert_eq(t_rptr1, t_rptr1);
384 env.assert_eq(t_rptr10, t_rptr10);
385 env.make_subtype(t_rptr1, t_rptr10);
390 fn contravariant_region_ptr_err() {
391 test_env("contravariant_region_ptr",
393 errors(["lifetime mismatch"]),
395 env.create_simple_region_hierarchy();
396 let t_rptr1 = env.t_rptr_scope(1);
397 let t_rptr10 = env.t_rptr_scope(10);
398 env.assert_eq(t_rptr1, t_rptr1);
399 env.assert_eq(t_rptr10, t_rptr10);
401 // will cause an error when regions are resolved
402 env.make_subtype(t_rptr10, t_rptr1);
407 fn lub_bound_bound() {
408 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
409 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
410 let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
411 env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()),
412 env.t_fn(22, [t_rptr_bound2], env.t_int()),
413 env.t_fn(22, [t_rptr_bound1], env.t_int()));
418 fn lub_bound_free() {
419 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
420 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
421 let t_rptr_free1 = env.t_rptr_free(0, 1);
422 env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()),
423 env.t_fn(22, [t_rptr_free1], env.t_int()),
424 env.t_fn(22, [t_rptr_free1], env.t_int()));
429 fn lub_bound_static() {
430 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
431 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
432 let t_rptr_static = env.t_rptr_static();
433 env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()),
434 env.t_fn(22, [t_rptr_static], env.t_int()),
435 env.t_fn(22, [t_rptr_static], env.t_int()));
440 fn lub_bound_bound_inverse_order() {
441 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
442 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
443 let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
444 env.check_lub(env.t_fn(22, [t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
445 env.t_fn(22, [t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
446 env.t_fn(22, [t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
452 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
453 let t_rptr_free1 = env.t_rptr_free(0, 1);
454 let t_rptr_free2 = env.t_rptr_free(0, 2);
455 let t_rptr_static = env.t_rptr_static();
456 env.check_lub(env.t_fn(22, [t_rptr_free1], env.t_int()),
457 env.t_fn(22, [t_rptr_free2], env.t_int()),
458 env.t_fn(22, [t_rptr_static], env.t_int()));
463 fn lub_returning_scope() {
464 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR,
465 errors(["cannot infer an appropriate lifetime"]), |env| {
466 let t_rptr_scope10 = env.t_rptr_scope(10);
467 let t_rptr_scope11 = env.t_rptr_scope(11);
469 // this should generate an error when regions are resolved
470 env.make_lub_ty(env.t_fn(22, [], t_rptr_scope10),
471 env.t_fn(22, [], t_rptr_scope11));
476 fn glb_free_free_with_common_scope() {
477 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
478 let t_rptr_free1 = env.t_rptr_free(0, 1);
479 let t_rptr_free2 = env.t_rptr_free(0, 2);
480 let t_rptr_scope = env.t_rptr_scope(0);
481 env.check_glb(env.t_fn(22, [t_rptr_free1], env.t_int()),
482 env.t_fn(22, [t_rptr_free2], env.t_int()),
483 env.t_fn(22, [t_rptr_scope], env.t_int()));
488 fn glb_bound_bound() {
489 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
490 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
491 let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
492 env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()),
493 env.t_fn(22, [t_rptr_bound2], env.t_int()),
494 env.t_fn(22, [t_rptr_bound1], env.t_int()));
499 fn glb_bound_free() {
500 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
501 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
502 let t_rptr_free1 = env.t_rptr_free(0, 1);
503 env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()),
504 env.t_fn(22, [t_rptr_free1], env.t_int()),
505 env.t_fn(22, [t_rptr_bound1], env.t_int()));
510 fn glb_bound_static() {
511 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
512 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
513 let t_rptr_static = env.t_rptr_static();
514 env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()),
515 env.t_fn(22, [t_rptr_static], env.t_int()),
516 env.t_fn(22, [t_rptr_bound1], env.t_int()));