Skip to content

Commit 8477c48

Browse files
committed
---
yaml --- r: 95966 b: refs/heads/dist-snap c: 168ac52 h: refs/heads/master v: v3
1 parent 276f991 commit 8477c48

File tree

7 files changed

+326
-325
lines changed

7 files changed

+326
-325
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ refs/heads/try: c274a6888410ce3e357e014568b43310ed787d36
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: 147ecfdd8221e4a4d4e090486829a06da1e0ca3c
9-
refs/heads/dist-snap: 9d3f57ef0869805e0dde99cdce9548a587df7893
9+
refs/heads/dist-snap: 168ac5290e9d4a787e020735f96fa789060a8f76
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503
1212
refs/heads/try3: 9387340aab40a73e8424c48fd42f0c521a4875c0

branches/dist-snap/src/librustc/middle/typeck/check/mod.rs

Lines changed: 322 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,23 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
603603
for m in ms.iter() {
604604
check_method_body(ccx, &impl_tpt.generics, None, *m);
605605
}
606-
vtable::resolve_impl(ccx, it);
606+
607+
match *opt_trait_ref {
608+
Some(ref ast_trait_ref) => {
609+
let impl_trait_ref =
610+
ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
611+
check_impl_methods_against_trait(ccx,
612+
it.span,
613+
&impl_tpt.generics,
614+
ast_trait_ref,
615+
impl_trait_ref,
616+
*ms);
617+
vtable::resolve_impl(ccx, it, &impl_tpt.generics,
618+
impl_trait_ref);
619+
}
620+
None => { }
621+
}
622+
607623
}
608624
ast::item_trait(_, _, ref trait_methods) => {
609625
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
@@ -707,6 +723,311 @@ fn check_method_body(ccx: @mut CrateCtxt,
707723
param_env);
708724
}
709725

