Skip to content

Factor out foldable better to reduce code duplication. #14158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 13, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 56 additions & 212 deletions src/librustc/middle/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,56 +12,48 @@

use middle::ty;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use middle::ty_fold::{TypeFoldable, TypeFolder};
use util::ppaux::Repr;

use std::rc::Rc;
use syntax::codemap::Span;
use syntax::owned_slice::OwnedSlice;

///////////////////////////////////////////////////////////////////////////
// Public trait `Subst`
//
// Just call `foo.subst(tcx, substs)` to perform a substitution across
// `foo`.
// Or use `foo.subst_spanned(tcx, substs, Some(span))` when there is more
// information available (for better errors).
// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
// there is more information available (for better errors).

pub trait Subst {
fn subst(&self, tcx: &ty::ctxt, substs: &ty::substs) -> Self {
self.subst_spanned(tcx, substs, None)
}

fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> Self;
span: Option<Span>)
-> Self;
}

///////////////////////////////////////////////////////////////////////////
// Substitution over types
//
// Because this is so common, we make a special optimization to avoid
// doing anything if `substs` is a no-op. I tried to generalize these
// to all subst methods but ran into trouble due to the limitations of
// our current method/trait matching algorithm. - Niko

impl Subst for ty::t {
fn subst_spanned(&self, tcx: &ty::ctxt,
impl<T:TypeFoldable> Subst for T {
fn subst_spanned(&self,
tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> ty::t {
if ty::substs_is_noop(substs) && !ty::type_has_params(*self) {
*self
} else {
let mut folder = SubstFolder {
tcx: tcx,
substs: substs,
span: span,
root_ty: Some(*self)
};
folder.fold_ty(*self)
}
span: Option<Span>)
-> T
{
let mut folder = SubstFolder { tcx: tcx,
substs: substs,
span: span,
root_ty: None,
ty_stack_depth: 0 };
(*self).fold_with(&mut folder)
}
}

///////////////////////////////////////////////////////////////////////////
// The actual substitution engine itself is a type folder.

struct SubstFolder<'a> {
tcx: &'a ty::ctxt,
substs: &'a ty::substs,
Expand All @@ -70,23 +62,50 @@ struct SubstFolder<'a> {
span: Option<Span>,

// The root type that is being substituted, if available.
root_ty: Option<ty::t>
root_ty: Option<ty::t>,

// Depth of type stack
ty_stack_depth: uint,
}

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

fn fold_region(&mut self, r: ty::Region) -> ty::Region {
r.subst(self.tcx, self.substs)
// Note: This routine only handles regions that are bound on
// type declarations and other outer declarations, not those
// bound in *fn types*. Region substitution of the bound
// regions that appear in a function signature is done using
// the specialized routine
// `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`.
match r {
ty::ReEarlyBound(_, i, _) => {
match self.substs.regions {
ty::ErasedRegions => ty::ReStatic,
ty::NonerasedRegions(ref regions) => *regions.get(i),
}
}
_ => r
}
}

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

match ty::get(t).sty {
// track the root type we were asked to substitute
let depth = self.ty_stack_depth;
if depth == 0 {
self.root_ty = Some(t);
}
self.ty_stack_depth += 1;

let t1 = match ty::get(t).sty {
ty::ty_param(p) => {
// FIXME -- This...really shouldn't happen. We should
// never be substituting without knowing what's in
// scope and knowing that the indices will line up!
if p.idx < self.substs.tps.len() {
*self.substs.tps.get(p.idx)
} else {
Expand Down Expand Up @@ -124,189 +143,14 @@ impl<'a> TypeFolder for SubstFolder<'a> {
}
}
_ => ty_fold::super_fold_ty(self, t)
}
}
}

///////////////////////////////////////////////////////////////////////////
// Other types

impl<T:Subst> Subst for Vec<T> {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> Vec<T> {
self.iter().map(|t| t.subst_spanned(tcx, substs, span)).collect()
}
}
impl<T:Subst> Subst for Rc<T> {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> Rc<T> {
Rc::new((**self).subst_spanned(tcx, substs, span))
}
}

impl<T:Subst> Subst for OwnedSlice<T> {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> OwnedSlice<T> {
self.map(|t| t.subst_spanned(tcx, substs, span))
}
}

impl<T:Subst + 'static> Subst for @T {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> @T {
match self {
t => @(**t).subst_spanned(tcx, substs, span)
}
}
}

impl<T:Subst> Subst for Option<T> {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> Option<T> {
self.as_ref().map(|t| t.subst_spanned(tcx, substs, span))
}
}

impl Subst for ty::TraitRef {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> ty::TraitRef {
ty::TraitRef {
def_id: self.def_id,
substs: self.substs.subst_spanned(tcx, substs, span)
}
}
}

impl Subst for ty::substs {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> ty::substs {
ty::substs {
regions: self.regions.subst_spanned(tcx, substs, span),
self_ty: self.self_ty.map(|typ| typ.subst_spanned(tcx, substs, span)),
tps: self.tps.iter().map(|typ| typ.subst_spanned(tcx, substs, span)).collect()
}
}
}

