Issue #5656: Make &self not mean "&'self self"

Fixes #5656.
Fixes #5541.
This commit is contained in:
Niko Matsakis 2013-04-10 13:11:27 -07:00
parent 3322595e89
commit 49de82cdca
16 changed files with 337 additions and 296 deletions

View File

@ -16,7 +16,7 @@ use middle::liveness;
use middle::pat_util;
use middle::ty;
use middle::typeck;
use util::ppaux::{Repr, ty_to_str, tys_to_str};
use util::ppaux::{Repr, ty_to_str};
use syntax::ast::*;
use syntax::attr::attrs_contains_name;

View File

@ -544,10 +544,6 @@ pub struct DetermineRpCtxt {
// 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,
@ -689,7 +685,7 @@ pub impl DetermineRpCtxt {
false
}
Some(ref l) if l.ident == special_idents::self_ => {
self.self_implies_rp
true
}
Some(_) => {
false
@ -700,23 +696,18 @@ 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;
self.self_implies_rp = self_implies_rp;
debug!("with_item_id(%d, %b, %b)",
debug!("with_item_id(%d, %b)",
item_id,
anon_implies_rp,
self_implies_rp);
anon_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()) {
@ -730,7 +721,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, true) {
do cx.with(item.id, true) {
visit::visit_item(item, cx, visitor);
}
}
@ -742,12 +733,7 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind,
_: ast::node_id,
&&cx: @mut DetermineRpCtxt,
visitor: visit::vt<@mut DetermineRpCtxt>) {
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(cx.item_id, false) {
do cx.with_ambient_variance(rv_contravariant) {
for decl.inputs.each |a| {
(visitor.visit_ty)(a.ty, cx, visitor);
@ -763,7 +749,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, !ty_m.self_ty.node.is_borrowed()) {
do cx.with(cx.item_id, false) {
visit::visit_ty_method(ty_m, cx, visitor);
}
}
@ -868,7 +854,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, true) {
do cx.with(cx.item_id, false) {
// parameters are contravariant
do cx.with_ambient_variance(rv_contravariant) {
for decl.inputs.each |a| {
@ -929,7 +915,6 @@ 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

@ -62,22 +62,7 @@ impl EffectfulSubst for ty::t {
_ => {
ty::fold_regions_and_ty(
tcx, *self,
|r| match r {
ty::re_bound(ty::br_self) => {
match substs.self_r {
None => {
tcx.sess.bug(
fmt!("ty::subst: \
Reference to self region when \
given substs with no self region, \
ty = %s",
self.repr(tcx)));
}
Some(self_r) => self_r
}
}
_ => r
},
|r| r.subst(tcx, substs),
|t| t.effectfulSubst(tcx, substs),
|t| t.effectfulSubst(tcx, substs))
}
@ -118,7 +103,7 @@ 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,
self_r: self.self_r.subst(tcx, substs),
self_ty: self.self_ty.map(|typ| typ.subst(tcx, substs)),
tps: self.tps.map(|typ| typ.subst(tcx, substs))
}
@ -166,6 +151,34 @@ impl Subst for ty::Generics {
}
}
impl Subst for ty::Region {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Region {
// Note: This routine only handles the self region, because it
// is only concerned with substitutions of regions that appear
// in types. Region substitution of the bound regions that
// appear in a function signature is done using the
// specialized routine
// `middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig()`.
// As we transition to the new region syntax this distinction
// 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)));
}
Some(self_r) => self_r
}
}
_ => *self
}
}
}
impl Subst for ty::ty_param_bounds_and_ty {
fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::ty_param_bounds_and_ty {
ty::ty_param_bounds_and_ty {

View File

@ -24,8 +24,7 @@ use middle::subst::Subst;
use middle::typeck;
use middle;
use util::ppaux::{note_and_explain_region, bound_region_to_str};
use util::ppaux::{region_to_str, vstore_to_str};
use util::ppaux::{trait_store_to_str, ty_to_str, tys_to_str};
use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str};
use util::ppaux::Repr;
use util::common::{indenter};

View File

@ -178,15 +178,6 @@ pub struct Candidate {
origin: method_origin,
}
/**
* How the self type should be transformed according to the form of explicit
* self provided by the method.
*/
pub enum TransformTypeFlag {
TransformTypeNormally,
TransformTypeForObject,
}
pub impl<'self> LookupContext<'self> {
fn do_lookup(&self, self_ty: ty::t) -> Option<method_map_entry> {
let mut self_ty = structurally_resolved_type(self.fcx,
@ -285,13 +276,13 @@ pub impl<'self> LookupContext<'self> {
fn push_inherent_candidates(&self, self_ty: ty::t) {
/*!
*
* Collect all inherent candidates into
* `self.inherent_candidates`. See comment at the start of
* the file. To find the inherent candidates, we repeatedly
* deref the self-ty to find the "base-type". So, for
* example, if the receiver is @@C where `C` is a struct type,
* we'll want to find the inherent impls for `C`. */
* we'll want to find the inherent impls for `C`.
*/
let mut enum_dids = ~[];
let mut self_ty = self_ty;
@ -407,16 +398,9 @@ pub impl<'self> LookupContext<'self> {
};
let method = trait_methods[pos];
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_ty,
rcvr_ty,
copy bound_trait_ref.substs,
TransformTypeNormally);
let cand = Candidate {
rcvr_ty: rcvr_ty,
rcvr_substs: rcvr_substs,
rcvr_substs: copy bound_trait_ref.substs,
method_ty: method,
origin: method_param(
method_param {
@ -476,14 +460,8 @@ pub impl<'self> LookupContext<'self> {
../*bad*/copy *substs
};
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(method.self_ty,
self_ty,
rcvr_substs,
TransformTypeForObject);
self.inherent_candidates.push(Candidate {
rcvr_ty: rcvr_ty,
rcvr_ty: self_ty,
rcvr_substs: rcvr_substs,
method_ty: method,
origin: method_trait(did, index, store)
@ -538,19 +516,13 @@ pub impl<'self> LookupContext<'self> {
// We've found a method -- return it
let rcvr_substs = substs {self_ty: Some(self_ty),
..copy *substs };
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(
info.method_ty.self_ty,
self_ty,
rcvr_substs,
TransformTypeNormally);
let origin = if did == info.trait_def_id {
method_self(info.trait_def_id, info.index)
} else {
method_super(info.trait_def_id, info.index)
};
self.inherent_candidates.push(Candidate {
rcvr_ty: rcvr_ty,
rcvr_ty: self_ty,
rcvr_substs: rcvr_substs,
method_ty: info.method_ty,
origin: origin
@ -598,13 +570,6 @@ pub impl<'self> LookupContext<'self> {
ty: impl_ty
} = impl_self_ty(&vcx, location_info, impl_info.did);
let (impl_ty, impl_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_ty,
impl_ty,
impl_substs,
TransformTypeNormally);
candidates.push(Candidate {
rcvr_ty: impl_ty,
rcvr_substs: impl_substs,
@ -639,69 +604,16 @@ pub impl<'self> LookupContext<'self> {
self_ty: None,
tps: ~[]
};
let (impl_ty, impl_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_ty,
self_ty,
dummy_substs,
TransformTypeNormally);
candidates.push(Candidate {
rcvr_ty: impl_ty,
rcvr_substs: impl_substs,
rcvr_ty: self_ty,
rcvr_substs: dummy_substs,
method_ty: method,
origin: method_static(provided_method_info.method_info.did)
});
}
}
fn create_rcvr_ty_and_substs_for_method(&self,
self_decl: ast::self_ty_,
self_ty: ty::t,
+self_substs: ty::substs,
transform_type: TransformTypeFlag)
-> (ty::t, ty::substs) {
// If the self type includes a region (like &self), we need to
// ensure that the receiver substitutions have a self region.
// If the receiver type does not itself contain borrowed
// pointers, there may not be one yet.
//
// FIXME(#3446)--this awkward situation comes about because
// the regions in the receiver are substituted before (and
// differently from) those in the argument types. This
// shouldn't really have to be.
let rcvr_substs = {
match self_decl {
sty_static | sty_value |
sty_box(_) | sty_uniq(_) => {
self_substs
}
sty_region(*) if self_substs.self_r.is_some() => {
// FIXME(#4846) ignoring expl lifetime here
self_substs
}
sty_region(*) => {
// FIXME(#4846) ignoring expl lifetime here
substs {
self_r:
Some(self.infcx().next_region_var(
self.expr.span,
self.expr.id)),
..self_substs
}
}
}
};
let rcvr_ty = transform_self_type_for_method(self.tcx(),
rcvr_substs.self_r,
self_ty,
self_decl,
transform_type);
(rcvr_ty, rcvr_substs)
}
// ______________________________________________________________________
// Candidate selection (see comment at start of file)
@ -1036,20 +948,34 @@ pub impl<'self> LookupContext<'self> {
self.enforce_trait_instance_limitations(fty, candidate);
self.enforce_drop_trait_limitations(candidate);
// before we only checked whether self_ty could be a subtype
// of rcvr_ty; now we actually make it so (this may cause
// variables to unify etc). Since we checked beforehand, and
// nothing has changed in the meantime, this unification
// should never fail.
match self.fcx.mk_subty(false, self.self_expr.span,
self_ty, candidate.rcvr_ty) {
result::Ok(_) => (),
result::Err(_) => {
self.bug(fmt!("%s was assignable to %s but now is not?",
self.ty_to_str(self_ty),
self.ty_to_str(candidate.rcvr_ty)));
// static methods should never have gotten this far:
assert!(candidate.method_ty.self_ty != sty_static);
let transformed_self_ty = match candidate.origin {
method_trait(*) => {
match candidate.method_ty.self_ty {
sty_region(*) => {
// FIXME(#5762) again, preserving existing
// behavior here which (for &self) desires
// &@Trait where @Trait is the type of the
// receiver. Here we fetch the method's
// transformed_self_ty which will be something
// like &'a Self. We then perform a
// substitution which will replace Self with
// @Trait.
let t = candidate.method_ty.transformed_self_ty.get();
ty::subst(tcx, &candidate.rcvr_substs, t)
}
_ => {
candidate.rcvr_ty
}
}
}
}
_ => {
let t = candidate.method_ty.transformed_self_ty.get();
ty::subst(tcx, &candidate.rcvr_substs, t)
}
};
// Determine the values for the type parameters of the method.
// If they were not explicitly supplied, just construct fresh
@ -1100,16 +1026,32 @@ pub impl<'self> LookupContext<'self> {
fmt!("Invoking method with non-bare-fn ty: %?", s));
}
};
let (_, _, fn_sig) =
let (_, opt_transformed_self_ty, fn_sig) =
replace_bound_regions_in_fn_sig(
tcx, @Nil, None, &bare_fn_ty.sig,
tcx, @Nil, Some(transformed_self_ty), &bare_fn_ty.sig,
|_br| self.fcx.infcx().next_region_var(
self.expr.span, self.expr.id));
let transformed_self_ty = opt_transformed_self_ty.get();
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {sig: fn_sig, ..bare_fn_ty});
debug!("after replacing bound regions, fty=%s", self.ty_to_str(fty));
let self_mode = get_mode_from_self_type(candidate.method_ty.self_ty);
// before we only checked whether self_ty could be a subtype
// of rcvr_ty; now we actually make it so (this may cause
// variables to unify etc). Since we checked beforehand, and
// nothing has changed in the meantime, this unification
// should never fail.
match self.fcx.mk_subty(false, self.self_expr.span,
self_ty, transformed_self_ty) {
result::Ok(_) => (),
result::Err(_) => {
self.bug(fmt!("%s was a subtype of %s but now is not?",
self.ty_to_str(self_ty),
self.ty_to_str(transformed_self_ty)));
}
}
self.fcx.write_ty(self.callee_id, fty);
self.fcx.write_substs(self.callee_id, all_substs);
method_map_entry {
@ -1180,7 +1122,87 @@ pub impl<'self> LookupContext<'self> {
debug!("is_relevant(self_ty=%s, candidate=%s)",
self.ty_to_str(self_ty), self.cand_to_str(candidate));
self.fcx.can_mk_subty(self_ty, candidate.rcvr_ty).is_ok()
// Check for calls to object methods. We resolve these differently.
//
// FIXME(#5762)---we don't check that an @self method is only called
// on an @Trait object here and so forth
match candidate.origin {
method_trait(*) => {
match candidate.method_ty.self_ty {
sty_static | sty_value => {
return false;
}
sty_region(*) => {
// just echoing current behavior here, which treats
// an &self method on an @Trait object as requiring
// an &@Trait receiver (wacky)
}
sty_box(*) | sty_uniq(*) => {
return self.fcx.can_mk_subty(self_ty,
candidate.rcvr_ty).is_ok();
}
};
}
_ => {}
}
return match candidate.method_ty.self_ty {
sty_static => {
false
}
sty_value => {
self.fcx.can_mk_subty(self_ty, candidate.rcvr_ty).is_ok()
}
sty_region(_, m) => {
match ty::get(self_ty).sty {
ty::ty_rptr(_, mt) => {
mutability_matches(mt.mutbl, m) &&
self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok()
}
_ => false
}
}
sty_box(m) => {
match ty::get(self_ty).sty {
ty::ty_box(mt) => {
mutability_matches(mt.mutbl, m) &&
self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok()
}
_ => false
}
}
sty_uniq(m) => {
match ty::get(self_ty).sty {
ty::ty_uniq(mt) => {
mutability_matches(mt.mutbl, m) &&
self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok()
}
_ => false
}
}
};
fn mutability_matches(self_mutbl: ast::mutability,
candidate_mutbl: ast::mutability) -> bool {
//! True if `self_mutbl <: candidate_mutbl`
match (self_mutbl, candidate_mutbl) {
(_, m_const) => true,
(m_mutbl, m_mutbl) => true,
(m_imm, m_imm) => true,
(m_mutbl, m_imm) => false,
(m_imm, m_mutbl) => false,
(m_const, m_imm) => false,
(m_const, m_mutbl) => false,
}
}
}
fn fn_ty_from_origin(&self, origin: &method_origin) -> ty::t {
@ -1281,45 +1303,6 @@ pub impl<'self> LookupContext<'self> {
}
}
pub fn transform_self_type_for_method(tcx: ty::ctxt,
self_region: Option<ty::Region>,
impl_ty: ty::t,
self_type: ast::self_ty_,
flag: TransformTypeFlag)
-> ty::t {
match self_type {
sty_static => {
tcx.sess.bug(~"calling transform_self_type_for_method on \
static method");
}
sty_value => {
impl_ty
}
sty_region(_, mutability) => {
// FIXME(#4846) ignoring expl lifetime here
mk_rptr(tcx,
self_region.expect(~"self region missing for &self param"),
ty::mt { ty: impl_ty, mutbl: mutability })
}
sty_box(mutability) => {
match flag {
TransformTypeNormally => {
mk_box(tcx, ty::mt { ty: impl_ty, mutbl: mutability })
}
TransformTypeForObject => impl_ty
}
}
sty_uniq(mutability) => {
match flag {
TransformTypeNormally => {
mk_uniq(tcx, ty::mt { ty: impl_ty, mutbl: mutability })
}
TransformTypeForObject => impl_ty
}
}
}
}
pub fn get_mode_from_self_type(self_type: ast::self_ty_) -> ast::rmode {
match self_type { sty_value => by_copy, _ => by_ref }
}

View File

@ -93,7 +93,6 @@ use middle::typeck::check::method::{AutoderefReceiver};
use middle::typeck::check::method::{AutoderefReceiverFlag};
use middle::typeck::check::method::{CheckTraitsAndInherentMethods};
use middle::typeck::check::method::{CheckTraitsOnly, DontAutoderefReceiver};
use middle::typeck::check::method::{TransformTypeNormally};
use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
use middle::typeck::check::regionmanip::relate_free_regions;
use middle::typeck::check::vtable::{LocationInfo, VtableContext};
@ -101,9 +100,8 @@ use middle::typeck::CrateCtxt;
use middle::typeck::infer::{resolve_type, force_tvar};
use middle::typeck::infer;
use middle::typeck::rscope::bound_self_region;
use middle::typeck::rscope::{RegionError, RegionParameterization};
use middle::typeck::rscope::{RegionError};
use middle::typeck::rscope::region_scope;
use middle::typeck::rscope;
use middle::typeck::{isr_alist, lookup_def_ccx};
use middle::typeck::no_params;
use middle::typeck::{require_same_types, method_map, vtable_map};
@ -280,7 +278,7 @@ pub fn check_bare_fn(ccx: @mut CrateCtxt,
}
pub fn check_fn(ccx: @mut CrateCtxt,
+self_info: Option<SelfInfo>,
opt_self_info: Option<SelfInfo>,
purity: ast::purity,
fn_sig: &ty::FnSig,
decl: &ast::fn_decl,
@ -307,23 +305,28 @@ pub fn check_fn(ccx: @mut CrateCtxt,
// First, we have to replace any bound regions in the fn and self
// types with free ones. The free region references will be bound
// the node_id of the body block.
let (isr, self_info, fn_sig) = {
replace_bound_regions_in_fn_sig(
tcx, inherited_isr, self_info, fn_sig,
|br| ty::re_free(ty::FreeRegion {scope_id: body.node.id,
bound_region: br}))
let (isr, opt_self_info, fn_sig) = {
let opt_self_ty = opt_self_info.map(|i| i.self_ty);
let (isr, opt_self_ty, fn_sig) =
replace_bound_regions_in_fn_sig(
tcx, inherited_isr, opt_self_ty, fn_sig,
|br| ty::re_free(ty::FreeRegion {scope_id: body.node.id,
bound_region: br}));
let opt_self_info =
opt_self_info.map(
|si| SelfInfo {self_ty: opt_self_ty.get(), ..*si});
(isr, opt_self_info, fn_sig)
};
relate_free_regions(tcx, self_info.map(|s| s.self_ty), &fn_sig);
relate_free_regions(tcx, opt_self_info.map(|s| s.self_ty), &fn_sig);
let arg_tys = fn_sig.inputs.map(|a| a.ty);
let ret_ty = fn_sig.output;
debug!("check_fn(arg_tys=%?, ret_ty=%?, self_info.self_ty=%?)",
arg_tys.map(|a| ppaux::ty_to_str(tcx, *a)),
debug!("check_fn(arg_tys=%?, ret_ty=%?, opt_self_ty=%?)",
arg_tys.map(|&a| ppaux::ty_to_str(tcx, a)),
ppaux::ty_to_str(tcx, ret_ty),
self_info.map(|s| ppaux::ty_to_str(tcx, s.self_ty)));
opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_ty)));
// ______________________________________________________________________
// Create the function context. This is either derived from scratch or,
@ -348,7 +351,7 @@ pub fn check_fn(ccx: @mut CrateCtxt,
}
};
gather_locals(fcx, decl, body, arg_tys, self_info);
gather_locals(fcx, decl, body, arg_tys, opt_self_info);
check_block_with_expected(fcx, body, Some(ret_ty));
// We unify the tail expr's type with the
@ -366,7 +369,7 @@ pub fn check_fn(ccx: @mut CrateCtxt,
None => ()
}
for self_info.each |self_info| {
for opt_self_info.each |self_info| {
fcx.write_ty(self_info.self_id, self_info.self_ty);
}
for vec::each2(decl.inputs, arg_tys) |input, arg| {
@ -379,7 +382,7 @@ pub fn check_fn(ccx: @mut CrateCtxt,
decl: &ast::fn_decl,
body: &ast::blk,
arg_tys: &[ty::t],
self_info: Option<SelfInfo>) {
opt_self_info: Option<SelfInfo>) {
let tcx = fcx.ccx.tcx;
let assign: @fn(ast::node_id, Option<ty::t>) = |nid, ty_opt| {
@ -398,7 +401,7 @@ pub fn check_fn(ccx: @mut CrateCtxt,
};
// Add the self parameter
for self_info.each |self_info| {
for opt_self_info.each |self_info| {
assign(self_info.self_id, Some(self_info.self_ty));
debug!("self is assigned to %s",
fcx.infcx().ty_to_str(
@ -484,26 +487,22 @@ pub fn check_fn(ccx: @mut CrateCtxt,
}
pub fn check_method(ccx: @mut CrateCtxt,
method: @ast::method,
self_ty: ty::t)
method: @ast::method)
{
let self_info = if method.self_ty.node == ast::sty_static {None} else {
let ty = method::transform_self_type_for_method(
ccx.tcx,
Some(ty::re_bound(ty::br_self)),
self_ty,
method.self_ty.node,
TransformTypeNormally);
Some(SelfInfo {self_ty: ty, self_id: method.self_id,
span: method.self_ty.span})
};
let method_def_id = local_def(method.id);
let method_ty = ty::method(ccx.tcx, method_def_id);
let opt_self_info = method_ty.transformed_self_ty.map(|&ty| {
SelfInfo {self_ty: ty,
self_id: method.self_id,
span: method.self_ty.span}
});
check_bare_fn(
ccx,
&method.decl,
&method.body,
method.id,
self_info
opt_self_info
);
}
@ -575,15 +574,12 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
ast::item_fn(ref decl, _, _, _, ref body) => {
check_bare_fn(ccx, decl, body, it.id, None);
}
ast::item_impl(ref generics, _, ty, ref ms) => {
ast::item_impl(_, _, _, ref ms) => {
let rp = ccx.tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
debug!("item_impl %s with id %d rp %?",
*ccx.tcx.sess.str_of(it.ident), it.id, rp);
let rp = RegionParameterization::from_variance_and_generics(
rp, generics);
let self_ty = ccx.to_ty(&rscope::type_rscope(rp), ty);
for ms.each |m| {
check_method(ccx, *m, self_ty);
check_method(ccx, *m);
}
}
ast::item_trait(_, _, ref trait_methods) => {
@ -594,8 +590,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
// bodies to check.
}
provided(m) => {
let self_ty = ty::mk_self(ccx.tcx, local_def(it.id));
check_method(ccx, m, self_ty);
check_method(ccx, m);
}
}
}

View File

@ -13,7 +13,7 @@
use core::prelude::*;
use middle::ty;
use middle::typeck::check::SelfInfo;
use middle::typeck::isr_alist;
use util::common::indenter;
use util::ppaux::region_to_str;
@ -26,29 +26,24 @@ use std::list::Cons;
pub fn replace_bound_regions_in_fn_sig(
tcx: ty::ctxt,
isr: isr_alist,
self_info: Option<SelfInfo>,
opt_self_ty: Option<ty::t>,
fn_sig: &ty::FnSig,
mapf: &fn(ty::bound_region) -> ty::Region)
-> (isr_alist, Option<SelfInfo>, ty::FnSig)
-> (isr_alist, Option<ty::t>, ty::FnSig)
{
// Take self_info apart; the self_ty part is the only one we want
// to update here.
let self_ty = self_info.map(|s| s.self_ty);
let rebuild_self_info = |t| self_info.map(|s| SelfInfo{self_ty: t, ..*s});
let mut all_tys = ty::tys_in_fn_sig(fn_sig);
for self_info.each |self_info| {
all_tys.push(self_info.self_ty);
for opt_self_ty.each |&self_ty| {
all_tys.push(self_ty);
}
for self_ty.each |t| { all_tys.push(*t) }
for opt_self_ty.each |&t| { all_tys.push(t) }
debug!("replace_bound_regions_in_fn_sig(self_info.self_ty=%?, fn_sig=%s, \
debug!("replace_bound_regions_in_fn_sig(self_ty=%?, fn_sig=%s, \
all_tys=%?)",
self_ty.map(|t| ppaux::ty_to_str(tcx, *t)),
opt_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)),
ppaux::fn_sig_to_str(tcx, fn_sig),
all_tys.map(|t| ppaux::ty_to_str(tcx, *t)));
all_tys.map(|&t| ppaux::ty_to_str(tcx, t)));
let _i = indenter();
let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| {
@ -58,20 +53,15 @@ pub fn replace_bound_regions_in_fn_sig(
let new_fn_sig = ty::fold_sig(fn_sig, |t| {
replace_bound_regions(tcx, isr, t)
});
let t_self = self_ty.map(|t| replace_bound_regions(tcx, isr, *t));
let new_self_ty = opt_self_ty.map(|&t| replace_bound_regions(tcx, isr, t));
debug!("result of replace_bound_regions_in_fn_sig: self_info.self_ty=%?, \
fn_sig=%s",
t_self.map(|t| ppaux::ty_to_str(tcx, *t)),
debug!("result of replace_bound_regions_in_fn_sig: \
new_self_ty=%?, \
fn_sig=%s",
new_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)),
ppaux::fn_sig_to_str(tcx, &new_fn_sig));
// Glue updated self_ty back together with its original def_id.
let new_self_info: Option<SelfInfo> = match t_self {
None => None,
Some(t) => rebuild_self_info(t)
};
return (isr, new_self_info, new_fn_sig);
return (isr, new_self_ty, new_fn_sig);
// Takes `isr`, a (possibly empty) mapping from in-scope region
// names ("isr"s) to their corresponding regions; `tys`, a list of
@ -288,4 +278,4 @@ pub fn relate_free_regions(
}
debug!("<< relate_free_regions");
}
}

View File

@ -11,7 +11,7 @@
use core::prelude::*;
use middle::resolve::Impl;
use middle::ty::{param_ty, substs};
use middle::ty::{param_ty};
use middle::ty;
use middle::typeck::check::{FnCtxt, impl_self_ty};
use middle::typeck::check::{structurally_resolved_type};
@ -489,6 +489,8 @@ pub fn early_resolve_expr(ex: @ast::expr,
match ex.node {
ast::expr_path(*) => {
for fcx.opt_node_ty_substs(ex.id) |substs| {
debug!("vtable resolution on parameter bounds for expr %s",
ex.repr(fcx.tcx()));
let def = *cx.tcx.def_map.get(&ex.id);
let did = ast_util::def_id_of_def(def);
let item_ty = ty::lookup_item_type(cx.tcx, did);
@ -518,6 +520,8 @@ pub fn early_resolve_expr(ex: @ast::expr,
ast::expr_index(*) | ast::expr_method_call(*) => {
match ty::method_call_type_param_defs(cx.tcx, fcx.inh.method_map, ex.id) {
Some(type_param_defs) => {
debug!("vtable resolution on parameter bounds for method call %s",
ex.repr(fcx.tcx()));
if has_trait_bounds(*type_param_defs) {
let callee_id = match ex.node {
ast::expr_field(_, _, _) => ex.id,
@ -537,6 +541,7 @@ pub fn early_resolve_expr(ex: @ast::expr,
}
}
ast::expr_cast(src, _) => {
debug!("vtable resolution on expr %s", ex.repr(fcx.tcx()));
let target_ty = fcx.expr_ty(ex);
match ty::get(target_ty).sty {
ty::ty_trait(target_def_id, ref target_substs, store) => {

View File

@ -24,7 +24,7 @@ use metadata::cstore::{CStore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo};
use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, bound_copy, get};
use middle::ty::{lookup_item_type, param_bounds, subst};
use middle::ty::{lookup_item_type, subst};
use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err};
use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil};
use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr};

View File

@ -55,7 +55,7 @@ use syntax::ast_util::{local_def, split_trait_methods};
use syntax::ast_util;
use syntax::codemap::span;
use syntax::codemap;
use syntax::print::pprust::path_to_str;
use syntax::print::pprust::{path_to_str, self_ty_to_str};
use syntax::visit;
use syntax::opt_vec::OptVec;
use syntax::opt_vec;
@ -453,31 +453,35 @@ pub fn compare_impl_method(tcx: ty::ctxt,
let impl_m = &cm.mty;
// FIXME(#2687)---this check is too strict. For example, a trait
// method with self type `&self` or `&mut self` should be
// implementable by an `&const self` method (the impl assumes less
// than the trait provides).
if impl_m.self_ty != trait_m.self_ty {
if impl_m.self_ty == ast::sty_static {
// Needs to be a fatal error because otherwise,
// method::transform_self_type_for_method ICEs
tcx.sess.span_fatal(cm.span,
fmt!("method `%s` is declared as \
static in its impl, but not in \
its trait", *tcx.sess.str_of(impl_m.ident)));
}
else if trait_m.self_ty == ast::sty_static {
tcx.sess.span_fatal(cm.span,
fmt!("method `%s` is declared as \
static in its trait, but not in \
its impl", *tcx.sess.str_of(impl_m.ident)));
}
else {
// Try to give more informative error messages about self typing
// mismatches. Note that any mismatch will also be detected
// below, where we construct a canonical function type that
// includes the self parameter as a normal parameter. It's just
// that the error messages you get out of this code are a bit more
// inscrutable, particularly for cases where one method has no
// self.
match (&trait_m.self_ty, &impl_m.self_ty) {
(&ast::sty_static, &ast::sty_static) => {}
(&ast::sty_static, _) => {
tcx.sess.span_err(
cm.span,
fmt!("method `%s`'s self type does \
not match the trait method's \
self type", *tcx.sess.str_of(impl_m.ident)));
fmt!("method `%s` has a `%s` declaration in the impl, \
but not in the trait",
*tcx.sess.str_of(trait_m.ident),
self_ty_to_str(impl_m.self_ty, tcx.sess.intr())));
return;
}
(_, &ast::sty_static) => {
tcx.sess.span_err(
cm.span,
fmt!("method `%s` has a `%s` declaration in the trait, \
but not in the impl",
*tcx.sess.str_of(trait_m.ident),
self_ty_to_str(trait_m.self_ty, tcx.sess.intr())));
return;
}
_ => {
// Let the type checker catch other errors below
}
}
@ -539,6 +543,51 @@ pub fn compare_impl_method(tcx: ty::ctxt,
bound_region: ty::br_self});
let self_ty = replace_bound_self(tcx, self_ty, dummy_self_r);
// We are going to create a synthetic fn type that includes
// both the method's self argument and its normal arguments.
// So a method like `fn(&self, a: uint)` would be converted
// into a function `fn(self: &T, a: uint)`.
let mut trait_fn_args = ~[];
let mut impl_fn_args = ~[];
// For both the trait and the impl, create an argument to
// represent the self argument (unless this is a static method).
// This argument will have the *transformed* self type.
for trait_m.transformed_self_ty.each |&t| {
trait_fn_args.push(ty::arg {mode: ast::expl(ast::by_copy), ty: t});
}
for impl_m.transformed_self_ty.each |&t| {
impl_fn_args.push(ty::arg {mode: ast::expl(ast::by_copy), ty: t});
}
// Add in the normal arguments.
trait_fn_args.push_all(trait_m.fty.sig.inputs);
impl_fn_args.push_all(impl_m.fty.sig.inputs);
// Create a bare fn type for trait/impl that includes self argument
let trait_fty =
ty::mk_bare_fn(
tcx,
ty::BareFnTy {purity: trait_m.fty.purity,
abis: trait_m.fty.abis,
sig: ty::FnSig {
bound_lifetime_names:
copy trait_m.fty.sig.bound_lifetime_names,
inputs: trait_fn_args,
output: trait_m.fty.sig.output
}});
let impl_fty =
ty::mk_bare_fn(
tcx,
ty::BareFnTy {purity: impl_m.fty.purity,
abis: impl_m.fty.abis,
sig: ty::FnSig {
bound_lifetime_names:
copy impl_m.fty.sig.bound_lifetime_names,
inputs: impl_fn_args,
output: impl_m.fty.sig.output
}});
// Perform substitutions so that the trait/impl methods are expressed
// in terms of the same set of type/region parameters:
// - replace trait type parameters with those from `trait_substs`,
@ -547,7 +596,6 @@ pub fn compare_impl_method(tcx: ty::ctxt,
// that correspond to the parameters we will find on the impl
// - replace self region with a fresh, dummy region
let impl_fty = {
let impl_fty = ty::mk_bare_fn(tcx, copy impl_m.fty);
debug!("impl_fty (pre-subst): %s", ppaux::ty_to_str(tcx, impl_fty));
replace_bound_self(tcx, impl_fty, dummy_self_r)
};
@ -565,7 +613,6 @@ pub fn compare_impl_method(tcx: ty::ctxt,
self_ty: Some(self_ty),
tps: vec::append(trait_tps, dummy_tps)
};
let trait_fty = ty::mk_bare_fn(tcx, copy trait_m.fty);
debug!("trait_fty (pre-subst): %s substs=%s",
trait_fty.repr(tcx), substs.repr(tcx));
ty::subst(tcx, &substs, trait_fty)

View File

@ -180,12 +180,11 @@ impl region_scope for MethodRscope {
})
}
fn self_region(&self, _span: span) -> Result<ty::Region, RegionError> {
assert!(self.variance.is_some() || self.self_ty.is_borrowed());
assert!(self.variance.is_some());
match self.variance {
None => {} // must be borrowed self, so this is OK
Some(_) => {
if !self.self_ty.is_borrowed() &&
!self.region_param_names.has_self() {
if !self.region_param_names.has_self() {
return Err(RegionError {
msg: ~"the `self` lifetime must be declared",
replacement: ty::re_bound(ty::br_self)

View File

@ -750,6 +750,12 @@ impl Repr for ty::TraitStore {
}
}
impl Repr for ty::vstore {
fn repr(&self, tcx: ctxt) -> ~str {
vstore_to_str(tcx, *self)
}
}
// Local Variables:
// mode: rust
// fill-column: 78;

View File

@ -1002,15 +1002,6 @@ pub enum self_ty_ {
sty_uniq(mutability) // `~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

@ -454,6 +454,7 @@ impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{
// ugh: can't get this to compile with mut because of the
// lack of flow sensitivity.
#[cfg(stage0)]
fn get_map(&self) -> &'self HashMap<K,@V> {
match *self {
BaseMapChain (~ref map) => map,
@ -461,6 +462,18 @@ impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{
}
}
// ugh: can't get this to compile with mut because of the
// lack of flow sensitivity.
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> {
match *self {
BaseMapChain (~ref map) => map,
ConsMapChain (~ref map,_) => map
}
}
// traits just don't work anywhere...?
//pub impl Map<Name,SyntaxExtension> for MapChain {

View File

@ -61,6 +61,7 @@ impl<T> OptVec<T> {
}
}
#[cfg(stage0)]
fn get(&self, i: uint) -> &'self T {
match *self {
Empty => fail!(fmt!("Invalid index %u", i)),
@ -68,6 +69,16 @@ impl<T> OptVec<T> {
}
}
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn get<'a>(&'a self, i: uint) -> &'a T {
match *self {
Empty => fail!(fmt!("Invalid index %u", i)),
Vec(ref v) => &v[i]
}
}
fn is_empty(&self) -> bool {
self.len() == 0
}

View File

@ -1633,6 +1633,10 @@ pub fn print_pat(s: @ps, &&pat: @ast::pat, refutable: bool) {
(s.ann.post)(ann_node);
}
pub fn self_ty_to_str(self_ty: ast::self_ty_, intr: @ident_interner) -> ~str {
to_str(self_ty, |a, b| { print_self_ty(a, b); () }, intr)
}
// Returns whether it printed anything
pub fn print_self_ty(s: @ps, self_ty: ast::self_ty_) -> bool {
match self_ty {