diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 5ab8eeeb36055..0adc8e915c679 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -132,7 +132,8 @@ pub fn get_method(tcx: &ty::ctxt, def: ast::DefId) -> ty::Method { pub fn get_method_name_and_explicit_self(cstore: &cstore::CStore, def: ast::DefId) - -> (ast::Ident, ast::ExplicitSelf_) + -> (ast::Ident, + ty::ExplicitSelfCategory) { let cdata = cstore.get_crate_data(def.krate); decoder::get_method_name_and_explicit_self(cstore.intr.clone(), &*cdata, def.node) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index cc41223688ee0..094e83d2a4770 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -724,7 +724,7 @@ pub fn get_enum_variants(intr: Rc, cdata: Cmd, id: ast::NodeId, }).collect() } -fn get_explicit_self(item: ebml::Doc) -> ast::ExplicitSelf_ { +fn get_explicit_self(item: ebml::Doc) -> ty::ExplicitSelfCategory { fn get_mutability(ch: u8) -> ast::Mutability { match ch as char { 'i' => ast::MutImmutable, @@ -738,12 +738,15 @@ fn get_explicit_self(item: ebml::Doc) -> ast::ExplicitSelf_ { let explicit_self_kind = string.as_bytes()[0]; match explicit_self_kind as char { - 's' => ast::SelfStatic, - 'v' => ast::SelfValue(special_idents::self_), - '~' => ast::SelfUniq(special_idents::self_), + 's' => ty::StaticExplicitSelfCategory, + 'v' => ty::ByValueExplicitSelfCategory, + '~' => ty::ByBoxExplicitSelfCategory, // FIXME(#4846) expl. region - '&' => ast::SelfRegion(None, get_mutability(string.as_bytes()[1]), - special_idents::self_), + '&' => { + ty::ByReferenceExplicitSelfCategory( + ty::ReEmpty, + get_mutability(string.as_bytes()[1])) + } _ => fail!("unknown self type code: `{}`", explicit_self_kind as char) } } @@ -761,11 +764,11 @@ pub fn get_impl_methods(cdata: Cmd, impl_id: ast::NodeId) -> Vec { methods } -pub fn get_method_name_and_explicit_self( - intr: Rc, - cdata: Cmd, - id: ast::NodeId) -> (ast::Ident, ast::ExplicitSelf_) -{ +pub fn get_method_name_and_explicit_self(intr: Rc, + cdata: Cmd, + id: ast::NodeId) + -> (ast::Ident, + ty::ExplicitSelfCategory) { let method_doc = lookup_item(id, cdata.data()); let name = item_name(&*intr, method_doc); let explicit_self = get_explicit_self(method_doc); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 0a050850fe907..3c9f32dcd2f85 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -402,7 +402,7 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext, for base_impl_did in implementations.borrow().iter() { for &method_did in impl_methods.get(base_impl_did).iter() { let m = ty::method(ecx.tcx, method_did); - if m.explicit_self == ast::SelfStatic { + if m.explicit_self == ty::StaticExplicitSelfCategory { encode_reexported_static_method(ebml_w, exp, m.def_id, m.ident); } } @@ -421,7 +421,7 @@ fn encode_reexported_static_trait_methods(ecx: &EncodeContext, match ecx.tcx.trait_methods_cache.borrow().find(&exp.def_id) { Some(methods) => { for m in methods.iter() { - if m.explicit_self == ast::SelfStatic { + if m.explicit_self == ty::StaticExplicitSelfCategory { encode_reexported_static_method(ebml_w, exp, m.def_id, m.ident); } } @@ -623,15 +623,22 @@ fn encode_visibility(ebml_w: &mut Encoder, visibility: Visibility) { ebml_w.end_tag(); } -fn encode_explicit_self(ebml_w: &mut Encoder, explicit_self: ast::ExplicitSelf_) { +fn encode_explicit_self(ebml_w: &mut Encoder, + explicit_self: &ty::ExplicitSelfCategory) { ebml_w.start_tag(tag_item_trait_method_explicit_self); // Encode the base self type. - match explicit_self { - SelfStatic => { ebml_w.writer.write(&[ 's' as u8 ]); } - SelfValue(_) => { ebml_w.writer.write(&[ 'v' as u8 ]); } - SelfUniq(_) => { ebml_w.writer.write(&[ '~' as u8 ]); } - SelfRegion(_, m, _) => { + match *explicit_self { + ty::StaticExplicitSelfCategory => { + ebml_w.writer.write(&[ 's' as u8 ]); + } + ty::ByValueExplicitSelfCategory => { + ebml_w.writer.write(&[ 'v' as u8 ]); + } + ty::ByBoxExplicitSelfCategory => { + ebml_w.writer.write(&[ '~' as u8 ]); + } + ty::ByReferenceExplicitSelfCategory(_, m) => { // FIXME(#4846) encode custom lifetime ebml_w.writer.write(&['&' as u8]); encode_mutability(ebml_w, m); @@ -748,10 +755,10 @@ fn encode_method_ty_fields(ecx: &EncodeContext, tag_item_method_tps); encode_method_fty(ecx, ebml_w, &method_ty.fty); encode_visibility(ebml_w, method_ty.vis); - encode_explicit_self(ebml_w, method_ty.explicit_self); + encode_explicit_self(ebml_w, &method_ty.explicit_self); let fn_style = method_ty.fty.fn_style; match method_ty.explicit_self { - ast::SelfStatic => { + ty::StaticExplicitSelfCategory => { encode_family(ebml_w, fn_style_static_method_family(fn_style)); } _ => encode_family(ebml_w, style_fn_family(fn_style)) @@ -1206,7 +1213,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_path(ebml_w, path.clone().chain(Some(elem).move_iter())); match method_ty.explicit_self { - SelfStatic => { + ty::StaticExplicitSelfCategory => { encode_family(ebml_w, fn_style_static_method_family( method_ty.fty.fn_style)); @@ -1233,7 +1240,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_attributes(ebml_w, m.attrs.as_slice()); // If this is a static method, we've already encoded // this. - if method_ty.explicit_self != SelfStatic { + if method_ty.explicit_self != ty::StaticExplicitSelfCategory { // FIXME: I feel like there is something funny going on. let pty = ty::lookup_item_type(tcx, method_def_id); encode_bounds_and_type(ebml_w, ecx, &pty); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index df4d3b7efe432..822a43f2619dc 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -314,6 +314,16 @@ impl RegionMaps { self.sub_free_region(sub_fr, super_fr) } + (ty::ReEarlyBound(param_id_a, param_space_a, index_a, _), + ty::ReEarlyBound(param_id_b, param_space_b, index_b, _)) => { + // This case is used only to make sure that explicitly- + // specified `Self` types match the real self type in + // implementations. + param_id_a == param_id_b && + param_space_a == param_space_b && + index_a == index_b + } + _ => { false } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 40237e7984f6c..f00d7c36f5333 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -11,13 +11,14 @@ #![allow(non_camel_case_types)] use driver::session::Session; +use lint; use metadata::csearch; use metadata::decoder::{DefLike, DlDef, DlField, DlImpl}; use middle::def::*; use middle::lang_items::LanguageItems; use middle::pat_util::pat_bindings; use middle::subst::{ParamSpace, FnSpace, TypeSpace}; -use lint; +use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory}; use util::nodemap::{NodeMap, DefIdSet, FnvHashMap}; use syntax::ast::*; @@ -287,6 +288,24 @@ enum ModulePrefixResult { PrefixFound(Rc, uint) } +#[deriving(Clone, Eq, PartialEq)] +enum MethodIsStaticFlag { + MethodIsNotStatic, + MethodIsStatic, +} + +impl MethodIsStaticFlag { + fn from_explicit_self_category(explicit_self_category: + ExplicitSelfCategory) + -> MethodIsStaticFlag { + if explicit_self_category == StaticExplicitSelfCategory { + MethodIsStatic + } else { + MethodIsNotStatic + } + } +} + #[deriving(PartialEq)] enum NameSearchType { /// We're doing a name search in order to resolve a `use` directive. @@ -805,7 +824,8 @@ struct Resolver<'a> { graph_root: NameBindings, - method_map: RefCell>, + method_map: RefCell>, + structs: FnvHashMap>, // The number of imports that are currently unresolved. @@ -1361,17 +1381,19 @@ impl<'a> Resolver<'a> { let ident = ty_m.ident; // Add it as a name in the trait module. - let def = match ty_m.explicit_self.node { + let (def, static_flag) = match ty_m.explicit_self.node { SelfStatic => { // Static methods become `def_static_method`s. - DefStaticMethod(local_def(ty_m.id), + (DefStaticMethod(local_def(ty_m.id), FromTrait(local_def(item.id)), - ty_m.fn_style) + ty_m.fn_style), + MethodIsStatic) } _ => { // Non-static methods become `def_method`s. - DefMethod(local_def(ty_m.id), - Some(local_def(item.id))) + (DefMethod(local_def(ty_m.id), + Some(local_def(item.id))), + MethodIsNotStatic) } }; @@ -1382,8 +1404,9 @@ impl<'a> Resolver<'a> { ty_m.span); method_name_bindings.define_value(def, ty_m.span, true); - self.method_map.borrow_mut().insert((ident.name, def_id), - ty_m.explicit_self.node); + self.method_map + .borrow_mut() + .insert((ident.name, def_id), static_flag); } name_bindings.define_type(DefTrait(def_id), sp, is_public); @@ -1670,7 +1693,11 @@ impl<'a> Resolver<'a> { trait method '{}'", token::get_ident(method_name)); - self.method_map.borrow_mut().insert((method_name.name, def_id), explicit_self); + self.method_map + .borrow_mut() + .insert((method_name.name, def_id), + MethodIsStaticFlag::from_explicit_self_category( + explicit_self)); if is_exported { self.external_exports.insert(method_def_id); @@ -3678,6 +3705,13 @@ impl<'a> Resolver<'a> { this.resolve_type(&*argument.ty); } + match ty_m.explicit_self.node { + SelfExplicit(ref typ, _) => { + this.resolve_type(*typ) + } + _ => {} + } + this.resolve_type(&*ty_m.decl.output); }); } @@ -4009,7 +4043,14 @@ impl<'a> Resolver<'a> { method.id, rib_kind); - self.resolve_function(rib_kind, Some(method.pe_fn_decl()), type_parameters, + match method.pe_explicit_self().node { + SelfExplicit(ref typ, _) => self.resolve_type(*typ), + _ => {} + } + + self.resolve_function(rib_kind, + Some(method.pe_fn_decl()), + type_parameters, method.pe_body()); } @@ -4765,7 +4806,7 @@ impl<'a> Resolver<'a> { match containing_module.def_id.get() { Some(def_id) => { match self.method_map.borrow().find(&(ident.name, def_id)) { - Some(x) if *x == SelfStatic => (), + Some(&MethodIsStatic) => (), None => (), _ => { debug!("containing module was a trait or impl \ @@ -5037,7 +5078,7 @@ impl<'a> Resolver<'a> { let path_str = self.path_idents_to_string(&trait_ref.path); match method_map.find(&(name, did)) { - Some(&SelfStatic) => return StaticTraitMethod(path_str), + Some(&MethodIsStatic) => return StaticTraitMethod(path_str), Some(_) => return TraitMethod, None => {} } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index f9c5f82fb29ac..53f0645cb8702 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -502,15 +502,12 @@ fn emit_vtable_methods(bcx: &Block, ExprId(0), substs.clone(), vtables.clone()); - match m.explicit_self { - ast::SelfValue(_) => { - fn_ref = trans_unboxing_shim(bcx, - fn_ref, - &*m, - m_id, - substs.clone()); - }, - _ => {} + if m.explicit_self == ty::ByValueExplicitSelfCategory { + fn_ref = trans_unboxing_shim(bcx, + fn_ref, + &*m, + m_id, + substs.clone()); } fn_ref } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index dc69e3fd6399d..cfafe99090d58 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -85,7 +85,7 @@ pub struct Method { pub ident: ast::Ident, pub generics: ty::Generics, pub fty: BareFnTy, - pub explicit_self: ast::ExplicitSelf_, + pub explicit_self: ExplicitSelfCategory, pub vis: ast::Visibility, pub def_id: ast::DefId, pub container: MethodContainer, @@ -98,7 +98,7 @@ impl Method { pub fn new(ident: ast::Ident, generics: ty::Generics, fty: BareFnTy, - explicit_self: ast::ExplicitSelf_, + explicit_self: ExplicitSelfCategory, vis: ast::Visibility, def_id: ast::DefId, container: MethodContainer, @@ -311,6 +311,9 @@ pub struct ctxt { /// (inferred) variance. pub item_variance_map: RefCell>>, + /// True if the variance has been computed yet; false otherwise. + pub variance_computed: Cell, + /// A mapping from the def ID of an enum or struct type to the def ID /// of the method that implements its destructor. If the type is not /// present in this map, it does not have a destructor. This map is @@ -1055,6 +1058,7 @@ pub fn mk_ctxt(s: Session, ctxt { named_region_map: named_region_map, item_variance_map: RefCell::new(DefIdMap::new()), + variance_computed: Cell::new(false), interner: RefCell::new(FnvHashMap::new()), next_id: Cell::new(primitives::LAST_PRIMITIVE_ID), sess: s, @@ -4767,3 +4771,13 @@ impl mc::Typer for ty::ctxt { self.upvar_borrow_map.borrow().get_copy(&upvar_id) } } + +/// The category of explicit self. +#[deriving(Clone, Eq, PartialEq)] +pub enum ExplicitSelfCategory { + StaticExplicitSelfCategory, + ByValueExplicitSelfCategory, + ByReferenceExplicitSelfCategory(Region, ast::Mutability), + ByBoxExplicitSelfCategory, +} + diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 5ed92b305be0d..09557c94aa62a 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -52,13 +52,13 @@ use middle::const_eval; use middle::def; use middle::lang_items::FnMutTraitLangItem; -use rl = middle::resolve_lifetime; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::ty; -use middle::typeck::TypeAndSubsts; -use middle::typeck::lookup_def_tcx; +use middle::ty_fold::TypeFolder; use middle::typeck::rscope::RegionScope; -use middle::typeck::rscope; +use middle::typeck::{TypeAndSubsts, infer, lookup_def_tcx, rscope}; +use middle::typeck; +use rl = middle::resolve_lifetime; use util::ppaux::Repr; use std::rc::Rc; @@ -900,58 +900,73 @@ pub fn ty_of_arg(this: &AC, rscope: &RS, a: &ast:: } } -struct SelfInfo { +struct SelfInfo<'a> { untransformed_self_ty: ty::t, - explicit_self: ast::ExplicitSelf + explicit_self: ast::ExplicitSelf, } pub fn ty_of_method( - this: &AC, - id: ast::NodeId, - fn_style: ast::FnStyle, - untransformed_self_ty: ty::t, - explicit_self: ast::ExplicitSelf, - decl: &ast::FnDecl) - -> ty::BareFnTy -{ - ty_of_method_or_bare_fn(this, id, fn_style, abi::Rust, Some(SelfInfo { + this: &AC, + id: ast::NodeId, + fn_style: ast::FnStyle, + untransformed_self_ty: ty::t, + explicit_self: ast::ExplicitSelf, + decl: &ast::FnDecl) + -> (ty::BareFnTy, ty::ExplicitSelfCategory) { + let self_info = Some(SelfInfo { untransformed_self_ty: untransformed_self_ty, - explicit_self: explicit_self - }), decl) + explicit_self: explicit_self, + }); + let (bare_fn_ty, optional_explicit_self_category) = + ty_of_method_or_bare_fn(this, + id, + fn_style, + abi::Rust, + self_info, + decl); + (bare_fn_ty, optional_explicit_self_category.unwrap()) } pub fn ty_of_bare_fn(this: &AC, id: ast::NodeId, fn_style: ast::FnStyle, abi: abi::Abi, decl: &ast::FnDecl) -> ty::BareFnTy { - ty_of_method_or_bare_fn(this, id, fn_style, abi, None, decl) + let (bare_fn_ty, _) = + ty_of_method_or_bare_fn(this, id, fn_style, abi, None, decl); + bare_fn_ty } -fn ty_of_method_or_bare_fn(this: &AC, id: ast::NodeId, - fn_style: ast::FnStyle, abi: abi::Abi, - opt_self_info: Option, - decl: &ast::FnDecl) -> ty::BareFnTy { +fn ty_of_method_or_bare_fn( + this: &AC, + id: ast::NodeId, + fn_style: ast::FnStyle, + abi: abi::Abi, + opt_self_info: Option, + decl: &ast::FnDecl) + -> (ty::BareFnTy, + Option) { debug!("ty_of_method_or_bare_fn"); // new region names that appear inside of the fn decl are bound to // that function type let rb = rscope::BindingRscope::new(id); + let mut explicit_self_category_result = None; let self_ty = opt_self_info.and_then(|self_info| { - match self_info.explicit_self.node { - ast::SelfStatic => None, - ast::SelfValue(_) => { + // Figure out and record the explicit self category. + let explicit_self_category = + determine_explicit_self_category(this, &rb, &self_info); + explicit_self_category_result = Some(explicit_self_category); + match explicit_self_category { + ty::StaticExplicitSelfCategory => None, + ty::ByValueExplicitSelfCategory => { Some(self_info.untransformed_self_ty) } - ast::SelfRegion(ref lifetime, mutability, _) => { - let region = - opt_ast_region_to_region(this, &rb, - self_info.explicit_self.span, - lifetime); + ty::ByReferenceExplicitSelfCategory(region, mutability) => { Some(ty::mk_rptr(this.tcx(), region, ty::mt {ty: self_info.untransformed_self_ty, mutbl: mutability})) } - ast::SelfUniq(_) => { + ty::ByBoxExplicitSelfCategory => { Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty)) } } @@ -972,7 +987,7 @@ fn ty_of_method_or_bare_fn(this: &AC, id: ast::NodeId, _ => ast_ty_to_ty(this, &rb, &*decl.output) }; - return ty::BareFnTy { + (ty::BareFnTy { fn_style: fn_style, abi: abi, sig: ty::FnSig { @@ -981,7 +996,83 @@ fn ty_of_method_or_bare_fn(this: &AC, id: ast::NodeId, output: output_ty, variadic: decl.variadic } - }; + }, explicit_self_category_result) +} + +fn determine_explicit_self_category( + this: &AC, + rscope: &RS, + self_info: &SelfInfo) + -> ty::ExplicitSelfCategory { + match self_info.explicit_self.node { + ast::SelfStatic => ty::StaticExplicitSelfCategory, + ast::SelfValue(_) => ty::ByValueExplicitSelfCategory, + ast::SelfRegion(ref lifetime, mutability, _) => { + let region = + opt_ast_region_to_region(this, + rscope, + self_info.explicit_self.span, + lifetime); + ty::ByReferenceExplicitSelfCategory(region, mutability) + } + ast::SelfUniq(_) => ty::ByBoxExplicitSelfCategory, + ast::SelfExplicit(ast_type, _) => { + let explicit_type = ast_ty_to_ty(this, rscope, ast_type); + + { + let inference_context = infer::new_infer_ctxt(this.tcx()); + let expected_self = self_info.untransformed_self_ty; + let actual_self = explicit_type; + let result = infer::mk_eqty( + &inference_context, + false, + infer::Misc(self_info.explicit_self.span), + expected_self, + actual_self); + match result { + Ok(_) => { + inference_context.resolve_regions_and_report_errors(); + return ty::ByValueExplicitSelfCategory + } + Err(_) => {} + } + } + + match ty::get(explicit_type).sty { + ty::ty_rptr(region, tm) => { + typeck::require_same_types( + this.tcx(), + None, + false, + self_info.explicit_self.span, + self_info.untransformed_self_ty, + tm.ty, + || "not a valid type for `self`".to_owned()); + return ty::ByReferenceExplicitSelfCategory(region, + tm.mutbl) + } + ty::ty_uniq(typ) => { + typeck::require_same_types( + this.tcx(), + None, + false, + self_info.explicit_self.span, + self_info.untransformed_self_ty, + typ, + || "not a valid type for `self`".to_owned()); + return ty::ByBoxExplicitSelfCategory + } + _ => { + this.tcx() + .sess + .span_err(self_info.explicit_self.span, + "not a valid type for `self`"); + return ty::ByValueExplicitSelfCategory + } + } + } + } } pub fn ty_of_closure( @@ -1098,3 +1189,4 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, (&None, ty::UniqTraitStore) => ty::empty_builtin_bounds(), } } + diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 4787837093844..e12fae4f9501e 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -100,9 +100,7 @@ use util::ppaux::Repr; use std::collections::HashSet; use std::rc::Rc; -use syntax::ast::{DefId, SelfValue, SelfRegion}; -use syntax::ast::{SelfUniq, SelfStatic}; -use syntax::ast::{MutMutable, MutImmutable}; +use syntax::ast::{DefId, MutImmutable, MutMutable}; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token; @@ -267,15 +265,15 @@ fn construct_transformed_self_ty_for_object( obj_substs.types.pop(subst::SelfSpace).unwrap(); match method_ty.explicit_self { - ast::SelfStatic => { + StaticExplicitSelfCategory => { tcx.sess.span_bug(span, "static method for object type receiver"); } - ast::SelfValue(_) => { + ByValueExplicitSelfCategory => { let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, ty::empty_builtin_bounds()); ty::mk_uniq(tcx, tr) } - ast::SelfRegion(..) | ast::SelfUniq(..) => { + ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => { let transformed_self_ty = *method_ty.fty.sig.inputs.get(0); match ty::get(transformed_self_ty).sty { ty::ty_rptr(r, mt) => { // must be SelfRegion @@ -618,7 +616,7 @@ impl<'a> LookupContext<'a> { let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); match trait_methods.iter().position(|m| { - m.explicit_self != ast::SelfStatic && + m.explicit_self != ty::StaticExplicitSelfCategory && m.ident.name == self.m_name }) { Some(pos) => { let method = trait_methods.get(pos).clone(); @@ -1023,7 +1021,10 @@ impl<'a> LookupContext<'a> { if self.report_statics == ReportStaticMethods { // lookup should only be called with ReportStaticMethods if a regular lookup failed - assert!(relevant_candidates.iter().all(|c| c.method_ty.explicit_self == SelfStatic)); + assert!(relevant_candidates.iter() + .all(|c| { + c.method_ty.explicit_self == ty::StaticExplicitSelfCategory + })); self.tcx().sess.fileline_note(self.span, "found defined static methods, maybe a `self` is missing?"); @@ -1100,7 +1101,8 @@ impl<'a> LookupContext<'a> { self.enforce_drop_trait_limitations(candidate); // static methods should never have gotten this far: - assert!(candidate.method_ty.explicit_self != SelfStatic); + assert!(candidate.method_ty.explicit_self != + ty::StaticExplicitSelfCategory); // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh @@ -1217,12 +1219,16 @@ impl<'a> LookupContext<'a> { } match candidate.method_ty.explicit_self { - ast::SelfStatic => { // reason (a) above - span_err!(self.tcx().sess, self.span, E0037, - "cannot call a method without a receiver through an object"); + ty::StaticExplicitSelfCategory => { // reason (a) above + self.tcx().sess.span_err( + self.span, + "cannot call a method without a receiver \ + through an object"); } - ast::SelfValue(_) | ast::SelfRegion(..) | ast::SelfUniq(_) => {} + ty::ByValueExplicitSelfCategory | + ty::ByReferenceExplicitSelfCategory(..) | + ty::ByBoxExplicitSelfCategory => {} } // reason (a) above @@ -1284,12 +1290,12 @@ impl<'a> LookupContext<'a> { self.ty_to_string(rcvr_ty), candidate.repr(self.tcx())); return match candidate.method_ty.explicit_self { - SelfStatic => { + StaticExplicitSelfCategory => { debug!("(is relevant?) explicit self is static"); self.report_statics == ReportStaticMethods } - SelfValue(_) => { + ByValueExplicitSelfCategory => { debug!("(is relevant?) explicit self is by-value"); match ty::get(rcvr_ty).sty { ty::ty_uniq(typ) => { @@ -1312,7 +1318,7 @@ impl<'a> LookupContext<'a> { } } - SelfRegion(_, m, _) => { + ByReferenceExplicitSelfCategory(_, m) => { debug!("(is relevant?) explicit self is a region"); match ty::get(rcvr_ty).sty { ty::ty_rptr(_, mt) => { @@ -1332,7 +1338,7 @@ impl<'a> LookupContext<'a> { } } - SelfUniq(_) => { + ByBoxExplicitSelfCategory => { debug!("(is relevant?) explicit self is a unique pointer"); match ty::get(rcvr_ty).sty { ty::ty_uniq(typ) => { @@ -1480,3 +1486,6 @@ impl Repr for RcvrMatchCondition { } } } + + + diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index bc4d1c73ffbf3..4f07f1121b7ce 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -862,19 +862,26 @@ fn compare_impl_method(tcx: &ty::ctxt, // inscrutable, particularly for cases where one method has no // self. match (&trait_m.explicit_self, &impl_m.explicit_self) { - (&ast::SelfStatic, &ast::SelfStatic) => {} - (&ast::SelfStatic, _) => { - span_err!(tcx.sess, impl_m_span, E0047, - "method `{}` has a `{}` declaration in the impl, but not in the trait", - token::get_ident(trait_m.ident), - pprust::explicit_self_to_string(impl_m.explicit_self)); + (&ty::StaticExplicitSelfCategory, + &ty::StaticExplicitSelfCategory) => {} + (&ty::StaticExplicitSelfCategory, _) => { + tcx.sess.span_err( + impl_m_span, + format!("method `{}` has a `{}` declaration in the impl, \ + but not in the trait", + token::get_ident(trait_m.ident), + ppaux::explicit_self_category_to_str( + &impl_m.explicit_self)).as_slice()); return; } - (_, &ast::SelfStatic) => { - span_err!(tcx.sess, impl_m_span, E0048, - "method `{}` has a `{}` declaration in the trait, but not in the impl", - token::get_ident(trait_m.ident), - pprust::explicit_self_to_string(trait_m.explicit_self)); + (_, &ty::StaticExplicitSelfCategory) => { + tcx.sess.span_err( + impl_m_span, + format!("method `{}` has a `{}` declaration in the trait, \ + but not in the impl", + token::get_ident(trait_m.ident), + ppaux::explicit_self_category_to_str( + &trait_m.explicit_self)).as_slice()); return; } _ => { @@ -4787,3 +4794,4 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { }); } } + diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index e21a7949ec799..eea26fbcfc73f 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -40,11 +40,14 @@ use middle::subst::{Substs}; use middle::ty::{ImplContainer, MethodContainer, TraitContainer}; use middle::ty::{Polytype}; use middle::ty; +use middle::ty_fold::TypeFolder; use middle::typeck::astconv::{AstConv, ty_of_arg}; use middle::typeck::astconv::{ast_ty_to_ty}; use middle::typeck::astconv; +use middle::typeck::infer; use middle::typeck::rscope::*; use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; +use middle::typeck; use util::ppaux; use util::ppaux::Repr; @@ -218,7 +221,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, } }); - if ty_method.explicit_self == ast::SelfStatic { + if ty_method.explicit_self == + ty::StaticExplicitSelfCategory { make_static_method_ty(ccx, &*ty_method); } @@ -266,18 +270,26 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, m_fn_style: &ast::FnStyle, m_decl: &ast::FnDecl) -> ty::Method { - let trait_self_ty = ty::mk_self_type(this.tcx, local_def(trait_id)); - let fty = astconv::ty_of_method(this, *m_id, *m_fn_style, trait_self_ty, - *m_explicit_self, m_decl); - let ty_generics = - ty_generics_for_fn_or_method(this, - m_generics, - (*trait_generics).clone()); + let trait_self_ty = ty::mk_param(this.tcx, + subst::SelfSpace, + 0, + local_def(trait_id)); + let ty_generics = ty_generics_for_fn_or_method( + this, + m_generics, + (*trait_generics).clone()); + let (fty, explicit_self_category) = + astconv::ty_of_method(this, + *m_id, + *m_fn_style, + trait_self_ty, + *m_explicit_self, + m_decl); ty::Method::new( *m_ident, ty_generics, fty, - m_explicit_self.node, + explicit_self_category, // assume public, because this is only invoked on trait methods ast::Public, local_def(*m_id), @@ -365,9 +377,13 @@ fn convert_methods(ccx: &CrateCtxt, rcvr_visibility: ast::Visibility) -> ty::Method { - let fty = astconv::ty_of_method(ccx, m.id, m.pe_fn_style(), - untransformed_rcvr_ty, - *m.pe_explicit_self(), m.pe_fn_decl()); + let (fty, explicit_self_category) = + astconv::ty_of_method(ccx, + m.id, + m.pe_fn_style(), + untransformed_rcvr_ty, + *m.pe_explicit_self(), + m.pe_fn_decl()); // if the method specifies a visibility, use that, otherwise // inherit the visibility from the impl (so `foo` in `pub impl @@ -381,7 +397,7 @@ fn convert_methods(ccx: &CrateCtxt, ty::Method::new(m.pe_ident(), m_ty_generics, fty, - m.pe_explicit_self().node, + explicit_self_category, method_vis, local_def(m.id), container, @@ -450,6 +466,13 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { it.vis }; + for method in ms.iter() { + check_method_self_type(ccx, + &BindingRscope::new(method.id), + selfty, + method.pe_explicit_self()) + } + convert_methods(ccx, ImplContainer(local_def(it.id)), ms.as_slice(), @@ -464,6 +487,28 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ast::ItemTrait(_, _, _, ref trait_methods) => { let trait_def = trait_def_of_item(ccx, it); + for trait_method in trait_methods.iter() { + let self_type = ty::mk_param(ccx.tcx, + subst::SelfSpace, + 0, + local_def(it.id)); + match *trait_method { + ast::Required(ref type_method) => { + let rscope = BindingRscope::new(type_method.id); + check_method_self_type(ccx, + &rscope, + self_type, + &type_method.explicit_self) + } + ast::Provided(ref method) => { + check_method_self_type(ccx, + &BindingRscope::new(method.id), + self_type, + method.pe_explicit_self()) + } + } + } + // Run convert_methods on the provided methods. let (_, provided_methods) = split_trait_methods(trait_methods.as_slice()); @@ -1240,3 +1285,36 @@ pub fn mk_item_substs(ccx: &CrateCtxt, subst::Substs::new(types, regions) } + +/// Verifies that the explicit self type of a method matches the impl or +/// trait. +fn check_method_self_type( + crate_context: &CrateCtxt, + rs: &RS, + required_type: ty::t, + explicit_self: &ast::ExplicitSelf) { + match explicit_self.node { + ast::SelfExplicit(ref ast_type, _) => { + let typ = crate_context.to_ty(rs, *ast_type); + let base_type = match ty::get(typ).sty { + ty::ty_rptr(_, tm) => tm.ty, + ty::ty_uniq(typ) => typ, + _ => typ, + }; + let infcx = infer::new_infer_ctxt(crate_context.tcx); + drop(typeck::require_same_types(crate_context.tcx, + Some(&infcx), + false, + explicit_self.span, + base_type, + required_type, + || { + format!("mismatched self type: expected `{}`", + ppaux::ty_to_string(crate_context.tcx, required_type)) + })); + infcx.resolve_regions_and_report_errors(); + } + _ => {} + } +} + diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 1e33b1d5d0ebd..c3de120a0c393 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -111,7 +111,11 @@ pub trait Combine { b_subst: &subst::Substs) -> cres { - let variances = ty::item_variances(self.infcx().tcx, item_def_id); + let variances = if self.infcx().tcx.variance_computed.get() { + Some(ty::item_variances(self.infcx().tcx, item_def_id)) + } else { + None + }; let mut substs = subst::Substs::empty(); for &space in subst::ParamSpace::all().iter() { @@ -121,7 +125,18 @@ pub trait Combine { let a_regions = a_subst.regions().get_slice(space); let b_regions = b_subst.regions().get_slice(space); - let r_variances = variances.regions.get_slice(space); + + let mut invariance = Vec::new(); + let r_variances = match variances { + Some(ref variances) => variances.regions.get_slice(space), + None => { + for _ in a_regions.iter() { + invariance.push(ty::Invariant); + } + invariance.as_slice() + } + }; + let regions = if_ok!(relate_region_params(self, item_def_id, r_variances, diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 28240686dc358..d17553e9c39b3 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -13,16 +13,15 @@ use middle::ty; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; -use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound, - ReLateBound}; -use middle::ty::{ReScope, ReVar, ReSkolemized, BrFresh}; +use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; +use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use middle::typeck::infer::cres; use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin, TypeTrace}; use middle::typeck::infer; use middle::graph; use middle::graph::{Direction, NodeIndex}; use util::common::indenter; -use util::ppaux::{Repr}; +use util::ppaux::Repr; use std::cell::{Cell, RefCell}; use std::uint; @@ -318,6 +317,11 @@ impl<'a> RegionVarBindings<'a> { origin.repr(self.tcx)); match (sub, sup) { + (ReEarlyBound(..), ReEarlyBound(..)) => { + // This case is used only to make sure that explicitly-specified + // `Self` types match the real self type in implementations. + self.add_constraint(ConstrainRegSubReg(sub, sup), origin); + } (ReEarlyBound(..), _) | (ReLateBound(..), _) | (_, ReEarlyBound(..)) | diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 8b5d16620b0f5..a65aa0423a6d0 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -214,6 +214,7 @@ pub fn infer_variance(tcx: &ty::ctxt, let terms_cx = determine_parameters_to_be_inferred(tcx, &mut arena, krate); let constraints_cx = add_constraints_from_crate(terms_cx, krate); solve_constraints(constraints_cx); + tcx.variance_computed.set(true); } /************************************************************************** diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6526943955c92..e37bef98e4404 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -14,7 +14,7 @@ use middle::subst; use middle::subst::{VecPerParamSpace,Subst}; use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{BoundRegion, BrAnon, BrNamed}; -use middle::ty::{BrFresh, ctxt}; +use middle::ty::{ReEarlyBound, BrFresh, ctxt}; use middle::ty::{mt, t, ParamTy}; use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; @@ -130,9 +130,13 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) ReEmpty => { ("the empty lifetime".to_string(), None) } + ReEarlyBound(_, _, _, name) => { + (format!("{}", token::get_name(name)), None) + } + // I believe these cases should not occur (except when debugging, // perhaps) - ty::ReInfer(_) | ty::ReEarlyBound(..) | ty::ReLateBound(..) => { + ty::ReInfer(_) | ty::ReLateBound(..) => { (format!("lifetime {:?}", region), None) } }; @@ -421,6 +425,19 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { } } +pub fn explicit_self_category_to_str(category: &ty::ExplicitSelfCategory) + -> &'static str { + match *category { + ty::StaticExplicitSelfCategory => "static", + ty::ByValueExplicitSelfCategory => "self", + ty::ByReferenceExplicitSelfCategory(_, ast::MutMutable) => { + "&mut self" + } + ty::ByReferenceExplicitSelfCategory(_, ast::MutImmutable) => "&self", + ty::ByBoxExplicitSelfCategory => "Box", + } +} + pub fn parameterized(cx: &ctxt, base: &str, substs: &subst::Substs, @@ -1083,3 +1100,10 @@ impl Repr for region_inference::VarValue { } } } + +impl Repr for ty::ExplicitSelfCategory { + fn repr(&self, _: &ctxt) -> String { + explicit_self_category_to_str(self).to_string() + } +} + diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 54053d215dc3b..5be668853207f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -394,7 +394,7 @@ impl Clean for doctree::Module { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub enum Attribute { Word(String), List(String, Vec ), @@ -447,7 +447,7 @@ impl<'a> attr::AttrMetaMethods for &'a Attribute { fn meta_item_list<'a>(&'a self) -> Option<&'a [Gc]> { None } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct TyParam { pub name: String, pub did: ast::DefId, @@ -479,7 +479,7 @@ impl Clean for ty::TypeParameterDef { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub enum TyParamBound { RegionBound, TraitBound(Type) @@ -638,7 +638,7 @@ impl Clean> for ty::Region { } // maybe use a Generic enum and use ~[Generic]? -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct Generics { pub lifetimes: Vec, pub type_params: Vec, @@ -771,6 +771,7 @@ pub enum SelfTy { SelfValue, SelfBorrowed(Option, Mutability), SelfOwned, + SelfExplicit(Type), } impl Clean for ast::ExplicitSelf_ { @@ -779,7 +780,10 @@ impl Clean for ast::ExplicitSelf_ { ast::SelfStatic => SelfStatic, ast::SelfValue(_) => SelfValue, ast::SelfUniq(_) => SelfOwned, - ast::SelfRegion(lt, mt, _) => SelfBorrowed(lt.clean(), mt.clean()), + ast::SelfRegion(lt, mt, _) => { + SelfBorrowed(lt.clean(), mt.clean()) + } + ast::SelfExplicit(typ, _) => SelfExplicit(typ.clean()), } } } @@ -809,7 +813,7 @@ impl Clean for doctree::Function { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct ClosureDecl { pub lifetimes: Vec, pub decl: FnDecl, @@ -833,7 +837,7 @@ impl Clean for ast::ClosureTy { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct FnDecl { pub inputs: Arguments, pub output: Type, @@ -841,7 +845,7 @@ pub struct FnDecl { pub attrs: Vec, } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct Arguments { pub values: Vec, } @@ -888,7 +892,7 @@ impl<'a> Clean for (ast::DefId, &'a ty::FnSig) { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct Argument { pub type_: Type, pub name: String, @@ -905,7 +909,7 @@ impl Clean for ast::Arg { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub enum RetStyle { NoReturn, Return @@ -991,22 +995,28 @@ impl Clean for ty::Method { fn clean(&self) -> Item { let cx = get_cx(); let (self_, sig) = match self.explicit_self { - ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()), + ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(), self.fty.sig.clone()), s => { let sig = ty::FnSig { inputs: Vec::from_slice(self.fty.sig.inputs.slice_from(1)), ..self.fty.sig.clone() }; let s = match s { - ast::SelfRegion(..) => { - match ty::get(self.fty.sig.inputs[0]).sty { + ty::ByReferenceExplicitSelfCategory(..) => { + match ty::get(*self.fty.sig.inputs[0]).sty { ty::ty_rptr(r, mt) => { SelfBorrowed(r.clean(), mt.mutbl.clean()) } - _ => s.clean(), + _ => { + // FIXME(pcwalton): This is wrong. + SelfStatic + } } } - s => s.clean(), + _ => { + // FIXME(pcwalton): This is wrong. + SelfStatic + } }; (s, sig) } @@ -1032,7 +1042,7 @@ impl Clean for ty::Method { /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original /// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly /// it does not preserve mutability or boxes. -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub enum Type { /// structs/enums/traits (anything that'd be an ast::TyPath) ResolvedPath { @@ -1550,7 +1560,7 @@ impl Clean for syntax::codemap::Span { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct Path { pub global: bool, pub segments: Vec, @@ -1565,7 +1575,7 @@ impl Clean for ast::Path { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct PathSegment { pub name: String, pub lifetimes: Vec, @@ -1631,7 +1641,7 @@ impl Clean for doctree::Typedef { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct BareFunctionDecl { pub fn_style: ast::FnStyle, pub generics: Generics, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f64a75c559e9b..d0f9b37cc4ce4 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -500,6 +500,9 @@ impl<'a> fmt::Show for Method<'a> { args.push_str(format!("&{}self", MutableSpace(mtbl)).as_slice()); } + clean::SelfExplicit(ref typ) => { + args.push_str(format!("self: {}", *typ).as_slice()); + } } for (i, input) in d.inputs.values.iter().enumerate() { if i > 0 || args.len() > 0 { args.push_str(", "); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 857cb4c0162ce..d9f14bfa15661 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -949,12 +949,14 @@ pub enum RetStyle { pub enum ExplicitSelf_ { /// No self SelfStatic, - /// `self + /// `self` SelfValue(Ident), /// `&'lt self`, `&'lt mut self` SelfRegion(Option, Mutability, Ident), /// `~self` - SelfUniq(Ident) + SelfUniq(Ident), + /// `self: TYPE` + SelfExplicit(P, Ident), } pub type ExplicitSelf = Spanned; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fd786192cb48c..87c762af2e5bd 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -344,6 +344,7 @@ pub trait Folder { SelfRegion(ref lifetime, m, id) => { SelfRegion(fold_opt_lifetime(lifetime, self), m, id) } + SelfExplicit(ref typ, id) => SelfExplicit(self.fold_ty(*typ), id), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e0c94dffb5cae..bdfd928cfbcd8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -45,7 +45,7 @@ use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; use ast::{StructVariantKind, BiSub}; use ast::StrStyle; -use ast::{SelfRegion, SelfStatic, SelfUniq, SelfValue}; +use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfUniq, SelfValue}; use ast::{TokenTree, TraitMethod, TraitRef, TTDelim, TTSeq, TTTok}; use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox}; use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; @@ -3843,7 +3843,15 @@ impl<'a> Parser<'a> { } } token::IDENT(..) if self.is_self_ident() => { - SelfValue(self.expect_self_ident()) + let self_ident = self.expect_self_ident(); + + // Determine whether this is the fully explicit form, `self: + // TYPE`. + if self.eat(&token::COLON) { + SelfExplicit(self.parse_ty(false), self_ident) + } else { + SelfValue(self_ident) + } } token::BINOP(token::STAR) => { // Possibly "*self" or "*mut self" -- not supported. Try to avoid @@ -3851,7 +3859,9 @@ impl<'a> Parser<'a> { self.bump(); let _mutability = if Parser::token_is_mutability(&self.token) { self.parse_mutability() - } else { MutImmutable }; + } else { + MutImmutable + }; if self.is_self_ident() { let span = self.span; self.span_err(span, "cannot pass self by unsafe pointer"); @@ -3863,7 +3873,15 @@ impl<'a> Parser<'a> { _ if Parser::token_is_mutability(&self.token) && self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) => { mutbl_self = self.parse_mutability(); - SelfValue(self.expect_self_ident()) + let self_ident = self.expect_self_ident(); + + // Determine whether this is the fully explicit form, `self: + // TYPE`. + if self.eat(&token::COLON) { + SelfExplicit(self.parse_ty(false), self_ident) + } else { + SelfValue(self_ident) + } } _ if Parser::token_is_mutability(&self.token) && self.look_ahead(1, |t| *t == token::TILDE) && @@ -3914,8 +3932,8 @@ impl<'a> Parser<'a> { } SelfValue(id) => parse_remaining_arguments!(id), SelfRegion(_,_,id) => parse_remaining_arguments!(id), - SelfUniq(id) => parse_remaining_arguments!(id) - + SelfUniq(id) => parse_remaining_arguments!(id), + SelfExplicit(_,id) => parse_remaining_arguments!(id), }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d524622f8ecf5..428a15cb8cf74 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1859,6 +1859,11 @@ impl<'a> State<'a> { try!(self.print_mutability(m)); try!(word(&mut self.s, "self")); } + ast::SelfExplicit(ref typ, _) => { + try!(word(&mut self.s, "self")); + try!(self.word_space(":")); + try!(self.print_type(*typ)); + } } return Ok(true); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 795f19d0cfb06..6760d7a393205 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -215,6 +215,7 @@ pub fn walk_explicit_self>(visitor: &mut V, SelfRegion(ref lifetime, _, _) => { visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime, env) } + SelfExplicit(ref typ, _) => visitor.visit_ty(*typ, env.clone()), } } diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs new file mode 100644 index 0000000000000..285792e26b1bf --- /dev/null +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -0,0 +1,26 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo<'a,'b> { + x: &'a int, + y: &'b int, +} + +impl<'a,'b> Foo<'a,'b> { + // The number of errors is related to the way invariance works. + fn bar(self: Foo<'b,'a>) {} + //~^ ERROR mismatched types: expected `Foo<'a,'b>` but found `Foo<'b,'a>` + //~^^ ERROR mismatched types: expected `Foo<'a,'b>` but found `Foo<'b,'a>` + //~^^^ ERROR mismatched types: expected `Foo<'b,'a>` but found `Foo<'a,'b>` + //~^^^^ ERROR mismatched types: expected `Foo<'b,'a>` but found `Foo<'a,'b>` +} + +fn main() {} + diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs new file mode 100644 index 0000000000000..e5bad7e31b81e --- /dev/null +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -0,0 +1,49 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::owned::Box; + +struct Foo { + f: int, +} + +impl Foo { + fn foo(self: int, x: int) -> int { //~ ERROR mismatched self type +//~^ ERROR not a valid type for `self` + self.f + x + } +} + +struct Bar { + f: T, +} + +impl Bar { + fn foo(self: Bar, x: int) -> int { //~ ERROR mismatched self type +//~^ ERROR not a valid type for `self` + x + } + fn bar(self: &Bar, x: int) -> int { //~ ERROR mismatched self type +//~^ ERROR not a valid type for `self` + x + } +} + +fn main() { + let foo = box Foo { + f: 1, + }; + println!("{}", foo.foo(2)); + let bar = box Bar { + f: 1, + }; + println!("{} {}", bar.foo(2), bar.bar(2)); +} + diff --git a/src/test/run-pass/ufcs-explicit-self.rs b/src/test/run-pass/ufcs-explicit-self.rs new file mode 100644 index 0000000000000..9ffb56c516af5 --- /dev/null +++ b/src/test/run-pass/ufcs-explicit-self.rs @@ -0,0 +1,57 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::owned::Box; + +struct Foo { + f: int, +} + +impl Foo { + fn foo(self: Foo, x: int) -> int { + self.f + x + } + fn bar(self: &Foo, x: int) -> int { + self.f + x + } + fn baz(self: Box, x: int) -> int { + self.f + x + } +} + +struct Bar { + f: T, +} + +impl Bar { + fn foo(self: Bar, x: int) -> int { + x + } + fn bar<'a>(self: &'a Bar, x: int) -> int { + x + } + fn baz(self: Bar, x: int) -> int { + x + } +} + +fn main() { + let foo = box Foo { + f: 1, + }; + println!("{} {} {}", foo.foo(2), foo.bar(2), foo.baz(2)); + let bar = box Bar { + f: 1, + }; + println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2)); + let bar: Box> = bar; + println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2)); +} +