diff --git a/src/librustc/middle/trans/deriving.rs b/src/librustc/middle/trans/deriving.rs index 7fe4a0b0e4620..8fc81101faf05 100644 --- a/src/librustc/middle/trans/deriving.rs +++ b/src/librustc/middle/trans/deriving.rs @@ -1,9 +1,10 @@ // Translation of automatically-derived trait implementations. This handles // enums and structs only; other types cannot be automatically derived. -use lib::llvm::llvm; +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; @@ -11,9 +12,11 @@ use middle::trans::callee::{ArgVals, Callee, DontAutorefArg, Method}; use middle::trans::callee::{MethodData}; use middle::trans::common; 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}; @@ -21,6 +24,10 @@ use syntax::ast_map::path; use syntax::ast_util; use syntax::ast_util::local_def; +use core::dvec::DVec; +use core::dvec; +use core::libc::c_uint; + /// The kind of deriving method this is. enum DerivingKind { BoolKind, // fn f(&self, other: &other) -> bool @@ -73,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 \ @@ -93,10 +119,28 @@ pub fn trans_deriving_impl(ccx: @crate_ctxt, } } +fn get_extra_params(llfn: ValueRef, kind: DerivingKind) -> ~[ValueRef] { + let n_params = LLVMCountParams(llfn) as uint; + + let initial_extra_param; + match kind { + BoolKind => initial_extra_param = 3, + UnitKind => initial_extra_param = 2, + } + + let extra_params = DVec(); + for uint::range(initial_extra_param, n_params) |i| { + extra_params.push(LLVMGetParam(llfn, i as c_uint)); + } + + return dvec::unwrap(move extra_params); +} + 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); @@ -104,14 +148,18 @@ fn trans_deriving_struct_method(ccx: @crate_ctxt, let lltop = top_bcx.llbb; let mut bcx = top_bcx; - let llselfty = type_of(ccx, self_ty); - let llselfval = PointerCast(bcx, fcx.llenv, T_ptr(llselfty)); + let llextraparams = get_extra_params(llfn, kind); + + 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. let llotherval_opt; match kind { - BoolKind => llotherval_opt = Some(llvm::LLVMGetParam(llfn, 2)), + BoolKind => llotherval_opt = Some(LLVMGetParam(llfn, 2)), UnitKind => llotherval_opt = None } @@ -131,13 +179,20 @@ 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])); let self_ty = struct_field_tys[i].mt.ty; - bcx = call_substructure_method(bcx, derived_method_info, self_ty, - llselfval, llotherval_opt); + bcx = call_substructure_method(bcx, + derived_method_info, + self_ty, + llselfalloca, + llotherval_opt, + llextraparams); // If this derived method is of boolean kind, return immediately if // the call to the substructure method returned false. @@ -169,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); @@ -176,13 +232,17 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, let lltop = top_bcx.llbb; let mut bcx = top_bcx; - let llselfty = type_of(ccx, self_ty); - let llselfval = PointerCast(bcx, fcx.llenv, T_ptr(llselfty)); + let llextraparams = get_extra_params(llfn, kind); + + 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 { UnitKind => llotherval_opt = None, - BoolKind => llotherval_opt = Some(llvm::LLVMGetParam(llfn, 2)) + BoolKind => llotherval_opt = Some(LLVMGetParam(llfn, 2)) } let enum_id, enum_substs, enum_variant_infos; @@ -250,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, @@ -259,8 +322,9 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, match_bcx = call_substructure_method(match_bcx, derived_method_info, self_ty, - llselfval, - llotherval_opt); + llselfalloca, + llotherval_opt, + llextraparams); // If this is a boolean-kind deriving method, then return // immediately if the call to the substructure returned false. @@ -339,7 +403,8 @@ fn call_substructure_method(bcx: block, derived_field_info: &DerivedFieldInfo, self_ty: ty::t, llselfval: ValueRef, - llotherval_opt: Option) -> block { + llotherval_opt: Option, + llextraparams: &[ValueRef]) -> block { let fcx = bcx.fcx; let ccx = fcx.ccx; @@ -367,6 +432,7 @@ fn call_substructure_method(bcx: block, vtable_result); let llfn = fn_data.llfn; + // Create the callee. let cb: &fn(block) -> Callee = |bloc| { Callee { bcx: bloc, @@ -379,18 +445,18 @@ fn call_substructure_method(bcx: block, } }; - let arg_values; - match llotherval_opt { - None => arg_values = ArgVals(~[]), - Some(copy llotherval) => arg_values = ArgVals(~[llotherval]) - } + // Build up the argument list. + let llargvals = DVec(); + for llotherval_opt.each |llotherval| { llargvals.push(*llotherval); } + for llextraparams.each |llextraparam| { llargvals.push(*llextraparam); } + // And perform the call. callee::trans_call_inner(bcx, None, fn_expr_tpbt.ty, ty::mk_bool(ccx.tcx), cb, - move arg_values, + ArgVals(dvec::unwrap(move llargvals)), SaveIn(fcx.llretptr), DontAutorefArg) } diff --git a/src/librustc/middle/typeck.rs b/src/librustc/middle/typeck.rs index d4df07f7eb897..977fc06ce8659 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 197a06a1d972e..010ca242c7dce 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 0dd9ae7217f47..2b92255bcc561 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 eb103a48df967..0d6d499842f87 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 140c915c57dbb..a28519e0a56d2 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 a45b7df3a2afe..2dd27fdba675a 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 20fe5a35cd3ed..3a4e9db22c84b 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 5b030e4db18af..ff6b4480259dd 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 new file mode 100644 index 0000000000000..35ec951d6e7dd --- /dev/null +++ b/src/test/run-pass/deriving-param-pass-through.rs @@ -0,0 +1,31 @@ +trait Trait { + #[derivable] + fn f(&self, x: int, y: &str); +} + +impl int : Trait { + fn f(&self, x: int, y: &str) { + assert x == 42; + assert y == "hello"; + } +} + +impl float : Trait { + fn f(&self, x: int, y: &str) { + assert x == 42; + assert y == "hello"; + } +} + +struct Foo { + x: int, + y: float +} + +impl Foo : Trait; + +fn main() { + let a: Foo = Foo { x: 1, y: 2.0 }; + a.f(42, "hello"); +} + diff --git a/src/test/run-pass/deriving-returning-nil.rs b/src/test/run-pass/deriving-returning-nil.rs index 385bb9a3b95db..af0a5518967e7 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 60c51a73ddb94..35d3584bcae66 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 b075f1b1c6ad4..a084b4cec4fbb 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 }