Remove old deriving
This commit is contained in:
parent
6439f2d546
commit
a7159be24a
16 changed files with 17 additions and 1302 deletions
|
@ -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");
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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()}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue