]> git.lizzy.rs Git - rust.git/commitdiff
support `default impl` for specialization
authorGianni Ciccarelli <gianni.ciccarelli@gmail.com>
Thu, 12 Oct 2017 17:38:44 +0000 (17:38 +0000)
committerGianni Ciccarelli <gianni.ciccarelli@gmail.com>
Wed, 7 Feb 2018 17:42:29 +0000 (17:42 +0000)
    a `default impl` need not include all items from the trait
    a `default impl` alone does not mean that a type implements the trait

30 files changed:
src/librustc/ich/impls_ty.rs
src/librustc/traits/select.rs
src/librustc/traits/util.rs
src/librustc/ty/instance.rs
src/librustc/ty/mod.rs
src/librustc/ty/structural_impls.rs
src/librustc/ty/sty.rs
src/librustc/util/ppaux.rs
src/librustc_mir/monomorphize/collector.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/dropck.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/collect.rs
src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs [new file with mode: 0644]
src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs [new file with mode: 0644]
src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs [new file with mode: 0644]
src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs [new file with mode: 0644]
src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs [new file with mode: 0644]
src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs [new file with mode: 0644]
src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs [new file with mode: 0644]

index 107779ec3fa155cfc588b36c71aca00842c25196..42724274eb701b685452731f7addc9a3183f99d1 100644 (file)
@@ -218,7 +218,8 @@ fn hash_stable<W: StableHasherResult>(&self,
 });
 
 impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
-impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
+impl_stable_hash_for!(enum ty::DefaultImplCheck { Yes, No });
+impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref, default_impl_check });
 impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 });
 impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b });
 
index 4ed25646d436d03671852d1d3a0fcd0f625e9c85..ee6bf4180ddab1fabfb4c0236497895b0da53436 100644 (file)
@@ -1083,12 +1083,39 @@ fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
     }
 
     // Treat negative impls as unimplemented
-    fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
-                             -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+    fn filter_negative_and_default_impls<'o>(&self,
+                                             candidate: SelectionCandidate<'tcx>,
+                                             stack: &TraitObligationStack<'o, 'tcx>)
+                                             -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+
         if let ImplCandidate(def_id) = candidate {
             if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative {
                 return Err(Unimplemented)
             }
+
+            // if def_id is a default impl and it doesn't implement all the trait items,
+            // the impl doesn't implement the trait.
+            // An `Unimplemented` error is returned only if the default_impl_check is
+            // applicable to the trait predicate or the cause of the predicate is an
+            // `ObjectCastObligation`
+            if self.tcx().impl_is_default(def_id) &&
+               !self.tcx().default_impl_implement_all_methods(def_id){
+                match stack.obligation.cause.code {
+                    ObligationCauseCode::ObjectCastObligation(_) =>  {
+                        return Err(Unimplemented)
+                    },
+                    ObligationCauseCode::ItemObligation(..) |
+                    ObligationCauseCode::MiscObligation =>  {
+                        if let ty::DefaultImplCheck::Yes = stack.obligation
+                                                                .predicate
+                                                                .skip_binder()
+                                                                .default_impl_check {
+                            return Err(Unimplemented)
+                        }
+                    },
+                    _ => {}
+                }
+            }
         }
         Ok(Some(candidate))
     }
@@ -1178,9 +1205,8 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
         // Instead, we select the right impl now but report `Bar does
         // not implement Clone`.
         if candidates.len() == 1 {
-            return self.filter_negative_impls(candidates.pop().unwrap());
+            return self.filter_negative_and_default_impls(candidates.pop().unwrap(), stack);
         }
-
         // Winnow, but record the exact outcome of evaluation, which
         // is needed for specialization.
         let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| {
@@ -1239,7 +1265,7 @@ fn candidate_from_obligation_no_cache<'o>(&mut self,
         }
 
         // Just one candidate left.
-        self.filter_negative_impls(candidates.pop().unwrap().candidate)
+        self.filter_negative_and_default_impls(candidates.pop().unwrap().candidate, stack)
     }
 
     fn is_knowable<'o>(&mut self,
