1
Fork 0

Remove old deriving

This commit is contained in:
Brian Anderson 2012-12-11 16:41:43 -08:00
parent 6439f2d546
commit a7159be24a
16 changed files with 17 additions and 1302 deletions

View file

@ -52,7 +52,6 @@ use util::ppaux;
use util::ppaux::{ty_to_str, ty_to_short_str};
use syntax::diagnostic::expect;
use util::common::indenter;
use ty::DerivedMethodInfo;
use build::*;
use shape::*;
@ -1878,10 +1877,6 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
}
}
ast::item_impl(tps, _, _, ms) => {
// This call will do nothing if there are no derivable methods.
deriving::trans_deriving_impl(ccx, *path, item.ident, tps,
item.id);
meth::trans_impl(ccx, *path, item.ident, ms, tps, None,
item.id);
}
@ -2112,20 +2107,7 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
match ccx.item_vals.find(id) {
Some(v) => v,
None => {
// First, check whether we need to automatically generate a method
// via the deriving mechanism.
match ccx.tcx.automatically_derived_methods.find(local_def(id)) {
None => {} // Continue.
Some(ref derived_method_info) => {
// XXX: Mark as internal if necessary.
let llfn = register_deriving_method(
ccx, id, derived_method_info);
ccx.item_vals.insert(id, llfn);
return llfn;
}
}
// Failing that, look for an item.
let mut exprt = false;
let val = match ccx.tcx.items.get(id) {
ast_map::node_item(i, pth) => {
@ -2273,34 +2255,6 @@ fn register_method(ccx: @crate_ctxt, id: ast::node_id, pth: @ast_map::path,
llfn
}
fn register_deriving_method(ccx: @crate_ctxt,
id: ast::node_id,
derived_method_info: &DerivedMethodInfo) ->
ValueRef {
// Find the path of the item.
let path, span;
match ccx.tcx.items.get(derived_method_info.containing_impl.node) {
ast_map::node_item(item, found_path) => {
path = found_path;
span = item.span;
}
_ => {
ccx.tcx.sess.bug(~"derived method info containing impl didn't \
refer to an item");
}
}
let path = vec::append(*path, ~[
ast_map::path_mod(
ccx.sess.parse_sess.interner.intern(@fmt!("__derived%d__", id))),
ast_map::path_name(derived_method_info.method_info.ident)
]);
let mty = ty::lookup_item_type(ccx.tcx, local_def(id)).ty;
let llfn = register_fn_full(ccx, span, path, id, mty);
// XXX: Inline hint.
llfn
}
// The constant translation pass.
fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
let _icx = ccx.insn_ctxt("trans_constant");

View file

@ -223,8 +223,6 @@ fn trans_fn_ref_with_vtables(
let must_monomorphise;
if type_params.len() > 0 || opt_impl_did.is_some() {
must_monomorphise = true;
} else if ccx.tcx.automatically_derived_methods.contains_key(def_id) {
must_monomorphise = false;
} else if def_id.crate == ast::local_crate {
let map_node = session::expect(
ccx.sess,

View file

@ -1,473 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Translation of automatically-derived trait implementations. This handles
// enums and structs only; other types cannot be automatically derived.
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;
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, 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};
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
UnitKind, // fn f(&self) -> ()
}
impl DerivingKind {
static fn of_item(ccx: @crate_ctxt, method_did: ast::def_id)
-> DerivingKind {
let item_type = ty::lookup_item_type(ccx.tcx, method_did).ty;
match ty::get(item_type).sty {
ty::ty_fn(ref f) => {
match ty::get(f.sig.output).sty {
ty::ty_bool => BoolKind,
ty::ty_nil => UnitKind,
_ => {
// FIXME (#3957): Report this earlier.
ccx.tcx.sess.fatal(~"attempt to automatically derive \
derive an implementation of a \
function returning something \
other than bool or ()");
}
}
}
_ => {
ccx.tcx.sess.bug(~"DerivingKind::of_item(): method def ID \
didn't have a function type");
}
}
}
}
/// The main "translation" pass for the automatically-derived methods in
/// an impl. Generates code for monomorphic methods only. Other methods will
/// be generated when they are invoked with specific type parameters; see
/// `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
pub fn trans_deriving_impl(ccx: @crate_ctxt,
_path: path,
_name: ident,
tps: ~[ty_param],
id: node_id) {
let _icx = ccx.insn_ctxt("deriving::trans_deriving_impl");
if tps.len() > 0 { return; }
let impl_def_id = local_def(id);
let self_ty = ty::lookup_item_type(ccx.tcx, impl_def_id);
match ccx.tcx.automatically_derived_methods_for_impl.find(impl_def_id) {
Some(copy method_dids) => {
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_struct(*) => {
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,
transformed_self_ty,
kind);
}
_ => {
ccx.tcx.sess.bug(~"translation of non-struct \
deriving method");
}
}
}
}
None => {} // Nothing to do.
}
}
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);
let top_bcx = top_scope_block(fcx, None);
let lltop = top_bcx.llbb;
let mut bcx = top_bcx;
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(LLVMGetParam(llfn, 2)),
UnitKind => llotherval_opt = None
}
let struct_field_tys;
match ty::get(self_ty).sty {
ty::ty_struct(struct_id, ref struct_substs) => {
struct_field_tys = ty::struct_fields(
ccx.tcx, struct_id, struct_substs);
}
_ => {
ccx.tcx.sess.bug(~"passed non-struct to \
trans_deriving_struct_method");
}
}
// Iterate over every element of the struct.
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,
llselfalloca,
llotherval_opt,
llextraparams);
// If this derived method is of boolean kind, return immediately if
// the call to the substructure method returned false.
match kind {
BoolKind => {
let next_block = sub_block(top_bcx, ~"next");
let llcond = Load(bcx, fcx.llretptr);
CondBr(bcx, llcond, next_block.llbb, fcx.llreturn);
bcx = next_block;
}
UnitKind => {} // Unconditionally continue.
}
}
// Store true if necessary.
match kind {
BoolKind => Store(bcx, C_bool(true), fcx.llretptr),
UnitKind => {}
}
Br(bcx, fcx.llreturn);
finish_fn(fcx, lltop);
}
// This could have been combined with trans_deriving_struct_method, but it
// would probably be too big and hard to understand.
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);
let top_bcx = top_scope_block(fcx, None);
let lltop = top_bcx.llbb;
let mut bcx = top_bcx;
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(LLVMGetParam(llfn, 2))
}
let enum_id, enum_substs, enum_variant_infos;
match ty::get(self_ty).sty {
ty::ty_enum(found_enum_id, ref found_enum_substs) => {
enum_id = found_enum_id;
enum_substs = copy *found_enum_substs;
enum_variant_infos = ty::substd_enum_variants(
ccx.tcx, enum_id, &enum_substs);
}
_ => {
ccx.tcx.sess.bug(~"passed non-enum to \
trans_deriving_enum_method");
}
}
// Create the "no match" basic block, if necessary. This is a basic block
// that does nothing more than return false.
let nomatch_bcx_opt;
match kind {
BoolKind => {
let nomatch_bcx = sub_block(top_bcx, ~"no_match");
Store(nomatch_bcx, C_bool(false), fcx.llretptr);
Br(nomatch_bcx, fcx.llreturn);
nomatch_bcx_opt = Some(nomatch_bcx);
}
UnitKind => nomatch_bcx_opt = None
}
// Create the "unreachable" basic block.
let unreachable_bcx = sub_block(top_bcx, ~"unreachable");
Unreachable(unreachable_bcx);
// Get the deriving enum method info.
let deriving_enum_methods = ccx.tcx.deriving_enum_methods.get(impl_did);
let n_variants = deriving_enum_methods.len();
if n_variants != 1 {
// Grab the two discriminants.
let llselfdiscrim = Load(bcx, GEPi(bcx, llselfval, [0, 0]));
let llotherdiscrim_opt = llotherval_opt.map(
|llotherval| Load(bcx, GEPi(bcx, *llotherval, [0, 0])));
// Skip over the discriminants and compute the address of the payload.
let llselfpayload = GEPi(bcx, llselfval, [0, 1]);
let llotherpayload_opt = llotherval_opt.map(
|llotherval| GEPi(bcx, *llotherval, [0, 1]));
// Create basic blocks for the outer switch.
let outer_bcxs = vec::from_fn(
deriving_enum_methods.len(),
|i| sub_block(top_bcx, fmt!("outer_%u", i)));
// For each basic block in the outer switch...
for outer_bcxs.eachi |self_variant_index, bcx| {
// Create the matching basic block for the inner switch.
let top_match_bcx = sub_block(top_bcx, fmt!("maybe_match_%u",
self_variant_index));
let mut match_bcx = top_match_bcx;
// Compare each variant.
for deriving_enum_methods[self_variant_index].eachi
|i, derived_method_info| {
let variant_def_id =
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,
variant_def_id, enum_substs.tps, i));
let self_ty = enum_variant_infos[self_variant_index].args[i];
match_bcx = call_substructure_method(match_bcx,
derived_method_info,
self_ty,
llselfalloca,
llotherval_opt,
llextraparams);
// If this is a boolean-kind deriving method, then return
// immediately if the call to the substructure returned false.
match kind {
BoolKind => {
let next_bcx = sub_block(top_bcx,
fmt!("next_%u_%u",
self_variant_index,
i));
let llcond = Load(match_bcx, fcx.llretptr);
CondBr(match_bcx,
llcond,
next_bcx.llbb,
fcx.llreturn);
match_bcx = next_bcx;
}
UnitKind => {}
}
}
// Store true in the return pointer if this is a boolean-kind
// deriving method.
match kind {
BoolKind => Store(match_bcx, C_bool(true), fcx.llretptr),
UnitKind => {}
}
// Finish up the matching block.
Br(match_bcx, fcx.llreturn);
// If this is a boolean-kind derived method, build the inner
// switch. Otherwise, just jump to the matching case.
match llotherdiscrim_opt {
None => Br(*bcx, top_match_bcx.llbb),
Some(copy llotherdiscrim) => {
let llswitch = Switch(*bcx,
llotherdiscrim,
unreachable_bcx.llbb,
n_variants);
for uint::range(0, n_variants) |other_variant_index| {
let discriminant =
enum_variant_infos[other_variant_index].disr_val;
if self_variant_index == other_variant_index {
// This is the potentially-matching case.
AddCase(llswitch,
C_int(ccx, discriminant),
top_match_bcx.llbb);
} else {
// This is always a non-matching case.
AddCase(llswitch,
C_int(ccx, discriminant),
nomatch_bcx_opt.get().llbb);
}
}
}
}
}
// Now build the outer switch.
let llswitch = Switch(top_bcx, llselfdiscrim, unreachable_bcx.llbb,
n_variants);
for outer_bcxs.eachi |self_variant_index, outer_bcx| {
let discriminant =
enum_variant_infos[self_variant_index].disr_val;
AddCase(llswitch, C_int(ccx, discriminant), outer_bcx.llbb);
}
} else {
ccx.tcx.sess.unimpl(~"degenerate enum deriving");
}
// Finish up the function.
finish_fn(fcx, lltop);
}
fn call_substructure_method(bcx: block,
derived_field_info: &DerivedFieldInfo,
self_ty: ty::t,
llselfval: ValueRef,
llotherval_opt: Option<ValueRef>,
llextraparams: &[ValueRef]) -> block {
let fcx = bcx.fcx;
let ccx = fcx.ccx;
let target_method_def_id;
match derived_field_info.method_origin {
method_static(did) => target_method_def_id = did,
_ => fail ~"derived method didn't resolve to a static method"
}
let fn_expr_tpbt = ty::lookup_item_type(ccx.tcx, target_method_def_id);
debug!("(calling substructure method) substructure method has %u \
parameter(s), vtable result is %?",
fn_expr_tpbt.bounds.len(),
derived_field_info.vtable_result);
// Get the substructure method we need to call. This may involve
// code generation in the case of generics, default methods, or cross-
// crate inlining.
let fn_data = callee::trans_fn_ref_with_vtables(bcx,
target_method_def_id,
0, // ref id
*derived_field_info.
type_parameter_substitutions,
derived_field_info.
vtable_result);
let llfn = fn_data.llfn;
// Create the callee.
let cb: &fn(block) -> Callee = |bloc| {
Callee {
bcx: bloc,
data: Method(MethodData {
llfn: llfn,
llself: llselfval,
self_ty: self_ty,
self_mode: ast::by_copy
})
}
};
// 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,
ArgVals(dvec::unwrap(move llargvals)),
SaveIn(fcx.llretptr),
DontAutorefArg)
}

