]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/infer/lub.rs
librustc: Remove all uses of {:?}.
[rust.git] / src / librustc / middle / typeck / infer / lub.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 use middle::ty::{BuiltinBounds};
12 use middle::ty::RegionVid;
13 use middle::ty;
14 use middle::typeck::infer::combine::*;
15 use middle::typeck::infer::equate::Equate;
16 use middle::typeck::infer::glb::Glb;
17 use middle::typeck::infer::lattice::*;
18 use middle::typeck::infer::sub::Sub;
19 use middle::typeck::infer::{cres, InferCtxt};
20 use middle::typeck::infer::fold_regions_in_sig;
21 use middle::typeck::infer::{TypeTrace, Subtype};
22 use middle::typeck::infer::region_inference::RegionMark;
23 use std::collections::HashMap;
24 use syntax::ast::{Many, Once, NodeId};
25 use syntax::ast::{NormalFn, UnsafeFn};
26 use syntax::ast::{Onceness, FnStyle};
27 use syntax::ast::{MutMutable, MutImmutable};
28 use util::ppaux::mt_to_string;
29 use util::ppaux::Repr;
30
31 /// "Least upper bound" (common supertype)
32 pub struct Lub<'f, 'tcx: 'f> {
33     fields: CombineFields<'f, 'tcx>
34 }
35
36 #[allow(non_snake_case)]
37 pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> {
38     Lub { fields: cf }
39 }
40
41 impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
42     fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx }
43     fn tag(&self) -> String { "lub".to_string() }
44     fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
45     fn trace(&self) -> TypeTrace { self.fields.trace.clone() }
46
47     fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) }
48     fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) }
49     fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) }
50     fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
51
52     fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
53         let tcx = self.fields.infcx.tcx;
54
55         debug!("{}.mts({}, {})",
56                self.tag(),
57                mt_to_string(tcx, a),
58                mt_to_string(tcx, b));
59
60         if a.mutbl != b.mutbl {
61             return Err(ty::terr_mutability)
62         }
63
64         let m = a.mutbl;
65         match m {
66             MutImmutable => {
67                 let t = try!(self.tys(a.ty, b.ty));
68                 Ok(ty::mt {ty: t, mutbl: m})
69             }
70
71             MutMutable => {
72                 let t = try!(self.equate().tys(a.ty, b.ty));
73                 Ok(ty::mt {ty: t, mutbl: m})
74             }
75         }
76     }
77
78     fn contratys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
79         self.glb().tys(a, b)
80     }
81
82     fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
83         match (a, b) {
84           (UnsafeFn, _) | (_, UnsafeFn) => Ok(UnsafeFn),
85           (NormalFn, NormalFn) => Ok(NormalFn),
86         }
87     }
88
89     fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness> {
90         match (a, b) {
91             (Once, _) | (_, Once) => Ok(Once),
92             (Many, Many) => Ok(Many)
93         }
94     }
95
96     fn builtin_bounds(&self,
97                       a: ty::BuiltinBounds,
98                       b: ty::BuiltinBounds)
99                       -> cres<ty::BuiltinBounds> {
100         // More bounds is a subtype of fewer bounds, so
101         // the LUB (mutual supertype) is the intersection.
102         Ok(a.intersection(b))
103     }
104
105     fn contraregions(&self, a: ty::Region, b: ty::Region)
106                     -> cres<ty::Region> {
107         self.glb().regions(a, b)
108     }
109
110     fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
111         debug!("{}.regions({}, {})",
112                self.tag(),
113                a.repr(self.fields.infcx.tcx),
114                b.repr(self.fields.infcx.tcx));
115
116         Ok(self.fields.infcx.region_vars.lub_regions(Subtype(self.trace()), a, b))
117     }
118
119     fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
120         // Note: this is a subtle algorithm.  For a full explanation,
121         // please see the large comment in `region_inference.rs`.
122
123         // Make a mark so we can examine "all bindings that were
124         // created as part of this type comparison".
125         let mark = self.fields.infcx.region_vars.mark();
126
127         // Instantiate each bound region with a fresh region variable.
128         let (a_with_fresh, a_map) =
129             self.fields.infcx.replace_late_bound_regions_with_fresh_regions(
130                 self.trace(), a);
131         let (b_with_fresh, _) =
132             self.fields.infcx.replace_late_bound_regions_with_fresh_regions(
133                 self.trace(), b);
134
135         // Collect constraints.
136         let sig0 = try!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
137         debug!("sig0 = {}", sig0.repr(self.fields.infcx.tcx));
138
139         // Generalize the regions appearing in sig0 if possible
140         let new_vars =
141             self.fields.infcx.region_vars.vars_created_since_mark(mark);
142         let sig1 =
143             fold_regions_in_sig(
144                 self.fields.infcx.tcx,
145                 &sig0,
146                 |r| generalize_region(self, mark, new_vars.as_slice(),
147                                       sig0.binder_id, &a_map, r));
148         return Ok(sig1);
149
150         fn generalize_region(this: &Lub,
151                              mark: RegionMark,
152                              new_vars: &[RegionVid],
153                              new_scope: NodeId,
154                              a_map: &HashMap<ty::BoundRegion, ty::Region>,
155                              r0: ty::Region)
156                              -> ty::Region {
157             // Regions that pre-dated the LUB computation stay as they are.
158             if !is_var_in_set(new_vars, r0) {
159                 assert!(!r0.is_bound());
160                 debug!("generalize_region(r0={}): not new variable", r0);
161                 return r0;
162             }
163
164             let tainted = this.fields.infcx.region_vars.tainted(mark, r0);
165
166             // Variables created during LUB computation which are
167             // *related* to regions that pre-date the LUB computation
168             // stay as they are.
169             if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) {
170                 debug!("generalize_region(r0={}): \
171                         non-new-variables found in {}",
172                        r0, tainted);
173                 assert!(!r0.is_bound());
174                 return r0;
175             }
176
177             // Otherwise, the variable must be associated with at
178             // least one of the variables representing bound regions
179             // in both A and B.  Replace the variable with the "first"
180             // bound region from A that we find it to be associated
181             // with.
182             for (a_br, a_r) in a_map.iter() {
183                 if tainted.iter().any(|x| x == a_r) {
184                     debug!("generalize_region(r0={}): \
185                             replacing with {}, tainted={}",
186                            r0, *a_br, tainted);
187                     return ty::ReLateBound(new_scope, *a_br);
188                 }
189             }
190
191             this.fields.infcx.tcx.sess.span_bug(
192                 this.fields.trace.origin.span(),
193                 format!("region {} is not associated with \
194                          any bound region from A!",
195                         r0).as_slice())
196         }
197     }
198
199     fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
200         super_lattice_tys(self, a, b)
201     }
202 }