Skip to content

Commit e96f4be

Browse files
committed
extract instantiate_anon_types to the InferCtxt
No functional change.
1 parent 4a967c9 commit e96f4be

File tree

4 files changed

+225
-112
lines changed

4 files changed

+225
-112
lines changed

src/librustc/infer/anon_types/mod.rs

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
// Copyright 2012-2015 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 hir::def_id::DefId;
12+
use infer::{InferCtxt, InferOk, TypeVariableOrigin};
13+
use syntax::ast;
14+
use traits::{self, PredicateObligation};
15+
use ty::{self, Ty};
16+
use ty::fold::{BottomUpFolder, TypeFoldable};
17+
use ty::subst::Substs;
18+
use util::nodemap::DefIdMap;
19+
20+
pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
21+
22+
/// Information about the anonymous, abstract types whose values we
23+
/// are inferring in this function (these are the `impl Trait` that
24+
/// appear in the return type).
25+
#[derive(Copy, Clone, Debug)]
26+
pub struct AnonTypeDecl<'tcx> {
27+
/// The substitutions that we apply to the abstract that that this
28+
/// `impl Trait` desugars to. e.g., if:
29+
///
30+
/// fn foo<'a, 'b, T>() -> impl Trait<'a>
31+
///
32+
/// winds up desugared to:
33+
///
34+
/// abstract type Foo<'x, T>: Trait<'x>
35+
/// fn foo<'a, 'b, T>() -> Foo<'a, T>
36+
///
37+
/// then `substs` would be `['a, T]`.
38+
pub substs: &'tcx Substs<'tcx>,
39+
40+
/// The type variable that represents the value of the abstract type
41+
/// that we require. In other words, after we compile this function,
42+
/// we will be created a constraint like:
43+
///
44+
/// Foo<'a, T> = ?C
45+
///
46+
/// where `?C` is the value of this type variable. =) It may
47+
/// naturally refer to the type and lifetime parameters in scope
48+
/// in this function, though ultimately it should only reference
49+
/// those that are arguments to `Foo` in the constraint above. (In
50+
/// other words, `?C` should not include `'b`, even though it's a
51+
/// lifetime parameter on `foo`.)
52+
pub concrete_ty: Ty<'tcx>,
53+
54+
/// True if the `impl Trait` bounds include region bounds.
55+
/// For example, this would be true for:
56+
///
57+
/// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
58+
///
59+
/// but false for:
60+
///
61+
/// fn foo<'c>() -> impl Trait<'c>
62+
///
63+
/// unless `Trait` was declared like:
64+
///
65+
/// trait Trait<'c>: 'c
66+
///
67+
/// in which case it would be true.
68+
///
69+
/// This is used during regionck to decide whether we need to
70+
/// impose any additional constraints to ensure that region
71+
/// variables in `concrete_ty` wind up being constrained to
72+
/// something from `substs` (or, at minimum, things that outlive
73+
/// the fn body). (Ultimately, writeback is responsible for this
74+
/// check.)
75+
pub has_required_region_bounds: bool,
76+
}
77+
78+
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
79+
/// Replace all anonymized types in `value` with fresh inference variables
80+
/// and creates appropriate obligations. For example, given the input:
81+
///
82+
/// impl Iterator<Item = impl Debug>
83+
///
84+
/// this method would create two type variables, `?0` and `?1`. It would
85+
/// return the type `?0` but also the obligations:
86+
///
87+
/// ?0: Iterator<Item = ?1>
88+
/// ?1: Debug
89+
///
90+
/// Moreover, it returns a `AnonTypeMap` that would map `?0` to
91+
/// info about the `impl Iterator<..>` type and `?1` to info about
92+
/// the `impl Debug` type.
93+
pub fn instantiate_anon_types<T: TypeFoldable<'tcx>>(
94+
&self,
95+
body_id: ast::NodeId,
96+
param_env: ty::ParamEnv<'tcx>,
97+
value: &T,
98+
) -> InferOk<'tcx, (T, AnonTypeMap<'tcx>)> {
99+
debug!(
100+
"instantiate_anon_types(value={:?}, body_id={:?}, param_env={:?})",
101+
value,
102+
body_id,
103+
param_env,
104+
);
105+
let mut instantiator = Instantiator {
106+
infcx: self,
107+
body_id,
108+
param_env,
109+
anon_types: DefIdMap(),
110+
obligations: vec![],
111+
};
112+
let value = instantiator.instantiate_anon_types_in_map(value);
113+
InferOk {
114+
value: (value, instantiator.anon_types),
115+
obligations: instantiator.obligations,
116+
}
117+
}
118+
}
119+
120+
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
121+
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
122+
body_id: ast::NodeId,
123+
param_env: ty::ParamEnv<'tcx>,
124+
anon_types: AnonTypeMap<'tcx>,
125+
obligations: Vec<PredicateObligation<'tcx>>,
126+
}
127+
128+
impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
129+
fn instantiate_anon_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
130+
debug!("instantiate_anon_types_in_map(value={:?})", value);
131+
value.fold_with(&mut BottomUpFolder {
132+
tcx: self.infcx.tcx,
133+
fldop: |ty| if let ty::TyAnon(def_id, substs) = ty.sty {
134+
self.fold_anon_ty(ty, def_id, substs)
135+
} else {
136+
ty
137+
},
138+
})
139+
}
140+
141+
fn fold_anon_ty(
142+
&mut self,
143+
ty: Ty<'tcx>,
144+
def_id: DefId,
145+
substs: &'tcx Substs<'tcx>,
146+
) -> Ty<'tcx> {
147+
let infcx = self.infcx;
148+
let tcx = infcx.tcx;
149+
150+
debug!(
151+
"instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})",
152+
def_id,
153+
substs
154+
);
155+
156+
// Use the same type variable if the exact same TyAnon appears more
157+
// than once in the return type (e.g. if it's passed to a type alias).
158+
if let Some(anon_defn) = self.anon_types.get(&def_id) {
159+
return anon_defn.concrete_ty;
160+
}
161+
let span = tcx.def_span(def_id);
162+
let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
163+
164+
let predicates_of = tcx.predicates_of(def_id);
165+
let bounds = predicates_of.instantiate(tcx, substs);
166+
debug!("instantiate_anon_types: bounds={:?}", bounds);
167+
168+
let required_region_bounds = tcx.required_region_bounds(ty, bounds.predicates.clone());
169+
debug!(
170+
"instantiate_anon_types: required_region_bounds={:?}",
171+
required_region_bounds
172+
);
173+
174+
self.anon_types.insert(
175+
def_id,
176+
AnonTypeDecl {
177+
substs,
178+
concrete_ty: ty_var,
179+
has_required_region_bounds: !required_region_bounds.is_empty(),
180+
},
181+
);
182+
debug!("instantiate_anon_types: ty_var={:?}", ty_var);
183+
184+
for predicate in bounds.predicates {
185+
// Change the predicate to refer to the type variable,
186+
// which will be the concrete type, instead of the TyAnon.
187+
// This also instantiates nested `impl Trait`.
188+
let predicate = self.instantiate_anon_types_in_map(&predicate);
189+
190+
let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType);
191+
192+
// Require that the predicate holds for the concrete type.
193+
debug!("instantiate_anon_types: predicate={:?}", predicate);
194+
self.obligations
195+
.push(traits::Obligation::new(cause, self.param_env, predicate));
196+
}
197+
198+
ty_var
199+
}
200+
}

