]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/infer/freshen.rs
Auto merge of #31077 - nagisa:mir-temp-promotion, r=dotdash
[rust.git] / src / librustc / middle / infer / freshen.rs
1 // Copyright 2014 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 //! Freshening is the process of replacing unknown variables with fresh types. The idea is that
12 //! the type, after freshening, contains no inference variables but instead contains either a
13 //! value for each variable or fresh "arbitrary" types wherever a variable would have been.
14 //!
15 //! Freshening is used primarily to get a good type for inserting into a cache. The result
16 //! summarizes what the type inferencer knows "so far". The primary place it is used right now is
17 //! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type
18 //! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in
19 //! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending
20 //! on what type that type variable is ultimately assigned, the match may or may not succeed.
21 //!
22 //! Note that you should be careful not to allow the output of freshening to leak to the user in
23 //! error messages or in any other form. Freshening is only really useful as an internal detail.
24 //!
25 //! __An important detail concerning regions.__ The freshener also replaces *all* regions with
26 //! 'static. The reason behind this is that, in general, we do not take region relationships into
27 //! account when making type-overloaded decisions. This is important because of the design of the
28 //! region inferencer, which is not based on unification but rather on accumulating and then
29 //! solving a set of constraints. In contrast, the type inferencer assigns a value to each type
30 //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
31 //! inferencer knows "so far".
32
33 use middle::ty::{self, Ty, TypeFoldable};
34 use middle::ty::fold::TypeFolder;
35 use std::collections::hash_map::{self, Entry};
36
37 use super::InferCtxt;
38 use super::unify_key::ToType;
39
40 pub struct TypeFreshener<'a, 'tcx:'a> {
41     infcx: &'a InferCtxt<'a, 'tcx>,
42     freshen_count: u32,
43     freshen_map: hash_map::HashMap<ty::InferTy, Ty<'tcx>>,
44 }
45
46 impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
47     pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> {
48         TypeFreshener {
49             infcx: infcx,
50             freshen_count: 0,
51             freshen_map: hash_map::HashMap::new(),
52         }
53     }
54
55     fn freshen<F>(&mut self,
56                   opt_ty: Option<Ty<'tcx>>,
57                   key: ty::InferTy,
58                   freshener: F)
59                   -> Ty<'tcx> where
60         F: FnOnce(u32) -> ty::InferTy,
61     {
62         match opt_ty {
63             Some(ty) => { return ty.fold_with(self); }
64             None => { }
65         }
66
67         match self.freshen_map.entry(key) {
68             Entry::Occupied(entry) => *entry.get(),
69             Entry::Vacant(entry) => {
70                 let index = self.freshen_count;
71                 self.freshen_count += 1;
72                 let t = self.infcx.tcx.mk_infer(freshener(index));
73                 entry.insert(t);
74                 t
75             }
76         }
77     }
78 }
79
80 impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
81     fn tcx<'b>(&'b self) -> &'b ty::ctxt<'tcx> {
82         self.infcx.tcx
83     }
84
85     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
86         match r {
87             ty::ReEarlyBound(..) |
88             ty::ReLateBound(..) => {
89                 // leave bound regions alone
90                 r
91             }
92
93             ty::ReStatic |
94             ty::ReFree(_) |
95             ty::ReScope(_) |
96             ty::ReVar(_) |
97             ty::ReSkolemized(..) |
98             ty::ReEmpty => {
99                 // replace all free regions with 'static
100                 ty::ReStatic
101             }
102         }
103     }
104
105     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
106         if !t.needs_infer() && !t.has_erasable_regions() {
107             return t;
108         }
109
110         let tcx = self.infcx.tcx;
111
112         match t.sty {
113             ty::TyInfer(ty::TyVar(v)) => {
114                 self.freshen(
115                     self.infcx.type_variables.borrow().probe(v),
116                     ty::TyVar(v),
117                     ty::FreshTy)
118             }
119
120             ty::TyInfer(ty::IntVar(v)) => {
121                 self.freshen(
122                     self.infcx.int_unification_table.borrow_mut()
123                                                     .probe(v)
124                                                     .map(|v| v.to_type(tcx)),
125                     ty::IntVar(v),
126                     ty::FreshIntTy)
127             }
128
129             ty::TyInfer(ty::FloatVar(v)) => {
130                 self.freshen(
131                     self.infcx.float_unification_table.borrow_mut()
132                                                       .probe(v)
133                                                       .map(|v| v.to_type(tcx)),
134                     ty::FloatVar(v),
135                     ty::FreshFloatTy)
136             }
137
138             ty::TyInfer(ty::FreshTy(c)) |
139             ty::TyInfer(ty::FreshIntTy(c)) |
140             ty::TyInfer(ty::FreshFloatTy(c)) => {
141                 if c >= self.freshen_count {
142                     tcx.sess.bug(
143                         &format!("Encountered a freshend type with id {} \
144                                   but our counter is only at {}",
145                                  c,
146                                  self.freshen_count));
147                 }
148                 t
149             }
150
151             ty::TyBool |
152             ty::TyChar |
153             ty::TyInt(..) |
154             ty::TyUint(..) |
155             ty::TyFloat(..) |
156             ty::TyEnum(..) |
157             ty::TyBox(..) |
158             ty::TyStr |
159             ty::TyError |
160             ty::TyArray(..) |
161             ty::TySlice(..) |
162             ty::TyRawPtr(..) |
163             ty::TyRef(..) |
164             ty::TyBareFn(..) |
165             ty::TyTrait(..) |
166             ty::TyStruct(..) |
167             ty::TyClosure(..) |
168             ty::TyTuple(..) |
169             ty::TyProjection(..) |
170             ty::TyParam(..) => {
171                 t.super_fold_with(self)
172             }
173         }
174     }
175 }