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;
26 use middle::lang_items;
29 use middle::resolve_lifetime;
30 use middle::stability;
32 use middle::typeck::infer::combine::Combine;
33 use middle::typeck::infer;
34 use middle::typeck::infer::lub::Lub;
35 use middle::typeck::infer::glb::Glb;
37 use syntax::codemap::{Span, CodeMap, DUMMY_SP};
38 use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note};
40 use syntax::crateid::CrateId;
41 use util::ppaux::{ty_to_str, UserString};
46 infcx: &'a infer::InferCtxt<'a>,
54 static EMPTY_SOURCE_STR: &'static str = "#![no_std]";
56 struct ExpectErrorEmitter {
60 fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
62 Bug | Fatal | Error => { }
63 Warning | Note => { return; }
66 debug!("Error: {}", msg);
67 match e.messages.iter().position(|m| msg.contains(m.as_slice())) {
72 fail!("Unexpected error: {} Expected: {}",
78 impl Emitter for ExpectErrorEmitter {
80 _cmsp: Option<(&codemap::CodeMap, Span)>,
84 remove_message(self, msg, lvl);
87 fn custom_emit(&mut self,
88 _cm: &codemap::CodeMap,
93 remove_message(self, msg, lvl);
97 fn errors(msgs: &[&str]) -> (Box<Emitter+Send>, uint) {
98 let v = Vec::from_fn(msgs.len(), |i| msgs[i].to_owned());
99 (box ExpectErrorEmitter { messages: v } as Box<Emitter+Send>, msgs.len())
102 fn test_env(_test_name: &str,
104 (emitter, expected_err_count): (Box<Emitter+Send>, uint),
107 config::basic_options();
110 let diagnostic_handler =
111 diagnostic::mk_handler(emitter);
112 let span_diagnostic_handler =
113 diagnostic::mk_span_handler(diagnostic_handler, codemap);
115 let sess = session::build_session_(options, None, span_diagnostic_handler);
116 let krate_config = Vec::new();
117 let input = driver::StrInput(source_string.to_owned());
118 let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
119 let krate_id = CrateId { path: "test".to_owned(),
120 name: "test".to_owned(),
122 let (krate, ast_map) =
123 driver::phase_2_configure_and_expand(&sess, krate, &krate_id);
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: def_map, .. } =
128 resolve::resolve_crate(&sess, &lang_items, &krate);
129 let freevars_map = freevars::annotate_freevars(&def_map, &krate);
130 let named_region_map = resolve_lifetime::krate(&sess, &krate);
131 let region_map = region::resolve_crate(&sess, &krate);
132 let stability_index = stability::Index::build(&krate);
133 let tcx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
134 freevars_map, region_map, lang_items, stability_index);
135 let infcx = infer::new_infer_ctxt(&tcx);
136 let env = Env {krate: krate,
140 infcx.resolve_regions_and_report_errors();
141 assert_eq!(tcx.sess.err_count(), expected_err_count);
145 pub fn create_region_hierarchy(&self, rh: &RH) {
146 for child_rh in rh.sub.iter() {
147 self.create_region_hierarchy(child_rh);
148 self.tcx.region_maps.record_encl_scope(child_rh.id, rh.id);
152 pub fn create_simple_region_hierarchy(&self) {
153 // creates a region hierarchy where 1 is root, 10 and 11 are
154 // children of 1, etc
155 self.create_region_hierarchy(
163 pub fn lookup_item(&self, names: &[String]) -> ast::NodeId {
164 return match search_mod(self, &self.krate.module, 0, names) {
167 fail!("no item found: `{}`", names.connect("::"));
171 fn search_mod(this: &Env,
175 -> Option<ast::NodeId> {
176 assert!(idx < names.len());
177 for item in m.items.iter() {
178 if item.ident.user_string(this.tcx) == names[idx] {
179 return search(this, *item, idx+1, names);
185 fn search(this: &Env,
189 -> Option<ast::NodeId> {
190 if idx == names.len() {
194 return match it.node {
195 ast::ItemStatic(..) | ast::ItemFn(..) |
196 ast::ItemForeignMod(..) | ast::ItemTy(..) => {
200 ast::ItemEnum(..) | ast::ItemStruct(..) |
201 ast::ItemTrait(..) | ast::ItemImpl(..) |
202 ast::ItemMac(..) => {
206 ast::ItemMod(ref m) => {
207 search_mod(this, m, idx, names)
213 pub fn make_subtype(&self, a: ty::t, b: ty::t) -> bool {
214 match infer::mk_subty(self.infcx, true, infer::Misc(DUMMY_SP), a, b) {
216 Err(ref e) => fail!("Encountered error: {}",
217 ty::type_err_to_str(self.tcx, e))
221 pub fn is_subtype(&self, a: ty::t, b: ty::t) -> bool {
222 match infer::can_mk_subty(self.infcx, a, b) {
228 pub fn assert_subtype(&self, a: ty::t, b: ty::t) {
229 if !self.is_subtype(a, b) {
230 fail!("{} is not a subtype of {}, but it should be",
236 pub fn assert_not_subtype(&self, a: ty::t, b: ty::t) {
237 if self.is_subtype(a, b) {
238 fail!("{} is a subtype of {}, but it shouldn't be",
244 pub fn assert_eq(&self, a: ty::t, b: ty::t) {
245 self.assert_subtype(a, b);
246 self.assert_subtype(b, a);
249 pub fn ty_to_str(&self, a: ty::t) -> String {
250 ty_to_str(self.tcx, a)
254 binder_id: ast::NodeId,
259 ty::mk_ctor_fn(self.tcx, binder_id, input_tys, output_ty)
262 pub fn t_int(&self) -> ty::t {
266 pub fn t_rptr_late_bound(&self, binder_id: ast::NodeId, id: uint) -> ty::t {
267 ty::mk_imm_rptr(self.tcx, ty::ReLateBound(binder_id, ty::BrAnon(id)),
271 pub fn t_rptr_scope(&self, id: ast::NodeId) -> ty::t {
272 ty::mk_imm_rptr(self.tcx, ty::ReScope(id), self.t_int())
275 pub fn t_rptr_free(&self, nid: ast::NodeId, id: uint) -> ty::t {
276 ty::mk_imm_rptr(self.tcx,
277 ty::ReFree(ty::FreeRegion {scope_id: nid,
278 bound_region: ty::BrAnon(id)}),
282 pub fn t_rptr_static(&self) -> ty::t {
283 ty::mk_imm_rptr(self.tcx, ty::ReStatic, self.t_int())
286 pub fn dummy_type_trace(&self) -> infer::TypeTrace {
288 origin: infer::Misc(DUMMY_SP),
289 values: infer::Types(ty::expected_found {
290 expected: ty::mk_err(),
296 pub fn lub(&self) -> Lub<'a> {
297 let trace = self.dummy_type_trace();
298 Lub(self.infcx.combine_fields(true, trace))
301 pub fn glb(&self) -> Glb<'a> {
302 let trace = self.dummy_type_trace();
303 Glb(self.infcx.combine_fields(true, trace))
306 pub fn resolve_regions(&self) {
307 self.infcx.resolve_regions_and_report_errors();
310 pub fn make_lub_ty(&self, t1: ty::t, t2: ty::t) -> ty::t {
311 match self.lub().tys(t1, t2) {
313 Err(ref e) => fail!("unexpected error computing LUB: {:?}",
314 ty::type_err_to_str(self.tcx, e))
318 /// Checks that `LUB(t1,t2) == t_lub`
319 pub fn check_lub(&self, t1: ty::t, t2: ty::t, t_lub: ty::t) {
320 match self.lub().tys(t1, t2) {
322 self.assert_eq(t, t_lub);
325 fail!("unexpected error in LUB: {}",
326 ty::type_err_to_str(self.tcx, e))
331 /// Checks that `GLB(t1,t2) == t_glb`
332 pub fn check_glb(&self, t1: ty::t, t2: ty::t, t_glb: ty::t) {
333 debug!("check_glb(t1={}, t2={}, t_glb={})",
336 self.ty_to_str(t_glb));
337 match self.glb().tys(t1, t2) {
339 fail!("unexpected error computing LUB: {:?}", e)
342 self.assert_eq(t, t_glb);
344 // sanity check for good measure:
345 self.assert_subtype(t, t1);
346 self.assert_subtype(t, t2);
351 /// Checks that `LUB(t1,t2)` is undefined
352 pub fn check_no_lub(&self, t1: ty::t, t2: ty::t) {
353 match self.lub().tys(t1, t2) {
356 fail!("unexpected success computing LUB: {}", self.ty_to_str(t))
361 /// Checks that `GLB(t1,t2)` is undefined
362 pub fn check_no_glb(&self, t1: ty::t, t2: ty::t) {
363 match self.glb().tys(t1, t2) {
366 fail!("unexpected success computing GLB: {}", self.ty_to_str(t))
373 fn contravariant_region_ptr_ok() {
374 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
375 env.create_simple_region_hierarchy();
376 let t_rptr1 = env.t_rptr_scope(1);
377 let t_rptr10 = env.t_rptr_scope(10);
378 env.assert_eq(t_rptr1, t_rptr1);
379 env.assert_eq(t_rptr10, t_rptr10);
380 env.make_subtype(t_rptr1, t_rptr10);
385 fn contravariant_region_ptr_err() {
386 test_env("contravariant_region_ptr",
388 errors(["lifetime mismatch"]),
390 env.create_simple_region_hierarchy();
391 let t_rptr1 = env.t_rptr_scope(1);
392 let t_rptr10 = env.t_rptr_scope(10);
393 env.assert_eq(t_rptr1, t_rptr1);
394 env.assert_eq(t_rptr10, t_rptr10);
396 // will cause an error when regions are resolved
397 env.make_subtype(t_rptr10, t_rptr1);
402 fn lub_bound_bound() {
403 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
404 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
405 let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
406 env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()),
407 env.t_fn(22, [t_rptr_bound2], env.t_int()),
408 env.t_fn(22, [t_rptr_bound1], env.t_int()));
413 fn lub_bound_free() {
414 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
415 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
416 let t_rptr_free1 = env.t_rptr_free(0, 1);
417 env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()),
418 env.t_fn(22, [t_rptr_free1], env.t_int()),
419 env.t_fn(22, [t_rptr_free1], env.t_int()));
424 fn lub_bound_static() {
425 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
426 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
427 let t_rptr_static = env.t_rptr_static();
428 env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()),
429 env.t_fn(22, [t_rptr_static], env.t_int()),
430 env.t_fn(22, [t_rptr_static], env.t_int()));
435 fn lub_bound_bound_inverse_order() {
436 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
437 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
438 let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
439 env.check_lub(env.t_fn(22, [t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
440 env.t_fn(22, [t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
441 env.t_fn(22, [t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
447 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
448 let t_rptr_free1 = env.t_rptr_free(0, 1);
449 let t_rptr_free2 = env.t_rptr_free(0, 2);
450 let t_rptr_static = env.t_rptr_static();
451 env.check_lub(env.t_fn(22, [t_rptr_free1], env.t_int()),
452 env.t_fn(22, [t_rptr_free2], env.t_int()),
453 env.t_fn(22, [t_rptr_static], env.t_int()));
458 fn lub_returning_scope() {
459 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR,
460 errors(["cannot infer an appropriate lifetime"]), |env| {
461 let t_rptr_scope10 = env.t_rptr_scope(10);
462 let t_rptr_scope11 = env.t_rptr_scope(11);
464 // this should generate an error when regions are resolved
465 env.make_lub_ty(env.t_fn(22, [], t_rptr_scope10),
466 env.t_fn(22, [], t_rptr_scope11));
471 fn glb_free_free_with_common_scope() {
472 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
473 let t_rptr_free1 = env.t_rptr_free(0, 1);
474 let t_rptr_free2 = env.t_rptr_free(0, 2);
475 let t_rptr_scope = env.t_rptr_scope(0);
476 env.check_glb(env.t_fn(22, [t_rptr_free1], env.t_int()),
477 env.t_fn(22, [t_rptr_free2], env.t_int()),
478 env.t_fn(22, [t_rptr_scope], env.t_int()));
483 fn glb_bound_bound() {
484 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
485 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
486 let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
487 env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()),
488 env.t_fn(22, [t_rptr_bound2], env.t_int()),
489 env.t_fn(22, [t_rptr_bound1], env.t_int()));
494 fn glb_bound_free() {
495 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
496 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
497 let t_rptr_free1 = env.t_rptr_free(0, 1);
498 env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()),
499 env.t_fn(22, [t_rptr_free1], env.t_int()),
500 env.t_fn(22, [t_rptr_bound1], env.t_int()));
505 fn glb_bound_static() {
506 test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
507 let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
508 let t_rptr_static = env.t_rptr_static();
509 env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()),
510 env.t_fn(22, [t_rptr_static], env.t_int()),
511 env.t_fn(22, [t_rptr_bound1], env.t_int()));