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.
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.
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.
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.
22 //! To handle closures, freshened types also have to contain the signature and kind of any
23 //! closure in the local inference context, as otherwise the cache key might be invalidated.
24 //! The way this is done is somewhat hacky - the closure signature is appended to the substs,
25 //! as well as the closure kind "encoded" as a type. Also, special handling is needed when
26 //! the closure signature contains a reference to the original closure.
28 //! Note that you should be careful not to allow the output of freshening to leak to the user in
29 //! error messages or in any other form. Freshening is only really useful as an internal detail.
31 //! Because of the manipulation required to handle closures, doing arbitrary operations on
32 //! freshened types is not recommended. However, in addition to doing equality/hash
33 //! comparisons (for caching), it is possible to do a `ty::_match` operation between
34 //! 2 freshened types - this works even with the closure encoding.
36 //! __An important detail concerning regions.__ The freshener also replaces *all* free regions with
37 //! 'erased. The reason behind this is that, in general, we do not take region relationships into
38 //! account when making type-overloaded decisions. This is important because of the design of the
39 //! region inferencer, which is not based on unification but rather on accumulating and then
40 //! solving a set of constraints. In contrast, the type inferencer assigns a value to each type
41 //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type
42 //! inferencer knows "so far".
44 use ty
::{self, Ty, TyCtxt, TypeFoldable}
;
45 use ty
::fold
::TypeFolder
;
46 use ty
::subst
::Substs
;
47 use util
::nodemap
::FxHashMap
;
48 use hir
::def_id
::DefId
;
50 use std
::collections
::hash_map
::Entry
;
53 use super::unify_key
::ToType
;
55 pub struct TypeFreshener
<'a
, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
> {
56 infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>,
58 freshen_map
: FxHashMap
<ty
::InferTy
, Ty
<'tcx
>>,
59 closure_set
: Vec
<DefId
>,
62 impl<'a
, 'gcx
, 'tcx
> TypeFreshener
<'a
, 'gcx
, 'tcx
> {
63 pub fn new(infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>)
64 -> TypeFreshener
<'a
, 'gcx
, 'tcx
> {
68 freshen_map
: FxHashMap(),
73 fn freshen
<F
>(&mut self,
74 opt_ty
: Option
<Ty
<'tcx
>>,
78 F
: FnOnce(u32) -> ty
::InferTy
,
80 if let Some(ty
) = opt_ty
{
81 return ty
.fold_with(self);
84 match self.freshen_map
.entry(key
) {
85 Entry
::Occupied(entry
) => *entry
.get(),
86 Entry
::Vacant(entry
) => {
87 let index
= self.freshen_count
;
88 self.freshen_count
+= 1;
89 let t
= self.infcx
.tcx
.mk_infer(freshener(index
));
96 fn next_fresh
<F
>(&mut self,
99 where F
: FnOnce(u32) -> ty
::InferTy
,
101 let index
= self.freshen_count
;
102 self.freshen_count
+= 1;
103 self.infcx
.tcx
.mk_infer(freshener(index
))
106 fn freshen_closure_like
<M
, C
>(&mut self,
108 substs
: ty
::ClosureSubsts
<'tcx
>,
113 where M
: FnOnce(&mut Self) -> (Ty
<'tcx
>, Ty
<'tcx
>),
114 C
: FnOnce(&'tcx Substs
<'tcx
>) -> Ty
<'tcx
>
116 let tcx
= self.infcx
.tcx
;
118 let closure_in_progress
= self.infcx
.in_progress_tables
.map_or(false, |tables
| {
119 tcx
.hir
.as_local_node_id(def_id
).map_or(false, |closure_id
| {
120 tables
.borrow().local_id_root
==
121 Some(DefId
::local(tcx
.hir
.node_to_hir_id(closure_id
).owner
))
125 if !closure_in_progress
{
126 // If this closure belongs to another infcx, its kind etc. were
127 // fully inferred and its signature/kind are exactly what's listed
128 // in its infcx. So we don't need to add the markers for them.
129 return t
.super_fold_with(self);
132 // We are encoding a closure in progress. Because we want our freshening
133 // key to contain all inference information needed to make sense of our
134 // value, we need to encode the closure signature and kind. The way
135 // we do that is to add them as 2 variables to the closure substs,
136 // basically because it's there (and nobody cares about adding extra stuff
139 // This means the "freshened" closure substs ends up looking like
140 // fresh_substs = [PARENT_SUBSTS* ; UPVARS* ; SIG_MARKER ; KIND_MARKER]
141 let (marker_1
, marker_2
) = if self.closure_set
.contains(&def_id
) {
142 // We found the closure def-id within its own signature. Just
143 // leave a new freshened type - any matching operations would
144 // have found and compared the exterior closure already to
147 // In that case, we already know what the signature would
148 // be - the parent closure on the stack already contains a
149 // "copy" of the signature, so there is no reason to encode
150 // it again for injectivity. Just use a fresh type variable
151 // to make everything comparable.
153 // For example (closure kinds omitted for clarity)
154 // t=[closure FOO sig=[closure BAR sig=[closure FOO ..]]]
155 // Would get encoded to
156 // t=[closure FOO sig=[closure BAR sig=[closure FOO sig=$0]]]
158 // and we can decode by having
159 // $0=[closure BAR {sig doesn't exist in decode}]
162 // sig[FOO] = [closure BAR]
163 // sig[BAR] = [closure FOO]
164 (self.next_fresh(ty
::FreshTy
), self.next_fresh(ty
::FreshTy
))
166 self.closure_set
.push(def_id
);
167 let markers
= markers(self);
168 self.closure_set
.pop();
172 combine(tcx
.mk_substs(
173 substs
.substs
.iter().map(|k
| k
.fold_with(self)).chain(
174 [marker_1
, marker_2
].iter().cloned().map(From
::from
)
179 impl<'a
, 'gcx
, 'tcx
> TypeFolder
<'gcx
, 'tcx
> for TypeFreshener
<'a
, 'gcx
, 'tcx
> {
180 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'b
, 'gcx
, 'tcx
> {
184 fn fold_region(&mut self, r
: ty
::Region
<'tcx
>) -> ty
::Region
<'tcx
> {
186 ty
::ReLateBound(..) => {
187 // leave bound regions alone
192 ty
::ReEarlyBound(..) |
196 ty
::ReSkolemized(..) |
199 // replace all free regions with 'erased
200 self.tcx().types
.re_erased
205 fn fold_ty(&mut self, t
: Ty
<'tcx
>) -> Ty
<'tcx
> {
206 if !t
.needs_infer() && !t
.has_erasable_regions() &&
207 !(t
.has_closure_types() && self.infcx
.in_progress_tables
.is_some()) {
211 let tcx
= self.infcx
.tcx
;
214 ty
::TyInfer(ty
::TyVar(v
)) => {
215 let opt_ty
= self.infcx
.type_variables
.borrow_mut().probe(v
);
222 ty
::TyInfer(ty
::IntVar(v
)) => {
224 self.infcx
.int_unification_table
.borrow_mut()
226 .map(|v
| v
.to_type(tcx
)),
231 ty
::TyInfer(ty
::FloatVar(v
)) => {
233 self.infcx
.float_unification_table
.borrow_mut()
235 .map(|v
| v
.to_type(tcx
)),
240 ty
::TyInfer(ty
::FreshTy(c
)) |
241 ty
::TyInfer(ty
::FreshIntTy(c
)) |
242 ty
::TyInfer(ty
::FreshFloatTy(c
)) => {
243 if c
>= self.freshen_count
{
244 bug
!("Encountered a freshend type with id {} \
245 but our counter is only at {}",
252 ty
::TyClosure(def_id
, substs
) => {
253 self.freshen_closure_like(
256 // HACK: use a "random" integer type to mark the kind. Because
257 // different closure kinds shouldn't get unified during
258 // selection, the "subtyping" relationship (where any kind is
259 // better than no kind) shouldn't matter here, just that the
260 // types are different.
261 let closure_kind
= this
.infcx
.closure_kind(def_id
);
262 let closure_kind_marker
= match closure_kind
{
263 None
=> tcx
.types
.i8,
264 Some(ty
::ClosureKind
::Fn
) => tcx
.types
.i16,
265 Some(ty
::ClosureKind
::FnMut
) => tcx
.types
.i32,
266 Some(ty
::ClosureKind
::FnOnce
) => tcx
.types
.i64,
269 let closure_sig
= this
.infcx
.fn_sig(def_id
);
270 (tcx
.mk_fn_ptr(closure_sig
.fold_with(this
)),
273 |substs
| tcx
.mk_closure(def_id
, substs
)
277 ty
::TyGenerator(def_id
, substs
, interior
) => {
278 self.freshen_closure_like(
281 let gen_sig
= this
.infcx
.generator_sig(def_id
).unwrap();
282 // FIXME: want to revise this strategy when generator
283 // signatures can actually contain LBRs.
284 let sig
= this
.tcx().no_late_bound_regions(&gen_sig
)
286 bug
!("late-bound regions in signature of {:?}",
289 (sig
.yield_ty
, sig
.return_ty
).fold_with(this
)
292 tcx
.mk_generator(def_id
, ty
::ClosureSubsts { substs }
, interior
)
314 ty
::TyProjection(..) |
318 t
.super_fold_with(self)