index 898accb90215934e4006b3e81a982fa494e4bb75..9e0859c67a0adfcce45c9f11b7c3b82460329728 100644 (file)
@@ -22,8 +22,11 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                        pred: &ty::Predicate<'tcx>)
                                        -> ty::Predicate<'tcx> {
     match *pred {
-        ty::Predicate::Trait(ref data) =>
-            ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)),
+        ty::Predicate::Trait(ref data) => {
+            let anonymized_pred = ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data));
+            anonymized_pred.change_default_impl_check(ty::DefaultImplCheck::No)
+                           .unwrap_or(anonymized_pred)
+        }
 
         ty::Predicate::Equate(ref data) =>
             ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)),
@@ -554,6 +557,24 @@ pub fn impl_is_default(self, node_item_def_id: DefId) -> bool {
     pub fn impl_item_is_final(self, node_item: &NodeItem<hir::Defaultness>) -> bool {
         node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id())
     }
+
+    pub fn default_impl_implement_all_methods(self, node_item_def_id: DefId) -> bool {
+        if let Some(impl_trait_ref) = self.impl_trait_ref(node_item_def_id) {
+            let trait_def = self.trait_def(impl_trait_ref.def_id);
+            for trait_item in self.associated_items(impl_trait_ref.def_id) {
+                let is_implemented = trait_def.ancestors(self, node_item_def_id)
+                    .defs(self, trait_item.name, trait_item.kind, impl_trait_ref.def_id)
+                    .next()
+                    .map(|node_item| !node_item.node.is_from_trait())
+                    .unwrap_or(false);
+
+                if !is_implemented {
+                    return false;
+                }
+            }
+        }
+        true
+    }
 }
 
 pub enum TupleArgumentsFlag { Yes, No }
index 63bf52a9bdf786d7603cf2cf43f8e4a012927d0f..0bc092d99eba1cef464e87514db77ad0b3e39534 100644 (file)
@@ -9,14 +9,19 @@
 // except according to those terms.
 
 use hir::def_id::DefId;
-use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
-use ty::subst::Kind;
+use ty::{self, Ty, TypeFoldable, Substs, TyCtxt, AssociatedKind, AssociatedItemContainer};
+use ty::subst::{Kind, Subst};
 use traits;
 use syntax::abi::Abi;
 use util::ppaux;
 
 use std::fmt;
 
+use syntax_pos::{BytePos, Span};
+use syntax::ext::hygiene::SyntaxContext;
+use hir::map::Node::NodeTraitItem;
+use hir;
+
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct Instance<'tcx> {
     pub def: InstanceDef<'tcx>,