View file

@ -213,8 +213,6 @@ export opt_region_variance;
export determine_inherited_purity;
export provided_trait_methods;
export trait_supertraits;
export DerivedMethodInfo;
export DerivedFieldInfo;
export AutoAdjustment;
export AutoRef;
export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn;
@ -383,17 +381,6 @@ struct InstantiatedTraitRef {
tpt: ty_param_substs_and_ty
}
struct DerivedMethodInfo {
method_info: @middle::resolve::MethodInfo,
containing_impl: ast::def_id
}
struct DerivedFieldInfo {
method_origin: typeck::method_origin,
type_parameter_substitutions: @~[ty::t],
vtable_result: Option<typeck::vtable_res>
}
type ctxt =
@{diag: syntax::diagnostic::span_handler,
interner: HashMap<intern_key, t_box>,
@ -443,20 +430,6 @@ type ctxt =
provided_methods: ProvidedMethodsMap,
provided_method_sources: HashMap<ast::def_id, ProvidedMethodSource>,
supertraits: HashMap<ast::def_id, @~[InstantiatedTraitRef]>,
deriving_struct_methods: HashMap<ast::def_id, @~[DerivedFieldInfo]>,
// The outer vector here describes each enum variant, while the inner
// nested vector describes each enum variant argument.
deriving_enum_methods: HashMap<ast::def_id, @~[@~[DerivedFieldInfo]]>,
// A mapping from the def ID of a method that was automatically derived
// to information about it.
automatically_derived_methods: HashMap<ast::def_id, DerivedMethodInfo>,
// A mapping from the def ID of an impl to the IDs of the derived
// methods within it.
automatically_derived_methods_for_impl:
HashMap<ast::def_id, @~[ast::def_id]>,
// 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
@ -1003,10 +976,6 @@ fn mk_ctxt(s: session::Session,
provided_methods: HashMap(),
provided_method_sources: HashMap(),
supertraits: HashMap(),
deriving_struct_methods: HashMap(),
deriving_enum_methods: HashMap(),
automatically_derived_methods: HashMap(),
automatically_derived_methods_for_impl: HashMap(),
destructor_for_type: HashMap(),
destructors: HashMap(),
value_modes: HashMap()}

View file

@ -19,7 +19,7 @@ use metadata::csearch::{get_impls_for_mod};
use metadata::cstore::{CStore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo};
use middle::ty::{DerivedMethodInfo, ProvidedMethodSource,
use middle::ty::{ProvidedMethodSource,
ProvidedMethodInfo, get};
use middle::ty::{lookup_item_type, subst, t, ty_bot, ty_box, ty_struct};
use middle::ty::{ty_bool, ty_enum, ty_int, ty_nil, ty_ptr, ty_rptr, ty_uint};
@ -598,105 +598,31 @@ impl CoherenceChecker {
return trait_id;
}
/// Returns true if the method has been marked with the #[derivable]
/// attribute and false otherwise.
fn method_is_derivable(method_def_id: ast::def_id) -> bool {
if method_def_id.crate == local_crate {
match self.crate_context.tcx.items.find(method_def_id.node) {
Some(ast_map::node_trait_method(trait_method, _, _)) => {
match *trait_method {
ast::required(ref ty_method) => {
attr::attrs_contains_name((*ty_method).attrs,
~"derivable")
}
ast::provided(method) => {
attr::attrs_contains_name(method.attrs,
~"derivable")
}
}
}
_ => {
self.crate_context.tcx.sess.bug(~"method_is_derivable(): \
def ID passed in \
wasn't a trait method")
}
}
} else {
false // XXX: Unimplemented.
}
}
// This check doesn't really have anything to do with coherence. It's
// here for historical reasons
fn please_check_that_trait_methods_are_implemented(
all_methods: &mut ~[@MethodInfo],
trait_did: def_id,
trait_ref_span: span) {
fn add_automatically_derived_methods_from_trait(
all_methods: &mut ~[@MethodInfo],
trait_did: def_id,
self_ty: ty::t,
impl_did: def_id,
trait_ref_span: span) {
let tcx = self.crate_context.tcx;
// Make a set of all the method names that this implementation and
// trait provided so that we don't try to automatically derive
// implementations for them.
let mut provided_names = send_map::linear::LinearMap();
// Implemented methods
for uint::range(0, all_methods.len()) |i| {
provided_names.insert(all_methods[i].ident, ());
}
// Default methods
for ty::provided_trait_methods(tcx, trait_did).each |ident| {
provided_names.insert(*ident, ());
}
let new_method_dids = dvec::DVec();
for (*ty::trait_methods(tcx, trait_did)).each |method| {
// Check to see whether we need to derive this method. We need to
// derive a method only if and only if neither the trait nor the
// implementation we're considering provided a body.
if provided_names.contains_key(&method.ident) { loop; }
if !self.method_is_derivable(method.def_id) {
tcx.sess.span_err(trait_ref_span,
fmt!("missing method `%s`",
tcx.sess.str_of(method.ident)));
loop;
}
// Generate a def ID for each node.
let new_def_id = local_def(tcx.sess.next_node_id());
let method_info = @{
did: new_def_id,
n_tps: method.tps.len(),
ident: method.ident,
self_type: method.self_ty
};
all_methods.push(method_info);
// Note that this method was automatically derived so that trans
// can handle it differently.
let derived_method_info = DerivedMethodInfo {
method_info: method_info,
containing_impl: impl_did
};
tcx.automatically_derived_methods.insert(new_def_id,
derived_method_info);
new_method_dids.push(new_def_id);
// Additionally, generate the type for the derived method and add
// it to the type cache.
//
// XXX: Handle generics correctly.
let substs = { self_r: None, self_ty: Some(self_ty), tps: ~[] };
tcx.tcache.insert(new_def_id, {
bounds: @~[],
region_param: None,
ty: ty::subst(tcx, &substs, ty::mk_fn(tcx, method.fty))
});
}
let new_method_dids = @dvec::unwrap(move new_method_dids);
if new_method_dids.len() > 0 {
tcx.automatically_derived_methods_for_impl.insert(
impl_did, new_method_dids);
tcx.sess.span_err(trait_ref_span,
fmt!("missing method `%s`",
tcx.sess.str_of(method.ident)));
}
}
@ -720,19 +646,14 @@ impl CoherenceChecker {
methods.push(method_to_MethodInfo(*ast_method));
}
// Now search for methods that need to be automatically
// derived.
let tcx = self.crate_context.tcx;
let self_ty = ty::lookup_item_type(tcx, local_def(item.id));
// Check that we have implementations of every trait method
for trait_refs.each |trait_ref| {
let trait_did =
self.trait_ref_to_trait_def_id(*trait_ref);
self.add_automatically_derived_methods_from_trait(
&mut methods,
trait_did,
self_ty.ty,
local_def(item.id),
trait_ref.path.span);
self.please_check_that_trait_methods_are_implemented(
&mut methods,
trait_did,
trait_ref.path.span);
}
// For each trait that the impl implements, see which

View file

@ -1,322 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Deriving phase
//
// The purpose of the deriving phase of typechecking is to ensure that, for
// each automatically derived implementation of an automatically-derivable
// trait (for example, Eq), all the subcomponents of the type in question
// also implement the trait. This phase runs after coherence.
use syntax::ast::crate;
use syntax::ast::{def_id, ident};
use syntax::ast::item_impl;
use syntax::ast::node_id;
use syntax::ast::self_ty_;
use syntax::ast::trait_ref;
use syntax::ast_util::{def_id_of_def, dummy_sp};
use syntax::codemap::span;
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, ReVar, re_infer, re_static, substs};
use middle::ty::{ty_struct, ty_enum, ty_param_bounds_and_ty};
use /*middle::typeck::*/check::method;
use /*middle::typeck::*/check::vtable;
use /*middle::typeck::*/infer::infer_ctxt;
use /*middle::typeck::*/vtable::{LocationInfo, VtableContext};
use util::ppaux;
struct MethodMatch {
method_def_id: def_id,
type_parameter_substitutions: @~[ty::t],
vtable_result: Option<vtable_res>
}
struct DerivingChecker {
crate_context: @crate_ctxt
}
fn DerivingChecker_new(crate_context: @crate_ctxt) -> DerivingChecker {
DerivingChecker {
crate_context: crate_context,
}
}
struct TyParamSubstsAndVtableResult {
type_parameter_substitutions: @~[ty::t],
vtable_result: Option<vtable_res>
}
impl DerivingChecker {
/// Matches one substructure type against an implementation.
fn match_impl_method(impl_info: @Impl,
substructure_type: ty::t,
method_info: @MethodInfo,
span: span) ->
Option<TyParamSubstsAndVtableResult> {
let tcx = self.crate_context.tcx;
let impl_self_tpbt = ty::lookup_item_type(tcx, impl_info.did);
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,
tps: inference_context.next_ty_vars(impl_self_tpbt.bounds.len())
};
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),
ppaux::ty_to_str(self.crate_context.tcx, transformed_type),
substs.tps.len());
if !infer::mk_subty(inference_context,
true,
ast_util::dummy_sp(),
substructure_type,
transformed_type).is_ok() {
return None;
}
// Get the vtables.
let vtable_result;
if substs.tps.len() == 0 {
vtable_result = None;
} else {
let vcx = VtableContext {
ccx: self.crate_context,
infcx: inference_context
};
let location_info = LocationInfo {
span: span,
id: impl_info.did.node
};
vtable_result = Some(vtable::lookup_vtables(&vcx,
&location_info,
impl_self_tpbt.bounds,
&substs,
false,
false));
}
// Extract the type parameter substitutions.
let type_parameter_substitutions = @substs.tps.map(|ty_var|
inference_context.resolve_type_vars_if_possible(*ty_var));
Some(TyParamSubstsAndVtableResult {
type_parameter_substitutions: type_parameter_substitutions,
vtable_result: vtable_result
})
}
fn check_deriving_for_substructure_type(substructure_type: ty::t,
trait_ref: @trait_ref,
impl_span: span) ->
Option<MethodMatch> {
let tcx = self.crate_context.tcx;
let sess = tcx.sess;
let coherence_info = self.crate_context.coherence_info;
let trait_id = def_id_of_def(tcx.def_map.get(trait_ref.ref_id));
match coherence_info.extension_methods.find(trait_id) {
None => {
sess.span_bug(impl_span, ~"no extension method info found \
for this trait");
}
Some(impls) => {
// Try to unify each of these impls with the substructure
// type.
//
// NB: Using range to avoid a recursive-use-of-dvec error.
for uint::range(0, impls.len()) |i| {
let impl_info = impls[i];
for uint::range(0, impl_info.methods.len()) |j| {
let method_info = impl_info.methods[j];
match self.match_impl_method(impl_info,
substructure_type,
method_info,
trait_ref.path.span) {
Some(move result) => {
return Some(MethodMatch {
method_def_id: method_info.did,
type_parameter_substitutions:
result.type_parameter_substitutions,
vtable_result: result.vtable_result
});
}
None => {} // Continue.
}
}
}
}
}
return None;
}
fn check_deriving_for_struct(struct_def_id: def_id,
struct_substs: &substs,
trait_ref: @trait_ref,
impl_id: node_id,
impl_span: span) {
let tcx = self.crate_context.tcx;
let field_info = dvec::DVec();
for ty::lookup_struct_fields(tcx, struct_def_id).each |field| {
let field_type = ty::lookup_field_type(
tcx, struct_def_id, field.id, struct_substs);
match self.check_deriving_for_substructure_type(field_type,
trait_ref,
impl_span) {
Some(method_match) => {
field_info.push(DerivedFieldInfo {
method_origin:
method_static(method_match.method_def_id),
type_parameter_substitutions:
method_match.type_parameter_substitutions,
vtable_result:
method_match.vtable_result
});
}
None => {
let trait_str = pprust::path_to_str(
trait_ref.path, tcx.sess.parse_sess.interner);
tcx.sess.span_err(impl_span,
fmt!("cannot automatically derive an \
implementation for `%s`: field \
`%s` does not implement the \
trait `%s`",
trait_str,
tcx.sess.str_of(field.ident),
trait_str));
}
}
}
let field_info = @dvec::unwrap(move field_info);
tcx.deriving_struct_methods.insert(local_def(impl_id), field_info);
}
fn check_deriving_for_enum(enum_def_id: def_id,
enum_substs: &substs,
trait_ref: @trait_ref,
impl_id: node_id,
impl_span: span) {
let tcx = self.crate_context.tcx;
let enum_methods = dvec::DVec();
let variants = ty::substd_enum_variants(
tcx, enum_def_id, enum_substs);
for variants.each |enum_variant_info| {
let variant_methods = dvec::DVec();
for enum_variant_info.args.eachi |i, variant_arg_type| {
match self.check_deriving_for_substructure_type(
*variant_arg_type, trait_ref, impl_span) {
Some(method_match) => {
variant_methods.push(DerivedFieldInfo {
method_origin:
method_static(method_match.method_def_id),
type_parameter_substitutions:
method_match.type_parameter_substitutions,
vtable_result:
method_match.vtable_result
});
}
None => {
let trait_str = pprust::path_to_str(
trait_ref.path, tcx.sess.parse_sess.interner);
tcx.sess.span_err(impl_span,
fmt!("cannot automatically derive \
an implementation for `%s`: \
argument %u of variant `%s` \
does not implement the trait \
`%s`",
trait_str,
i + 1,
tcx.sess.str_of(
enum_variant_info.name),
trait_str));
}
}
}
enum_methods.push(@dvec::unwrap(move variant_methods));
}
let enum_methods = @dvec::unwrap(move enum_methods);
tcx.deriving_enum_methods.insert(local_def(impl_id), enum_methods);
}
fn check_deriving(crate: @crate) {
let tcx = self.crate_context.tcx;
visit_crate(*crate, (), mk_simple_visitor(@{
visit_item: |item| {
match item.node {
item_impl(_, Some(trait_ref), _, _) => {
// Determine whether there were any automatically-
// derived methods in this implementation.
let impl_did = local_def(item.id);
if tcx.automatically_derived_methods_for_impl.
contains_key(impl_did) {
// XXX: This does not handle generic impls.
let superty = ty::lookup_item_type(
tcx, local_def(item.id)).ty;
match ty::get(superty).sty {
ty_enum(def_id, ref substs) => {
self.check_deriving_for_enum(
def_id,
substs,
trait_ref,
item.id,
item.span);
}
ty_struct(def_id, ref substs) => {
self.check_deriving_for_struct(
def_id,
substs,
trait_ref,
item.id,
item.span);
}
_ => {
tcx.sess.span_err(item.span,
~"only enums and \
structs may have \
implementations \
automatically \
derived for them");
}
}
}
}
_ => {}
}
},
..*default_simple_visitor()
}));
}
}
pub fn check_deriving(crate_context: @crate_ctxt, crate: @crate) {
let deriving_checker = @DerivingChecker_new(crate_context);
deriving_checker.check_deriving(crate);
}

