auto merge of #14055 : nikomatsakis/rust/issue-5527-use-substs-in-trans, r=pcwalton

Code to use `ty::substs` in trans. As part of this, uncovered (and fixed) issue #14050.

r? @pcwalton
This commit is contained in:
bors 2014-05-09 14:51:38 -07:00
commit 3d6cf1d525
21 changed files with 436 additions and 354 deletions

View File

@ -128,7 +128,7 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f
tag_table_val = 0x45,
tag_table_def = 0x46,
tag_table_node_type = 0x47,
tag_table_node_type_subst = 0x48,
tag_table_item_subst = 0x48,
tag_table_freevars = 0x49,
tag_table_tcache = 0x4a,
tag_table_param_defs = 0x4b,

View File

@ -657,13 +657,13 @@ pub fn encode_vtable_origin(ecx: &e::EncodeContext,
vtable_origin: &typeck::vtable_origin) {
ebml_w.emit_enum("vtable_origin", |ebml_w| {
match *vtable_origin {
typeck::vtable_static(def_id, ref tys, ref vtable_res) => {
typeck::vtable_static(def_id, ref substs, ref vtable_res) => {
ebml_w.emit_enum_variant("vtable_static", 0u, 3u, |ebml_w| {
ebml_w.emit_enum_variant_arg(0u, |ebml_w| {
Ok(ebml_w.emit_def_id(def_id))
});
ebml_w.emit_enum_variant_arg(1u, |ebml_w| {
Ok(ebml_w.emit_tys(ecx, tys.as_slice()))
Ok(ebml_w.emit_substs(ecx, substs))
});
ebml_w.emit_enum_variant_arg(2u, |ebml_w| {
Ok(encode_vtable_res(ecx, ebml_w, vtable_res))
@ -744,7 +744,7 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
Ok(this.read_def_id_noxcx(cdata))
}).unwrap(),
this.read_enum_variant_arg(1u, |this| {
Ok(this.read_tys_noxcx(tcx, cdata))
Ok(this.read_substs_noxcx(tcx, cdata))
}).unwrap(),
this.read_enum_variant_arg(2u, |this| {
Ok(this.read_vtable_res(tcx, cdata))
@ -962,11 +962,11 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
})
}
for tys in tcx.node_type_substs.borrow().find(&id).iter() {
ebml_w.tag(c::tag_table_node_type_subst, |ebml_w| {
for &item_substs in tcx.item_substs.borrow().find(&id).iter() {
ebml_w.tag(c::tag_table_item_subst, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
ebml_w.emit_tys(ecx, tys.as_slice())
ebml_w.emit_substs(ecx, &item_substs.substs);
})
})
}
@ -1091,6 +1091,9 @@ trait ebml_decoder_decoder_helpers {
fn read_tys_noxcx(&mut self,
tcx: &ty::ctxt,
cdata: &cstore::crate_metadata) -> Vec<ty::t>;
fn read_substs_noxcx(&mut self, tcx: &ty::ctxt,
cdata: &cstore::crate_metadata)
-> ty::substs;
}
impl<'a> ebml_decoder_decoder_helpers for reader::Decoder<'a> {
@ -1115,6 +1118,21 @@ impl<'a> ebml_decoder_decoder_helpers for reader::Decoder<'a> {
.collect()
}
fn read_substs_noxcx(&mut self,
tcx: &ty::ctxt,
cdata: &cstore::crate_metadata)
-> ty::substs
{
self.read_opaque(|_, doc| {
Ok(tydecode::parse_substs_data(
doc.data,
cdata.cnum,
doc.start,
tcx,
|_, id| decoder::translate_def_id(cdata, id)))
}).unwrap()
}
fn read_ty(&mut self, xcx: &ExtendedDecodeContext) -> ty::t {
// Note: regions types embed local node ids. In principle, we
// should translate these node ids into the new decode
@ -1312,9 +1330,12 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
id, ty_to_str(dcx.tcx, ty));
dcx.tcx.node_types.borrow_mut().insert(id as uint, ty);
}
c::tag_table_node_type_subst => {
let tys = val_dsr.read_tys(xcx);
dcx.tcx.node_type_substs.borrow_mut().insert(id, tys);
c::tag_table_item_subst => {
let item_substs = ty::ItemSubsts {
substs: val_dsr.read_substs(xcx)
};
dcx.tcx.item_substs.borrow_mut().insert(
id, item_substs);
}
c::tag_table_freevars => {
let fv_info = val_dsr.read_to_vec(|val_dsr| {

View File

@ -245,10 +245,10 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
{
let method_map = cx.tcx.method_map.borrow();
let method = method_map.find(&typeck::MethodCall::expr(e.id));
let node_type_substs = cx.tcx.node_type_substs.borrow();
let item_substs = cx.tcx.item_substs.borrow();
let r = match method {
Some(method) => Some(&method.substs.tps),
None => node_type_substs.find(&e.id)
None => item_substs.find(&e.id).map(|s| &s.substs.tps)
};
for ts in r.iter() {
let def_map = cx.tcx.def_map.borrow();
@ -341,15 +341,19 @@ fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span:
fn check_ty(cx: &mut Context, aty: &Ty) {
match aty.node {
TyPath(_, _, id) => {
let node_type_substs = cx.tcx.node_type_substs.borrow();
let r = node_type_substs.find(&id);
for ts in r.iter() {
let def_map = cx.tcx.def_map.borrow();
let did = ast_util::def_id_of_def(def_map.get_copy(&id));
let generics = ty::lookup_item_type(cx.tcx, did).generics;
let type_param_defs = generics.type_param_defs();
for (&ty, type_param_def) in ts.iter().zip(type_param_defs.iter()) {
check_typaram_bounds(cx, aty.span, ty, type_param_def)
match cx.tcx.item_substs.borrow().find(&id) {
None => { }
Some(ref item_substs) => {
let def_map = cx.tcx.def_map.borrow();
let did = ast_util::def_id_of_def(def_map.get_copy(&id));
let generics = ty::lookup_item_type(cx.tcx, did).generics;
let type_param_defs = generics.type_param_defs();
for (&ty, type_param_def) in
item_substs.substs.tps.iter().zip(
type_param_defs.iter())
{
check_typaram_bounds(cx, aty.span, ty, type_param_def)
}
}
}
}

View File

@ -195,6 +195,17 @@ impl Subst for ty::substs {
}
}
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,

View File

@ -478,7 +478,7 @@ pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: ~str) {
pub fn get_res_dtor(ccx: &CrateContext,
did: ast::DefId,
parent_id: ast::DefId,
substs: &[ty::t])
substs: &ty::substs)
-> ValueRef {
let _icx = push_ctxt("trans_res_dtor");
let did = if did.krate != ast::LOCAL_CRATE {
@ -486,16 +486,12 @@ pub fn get_res_dtor(ccx: &CrateContext,
} else {
did
};
if !substs.is_empty() {
assert_eq!(did.krate, ast::LOCAL_CRATE);
let tsubsts = ty::substs {
regions: ty::ErasedRegions,
self_ty: None,
tps: Vec::from_slice(substs),
};
let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx(), did.node, &tsubsts);
let (val, _) = monomorphize::monomorphic_fn(ccx, did, &tsubsts, vtables, None, None);
if !substs.tps.is_empty() || !substs.self_ty.is_none() {
assert_eq!(did.krate, ast::LOCAL_CRATE);
let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx(), did.node, substs);
let (val, _) = monomorphize::monomorphic_fn(ccx, did, substs, vtables, None, None);
val
} else if did.krate == ast::LOCAL_CRATE {
@ -503,10 +499,8 @@ pub fn get_res_dtor(ccx: &CrateContext,
} else {
let tcx = ccx.tcx();
let name = csearch::get_symbol(&ccx.sess().cstore, did);
let class_ty = ty::subst_tps(tcx,
substs,
None,
ty::lookup_item_type(tcx, parent_id).ty);
let class_ty = ty::subst(tcx, substs,
ty::lookup_item_type(tcx, parent_id).ty);
let llty = type_of_dtor(ccx, class_ty);
get_extern_fn(&mut *ccx.externs.borrow_mut(), ccx.llmod, name,
@ -670,7 +664,7 @@ pub fn iter_structural_ty<'r,
repr: &adt::Repr,
av: ValueRef,
variant: &ty::VariantInfo,
tps: &[ty::t],
substs: &ty::substs,
f: val_and_ty_fn<'r,'b>)
-> &'b Block<'b> {
let _icx = push_ctxt("iter_variant");
@ -680,7 +674,7 @@ pub fn iter_structural_ty<'r,
for (i, &arg) in variant.args.iter().enumerate() {
cx = f(cx,
adt::trans_field_ptr(cx, repr, av, variant.disr_val, i),
ty::subst_tps(tcx, tps, None, arg));
ty::subst(tcx, substs, arg));
}
return cx;
}
@ -722,7 +716,7 @@ pub fn iter_structural_ty<'r,
match adt::trans_switch(cx, &*repr, av) {
(_match::single, None) => {
cx = iter_variant(cx, &*repr, av, &**variants.get(0),
substs.tps.as_slice(), f);
substs, f);
}
(_match::switch, Some(lldiscrim_a)) => {
cx = f(cx, lldiscrim_a, ty::mk_int());
@ -748,7 +742,7 @@ pub fn iter_structural_ty<'r,
&*repr,
av,
&**variant,
substs.tps.as_slice(),
substs,
|x,y,z| f(x,y,z));
Br(variant_cx, next_cx.llbb);
}
@ -1153,15 +1147,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
},
id, param_substs.map(|s| s.repr(ccx.tcx())));
let substd_output_type = match param_substs {
None => output_type,
Some(substs) => {
ty::subst_tps(ccx.tcx(),
substs.tys.as_slice(),
substs.self_ty,
output_type)
}
};
let substd_output_type = output_type.substp(ccx.tcx(), param_substs);
let uses_outptr = type_of::return_uses_outptr(ccx, substd_output_type);
let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
@ -1213,15 +1199,7 @@ pub fn init_function<'a>(fcx: &'a FunctionContext<'a>,
// This shouldn't need to recompute the return type,
// as new_fn_ctxt did it already.
let substd_output_type = match fcx.param_substs {
None => output_type,
Some(substs) => {
ty::subst_tps(fcx.ccx.tcx(),
substs.tys.as_slice(),
substs.self_ty,
output_type)
}
};
let substd_output_type = output_type.substp(fcx.ccx.tcx(), fcx.param_substs);
if !return_type_is_void(fcx.ccx, substd_output_type) {
// If the function returns nil/bot, there is no real return
@ -1508,18 +1486,8 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
disr: ty::Disr,
param_substs: Option<&param_substs>,
llfndecl: ValueRef) {
let ctor_ty = {
let no_substs: &[ty::t] = [];
let ty_param_substs: &[ty::t] = match param_substs {
Some(substs) => substs.tys.as_slice(),
None => no_substs
};
ty::subst_tps(ccx.tcx(),
ty_param_substs,
None,
ty::node_id_to_type(ccx.tcx(), ctor_id))
};
let ctor_ty = ty::node_id_to_type(ccx.tcx(), ctor_id);
let ctor_ty = ctor_ty.substp(ccx.tcx(), param_substs);
let result_ty = match ty::get(ctor_ty).sty {
ty::ty_bare_fn(ref bft) => bft.sig.output,

View File

@ -159,36 +159,36 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> {
pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId, node: ExprOrMethodCall) -> ValueRef {
/*!
*
* Translates a reference (with id `ref_id`) to the fn/method
* with id `def_id` into a function pointer. This may require
* monomorphization or inlining. */
* monomorphization or inlining.
*/
let _icx = push_ctxt("trans_fn_ref");
let type_params = node_id_type_params(bcx, node);
let substs = node_id_substs(bcx, node);
let vtable_key = match node {
ExprId(id) => MethodCall::expr(id),
MethodCall(method_call) => method_call
};
let vtables = node_vtables(bcx, vtable_key);
debug!("trans_fn_ref(def_id={}, node={:?}, type_params={}, vtables={})",
def_id.repr(bcx.tcx()), node, type_params.repr(bcx.tcx()),
debug!("trans_fn_ref(def_id={}, node={:?}, substs={}, vtables={})",
def_id.repr(bcx.tcx()),
node,
substs.repr(bcx.tcx()),
vtables.repr(bcx.tcx()));
trans_fn_ref_with_vtables(bcx, def_id, node,
type_params,
vtables)
trans_fn_ref_with_vtables(bcx, def_id, node, substs, vtables)
}
fn trans_fn_ref_with_vtables_to_callee<'a>(bcx: &'a Block<'a>,
def_id: ast::DefId,
ref_id: ast::NodeId,
type_params: Vec<ty::t>,
substs: ty::substs,
vtables: Option<typeck::vtable_res>)
-> Callee<'a> {
Callee {bcx: bcx,
data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ExprId(ref_id),
type_params, vtables))}
substs, vtables))}
}
fn resolve_default_method_vtables(bcx: &Block,
@ -204,8 +204,7 @@ fn resolve_default_method_vtables(bcx: &Block,
// Build up a param_substs that we are going to resolve the
// trait_vtables under.
let param_substs = param_substs {
tys: substs.tps.clone(),
self_ty: substs.self_ty,
substs: (*substs).clone(),
vtables: impl_vtables.clone(),
self_vtables: None
};
@ -241,7 +240,7 @@ pub fn trans_fn_ref_with_vtables(
bcx: &Block, //
def_id: ast::DefId, // def id of fn
node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A
type_params: Vec<ty::t>, // values for fn's ty params
substs: ty::substs, // values for fn's ty params
vtables: Option<typeck::vtable_res>) // vtables for the call
-> ValueRef {
/*!
@ -255,7 +254,7 @@ pub fn trans_fn_ref_with_vtables(
* - `node`: node id of the reference to the fn/method, if applicable.
* This parameter may be zero; but, if so, the resulting value may not
* have the right type, so it must be cast before being used.
* - `type_params`: values for each of the fn/method's type parameters
* - `substs`: values for each of the fn/method's parameters
* - `vtables`: values for each bound on each of the type parameters
*/
@ -264,24 +263,18 @@ pub fn trans_fn_ref_with_vtables(
let tcx = bcx.tcx();
debug!("trans_fn_ref_with_vtables(bcx={}, def_id={}, node={:?}, \
type_params={}, vtables={})",
substs={}, vtables={})",
bcx.to_str(),
def_id.repr(tcx),
node,
type_params.repr(tcx),
substs.repr(tcx),
vtables.repr(tcx));
assert!(type_params.iter().all(|t| !ty::type_needs_infer(*t)));
assert!(substs.tps.iter().all(|t| !ty::type_needs_infer(*t)));
// Polytype of the function item (may have type params)
let fn_tpt = ty::lookup_item_type(tcx, def_id);
let substs = ty::substs {
regions: ty::ErasedRegions,
self_ty: None,
tps: type_params
};
// Load the info for the appropriate trait if necessary.
match ty::trait_of_method(tcx, def_id) {
None => {}
@ -510,7 +503,7 @@ pub fn trans_lang_call<'a>(
trans_fn_ref_with_vtables_to_callee(bcx,
did,
0,
vec!(),
ty::substs::empty(),
None)
},
ArgVals(args),

View File

@ -25,6 +25,7 @@ use middle::trans::datum::{Datum, Lvalue};
use middle::trans::debuginfo;
use middle::trans::type_::Type;
use middle::ty;
use middle::subst::Subst;
use middle::typeck;
use util::ppaux::Repr;
use util::nodemap::NodeMap;
@ -177,23 +178,24 @@ pub type ExternMap = HashMap<~str, ValueRef>;
// Here `self_ty` is the real type of the self parameter to this method. It
// will only be set in the case of default methods.
pub struct param_substs {
pub tys: Vec<ty::t> ,
pub self_ty: Option<ty::t>,
pub substs: ty::substs,
pub vtables: Option<typeck::vtable_res>,
pub self_vtables: Option<typeck::vtable_param_res>
}
impl param_substs {
pub fn validate(&self) {
for t in self.tys.iter() { assert!(!ty::type_needs_infer(*t)); }
for t in self.self_ty.iter() { assert!(!ty::type_needs_infer(*t)); }
for t in self.substs.tps.iter() {
assert!(!ty::type_needs_infer(*t));
}
for t in self.substs.self_ty.iter() {
assert!(!ty::type_needs_infer(*t));
}
}
}
fn param_substs_to_str(this: &param_substs, tcx: &ty::ctxt) -> ~str {
format!("param_substs \\{tys:{}, vtables:{}\\}",
this.tys.repr(tcx),
this.vtables.repr(tcx))
format!("param_substs({})", this.substs.repr(tcx))
}
impl Repr for param_substs {
@ -202,6 +204,25 @@ impl Repr for param_substs {
}
}
pub trait SubstP {
fn substp(&self, tcx: &ty::ctxt, param_substs: Option<&param_substs>)
-> Self;
}
impl<T:Subst+Clone> SubstP for T {
fn substp(&self, tcx: &ty::ctxt, param_substs: Option<&param_substs>)
-> T {
match param_substs {
Some(substs) => {
self.subst(tcx, &substs.substs)
}
None => {
(*self).clone()
}
}
}
}
// work around bizarre resolve errors
pub type RvalueDatum = datum::Datum<datum::Rvalue>;
pub type LvalueDatum = datum::Datum<datum::Lvalue>;
@ -676,7 +697,7 @@ pub fn is_null(val: ValueRef) -> bool {
pub fn monomorphize_type(bcx: &Block, t: ty::t) -> ty::t {
match bcx.fcx.param_substs {
Some(ref substs) => {
ty::subst_tps(bcx.tcx(), substs.tys.as_slice(), substs.self_ty, t)
ty::subst(bcx.tcx(), &substs.substs, t)
}
_ => {
assert!(!ty::type_has_params(t));
@ -710,32 +731,28 @@ pub enum ExprOrMethodCall {
MethodCall(typeck::MethodCall)
}
pub fn node_id_type_params(bcx: &Block, node: ExprOrMethodCall) -> Vec<ty::t> {
pub fn node_id_substs(bcx: &Block,
node: ExprOrMethodCall)
-> ty::substs {
let tcx = bcx.tcx();
let params = match node {
ExprId(id) => ty::node_id_to_type_params(tcx, id),
let substs = match node {
ExprId(id) => {
ty::node_id_item_substs(tcx, id).substs
}
MethodCall(method_call) => {
tcx.method_map.borrow().get(&method_call).substs.tps.clone()
tcx.method_map.borrow().get(&method_call).substs.clone()
}
};
if !params.iter().all(|t| !ty::type_needs_infer(*t)) {
if !substs.tps.iter().all(|t| !ty::type_needs_infer(*t)) {
bcx.sess().bug(
format!("type parameters for node {:?} include inference types: {}",
node, params.iter()
.map(|t| bcx.ty_to_str(*t))
.collect::<Vec<~str>>()
.connect(",")));
node,
substs.repr(bcx.tcx())));
}
match bcx.fcx.param_substs {
Some(ref substs) => {
params.iter().map(|t| {
ty::subst_tps(tcx, substs.tys.as_slice(), substs.self_ty, *t)
}).collect()
}
_ => params
}
substs.substp(tcx, bcx.fcx.param_substs)
}
pub fn node_vtables(bcx: &Block, id: typeck::MethodCall)
@ -785,20 +802,10 @@ pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt,
vt: &typeck::vtable_origin)
-> typeck::vtable_origin {
match *vt {
typeck::vtable_static(trait_id, ref tys, ref sub) => {
let tys = match param_substs {
Some(substs) => {
tys.iter().map(|t| {
ty::subst_tps(tcx,
substs.tys.as_slice(),
substs.self_ty,
*t)
}).collect()
}
_ => Vec::from_slice(tys.as_slice())
};
typeck::vtable_static(trait_id, ref vtable_substs, ref sub) => {
let vtable_substs = vtable_substs.substp(tcx, param_substs);
typeck::vtable_static(
trait_id, tys,
trait_id, vtable_substs,
resolve_vtables_under_param_substs(tcx, param_substs, sub.as_slice()))
}
typeck::vtable_param(n_param, n_bound) => {

View File

@ -793,16 +793,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
assert_type_for_node_id(cx, fn_ast_id, error_span);
let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id);
let return_type = match param_substs {
None => return_type,
Some(substs) => {
ty::subst_tps(cx.tcx(),
substs.tys.as_slice(),
substs.self_ty,
return_type)
}
};
let return_type = return_type.substp(cx.tcx(), param_substs);
signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP));
}
}
@ -811,16 +802,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
for arg in fn_decl.inputs.iter() {
assert_type_for_node_id(cx, arg.pat.id, arg.pat.span);
let arg_type = ty::node_id_to_type(cx.tcx(), arg.pat.id);
let arg_type = match param_substs {
None => arg_type,
Some(substs) => {
ty::subst_tps(cx.tcx(),
substs.tys.as_slice(),
substs.self_ty,
arg_type)
}
};
let arg_type = arg_type.substp(cx.tcx(), param_substs);
signature.push(type_metadata(cx, arg_type, codemap::DUMMY_SP));
}
@ -834,7 +816,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
name_to_append_suffix_to: &mut StrBuf)
-> DIArray {
let self_type = match param_substs {
Some(param_substs) => param_substs.self_ty,
Some(param_substs) => param_substs.substs.self_ty,
_ => None
};
@ -890,7 +872,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
// Handle other generic parameters
let actual_types = match param_substs {
Some(param_substs) => &param_substs.tys,
Some(param_substs) => &param_substs.substs.tps,
None => {
return create_DIArray(DIB(cx), template_params.as_slice());
}

View File

@ -236,7 +236,7 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
// Find and call the actual destructor
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did,
class_did, substs.tps.as_slice());
class_did, substs);
// The second argument is the "self" argument for drop
let params = unsafe {

View File

@ -295,7 +295,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
RetVoid(bcx);
}
"size_of" => {
let tp_ty = *substs.tys.get(0);
let tp_ty = *substs.substs.tps.get(0);
let lltp_ty = type_of::type_of(ccx, tp_ty);
Ret(bcx, C_uint(ccx, machine::llsize_of_real(ccx, lltp_ty) as uint));
}
@ -305,7 +305,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
// if the value is non-immediate. Note that, with
// intrinsics, there are no argument cleanups to
// concern ourselves with, so we can use an rvalue datum.
let tp_ty = *substs.tys.get(0);
let tp_ty = *substs.substs.tps.get(0);
let mode = appropriate_rvalue_mode(ccx, tp_ty);
let src = Datum {val: get_param(decl, first_real_arg + 1u),
ty: tp_ty,
@ -314,17 +314,17 @@ pub fn trans_intrinsic(ccx: &CrateContext,
RetVoid(bcx);
}
"min_align_of" => {
let tp_ty = *substs.tys.get(0);
let tp_ty = *substs.substs.tps.get(0);
let lltp_ty = type_of::type_of(ccx, tp_ty);
Ret(bcx, C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty) as uint));
}
"pref_align_of"=> {
let tp_ty = *substs.tys.get(0);
let tp_ty = *substs.substs.tps.get(0);
let lltp_ty = type_of::type_of(ccx, tp_ty);
Ret(bcx, C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty) as uint));
}
"get_tydesc" => {
let tp_ty = *substs.tys.get(0);
let tp_ty = *substs.substs.tps.get(0);
let static_ti = get_tydesc(ccx, tp_ty);
glue::lazily_emit_visit_glue(ccx, &*static_ti);
@ -339,7 +339,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
"type_id" => {
let hash = ty::hash_crate_independent(
ccx.tcx(),
*substs.tys.get(0),
*substs.substs.tps.get(0),
&ccx.link_meta.crate_hash);
// NB: This needs to be kept in lockstep with the TypeId struct in
// libstd/unstable/intrinsics.rs
@ -354,7 +354,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
}
}
"init" => {
let tp_ty = *substs.tys.get(0);
let tp_ty = *substs.substs.tps.get(0);
let lltp_ty = type_of::type_of(ccx, tp_ty);
match bcx.fcx.llretptr.get() {
Some(ptr) => { Store(bcx, C_null(lltp_ty), ptr); RetVoid(bcx); }
@ -364,7 +364,7 @@ pub fn trans_intrinsic(ccx: &CrateContext,
}
"uninit" => {
// Do nothing, this is effectively a no-op
let retty = *substs.tys.get(0);
let retty = *substs.substs.tps.get(0);
if type_is_immediate(ccx, retty) && !return_type_is_void(ccx, retty) {
unsafe {
Ret(bcx, lib::llvm::llvm::LLVMGetUndef(type_of(ccx, retty).to_ref()));
@ -377,7 +377,8 @@ pub fn trans_intrinsic(ccx: &CrateContext,
RetVoid(bcx);
}
"transmute" => {
let (in_type, out_type) = (*substs.tys.get(0), *substs.tys.get(1));
let (in_type, out_type) = (*substs.substs.tps.get(0),
*substs.substs.tps.get(1));
let llintype = type_of::type_of(ccx, in_type);
let llouttype = type_of::type_of(ccx, out_type);
@ -444,11 +445,11 @@ pub fn trans_intrinsic(ccx: &CrateContext,
}
}
"needs_drop" => {
let tp_ty = *substs.tys.get(0);
let tp_ty = *substs.substs.tps.get(0);
Ret(bcx, C_bool(ccx, ty::type_needs_drop(ccx.tcx(), tp_ty)));
}
"owns_managed" => {
let tp_ty = *substs.tys.get(0);
let tp_ty = *substs.substs.tps.get(0);
Ret(bcx, C_bool(ccx, ty::type_contents(ccx.tcx(), tp_ty).owns_managed()));
}
"visit_tydesc" => {
@ -464,14 +465,20 @@ pub fn trans_intrinsic(ccx: &CrateContext,
let lladdr = InBoundsGEP(bcx, ptr, [offset]);
Ret(bcx, lladdr);
}
"copy_nonoverlapping_memory" => copy_intrinsic(bcx, false, false, *substs.tys.get(0)),
"copy_memory" => copy_intrinsic(bcx, true, false, *substs.tys.get(0)),
"set_memory" => memset_intrinsic(bcx, false, *substs.tys.get(0)),
"copy_nonoverlapping_memory" => {
copy_intrinsic(bcx, false, false, *substs.substs.tps.get(0))
}
"copy_memory" => {
copy_intrinsic(bcx, true, false, *substs.substs.tps.get(0))
}
"set_memory" => {
memset_intrinsic(bcx, false, *substs.substs.tps.get(0))
}
"volatile_copy_nonoverlapping_memory" =>
copy_intrinsic(bcx, false, true, *substs.tys.get(0)),
"volatile_copy_memory" => copy_intrinsic(bcx, true, true, *substs.tys.get(0)),
"volatile_set_memory" => memset_intrinsic(bcx, true, *substs.tys.get(0)),
copy_intrinsic(bcx, false, true, *substs.substs.tps.get(0)),
"volatile_copy_memory" => copy_intrinsic(bcx, true, true, *substs.substs.tps.get(0)),
"volatile_set_memory" => memset_intrinsic(bcx, true, *substs.substs.tps.get(0)),
"ctlz8" => count_zeros_intrinsic(bcx, "llvm.ctlz.i8"),
"ctlz16" => count_zeros_intrinsic(bcx, "llvm.ctlz.i16"),

View File

@ -198,7 +198,7 @@ pub fn trans_static_method_callee(bcx: &Block,
match vtbls.move_iter().nth(bound_index).unwrap().move_iter().nth(0).unwrap() {
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t)));
assert!(rcvr_substs.tps.iter().all(|t| !ty::type_needs_infer(*t)));
let mth_id = method_with_name(ccx, impl_did, mname);
let (callee_substs, callee_origins) =
@ -277,39 +277,41 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>,
fn combine_impl_and_methods_tps(bcx: &Block,
mth_did: ast::DefId,
node: ExprOrMethodCall,
rcvr_substs: Vec<ty::t>,
rcvr_substs: ty::substs,
rcvr_origins: typeck::vtable_res)
-> (Vec<ty::t>, typeck::vtable_res) {
-> (ty::substs, typeck::vtable_res)
{
/*!
*
* Creates a concatenated set of substitutions which includes
* those from the impl and those from the method. This are
* some subtle complications here. Statically, we have a list
* of type parameters like `[T0, T1, T2, M1, M2, M3]` where
* `Tn` are type parameters that appear on the receiver. For
* example, if the receiver is a method parameter `A` with a
* bound like `trait<B,C,D>` then `Tn` would be `[B,C,D]`.
*
* The weird part is that the type `A` might now be bound to
* any other type, such as `foo<X>`. In that case, the vector
* we want is: `[X, M1, M2, M3]`. Therefore, what we do now is
* to slice off the method type parameters and append them to
* the type parameters from the type that the receiver is
* mapped to. */
* Creates a concatenated set of substitutions which includes
* those from the impl and those from the method. This are
* some subtle complications here. Statically, we have a list
* of type parameters like `[T0, T1, T2, M1, M2, M3]` where
* `Tn` are type parameters that appear on the receiver. For
* example, if the receiver is a method parameter `A` with a
* bound like `trait<B,C,D>` then `Tn` would be `[B,C,D]`.
*
* The weird part is that the type `A` might now be bound to
* any other type, such as `foo<X>`. In that case, the vector
* we want is: `[X, M1, M2, M3]`. Therefore, what we do now is
* to slice off the method type parameters and append them to
* the type parameters from the type that the receiver is
* mapped to.
*/
let ccx = bcx.ccx();
let method = ty::method(ccx.tcx(), mth_did);
let n_m_tps = method.generics.type_param_defs().len();
let node_substs = node_id_type_params(bcx, node);
let node_substs = node_id_substs(bcx, node);
debug!("rcvr_substs={:?}", rcvr_substs.repr(ccx.tcx()));
debug!("node_substs={:?}", node_substs.repr(ccx.tcx()));
let mut ty_substs = rcvr_substs;
let rcvr_self_ty = rcvr_substs.self_ty;
let mut tps = rcvr_substs.tps;
{
let start = node_substs.len() - n_m_tps;
ty_substs.extend(node_substs.move_iter().skip(start));
let start = node_substs.tps.len() - n_m_tps;
tps.extend(node_substs.tps.move_iter().skip(start));
}
debug!("n_m_tps={:?}", n_m_tps);
debug!("ty_substs={:?}", ty_substs.repr(ccx.tcx()));
debug!("tps={}", tps.repr(ccx.tcx()));
// Now, do the same work for the vtables. The vtables might not
@ -333,6 +335,12 @@ fn combine_impl_and_methods_tps(bcx: &Block,
}
}
let ty_substs = ty::substs {
tps: tps,
regions: ty::ErasedRegions,
self_ty: rcvr_self_ty
};
(ty_substs, vtables)
}
@ -485,7 +493,7 @@ pub fn make_vtable<I: Iterator<ValueRef>>(ccx: &CrateContext,
fn emit_vtable_methods(bcx: &Block,
impl_id: ast::DefId,
substs: Vec<ty::t>,
substs: ty::substs,
vtables: typeck::vtable_res)
-> Vec<ValueRef> {
let ccx = bcx.ccx();

View File

@ -85,9 +85,8 @@ pub fn monomorphic_fn(ccx: &CrateContext,
}
let psubsts = param_substs {
tys: real_substs.tps.clone(),
substs: (*real_substs).clone(),
vtables: vtables,
self_ty: real_substs.self_ty.clone(),
self_vtables: self_vtables
};
@ -139,8 +138,7 @@ pub fn monomorphic_fn(ccx: &CrateContext,
debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx()));
let mono_ty = match is_static_provided {
None => ty::subst_tps(ccx.tcx(), real_substs.tps.as_slice(),
real_substs.self_ty, llitem_ty),
None => ty::subst(ccx.tcx(), real_substs, llitem_ty),
Some(num_method_ty_params) => {
// Static default methods are a little unfortunate, in
// that the "internal" and "external" type of them differ.
@ -157,13 +155,19 @@ pub fn monomorphic_fn(ccx: &CrateContext,
// This is a bit unfortunate.
let idx = real_substs.tps.len() - num_method_ty_params;
let substs = Vec::from_slice(real_substs.tps.slice(0, idx))
.append([real_substs.self_ty.unwrap()])
.append(real_substs.tps.tailn(idx));
let mut tps = Vec::new();
tps.push_all(real_substs.tps.slice(0, idx));
tps.push(real_substs.self_ty.unwrap());
tps.push_all(real_substs.tps.tailn(idx));
let substs = ty::substs { regions: ty::ErasedRegions,
self_ty: None,
tps: tps };
debug!("static default: changed substitution to {}",
substs.repr(ccx.tcx()));
ty::subst_tps(ccx.tcx(), substs.as_slice(), None, llitem_ty)
ty::subst(ccx.tcx(), &substs, llitem_ty)
}
};
@ -334,7 +338,10 @@ pub fn make_vtable_id(ccx: &CrateContext,
&typeck::vtable_static(impl_id, ref substs, ref sub_vtables) => {
MonoId {
def: impl_id,
params: sub_vtables.iter().zip(substs.iter()).map(|(vtable, subst)| {
// FIXME(NDM) -- this is pretty bogus. It ignores self-type,
// and vtables are not necessary, AND they are not guaranteed
// to be same length as the number of TPS ANYHOW!
params: sub_vtables.iter().zip(substs.tps.iter()).map(|(vtable, subst)| {
MonoParamId {
subst: *subst,
// Do we really need the vtables to be hashed? Isn't the type enough?

View File

@ -255,9 +255,9 @@ pub struct ctxt {
// Stores the type parameters which were substituted to obtain the type
// of this node. This only applies to nodes that refer to entities
// parameterized by type parameters, such as generic fns, types, or
// param<eterized by type parameters, such as generic fns, types, or
// other items.
pub node_type_substs: RefCell<NodeMap<Vec<t>>>,
pub item_substs: RefCell<NodeMap<ItemSubsts>>,
// Maps from a method to the method "descriptor"
pub methods: RefCell<DefIdMap<Rc<Method>>>,
@ -1060,6 +1060,13 @@ pub struct TraitDef {
pub trait_ref: Rc<ty::TraitRef>,
}
/// Records the substitutions used to translate the polytype for an
/// item into the monotype of an item reference.
#[deriving(Clone)]
pub struct ItemSubsts {
pub substs: ty::substs,
}
pub struct ty_param_substs_and_ty {
pub substs: ty::substs,
pub ty: ty::t
@ -1086,7 +1093,7 @@ pub fn mk_ctxt(s: Session,
def_map: dm,
region_maps: region_maps,
node_types: RefCell::new(HashMap::new()),
node_type_substs: RefCell::new(NodeMap::new()),
item_substs: RefCell::new(NodeMap::new()),
trait_refs: RefCell::new(NodeMap::new()),
trait_defs: RefCell::new(DefIdMap::new()),
map: map,
@ -1510,47 +1517,13 @@ pub fn walk_regions_and_ty(cx: &ctxt, ty: t, fldr: |r: Region|, fldt: |t: t|)
|t| { fldt(t); t }).fold_ty(ty)
}
// Substitute *only* type parameters. Used in trans where regions are erased.
pub fn subst_tps(tcx: &ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t {
let mut subst = TpsSubst { tcx: tcx, self_ty_opt: self_ty_opt, tps: tps };
return subst.fold_ty(typ);
struct TpsSubst<'a> {
tcx: &'a ctxt,
self_ty_opt: Option<t>,
tps: &'a [t],
impl ItemSubsts {
pub fn empty() -> ItemSubsts {
ItemSubsts { substs: substs::empty() }
}
impl<'a> TypeFolder for TpsSubst<'a> {
fn tcx<'a>(&'a self) -> &'a ctxt { self.tcx }
fn fold_ty(&mut self, t: ty::t) -> ty::t {
if self.tps.len() == 0u && self.self_ty_opt.is_none() {
return t;
}
let tb = ty::get(t);
if self.self_ty_opt.is_none() && !tbox_has_flag(tb, has_params) {
return t;
}
match ty::get(t).sty {
ty_param(p) => {
self.tps[p.idx]
}
ty_self(_) => {
match self.self_ty_opt {
None => self.tcx.sess.bug("ty_self unexpected here"),
Some(self_ty) => self_ty
}
}
_ => {
ty_fold::super_fold_ty(self, t)
}
}
}
pub fn is_noop(&self) -> bool {
ty::substs_is_noop(&self.substs)
}
}
@ -2669,11 +2642,10 @@ pub fn node_id_to_type_opt(cx: &ctxt, id: ast::NodeId) -> Option<t> {
}
}
// FIXME(pcwalton): Makes a copy, bleh. Probably better to not do that.
pub fn node_id_to_type_params(cx: &ctxt, id: ast::NodeId) -> Vec<t> {
match cx.node_type_substs.borrow().find(&id) {
None => return Vec::new(),
Some(ts) => return (*ts).clone(),
pub fn node_id_item_substs(cx: &ctxt, id: ast::NodeId) -> ItemSubsts {
match cx.item_substs.borrow().find(&id) {
None => ItemSubsts::empty(),
Some(ts) => ts.clone(),
}
}
@ -2991,21 +2963,6 @@ impl AutoRef {
}
}
pub struct ParamsTy {
pub params: Vec<t>,
pub ty: t
}
#[allow(dead_code)] // this may be useful?
pub fn expr_ty_params_and_ty(cx: &ctxt,
expr: &ast::Expr)
-> ParamsTy {
ParamsTy {
params: node_id_to_type_params(cx, expr.id),
ty: node_id_to_type(cx, expr.id)
}
}
pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin)
-> Rc<Vec<TypeParameterDef>> {
match origin {

View File

@ -52,7 +52,7 @@ can be broken down into several distinct phases:
While type checking a function, the intermediate types for the
expressions, blocks, and so forth contained within the function are
stored in `fcx.node_types` and `fcx.node_type_substs`. These types
stored in `fcx.node_types` and `fcx.item_substs`. These types
may contain unresolved type variables. After type checking is
complete, the functions in the writeback module are used to take the
types from this table, resolve them, and then write them into their
@ -161,7 +161,7 @@ pub struct Inherited<'a> {
// Temporary tables:
node_types: RefCell<NodeMap<ty::t>>,
node_type_substs: RefCell<NodeMap<ty::substs>>,
item_substs: RefCell<NodeMap<ty::ItemSubsts>>,
adjustments: RefCell<NodeMap<ty::AutoAdjustment>>,
method_map: MethodMap,
vtable_map: vtable_map,
@ -268,7 +268,7 @@ impl<'a> Inherited<'a> {
locals: RefCell::new(NodeMap::new()),
param_env: param_env,
node_types: RefCell::new(NodeMap::new()),
node_type_substs: RefCell::new(NodeMap::new()),
item_substs: RefCell::new(NodeMap::new()),
adjustments: RefCell::new(NodeMap::new()),
method_map: RefCell::new(FnvHashMap::new()),
vtable_map: RefCell::new(FnvHashMap::new()),
@ -1111,22 +1111,22 @@ impl<'a> FnCtxt<'a> {
self.inh.node_types.borrow_mut().insert(node_id, ty);
}
pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::substs) {
if !ty::substs_is_noop(&substs) {
pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts) {
if !ty::substs_is_noop(&substs.substs) {
debug!("write_substs({}, {}) in fcx {}",
node_id,
ty::substs_to_str(self.tcx(), &substs),
substs.repr(self.tcx()),
self.tag());
self.inh.node_type_substs.borrow_mut().insert(node_id, substs);
self.inh.item_substs.borrow_mut().insert(node_id, substs);
}
}
pub fn write_ty_substs(&self,
node_id: ast::NodeId,
ty: ty::t,
substs: ty::substs) {
let ty = ty::subst(self.tcx(), &substs, ty);
substs: ty::ItemSubsts) {
let ty = ty::subst(self.tcx(), &substs.substs, ty);
self.write_ty(node_id, ty);
self.write_substs(node_id, substs);
}
@ -1204,8 +1204,8 @@ impl<'a> FnCtxt<'a> {
pub fn opt_node_ty_substs(&self,
id: ast::NodeId,
f: |&ty::substs|) {
match self.inh.node_type_substs.borrow().find(&id) {
f: |&ty::ItemSubsts|) {
match self.inh.item_substs.borrow().find(&id) {
Some(s) => { f(s) }
None => { }
}
@ -3963,10 +3963,10 @@ pub fn instantiate_path(fcx: &FnCtxt,
(tps, regions)
};
fcx.write_ty_substs(node_id, tpt.ty, substs {
regions: regions,
self_ty: None,
tps: tps
fcx.write_ty_substs(node_id, tpt.ty, ty::ItemSubsts {
substs: substs { regions: regions,
self_ty: None,
tps: tps }
});
debug!("<<<");

View File

@ -299,7 +299,7 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
// regionck assumes typeck succeeded
rcx.visit_expr(e, ());
}
fcx.infcx().resolve_regions();
fcx.infcx().resolve_regions_and_report_errors();
}
pub fn regionck_fn(fcx: &FnCtxt, blk: &ast::Block) {
@ -309,7 +309,7 @@ pub fn regionck_fn(fcx: &FnCtxt, blk: &ast::Block) {
// regionck assumes typeck succeeded
rcx.visit_block(blk, ());
}
fcx.infcx().resolve_regions();
fcx.infcx().resolve_regions_and_report_errors();
}
impl<'a> Visitor<()> for Rcx<'a> {

View File

@ -15,6 +15,7 @@ use middle::ty_fold::TypeFolder;
use middle::typeck::astconv::AstConv;
use middle::typeck::check::{FnCtxt, impl_self_ty};
use middle::typeck::check::{structurally_resolved_type};
use middle::typeck::check::writeback;
use middle::typeck::infer::fixup_err_to_str;
use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
use middle::typeck::infer;
@ -444,7 +445,7 @@ fn search_for_vtable(vcx: &VtableContext,
// Finally, we register that we found a matching impl, and
// record the def ID of the impl as well as the resolved list
// of type substitutions for the target trait.
found.push(vtable_static(impl_did, substs_f.tps.clone(), subres));
found.push(vtable_static(impl_did, substs_f, subres));
}
match found.len() {
@ -625,7 +626,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
};
match ex.node {
ast::ExprPath(..) => {
fcx.opt_node_ty_substs(ex.id, |substs| {
fcx.opt_node_ty_substs(ex.id, |item_substs| {
debug!("vtable resolution on parameter bounds for expr {}",
ex.repr(fcx.tcx()));
let def = cx.tcx.def_map.borrow().get_copy(&ex.id);
@ -639,7 +640,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
let vcx = fcx.vtable_context();
let vtbls = lookup_vtables(&vcx, ex.span,
item_ty.generics.type_param_defs(),
substs, is_early);
&item_substs.substs, is_early);
if !is_early {
insert_vtables(fcx, MethodCall::expr(ex.id), vtbls);
}
@ -734,6 +735,9 @@ pub fn resolve_impl(tcx: &ty::ctxt,
impl_item: &ast::Item,
impl_generics: &ty::Generics,
impl_trait_ref: &ty::TraitRef) {
debug!("resolve_impl(impl_item.id={})",
impl_item.id);
let param_env = ty::construct_parameter_environment(
tcx,
None,
@ -744,6 +748,7 @@ pub fn resolve_impl(tcx: &ty::ctxt,
impl_item.id);
let impl_trait_ref = impl_trait_ref.subst(tcx, &param_env.free_substs);
debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx));
let infcx = &infer::new_infer_ctxt(tcx);
let vcx = VtableContext { infcx: infcx, param_env: &param_env };
@ -774,13 +779,19 @@ pub fn resolve_impl(tcx: &ty::ctxt,
lookup_vtables_for_param(&vcx, impl_item.span, None,
&param_bounds, t, false);
infcx.resolve_regions_and_report_errors();
let res = impl_res {
trait_vtables: vtbls,
self_vtables: self_vtable_res
};
let res = writeback::resolve_impl_res(infcx, impl_item.span, &res);
let impl_def_id = ast_util::local_def(impl_item.id);
debug!("impl_vtables for {} are {}",
impl_def_id.repr(tcx),
res.repr(tcx));
tcx.impl_vtables.borrow_mut().insert(impl_def_id, res);
}

View File

@ -21,12 +21,15 @@ use middle::typeck::check::FnCtxt;
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::impl_res;
use middle::typeck::{MethodCall, MethodCallee};
use middle::typeck::{vtable_origin, vtable_static, vtable_param};
use middle::typeck::write_substs_to_tcx;
use middle::typeck::write_ty_to_tcx;
use util::ppaux::Repr;
use std::cell::Cell;
use syntax::ast;
use syntax::codemap::Span;
use syntax::print::pprust::pat_to_str;
@ -61,6 +64,17 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
wbcx.visit_upvar_borrow_map();
}
pub fn resolve_impl_res(infcx: &infer::InferCtxt,
span: Span,
impl_res: &impl_res)
-> impl_res {
let errors = Cell::new(false); // nobody cares
let mut resolver = Resolver::from_infcx(infcx,
&errors,
ResolvingImplRes(span));
impl_res.resolve_in(&mut resolver)
}
///////////////////////////////////////////////////////////////////////////
// The Writerback context. This visitor walks the AST, checking the
// fn-specific tables to find references to types or regions. It
@ -159,7 +173,7 @@ impl<'cx> Visitor<()> for WritebackCx<'cx> {
}
let var_ty = self.fcx.local_ty(l.span, l.id);
let var_ty = var_ty.resolve(self.fcx, ResolvingLocal(l.span));
let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
write_ty_to_tcx(self.tcx(), l.id, var_ty);
visit::walk_local(self, l, ());
}
@ -177,7 +191,7 @@ impl<'cx> WritebackCx<'cx> {
for (upvar_id, upvar_borrow) in self.fcx.inh.upvar_borrow_map.borrow().iter() {
let r = upvar_borrow.region;
let r = r.resolve(self.fcx, ResolvingUpvar(*upvar_id));
let r = self.resolve(&r, ResolvingUpvar(*upvar_id));
let new_upvar_borrow = ty::UpvarBorrow { kind: upvar_borrow.kind,
region: r };
debug!("Upvar borrow for {} resolved to {}",
@ -194,17 +208,14 @@ impl<'cx> WritebackCx<'cx> {
// Resolve the type of the node with id `id`
let n_ty = self.fcx.node_ty(id);
let n_ty = n_ty.resolve(self.fcx, reason);
let n_ty = self.resolve(&n_ty, reason);
write_ty_to_tcx(self.tcx(), id, n_ty);
debug!("Node {} has type {}", id, n_ty.repr(self.tcx()));
// Resolve any substitutions
self.fcx.opt_node_ty_substs(id, |node_substs| {
let mut new_tps = Vec::new();
for subst in node_substs.tps.iter() {
new_tps.push(subst.resolve(self.fcx, reason));
}
write_substs_to_tcx(self.tcx(), id, new_tps);
self.fcx.opt_node_ty_substs(id, |item_substs| {
write_substs_to_tcx(self.tcx(), id,
self.resolve(item_substs, reason));
});
}
@ -228,12 +239,12 @@ impl<'cx> WritebackCx<'cx> {
}
_ => {
self.tcx().sess.span_err(
reason.span(self.fcx),
reason.span(self.tcx()),
"cannot coerce non-statically resolved bare fn")
}
}
ty::AutoAddEnv(store.resolve(self.fcx, reason))
ty::AutoAddEnv(self.resolve(&store, reason))
}
ty::AutoDerefRef(adj) => {
@ -245,7 +256,7 @@ impl<'cx> WritebackCx<'cx> {
ty::AutoDerefRef(ty::AutoDerefRef {
autoderefs: adj.autoderefs,
autoref: adj.autoref.resolve(self.fcx, reason),
autoref: self.resolve(&adj.autoref, reason),
})
}
@ -269,8 +280,8 @@ impl<'cx> WritebackCx<'cx> {
method.repr(self.tcx()));
let mut new_method = MethodCallee {
origin: method.origin,
ty: method.ty.resolve(self.fcx, reason),
substs: method.substs.resolve(self.fcx, reason),
ty: self.resolve(&method.ty, reason),
substs: self.resolve(&method.substs, reason),
};
// Wack. For some reason I don't quite know, we always
@ -297,7 +308,7 @@ impl<'cx> WritebackCx<'cx> {
// Resolve any vtable map entry
match self.fcx.inh.vtable_map.borrow_mut().pop(&vtable_key) {
Some(origins) => {
let r_origins = origins.resolve(self.fcx, reason);
let r_origins = self.resolve(&origins, reason);
debug!("writeback::resolve_vtable_map_entry(\
vtable_key={}, vtables={:?})",
vtable_key, r_origins.repr(self.tcx()));
@ -306,6 +317,10 @@ impl<'cx> WritebackCx<'cx> {
None => {}
}
}
fn resolve<T:ResolveIn>(&self, t: &T, reason: ResolveReason) -> T {
t.resolve_in(&mut Resolver::new(self.fcx, reason))
}
}
///////////////////////////////////////////////////////////////////////////
@ -315,18 +330,20 @@ enum ResolveReason {
ResolvingExpr(Span),
ResolvingLocal(Span),
ResolvingPattern(Span),
ResolvingUpvar(ty::UpvarId)
ResolvingUpvar(ty::UpvarId),
ResolvingImplRes(Span),
}
impl ResolveReason {
fn span(&self, fcx: &FnCtxt) -> Span {
fn span(&self, tcx: &ty::ctxt) -> Span {
match *self {
ResolvingExpr(s) => s,
ResolvingLocal(s) => s,
ResolvingPattern(s) => s,
ResolvingUpvar(upvar_id) => {
ty::expr_span(fcx.tcx(), upvar_id.closure_expr_id)
ty::expr_span(tcx, upvar_id.closure_expr_id)
}
ResolvingImplRes(s) => s,
}
}
}
@ -334,59 +351,67 @@ impl ResolveReason {
///////////////////////////////////////////////////////////////////////////
// Convenience methods for resolving different kinds of things.
trait Resolve {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Self;
trait ResolveIn {
fn resolve_in(&self, resolver: &mut Resolver) -> Self;
}
impl<T:Resolve> Resolve for Option<T> {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Option<T> {
self.as_ref().map(|t| t.resolve(fcx, reason))
impl<T:ResolveIn> ResolveIn for Option<T> {
fn resolve_in(&self, resolver: &mut Resolver) -> Option<T> {
self.as_ref().map(|t| t.resolve_in(resolver))
}
}
impl<T:Resolve> Resolve for Vec<T> {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> Vec<T> {
self.iter().map(|t| t.resolve(fcx, reason)).collect()
impl<T:ResolveIn> ResolveIn for Vec<T> {
fn resolve_in(&self, resolver: &mut Resolver) -> Vec<T> {
self.iter().map(|t| t.resolve_in(resolver)).collect()
}
}
impl Resolve for ty::TraitStore {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::TraitStore {
Resolver::new(fcx, reason).fold_trait_store(*self)
impl ResolveIn for ty::TraitStore {
fn resolve_in(&self, resolver: &mut Resolver) -> ty::TraitStore {
resolver.fold_trait_store(*self)
}
}
impl Resolve for ty::t {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::t {
Resolver::new(fcx, reason).fold_ty(*self)
impl ResolveIn for ty::t {
fn resolve_in(&self, resolver: &mut Resolver) -> ty::t {
resolver.fold_ty(*self)
}
}
impl Resolve for ty::Region {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::Region {
Resolver::new(fcx, reason).fold_region(*self)
impl ResolveIn for ty::Region {
fn resolve_in(&self, resolver: &mut Resolver) -> ty::Region {
resolver.fold_region(*self)
}
}
impl Resolve for ty::substs {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::substs {
Resolver::new(fcx, reason).fold_substs(self)
impl ResolveIn for ty::substs {
fn resolve_in(&self, resolver: &mut Resolver) -> ty::substs {
resolver.fold_substs(self)
}
}
impl Resolve for ty::AutoRef {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> ty::AutoRef {
Resolver::new(fcx, reason).fold_autoref(self)
impl ResolveIn for ty::ItemSubsts {
fn resolve_in(&self, resolver: &mut Resolver) -> ty::ItemSubsts {
ty::ItemSubsts {
substs: self.substs.resolve_in(resolver)
}
}
}
impl Resolve for vtable_origin {
fn resolve(&self, fcx: &FnCtxt, reason: ResolveReason) -> vtable_origin {
impl ResolveIn for ty::AutoRef {
fn resolve_in(&self, resolver: &mut Resolver) -> ty::AutoRef {
resolver.fold_autoref(self)
}
}
impl ResolveIn for vtable_origin {
fn resolve_in(&self, resolver: &mut Resolver) -> vtable_origin {
match *self {
vtable_static(def_id, ref tys, ref origins) => {
let r_tys = tys.resolve(fcx, reason);
let r_origins = origins.resolve(fcx, reason);
vtable_static(def_id, r_tys, r_origins)
vtable_static(def_id, ref substs, ref origins) => {
let r_substs = substs.resolve_in(resolver);
let r_origins = origins.resolve_in(resolver);
vtable_static(def_id, r_substs, r_origins)
}
vtable_param(n, b) => {
vtable_param(n, b)
@ -395,12 +420,23 @@ impl Resolve for vtable_origin {
}
}
impl ResolveIn for impl_res {
fn resolve_in(&self, resolver: &mut Resolver) -> impl_res {
impl_res {
trait_vtables: self.trait_vtables.resolve_in(resolver),
self_vtables: self.self_vtables.resolve_in(resolver),
}
}
}
///////////////////////////////////////////////////////////////////////////
// The Resolver. This is the type folding engine that detects
// unresolved types and so forth.
struct Resolver<'cx> {
fcx: &'cx FnCtxt<'cx>,
tcx: &'cx ty::ctxt,
infcx: &'cx infer::InferCtxt<'cx>,
writeback_errors: &'cx Cell<bool>,
reason: ResolveReason,
}
@ -409,15 +445,29 @@ impl<'cx> Resolver<'cx> {
reason: ResolveReason)
-> Resolver<'cx>
{
Resolver { fcx: fcx, reason: reason }
Resolver { infcx: fcx.infcx(),
tcx: fcx.tcx(),
writeback_errors: &fcx.writeback_errors,
reason: reason }
}
fn from_infcx(infcx: &'cx infer::InferCtxt<'cx>,
writeback_errors: &'cx Cell<bool>,
reason: ResolveReason)
-> Resolver<'cx>
{
Resolver { infcx: infcx,
tcx: infcx.tcx,
writeback_errors: writeback_errors,
reason: reason }
}
fn report_error(&self, e: infer::fixup_err) {
self.fcx.writeback_errors.set(true);
if !self.tcx().sess.has_errors() {
self.writeback_errors.set(true);
if !self.tcx.sess.has_errors() {
match self.reason {
ResolvingExpr(span) => {
self.tcx().sess.span_err(
self.tcx.sess.span_err(
span,
format!("cannot determine a type for \
this expression: {}",
@ -425,7 +475,7 @@ impl<'cx> Resolver<'cx> {
}
ResolvingLocal(span) => {
self.tcx().sess.span_err(
self.tcx.sess.span_err(
span,
format!("cannot determine a type for \
this local variable: {}",
@ -433,7 +483,7 @@ impl<'cx> Resolver<'cx> {
}
ResolvingPattern(span) => {
self.tcx().sess.span_err(
self.tcx.sess.span_err(
span,
format!("cannot determine a type for \
this pattern binding: {}",
@ -441,16 +491,22 @@ impl<'cx> Resolver<'cx> {
}
ResolvingUpvar(upvar_id) => {
let span = self.reason.span(self.fcx);
self.tcx().sess.span_err(
let span = self.reason.span(self.tcx);
self.tcx.sess.span_err(
span,
format!("cannot resolve lifetime for \
captured variable `{}`: {}",
ty::local_var_name_str(
self.tcx(),
self.tcx,
upvar_id.var_id).get().to_str(),
infer::fixup_err_to_str(e)));
}
ResolvingImplRes(span) => {
self.tcx.sess.span_err(
span,
format!("cannot determine a type for impl supertrait"));
}
}
}
}
@ -458,7 +514,7 @@ impl<'cx> Resolver<'cx> {
impl<'cx> TypeFolder for Resolver<'cx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
self.fcx.tcx()
self.tcx
}
fn fold_ty(&mut self, t: ty::t) -> ty::t {
@ -466,7 +522,7 @@ impl<'cx> TypeFolder for Resolver<'cx> {
return t;
}
match resolve_type(self.fcx.infcx(), t, resolve_all | force_all) {
match resolve_type(self.infcx, t, resolve_all | force_all) {
Ok(t) => t,
Err(e) => {
self.report_error(e);
@ -476,7 +532,7 @@ impl<'cx> TypeFolder for Resolver<'cx> {
}
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
match resolve_region(self.fcx.infcx(), r, resolve_all | force_all) {
match resolve_region(self.infcx, r, resolve_all | force_all) {
Ok(r) => r,
Err(e) => {
self.report_error(e);

View File

@ -644,7 +644,7 @@ impl<'a> InferCtxt<'a> {
self.region_vars.new_bound(binder_id)
}
pub fn resolve_regions(&self) {
pub fn resolve_regions_and_report_errors(&self) {
let errors = self.region_vars.resolve_regions();
self.report_region_errors(&errors); // see error_reporting.rs
}

View File

@ -184,7 +184,7 @@ pub enum vtable_origin {
from whence comes the vtable, and tys are the type substs.
vtable_res is the vtable itself
*/
vtable_static(ast::DefId, Vec<ty::t>, vtable_res),
vtable_static(ast::DefId, ty::substs, vtable_res),
/*
Dynamic vtable, comes from a parameter that has a bound on it:
@ -253,13 +253,16 @@ pub fn write_ty_to_tcx(tcx: &ty::ctxt, node_id: ast::NodeId, ty: ty::t) {
}
pub fn write_substs_to_tcx(tcx: &ty::ctxt,
node_id: ast::NodeId,
substs: Vec<ty::t> ) {
if substs.len() > 0u {
debug!("write_substs_to_tcx({}, {:?})", node_id,
substs.iter().map(|t| ppaux::ty_to_str(tcx, *t)).collect::<Vec<~str>>());
assert!(substs.iter().all(|t| !ty::type_needs_infer(*t)));
item_substs: ty::ItemSubsts) {
if !item_substs.is_noop() {
debug!("write_substs_to_tcx({}, {})",
node_id,
item_substs.repr(tcx));
tcx.node_type_substs.borrow_mut().insert(node_id, substs);
assert!(item_substs.substs.tps.iter().
all(|t| !ty::type_needs_infer(*t)));
tcx.item_substs.borrow_mut().insert(node_id, item_substs);
}
}
pub fn lookup_def_tcx(tcx:&ty::ctxt, sp: Span, id: ast::NodeId) -> ast::Def {

View File

@ -561,6 +561,12 @@ impl Repr for ty::substs {
}
}
impl Repr for ty::ItemSubsts {
fn repr(&self, tcx: &ctxt) -> ~str {
format!("ItemSubsts({})", self.substs.repr(tcx))
}
}
impl Repr for ty::RegionSubsts {
fn repr(&self, tcx: &ctxt) -> ~str {
match *self {

View File

@ -0,0 +1,41 @@
// Copyright 2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that when we test the supertrait we ensure consistent use of
// lifetime parameters. In this case, implementing T2<'a,'b> requires
// an impl of T1<'a>, but we have an impl of T1<'b>.
trait T1<'x> {
fn x(&self) -> &'x int;
}
trait T2<'x, 'y> : T1<'x> {
fn y(&self) -> &'y int;
}
struct S<'a, 'b> {
a: &'a int,
b: &'b int
}
impl<'a,'b> T1<'b> for S<'a, 'b> {
fn x(&self) -> &'b int {
self.b
}
}
impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { //~ ERROR cannot infer an appropriate lifetime
fn y(&self) -> &'b int {
self.b
}
}
pub fn main() {
}