@@ -260,6 +265,13 @@ fn resolve_associated_item<'a, 'tcx>(
         traits::VtableImpl(impl_data) => {
             let (def_id, substs) = traits::find_associated_item(
                 tcx, trait_item, rcvr_substs, &impl_data);
+
+            check_unimplemented_trait_item(tcx,
+                                           impl_data.impl_def_id,
+                                           def_id,
+                                           trait_id,
+                                           trait_item);
+
             let substs = tcx.erase_regions(&substs);
             Some(ty::Instance::new(def_id, substs))
         }
@@ -363,3 +375,108 @@ fn fn_once_adapter_instance<'a, 'tcx>(
     debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
     Instance { def, substs }
 }
+
+fn check_unimplemented_trait_item<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    impl_def_id: DefId,
+    trait_item_def_id: DefId,
+    trait_id: DefId,
+    trait_item: &ty::AssociatedItem)
+{
+    // if trait_item_def_id is a trait item and it doesn't have a default trait implementation
+    // the resolution has found an unimplemented trait item inside a default impl
+    if tcx.impl_is_default(impl_def_id) {
+        let is_unimplemented_trait_item = match tcx.hir.as_local_node_id(trait_item_def_id) {
+            Some(node_id) =>
+                match tcx.hir.find(node_id) {
+                    Some(NodeTraitItem(item)) => {
+                        if let hir::TraitItemKind::Method(_,
+                                                          hir::TraitMethod::Provided(_))
+                                                          = item.node {
+                            false
+                        } else {
+                            true
+                        }
+                    },
+                    _ => false
+                }
+            None => {
+                let item = tcx.global_tcx().associated_item(trait_item_def_id);
+                match item.kind {
+                    AssociatedKind::Method => match item.container {
+                        AssociatedItemContainer::TraitContainer(_) => {
+                            !item.defaultness.has_value()
+                        }
+                        _ => false
+                    }
+                    _ => false
+                }
+            }
+        };
+
+        if is_unimplemented_trait_item {
+            let mut err = tcx.sess.struct_err(&format!("the trait method `{}` \
+                                                        is not implemented",
+                                               trait_item.name));
+
+            let mut help_messages = Vec::new();
+            help_messages.push(
+                if impl_def_id.is_local() {
+                    let item = tcx.hir
+                                  .expect_item(
+                                    tcx.hir
+                                       .as_local_node_id(impl_def_id).unwrap()
+                                  );
+                    (item.span, format!("implement it inside this `default impl`"))
+                } else {
+                    (Span::new (
+                        BytePos(0),
+                        BytePos(0),
+                        SyntaxContext::empty()
+                    ),
+                    format!("implement it inside the {} `default impl`",
+                            tcx.item_path_str(impl_def_id)))
+                }
+            );
+
+            help_messages.push(
+                if trait_id.is_local() {
+                    let trait_item = tcx.hir
+                                        .expect_item(
+                                          tcx.hir
+                                             .as_local_node_id(trait_id).unwrap()
+                                        );
+                    (trait_item.span, format!("provide a default method implementation \
+                                             inside this `trait`"))
+                } else {
+                    (Span::new (
+                        BytePos(0),
+                        BytePos(0),
+                        SyntaxContext::empty()
+                    ),
+                    format!("provide a default method implementation \
+                             inside the {} `trait`",
+                            tcx.item_path_str(trait_id)))
+                }
+            );
+
+            help_messages.sort_by(|&(a,_), &(b,_)| a.partial_cmp(&b).unwrap());
+
+            let mut cnjs = vec!["or ", "either "];
+            help_messages.iter().for_each(|&(span, ref msg)| {
+                let mut help_msg = String::from(cnjs.pop().unwrap_or(""));
+                help_msg.push_str(&msg);
+
+                if span.data().lo == BytePos(0) && span.data().hi == BytePos(0) {
+                    err.help(&help_msg);
+                } else {
+                    err.span_help(span, &help_msg);
+                }
+            });
+
+            err.note(&format!("a `default impl` doesn't need to include all \
+                               items from the trait"));
+            err.emit();
+        }
+    }
+}
\ No newline at end of file
index f52f2ea0f9fc8258b9d93964c6694a1da0cb9e9a..31cb4a64286955e7d9c2a23d9cbd341d111f3c42 100644 (file)
@@ -1070,9 +1070,13 @@ pub fn subst_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
     }
 }
 
+#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub enum DefaultImplCheck { Yes, No, }
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct TraitPredicate<'tcx> {
-    pub trait_ref: TraitRef<'tcx>
+    pub trait_ref: TraitRef<'tcx>,
+    pub default_impl_check: DefaultImplCheck
 }
 pub type PolyTraitPredicate<'tcx> = ty::Binder<TraitPredicate<'tcx>>;
 
@@ -1180,7 +1184,8 @@ fn to_predicate(&self) -> Predicate<'tcx> {
         assert!(!self.has_escaping_regions());
 
         ty::Predicate::Trait(ty::Binder(ty::TraitPredicate {
-            trait_ref: self.clone()
+            trait_ref: self.clone(),
+            default_impl_check: DefaultImplCheck::No
         }))
     }
 }
@@ -1298,6 +1303,36 @@ pub fn to_opt_type_outlives(&self) -> Option<PolyTypeOutlivesPredicate<'tcx>> {
             }
         }
     }
+
+    pub fn change_default_impl_check(&self, default_impl_check: ty::DefaultImplCheck)
+        -> Option<Predicate<'tcx>> {
+        match *self {
+            Predicate::Trait(ref t) => {
+                if t.skip_binder().default_impl_check != default_impl_check {
+                    Some(
+                        Predicate::Trait(ty::Binder(ty::TraitPredicate {
+                            trait_ref: t.skip_binder().trait_ref,
+                            default_impl_check: default_impl_check
+                        }))
+                    )
+                } else {
+                    None
+                }
+            }
+            Predicate::Trait(..) |
+            Predicate::Projection(..) |
+            Predicate::Equate(..) |
+            Predicate::Subtype(..) |
+            Predicate::RegionOutlives(..) |
+            Predicate::WellFormed(..) |
+            Predicate::ObjectSafe(..) |
+            Predicate::ClosureKind(..) |
+            Predicate::TypeOutlives(..) |
+            Predicate::ConstEvaluatable(..) => {
+                None
+            }
+        }
+    }
 }
 
 /// Represents the bounds declared on a particular set of type
