From adc4bed773ea6af7343a5a6bbe46e288367fecee Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 14 Nov 2012 16:32:37 -0800 Subject: [PATCH] librustc: Implement (and require) explicit self for derivable traits. r=nmatsakis --- src/librustc/middle/trans/deriving.rs | 55 +++++++++++++++---- src/librustc/middle/typeck.rs | 1 + src/librustc/middle/typeck/deriving.rs | 17 ++++-- src/librustc/rustc.rc | 8 +-- .../compile-fail/enum-deriving-incomplete.rs | 2 +- .../compile-fail/missing-derivable-attr.rs | 4 +- src/test/run-pass/deriving-generic-bounded.rs | 10 ++-- src/test/run-pass/deriving-one-method.rs | 10 ++-- src/test/run-pass/deriving-override.rs | 10 ++-- .../run-pass/deriving-param-pass-through.rs | 6 +- src/test/run-pass/deriving-returning-nil.rs | 4 +- src/test/run-pass/deriving-simple.rs | 4 +- src/test/run-pass/enum-deriving-simple.rs | 4 +- 13 files changed, 89 insertions(+), 46 deletions(-) diff --git a/src/librustc/middle/trans/deriving.rs b/src/librustc/middle/trans/deriving.rs index 6b54407781c..8fc81101faf 100644 --- a/src/librustc/middle/trans/deriving.rs +++ b/src/librustc/middle/trans/deriving.rs @@ -4,6 +4,7 @@ use lib::llvm::llvm::{LLVMCountParams, LLVMGetParam}; use middle::trans::base::{GEP_enum, finish_fn, get_insn_ctxt, get_item_val}; use middle::trans::base::{new_fn_ctxt, sub_block, top_scope_block}; +use middle::trans::base; use middle::trans::build::{AddCase, Br, CondBr, GEPi, Load, PointerCast}; use middle::trans::build::{Store, Switch, Unreachable, ValueRef}; use middle::trans::callee; @@ -14,7 +15,8 @@ use middle::trans::common::{C_bool, C_int, T_ptr, block, crate_ctxt}; use middle::trans::common::{fn_ctxt}; use middle::trans::expr::SaveIn; use middle::trans::type_of::type_of; -use middle::ty::DerivedFieldInfo; +use middle::ty::{DerivedFieldInfo, re_static}; +use middle::typeck::check::method; use middle::typeck::method_static; use syntax::ast; use syntax::ast::{def_id, ident, node_id, ty_param}; @@ -78,14 +80,33 @@ pub fn trans_deriving_impl(ccx: @crate_ctxt, for method_dids.each |method_did| { let kind = DerivingKind::of_item(ccx, *method_did); let llfn = get_item_val(ccx, method_did.node); + + // Transform the self type as appropriate. + let derived_method_info = + ccx.tcx.automatically_derived_methods.get(*method_did); + let transformed_self_ty = + method::transform_self_type_for_method( + ccx.tcx, + Some(re_static), + self_ty.ty, + derived_method_info.method_info.self_type); + match ty::get(self_ty.ty).sty { ty::ty_class(*) => { - trans_deriving_struct_method(ccx, llfn, impl_def_id, - self_ty.ty, kind); + trans_deriving_struct_method(ccx, + llfn, + impl_def_id, + self_ty.ty, + transformed_self_ty, + kind); } ty::ty_enum(*) => { - trans_deriving_enum_method(ccx, llfn, impl_def_id, - self_ty.ty, kind); + trans_deriving_enum_method(ccx, + llfn, + impl_def_id, + self_ty.ty, + transformed_self_ty, + kind); } _ => { ccx.tcx.sess.bug(~"translation of non-struct \ @@ -119,6 +140,7 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef, impl_did: def_id, self_ty: ty::t, + transformed_self_ty: ty::t, kind: DerivingKind) { let _icx = ccx.insn_ctxt("trans_deriving_struct_method"); let fcx = new_fn_ctxt(ccx, ~[], llfn, None); @@ -128,8 +150,10 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, let llextraparams = get_extra_params(llfn, kind); - let llselfty = type_of(ccx, self_ty); - let llselfval = PointerCast(bcx, fcx.llenv, T_ptr(llselfty)); + let lltransformedselfty = type_of(ccx, transformed_self_ty); + let lltransformedselfval = + PointerCast(bcx, fcx.llenv, T_ptr(lltransformedselfty)); + let llselfval = Load(bcx, lltransformedselfval); // If there is an "other" value, then get it. The "other" value is the // value we're comparing against in the case of Eq and Ord. @@ -155,6 +179,9 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, for ccx.tcx.deriving_struct_methods.get(impl_did).eachi |i, derived_method_info| { let llselfval = GEPi(bcx, llselfval, [0, 0, i]); + let llselfallocaty = common::val_ty(llselfval); + let llselfalloca = base::alloca(bcx, llselfallocaty); + Store(bcx, llselfval, llselfalloca); let llotherval_opt = llotherval_opt.map( |llotherval| GEPi(bcx, *llotherval, [0, 0, i])); @@ -163,7 +190,7 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, bcx = call_substructure_method(bcx, derived_method_info, self_ty, - llselfval, + llselfalloca, llotherval_opt, llextraparams); @@ -197,6 +224,7 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef, impl_did: def_id, self_ty: ty::t, + transformed_self_ty: ty::t, kind: DerivingKind) { let _icx = ccx.insn_ctxt("trans_deriving_enum_method"); let fcx = new_fn_ctxt(ccx, ~[], llfn, None); @@ -206,8 +234,10 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, let llextraparams = get_extra_params(llfn, kind); - let llselfty = type_of(ccx, self_ty); - let llselfval = PointerCast(bcx, fcx.llenv, T_ptr(llselfty)); + let lltransformedselfty = type_of(ccx, transformed_self_ty); + let lltransformedselfval = + PointerCast(bcx, fcx.llenv, T_ptr(lltransformedselfty)); + let llselfval = Load(bcx, lltransformedselfval); let llotherval_opt; match kind { @@ -280,6 +310,9 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, enum_variant_infos[self_variant_index].id; let llselfval = GEP_enum(match_bcx, llselfpayload, enum_id, variant_def_id, enum_substs.tps, i); + let llselfallocaty = common::val_ty(llselfval); + let llselfalloca = base::alloca(match_bcx, llselfallocaty); + Store(match_bcx, llselfval, llselfalloca); let llotherval_opt = llotherpayload_opt.map(|llotherpayload| GEP_enum(match_bcx, *llotherpayload, enum_id, @@ -289,7 +322,7 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, match_bcx = call_substructure_method(match_bcx, derived_method_info, self_ty, - llselfval, + llselfalloca, llotherval_opt, llextraparams); diff --git a/src/librustc/middle/typeck.rs b/src/librustc/middle/typeck.rs index d4df07f7eb8..977fc06ce86 100644 --- a/src/librustc/middle/typeck.rs +++ b/src/librustc/middle/typeck.rs @@ -63,6 +63,7 @@ use std::list; use list::{List, Nil, Cons}; use dvec::DVec; +export check; export check_crate; export infer; export method_map; diff --git a/src/librustc/middle/typeck/deriving.rs b/src/librustc/middle/typeck/deriving.rs index 197a06a1d97..010ca242c7d 100644 --- a/src/librustc/middle/typeck/deriving.rs +++ b/src/librustc/middle/typeck/deriving.rs @@ -17,8 +17,8 @@ use syntax::print::pprust; use syntax::visit::{default_simple_visitor, mk_simple_visitor, visit_crate}; use middle::resolve::{Impl, MethodInfo}; use middle::ty; -use middle::ty::{DerivedFieldInfo, substs, ty_class, ty_enum}; -use middle::ty::{ty_param_bounds_and_ty}; +use middle::ty::{DerivedFieldInfo, ReVar, re_infer, re_static, substs}; +use middle::ty::{ty_class, ty_enum, ty_param_bounds_and_ty}; use /*middle::typeck::*/check::method; use /*middle::typeck::*/check::vtable; use /*middle::typeck::*/infer::infer_ctxt; @@ -56,10 +56,12 @@ impl DerivingChecker { let tcx = self.crate_context.tcx; let impl_self_tpbt = ty::lookup_item_type(tcx, impl_info.did); - let transformed_type = method::transform_self_type_for_method( - tcx, None, impl_self_tpbt.ty, method_info.self_type); let inference_context = infer::new_infer_ctxt(self.crate_context.tcx); + let region = inference_context.next_region_var_nb(span); + let transformed_type = method::transform_self_type_for_method( + tcx, Some(region), impl_self_tpbt.ty, method_info.self_type); + let substs = { self_r: None, self_ty: None, @@ -68,6 +70,13 @@ impl DerivingChecker { let transformed_type = ty::subst( self.crate_context.tcx, &substs, transformed_type); + // Automatically reference the substructure type. + let region = inference_context.next_region_var_nb(span); + let substructure_type = ty::mk_rptr( + self.crate_context.tcx, + region, + { ty: substructure_type, mutbl: ast::m_imm }); + debug!("(matching impl method) substructure type %s, transformed \ type %s, subst tps %u", ppaux::ty_to_str(self.crate_context.tcx, substructure_type), diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 0dd9ae7217f..2b92255bcc5 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -95,10 +95,10 @@ mod middle { mod ty; #[legacy_exports] mod resolve; - mod typeck { + pub mod typeck { #[legacy_exports]; - mod check { - #[legacy_exports]; + #[legacy_exports] + pub mod check { #[legacy_exports] mod alt; #[legacy_exports] @@ -112,7 +112,7 @@ mod middle { #[legacy_exports] mod demand; #[legacy_exports] - mod method; + pub mod method; } #[legacy_exports] mod rscope; diff --git a/src/test/compile-fail/enum-deriving-incomplete.rs b/src/test/compile-fail/enum-deriving-incomplete.rs index eb103a48df9..0d6d499842f 100644 --- a/src/test/compile-fail/enum-deriving-incomplete.rs +++ b/src/test/compile-fail/enum-deriving-incomplete.rs @@ -1,6 +1,6 @@ trait MyEq { #[derivable] - pure fn eq(other: &self) -> bool; + pure fn eq(&self, other: &self) -> bool; } struct A { diff --git a/src/test/compile-fail/missing-derivable-attr.rs b/src/test/compile-fail/missing-derivable-attr.rs index 140c915c57d..a28519e0a56 100644 --- a/src/test/compile-fail/missing-derivable-attr.rs +++ b/src/test/compile-fail/missing-derivable-attr.rs @@ -1,5 +1,5 @@ trait MyEq { - pure fn eq(other: &self) -> bool; + pure fn eq(&self, other: &self) -> bool; } struct A { @@ -7,7 +7,7 @@ struct A { } impl int : MyEq { - pure fn eq(other: &int) -> bool { self == *other } + pure fn eq(&self, other: &int) -> bool { *self == *other } } impl A : MyEq; //~ ERROR missing method diff --git a/src/test/run-pass/deriving-generic-bounded.rs b/src/test/run-pass/deriving-generic-bounded.rs index a45b7df3a2a..2dd27fdba67 100644 --- a/src/test/run-pass/deriving-generic-bounded.rs +++ b/src/test/run-pass/deriving-generic-bounded.rs @@ -1,20 +1,20 @@ trait MyEq { #[derivable] - pure fn eq(other: &self) -> bool; + pure fn eq(&self, other: &self) -> bool; } impl int : MyEq { - pure fn eq(other: &int) -> bool { - self == *other + pure fn eq(&self, other: &int) -> bool { + *self == *other } } impl @T : MyEq { - pure fn eq(other: &@T) -> bool { + pure fn eq(&self, other: &@T) -> bool { unsafe { io::println("@T"); } - (*self).eq(&**other) + (**self).eq(&**other) } } diff --git a/src/test/run-pass/deriving-one-method.rs b/src/test/run-pass/deriving-one-method.rs index 20fe5a35cd3..3a4e9db22c8 100644 --- a/src/test/run-pass/deriving-one-method.rs +++ b/src/test/run-pass/deriving-one-method.rs @@ -1,7 +1,7 @@ trait MyEq { #[derivable] - pure fn eq(other: &self) -> bool; - pure fn ne(other: &self) -> bool; + pure fn eq(&self, other: &self) -> bool; + pure fn ne(&self, other: &self) -> bool; } struct A { @@ -9,12 +9,12 @@ struct A { } impl int : MyEq { - pure fn eq(other: &int) -> bool { self == *other } - pure fn ne(other: &int) -> bool { self != *other } + pure fn eq(&self, other: &int) -> bool { *self == *other } + pure fn ne(&self, other: &int) -> bool { *self != *other } } impl A : MyEq { - pure fn ne(other: &A) -> bool { !self.eq(other) } + pure fn ne(&self, other: &A) -> bool { !self.eq(other) } } fn main() { diff --git a/src/test/run-pass/deriving-override.rs b/src/test/run-pass/deriving-override.rs index 5b030e4db18..ff6b4480259 100644 --- a/src/test/run-pass/deriving-override.rs +++ b/src/test/run-pass/deriving-override.rs @@ -1,8 +1,8 @@ trait MyEq { #[derivable] - pure fn eq(other: &self) -> bool; + pure fn eq(&self, other: &self) -> bool; #[derivable] - pure fn ne(other: &self) -> bool; + pure fn ne(&self, other: &self) -> bool; } struct A { @@ -10,12 +10,12 @@ struct A { } impl int : MyEq { - pure fn eq(other: &int) -> bool { self == *other } - pure fn ne(other: &int) -> bool { self != *other } + pure fn eq(&self, other: &int) -> bool { *self == *other } + pure fn ne(&self, other: &int) -> bool { *self != *other } } impl A : MyEq { - pure fn ne(other: &A) -> bool { !self.eq(other) } + pure fn ne(&self, other: &A) -> bool { !self.eq(other) } } fn main() { diff --git a/src/test/run-pass/deriving-param-pass-through.rs b/src/test/run-pass/deriving-param-pass-through.rs index 23c540d9044..35ec951d6e7 100644 --- a/src/test/run-pass/deriving-param-pass-through.rs +++ b/src/test/run-pass/deriving-param-pass-through.rs @@ -1,17 +1,17 @@ trait Trait { #[derivable] - fn f(x: int, y: &str); + fn f(&self, x: int, y: &str); } impl int : Trait { - fn f(x: int, y: &str) { + fn f(&self, x: int, y: &str) { assert x == 42; assert y == "hello"; } } impl float : Trait { - fn f(x: int, y: &str) { + fn f(&self, x: int, y: &str) { assert x == 42; assert y == "hello"; } diff --git a/src/test/run-pass/deriving-returning-nil.rs b/src/test/run-pass/deriving-returning-nil.rs index 385bb9a3b95..af0a5518967 100644 --- a/src/test/run-pass/deriving-returning-nil.rs +++ b/src/test/run-pass/deriving-returning-nil.rs @@ -1,10 +1,10 @@ trait Show { #[derivable] - fn show(); + fn show(&self); } impl int : Show { - fn show() { + fn show(&self) { io::println(self.to_str()); } } diff --git a/src/test/run-pass/deriving-simple.rs b/src/test/run-pass/deriving-simple.rs index 60c51a73ddb..35d3584bcae 100644 --- a/src/test/run-pass/deriving-simple.rs +++ b/src/test/run-pass/deriving-simple.rs @@ -1,6 +1,6 @@ trait MyEq { #[derivable] - pure fn eq(other: &self) -> bool; + pure fn eq(&self, other: &self) -> bool; } struct A { @@ -14,7 +14,7 @@ struct B { } impl A : MyEq { - pure fn eq(other: &A) -> bool { + pure fn eq(&self, other: &A) -> bool { unsafe { io::println(fmt!("eq %d %d", self.x, other.x)); } self.x == other.x } diff --git a/src/test/run-pass/enum-deriving-simple.rs b/src/test/run-pass/enum-deriving-simple.rs index b075f1b1c6a..a084b4cec4f 100644 --- a/src/test/run-pass/enum-deriving-simple.rs +++ b/src/test/run-pass/enum-deriving-simple.rs @@ -1,6 +1,6 @@ trait MyEq { #[derivable] - pure fn eq(other: &self) -> bool; + pure fn eq(&self, other: &self) -> bool; } struct A { @@ -14,7 +14,7 @@ enum B { } impl A : MyEq { - pure fn eq(other: &A) -> bool { + pure fn eq(&self, other: &A) -> bool { unsafe { io::println("in eq"); } self.x == other.x }