impl Subst for ty::ItemSubsts {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>)
-> ty::ItemSubsts {
ty::ItemSubsts {
substs: self.substs.subst_spanned(tcx, substs, span)
}
}
}

impl Subst for ty::RegionSubsts {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> ty::RegionSubsts {
match *self {
ty::ErasedRegions => {
ty::ErasedRegions
}
ty::NonerasedRegions(ref regions) => {
ty::NonerasedRegions(regions.subst_spanned(tcx, substs, span))
}
}
}
}

impl Subst for ty::BareFnTy {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> ty::BareFnTy {
let mut folder = SubstFolder {
tcx: tcx,
substs: substs,
span: span,
root_ty: None
};
folder.fold_bare_fn_ty(self)
}
}

impl Subst for ty::ParamBounds {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> ty::ParamBounds {
ty::ParamBounds {
builtin_bounds: self.builtin_bounds,
trait_bounds: self.trait_bounds.subst_spanned(tcx, substs, span)
assert_eq!(depth + 1, self.ty_stack_depth);
self.ty_stack_depth -= 1;
if depth == 0 {
self.root_ty = None;
}
}
}

impl Subst for ty::TypeParameterDef {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> ty::TypeParameterDef {
ty::TypeParameterDef {
ident: self.ident,
def_id: self.def_id,
bounds: self.bounds.subst_spanned(tcx, substs, span),
default: self.default.map(|x| x.subst_spanned(tcx, substs, span))
}
}
}

impl Subst for ty::Generics {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> ty::Generics {
ty::Generics {
type_param_defs: self.type_param_defs.subst_spanned(tcx, substs, span),
region_param_defs: self.region_param_defs.subst_spanned(tcx, substs, span),
}
}
}

impl Subst for ty::RegionParameterDef {
fn subst_spanned(&self, _: &ty::ctxt,
_: &ty::substs,
_: Option<Span>) -> ty::RegionParameterDef {
*self
}
}

impl Subst for ty::Region {
fn subst_spanned(&self, _tcx: &ty::ctxt,
substs: &ty::substs,
_: Option<Span>) -> ty::Region {
// Note: This routine only handles regions that are bound on
// type declarations and other outer declarations, not those
// bound in *fn types*. Region substitution of the bound
// regions that appear in a function signature is done using
// the specialized routine
// `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`.
match self {
&ty::ReEarlyBound(_, i, _) => {
match substs.regions {
ty::ErasedRegions => ty::ReStatic,
ty::NonerasedRegions(ref regions) => *regions.get(i),
}
}
_ => *self
}
}
}

impl Subst for ty::ty_param_bounds_and_ty {
fn subst_spanned(&self, tcx: &ty::ctxt,
substs: &ty::substs,
span: Option<Span>) -> ty::ty_param_bounds_and_ty {
ty::ty_param_bounds_and_ty {
generics: self.generics.subst_spanned(tcx, substs, span),
ty: self.ty.subst_spanned(tcx, substs, span)
}
t1
}
}
16 changes: 9 additions & 7 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use middle::subst::Subst;
use middle::typeck;
use middle::typeck::MethodCall;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use middle::ty_fold::{TypeFoldable,TypeFolder};
use middle;
use util::ppaux::{note_and_explain_region, bound_region_ptr_to_str};
use util::ppaux::{trait_store_to_str, ty_to_str};
Expand Down Expand Up @@ -1034,7 +1034,7 @@ pub struct ParameterEnvironment {
pub self_param_bound: Option<Rc<TraitRef>>,

/// Bounds on each numbered type parameter
pub type_param_bounds: Vec<ParamBounds> ,
pub type_param_bounds: Vec<ParamBounds>,
}

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

impl ItemSubsts {
pub fn empty() -> ItemSubsts {
ItemSubsts { substs: substs::empty() }
ItemSubsts {
substs: substs::empty(),
}
}

pub fn is_noop(&self) -> bool {
Expand Down Expand Up @@ -4102,8 +4104,8 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t {
substs: &substs)
-> substs {
substs { regions: ErasedRegions,
self_ty: ty_fold::fold_opt_ty(self, substs.self_ty),
tps: ty_fold::fold_ty_vec(self, substs.tps.as_slice()) }
self_ty: substs.self_ty.fold_with(self),
tps: substs.tps.fold_with(self) }
}

fn fold_sig(&mut self,
Expand All @@ -4113,8 +4115,8 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t {
// are erased at trans time.
ty::FnSig {
binder_id: ast::DUMMY_NODE_ID,
inputs: ty_fold::fold_ty_vec(self, sig.inputs.as_slice()),
output: self.fold_ty(sig.output),
inputs: sig.inputs.fold_with(self),
output: sig.output.fold_with(self),
variadic: sig.variadic,
}
}
Expand Down
Loading