index 0dc1338fff8600c0782a8f83e5ad1b6c877350e5..122a76ca6253c2924a0fa66868d7d27c95bb53b6 100644 (file)
@@ -278,7 +278,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
                              -> Option<ty::TraitPredicate<'tcx>> {
         tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate {
-            trait_ref,
+            trait_ref: trait_ref,
+            default_impl_check: self.default_impl_check
         })
     }
 }
@@ -1127,7 +1128,8 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
 impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::TraitPredicate {
-            trait_ref: self.trait_ref.fold_with(folder)
+            trait_ref: self.trait_ref.fold_with(folder),
+            default_impl_check: self.default_impl_check
         }
     }
 
index 1593b452cdffc3c4541819d71e1e8cb36a2d58d1..542bf12ecddc29343588d8b325c3a9eb4910a69c 100644 (file)
@@ -582,7 +582,10 @@ pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a
 
     pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
         // Note that we preserve binding levels
-        Binder(ty::TraitPredicate { trait_ref: self.0.clone() })
+        Binder(ty::TraitPredicate {
+            trait_ref: self.0.clone(),
+            default_impl_check: ty::DefaultImplCheck::No
+        })
     }
 }
 
index 37d1c568515b546e82bfb848300bc57e2c411df3..8b7c9d505bc5bb8106dda640e7e6dc218a2dcd45 100644 (file)
@@ -1230,8 +1230,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 define_print! {
     ('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) {
         debug {
-            write!(f, "TraitPredicate({:?})",
-                   self.trait_ref)
+            let default_impl_check_value = match self.default_impl_check {
+                ty::DefaultImplCheck::Yes => "default_impl_check: yes",
+                ty::DefaultImplCheck::No => "default_impl_check: no",
+            };
+            write!(f, "TraitPredicate({:?}, {})",
+               self.trait_ref, default_impl_check_value)
         }
         display {
             print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref))
index f16187797d4e5127d2f6544683207a8cc244cb5c..0851075a0924f9e4cfce7650ca65c16a28f00043 100644 (file)
@@ -618,6 +618,18 @@ fn visit_terminator_kind(&mut self,
                                        self.output);
                 } else {
                     visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
+
+                    if tcx.sess.has_errors() {
+                        match func {
+                            &mir::Operand::Consume(_) => {}
+                            &mir::Operand::Constant(ref cst) => {
+                                tcx.sess
+                                   .span_note_without_error(cst.span,
+                                                            "the function call is here");
+                            }
+                        }
+                        tcx.sess.abort_if_errors();
+                    }
                 }
             }
             mir::TerminatorKind::Drop { ref location, .. } |
@@ -678,7 +690,10 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                              ty::ParamEnv::empty(traits::Reveal::All),
                                              def_id,
                                              substs).unwrap();
-        visit_instance_use(tcx, instance, is_direct_call, output);
+        if !tcx.sess.has_errors() {
+            // continue only if no errors are encountered during monomorphization
+            visit_instance_use(tcx, instance, is_direct_call, output);
+        }
     }
 }
 
index 1139ea5fbd364074c33abdf2c47d2fe2b12388e8..dc42aa8dc1a544cc84ef4166e00b43b4793316ed 100644 (file)
@@ -1378,7 +1378,10 @@ pub struct Bounds<'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
-    pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>)
+    pub fn predicates(&self,
+                      tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                      param_ty: Ty<'tcx>,
+                      default_impl_check: ty::DefaultImplCheck)
                       -> Vec<ty::Predicate<'tcx>>
     {
         let mut vec = Vec::new();
@@ -1402,7 +1405,16 @@ pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>)
         }
 
         for bound_trait_ref in &self.trait_bounds {
-            vec.push(bound_trait_ref.to_predicate());
+            vec.push(
+                if bound_trait_ref.skip_binder().def_id !=
+                   tcx.lang_items().sized_trait().unwrap() {
+                    bound_trait_ref.to_predicate()
+                                   .change_default_impl_check(default_impl_check)
+                                   .unwrap_or(bound_trait_ref.to_predicate())
+                } else {
+                    bound_trait_ref.to_predicate()
+                }
+            );
         }
 
         for projection in &self.projection_bounds {
index 4aed688027f767783bc65355b87936b28cade11a..d4180183aeffd0e49695bf4a80b82f40319ea7b1 100644 (file)
@@ -189,7 +189,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
     let generic_assumptions = tcx.predicates_of(self_type_did);
 
     let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs);