View file

@ -103,7 +103,6 @@ mod infer;
mod collect;
#[legacy_exports]
mod coherence;
mod deriving;
#[auto_serialize]
#[auto_deserialize]
@ -391,7 +390,6 @@ fn check_crate(tcx: ty::ctxt,
});
collect::collect_item_types(ccx, crate);
coherence::check_coherence(ccx, crate);
deriving::check_deriving(ccx, crate);
check::check_item_types(ccx, crate);
check_for_main_fn(ccx);

View file

@ -123,8 +123,6 @@ mod middle {
mod reachable;
#[path = "middle/trans/machine.rs"]
mod machine;
#[path = "middle/trans/deriving.rs"]
mod deriving;
}
#[legacy_exports]
#[path = "middle/ty.rs"]

View file

@ -1,35 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait MyEq {
#[derivable]
pure fn eq(&self, other: &self) -> bool;
}
struct A {
x: int
}
enum B {
C(A),
D(A),
E(A)
}
impl B : MyEq;
//~^ ERROR cannot automatically derive
//~^^ ERROR cannot automatically derive
//~^^^ ERROR cannot automatically derive
fn main() {
let c = C(A { x: 15 });
assert c.eq(&c);
}

View file

@ -1,44 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait MyEq {
#[derivable]
pure fn eq(&self, other: &self) -> bool;
}
impl int : MyEq {
pure fn eq(&self, other: &int) -> bool {
*self == *other
}
}
impl<T:MyEq> @T : MyEq {
pure fn eq(&self, other: &@T) -> bool {
unsafe {
io::println("@T");
}
(**self).eq(&**other)
}
}
struct A {
x: @int,
y: @int
}
impl A : MyEq;
fn main() {
let a = A { x: @3, y: @5 };
let b = A { x: @10, y: @20 };
assert a.eq(&a);
assert !a.eq(&b);
}