src/librustc/infer/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use self::outlives::env::OutlivesEnvironment;
4848
use self::type_variable::TypeVariableOrigin;
4949
use self::unify_key::ToType;
5050

51+
pub mod anon_types;
5152
pub mod at;
5253
mod combine;
5354
mod equate;

src/librustc_typeck/check/mod.rs

Lines changed: 23 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,15 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
9090
use std::slice;
9191
use namespace::Namespace;
9292
use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
93+
use rustc::infer::anon_types::AnonTypeDecl;
9394
use rustc::infer::type_variable::{TypeVariableOrigin};
9495
use rustc::middle::region;
9596
use rustc::ty::subst::{Kind, Subst, Substs};
9697
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
9798
use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
9899
use rustc::ty::{self, Ty, TyCtxt, Visibility};
99100
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
100-
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
101+
use rustc::ty::fold::TypeFoldable;
101102
use rustc::ty::maps::Providers;
102103
use rustc::ty::util::{Representability, IntTypeExt};
103104
use errors::{DiagnosticBuilder, DiagnosticId};
@@ -225,62 +226,6 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
225226
body_id: Option<hir::BodyId>,
226227
}
227228

228-
/// Information about the anonymous, abstract types whose values we
229-
/// are inferring in this function (these are the `impl Trait` that
230-
/// appear in the return type).
231-
#[derive(Debug)]
232-
struct AnonTypeDecl<'tcx> {
233-
/// The substitutions that we apply to the abstract that that this
234-
/// `impl Trait` desugars to. e.g., if:
235-
///
236-
/// fn foo<'a, 'b, T>() -> impl Trait<'a>
237-
///
238-
/// winds up desugared to:
239-
///
240-
/// abstract type Foo<'x, T>: Trait<'x>
241-
/// fn foo<'a, 'b, T>() -> Foo<'a, T>
242-
///
243-
/// then `substs` would be `['a, T]`.
244-
substs: &'tcx Substs<'tcx>,
245-
246-
/// The type variable that represents the value of the abstract type
247-
/// that we require. In other words, after we compile this function,
248-
/// we will be created a constraint like:
249-
///
250-
/// Foo<'a, T> = ?C
251-
///
252-
/// where `?C` is the value of this type variable. =) It may
253-
/// naturally refer to the type and lifetime parameters in scope
254-
/// in this function, though ultimately it should only reference
255-
/// those that are arguments to `Foo` in the constraint above. (In
256-
/// other words, `?C` should not include `'b`, even though it's a
257-
/// lifetime parameter on `foo`.)
258-
concrete_ty: Ty<'tcx>,
259-
260-
/// True if the `impl Trait` bounds include region bounds.
261-
/// For example, this would be true for:
262-
///
263-
/// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
264-
///
265-
/// but false for:
266-
///
267-
/// fn foo<'c>() -> impl Trait<'c>
268-
///
269-
/// unless `Trait` was declared like:
270-
///
271-
/// trait Trait<'c>: 'c
272-
///
273-
/// in which case it would be true.
274-
///
275-
/// This is used during regionck to decide whether we need to
276-
/// impose any additional constraints to ensure that region
277-
/// variables in `concrete_ty` wind up being constrained to
278-
/// something from `substs` (or, at minimum, things that outlive
279-
/// the fn body). (Ultimately, writeback is responsible for this
280-
/// check.)
281-
has_required_region_bounds: bool,
282-
}
283-
284229
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
285230
type Target = InferCtxt<'a, 'gcx, 'tcx>;
286231
fn deref(&self) -> &Self::Target {
@@ -892,8 +837,6 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
892837
&fn_sig);
893838

894839
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, false).0;
895-
// Ensure anon_types have been instantiated prior to entering regionck
896-
fcx.instantiate_anon_types(&fn_sig.output());
897840
fcx
898841
} else {
899842
let fcx = FnCtxt::new(&inh, param_env, body.value.id);
@@ -1042,7 +985,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
1042985

1043986
let ret_ty = fn_sig.output();
1044987
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::SizedReturnType);
1045-
let ret_ty = fcx.instantiate_anon_types(&ret_ty);
988+
let ret_ty = fcx.instantiate_anon_types_from_return_value(&ret_ty);
1046989
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
1047990
fn_sig = fcx.tcx.mk_fn_sig(
1048991
fn_sig.inputs().iter().cloned(),
@@ -1933,60 +1876,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
19331876
result
19341877
}
19351878

1936-
/// Replace all anonymized types with fresh inference variables
1937-
/// and record them for writeback.
1938-
fn instantiate_anon_types<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
1939-
debug!("instantiate_anon_types(value={:?})", value);
1940-
value.fold_with(&mut BottomUpFolder { tcx: self.tcx, fldop: |ty| {
1941-
if let ty::TyAnon(def_id, substs) = ty.sty {
1942-
debug!("instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})", def_id, substs);
1879+
/// Replace the anonymized types from the return value of the
1880+
/// function with type variables and records the `AnonTypeMap` for
1881+
/// later use during writeback. See
1882+
/// `InferCtxt::instantiate_anon_types` for more details.
1883+
fn instantiate_anon_types_from_return_value<T: TypeFoldable<'tcx>>(&self, value: &T) -> T {
1884+
debug!("instantiate_anon_types_from_return_value(value={:?})", value);
19431885

1944-
// Use the same type variable if the exact same TyAnon appears more
1945-
// than once in the return type (e.g. if it's passed to a type alias).
1946-
if let Some(anon_defn) = self.anon_types.borrow().get(&def_id) {
1947-
return anon_defn.concrete_ty;
1948-
}
1949-
let span = self.tcx.def_span(def_id);
1950-
let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
1951-
1952-
let predicates_of = self.tcx.predicates_of(def_id);
1953-
let bounds = predicates_of.instantiate(self.tcx, substs);
1954-
debug!("instantiate_anon_types: bounds={:?}", bounds);
1955-
1956-
let required_region_bounds =
1957-
self.tcx.required_region_bounds(ty, bounds.predicates.clone());
1958-
debug!("instantiate_anon_types: required_region_bounds={:?}",
1959-
required_region_bounds);
1960-
1961-
self.anon_types.borrow_mut().insert(def_id, AnonTypeDecl {
1962-
substs,
1963-
concrete_ty: ty_var,
1964-
has_required_region_bounds: !required_region_bounds.is_empty(),
1965-
});
1966-
debug!("instantiate_anon_types: ty_var={:?}", ty_var);
1967-
1968-
for predicate in bounds.predicates {
1969-
// Change the predicate to refer to the type variable,
1970-
// which will be the concrete type, instead of the TyAnon.
1971-
// This also instantiates nested `impl Trait`.
1972-
let predicate = self.instantiate_anon_types(&predicate);
1973-
1974-
// Require that the predicate holds for the concrete type.
1975-
let cause = traits::ObligationCause::new(span,
1976-
self.body_id,
1977-
traits::SizedReturnType);
1978-
1979-
debug!("instantiate_anon_types: predicate={:?}", predicate);
1980-
self.register_predicate(traits::Obligation::new(cause,
1981-
self.param_env,
1982-
predicate));
1983-
}
1886+
let (value, anon_type_map) = self.register_infer_ok_obligations(
1887+
self.instantiate_anon_types(
1888+
self.body_id,
1889+
self.param_env,
1890+
value,
1891+
)
1892+
);
19841893

1985-
ty_var
1986-
} else {
1987-
ty
1988-
}
1989-
}})
1894+
let mut anon_types = self.anon_types.borrow_mut();
1895+
for (ty, decl) in anon_type_map {
1896+
let old_value = anon_types.insert(ty, decl);
1897+
assert!(old_value.is_none(), "instantiated twice: {:?}/{:?}", ty, decl);
1898+
}
1899+
1900+
value
19901901
}
19911902

19921903
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T

src/librustc_typeck/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ This API is completely unstable and subject to change.
8181
#![feature(match_default_bindings)]
8282
#![feature(never_type)]
8383
#![feature(quote)]
84+
#![feature(refcell_replace_swap)]
8485
#![feature(rustc_diagnostic_macros)]
8586
#![feature(slice_patterns)]
8687

0 commit comments

Comments
 (0)