-    let assumptions_in_impl_context = assumptions_in_impl_context.predicates;
+    let assumptions_in_impl_context: Vec<ty::Predicate> =
+        assumptions_in_impl_context.predicates
+                                   .iter()
+                                   .map(|predicate| {
+                                       predicate.change_default_impl_check(ty::DefaultImplCheck::No)
+                                                .unwrap_or(predicate.clone())
+                                   }).collect();
 
     // An earlier version of this code attempted to do this checking
     // via the traits::fulfill machinery. However, it ran into trouble
@@ -211,7 +217,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
         // the analysis together via the fulfill , rather than the
         // repeated `contains` calls.
 
-        if !assumptions_in_impl_context.contains(&predicate) {
+        if !assumptions_in_impl_context.contains(
+                &predicate.change_default_impl_check(ty::DefaultImplCheck::No)
+                          .unwrap_or(predicate.clone())) {
             let item_span = tcx.hir.span(self_type_node_id);
             struct_span_err!(tcx.sess, drop_impl_span, E0367,
                              "The requirement `{}` is added only by the Drop impl.", predicate)
index f044b2c711e2049446fee6dbe11df2bacae0fc24..4fe2f5b574e67d6c040b183c93cc0b9799754260 100644 (file)
@@ -1395,7 +1395,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             .map(|node_item| !node_item.node.is_from_trait())
             .unwrap_or(false);
 
-        if !is_implemented {
+        if !is_implemented && !tcx.impl_is_default(impl_id) {
             if !trait_item.defaultness.has_value() {
                 missing_items.push(trait_item);
             } else if associated_type_overridden {
index 3668fc46ddc27b0e0fbba290fa762cc4f809f757..9c233a7a15d246160c15326a4b010a24eed15f6d 100644 (file)
@@ -25,6 +25,7 @@
 
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
+use rustc::ty::TypeFoldable;
 
 pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -343,8 +344,36 @@ fn check_impl(&mut self,
                                                   fcx.body_id,
                                                   &trait_ref,
                                                   ast_trait_ref.path.span);
+
+                    // not registering predicates associcated with a `default impl`
+                    // that doesn't implement all the trait items.
+                    // it's left to the trait selection to select those trait predicates
+                    // and trigger an `Unimplemented` error in case the defaul_impl_check
+                    // is applicable
+                    let impl_not_implement_trait =
+                        if fcx.tcx.impl_is_default(item_def_id) &&
+                           !fcx.tcx.default_impl_implement_all_methods(item_def_id) {
+                            true
+                        } else {
+                            false
+                        };
+
                     for obligation in obligations {
-                        fcx.register_predicate(obligation);
+                        let register = match obligation.predicate {
+                            ty::Predicate::Trait(..)  => {
+                                if impl_not_implement_trait &&
+                                   !obligation.predicate.has_param_types() {
+                                    false
+                                } else {
+                                    true
+                                }
+                            }
+                            _ => true
+                        };
+
+                        if register {
+                            fcx.register_predicate(obligation);
+                        }
                     }
                 }
                 None => {
index d5328a18c22400f52c5f5fb9b7e0ecede732a13b..40d69855c49a9530eafd04f83e0768073118f88b 100644 (file)
@@ -677,7 +677,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                       SizedByDefault::No,
                                       item.span);
 
-    let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+    let superbounds1 = superbounds1.predicates(tcx, self_param_ty, ty::DefaultImplCheck::No);
 
     // Convert any explicit superbounds in the where clause,
     // e.g. `trait Foo where Self : Bar`:
@@ -694,7 +694,11 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     ty::GenericPredicates {
         parent: None,
-        predicates: superbounds
+        predicates: superbounds.iter()
+                               .map(|predicate| {
+                                   predicate.change_default_impl_check(ty::DefaultImplCheck::Yes)
+                                            .unwrap_or(predicate.clone())
+                                }).collect()
     }
 }
 
@@ -1364,17 +1368,39 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let node = tcx.hir.get(node_id);
 
     let mut is_trait = None;
+    let mut default_impl_check = ty::DefaultImplCheck::No;
 
     let icx = ItemCtxt::new(tcx, def_id);
     let no_generics = hir::Generics::empty();
     let ast_generics = match node {
-        NodeTraitItem(item) => &item.generics,
-        NodeImplItem(item) => &item.generics,
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => {
+                    default_impl_check = ty::DefaultImplCheck::Yes;
+                    &item.generics
+                },
+                _ => &item.generics
+            }
+        }
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => {
+                    default_impl_check = ty::DefaultImplCheck::Yes;
+                    &item.generics
+                },
+                _ => &item.generics
+            }
+        }
 
         NodeItem(item) => {
             match item.node {
                 ItemFn(.., ref generics, _) |
                 ItemImpl(_, _, _, ref generics, ..) |
+                ItemStruct(_, ref generics) => {
+                    default_impl_check = ty::DefaultImplCheck::Yes;
+                    generics
+                }
+
                 ItemTy(_, ref generics) |
                 ItemEnum(_, ref generics) |
                 ItemStruct(_, ref generics) |
@@ -1415,7 +1441,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             debug!("explicit_predicates_of: bounds={:?}", bounds);
 
-            let predicates = bounds.predicates(tcx, anon_ty);
+            let predicates = bounds.predicates(tcx, anon_ty, ty::DefaultImplCheck::No);
 
             debug!("explicit_predicates_of: predicates={:?}", predicates);
 
@@ -1476,7 +1502,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     &param.bounds,
                                     SizedByDefault::Yes,
                                     param.span);
-        predicates.extend(bounds.predicates(tcx, param_ty));
+        predicates.extend(bounds.predicates(tcx, param_ty, default_impl_check));
     }
 
     // Add in the bounds that appear in the where-clause
@@ -1496,8 +1522,16 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                                     poly_trait_ref,
                                                                     ty,
                                                                     &mut projections);
-
-                            predicates.push(trait_ref.to_predicate());
+                            predicates.push(
+                               if trait_ref.skip_binder().def_id !=
+                                  tcx.lang_items().sized_trait().unwrap() {
+                                   trait_ref.to_predicate()
+                                            .change_default_impl_check(default_impl_check)
+                                            .unwrap_or(trait_ref.to_predicate())
+                               } else {
+                                   trait_ref.to_predicate()
+                               }
+                            );
 
                             for projection in &projections {
                                 predicates.push(projection.to_predicate());
@@ -1552,7 +1586,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         SizedByDefault::Yes,
                                         trait_item.span);
 
-            bounds.predicates(tcx, assoc_ty).into_iter()
+            bounds.predicates(tcx, assoc_ty, ty::DefaultImplCheck::No).into_iter()
         }))
     }
 
diff --git a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs b/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs
new file mode 100644 (file)
index 0000000..263f316
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 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.
+
+#![feature(specialization)]
+
+pub trait Foo {
+    fn foo_one(&self) -> &'static str;
+    fn foo_two(&self) -> &'static str;
+}
diff --git a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs b/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs
new file mode 100644 (file)
index 0000000..cee6fcf
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2014 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.
+
+#![feature(specialization)]
+
+pub trait Foo {
+    fn foo_one(&self) -> &'static str;
+    fn foo_two(&self) -> &'static str;
+}
+
+default impl<T> Foo for T {
+    fn foo_one(&self) -> &'static str {
+        "generic"
+    }
+}
diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs
new file mode 100644 (file)
index 0000000..54f6690
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2014 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.
+
+// aux-build:foo_trait_default_impl.rs
+
+#![feature(specialization)]
+
+extern crate foo_trait_default_impl;
+
+use foo_trait_default_impl::*;
+
+struct MyStruct;
+
+fn main() {
+    MyStruct.foo_two(); //~ NOTE the function call is here
+}
diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs
new file mode 100644 (file)
index 0000000..8e2de42
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+// aux-build:foo_trait.rs
+
+#![feature(specialization)]
+
+extern crate foo_trait;
+
+use foo_trait::{Foo};
+
+struct MyStruct;
+
+default impl Foo for MyStruct {
+    fn foo_one(&self) -> &'static str {
+        "generic"
+    }
+}
+//~^^^^^ HELP implement it inside this `default impl`
+
+fn main() {
+    MyStruct.foo_two(); //~ NOTE the function call is here
+}
diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs
new file mode 100644 (file)
index 0000000..d0db6e9
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+#![feature(specialization)]
+
+trait Foo {
+    fn foo_one(&self) -> &'static str;
+    fn foo_two(&self) -> &'static str;
+}
+//~^^^^ HELP provide a default method implementation inside this `trait`
+
+default impl<T> Foo for T {
+    fn foo_one(&self) -> &'static str {
+        "generic"
+    }
+}
+//~^^^^^ HELP implement it inside this `default impl`
+
+struct MyStruct;
+
+fn  main() {
+    MyStruct.foo_two(); //~ NOTE the function call is here
+}
diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs
new file mode 100644 (file)
index 0000000..81b85f5
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2014 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.
+
+// error-pattern: the trait bound `MyStruct: Draw` is not satisfied
+
+#![feature(specialization)]
+
+trait Draw {
+    fn draw(&self);
+    fn draw2(&self);
+}
+
+struct Screen {
+    pub components: Vec<Box<Draw>>,
+}
+
+impl Screen {
+    pub fn run(&self) {
+        for component in self.components.iter() {
+            component.draw();
+        }
+    }
+}
+
+default impl<T> Draw for T {
+    fn draw(&self) {
+        println!("draw");
+    }
+}
+
+struct MyStruct;
+
+fn main() {
+    let screen = Screen {
+        components: vec![
+            Box::new(MyStruct)
+        ]
+    };
+    screen.run();
+}
diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs
new file mode 100644 (file)
index 0000000..00cceeb
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2014 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.
+
+// error-pattern: the trait bound `MyStruct: Foo` is not satisfied
+
+#![feature(specialization)]
+
+trait Foo {
+    fn foo_one(&self) -> &'static str;
+    fn foo_two(&self) -> &'static str;
+}
+
+default impl<T> Foo for T {
+    fn foo_one(&self) -> &'static str {
+        "generic"
+    }
+}
+
+fn foo<T: Foo>(x: T) -> &'static str {
+    x.foo_one()
+}
+
+struct MyStruct;
+
+fn main() {
+    println!("{:?}", foo(MyStruct));
+}
diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs
new file mode 100644 (file)
index 0000000..51a6a9e
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2014 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.
+
+// error-pattern: the trait bound `MyStruct: Foo` is not satisfied
+
+#![feature(specialization)]
+
+trait Foo {
+    fn foo_one(&self) -> &'static str;
+    fn foo_two(&self) -> &'static str;
+}
+
+default impl<T> Foo for T {
+    fn foo_one(&self) -> &'static str {
+        "generic"
+    }
+}
+
+struct FooS;
+
+impl FooS{
+    fn foo<T: Foo>(&self, x: T) -> &'static str{
+        x.foo_one()
+    }
+}
+
+struct MyStruct;
+
+fn main() {
+    println!("{:?}", FooS.foo(MyStruct));
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs
new file mode 100644 (file)
index 0000000..3444dea
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2014 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.
+
+// error-pattern: the trait bound `MyStruct: SuperFoo` is not satisfied
+
+#![feature(specialization)]
+
+trait SuperFoo {
+    fn super_foo_one(&self) -> &'static str;
+    fn super_foo_two(&self) -> &'static str;
+}
+
+trait Foo: SuperFoo {
+    fn foo(&self) -> &'static str;
+}
+
+default impl<T> SuperFoo for T {
+    fn super_foo_one(&self) -> &'static str {
+        "generic"
+    }
+}
+
+struct MyStruct;
+
+impl Foo for MyStruct {
+    fn foo(&self) -> &'static str {
+        "foo"
+    }
+}
+
+fn main() {
+    println!("{:?}", MyStruct.foo());
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs
new file mode 100644 (file)
index 0000000..6af69e8
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2014 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.
+
+#![feature(specialization)]
+
+trait Foo<T> {
+    fn dummy(&self, t: T);
+}
+
+trait Bar<A> {
+    fn method<B>(&self) where A: Foo<B>;
+}
+
+struct S;
+struct X;
+
+default impl Foo<X> for X {}
+
+impl Bar<X> for isize {
+    fn method<U>(&self) where X: Foo<U> {
+    }
+}
+
+fn main() {
+    1.method::<X>();
+    //~^ ERROR the trait bound `X: Foo<X>` is not satisfied
+}
diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs
new file mode 100644 (file)
index 0000000..a2ea087
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2014 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.
+
+// error-pattern: the trait bound `MyStruct: Draw` is not satisfied
+
+#![feature(specialization)]
+
+trait Draw {
+    fn draw(&self);
+    fn draw2(&self);
+}
+
+struct Screen<T: Draw> {
+    pub components: Vec<T>,
+}
+
+impl<T> Screen<T>
+    where T: Draw {
+    pub fn run(&self) {
+        for component in self.components.iter() {
+            component.draw();
+        }
+    }
+}
+
+default impl Draw for MyStruct {
+    fn draw(&self) {
+        println!("draw");
+    }
+}
+
+struct MyStruct;
+
+fn main() {
+    let screen = Screen {
+        components: vec![
+            MyStruct
+        ]
+    };
+    screen.run();
+}
diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs
new file mode 100644 (file)
index 0000000..752b019
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+#![feature(specialization)]
+
+pub trait Foo {
+    fn foo_one(&self) -> &'static str;
+    fn foo_two(&self) -> &'static str {
+        "generic Trait"
+    }
+}
+
+default impl<T> Foo for T {
+    fn foo_one(&self) -> &'static str {
+        "generic"
+    }
+}
+
+default impl<T: Clone> Foo for T {
+    fn foo_two(&self) -> &'static str {
+        "generic Clone"
+    }
+}
\ No newline at end of file
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs
new file mode 100644 (file)
index 0000000..4ed37b3
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2014 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.
+
+#![feature(specialization)]
+
+trait Foo {
+    fn foo_one(&self) -> &'static str;
+    fn foo_two(&self) -> &'static str;
+}
+
+default impl<T> Foo for T {
+    fn foo_one(&self) -> &'static str {
+        "generic one"
+    }
+    fn foo_two(&self) -> &'static str {
+        "generic two"
+    }
+}
+
+fn foo_one<T: Foo>(x: T) -> &'static str {
+    x.foo_one()
+}
+
+fn foo_two<T: Foo>(x: T) -> &'static str {
+    x.foo_two()
+}
+
+struct MyStruct;
+
+fn main() {
+    assert!(foo_one(MyStruct) == "generic one");
+    assert!(foo_two(MyStruct) == "generic two");
+}
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs
new file mode 100644 (file)
index 0000000..5c0547b
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2014 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.
+
+// aux-build:foo_trait.rs
+
+#![feature(specialization)]
+
+extern crate foo_trait;
+
+use foo_trait::*;
+
+struct MyStruct;
+
+fn  main() {
+    assert!(MyStruct.foo_one() == "generic");
+    assert!(0u8.foo_two() == "generic Clone");
+    assert!(MyStruct.foo_two() == "generic Trait");
+}
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs
new file mode 100644 (file)
index 0000000..254d3be
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2014 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.
+
+#![feature(specialization)]
+
+trait Foo {
+    fn foo_one(&self) -> &'static str;
+    fn foo_two(&self) -> &'static str {
+        "generic Trait"
+    }
+}
+
+default impl<T> Foo for T {
+    fn foo_one(&self) -> &'static str {
+        "generic"
+    }
+}
+
+default impl<T: Clone> Foo for T {
+    fn foo_two(&self) -> &'static str {
+        "generic Clone"
+    }
+}
+
+struct MyStruct;
+
+fn  main() {
+    assert!(MyStruct.foo_one() == "generic");
+    assert!(0u8.foo_two() == "generic Clone");
+    assert!(MyStruct.foo_two() == "generic Trait");
+}
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs
new file mode 100644 (file)
index 0000000..409d2c7
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2014 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.
+
+#![feature(specialization)]
+
+trait Foo {
+    fn foo_one(&self) -> &'static str;
+    fn foo_two(&self) -> &'static str;
+}
+
+default impl<T> Foo for T {
+    fn foo_one(&self) -> &'static str {
+        "generic"
+    }
+}
+
+default impl<T: Clone> Foo for T {
+    fn foo_two(&self) -> &'static str {
+        "generic Clone"
+    }
+}
+
+struct MyStruct;
+
+fn  main() {
+    assert!(MyStruct.foo_one() == "generic");
+    assert!(0u8.foo_two() == "generic Clone");
+}