From 49de82cdca2064a909d3104f4e5eccacb0425fd0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Apr 2013 13:11:27 -0700 Subject: [PATCH] Issue #5656: Make &self not mean "&'self self" Fixes #5656. Fixes #5541. --- src/librustc/middle/kind.rs | 2 +- src/librustc/middle/region.rs | 29 +- src/librustc/middle/subst.rs | 47 +-- src/librustc/middle/ty.rs | 3 +- src/librustc/middle/typeck/check/method.rs | 283 ++++++++---------- src/librustc/middle/typeck/check/mod.rs | 71 ++--- .../middle/typeck/check/regionmanip.rs | 42 +-- src/librustc/middle/typeck/check/vtable.rs | 7 +- src/librustc/middle/typeck/coherence.rs | 2 +- src/librustc/middle/typeck/collect.rs | 99 ++++-- src/librustc/middle/typeck/rscope.rs | 5 +- src/librustc/util/ppaux.rs | 6 + src/libsyntax/ast.rs | 9 - src/libsyntax/ext/base.rs | 13 + src/libsyntax/opt_vec.rs | 11 + src/libsyntax/print/pprust.rs | 4 + 16 files changed, 337 insertions(+), 296 deletions(-) diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 1f8401c0d53..e5fc9f2d603 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -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; diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 79130097078..ecb9fc2cd08 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -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 }; diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index a754f93f010..35257f9574c 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -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 { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3921764e6af..2b4a4235950 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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}; diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 6a274e7f9eb..6b09133e73a 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -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 { 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, - 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 } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 6bc1317d5f9..5c7a6d9f52a 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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, + opt_self_info: Option, 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) { + opt_self_info: Option) { let tcx = fcx.ccx.tcx; let assign: @fn(ast::node_id, Option) = |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); } } } diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 359f938d0d9..1abcefeefac 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -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, + opt_self_ty: Option, fn_sig: &ty::FnSig, mapf: &fn(ty::bound_region) -> ty::Region) - -> (isr_alist, Option, ty::FnSig) + -> (isr_alist, Option, 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 = 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"); -} \ No newline at end of file +} diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 6ea668605fd..8245dc88114 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -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) => { diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 174a20dd7f4..247b8eae2a8 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -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}; diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 0ef6e2512f3..59ea8ea039e 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -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) diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index eeca90dbecd..3ff36a409a7 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -180,12 +180,11 @@ impl region_scope for MethodRscope { }) } fn self_region(&self, _span: span) -> Result { - 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) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index f8877f76881..9b9e0e81b43 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ec77b54a853..3b2df24e7d9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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; #[auto_encode] diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 92f0c7c7679..886af694920 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -454,6 +454,7 @@ impl MapChain{ // ugh: can't get this to compile with mut because of the // lack of flow sensitivity. + #[cfg(stage0)] fn get_map(&self) -> &'self HashMap { match *self { BaseMapChain (~ref map) => map, @@ -461,6 +462,18 @@ impl MapChain{ } } + // 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 { + match *self { + BaseMapChain (~ref map) => map, + ConsMapChain (~ref map,_) => map + } + } + // traits just don't work anywhere...? //pub impl Map for MapChain { diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index fd54746f3dc..1604c40f917 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -61,6 +61,7 @@ impl OptVec { } } + #[cfg(stage0)] fn get(&self, i: uint) -> &'self T { match *self { Empty => fail!(fmt!("Invalid index %u", i)), @@ -68,6 +69,16 @@ impl OptVec { } } + #[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 } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 20fc99baf21..36cd7c06842 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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 {