for m in ms.iter() {
check_method_body(ccx, &impl_tpt.generics, None, *m);
}
- vtable::resolve_impl(ccx, it);
+
+ match *opt_trait_ref {
+ Some(ref ast_trait_ref) => {
+ let impl_trait_ref =
+ ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
+ check_impl_methods_against_trait(ccx,
+ it.span,
+ &impl_tpt.generics,
+ ast_trait_ref,
+ impl_trait_ref,
+ *ms);
+ vtable::resolve_impl(ccx, it, &impl_tpt.generics,
+ impl_trait_ref);
+ }
+ None => { }
+ }
+
}
ast::item_trait(_, _, ref trait_methods) => {
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
param_env);
}
+fn check_impl_methods_against_trait(ccx: @mut CrateCtxt,
+ impl_span: Span,
+ impl_generics: &ty::Generics,
+ ast_trait_ref: &ast::trait_ref,
+ impl_trait_ref: &ty::TraitRef,
+ impl_methods: &[@ast::method]) {
+ // Locate trait methods
+ let tcx = ccx.tcx;
+ let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
+
+ // Check existing impl methods to see if they are both present in trait
+ // and compatible with trait signature
+ for impl_method in impl_methods.iter() {
+ let impl_method_def_id = local_def(impl_method.id);
+ let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
+
+ // If this is an impl of a trait method, find the corresponding
+ // method definition in the trait.
+ let opt_trait_method_ty =
+ trait_methods.iter().
+ find(|tm| tm.ident.name == impl_method_ty.ident.name);
+ match opt_trait_method_ty {
+ Some(trait_method_ty) => {
+ compare_impl_method(ccx.tcx,
+ impl_generics,
+ impl_method_ty,
+ impl_method.span,
+ impl_method.body.id,
+ *trait_method_ty,
+ &impl_trait_ref.substs);
+ }
+ None => {
+ tcx.sess.span_err(
+ impl_method.span,
+ format!("method `{}` is not a member of trait `{}`",
+ tcx.sess.str_of(impl_method_ty.ident),
+ pprust::path_to_str(&ast_trait_ref.path,
+ tcx.sess.intr())));
+ }
+ }
+ }
+
+ // Check for missing methods from trait
+ let provided_methods = ty::provided_trait_methods(tcx,
+ impl_trait_ref.def_id);
+ let mut missing_methods = ~[];
+ for trait_method in trait_methods.iter() {
+ let is_implemented =
+ impl_methods.iter().any(
+ |m| m.ident.name == trait_method.ident.name);
+ let is_provided =
+ provided_methods.iter().any(
+ |m| m.ident.name == trait_method.ident.name);
+ if !is_implemented && !is_provided {
+ missing_methods.push(
+ format!("`{}`", ccx.tcx.sess.str_of(trait_method.ident)));
+ }
+ }
+
+ if !missing_methods.is_empty() {
+ tcx.sess.span_err(
+ impl_span,
+ format!("not all trait methods implemented, missing: {}",
+ missing_methods.connect(", ")));
+ }
+}
+
+/**
+ * Checks that a method from an impl/class conforms to the signature of
+ * the same method as declared in the trait.
+ *
+ * # Parameters
+ *
+ * - impl_generics: the generics declared on the impl itself (not the method!)
+ * - impl_m: type of the method we are checking
+ * - impl_m_span: span to use for reporting errors
+ * - impl_m_body_id: id of the method body
+ * - trait_m: the method in the trait
+ * - trait_substs: the substitutions used on the type of the trait
+ * - self_ty: the self type of the impl
+ */
+pub fn compare_impl_method(tcx: ty::ctxt,
+ impl_generics: &ty::Generics,
+ impl_m: @ty::Method,
+ impl_m_span: Span,
+ impl_m_body_id: ast::NodeId,
+ trait_m: &ty::Method,
+ trait_substs: &ty::substs) {
+ debug!("compare_impl_method()");
+ let infcx = infer::new_infer_ctxt(tcx);
+
+ let impl_tps = impl_generics.type_param_defs.len();
+
+ // Try to give more informative error messages about self typing
+ // mismatches. Note that any mismatch will also be detected
+ // below, where we construct a canonical function type that
+ // includes the self parameter as a normal parameter. It's just
+ // that the error messages you get out of this code are a bit more
+ // inscrutable, particularly for cases where one method has no
+ // self.
+ match (&trait_m.explicit_self, &impl_m.explicit_self) {
+ (&ast::sty_static, &ast::sty_static) => {}
+ (&ast::sty_static, _) => {
+ tcx.sess.span_err(
+ impl_m_span,
+ format!("method `{}` has a `{}` declaration in the impl, \
+ but not in the trait",
+ tcx.sess.str_of(trait_m.ident),
+ pprust::explicit_self_to_str(&impl_m.explicit_self,
+ tcx.sess.intr())));
+ return;
+ }
+ (_, &ast::sty_static) => {
+ tcx.sess.span_err(
+ impl_m_span,
+ format!("method `{}` has a `{}` declaration in the trait, \
+ but not in the impl",
+ tcx.sess.str_of(trait_m.ident),
+ pprust::explicit_self_to_str(&trait_m.explicit_self,
+ tcx.sess.intr())));
+ return;
+ }
+ _ => {
+ // Let the type checker catch other errors below
+ }
+ }
+
+ let num_impl_m_type_params = impl_m.generics.type_param_defs.len();
+ let num_trait_m_type_params = trait_m.generics.type_param_defs.len();
+ if num_impl_m_type_params != num_trait_m_type_params {
+ tcx.sess.span_err(
+ impl_m_span,
+ format!("method `{}` has {} type parameter(s), but its trait \
+ declaration has {} type parameter(s)",
+ tcx.sess.str_of(trait_m.ident),
+ num_impl_m_type_params,
+ num_trait_m_type_params));
+ return;
+ }
+
+ if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
+ tcx.sess.span_err(
+ impl_m_span,
+ format!("method `{}` has {} parameter(s) \
+ but the trait has {} parameter(s)",
+ tcx.sess.str_of(trait_m.ident),
+ impl_m.fty.sig.inputs.len(),
+ trait_m.fty.sig.inputs.len()));
+ return;
+ }
+
+ for (i, trait_param_def) in trait_m.generics.type_param_defs.iter().enumerate() {
+ // For each of the corresponding impl ty param's bounds...
+ let impl_param_def = &impl_m.generics.type_param_defs[i];
+
+ // Check that the impl does not require any builtin-bounds
+ // that the trait does not guarantee:
+ let extra_bounds =
+ impl_param_def.bounds.builtin_bounds -
+ trait_param_def.bounds.builtin_bounds;
+ if !extra_bounds.is_empty() {
+ tcx.sess.span_err(
+ impl_m_span,
+ format!("in method `{}`, \
+ type parameter {} requires `{}`, \
+ which is not required by \
+ the corresponding type parameter \
+ in the trait declaration",
+ tcx.sess.str_of(trait_m.ident),
+ i,
+ extra_bounds.user_string(tcx)));
+ return;
+ }
+
+ // FIXME(#2687)---we should be checking that the bounds of the
+ // trait imply the bounds of the subtype, but it appears we
+ // are...not checking this.
+ if impl_param_def.bounds.trait_bounds.len() !=
+ trait_param_def.bounds.trait_bounds.len()
+ {
+ tcx.sess.span_err(
+ impl_m_span,
+ format!("in method `{}`, \
+ type parameter {} has {} trait bound(s), but the \
+ corresponding type parameter in \
+ the trait declaration has {} trait bound(s)",
+ tcx.sess.str_of(trait_m.ident),
+ i, impl_param_def.bounds.trait_bounds.len(),
+ trait_param_def.bounds.trait_bounds.len()));
+ return;
+ }
+ }
+
+ // Create a substitution that maps the type parameters on the impl
+ // to themselves and which replace any references to bound regions
+ // in the self type with free regions. So, for example, if the
+ // impl type is "&'self str", then this would replace the self
+ // type with a free region `self`.
+ let dummy_impl_tps: ~[ty::t] =
+ impl_generics.type_param_defs.iter().enumerate().
+ map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
+ collect();
+ let dummy_method_tps: ~[ty::t] =
+ impl_m.generics.type_param_defs.iter().enumerate().
+ map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
+ collect();
+ let dummy_impl_regions: OptVec<ty::Region> =
+ impl_generics.region_param_defs.iter().
+ map(|l| ty::re_free(ty::FreeRegion {
+ scope_id: impl_m_body_id,
+ bound_region: ty::br_named(l.def_id, l.ident)})).
+ collect();
+ let dummy_substs = ty::substs {
+ tps: vec::append(dummy_impl_tps, dummy_method_tps),
+ regions: ty::NonerasedRegions(dummy_impl_regions),
+ self_ty: None };
+
+ // We are going to create a synthetic fn type that includes
+ // both the method's self argument and its normal arguments.
+ // So a method like `fn(&self, a: uint)` would be converted
+ // into a function `fn(self: &T, a: uint)`.
+ let mut trait_fn_args = ~[];
+ let mut impl_fn_args = ~[];
+
+ // For both the trait and the impl, create an argument to
+ // represent the self argument (unless this is a static method).
+ // This argument will have the *transformed* self type.
+ for &t in trait_m.transformed_self_ty.iter() {
+ trait_fn_args.push(t);
+ }
+ for &t in impl_m.transformed_self_ty.iter() {
+ impl_fn_args.push(t);
+ }
+
+ // Add in the normal arguments.
+ trait_fn_args.push_all(trait_m.fty.sig.inputs);
+ impl_fn_args.push_all(impl_m.fty.sig.inputs);
+
+ // Create a bare fn type for trait/impl that includes self argument
+ let trait_fty =
+ ty::mk_bare_fn(tcx,
+ ty::BareFnTy {
+ purity: trait_m.fty.purity,
+ abis: trait_m.fty.abis,
+ sig: ty::FnSig {
+ binder_id: trait_m.fty.sig.binder_id,
+ inputs: trait_fn_args,
+ output: trait_m.fty.sig.output,
+ variadic: false
+ }
+ });
+ let impl_fty =
+ ty::mk_bare_fn(tcx,
+ ty::BareFnTy {
+ purity: impl_m.fty.purity,
+ abis: impl_m.fty.abis,
+ sig: ty::FnSig {
+ binder_id: impl_m.fty.sig.binder_id,
+ inputs: impl_fn_args,
+ output: impl_m.fty.sig.output,
+ variadic: false
+ }
+ });
+
+ // Perform substitutions so that the trait/impl methods are expressed
+ // in terms of the same set of type/region parameters:
+ // - replace trait type parameters with those from `trait_substs`,
+ // except with any reference to bound self replaced with `dummy_self_r`
+ // - replace method parameters on the trait with fresh, dummy parameters
+ // that correspond to the parameters we will find on the impl
+ // - replace self region with a fresh, dummy region
+ let impl_fty = {
+ debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
+ impl_fty.subst(tcx, &dummy_substs)
+ };
+ debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
+ let trait_fty = {
+ let substs { regions: trait_regions,
+ tps: trait_tps,
+ self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
+ let substs = substs {
+ regions: trait_regions,
+ tps: vec::append(trait_tps, dummy_method_tps),
+ self_ty: self_ty,
+ };
+ debug!("trait_fty (pre-subst): {} substs={}",
+ trait_fty.repr(tcx), substs.repr(tcx));
+ trait_fty.subst(tcx, &substs)
+ };
+ debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
+
+ match infer::mk_subty(infcx, false, infer::MethodCompatCheck(impl_m_span),
+ impl_fty, trait_fty) {
+ result::Ok(()) => {}
+ result::Err(ref terr) => {
+ tcx.sess.span_err(
+ impl_m_span,
+ format!("method `{}` has an incompatible type: {}",
+ tcx.sess.str_of(trait_m.ident),
+ ty::type_err_to_str(tcx, terr)));
+ ty::note_and_explain_type_err(tcx, terr);
+ }
+ }
+}
+
impl AstConv for FnCtxt {
fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
return trait_id;
}
- // This check doesn't really have anything to do with coherence. It's
- // here for historical reasons
- pub fn check_trait_methods_are_implemented(
- &self,
- all_methods: &mut ~[@Method],
- trait_did: DefId,
- trait_ref_span: Span) {
-
- let tcx = self.crate_context.tcx;
-
- let mut provided_names = HashSet::new();
- // Implemented methods
- for elt in all_methods.iter() {
- provided_names.insert(elt.ident.name);
- }
-
- let r = ty::trait_methods(tcx, trait_did);
- for method in r.iter() {
- debug!("checking for {}", method.ident.repr(tcx));
- if provided_names.contains(&method.ident.name) { continue; }
-
- tcx.sess.span_err(trait_ref_span,
- format!("missing method `{}`",
- tcx.sess.str_of(method.ident)));
- }
- }
-
/// For coherence, when we have `impl Type`, we need to guarantee that
/// `Type` is "local" to the crate. For our purposes, this means that it
/// must precisely name some nominal type defined in this crate.
let ty_trait_ref = ty::node_id_to_trait_ref(
self.crate_context.tcx,
trait_ref.ref_id);
- let trait_did = ty_trait_ref.def_id;
self.instantiate_default_methods(local_def(item.id),
ty_trait_ref,
&mut methods);
-
- // Check that we have implementations of every trait method
- self.check_trait_methods_are_implemented(
- &mut methods,
- trait_did,
- trait_ref.path.span);
}
return @Impl {
bounds
}
-/**
- * Checks that a method from an impl/class conforms to the signature of
- * the same method as declared in the trait.
- *
- * # Parameters
- *
- * - impl_tps: the type params declared on the impl itself (not the method!)
- * - cm: info about the method we are checking
- * - trait_m: the method in the trait
- * - trait_substs: the substitutions used on the type of the trait
- * - self_ty: the self type of the impl
- */
-pub fn compare_impl_method(tcx: ty::ctxt,
- impl_tps: uint,
- cm: &ConvertedMethod,
- trait_m: &ty::Method,
- trait_substs: &ty::substs,
- self_ty: ty::t) {
- debug!("compare_impl_method()");
- let infcx = infer::new_infer_ctxt(tcx);
-
- let impl_m = &cm.mty;
-
- // Try to give more informative error messages about self typing
- // mismatches. Note that any mismatch will also be detected
- // below, where we construct a canonical function type that
- // includes the self parameter as a normal parameter. It's just
- // that the error messages you get out of this code are a bit more
- // inscrutable, particularly for cases where one method has no
- // self.
- match (&trait_m.explicit_self, &impl_m.explicit_self) {
- (&ast::sty_static, &ast::sty_static) => {}
- (&ast::sty_static, _) => {
- tcx.sess.span_err(
- cm.span,
- format!("method `{}` has a `{}` declaration in the impl, \
- but not in the trait",
- tcx.sess.str_of(trait_m.ident),
- explicit_self_to_str(&impl_m.explicit_self, tcx.sess.intr())));
- return;
- }
- (_, &ast::sty_static) => {
- tcx.sess.span_err(
- cm.span,
- format!("method `{}` has a `{}` declaration in the trait, \
- but not in the impl",
- tcx.sess.str_of(trait_m.ident),
- explicit_self_to_str(&trait_m.explicit_self, tcx.sess.intr())));
- return;
- }
- _ => {
- // Let the type checker catch other errors below
- }
- }
-
- let num_impl_m_type_params = impl_m.generics.type_param_defs.len();
- let num_trait_m_type_params = trait_m.generics.type_param_defs.len();
- if num_impl_m_type_params != num_trait_m_type_params {
- tcx.sess.span_err(
- cm.span,
- format!("method `{}` has {} type {}, but its trait \
- declaration has {} type {}",
- tcx.sess.str_of(trait_m.ident),
- num_impl_m_type_params,
- pluralize(num_impl_m_type_params, ~"parameter"),
- num_trait_m_type_params,
- pluralize(num_trait_m_type_params, ~"parameter")));
- return;
- }
-
- if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
- tcx.sess.span_err(
- cm.span,
- format!("method `{}` has {} parameter{} \
- but the trait has {}",
- tcx.sess.str_of(trait_m.ident),
- impl_m.fty.sig.inputs.len(),
- if impl_m.fty.sig.inputs.len() == 1 { "" } else { "s" },
- trait_m.fty.sig.inputs.len()));
- return;
- }
-
- for (i, trait_param_def) in trait_m.generics.type_param_defs.iter().enumerate() {
- // For each of the corresponding impl ty param's bounds...
- let impl_param_def = &impl_m.generics.type_param_defs[i];
-
- // Check that the impl does not require any builtin-bounds
- // that the trait does not guarantee:
- let extra_bounds =
- impl_param_def.bounds.builtin_bounds -
- trait_param_def.bounds.builtin_bounds;
- if !extra_bounds.is_empty() {
- tcx.sess.span_err(
- cm.span,
- format!("in method `{}`, \
- type parameter {} requires `{}`, \
- which is not required by \
- the corresponding type parameter \
- in the trait declaration",
- tcx.sess.str_of(trait_m.ident),
- i,
- extra_bounds.user_string(tcx)));
- return;
- }
-
- // FIXME(#2687)---we should be checking that the bounds of the
- // trait imply the bounds of the subtype, but it appears we
- // are...not checking this.
- if impl_param_def.bounds.trait_bounds.len() !=
- trait_param_def.bounds.trait_bounds.len()
- {
- tcx.sess.span_err(
- cm.span,
- format!("in method `{}`, \
- type parameter {} has {} trait {}, but the \
- corresponding type parameter in \
- the trait declaration has {} trait {}",
- tcx.sess.str_of(trait_m.ident),
- i, impl_param_def.bounds.trait_bounds.len(),
- pluralize(impl_param_def.bounds.trait_bounds.len(),
- ~"bound"),
- trait_param_def.bounds.trait_bounds.len(),
- pluralize(trait_param_def.bounds.trait_bounds.len(),
- ~"bound")));
- return;
- }
- }
-
- // Replace any references to the self region in the self type with
- // a free region. So, for example, if the impl type is
- // "&'self str", then this would replace the self type with a free
- // region `self`.
- let dummy_self_r = ty::re_free(ty::FreeRegion {scope_id: cm.body_id,
- bound_region: ty::br_self});
- let self_ty = replace_bound_self(tcx, self_ty, dummy_self_r);
-
- // We are going to create a synthetic fn type that includes
- // both the method's self argument and its normal arguments.
- // So a method like `fn(&self, a: uint)` would be converted
- // into a function `fn(self: &T, a: uint)`.
- let mut trait_fn_args = ~[];
- let mut impl_fn_args = ~[];
-
- // For both the trait and the impl, create an argument to
- // represent the self argument (unless this is a static method).
- // This argument will have the *transformed* self type.
- for &t in trait_m.transformed_self_ty.iter() {
- trait_fn_args.push(t);
- }
- for &t in impl_m.transformed_self_ty.iter() {
- impl_fn_args.push(t);
- }
-
- // Add in the normal arguments.
- trait_fn_args.push_all(trait_m.fty.sig.inputs);
- impl_fn_args.push_all(impl_m.fty.sig.inputs);
-
- // Create a bare fn type for trait/impl that includes self argument
- let trait_fty =
- ty::mk_bare_fn(tcx,
- ty::BareFnTy {
- purity: trait_m.fty.purity,
- abis: trait_m.fty.abis,
- sig: ty::FnSig {
- bound_lifetime_names:
- trait_m.fty
- .sig
- .bound_lifetime_names
- .clone(),
- inputs: trait_fn_args,
- output: trait_m.fty.sig.output,
- variadic: false
- }
- });
- let impl_fty =
- ty::mk_bare_fn(tcx,
- ty::BareFnTy {
- purity: impl_m.fty.purity,
- abis: impl_m.fty.abis,
- sig: ty::FnSig {
- bound_lifetime_names:
- impl_m.fty
- .sig
- .bound_lifetime_names
- .clone(),
- inputs: impl_fn_args,
- output: impl_m.fty.sig.output,
- variadic: false
- }
- });
-
- // Perform substitutions so that the trait/impl methods are expressed
- // in terms of the same set of type/region parameters:
- // - replace trait type parameters with those from `trait_substs`,
- // except with any reference to bound self replaced with `dummy_self_r`
- // - replace method parameters on the trait with fresh, dummy parameters
- // that correspond to the parameters we will find on the impl
- // - replace self region with a fresh, dummy region
- let impl_fty = {
- debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
- replace_bound_self(tcx, impl_fty, dummy_self_r)
- };
- debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
- let trait_fty = {
- let num_trait_m_type_params = trait_m.generics.type_param_defs.len();
- let dummy_tps = do vec::from_fn(num_trait_m_type_params) |i| {
- ty::mk_param(tcx, i + impl_tps,
- impl_m.generics.type_param_defs[i].def_id)
- };
- let trait_tps = trait_substs.tps.map(
- |t| replace_bound_self(tcx, *t, dummy_self_r));
- let substs = substs {
- regions: ty::NonerasedRegions(opt_vec::with(dummy_self_r)),
- self_ty: Some(self_ty),
- tps: vec::append(trait_tps, dummy_tps)
- };
- debug!("trait_fty (pre-subst): {} substs={}",
- trait_fty.repr(tcx), substs.repr(tcx));
- ty::subst(tcx, &substs, trait_fty)
- };
- debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
-
- match infer::mk_subty(infcx, false, infer::MethodCompatCheck(cm.span),
- impl_fty, trait_fty) {
- result::Ok(()) => {}
- result::Err(ref terr) => {
- tcx.sess.span_err(
- cm.span,
- format!("method `{}` has an incompatible type: {}",
- tcx.sess.str_of(trait_m.ident),
- ty::type_err_to_str(tcx, terr)));
- ty::note_and_explain_type_err(tcx, terr);
- }
- }
- return;
-
- // Replaces bound references to the self region with `with_r`.
- fn replace_bound_self(tcx: ty::ctxt, ty: ty::t,
- with_r: ty::Region) -> ty::t {
- do ty::fold_regions(tcx, ty) |r, _in_fn| {
- if r == ty::re_bound(ty::br_self) {with_r} else {r}
- }
- }
-}
-
-pub fn check_methods_against_trait(ccx: &CrateCtxt,
- generics: &ast::Generics,
- rp: Option<ty::region_variance>,
- selfty: ty::t,
- a_trait_ty: &ast::trait_ref,
- impl_ms: &[ConvertedMethod])
-{
- let tcx = ccx.tcx;
- let trait_ref = instantiate_trait_ref(ccx, a_trait_ty, rp,
- generics, selfty);
-
- if trait_ref.def_id.crate == ast::LOCAL_CRATE {
- ensure_trait_methods(ccx, trait_ref.def_id.node);
- }
-
- // Check that each method we impl is a method on the trait
- // Trait methods we don't implement must be default methods, but if not
- // we'll catch it in coherence
- let trait_ms = ty::trait_methods(tcx, trait_ref.def_id);
- for impl_m in impl_ms.iter() {
- match trait_ms.iter().find(|trait_m| trait_m.ident.name == impl_m.mty.ident.name) {
- Some(trait_m) => {
- let num_impl_tps = generics.ty_params.len();
- compare_impl_method(
- ccx.tcx, num_impl_tps, impl_m, *trait_m,
- &trait_ref.substs, selfty);
- }
- None => {
- // This method is not part of the trait
- tcx.sess.span_err(
- impl_m.span,
- format!("method `{}` is not a member of trait `{}`",
- tcx.sess.str_of(impl_m.mty.ident),
- path_to_str(&a_trait_ty.path, tcx.sess.intr())));
- }
- }
- }
-} // fn
-
pub fn convert_field(ccx: &CrateCtxt,
struct_generics: &ty::Generics,
v: &ast::struct_field) {
"cannot provide an explicit implementation \
for a builtin kind");
}
-
- check_methods_against_trait(ccx, generics, rp, selfty, t, cms);
}
}
ast::item_trait(ref generics, _, ref trait_methods) => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern:missing method `eat`
trait animal {
fn eat(&self);
}
}
impl animal for cat {
+ //~^ ERROR not all trait methods implemented, missing: `eat`
}
fn cat(in_x : uint) -> cat {
// except according to those terms.
struct thing(uint);
-impl Ord for thing { //~ ERROR missing method `lt`
+impl Ord for thing { //~ ERROR not all trait methods implemented, missing: `lt`
fn le(&self, other: &thing) -> bool { **self < **other }
fn ge(&self, other: &thing) -> bool { **self < **other }
}
fn eq(&self, other: &int) -> bool { *self == *other }
}
-impl MyEq for A {} //~ ERROR missing method
+impl MyEq for A {} //~ ERROR not all trait methods implemented, missing: `eq`
fn main() {
}