Skip to content

Commit 7d6f1aa

Browse files
committed
Factor out foldable better to reduce code duplication. There is now a "double
dispatch" pattern that lets you easily write new folders and then apply them to various structures, reusing the "folding" effort.
1 parent 0550b79 commit 7d6f1aa

File tree

5 files changed

+330
-340
lines changed

5 files changed

+330
-340
lines changed

src/librustc/middle/subst.rs

+56-212
Original file line numberDiff line numberDiff line change
@@ -12,56 +12,48 @@
1212

1313
use middle::ty;
1414
use middle::ty_fold;
15-
use middle::ty_fold::TypeFolder;
15+
use middle::ty_fold::{TypeFoldable, TypeFolder};
1616
use util::ppaux::Repr;
1717

18-
use std::rc::Rc;
1918
use syntax::codemap::Span;
20-
use syntax::owned_slice::OwnedSlice;
2119

2220
///////////////////////////////////////////////////////////////////////////
2321
// Public trait `Subst`
2422
//
2523
// Just call `foo.subst(tcx, substs)` to perform a substitution across
26-
// `foo`.
27-
// Or use `foo.subst_spanned(tcx, substs, Some(span))` when there is more
28-
// information available (for better errors).
24+
// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
25+
// there is more information available (for better errors).
2926

3027
pub trait Subst {
3128
fn subst(&self, tcx: &ty::ctxt, substs: &ty::substs) -> Self {
3229
self.subst_spanned(tcx, substs, None)
3330
}
31+
3432
fn subst_spanned(&self, tcx: &ty::ctxt,
3533
substs: &ty::substs,
36-
span: Option<Span>) -> Self;
34+
span: Option<Span>)
35+
-> Self;
3736
}
3837

39-
///////////////////////////////////////////////////////////////////////////
40-
// Substitution over types
41-
//
42-
// Because this is so common, we make a special optimization to avoid
43-
// doing anything if `substs` is a no-op. I tried to generalize these
44-
// to all subst methods but ran into trouble due to the limitations of
45-
// our current method/trait matching algorithm. - Niko
46-
47-
impl Subst for ty::t {
48-
fn subst_spanned(&self, tcx: &ty::ctxt,
38+
impl<T:TypeFoldable> Subst for T {
39+
fn subst_spanned(&self,
40+
tcx: &ty::ctxt,
4941
substs: &ty::substs,
50-
span: Option<Span>) -> ty::t {
51-
if ty::substs_is_noop(substs) && !ty::type_has_params(*self) {
52-
*self
53-
} else {
54-
let mut folder = SubstFolder {
55-
tcx: tcx,
56-
substs: substs,
57-
span: span,
58-
root_ty: Some(*self)
59-
};
60-
folder.fold_ty(*self)
61-
}
42+
span: Option<Span>)
43+
-> T
44+
{
45+
let mut folder = SubstFolder { tcx: tcx,
46+
substs: substs,
47+
span: span,
48+
root_ty: None,
49+
ty_stack_depth: 0 };
50+
(*self).fold_with(&mut folder)
6251
}
6352
}
6453

54+
///////////////////////////////////////////////////////////////////////////
55+
// The actual substitution engine itself is a type folder.
56+
6557
struct SubstFolder<'a> {
6658
tcx: &'a ty::ctxt,
6759
substs: &'a ty::substs,
@@ -70,23 +62,50 @@ struct SubstFolder<'a> {
7062
span: Option<Span>,
7163

7264
// The root type that is being substituted, if available.
73-
root_ty: Option<ty::t>
65+
root_ty: Option<ty::t>,
66+
67+
// Depth of type stack
68+
ty_stack_depth: uint,
7469
}
7570

7671
impl<'a> TypeFolder for SubstFolder<'a> {
7772
fn tcx<'a>(&'a self) -> &'a ty::ctxt { self.tcx }
7873

7974
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
80-
r.subst(self.tcx, self.substs)
75+
// Note: This routine only handles regions that are bound on
76+
// type declarations and other outer declarations, not those
77+
// bound in *fn types*. Region substitution of the bound
78+
// regions that appear in a function signature is done using
79+
// the specialized routine
80+
// `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`.
81+
match r {
82+
ty::ReEarlyBound(_, i, _) => {
83+
match self.substs.regions {
84+
ty::ErasedRegions => ty::ReStatic,
85+
ty::NonerasedRegions(ref regions) => *regions.get(i),
86+
}
87+
}
88+
_ => r
89+
}
8190
}
8291