726+
fn check_impl_methods_against_trait(ccx: @mut CrateCtxt,
727+
impl_span: Span,
728+
impl_generics: &ty::Generics,
729+
ast_trait_ref: &ast::trait_ref,
730+
impl_trait_ref: &ty::TraitRef,
731+
impl_methods: &[@ast::method]) {
732+
// Locate trait methods
733+
let tcx = ccx.tcx;
734+
let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
735+
736+
// Check existing impl methods to see if they are both present in trait
737+
// and compatible with trait signature
738+
for impl_method in impl_methods.iter() {
739+
let impl_method_def_id = local_def(impl_method.id);
740+
let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
741+
742+
// If this is an impl of a trait method, find the corresponding
743+
// method definition in the trait.
744+
let opt_trait_method_ty =
745+
trait_methods.iter().
746+
find(|tm| tm.ident.name == impl_method_ty.ident.name);
747+
match opt_trait_method_ty {
748+
Some(trait_method_ty) => {
749+
compare_impl_method(ccx.tcx,
750+
impl_generics,
751+
impl_method_ty,
752+
impl_method.span,
753+
impl_method.body.id,
754+
*trait_method_ty,
755+
&impl_trait_ref.substs);
756+
}
757+
None => {
758+
tcx.sess.span_err(
759+
impl_method.span,
760+
format!("method `{}` is not a member of trait `{}`",
761+
tcx.sess.str_of(impl_method_ty.ident),
762+
pprust::path_to_str(&ast_trait_ref.path,
763+
tcx.sess.intr())));
764+
}
765+
}
766+
}
767+
768+
// Check for missing methods from trait
769+
let provided_methods = ty::provided_trait_methods(tcx,
770+
impl_trait_ref.def_id);
771+
let mut missing_methods = ~[];
772+
for trait_method in trait_methods.iter() {
773+
let is_implemented =
774+
impl_methods.iter().any(
775+
|m| m.ident.name == trait_method.ident.name);
776+
let is_provided =
777+
provided_methods.iter().any(
778+
|m| m.ident.name == trait_method.ident.name);
779+
if !is_implemented && !is_provided {
780+
missing_methods.push(
781+
format!("`{}`", ccx.tcx.sess.str_of(trait_method.ident)));
782+
}
783+
}
784+
785+
if !missing_methods.is_empty() {
786+
tcx.sess.span_err(
787+
impl_span,
788+
format!("not all trait methods implemented, missing: {}",
789+
missing_methods.connect(", ")));
790+
}
791+
}
792+
793+
/**
794+
* Checks that a method from an impl/class conforms to the signature of
795+
* the same method as declared in the trait.
796+
*
797+
* # Parameters
798+
*
799+
* - impl_generics: the generics declared on the impl itself (not the method!)
800+
* - impl_m: type of the method we are checking
801+
* - impl_m_span: span to use for reporting errors
802+
* - impl_m_body_id: id of the method body
803+
* - trait_m: the method in the trait
804+
* - trait_substs: the substitutions used on the type of the trait
805+
* - self_ty: the self type of the impl
806+
*/
807+
pub fn compare_impl_method(tcx: ty::ctxt,
808+
impl_generics: &ty::Generics,
809+
impl_m: @ty::Method,
810+
impl_m_span: Span,
811+
impl_m_body_id: ast::NodeId,
812+
trait_m: &ty::Method,
813+
trait_substs: &ty::substs) {
814+
debug!("compare_impl_method()");
815+
let infcx = infer::new_infer_ctxt(tcx);
816+
817+
let impl_tps = impl_generics.type_param_defs.len();
818+
819+
// Try to give more informative error messages about self typing
820+
// mismatches. Note that any mismatch will also be detected
821+
// below, where we construct a canonical function type that
822+
// includes the self parameter as a normal parameter. It's just
823+
// that the error messages you get out of this code are a bit more
824+
// inscrutable, particularly for cases where one method has no
825+
// self.
826+
match (&trait_m.explicit_self, &impl_m.explicit_self) {
827+
(&ast::sty_static, &ast::sty_static) => {}
828+
(&ast::sty_static, _) => {
829+
tcx.sess.span_err(
830+
impl_m_span,
831+
format!("method `{}` has a `{}` declaration in the impl, \
832+
but not in the trait",
833+
tcx.sess.str_of(trait_m.ident),
834+
pprust::explicit_self_to_str(&impl_m.explicit_self,
835+
tcx.sess.intr())));
836+
return;
837+
}
838+
(_, &ast::sty_static) => {
839+
tcx.sess.span_err(
840+
impl_m_span,
841+
format!("method `{}` has a `{}` declaration in the trait, \
842+
but not in the impl",
843+
tcx.sess.str_of(trait_m.ident),
844+
pprust::explicit_self_to_str(&trait_m.explicit_self,
845+
tcx.sess.intr())));
846+
return;
847+
}
848+
_ => {
849+
// Let the type checker catch other errors below
850+
}
851+
}
852+
853+
let num_impl_m_type_params = impl_m.generics.type_param_defs.len();
854+
let num_trait_m_type_params = trait_m.generics.type_param_defs.len();
855+
if num_impl_m_type_params != num_trait_m_type_params {
856+
tcx.sess.span_err(
857+
impl_m_span,
858+
format!("method `{}` has {} type parameter(s), but its trait \
859+
declaration has {} type parameter(s)",
860+
tcx.sess.str_of(trait_m.ident),
861+
num_impl_m_type_params,
862+
num_trait_m_type_params));
863+
return;
864+
}
865+
866+
if impl_m.fty.sig.inputs.len() != trait_m.fty.sig.inputs.len() {
867+
tcx.sess.span_err(
868+
impl_m_span,
869+
format!("method `{}` has {} parameter(s) \
870+
but the trait has {} parameter(s)",
871+
tcx.sess.str_of(trait_m.ident),
872+
impl_m.fty.sig.inputs.len(),
873+
trait_m.fty.sig.inputs.len()));
874+
return;
875+
}
876+
877+
for (i, trait_param_def) in trait_m.generics.type_param_defs.iter().enumerate() {
878+
// For each of the corresponding impl ty param's bounds...
879+
let impl_param_def = &impl_m.generics.type_param_defs[i];
880+
881+
// Check that the impl does not require any builtin-bounds
882+
// that the trait does not guarantee:
883+
let extra_bounds =
884+
impl_param_def.bounds.builtin_bounds -
885+
trait_param_def.bounds.builtin_bounds;
886+
if !extra_bounds.is_empty() {
887+
tcx.sess.span_err(
888+
impl_m_span,
889+
format!("in method `{}`, \
890+
type parameter {} requires `{}`, \
891+
which is not required by \
892+
the corresponding type parameter \
893+
in the trait declaration",
894+
tcx.sess.str_of(trait_m.ident),
895+
i,
896+
extra_bounds.user_string(tcx)));
897+
return;
898+
}
899+
900+
// FIXME(#2687)---we should be checking that the bounds of the
901+
// trait imply the bounds of the subtype, but it appears we
902+
// are...not checking this.
903+
if impl_param_def.bounds.trait_bounds.len() !=
904+
trait_param_def.bounds.trait_bounds.len()
905+
{
906+
tcx.sess.span_err(
907+
impl_m_span,
908+
format!("in method `{}`, \
909+
type parameter {} has {} trait bound(s), but the \
910+
corresponding type parameter in \
911+
the trait declaration has {} trait bound(s)",
912+
tcx.sess.str_of(trait_m.ident),
913+
i, impl_param_def.bounds.trait_bounds.len(),
914+
trait_param_def.bounds.trait_bounds.len()));
915+
return;
916+
}
917+
}
918+
919+
// Create a substitution that maps the type parameters on the impl
920+
// to themselves and which replace any references to bound regions
921+
// in the self type with free regions. So, for example, if the
922+
// impl type is "&'self str", then this would replace the self
923+
// type with a free region `self`.
924+
let dummy_impl_tps: ~[ty::t] =
925+
impl_generics.type_param_defs.iter().enumerate().
926+
map(|(i,t)| ty::mk_param(tcx, i, t.def_id)).
927+
collect();
928+
let dummy_method_tps: ~[ty::t] =
929+
impl_m.generics.type_param_defs.iter().enumerate().
930+
map(|(i,t)| ty::mk_param(tcx, i + impl_tps, t.def_id)).
931+
collect();
932+
let dummy_impl_regions: OptVec<ty::Region> =
933+
impl_generics.region_param_defs.iter().
934+
map(|l| ty::re_free(ty::FreeRegion {
935+
scope_id: impl_m_body_id,
936+
bound_region: ty::br_named(l.def_id, l.ident)})).
937+
collect();
938+
let dummy_substs = ty::substs {
939+
tps: vec::append(dummy_impl_tps, dummy_method_tps),
940+
regions: ty::NonerasedRegions(dummy_impl_regions),
941+
self_ty: None };
942+
943+
// We are going to create a synthetic fn type that includes
944+
// both the method's self argument and its normal arguments.
945+
// So a method like `fn(&self, a: uint)` would be converted
946+
// into a function `fn(self: &T, a: uint)`.
947+
let mut trait_fn_args = ~[];
948+
let mut impl_fn_args = ~[];
949+
950+
// For both the trait and the impl, create an argument to
951+
// represent the self argument (unless this is a static method).
952+
// This argument will have the *transformed* self type.
953+
for &t in trait_m.transformed_self_ty.iter() {
954+
trait_fn_args.push(t);
955+
}
956+
for &t in impl_m.transformed_self_ty.iter() {
957+
impl_fn_args.push(t);
958+
}
959+
960+
// Add in the normal arguments.
961+
trait_fn_args.push_all(trait_m.fty.sig.inputs);
962+
impl_fn_args.push_all(impl_m.fty.sig.inputs);
963+
964+
// Create a bare fn type for trait/impl that includes self argument
965+
let trait_fty =
966+
ty::mk_bare_fn(tcx,
967+
ty::BareFnTy {
968+
purity: trait_m.fty.purity,
969+
abis: trait_m.fty.abis,
970+
sig: ty::FnSig {
971+
binder_id: trait_m.fty.sig.binder_id,
972+
inputs: trait_fn_args,
973+
output: trait_m.fty.sig.output,
974+
variadic: false
975+
}
976+
});
977+
let impl_fty =
978+
ty::mk_bare_fn(tcx,
979+
ty::BareFnTy {
980+
purity: impl_m.fty.purity,
981+
abis: impl_m.fty.abis,
982+
sig: ty::FnSig {
983+
binder_id: impl_m.fty.sig.binder_id,
984+
inputs: impl_fn_args,
985+
output: impl_m.fty.sig.output,
986+
variadic: false
987+
}
988+
});
989+
990+
// Perform substitutions so that the trait/impl methods are expressed
991+
// in terms of the same set of type/region parameters:
992+
// - replace trait type parameters with those from `trait_substs`,
993+
// except with any reference to bound self replaced with `dummy_self_r`
994+
// - replace method parameters on the trait with fresh, dummy parameters
995+
// that correspond to the parameters we will find on the impl
996+
// - replace self region with a fresh, dummy region
997+
let impl_fty = {
998+
debug!("impl_fty (pre-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
999+
impl_fty.subst(tcx, &dummy_substs)
1000+
};
1001+
debug!("impl_fty (post-subst): {}", ppaux::ty_to_str(tcx, impl_fty));
1002+
let trait_fty = {
1003+
let substs { regions: trait_regions,
1004+
tps: trait_tps,
1005+
self_ty: self_ty } = trait_substs.subst(tcx, &dummy_substs);
1006+
let substs = substs {
1007+
regions: trait_regions,
1008+
tps: vec::append(trait_tps, dummy_method_tps),
1009+
self_ty: self_ty,
1010+
};
1011+
debug!("trait_fty (pre-subst): {} substs={}",
1012+
trait_fty.repr(tcx), substs.repr(tcx));
1013+
trait_fty.subst(tcx, &substs)
1014+
};
1015+
debug!("trait_fty (post-subst): {}", trait_fty.repr(tcx));
1016+
1017+
match infer::mk_subty(infcx, false, infer::MethodCompatCheck(impl_m_span),
1018+
impl_fty, trait_fty) {
1019+
result::Ok(()) => {}
1020+
result::Err(ref terr) => {
1021+
tcx.sess.span_err(
1022+
impl_m_span,
1023+
format!("method `{}` has an incompatible type: {}",
1024+
tcx.sess.str_of(trait_m.ident),
1025+
ty::type_err_to_str(tcx, terr)));
1026+
ty::note_and_explain_type_err(tcx, terr);
1027+
}
1028+
}
1029+
}
1030+
7101031
impl AstConv for FnCtxt {
7111032
fn tcx(&self) -> ty::ctxt { self.ccx.tcx }
7121033

branches/dist-snap/src/librustc/middle/typeck/coherence.rs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -536,33 +536,6 @@ impl CoherenceChecker {
536536
return trait_id;
537537
}
538538

539-
// This check doesn't really have anything to do with coherence. It's
540-
// here for historical reasons
541-
pub fn check_trait_methods_are_implemented(
542-
&self,
543-
all_methods: &mut ~[@Method],
544-
trait_did: DefId,
545-
trait_ref_span: Span) {
546-
547-
let tcx = self.crate_context.tcx;
548-
549-
let mut provided_names = HashSet::new();
550-
// Implemented methods
551-
for elt in all_methods.iter() {
552-
provided_names.insert(elt.ident.name);
553-
}
554-
555-
let r = ty::trait_methods(tcx, trait_did);
556-
for method in r.iter() {
557-
debug!("checking for {}", method.ident.repr(tcx));
558-
if provided_names.contains(&method.ident.name) { continue; }
559-
560-
tcx.sess.span_err(trait_ref_span,
561-
format!("missing method `{}`",
562-
tcx.sess.str_of(method.ident)));
563-
}
564-
}
565-
566539
/// For coherence, when we have `impl Type`, we need to guarantee that
567540
/// `Type` is "local" to the crate. For our purposes, this means that it
568541
/// must precisely name some nominal type defined in this crate.
@@ -617,17 +590,10 @@ impl CoherenceChecker {
617590
let ty_trait_ref = ty::node_id_to_trait_ref(
618591
self.crate_context.tcx,
619592
trait_ref.ref_id);
620-
let trait_did = ty_trait_ref.def_id;
621593

622594
self.instantiate_default_methods(local_def(item.id),
623595
ty_trait_ref,
624596
&mut methods);
625-
626-
// Check that we have implementations of every trait method
627-
self.check_trait_methods_are_implemented(
628-
&mut methods,
629-
trait_did,
630-
trait_ref.path.span);
631597
}
632598

633599
return @Impl {

0 commit comments

Comments
 (0)