View file

@ -1,35 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait MyEq {
#[derivable]
pure fn eq(&self, other: &self) -> bool;
pure fn ne(&self, other: &self) -> bool;
}
struct A {
x: int
}
impl int : MyEq {
pure fn eq(&self, other: &int) -> bool { *self == *other }
pure fn ne(&self, other: &int) -> bool { *self != *other }
}
impl A : MyEq {
pure fn ne(&self, other: &A) -> bool { !self.eq(other) }
}
fn main() {
let a = A { x: 1 };
assert a.eq(&a);
assert !a.ne(&a);
}

View file

@ -1,36 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait MyEq {
#[derivable]
pure fn eq(&self, other: &self) -> bool;
#[derivable]
pure fn ne(&self, other: &self) -> bool;
}
struct A {
x: int
}
impl int : MyEq {
pure fn eq(&self, other: &int) -> bool { *self == *other }
pure fn ne(&self, other: &int) -> bool { *self != *other }
}
impl A : MyEq {
pure fn ne(&self, other: &A) -> bool { !self.eq(other) }
}
fn main() {
let a = A { x: 1 };
assert a.eq(&a);
assert !a.ne(&a);
}

View file

@ -1,41 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
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");
}

View file

@ -1,51 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait Show {
#[derivable]
fn show(&self);
}
impl int : Show {
fn show(&self) {
io::println(self.to_str());
}
}
struct Foo {
x: int,
y: int,
z: int,
}
impl Foo : Show;
enum Bar {
Baz(int, int),
Boo(Foo),
}
impl Bar : Show;
fn main() {
let foo = Foo { x: 1, y: 2, z: 3 };
foo.show();
io::println("---");
let baz = Baz(4, 5);
baz.show();
io::println("---");
let boo = Boo(Foo { x: 6, y: 7, z: 8 });
boo.show();
}

