Skip to content

Generalize the ty::substs struct so that it can represent multiple lifetime parameters #8027

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

Closed
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
20 changes: 18 additions & 2 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ fn parse_trait_store(st: &mut PState) -> ty::TraitStore {
}

fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs {
let self_r = parse_opt(st, |st| parse_region(st) );
let regions = parse_region_substs(st, |x,y| conv(x,y));

let self_ty = parse_opt(st, |st| parse_ty(st, |x,y| conv(x,y)) );

Expand All @@ -196,12 +196,28 @@ fn parse_substs(st: &mut PState, conv: conv_did) -> ty::substs {
st.pos = st.pos + 1u;

return ty::substs {
self_r: self_r,
regions: regions,
self_ty: self_ty,
tps: params
};
}

fn parse_region_substs(st: &mut PState, conv: conv_did) -> ty::RegionSubsts {
match next(st) {
'e' => ty::ErasedRegions,
'n' => {
let mut regions = opt_vec::Empty;
while peek(st) != '.' {
let r = parse_region(st);
regions.push(r);
}
assert_eq!(next(st), '.');
ty::NonerasedRegions(regions)
}
_ => fail!("parse_bound_region: bad input")
}
}

fn parse_bound_region(st: &mut PState) -> ty::bound_region {
match next(st) {
's' => ty::br_self,
Expand Down
17 changes: 16 additions & 1 deletion src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,28 @@ fn enc_opt<T>(w: @io::Writer, t: Option<T>, enc_f: &fn(T)) {
}

fn enc_substs(w: @io::Writer, cx: @ctxt, substs: &ty::substs) {
do enc_opt(w, substs.self_r) |r| { enc_region(w, cx, r) }
enc_region_substs(w, cx, &substs.regions);
do enc_opt(w, substs.self_ty) |t| { enc_ty(w, cx, t) }
w.write_char('[');
for substs.tps.iter().advance |t| { enc_ty(w, cx, *t); }
w.write_char(']');
}

fn enc_region_substs(w: @io::Writer, cx: @ctxt, substs: &ty::RegionSubsts) {
match *substs {
ty::ErasedRegions => {
w.write_char('e');
}
ty::NonerasedRegions(ref regions) => {
w.write_char('n');
for regions.iter().advance |&r| {
enc_region(w, cx, r);
}
w.write_char('.');
}
}
}

fn enc_region(w: @io::Writer, cx: @ctxt, r: ty::Region) {
match r {
ty::re_bound(br) => {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use util::ppaux::UserString;
use syntax::ast::*;
use syntax::attr;
use syntax::codemap::span;
use syntax::opt_vec;
use syntax::print::pprust::expr_to_str;
use syntax::{visit, ast_util};

Expand Down Expand Up @@ -83,7 +84,7 @@ fn check_struct_safe_for_destructor(cx: Context,
let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
if !struct_tpt.generics.has_type_params() {
let struct_ty = ty::mk_struct(cx.tcx, struct_did, ty::substs {
self_r: None,
regions: ty::NonerasedRegions(opt_vec::Empty),
self_ty: None,
tps: ~[]
});
Expand Down
41 changes: 32 additions & 9 deletions src/librustc/middle/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


use middle::ty;
use syntax::opt_vec::OptVec;
use util::ppaux::Repr;

///////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -79,6 +80,12 @@ impl<T:Subst> Subst for ~[T] {
}
}

impl<T:Subst> Subst for OptVec<T> {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> OptVec<T> {
self.map(|t| t.subst(tcx, substs))
}
}

impl<T:Subst + 'static> Subst for @T {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @T {
match self {
Expand All @@ -105,13 +112,26 @@ impl Subst for ty::TraitRef {
impl Subst for ty::substs {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::substs {
ty::substs {
self_r: self.self_r.subst(tcx, substs),
regions: self.regions.subst(tcx, substs),
self_ty: self.self_ty.map(|typ| typ.subst(tcx, substs)),
tps: self.tps.map(|typ| typ.subst(tcx, substs))
}
}
}

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

impl Subst for ty::BareFnTy {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::BareFnTy {
ty::fold_bare_fn_ty(self, |t| t.subst(tcx, substs))
Expand Down Expand Up @@ -158,15 +178,18 @@ impl Subst for ty::Region {
// will most likely disappear.
match self {
&ty::re_bound(ty::br_self) => {
match substs.self_r {
None => {
tcx.sess.bug(
fmt!("ty::Region#subst(): \
Reference to self region when \
given substs with no self region: %s",
substs.repr(tcx)));
match substs.regions {
ty::ErasedRegions => ty::re_static,
ty::NonerasedRegions(ref regions) => {
if regions.len() != 1 {
tcx.sess.bug(
fmt!("ty::Region#subst(): \
Reference to self region when \
given substs with no self region: %s",
substs.repr(tcx)));
}
*regions.get(0)
}
Some(self_r) => self_r
}
}
_ => *self
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,8 @@ pub fn get_res_dtor(ccx: @mut CrateContext,
did
};
assert_eq!(did.crate, ast::local_crate);
let tsubsts = ty::substs { self_r: None, self_ty: None,
let tsubsts = ty::substs {regions: ty::ErasedRegions,
self_ty: None,
tps: /*bad*/ substs.to_owned() };
let (val, _) = monomorphize::monomorphic_fn(ccx,
did,
Expand Down
7 changes: 1 addition & 6 deletions src/librustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,10 @@ pub fn trans_fn_ref_with_vtables(
// Polytype of the function item (may have type params)
let fn_tpt = ty::lookup_item_type(tcx, def_id);

// For simplicity, we want to use the Subst trait when composing
// substitutions for default methods. The subst trait does
// substitutions with regions, though, so we put a dummy self
// region parameter in to keep it from failing. This is a hack.
let substs = ty::substs { self_r: Some(ty::re_empty),
let substs = ty::substs { regions: ty::ErasedRegions,
self_ty: None,
tps: /*bad*/ type_params.to_owned() };


// We need to do a bunch of special handling for default methods.
// We need to modify the def_id and our substs in order to monomorphize
// the function.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ pub fn find_vtable(tcx: ty::ctxt,

pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs {
substs {
self_r: Some(ty::re_bound(ty::br_self)),
regions: ty::ErasedRegions,
self_ty: None,
tps: tps
}
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/middle/trans/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use util::ppaux;
use middle::trans::type_::Type;

use syntax::ast;
use syntax::opt_vec;

pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: &ty::t) -> bool {
!ty::type_is_immediate(ccx.tcx, *arg_ty)
Expand Down Expand Up @@ -312,7 +313,8 @@ pub fn llvm_type_name(cx: &CrateContext,
a_struct => { "struct" }
an_enum => { "enum" }
};
let tstr = ppaux::parameterized(cx.tcx, ty::item_path_str(cx.tcx, did), None, tps);
let tstr = ppaux::parameterized(cx.tcx, ty::item_path_str(cx.tcx, did),
&ty::NonerasedRegions(opt_vec::Empty), tps);
if did.crate == 0 {
fmt!("%s.%s", name, tstr)
} else {
Expand Down
90 changes: 60 additions & 30 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,15 @@ pub enum bound_region {
br_cap_avoid(ast::node_id, @bound_region),
}

type opt_region = Option<Region>;
/**
* Represents the values to use when substituting lifetime parameters.
* If the value is `ErasedRegions`, then this subst is occurring during
* trans, and all region parameters will be replaced with `ty::re_static`. */
#[deriving(Clone, Eq, IterBytes)]
pub enum RegionSubsts {
ErasedRegions,
NonerasedRegions(OptVec<ty::Region>)
}

/**
* The type substs represents the kinds of things that can be substituted to
Expand All @@ -507,9 +515,9 @@ type opt_region = Option<Region>;
* always substituted away to the implementing type for a trait. */
#[deriving(Clone, Eq, IterBytes)]
pub struct substs {
self_r: opt_region,
self_ty: Option<ty::t>,
tps: ~[t]
tps: ~[t],
regions: RegionSubsts,
}

mod primitives {
Expand Down Expand Up @@ -948,7 +956,14 @@ fn mk_t(cx: ctxt, st: sty) -> t {
fn sflags(substs: &substs) -> uint {
let mut f = 0u;
for substs.tps.iter().advance |tt| { f |= get(*tt).flags; }
for substs.self_r.iter().advance |r| { f |= rflags(*r) }
match substs.regions {
ErasedRegions => {}
NonerasedRegions(ref regions) => {
for regions.iter().advance |r| {
f |= rflags(*r)
}
}
}
return f;
}
match &st {
Expand Down Expand Up @@ -1286,7 +1301,7 @@ pub fn fold_bare_fn_ty(fty: &BareFnTy, fldop: &fn(t) -> t) -> BareFnTy {

fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty {
fn fold_substs(substs: &substs, fldop: &fn(t) -> t) -> substs {
substs {self_r: substs.self_r,
substs {regions: substs.regions.clone(),
self_ty: substs.self_ty.map(|t| fldop(*t)),
tps: substs.tps.map(|t| fldop(*t))}
}
Expand Down Expand Up @@ -1378,8 +1393,15 @@ pub fn fold_regions_and_ty(
fldr: &fn(r: Region) -> Region,
fldt: &fn(t: t) -> t)
-> substs {
let regions = match substs.regions {
ErasedRegions => ErasedRegions,
NonerasedRegions(ref regions) => {
NonerasedRegions(regions.map(|r| fldr(*r)))
}
};

substs {
self_r: substs.self_r.map(|r| fldr(*r)),
regions: regions,
self_ty: substs.self_ty.map(|t| fldt(*t)),
tps: substs.tps.map(|t| fldt(*t))
}
Expand Down Expand Up @@ -1478,8 +1500,13 @@ pub fn subst_tps(cx: ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t {
}

pub fn substs_is_noop(substs: &substs) -> bool {
let regions_is_noop = match substs.regions {
ErasedRegions => false, // may be used to canonicalize
NonerasedRegions(ref regions) => regions.is_empty()
};

substs.tps.len() == 0u &&
substs.self_r.is_none() &&
regions_is_noop &&
substs.self_ty.is_none()
}

Expand Down Expand Up @@ -4227,30 +4254,33 @@ pub fn normalize_ty(cx: ctxt, t: t) -> t {
})
}

ty_enum(did, ref r) =>
match (*r).self_r {
Some(_) =>
// Use re_static since trans doesn't care about regions
mk_enum(cx, did,
substs {
self_r: Some(ty::re_static),
self_ty: None,
tps: (*r).tps.clone()
}),
None =>
ty_enum(did, ref r) => {
match (*r).regions {
NonerasedRegions(_) => {
// trans doesn't care about regions
mk_enum(cx, did, substs {regions: ty::ErasedRegions,
self_ty: None,
tps: (*r).tps.clone()})
}
ErasedRegions => {
t
},
}
}
}

ty_struct(did, ref r) =>
match (*r).self_r {
Some(_) =>
// Ditto.
mk_struct(cx, did, substs {self_r: Some(ty::re_static),
self_ty: None,
tps: (*r).tps.clone()}),
None =>
t
},
ty_struct(did, ref r) => {
match (*r).regions {
NonerasedRegions(_) => {
// Ditto.
mk_struct(cx, did, substs {regions: ty::ErasedRegions,
self_ty: None,
tps: (*r).tps.clone()})
}
ErasedRegions => {
t
}
}
}

_ =>
t
Expand Down Expand Up @@ -4434,7 +4464,7 @@ pub fn visitor_object_ty(tcx: ctxt) -> Result<(@TraitRef, t), ~str> {
Err(s) => { return Err(s); }
};
let substs = substs {
self_r: None,
regions: ty::NonerasedRegions(opt_vec::Empty),
self_ty: None,
tps: ~[]
};
Expand Down
Loading