Update region inference for traits so that a method with

explicit self doesn't incorrectly cause the entire trait to
be tagged as being region-parameterized.

Fixes #5224.
This commit is contained in:
Niko Matsakis 2013-02-26 14:37:31 -05:00
parent 65986ba0c0
commit cbfd88a486
13 changed files with 264 additions and 190 deletions

View file

@ -16,7 +16,6 @@ use middle::ty;
use middle::typeck;
use util::ppaux;
use core::option;
use syntax::ast::*;
use syntax::codemap;
use syntax::{visit, ast_util, ast_map};

View file

@ -19,7 +19,6 @@ use middle::typeck::method_map;
use middle::moves;
use util::ppaux::ty_to_str;
use core::option;
use core::uint;
use core::vec;
use std::sort;

View file

@ -18,7 +18,6 @@ use middle::ty;
use middle::typeck;
use util::ppaux::{ty_to_str, tys_to_str};
use core::option;
use core::str;
use core::vec;
use std::oldmap::HashMap;

View file

@ -416,9 +416,13 @@ pub struct DetermineRpCtxt {
item_id: ast::node_id,
// true when we are within an item but not within a method.
// see long discussion on region_is_relevant()
// see long discussion on region_is_relevant().
anon_implies_rp: bool,
// true when we are not within an &self method.
// see long discussion on region_is_relevant().
self_implies_rp: bool,
// encodes the context of the current type; invariant if
// mutable, covariant otherwise
ambient_variance: region_variance,
@ -458,14 +462,14 @@ pub fn add_variance(+ambient_variance: region_variance,
}
pub impl DetermineRpCtxt {
fn add_variance(@mut self, variance: region_variance) -> region_variance {
fn add_variance(&self, variance: region_variance) -> region_variance {
add_variance(self.ambient_variance, variance)
}
/// Records that item `id` is region-parameterized with the
/// variance `variance`. If `id` was already parameterized, then
/// the new variance is joined with the old variance.
fn add_rp(@mut self, id: ast::node_id, variance: region_variance) {
fn add_rp(&mut self, id: ast::node_id, variance: region_variance) {
assert id != 0;
let old_variance = self.region_paramd_items.find(&id);
let joined_variance = match old_variance {
@ -490,7 +494,7 @@ pub impl DetermineRpCtxt {
/// `from`. Put another way, it indicates that the current item
/// contains a value of type `from`, so if `from` is
/// region-parameterized, so is the current item.
fn add_dep(@mut self, from: ast::node_id) {
fn add_dep(&mut self, from: ast::node_id) {
debug!("add dependency from %d -> %d (%s -> %s) with variance %?",
from, self.item_id,
ast_map::node_id_to_str(self.ast_map, from,
@ -515,42 +519,46 @@ pub impl DetermineRpCtxt {
}
// Determines whether a reference to a region that appears in the
// AST implies that the enclosing type is region-parameterized.
//
// This point is subtle. Here are four examples to make it more
// AST implies that the enclosing type is region-parameterized (RP).
// This point is subtle. Here are some examples to make it more
// concrete.
//
// 1. impl foo for &int { ... }
// 2. impl foo for &self/int { ... }
// 3. impl foo for bar { fn m() -> &self/int { ... } }
// 4. impl foo for bar { fn m() -> &int { ... } }
// 3. impl foo for bar { fn m(@self) -> &self/int { ... } }
// 4. impl foo for bar { fn m(&self) -> &self/int { ... } }
// 5. impl foo for bar { fn m(&self) -> &int { ... } }
//
// In case 1, the anonymous region is being referenced,
// but it appears in a context where the anonymous region
// resolves to self, so the impl foo is region-parameterized.
// resolves to self, so the impl foo is RP.
//
// In case 2, the self parameter is written explicitly.
//
// In case 3, the method refers to self, so that implies that the
// impl must be region parameterized. (If the type bar is not
// region parameterized, that is an error, because the self region
// is effectively unconstrained, but that is detected elsewhere).
// In case 3, the method refers to the region `self`, so that
// implies that the impl must be region parameterized. (If the
// type bar is not region parameterized, that is an error, because
// the self region is effectively unconstrained, but that is
// detected elsewhere).
//
// In case 4, the anonymous region is referenced, but it
// In case 4, the method refers to the region `self`, but the
// `self` region is bound by the `&self` receiver, and so this
// does not require that `bar` be RP.
//
// In case 5, the anonymous region is referenced, but it
// bound by the method, so it does not refer to self. This impl
// need not be region parameterized.
//
// So the rules basically are: the `self` region always implies
// that the enclosing type is region parameterized. The anonymous
// region also does, unless it appears within a method, in which
// case it is bound. We handle this by setting a flag
// (anon_implies_rp) to true when we enter an item and setting
// that flag to false when we enter a method.
fn region_is_relevant(@mut self, r: @ast::region) -> bool {
// Normally, & or &self implies that the enclosing item is RP.
// However, within a function, & is always bound. Within a method
// with &self type, &self is also bound. We detect those last two
// cases via flags (anon_implies_rp and self_implies_rp) that are
// true when the anon or self region implies RP.
fn region_is_relevant(&self, r: @ast::region) -> bool {
match r.node {
ast::re_static => false,
ast::re_anon => self.anon_implies_rp,
ast::re_self => true,
ast::re_self => self.self_implies_rp,
ast::re_named(_) => false
}
}
@ -561,7 +569,7 @@ pub impl DetermineRpCtxt {
//
// If the region is explicitly specified, then we follows the
// normal rules.
fn opt_region_is_relevant(@mut self,
fn opt_region_is_relevant(&self,
opt_r: Option<@ast::region>)
-> bool {
debug!("opt_region_is_relevant: %? (anon_implies_rp=%b)",
@ -575,16 +583,23 @@ pub impl DetermineRpCtxt {
fn with(@mut self,
item_id: ast::node_id,
anon_implies_rp: bool,
self_implies_rp: bool,
f: &fn()) {
let old_item_id = self.item_id;
let old_anon_implies_rp = self.anon_implies_rp;
let old_self_implies_rp = self.self_implies_rp;
self.item_id = item_id;
self.anon_implies_rp = anon_implies_rp;
debug!("with_item_id(%d, %b)", item_id, anon_implies_rp);
self.self_implies_rp = self_implies_rp;
debug!("with_item_id(%d, %b, %b)",
item_id,
anon_implies_rp,
self_implies_rp);
let _i = ::util::common::indenter();
f();
self.item_id = old_item_id;
self.anon_implies_rp = old_anon_implies_rp;
self.self_implies_rp = old_self_implies_rp;
}
fn with_ambient_variance(@mut self, variance: region_variance, f: &fn()) {
@ -598,7 +613,7 @@ pub impl DetermineRpCtxt {
pub fn determine_rp_in_item(item: @ast::item,
&&cx: @mut DetermineRpCtxt,
visitor: visit::vt<@mut DetermineRpCtxt>) {
do cx.with(item.id, true) {
do cx.with(item.id, true, true) {
visit::visit_item(item, cx, visitor);
}
}
@ -610,7 +625,12 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind,
_: ast::node_id,
&&cx: @mut DetermineRpCtxt,
visitor: visit::vt<@mut DetermineRpCtxt>) {
do cx.with(cx.item_id, false) {
let self_implies_rp = match fk {
&visit::fk_method(_, _, m) => !m.self_ty.node.is_borrowed(),
_ => true
};
do cx.with(cx.item_id, false, self_implies_rp) {
do cx.with_ambient_variance(rv_contravariant) {
for decl.inputs.each |a| {
(visitor.visit_ty)(a.ty, cx, visitor);
@ -626,7 +646,7 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind,
pub fn determine_rp_in_ty_method(ty_m: &ast::ty_method,
&&cx: @mut DetermineRpCtxt,
visitor: visit::vt<@mut DetermineRpCtxt>) {
do cx.with(cx.item_id, false) {
do cx.with(cx.item_id, false, !ty_m.self_ty.node.is_borrowed()) {
visit::visit_ty_method(ty_m, cx, visitor);
}
}
@ -735,7 +755,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => {
// fn() binds the & region, so do not consider &T types that
// appear *inside* a fn() type to affect the enclosing item:
do cx.with(cx.item_id, false) {
do cx.with(cx.item_id, false, true) {
// parameters are contravariant
do cx.with_ambient_variance(rv_contravariant) {
for decl.inputs.each |a| {
@ -796,6 +816,7 @@ pub fn determine_rp_in_crate(sess: Session,
worklist: ~[],
item_id: 0,
anon_implies_rp: false,
self_implies_rp: true,
ambient_variance: rv_covariant
};

View file

@ -69,7 +69,6 @@ use core::hash;
use core::int;
use core::io;
use core::libc::{c_uint, c_ulonglong};
use core::option;
use core::uint;
use std::oldmap::HashMap;
use std::{oldmap, time, list};

View file

@ -69,12 +69,11 @@ use syntax::print::pprust::path_to_str;
use util::common::indenter;
pub trait AstConv {
fn tcx(@mut self) -> ty::ctxt;
fn ccx(@mut self) -> @mut CrateCtxt;
fn get_item_ty(@mut self, id: ast::def_id) -> ty::ty_param_bounds_and_ty;
fn tcx(&self) -> ty::ctxt;
fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty;
// what type should we use when a type is omitted?
fn ty_infer(@mut self, span: span) -> ty::t;
fn ty_infer(&self, span: span) -> ty::t;
}
pub fn get_region_reporting_err(tcx: ty::ctxt,
@ -92,8 +91,8 @@ pub fn get_region_reporting_err(tcx: ty::ctxt,
}
pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Copy + Durable>(
self: @mut AC,
rscope: RS,
self: &AC,
rscope: &RS,
span: span,
a_r: @ast::region)
-> ty::Region {
@ -108,8 +107,8 @@ pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Copy + Durable>(
}
pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
self: @mut AC,
rscope: RS,
self: &AC,
rscope: &RS,
did: ast::def_id,
path: @ast::path)
-> ty_param_substs_and_ty {
@ -164,8 +163,8 @@ pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
}
pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
self: @mut AC,
rscope: RS,
self: &AC,
rscope: &RS,
did: ast::def_id,
path: @ast::path,
path_id: ast::node_id)
@ -189,11 +188,11 @@ pub const NO_TPS: uint = 2;
// Parses the programmer's textual representation of a type into our
// internal notion of a type. `getter` is a function that returns the type
// corresponding to a definition ID:
pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
self: @mut AC, rscope: RS, &&ast_ty: @ast::Ty) -> ty::t {
pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + Durable>(
self: &AC, rscope: &RS, &&ast_ty: @ast::Ty) -> ty::t {
fn ast_mt_to_mt<AC:AstConv,RS:region_scope + Copy + Durable>(
self: @mut AC, rscope: RS, mt: ast::mt) -> ty::mt {
fn ast_mt_to_mt<AC:AstConv, RS:region_scope + Copy + Durable>(
self: &AC, rscope: &RS, mt: ast::mt) -> ty::mt {
ty::mt {ty: ast_ty_to_ty(self, rscope, mt.ty), mutbl: mt.mutbl}
}
@ -202,8 +201,8 @@ pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
// If a_seq_ty is a str or a vec, make it an estr/evec.
// Also handle function sigils and first-class trait types.
fn mk_pointer<AC:AstConv,RS:region_scope + Copy + Durable>(
self: @mut AC,
rscope: RS,
self: &AC,
rscope: &RS,
a_seq_ty: ast::mt,
vst: ty::vstore,
constr: fn(ty::mt) -> ty::t) -> ty::t
@ -316,7 +315,8 @@ pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
}
ast::ty_rptr(region, mt) => {
let r = ast_region_to_region(self, rscope, ast_ty.span, region);
mk_pointer(self, in_anon_rscope(rscope, r), mt, ty::vstore_slice(r),
let anon_rscope = in_anon_rscope(rscope, r);
mk_pointer(self, &anon_rscope, mt, ty::vstore_slice(r),
|tmt| ty::mk_rptr(tcx, r, tmt))
}
ast::ty_tup(fields) => {
@ -419,8 +419,8 @@ pub fn ast_ty_to_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
}
pub fn ty_of_arg<AC:AstConv,RS:region_scope + Copy + Durable>(
self: @mut AC,
rscope: RS,
self: &AC,
rscope: &RS,
a: ast::arg,
expected_ty: Option<ty::arg>)
-> ty::arg {
@ -467,8 +467,8 @@ pub fn ty_of_arg<AC:AstConv,RS:region_scope + Copy + Durable>(
}
pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
self: @mut AC,
rscope: RS,
self: &AC,
rscope: &RS,
purity: ast::purity,
abi: ast::Abi,
decl: &ast::fn_decl)
@ -479,10 +479,10 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
// that function type
let rb = in_binding_rscope(rscope);
let input_tys = decl.inputs.map(|a| ty_of_arg(self, rb, *a, None));
let input_tys = decl.inputs.map(|a| ty_of_arg(self, &rb, *a, None));
let output_ty = match decl.output.node {
ast::ty_infer => self.ty_infer(decl.output.span),
_ => ast_ty_to_ty(self, rb, decl.output)
_ => ast_ty_to_ty(self, &rb, decl.output)
};
ty::BareFnTy {
@ -493,8 +493,8 @@ pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Copy + Durable>(
}
pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
self: @mut AC,
rscope: RS,
self: &AC,
rscope: &RS,
sigil: ast::Sigil,
purity: ast::purity,
onceness: ast::Onceness,
@ -538,14 +538,14 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
// were supplied
if i < e.inputs.len() {Some(e.inputs[i])} else {None}
};
ty_of_arg(self, rb, *a, expected_arg_ty)
ty_of_arg(self, &rb, *a, expected_arg_ty)
};
let expected_ret_ty = expected_tys.map(|e| e.output);
let output_ty = match decl.output.node {
ast::ty_infer if expected_ret_ty.is_some() => expected_ret_ty.get(),
ast::ty_infer => self.ty_infer(decl.output.span),
_ => ast_ty_to_ty(self, rb, decl.output)
_ => ast_ty_to_ty(self, &rb, decl.output)
};
ty::ClosureTy {

View file

@ -581,7 +581,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
let rp = ccx.tcx.region_paramd_items.find(&it.id);
debug!("item_impl %s with id %d rp %?",
*ccx.tcx.sess.str_of(it.ident), it.id, rp);
let self_ty = ccx.to_ty(rscope::type_rscope(rp), ty);
let self_ty = ccx.to_ty(&rscope::type_rscope(rp), ty);
for ms.each |m| {
check_method(ccx, *m, self_ty, local_def(it.id));
}
@ -636,21 +636,20 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
}
impl AstConv for FnCtxt {
fn tcx(@mut self) -> ty::ctxt { self.ccx.tcx }
fn ccx(@mut self) -> @mut CrateCtxt { self.ccx }
fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
fn get_item_ty(@mut self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
ty::lookup_item_type(self.tcx(), id)
}
fn ty_infer(@mut self, _span: span) -> ty::t {
fn ty_infer(&self, _span: span) -> ty::t {
self.infcx().next_ty_var()
}
}
pub impl FnCtxt {
fn infcx(@mut self) -> @mut infer::InferCtxt { self.inh.infcx }
fn search_in_scope_regions(@mut self,
fn infcx(&self) -> @mut infer::InferCtxt { self.inh.infcx }
fn search_in_scope_regions(&self,
br: ty::bound_region)
-> Result<ty::Region, ~str> {
let in_scope_regions = self.in_scope_regions;
@ -669,25 +668,17 @@ pub impl FnCtxt {
}
}
impl region_scope for @mut FnCtxt {
pure fn anon_region(&self, span: span) -> Result<ty::Region, ~str> {
// XXX: Unsafe to work around purity
unsafe {
result::Ok(self.infcx().next_region_var_nb(span))
}
impl region_scope for FnCtxt {
fn anon_region(&self, span: span) -> Result<ty::Region, ~str> {
result::Ok(self.infcx().next_region_var_nb(span))
}
pure fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
// XXX: Unsafe to work around purity
unsafe {
self.search_in_scope_regions(ty::br_self)
}
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
self.search_in_scope_regions(ty::br_self)
}
pure fn named_region(&self, _span: span, id: ast::ident)
-> Result<ty::Region, ~str> {
// XXX: Unsafe to work around purity
unsafe {
self.search_in_scope_regions(ty::br_named(id))
}
fn named_region(&self,
_span: span,
id: ast::ident) -> Result<ty::Region, ~str> {
self.search_in_scope_regions(ty::br_named(id))
}
}
@ -710,7 +701,7 @@ pub impl FnCtxt {
pprust::expr_to_str(expr, self.tcx().sess.intr()))
}
fn block_region(@mut self) -> ty::Region {
fn block_region(&self) -> ty::Region {
ty::re_scope(self.region_lb)
}
@ -1076,7 +1067,7 @@ pub fn impl_self_ty(vcx: &VtableContext,
}, _)) => {
(ts.ty_params.len(),
region_param,
vcx.ccx.to_ty(rscope::type_rscope(region_param), st))
vcx.ccx.to_ty(&rscope::type_rscope(region_param), st))
}
Some(ast_map::node_item(@ast::item {
node: ast::item_struct(_, ref ts),

View file

@ -47,7 +47,6 @@ use util::common::{indenter, pluralize};
use util::ppaux;
use core::dvec;
use core::option;
use core::vec;
use syntax::ast::{RegionTyParamBound, TraitTyParamBound};
use syntax::ast;
@ -108,24 +107,24 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: @ast::crate) {
visit::visit_crate(
*crate, (),
visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_item: |a|convert(ccx, a),
visit_item: |a| convert(ccx, a),
visit_foreign_item: |a|convert_foreign(ccx, a),
.. *visit::default_simple_visitor()
}));
}
pub impl @mut CrateCtxt {
fn to_ty<RS:region_scope + Copy + Durable>(rs: RS, ast_ty: @ast::Ty)
-> ty::t {
impl CrateCtxt {
fn to_ty<RS:region_scope + Copy + Durable>(
&self, rs: &RS, ast_ty: @ast::Ty) -> ty::t
{
ast_ty_to_ty(self, rs, ast_ty)
}
}
impl AstConv for CrateCtxt {
fn tcx(@mut self) -> ty::ctxt { self.tcx }
fn ccx(@mut self) -> @mut CrateCtxt { self }
fn tcx(&self) -> ty::ctxt { self.tcx }
fn get_item_ty(@mut self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty {
if id.crate != ast::local_crate {
csearch::get_type(self.tcx, id)
} else {
@ -144,13 +143,13 @@ impl AstConv for CrateCtxt {
}
}
fn ty_infer(@mut self, span: span) -> ty::t {
fn ty_infer(&self, span: span) -> ty::t {
self.tcx.sess.span_bug(span,
~"found `ty_infer` in unexpected place");
}
}
pub fn get_enum_variant_types(ccx: @mut CrateCtxt,
pub fn get_enum_variant_types(ccx: &CrateCtxt,
enum_ty: ty::t,
variants: &[ast::variant],
generics: &ast::Generics,
@ -165,7 +164,7 @@ pub fn get_enum_variant_types(ccx: @mut CrateCtxt,
match variant.node.kind {
ast::tuple_variant_kind(ref args) if args.len() > 0 => {
let rs = type_rscope(rp);
let input_tys = args.map(|va| ccx.to_ty(rs, va.ty));
let input_tys = args.map(|va| ccx.to_ty(&rs, va.ty));
result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty));
}
@ -217,17 +216,17 @@ pub fn get_enum_variant_types(ccx: @mut CrateCtxt,
}
}
pub fn ensure_trait_methods(ccx: @mut CrateCtxt,
pub fn ensure_trait_methods(ccx: &CrateCtxt,
id: ast::node_id,
trait_ty: ty::t) {
fn store_methods<T>(ccx: @mut CrateCtxt,
fn store_methods<T>(ccx: &CrateCtxt,
id: ast::node_id,
stuff: ~[T],
f: &fn(v: &T) -> ty::method) {
ty::store_trait_methods(ccx.tcx, id, @vec::map(stuff, f));
}
fn make_static_method_ty(ccx: @mut CrateCtxt,
fn make_static_method_ty(ccx: &CrateCtxt,
am: &ast::ty_method,
rp: Option<ty::region_variance>,
m: ty::method,
@ -308,7 +307,7 @@ pub fn ensure_trait_methods(ccx: @mut CrateCtxt,
}
}
pub fn ensure_supertraits(ccx: @mut CrateCtxt,
pub fn ensure_supertraits(ccx: &CrateCtxt,
id: ast::node_id,
sp: codemap::span,
rp: Option<ty::region_variance>,
@ -492,7 +491,7 @@ pub fn compare_impl_method(tcx: ty::ctxt,
}
}
pub fn check_methods_against_trait(ccx: @mut CrateCtxt,
pub fn check_methods_against_trait(ccx: &CrateCtxt,
generics: &ast::Generics,
rp: Option<ty::region_variance>,
selfty: ty::t,
@ -544,11 +543,11 @@ pub fn check_methods_against_trait(ccx: @mut CrateCtxt,
}
} // fn
pub fn convert_field(ccx: @mut CrateCtxt,
pub fn convert_field(ccx: &CrateCtxt,
rp: Option<ty::region_variance>,
bounds: @~[ty::param_bounds],
v: @ast::struct_field) {
let tt = ccx.to_ty(type_rscope(rp), v.node.ty);
let tt = ccx.to_ty(&type_rscope(rp), v.node.ty);
write_ty_to_tcx(ccx.tcx, v.node.id, tt);
/* add the field to the tcache */
ccx.tcx.tcache.insert(local_def(v.node.id),
@ -566,8 +565,8 @@ pub struct ConvertedMethod {
body_id: ast::node_id
}
pub fn convert_methods(ccx: @mut CrateCtxt,
ms: ~[@ast::method],
pub fn convert_methods(ccx: &CrateCtxt,
ms: &[@ast::method],
rp: Option<ty::region_variance>,
rcvr_bounds: @~[ty::param_bounds])
-> ~[ConvertedMethod] {
@ -593,7 +592,7 @@ pub fn convert_methods(ccx: @mut CrateCtxt,
}
}
pub fn ensure_no_ty_param_bounds(ccx: @mut CrateCtxt,
pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
span: span,
generics: &ast::Generics,
thing: &static/str) {
@ -607,7 +606,7 @@ pub fn ensure_no_ty_param_bounds(ccx: @mut CrateCtxt,
}
}
pub fn convert(ccx: @mut CrateCtxt, it: @ast::item) {
pub fn convert(ccx: &CrateCtxt, it: @ast::item) {
let tcx = ccx.tcx;
let rp = tcx.region_paramd_items.find(&it.id);
debug!("convert: item %s with id %d rp %?",
@ -627,7 +626,7 @@ pub fn convert(ccx: @mut CrateCtxt, it: @ast::item) {
}
ast::item_impl(ref generics, trait_ref, selfty, ref ms) => {
let i_bounds = ty_param_bounds(ccx, generics);
let selfty = ccx.to_ty(type_rscope(rp), selfty);
let selfty = ccx.to_ty(&type_rscope(rp), selfty);
write_ty_to_tcx(tcx, it.id, selfty);
tcx.tcache.insert(local_def(it.id),
ty_param_bounds_and_ty {
@ -636,7 +635,7 @@ pub fn convert(ccx: @mut CrateCtxt, it: @ast::item) {
ty: selfty});
// XXX: Bad copy of `ms` below.
let cms = convert_methods(ccx, /*bad*/copy *ms, rp, i_bounds);
let cms = convert_methods(ccx, *ms, rp, i_bounds);
for trait_ref.each |t| {
check_methods_against_trait(ccx, generics, rp, selfty,
*t, /*bad*/copy cms);
@ -680,7 +679,7 @@ pub fn convert(ccx: @mut CrateCtxt, it: @ast::item) {
}
}
pub fn convert_struct(ccx: @mut CrateCtxt,
pub fn convert_struct(ccx: &CrateCtxt,
rp: Option<ty::region_variance>,
struct_def: @ast::struct_def,
generics: &ast::Generics,
@ -693,7 +692,7 @@ pub fn convert_struct(ccx: @mut CrateCtxt,
let t_dtor = ty::mk_bare_fn(
tcx,
astconv::ty_of_bare_fn(
ccx, type_rscope(rp),
ccx, &type_rscope(rp),
ast::impure_fn, ast::RustAbi,
&ast_util::dtor_dec()));
write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
@ -738,7 +737,7 @@ pub fn convert_struct(ccx: @mut CrateCtxt,
}
}
pub fn convert_foreign(ccx: @mut CrateCtxt, i: @ast::foreign_item) {
pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) {
// As above, this call populates the type table with the converted
// type of the foreign item. We simply write it into the node type
// table.
@ -747,13 +746,18 @@ pub fn convert_foreign(ccx: @mut CrateCtxt, i: @ast::foreign_item) {
ccx.tcx.tcache.insert(local_def(i.id), tpt);
}
pub fn ty_of_method(ccx: @mut CrateCtxt,
pub fn ty_of_method(ccx: &CrateCtxt,
m: @ast::method,
rp: Option<ty::region_variance>) -> ty::method {
let rscope = MethodRscope {
self_ty: m.self_ty.node,
region_parameterization: rp
};
ty::method {
ident: m.ident,
tps: ty_param_bounds(ccx, &m.generics),
fty: astconv::ty_of_bare_fn(ccx, type_rscope(rp), m.purity,
fty: astconv::ty_of_bare_fn(ccx, &rscope, m.purity,
ast::RustAbi, &m.decl),
self_ty: m.self_ty.node,
vis: m.vis,
@ -761,14 +765,19 @@ pub fn ty_of_method(ccx: @mut CrateCtxt,
}
}
pub fn ty_of_ty_method(self: @mut CrateCtxt,
pub fn ty_of_ty_method(self: &CrateCtxt,
m: &ast::ty_method,
rp: Option<ty::region_variance>,
id: ast::def_id) -> ty::method {
let rscope = MethodRscope {
self_ty: m.self_ty.node,
region_parameterization: rp
};
ty::method {
ident: m.ident,
tps: ty_param_bounds(self, &m.generics),
fty: astconv::ty_of_bare_fn(self, type_rscope(rp), m.purity,
fty: astconv::ty_of_bare_fn(self, &rscope, m.purity,
ast::RustAbi, &m.decl),
// assume public, because this is only invoked on trait methods
self_ty: m.self_ty.node,
@ -782,7 +791,7 @@ pub fn ty_of_ty_method(self: @mut CrateCtxt,
it's bound to a valid trait type. Returns the def_id for the defining
trait. Fails if the type is a type other than an trait type.
*/
pub fn instantiate_trait_ref(ccx: @mut CrateCtxt, t: @ast::trait_ref,
pub fn instantiate_trait_ref(ccx: &CrateCtxt, t: @ast::trait_ref,
rp: Option<ty::region_variance>)
-> (ast::def_id, ty_param_substs_and_ty) {
@ -793,7 +802,7 @@ pub fn instantiate_trait_ref(ccx: @mut CrateCtxt, t: @ast::trait_ref,
match lookup_def_tcx(ccx.tcx, t.path.span, t.ref_id) {
ast::def_ty(t_id) => {
let tpt = astconv::ast_path_to_ty(ccx, rscope, t_id, t.path,
let tpt = astconv::ast_path_to_ty(ccx, &rscope, t_id, t.path,
t.ref_id);
match ty::get(tpt.ty).sty {
ty::ty_trait(*) => {
@ -806,7 +815,7 @@ pub fn instantiate_trait_ref(ccx: @mut CrateCtxt, t: @ast::trait_ref,
}
}
pub fn ty_of_item(ccx: @mut CrateCtxt, it: @ast::item)
pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item)
-> ty::ty_param_bounds_and_ty {
let def_id = local_def(it.id);
let tcx = ccx.tcx;
@ -817,14 +826,14 @@ pub fn ty_of_item(ccx: @mut CrateCtxt, it: @ast::item)
let rp = tcx.region_paramd_items.find(&it.id);
match it.node {
ast::item_const(t, _) => {
let typ = ccx.to_ty(empty_rscope, t);
let typ = ccx.to_ty(&empty_rscope, t);
let tpt = no_params(typ);
tcx.tcache.insert(local_def(it.id), tpt);
return tpt;
}
ast::item_fn(ref decl, purity, ref generics, _) => {
let bounds = ty_param_bounds(ccx, generics);
let tofd = astconv::ty_of_bare_fn(ccx, empty_rscope, purity,
let tofd = astconv::ty_of_bare_fn(ccx, &empty_rscope, purity,
ast::RustAbi, decl);
let tpt = ty_param_bounds_and_ty {
bounds: bounds,
@ -847,7 +856,7 @@ pub fn ty_of_item(ccx: @mut CrateCtxt, it: @ast::item)
let rp = tcx.region_paramd_items.find(&it.id);
let tpt = {
let ty = {
let t0 = ccx.to_ty(type_rscope(rp), t);
let t0 = ccx.to_ty(&type_rscope(rp), t);
// Do not associate a def id with a named, parameterized type
// like "foo<X>". This is because otherwise ty_to_str will
// print the name as merely "foo", as it has no way to
@ -906,23 +915,21 @@ pub fn ty_of_item(ccx: @mut CrateCtxt, it: @ast::item)
}
}
pub fn ty_of_foreign_item(ccx: @mut CrateCtxt, it: @ast::foreign_item)
pub fn ty_of_foreign_item(ccx: &CrateCtxt, it: @ast::foreign_item)
-> ty::ty_param_bounds_and_ty {
match /*bad*/copy it.node {
match it.node {
ast::foreign_item_fn(ref fn_decl, _, ref generics) => {
ty_of_foreign_fn_decl(
ccx,
fn_decl,
local_def(it.id),
generics
)
ty_of_foreign_fn_decl(ccx,
fn_decl,
local_def(it.id),
generics)
}
ast::foreign_item_const(t) => {
let rb = in_binding_rscope(empty_rscope);
let rb = in_binding_rscope(&empty_rscope);
ty::ty_param_bounds_and_ty {
bounds: @~[],
region_param: None,
ty: ast_ty_to_ty(ccx, rb, t)
ty: ast_ty_to_ty(ccx, &rb, t)
}
}
}
@ -932,14 +939,14 @@ pub fn ty_of_foreign_item(ccx: @mut CrateCtxt, it: @ast::foreign_item)
// of a newtyped Ty or a region) to ty's notion of ty param bounds, which can
// either be user-defined traits, or one of the four built-in traits (formerly
// known as kinds): Const, Copy, Durable, and Send.
pub fn compute_bounds(ccx: @mut CrateCtxt,
pub fn compute_bounds(ccx: &CrateCtxt,
ast_bounds: @OptVec<ast::TyParamBound>)
-> ty::param_bounds {
@ast_bounds.flat_map_to_vec(|b| {
match b {
&TraitTyParamBound(b) => {
let li = &ccx.tcx.lang_items;
let ity = ast_ty_to_ty(ccx, empty_rscope, b);
let ity = ast_ty_to_ty(ccx, &empty_rscope, b);
match ty::get(ity).sty {
ty::ty_trait(did, _, _) => {
if did == li.owned_trait() {
@ -968,7 +975,7 @@ pub fn compute_bounds(ccx: @mut CrateCtxt,
})
}
pub fn ty_param_bounds(ccx: @mut CrateCtxt,
pub fn ty_param_bounds(ccx: &CrateCtxt,
generics: &ast::Generics)
-> @~[ty::param_bounds] {
@do generics.ty_params.map_to_vec |param| {
@ -983,15 +990,15 @@ pub fn ty_param_bounds(ccx: @mut CrateCtxt,
}
}
pub fn ty_of_foreign_fn_decl(ccx: @mut CrateCtxt,
pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
decl: &ast::fn_decl,
def_id: ast::def_id,
generics: &ast::Generics)
-> ty::ty_param_bounds_and_ty {
let bounds = ty_param_bounds(ccx, generics);
let rb = in_binding_rscope(empty_rscope);
let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, rb, *a, None) );
let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
let rb = in_binding_rscope(&empty_rscope);
let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, &rb, *a, None) );
let output_ty = ast_ty_to_ty(ccx, &rb, decl.output);
let t_fn = ty::mk_bare_fn(
ccx.tcx,
@ -1009,7 +1016,7 @@ pub fn ty_of_foreign_fn_decl(ccx: @mut CrateCtxt,
return tpt;
}
pub fn mk_generics(ccx: @mut CrateCtxt, generics: &ast::Generics)
pub fn mk_generics(ccx: &CrateCtxt, generics: &ast::Generics)
-> (@~[ty::param_bounds], ~[ty::t])
{
let mut i = 0u;
@ -1022,7 +1029,7 @@ pub fn mk_generics(ccx: @mut CrateCtxt, generics: &ast::Generics)
}))
}
pub fn mk_substs(ccx: @mut CrateCtxt,
pub fn mk_substs(ccx: &CrateCtxt,
generics: &ast::Generics,
rp: Option<ty::region_variance>)
-> (@~[ty::param_bounds], ty::substs)

View file

@ -18,41 +18,59 @@ use syntax::ast;
use syntax::codemap::span;
pub trait region_scope {
pure fn anon_region(&self, span: span) -> Result<ty::Region, ~str>;
pure fn self_region(&self, span: span) -> Result<ty::Region, ~str>;
pure fn named_region(&self, span: span, id: ast::ident)
fn anon_region(&self, span: span) -> Result<ty::Region, ~str>;
fn self_region(&self, span: span) -> Result<ty::Region, ~str>;
fn named_region(&self, span: span, id: ast::ident)
-> Result<ty::Region, ~str>;
}
pub enum empty_rscope { empty_rscope }
impl region_scope for empty_rscope {
pure fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
result::Ok(ty::re_static)
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
Ok(ty::re_static)
}
pure fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
result::Err(~"only the static region is allowed here")
}
pure fn named_region(&self, _span: span, _id: ast::ident)
fn named_region(&self, _span: span, _id: ast::ident)
-> Result<ty::Region, ~str> {
result::Err(~"only the static region is allowed here")
}
}
pub enum type_rscope = Option<ty::region_variance>;
impl region_scope for type_rscope {
pure fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
match **self {
Some(_) => result::Ok(ty::re_bound(ty::br_self)),
None => result::Err(~"to use region types here, the containing \
type must be declared with a region bound")
pub struct MethodRscope {
self_ty: ast::self_ty_,
region_parameterization: Option<ty::region_variance>
}
impl region_scope for MethodRscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
result::Err(~"anonymous region types are not permitted here")
}
fn self_region(&self, _span: span) -> Result<ty::Region, ~str> {
assert self.region_parameterization.is_some() ||
self.self_ty.is_borrowed();
result::Ok(ty::re_bound(ty::br_self))
}
fn named_region(&self, span: span, id: ast::ident)
-> Result<ty::Region, ~str> {
do empty_rscope.named_region(span, id).chain_err |_e| {
result::Err(~"region is not in scope here")
}
}
pure fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
}
pub enum type_rscope = Option<ty::region_variance>;
impl region_scope for type_rscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
// if the anon or self region is used, region parameterization should
// have inferred that this type is RP
assert self.is_some();
result::Ok(ty::re_bound(ty::br_self))
}
fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
self.anon_region(span)
}
pure fn named_region(&self, span: span, id: ast::ident)
fn named_region(&self, span: span, id: ast::ident)
-> Result<ty::Region, ~str> {
do empty_rscope.named_region(span, id).chain_err |_e| {
result::Err(~"named regions other than `self` are not \
@ -70,50 +88,55 @@ pub fn bound_self_region(rp: Option<ty::region_variance>)
}
pub struct anon_rscope { anon: ty::Region, base: @region_scope }
pub fn in_anon_rscope<RS:region_scope + Copy + Durable>(self: RS,
r: ty::Region)
-> @anon_rscope {
@anon_rscope {anon: r, base: @self as @region_scope}
pub fn in_anon_rscope<RS:region_scope + Copy + Durable>(
self: &RS,
r: ty::Region) -> anon_rscope
{
let base = @(copy *self) as @region_scope;
anon_rscope {anon: r, base: base}
}
impl region_scope for @anon_rscope {
pure fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
impl region_scope for anon_rscope {
fn anon_region(&self,
_span: span) -> Result<ty::Region, ~str>
{
result::Ok(self.anon)
}
pure fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
fn self_region(&self,
span: span) -> Result<ty::Region, ~str>
{
self.base.self_region(span)
}
pure fn named_region(&self, span: span, id: ast::ident)
-> Result<ty::Region, ~str> {
fn named_region(&self,
span: span,
id: ast::ident) -> Result<ty::Region, ~str>
{
self.base.named_region(span, id)
}
}
pub struct binding_rscope {
base: region_scope,
anon_bindings: uint,
base: @region_scope,
anon_bindings: @mut uint,
}
pub fn in_binding_rscope<RS:region_scope + Copy + Durable>(self: RS)
-> @mut binding_rscope {
let base = @self as @region_scope;
@mut binding_rscope { base: base, anon_bindings: 0 }
pub fn in_binding_rscope<RS:region_scope + Copy + Durable>(self: &RS)
-> binding_rscope {
let base = @(copy *self) as @region_scope;
binding_rscope { base: base, anon_bindings: @mut 0 }
}
impl region_scope for @mut binding_rscope {
pure fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
// XXX: Unsafe to work around purity
unsafe {
let idx = self.anon_bindings;
self.anon_bindings += 1;
result::Ok(ty::re_bound(ty::br_anon(idx)))
}
impl region_scope for binding_rscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, ~str> {
let idx = *self.anon_bindings;
*self.anon_bindings += 1;
result::Ok(ty::re_bound(ty::br_anon(idx)))
}
pure fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
fn self_region(&self, span: span) -> Result<ty::Region, ~str> {
self.base.self_region(span)
}
pure fn named_region(&self, span: span, id: ast::ident)
-> Result<ty::Region, ~str> {
fn named_region(&self,
span: span,
id: ast::ident) -> Result<ty::Region, ~str>
{
do self.base.named_region(span, id).chain_err |_e| {
result::Ok(ty::re_bound(ty::br_named(id)))
}

View file

@ -1017,6 +1017,15 @@ pub enum self_ty_ {
sty_uniq(mutability) // by-unique-pointer self: `~self`
}
impl self_ty_ {
fn is_borrowed(&self) -> bool {
match *self {
sty_region(_) => true,
_ => false
}
}
}
pub type self_ty = spanned<self_ty_>;
#[auto_encode]

View file

@ -30,7 +30,6 @@ use print::pprust;
use core::char;
use core::dvec::DVec;
use core::io;
use core::option;
use core::str;
use core::u64;
use core::vec;

View file

@ -17,5 +17,5 @@ fn main() {
let x: @Map<~str, ~str> = @LinearMap::new::<~str, ~str>() as
Map::<~str, ~str>;
let y: @Map<uint, ~str> = @x;
//~^ ERROR mismatched types: expected `@core::container::Map/&<uint,~str>`
//~^ ERROR mismatched types: expected `@core::container::Map<uint,~str>`
}

View file

@ -0,0 +1,28 @@
// Test how region-parameterization inference
// interacts with explicit self types.
//
// Issue #5224.
trait Getter {
// This trait does not need to be
// region-parameterized, because 'self
// is bound in the self type:
fn get(&self) -> &'self int;
}
struct Foo {
field: int
}
impl Getter for Foo {
fn get(&self) -> &'self int { &self.field }
}
fn get_int<G: Getter>(g: &G) -> int {
*g.get()
}
fn main() {
let foo = Foo { field: 22 };
assert get_int(&foo) == 22;
}