View file

@ -1,43 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait MyEq {
#[derivable]
pure fn eq(&self, other: &self) -> bool;
}
struct A {
x: int
}
struct B {
x: A,
y: A,
z: A
}
impl A : MyEq {
pure fn eq(&self, other: &A) -> bool {
unsafe { io::println(fmt!("eq %d %d", self.x, other.x)); }
self.x == other.x
}
}
impl B : MyEq;
fn main() {
let b = B { x: A { x: 1 }, y: A { x: 2 }, z: A { x: 3 } };
let c = B { x: A { x: 1 }, y: A { x: 3 }, z: A { x: 4 } };
assert b.eq(&b);
assert c.eq(&c);
assert !b.eq(&c);
assert !c.eq(&b);
}

View file

@ -1,43 +0,0 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait MyEq {
#[derivable]
pure fn eq(&self, other: &self) -> bool;
}
struct A {
x: int
}
enum B {
C(A),
D(A),
E(A)
}
impl A : MyEq {
pure fn eq(&self, other: &A) -> bool {
unsafe { io::println("in eq"); }
self.x == other.x
}
}
impl B : MyEq;
fn main() {
let c = C(A { x: 15 });
let d = D(A { x: 30 });
let e = C(A { x: 30 });
assert c.eq(&c);
assert !c.eq(&d);
assert !c.eq(&e);
}