8392
fn fold_ty(&mut self, t: ty::t) -> ty::t {
8493
if !ty::type_needs_subst(t) {
8594
return t;
8695
}
8796

88-
match ty::get(t).sty {
97+
// track the root type we were asked to substitute
98+
let depth = self.ty_stack_depth;
99+
if depth == 0 {
100+
self.root_ty = Some(t);
101+
}
102+
self.ty_stack_depth += 1;
103+
104+
let t1 = match ty::get(t).sty {
89105
ty::ty_param(p) => {
106+
// FIXME -- This...really shouldn't happen. We should
107+
// never be substituting without knowing what's in
108+
// scope and knowing that the indices will line up!
90109
if p.idx < self.substs.tps.len() {
91110
*self.substs.tps.get(p.idx)
92111
} else {
@@ -124,189 +143,14 @@ impl<'a> TypeFolder for SubstFolder<'a> {
124143
}
125144
}
126145
_ => ty_fold::super_fold_ty(self, t)
127-
}
128-
}
129-
}
130-
131-
///////////////////////////////////////////////////////////////////////////
132-
// Other types
133-
134-
impl<T:Subst> Subst for Vec<T> {
135-
fn subst_spanned(&self, tcx: &ty::ctxt,
136-
substs: &ty::substs,
137-
span: Option<Span>) -> Vec<T> {
138-
self.iter().map(|t| t.subst_spanned(tcx, substs, span)).collect()
139-
}
140-
}
141-
impl<T:Subst> Subst for Rc<T> {
142-
fn subst_spanned(&self, tcx: &ty::ctxt,
143-
substs: &ty::substs,
144-
span: Option<Span>) -> Rc<T> {
145-
Rc::new((**self).subst_spanned(tcx, substs, span))
146-
}
147-
}
148-
149-
impl<T:Subst> Subst for OwnedSlice<T> {
150-
fn subst_spanned(&self, tcx: &ty::ctxt,
151-
substs: &ty::substs,
152-
span: Option<Span>) -> OwnedSlice<T> {
153-
self.map(|t| t.subst_spanned(tcx, substs, span))
154-
}
155-
}
156-
157-
impl<T:Subst + 'static> Subst for @T {
158-
fn subst_spanned(&self, tcx: &ty::ctxt,
159-
substs: &ty::substs,
160-
span: Option<Span>) -> @T {
161-
match self {
162-
t => @(**t).subst_spanned(tcx, substs, span)
163-
}
164-
}
165-
}
166-
167-
impl<T:Subst> Subst for Option<T> {
168-
fn subst_spanned(&self, tcx: &ty::ctxt,
169-
substs: &ty::substs,
170-
span: Option<Span>) -> Option<T> {
171-
self.as_ref().map(|t| t.subst_spanned(tcx, substs, span))
172-
}
173-
}
174-
175-
impl Subst for ty::TraitRef {
176-
fn subst_spanned(&self, tcx: &ty::ctxt,
177-
substs: &ty::substs,
178-
span: Option<Span>) -> ty::TraitRef {
179-
ty::TraitRef {
180-
def_id: self.def_id,
181-
substs: self.substs.subst_spanned(tcx, substs, span)
182-
}
183-
}
184-
}
185-
186-
impl Subst for ty::substs {
187-
fn subst_spanned(&self, tcx: &ty::ctxt,
188-
substs: &ty::substs,
189-
span: Option<Span>) -> ty::substs {
190-
ty::substs {
191-
regions: self.regions.subst_spanned(tcx, substs, span),
192-
self_ty: self.self_ty.map(|typ| typ.subst_spanned(tcx, substs, span)),
193-
tps: self.tps.iter().map(|typ| typ.subst_spanned(tcx, substs, span)).collect()
194-
}
195-
}
196-
}
197-
198-
impl Subst for ty::ItemSubsts {
199-
fn subst_spanned(&self, tcx: &ty::ctxt,
200-
substs: &ty::substs,
201-
span: Option<Span>)
202-
-> ty::ItemSubsts {
203-
ty::ItemSubsts {
204-
substs: self.substs.subst_spanned(tcx, substs, span)
205-
}
206-
}
207-
}
208-
209-
impl Subst for ty::RegionSubsts {
210-
fn subst_spanned(&self, tcx: &ty::ctxt,
211-
substs: &ty::substs,
212-
span: Option<Span>) -> ty::RegionSubsts {
213-
match *self {
214-
ty::ErasedRegions => {
215-
ty::ErasedRegions
216-
}
217-
ty::NonerasedRegions(ref regions) => {
218-
ty::NonerasedRegions(regions.subst_spanned(tcx, substs, span))
219-
}
220-
}
221-
}
222-
}
223-
224-
impl Subst for ty::BareFnTy {
225-
fn subst_spanned(&self, tcx: &ty::ctxt,
226-
substs: &ty::substs,
227-
span: Option<Span>) -> ty::BareFnTy {
228-
let mut folder = SubstFolder {
229-
tcx: tcx,
230-
substs: substs,
231-
span: span,
232-
root_ty: None
233146
};
234-
folder.fold_bare_fn_ty(self)
235-
}
236-
}
237147

