]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/infer/resolve.rs
Doc says to avoid mixing allocator instead of forbiding it
[rust.git] / src / librustc / middle / typeck / infer / resolve.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 // Resolution is the process of removing type variables and replacing
12 // them with their inferred values.  Unfortunately our inference has
13 // become fairly complex and so there are a number of options to
14 // control *just how much* you want to resolve and how you want to do
15 // it.
16 //
17 // # Controlling the scope of resolution
18 //
19 // The options resolve_* determine what kinds of variables get
20 // resolved.  Generally resolution starts with a top-level type
21 // variable; we will always resolve this.  However, once we have
22 // resolved that variable, we may end up with a type that still
23 // contains type variables.  For example, if we resolve `<T0>` we may
24 // end up with something like `[<T1>]`.  If the option
25 // `resolve_nested_tvar` is passed, we will then go and recursively
26 // resolve `<T1>`.
27 //
28 // The options `resolve_rvar` controls whether we resolve region
29 // variables. The options `resolve_fvar` and `resolve_ivar` control
30 // whether we resolve floating point and integral variables,
31 // respectively.
32 //
33 // # What do if things are unconstrained
34 //
35 // Sometimes we will encounter a variable that has no constraints, and
36 // therefore cannot sensibly be mapped to any particular result.  By
37 // default, we will leave such variables as is (so you will get back a
38 // variable in your result).  The options force_* will cause the
39 // resolution to fail in this case instead, except for the case of
40 // integral variables, which resolve to `int` if forced.
41 //
42 // # resolve_all and force_all
43 //
44 // The options are a bit set, so you can use the *_all to resolve or
45 // force all kinds of variables (including those we may add in the
46 // future).  If you want to resolve everything but one type, you are
47 // probably better off writing `resolve_all - resolve_ivar`.
48
49
50 use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid};
51 use middle::ty::{IntType, UintType};
52 use middle::ty;
53 use middle::ty_fold;
54 use middle::typeck::infer::{fixup_err, fres, InferCtxt};
55 use middle::typeck::infer::{unresolved_int_ty,unresolved_float_ty,unresolved_ty};
56 use syntax::codemap::Span;
57 use util::common::indent;
58 use util::ppaux::{Repr, ty_to_string};
59
60 pub static resolve_nested_tvar: uint = 0b0000000001;
61 pub static resolve_rvar: uint        = 0b0000000010;
62 pub static resolve_ivar: uint        = 0b0000000100;
63 pub static resolve_fvar: uint        = 0b0000001000;
64 pub static resolve_all: uint         = 0b0000001111;
65 pub static force_tvar: uint          = 0b0000100000;
66 pub static force_rvar: uint          = 0b0001000000;
67 pub static force_ivar: uint          = 0b0010000000;
68 pub static force_fvar: uint          = 0b0100000000;
69 pub static force_all: uint           = 0b0111100000;
70
71 pub static not_regions: uint         = !(force_rvar | resolve_rvar);
72
73 pub static try_resolve_tvar_shallow: uint = 0;
74 pub static resolve_and_force_all_but_regions: uint =
75     (resolve_all | force_all) & not_regions;
76
77 pub struct ResolveState<'a, 'tcx: 'a> {
78     infcx: &'a InferCtxt<'a, 'tcx>,
79     modes: uint,
80     err: Option<fixup_err>,
81     type_depth: uint,
82 }
83
84 pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>,
85                           modes: uint,
86                           _: Option<Span>)
87                           -> ResolveState<'a, 'tcx> {
88     ResolveState {
89         infcx: infcx,
90         modes: modes,
91         err: None,
92         type_depth: 0,
93     }
94 }
95
96 impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for ResolveState<'a, 'tcx> {
97     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
98         self.infcx.tcx
99     }
100
101     fn fold_ty(&mut self, t: ty::t) -> ty::t {
102         self.resolve_type(t)
103     }
104
105     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
106         self.resolve_region(r)
107     }
108 }
109
110 impl<'a, 'tcx> ResolveState<'a, 'tcx> {
111     pub fn should(&mut self, mode: uint) -> bool {
112         (self.modes & mode) == mode
113     }
114
115     pub fn resolve_type_chk(&mut self,
116                             typ: ty::t)
117                             -> fres<ty::t> {
118         self.err = None;
119
120         debug!("Resolving {} (modes={:x})",
121                ty_to_string(self.infcx.tcx, typ),
122                self.modes);
123
124         // n.b. This is a hokey mess because the current fold doesn't
125         // allow us to pass back errors in any useful way.
126
127         let rty = self.resolve_type(typ);
128         match self.err {
129           None => {
130             debug!("Resolved {} to {} (modes={:x})",
131                    ty_to_string(self.infcx.tcx, typ),
132                    ty_to_string(self.infcx.tcx, rty),
133                    self.modes);
134             return Ok(rty);
135           }
136           Some(e) => return Err(e)
137         }
138     }
139
140     pub fn resolve_region_chk(&mut self,
141                               orig: ty::Region)
142                               -> fres<ty::Region> {
143         self.err = None;
144         let resolved = indent(|| self.resolve_region(orig) );
145         match self.err {
146           None => Ok(resolved),
147           Some(e) => Err(e)
148         }
149     }
150
151     pub fn resolve_type(&mut self, typ: ty::t) -> ty::t {
152         debug!("resolve_type({})", typ.repr(self.infcx.tcx));
153
154         if !ty::type_needs_infer(typ) {
155             return typ;
156         }
157
158         if self.type_depth > 0 && !self.should(resolve_nested_tvar) {
159             return typ;
160         }
161
162         match ty::get(typ).sty {
163             ty::ty_infer(TyVar(vid)) => {
164                 self.resolve_ty_var(vid)
165             }
166             ty::ty_infer(IntVar(vid)) => {
167                 self.resolve_int_var(vid)
168             }
169             ty::ty_infer(FloatVar(vid)) => {
170                 self.resolve_float_var(vid)
171             }
172             _ => {
173                 if self.modes & resolve_all == 0 {
174                     // if we are only resolving top-level type
175                     // variables, and this is not a top-level type
176                     // variable, then shortcircuit for efficiency
177                     typ
178                 } else {
179                     self.type_depth += 1;
180                     let result = ty_fold::super_fold_ty(self, typ);
181                     self.type_depth -= 1;
182                     result
183                 }
184             }
185         }
186     }
187
188     pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region {
189         debug!("Resolve_region({})", orig.repr(self.infcx.tcx));
190         match orig {
191           ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid),
192           _ => orig
193         }
194     }
195
196     pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region {
197         if !self.should(resolve_rvar) {
198             return ty::ReInfer(ty::ReVar(rid));
199         }
200         self.infcx.region_vars.resolve_var(rid)
201     }
202
203     pub fn resolve_ty_var(&mut self, vid: TyVid) -> ty::t {
204         let tcx = self.infcx.tcx;
205         let t1 = match self.infcx.type_variables.borrow().probe(vid) {
206             Some(t) => {
207                 self.resolve_type(t)
208             }
209             None => {
210                 if self.should(force_tvar) {
211                     self.err = Some(unresolved_ty(vid));
212                 }
213                 ty::mk_var(tcx, vid)
214             }
215         };
216         return t1;
217     }
218
219     pub fn resolve_int_var(&mut self, vid: IntVid) -> ty::t {
220         if !self.should(resolve_ivar) {
221             return ty::mk_int_var(self.infcx.tcx, vid);
222         }
223
224         let tcx = self.infcx.tcx;
225         let table = &self.infcx.int_unification_table;
226         let node = table.borrow_mut().get(tcx, vid);
227         match node.value {
228           Some(IntType(t)) => ty::mk_mach_int(t),
229           Some(UintType(t)) => ty::mk_mach_uint(t),
230           None => {
231             if self.should(force_ivar) {
232                 // As a last resort, emit an error.
233                 self.err = Some(unresolved_int_ty(vid));
234             }
235             ty::mk_int_var(self.infcx.tcx, vid)
236           }
237         }
238     }
239
240     pub fn resolve_float_var(&mut self, vid: FloatVid) -> ty::t {
241         if !self.should(resolve_fvar) {
242             return ty::mk_float_var(self.infcx.tcx, vid);
243         }
244
245         let tcx = self.infcx.tcx;
246         let table = &self.infcx.float_unification_table;
247         let node = table.borrow_mut().get(tcx, vid);
248         match node.value {
249           Some(t) => ty::mk_mach_float(t),
250           None => {
251             if self.should(force_fvar) {
252                 // As a last resort, emit an error.
253                 self.err = Some(unresolved_float_ty(vid));
254             }
255             ty::mk_float_var(self.infcx.tcx, vid)
256           }
257         }
258     }
259 }