// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. // Generalized type folding mechanism. use middle::ty; use util::ppaux::Repr; pub trait TypeFolder { fn tcx(&self) -> ty::ctxt; fn fold_ty(&mut self, t: ty::t) -> ty::t { super_fold_ty(self, t) } fn fold_mt(&mut self, t: &ty::mt) -> ty::mt { super_fold_mt(self, t) } fn fold_trait_ref(&mut self, t: &ty::TraitRef) -> ty::TraitRef { super_fold_trait_ref(self, t) } fn fold_sty(&mut self, sty: &ty::sty) -> ty::sty { super_fold_sty(self, sty) } fn fold_substs(&mut self, substs: &ty::substs) -> ty::substs { super_fold_substs(self, substs) } fn fold_sig(&mut self, sig: &ty::FnSig) -> ty::FnSig { super_fold_sig(self, sig) } fn fold_bare_fn_ty(&mut self, fty: &ty::BareFnTy) -> ty::BareFnTy { ty::BareFnTy { sig: self.fold_sig(&fty.sig), abis: fty.abis, purity: fty.purity } } fn fold_closure_ty(&mut self, fty: &ty::ClosureTy) -> ty::ClosureTy { ty::ClosureTy { region: self.fold_region(fty.region), sig: self.fold_sig(&fty.sig), purity: fty.purity, sigil: fty.sigil, onceness: fty.onceness, bounds: fty.bounds, } } fn fold_region(&mut self, r: ty::Region) -> ty::Region { r } fn fold_vstore(&mut self, vstore: ty::vstore) -> ty::vstore { super_fold_vstore(self, vstore) } fn fold_trait_store(&mut self, s: ty::TraitStore) -> ty::TraitStore { super_fold_trait_store(self, s) } } pub fn fold_opt_ty(this: &mut T, t: Option) -> Option { t.map(|t| this.fold_ty(t)) } pub fn fold_ty_vec(this: &mut T, tys: &[ty::t]) -> ~[ty::t] { tys.map(|t| this.fold_ty(*t)) } pub fn super_fold_ty(this: &mut T, t: ty::t) -> ty::t { ty::mk_t(this.tcx(), this.fold_sty(&ty::get(t).sty)) } pub fn super_fold_substs(this: &mut T, substs: &ty::substs) -> ty::substs { let regions = match substs.regions { ty::ErasedRegions => { ty::ErasedRegions } ty::NonerasedRegions(ref regions) => { ty::NonerasedRegions(regions.map(|r| this.fold_region(*r))) } }; ty::substs { regions: regions, self_ty: fold_opt_ty(this, substs.self_ty), tps: fold_ty_vec(this, substs.tps), } } pub fn super_fold_sig(this: &mut T, sig: &ty::FnSig) -> ty::FnSig { ty::FnSig { binder_id: sig.binder_id, inputs: fold_ty_vec(this, sig.inputs), output: this.fold_ty(sig.output), variadic: sig.variadic } } pub fn super_fold_trait_ref(this: &mut T, t: &ty::TraitRef) -> ty::TraitRef { ty::TraitRef { def_id: t.def_id, substs: this.fold_substs(&t.substs) } } pub fn super_fold_mt(this: &mut T, mt: &ty::mt) -> ty::mt { ty::mt {ty: this.fold_ty(mt.ty), mutbl: mt.mutbl} } pub fn super_fold_sty(this: &mut T, sty: &ty::sty) -> ty::sty { match *sty { ty::ty_box(typ) => { ty::ty_box(this.fold_ty(typ)) } ty::ty_uniq(ref tm) => { ty::ty_uniq(this.fold_mt(tm)) } ty::ty_ptr(ref tm) => { ty::ty_ptr(this.fold_mt(tm)) } ty::ty_unboxed_vec(ref tm) => { ty::ty_unboxed_vec(this.fold_mt(tm)) } ty::ty_vec(ref tm, vst) => { ty::ty_vec(this.fold_mt(tm), this.fold_vstore(vst)) } ty::ty_enum(tid, ref substs) => { ty::ty_enum(tid, this.fold_substs(substs)) } ty::ty_trait(did, ref substs, st, mutbl, bounds) => { ty::ty_trait(did, this.fold_substs(substs), this.fold_trait_store(st), mutbl, bounds) } ty::ty_tup(ref ts) => { ty::ty_tup(fold_ty_vec(this, *ts)) } ty::ty_bare_fn(ref f) => { ty::ty_bare_fn(this.fold_bare_fn_ty(f)) } ty::ty_closure(ref f) => { ty::ty_closure(this.fold_closure_ty(f)) } ty::ty_rptr(r, ref tm) => { ty::ty_rptr(this.fold_region(r), ty::mt {ty: this.fold_ty(tm.ty), mutbl: tm.mutbl}) } ty::ty_struct(did, ref substs) => { ty::ty_struct(did, this.fold_substs(substs)) } ty::ty_str(vst) => { ty::ty_str(this.fold_vstore(vst)) } ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | ty::ty_type | ty::ty_opaque_closure_ptr(_) | ty::ty_err | ty::ty_infer(_) | ty::ty_param(..) | ty::ty_self(_) => { (*sty).clone() } } } pub fn super_fold_vstore(this: &mut T, vstore: ty::vstore) -> ty::vstore { match vstore { ty::vstore_fixed(i) => ty::vstore_fixed(i), ty::vstore_uniq => ty::vstore_uniq, ty::vstore_box => ty::vstore_box, ty::vstore_slice(r) => ty::vstore_slice(this.fold_region(r)), } } pub fn super_fold_trait_store(this: &mut T, trait_store: ty::TraitStore) -> ty::TraitStore { match trait_store { ty::UniqTraitStore => ty::UniqTraitStore, ty::BoxTraitStore => ty::BoxTraitStore, ty::RegionTraitStore(r) => ty::RegionTraitStore(this.fold_region(r)), } } /////////////////////////////////////////////////////////////////////////// // Some sample folders pub struct BottomUpFolder<'a> { tcx: ty::ctxt, fldop: 'a |ty::t| -> ty::t, } impl<'a> TypeFolder for BottomUpFolder<'a> { fn tcx(&self) -> ty::ctxt { self.tcx } fn fold_ty(&mut self, ty: ty::t) -> ty::t { let t1 = super_fold_ty(self, ty); (self.fldop)(t1) } } /////////////////////////////////////////////////////////////////////////// // Region folder pub struct RegionFolder<'a> { tcx: ty::ctxt, fld_t: 'a |ty::t| -> ty::t, fld_r: 'a |ty::Region| -> ty::Region, } impl<'a> RegionFolder<'a> { pub fn general(tcx: ty::ctxt, fld_r: 'a |ty::Region| -> ty::Region, fld_t: 'a |ty::t| -> ty::t) -> RegionFolder<'a> { RegionFolder { tcx: tcx, fld_t: fld_t, fld_r: fld_r } } pub fn regions(tcx: ty::ctxt, fld_r: 'a |ty::Region| -> ty::Region) -> RegionFolder<'a> { fn noop(t: ty::t) -> ty::t { t } RegionFolder { tcx: tcx, fld_t: noop, fld_r: fld_r } } } impl<'a> TypeFolder for RegionFolder<'a> { fn tcx(&self) -> ty::ctxt { self.tcx } fn fold_ty(&mut self, ty: ty::t) -> ty::t { debug!("RegionFolder.fold_ty({})", ty.repr(self.tcx())); let t1 = super_fold_ty(self, ty); (self.fld_t)(t1) } fn fold_region(&mut self, r: ty::Region) -> ty::Region { debug!("RegionFolder.fold_region({})", r.repr(self.tcx())); (self.fld_r)(r) } }