238-
impl Subst for ty::ParamBounds {
239-
fn subst_spanned(&self, tcx: &ty::ctxt,
240-
substs: &ty::substs,
241-
span: Option<Span>) -> ty::ParamBounds {
242-
ty::ParamBounds {
243-
builtin_bounds: self.builtin_bounds,
244-
trait_bounds: self.trait_bounds.subst_spanned(tcx, substs, span)
148+
assert_eq!(depth + 1, self.ty_stack_depth);
149+
self.ty_stack_depth -= 1;
150+
if depth == 0 {
151+
self.root_ty = None;
245152
}
246-
}
247-
}
248153

249-
impl Subst for ty::TypeParameterDef {
250-
fn subst_spanned(&self, tcx: &ty::ctxt,
251-
substs: &ty::substs,
252-
span: Option<Span>) -> ty::TypeParameterDef {
253-
ty::TypeParameterDef {
254-
ident: self.ident,
255-
def_id: self.def_id,
256-
bounds: self.bounds.subst_spanned(tcx, substs, span),
257-
default: self.default.map(|x| x.subst_spanned(tcx, substs, span))
258-
}
259-
}
260-
}
261-
262-
impl Subst for ty::Generics {
263-
fn subst_spanned(&self, tcx: &ty::ctxt,
264-
substs: &ty::substs,
265-
span: Option<Span>) -> ty::Generics {
266-
ty::Generics {
267-
type_param_defs: self.type_param_defs.subst_spanned(tcx, substs, span),
268-
region_param_defs: self.region_param_defs.subst_spanned(tcx, substs, span),
269-
}
270-
}
271-
}
272-
273-
impl Subst for ty::RegionParameterDef {
274-
fn subst_spanned(&self, _: &ty::ctxt,
275-
_: &ty::substs,
276-
_: Option<Span>) -> ty::RegionParameterDef {
277-
*self
278-
}
279-
}
280-
281-
impl Subst for ty::Region {
282-
fn subst_spanned(&self, _tcx: &ty::ctxt,
283-
substs: &ty::substs,
284-
_: Option<Span>) -> ty::Region {
285-
// Note: This routine only handles regions that are bound on
286-
// type declarations and other outer declarations, not those
287-
// bound in *fn types*. Region substitution of the bound
288-
// regions that appear in a function signature is done using
289-
// the specialized routine
290-
// `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`.
291-
match self {
292-
&ty::ReEarlyBound(_, i, _) => {
293-
match substs.regions {
294-
ty::ErasedRegions => ty::ReStatic,
295-
ty::NonerasedRegions(ref regions) => *regions.get(i),
296-
}
297-
}
298-
_ => *self
299-
}
300-
}
301-
}
302-
303-
impl Subst for ty::ty_param_bounds_and_ty {
304-
fn subst_spanned(&self, tcx: &ty::ctxt,
305-
substs: &ty::substs,
306-
span: Option<Span>) -> ty::ty_param_bounds_and_ty {
307-
ty::ty_param_bounds_and_ty {
308-
generics: self.generics.subst_spanned(tcx, substs, span),
309-
ty: self.ty.subst_spanned(tcx, substs, span)
310-
}
154+
t1
311155
}
312156
}

src/librustc/middle/ty.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use middle::subst::Subst;
2626
use middle::typeck;
2727
use middle::typeck::MethodCall;
2828
use middle::ty_fold;
29-
use middle::ty_fold::TypeFolder;
29+
use middle::ty_fold::{TypeFoldable,TypeFolder};
3030
use middle;
3131
use util::ppaux::{note_and_explain_region, bound_region_ptr_to_str};
3232
use util::ppaux::{trait_store_to_str, ty_to_str};
@@ -1034,7 +1034,7 @@ pub struct ParameterEnvironment {
10341034
pub self_param_bound: Option<Rc<TraitRef>>,
10351035

10361036
/// Bounds on each numbered type parameter
1037-
pub type_param_bounds: Vec<ParamBounds> ,
1037+
pub type_param_bounds: Vec<ParamBounds>,
10381038
}
10391039

10401040
/// A polytype.
@@ -1519,7 +1519,9 @@ pub fn walk_regions_and_ty(cx: &ctxt, ty: t, fldr: |r: Region|, fldt: |t: t|)
15191519

15201520
impl ItemSubsts {
15211521
pub fn empty() -> ItemSubsts {
1522-
ItemSubsts { substs: substs::empty() }
1522+
ItemSubsts {
1523+
substs: substs::empty(),
1524+
}
15231525
}
15241526

15251527
pub fn is_noop(&self) -> bool {
@@ -4102,8 +4104,8 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t {
41024104
substs: &substs)
41034105
-> substs {
41044106
substs { regions: ErasedRegions,
4105-
self_ty: ty_fold::fold_opt_ty(self, substs.self_ty),
4106-
tps: ty_fold::fold_ty_vec(self, substs.tps.as_slice()) }
4107+
self_ty: substs.self_ty.fold_with(self),
4108+
tps: substs.tps.fold_with(self) }
41074109
}
41084110

41094111
fn fold_sig(&mut self,
@@ -4113,8 +4115,8 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t {
41134115
// are erased at trans time.
41144116
ty::FnSig {
41154117
binder_id: ast::DUMMY_NODE_ID,
4116-
inputs: ty_fold::fold_ty_vec(self, sig.inputs.as_slice()),
4117-
output: self.fold_ty(sig.output),
4118+
inputs: sig.inputs.fold_with(self),
4119+
output: sig.output.fold_with(self),
41184120
variadic: sig.variadic,
41194121
}
41204122
}

0 commit comments

Comments
 (0)