]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/infer/test.rs
e4636e1c7c6d721d32ae97faf60527cecf790bc5
[rust.git] / src / librustc / middle / typeck / infer / test.rs
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 /**
12
13 # Standalone Tests for the Inference Module
14
15 Note: This module is only compiled when doing unit testing.
16
17 */
18
19 use driver::diagnostic;
20 use driver::driver::{optgroups, build_session_options, build_session};
21 use driver::driver::{str_input, build_configuration};
22 use middle::lang_items::{LanguageItems, language_items};
23 use middle::ty::{FnTyBase, FnMeta, FnSig};
24 use util::ppaux::ty_to_str;
25
26 use extra::oldmap::HashMap;
27 use getopts::{optopt, optmulti, optflag, optflagopt, getopts};
28 use getopts::opt_present;
29 use syntax::codemap::DUMMY_SP;
30 use syntax::parse::parse_crate_from_source_str;
31 use syntax::{ast, attr, parse};
32
33 struct Env {
34     krate: @ast::Crate,
35     tcx: ty::ctxt,
36     infcx: infer::infer_ctxt,
37     err_messages: @DVec<String>
38 }
39
40 struct RH {
41     id: ast::node_id,
42     sub: &[RH]
43 }
44
45 static EMPTY_SOURCE_STR: &str = "/* Hello, world! */";
46
47 fn setup_env(test_name: &str, source_string: &str) -> Env {
48     let messages = @DVec();
49     let matches = getopts(vec!("-Z".to_string(), "verbose".to_string()), optgroups()).get();
50     let diag = diagnostic::collect(messages);
51     let sessopts = build_session_options("rustc".to_string(), &matches, diag);
52     let sess = build_session(sessopts, None, diag);
53     let cfg = build_configuration(sess, "whatever".to_string(), str_input("".to_string()));
54     let dm = HashMap();
55     let amap = HashMap();
56     let freevars = HashMap();
57     let region_paramd_items = HashMap();
58     let region_map = HashMap();
59     let lang_items = LanguageItems::new();
60
61     let parse_sess = parse::new_parse_sess(None);
62     let krate = parse_crate_from_source_str(
63         test_name.to_str(), @source_string.to_str(),
64         cfg, parse_sess);
65
66     let tcx = ty::mk_ctxt(sess, dm, amap, freevars, region_map,
67                           region_paramd_items, lang_items);
68
69     let infcx = infer::new_infer_ctxt(tcx);
70
71     return Env {krate: krate,
72                 tcx: tcx,
73                 infcx: infcx,
74                 err_messages: messages};
75 }
76
77 impl Env {
78     pub fn create_region_hierarchy(&self, rh: &RH) {
79         for child_rh in rh.sub.iter() {
80             self.create_region_hierarchy(child_rh);
81             self.tcx.region_map.insert(child_rh.id, rh.id);
82         }
83     }
84
85     pub fn create_simple_region_hierarchy(&self) {
86         // creates a region hierarchy where 1 is root, 10 and 11 are
87         // children of 1, etc
88         self.create_region_hierarchy(
89             &RH {id: 1,
90                  sub: &[RH {id: 10,
91                             sub: &[]},
92                         RH {id: 11,
93                             sub: &[]}]});
94     }
95
96     pub fn lookup_item(&self, names: &[String]) -> ast::node_id {
97         return match search_mod(self, &self.krate.node.module, 0, names) {
98             Some(id) => id,
99             None => {
100                 fail!("no item found: `%s`", names.connect("::"));
101             }
102         };
103
104         fn search_mod(self: &Env,
105                       m: &ast::Mod,
106                       idx: uint,
107                       names: &[String]) -> Option<ast::node_id> {
108             assert!(idx < names.len());
109             for item in m.items.iter() {
110                 if self.tcx.sess.str_of(item.ident) == names[idx] {
111                     return search(self, *item, idx+1, names);
112                 }
113             }
114             return None;
115         }
116
117         fn search(self: &Env,
118                   it: @ast::Item,
119                   idx: uint,
120                   names: &[String]) -> Option<ast::node_id> {
121             if idx == names.len() {
122                 return Some(it.id);
123             }
124
125             return match it.node {
126                 ast::ItemConst(..) | ast::ItemFn(..) |
127                 ast::ItemForeignMod(..) | ast::ItemTy(..) => {
128                     None
129                 }
130
131                 ast::ItemEnum(..) | ast::ItemStruct(..) |
132                 ast::ItemTrait(..) | ast::ItemImpl(..) |
133                 ast::ItemMac(..) => {
134                     None
135                 }
136
137                 ast::ItemMod(ref m) => {
138                     search_mod(self, m, idx, names)
139                 }
140             };
141         }
142     }
143
144     pub fn is_subtype(&self, a: ty::t, b: ty::t) -> bool {
145         match infer::can_mk_subty(self.infcx, a, b) {
146             Ok(_) => true,
147             Err(_) => false
148         }
149     }
150
151     pub fn assert_subtype(&self, a: ty::t, b: ty::t) {
152         if !self.is_subtype(a, b) {
153             fail!("%s is not a subtype of %s, but it should be",
154                   self.ty_to_str(a),
155                   self.ty_to_str(b));
156         }
157     }
158
159     pub fn assert_not_subtype(&self, a: ty::t, b: ty::t) {
160         if self.is_subtype(a, b) {
161             fail!("%s is a subtype of %s, but it shouldn't be",
162                   self.ty_to_str(a),
163                   self.ty_to_str(b));
164         }
165     }
166
167     pub fn assert_strict_subtype(&self, a: ty::t, b: ty::t) {
168         self.assert_subtype(a, b);
169         self.assert_not_subtype(b, a);
170     }
171
172     pub fn assert_eq(&self, a: ty::t, b: ty::t) {
173         self.assert_subtype(a, b);
174         self.assert_subtype(b, a);
175     }
176
177     pub fn ty_to_str(&self, a: ty::t) -> String {
178         ty_to_str(self.tcx, a)
179     }
180
181     pub fn t_fn(&self, input_tys: &[ty::t], output_ty: ty::t) -> ty::t {
182         let inputs = input_tys.map(|t| {mode: ast::expl(ast::by_copy),
183                                         ty: *t});
184         ty::mk_fn(self.tcx, FnTyBase {
185             meta: FnMeta {fn_style: ast::NormalFn,
186                           proto: ast::ProtoBare,
187                           onceness: ast::Many,
188                           region: ty::ReStatic,
189                           bounds: @Vec::new()},
190             sig: FnSig {
191                 inputs: inputs,
192                 output: output_ty,
193                 variadic: false
194             }
195         })
196     }
197
198     pub fn t_int(&self) -> ty::t {
199         ty::mk_int(self.tcx)
200     }
201
202     pub fn t_rptr_bound(&self, id: uint) -> ty::t {
203         ty::mk_imm_rptr(self.tcx, ty::re_bound(ty::BrAnon(id)), self.t_int())
204     }
205
206     pub fn t_rptr_scope(&self, id: ast::node_id) -> ty::t {
207         ty::mk_imm_rptr(self.tcx, ty::ReScope(id), self.t_int())
208     }
209
210     pub fn t_rptr_free(&self, nid: ast::node_id, id: uint) -> ty::t {
211         ty::mk_imm_rptr(self.tcx,
212                         ty::ReFree(ty::FreeRegion {scope_id: nid,
213                                                     bound_region: ty::BrAnon(id)}),
214                         self.t_int())
215     }
216
217     pub fn t_rptr_static(&self) -> ty::t {
218         ty::mk_imm_rptr(self.tcx, ty::ReStatic, self.t_int())
219     }
220
221     pub fn lub() -> Lub { Lub(self.infcx.combine_fields(true, DUMMY_SP)) }
222
223     pub fn glb() -> Glb { Glb(self.infcx.combine_fields(true, DUMMY_SP)) }
224
225     pub fn resolve_regions(exp_count: uint) {
226         debug!("resolve_regions(%u)", exp_count);
227
228         self.infcx.resolve_regions();
229         if self.err_messages.len() != exp_count {
230             for msg in self.err_messages.iter() {
231                 debug!("Error encountered: %s", *msg);
232             }
233             format!("resolving regions encountered %u errors but expected %u!",
234                  self.err_messages.len(),
235                  exp_count);
236         }
237     }
238
239     /// Checks that `LUB(t1,t2) == t_lub`
240     pub fn check_lub(&self, t1: ty::t, t2: ty::t, t_lub: ty::t) {
241         match self.lub().tys(t1, t2) {
242             Err(e) => {
243                 fail!("unexpected error computing LUB: %?", e)
244             }
245             Ok(t) => {
246                 self.assert_eq(t, t_lub);
247
248                 // sanity check for good measure:
249                 self.assert_subtype(t1, t);
250                 self.assert_subtype(t2, t);
251
252                 self.resolve_regions(0);
253             }
254         }
255     }
256
257     /// Checks that `GLB(t1,t2) == t_glb`
258     pub fn check_glb(&self, t1: ty::t, t2: ty::t, t_glb: ty::t) {
259         debug!("check_glb(t1=%s, t2=%s, t_glb=%s)",
260                self.ty_to_str(t1),
261                self.ty_to_str(t2),
262                self.ty_to_str(t_glb));
263         match self.glb().tys(t1, t2) {
264             Err(e) => {
265                 fail!("unexpected error computing LUB: %?", e)
266             }
267             Ok(t) => {
268                 self.assert_eq(t, t_glb);
269
270                 // sanity check for good measure:
271                 self.assert_subtype(t, t1);
272                 self.assert_subtype(t, t2);
273
274                 self.resolve_regions(0);
275             }
276         }
277     }
278
279     /// Checks that `LUB(t1,t2)` is undefined
280     pub fn check_no_lub(&self, t1: ty::t, t2: ty::t) {
281         match self.lub().tys(t1, t2) {
282             Err(_) => {}
283             Ok(t) => {
284                 fail!("unexpected success computing LUB: %?", self.ty_to_str(t))
285             }
286         }
287     }
288
289     /// Checks that `GLB(t1,t2)` is undefined
290     pub fn check_no_glb(&self, t1: ty::t, t2: ty::t) {
291         match self.glb().tys(t1, t2) {
292             Err(_) => {}
293             Ok(t) => {
294                 fail!("unexpected success computing GLB: %?", self.ty_to_str(t))
295             }
296         }
297     }
298 }
299
300 #[test]
301 fn contravariant_region_ptr() {
302     let env = setup_env("contravariant_region_ptr", EMPTY_SOURCE_STR);
303     env.create_simple_region_hierarchy();
304     let t_rptr1 = env.t_rptr_scope(1);
305     let t_rptr10 = env.t_rptr_scope(10);
306     env.assert_eq(t_rptr1, t_rptr1);
307     env.assert_eq(t_rptr10, t_rptr10);
308     env.assert_strict_subtype(t_rptr1, t_rptr10);
309 }
310
311 #[test]
312 fn lub_bound_bound() {
313     let env = setup_env("lub_bound_bound", EMPTY_SOURCE_STR);
314     let t_rptr_bound1 = env.t_rptr_bound(1);
315     let t_rptr_bound2 = env.t_rptr_bound(2);
316     env.check_lub(env.t_fn([t_rptr_bound1], env.t_int()),
317                   env.t_fn([t_rptr_bound2], env.t_int()),
318                   env.t_fn([t_rptr_bound1], env.t_int()));
319 }
320
321 #[test]
322 fn lub_bound_free() {
323     let env = setup_env("lub_bound_free", EMPTY_SOURCE_STR);
324     let t_rptr_bound1 = env.t_rptr_bound(1);
325     let t_rptr_free1 = env.t_rptr_free(0, 1);
326     env.check_lub(env.t_fn([t_rptr_bound1], env.t_int()),
327                   env.t_fn([t_rptr_free1], env.t_int()),
328                   env.t_fn([t_rptr_free1], env.t_int()));
329 }
330
331 #[test]
332 fn lub_bound_static() {
333     let env = setup_env("lub_bound_static", EMPTY_SOURCE_STR);
334     let t_rptr_bound1 = env.t_rptr_bound(1);
335     let t_rptr_static = env.t_rptr_static();
336     env.check_lub(env.t_fn([t_rptr_bound1], env.t_int()),
337                   env.t_fn([t_rptr_static], env.t_int()),
338                   env.t_fn([t_rptr_static], env.t_int()));
339 }
340
341 #[test]
342 fn lub_bound_bound_inverse_order() {
343     let env = setup_env("lub_bound_bound_inverse_order", EMPTY_SOURCE_STR);
344     let t_rptr_bound1 = env.t_rptr_bound(1);
345     let t_rptr_bound2 = env.t_rptr_bound(2);
346     env.check_lub(env.t_fn([t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
347                   env.t_fn([t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
348                   env.t_fn([t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
349 }
350
351 #[test]
352 fn lub_free_free() {
353     let env = setup_env("lub_free_free", EMPTY_SOURCE_STR);
354     let t_rptr_free1 = env.t_rptr_free(0, 1);
355     let t_rptr_free2 = env.t_rptr_free(0, 2);
356     let t_rptr_static = env.t_rptr_static();
357     env.check_lub(env.t_fn([t_rptr_free1], env.t_int()),
358                   env.t_fn([t_rptr_free2], env.t_int()),
359                   env.t_fn([t_rptr_static], env.t_int()));
360 }
361
362 #[test]
363 fn lub_returning_scope() {
364     let env = setup_env("lub_returning_scope", EMPTY_SOURCE_STR);
365     let t_rptr_scope10 = env.t_rptr_scope(10);
366     let t_rptr_scope11 = env.t_rptr_scope(11);
367     env.check_no_lub(env.t_fn([], t_rptr_scope10),
368                      env.t_fn([], t_rptr_scope11));
369 }
370
371 #[test]
372 fn glb_free_free_with_common_scope() {
373     let env = setup_env("glb_free_free", EMPTY_SOURCE_STR);
374     let t_rptr_free1 = env.t_rptr_free(0, 1);
375     let t_rptr_free2 = env.t_rptr_free(0, 2);
376     let t_rptr_scope = env.t_rptr_scope(0);
377     env.check_glb(env.t_fn([t_rptr_free1], env.t_int()),
378                   env.t_fn([t_rptr_free2], env.t_int()),
379                   env.t_fn([t_rptr_scope], env.t_int()));
380 }
381
382 #[test]
383 fn glb_bound_bound() {
384     let env = setup_env("glb_bound_bound", EMPTY_SOURCE_STR);
385     let t_rptr_bound1 = env.t_rptr_bound(1);
386     let t_rptr_bound2 = env.t_rptr_bound(2);
387     env.check_glb(env.t_fn([t_rptr_bound1], env.t_int()),
388                   env.t_fn([t_rptr_bound2], env.t_int()),
389                   env.t_fn([t_rptr_bound1], env.t_int()));
390 }
391
392 #[test]
393 fn glb_bound_free() {
394     let env = setup_env("glb_bound_free", EMPTY_SOURCE_STR);
395     let t_rptr_bound1 = env.t_rptr_bound(1);
396     let t_rptr_free1 = env.t_rptr_free(0, 1);
397     env.check_glb(env.t_fn([t_rptr_bound1], env.t_int()),
398                   env.t_fn([t_rptr_free1], env.t_int()),
399                   env.t_fn([t_rptr_bound1], env.t_int()));
400 }
401
402 #[test]
403 fn glb_bound_static() {
404     let env = setup_env("glb_bound_static", EMPTY_SOURCE_STR);
405     let t_rptr_bound1 = env.t_rptr_bound(1);
406     let t_rptr_static = env.t_rptr_static();
407     env.check_glb(env.t_fn([t_rptr_bound1], env.t_int()),
408                   env.t_fn([t_rptr_static], env.t_int()),
409                   env.t_fn([t_rptr_bound1], env.t_int()));
410 }