From f5c55ff379913b7acca2ae032120e74aaa4dd822 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Thu, 12 Oct 2017 17:38:44 +0000 Subject: [PATCH 1/5] support `default impl` for specialization a `default impl` need not include all items from the trait a `default impl` alone does not mean that a type implements the trait --- src/librustc/ich/impls_ty.rs | 3 +- src/librustc/traits/select.rs | 36 +++++- src/librustc/traits/util.rs | 25 +++- src/librustc/ty/instance.rs | 121 +++++++++++++++++- src/librustc/ty/mod.rs | 39 +++++- src/librustc/ty/structural_impls.rs | 6 +- src/librustc/ty/sty.rs | 5 +- src/librustc/util/ppaux.rs | 8 +- src/librustc_mir/monomorphize/collector.rs | 17 ++- src/librustc_typeck/astconv.rs | 16 ++- src/librustc_typeck/check/dropck.rs | 12 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 31 ++++- src/librustc_typeck/collect.rs | 52 ++++++-- .../defaultimpl/auxiliary/foo_trait.rs | 16 +++ .../auxiliary/foo_trait_default_impl.rs | 22 ++++ ...method-not-implemented-cross-crate-impl.rs | 23 ++++ ...tion-method-not-implemented-cross-crate.rs | 30 +++++ .../specialization-method-not-implemented.rs | 30 +++++ .../specialization-trait-bounds-casting.rs | 47 +++++++ .../specialization-trait-bounds-fn.rs | 34 +++++ .../specialization-trait-bounds-impl-item.rs | 38 ++++++ ...specialization-trait-bounds-super-trait.rs | 40 ++++++ .../specialization-trait-bounds-trait-item.rs | 34 +++++ .../specialization-trait-bounds-vec.rs | 48 +++++++ .../defaultimpl/auxiliary/foo_trait.rs | 30 +++++ .../specialization-trait-bounds.rs | 40 ++++++ ...-traits-impl-default-method-cross-crate.rs | 25 ++++ ...ecialization-traits-impl-default-method.rs | 38 ++++++ .../defaultimpl/specialization-traits-impl.rs | 35 +++++ 30 files changed, 870 insertions(+), 33 deletions(-) create mode 100644 src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 107779ec3fa..42724274eb7 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -218,7 +218,8 @@ impl_stable_hash_for!(enum ty::Visibility { }); 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 }); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4ed25646d43..ee6bf4180dd 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1083,12 +1083,39 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // 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 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // 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 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // 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, diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 898accb9021..9e0859c67a0 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn impl_item_is_final(self, node_item: &NodeItem) -> 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 } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 63bf52a9bdf..0bc092d99eb 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -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 diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9f..31cb4a64286 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1070,9 +1070,13 @@ impl<'a, 'gcx, 'tcx> Predicate<'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>; @@ -1180,7 +1184,8 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'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 @@ impl<'tcx> Predicate<'tcx> { } } } + + pub fn change_default_impl_check(&self, default_impl_check: ty::DefaultImplCheck) + -> Option> { + 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 diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 0dc1338fff8..122a76ca625 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -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> { 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 @@ impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { 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 } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 1593b452cdf..542bf12ecdd 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -582,7 +582,10 @@ impl<'tcx> PolyTraitRef<'tcx> { 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 + }) } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 37d1c568515..8b7c9d505bc 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1230,8 +1230,12 @@ define_print! { 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)) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index f16187797d4..0851075a092 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -618,6 +618,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { 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); + } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1139ea5fbd3..dc42aa8dc1a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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> { let mut vec = Vec::new(); @@ -1402,7 +1405,16 @@ impl<'a, 'gcx, 'tcx> Bounds<'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 { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 4aed688027f..d4180183aef 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -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 = + 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) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f044b2c711e..4fe2f5b574e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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 { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 3668fc46ddc..9c233a7a15d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -25,6 +25,7 @@ use errors::{DiagnosticBuilder, DiagnosticId}; 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 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { 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 => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d5328a18c22..40d69855c49 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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>, ¶m.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 index 00000000000..263f316f3c8 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs @@ -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 or the MIT license +// , 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 index 00000000000..cee6fcf7d9a --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs @@ -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 or the MIT license +// , 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 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 index 00000000000..54f6690aa9f --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs @@ -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 or the MIT license +// , 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 index 00000000000..8e2de42a099 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs @@ -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 or the MIT license +// , 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 index 00000000000..d0db6e996d8 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs @@ -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 or the MIT license +// , 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 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 index 00000000000..81b85f58998 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs @@ -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 or the MIT license +// , 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>, +} + +impl Screen { + pub fn run(&self) { + for component in self.components.iter() { + component.draw(); + } + } +} + +default impl 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 index 00000000000..00cceeb4db3 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs @@ -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 or the MIT license +// , 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 Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +fn 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 index 00000000000..51a6a9e2c6b --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs @@ -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 or the MIT license +// , 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 Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +struct FooS; + +impl FooS{ + fn 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 index 00000000000..3444dea39c2 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs @@ -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 or the MIT license +// , 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 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 index 00000000000..6af69e89316 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +trait Foo { + fn dummy(&self, t: T); +} + +trait Bar { + fn method(&self) where A: Foo; +} + +struct S; +struct X; + +default impl Foo for X {} + +impl Bar for isize { + fn method(&self) where X: Foo { + } +} + +fn main() { + 1.method::(); + //~^ ERROR the trait bound `X: Foo` 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 index 00000000000..a2ea087220f --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs @@ -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 or the MIT license +// , 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, +} + +impl Screen + 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 index 00000000000..752b0190ea6 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs @@ -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 or the MIT license +// , 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 Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +default impl 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 index 00000000000..4ed37b311ef --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs @@ -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 or the MIT license +// , 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 Foo for T { + fn foo_one(&self) -> &'static str { + "generic one" + } + fn foo_two(&self) -> &'static str { + "generic two" + } +} + +fn foo_one(x: T) -> &'static str { + x.foo_one() +} + +fn foo_two(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 index 00000000000..5c0547b0341 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs @@ -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 or the MIT license +// , 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 index 00000000000..254d3bebb90 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs @@ -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 or the MIT license +// , 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 Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +default impl 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 index 00000000000..409d2c78e77 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs @@ -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 or the MIT license +// , 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 Foo for T { + fn foo_one(&self) -> &'static str { + "generic" + } +} + +default impl 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"); +} From 13e80af159a709e5bb9a178b19b4319716261661 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Tue, 24 Oct 2017 09:55:57 +0000 Subject: [PATCH 2/5] support `default impl` for specialization a default impl should never be considered as implementing the trait on its own -- regardless of whether it contains all items or not --- src/librustc/ich/impls_ty.rs | 3 +- src/librustc/traits/select.rs | 36 +----- src/librustc/traits/util.rs | 25 +--- src/librustc/ty/instance.rs | 119 +----------------- src/librustc/ty/mod.rs | 39 +----- src/librustc/ty/structural_impls.rs | 6 +- src/librustc/ty/sty.rs | 5 +- src/librustc/ty/trait_def.rs | 12 +- src/librustc/util/ppaux.rs | 8 +- src/librustc_mir/monomorphize/collector.rs | 17 +-- src/librustc_typeck/astconv.rs | 16 +-- src/librustc_typeck/check/dropck.rs | 12 +- src/librustc_typeck/check/wfcheck.rs | 23 +--- src/librustc_typeck/collect.rs | 52 ++------ .../defaultimpl/auxiliary/foo_trait.rs | 16 --- .../specialization-default-projection.rs | 46 ------- .../specialization-default-types.rs | 45 ------- ...method-not-implemented-cross-crate-impl.rs | 23 ---- ...tion-method-not-implemented-cross-crate.rs | 30 ----- .../specialization-method-not-implemented.rs | 30 ----- .../specialization-trait-bounds-casting.rs | 47 ------- .../specialization-trait-bounds-impl-item.rs | 38 ------ ...specialization-trait-bounds-super-trait.rs | 40 ------ .../specialization-trait-bounds-trait-item.rs | 34 ----- .../specialization-trait-bounds-vec.rs | 48 ------- ...cialization-trait-item-not-implemented.rs} | 17 ++- ...> specialization-trait-not-implemented.rs} | 12 +- .../specialization/defaultimpl/assoc-fns.rs | 37 ------ .../defaultimpl/auxiliary/cross_crate.rs | 82 ------------ .../auxiliary/cross_crate_defaults.rs | 49 -------- .../defaultimpl/auxiliary/foo_trait.rs | 30 ----- .../defaultimpl/basics-unsafe.rs | 106 ---------------- .../specialization/defaultimpl/basics.rs | 106 ---------------- .../defaultimpl/cross-crate-defaults.rs | 49 -------- .../defaultimpl/cross-crate-no-gate.rs | 29 ----- .../specialization/defaultimpl/cross-crate.rs | 58 --------- .../defaultimpl/default-methods.rs | 94 -------------- .../defaultimpl/projection-alias.rs | 32 ----- .../specialization-trait-bounds.rs | 40 ------ ...cialization-trait-item-not-implemented.rs} | 17 ++- ...-traits-impl-default-method-cross-crate.rs | 25 ---- ...ecialization-traits-impl-default-method.rs | 38 ------ 42 files changed, 66 insertions(+), 1525 deletions(-) delete mode 100644 src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs delete mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs rename src/test/compile-fail/specialization/defaultimpl/{specialization-trait-bounds-fn.rs => specialization-trait-item-not-implemented.rs} (74%) rename src/test/compile-fail/specialization/defaultimpl/{auxiliary/foo_trait_default_impl.rs => specialization-trait-not-implemented.rs} (71%) delete mode 100644 src/test/run-pass/specialization/defaultimpl/assoc-fns.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/basics.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/cross-crate.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/default-methods.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/projection-alias.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs rename src/test/run-pass/specialization/defaultimpl/{specialization-traits-impl.rs => specialization-trait-item-not-implemented.rs} (74%) delete mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs delete mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 42724274eb7..107779ec3fa 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -218,8 +218,7 @@ impl_stable_hash_for!(enum ty::Visibility { }); impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); -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!(struct ty::TraitPredicate<'tcx> { trait_ref }); impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index ee6bf4180dd..4ed25646d43 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1083,39 +1083,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Treat negative impls as unimplemented - fn filter_negative_and_default_impls<'o>(&self, - candidate: SelectionCandidate<'tcx>, - stack: &TraitObligationStack<'o, 'tcx>) - -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - + fn filter_negative_impls(&self, candidate: SelectionCandidate<'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)) } @@ -1205,8 +1178,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Instead, we select the right impl now but report `Bar does // not implement Clone`. if candidates.len() == 1 { - return self.filter_negative_and_default_impls(candidates.pop().unwrap(), stack); + return self.filter_negative_impls(candidates.pop().unwrap()); } + // Winnow, but record the exact outcome of evaluation, which // is needed for specialization. let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| { @@ -1265,7 +1239,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Just one candidate left. - self.filter_negative_and_default_impls(candidates.pop().unwrap().candidate, stack) + self.filter_negative_impls(candidates.pop().unwrap().candidate) } fn is_knowable<'o>(&mut self, diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 9e0859c67a0..898accb9021 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -22,11 +22,8 @@ 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) => { - 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::Trait(ref data) => + ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)), ty::Predicate::Equate(ref data) => ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)), @@ -557,24 +554,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn impl_item_is_final(self, node_item: &NodeItem) -> 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 } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 0bc092d99eb..6c727c94f58 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -9,7 +9,7 @@ // except according to those terms. use hir::def_id::DefId; -use ty::{self, Ty, TypeFoldable, Substs, TyCtxt, AssociatedKind, AssociatedItemContainer}; +use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; use ty::subst::{Kind, Subst}; use traits; use syntax::abi::Abi; @@ -17,11 +17,6 @@ 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>, @@ -265,13 +260,6 @@ 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)) } @@ -375,108 +363,3 @@ 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 diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 31cb4a64286..f52f2ea0f9f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1070,13 +1070,9 @@ impl<'a, 'gcx, 'tcx> Predicate<'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 default_impl_check: DefaultImplCheck + pub trait_ref: TraitRef<'tcx> } pub type PolyTraitPredicate<'tcx> = ty::Binder>; @@ -1184,8 +1180,7 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { assert!(!self.has_escaping_regions()); ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { - trait_ref: self.clone(), - default_impl_check: DefaultImplCheck::No + trait_ref: self.clone() })) } } @@ -1303,36 +1298,6 @@ impl<'tcx> Predicate<'tcx> { } } } - - pub fn change_default_impl_check(&self, default_impl_check: ty::DefaultImplCheck) - -> Option> { - 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 diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 122a76ca625..0dc1338fff8 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -278,8 +278,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate { - trait_ref: trait_ref, - default_impl_check: self.default_impl_check + trait_ref, }) } } @@ -1128,8 +1127,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { 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), - default_impl_check: self.default_impl_check + trait_ref: self.trait_ref.fold_with(folder) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 542bf12ecdd..1593b452cdf 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -582,10 +582,7 @@ impl<'tcx> PolyTraitRef<'tcx> { pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { // Note that we preserve binding levels - Binder(ty::TraitPredicate { - trait_ref: self.0.clone(), - default_impl_check: ty::DefaultImplCheck::No - }) + Binder(ty::TraitPredicate { trait_ref: self.0.clone() }) } } diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 0fbf9f1bd58..33972df97fb 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -92,10 +92,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self_ty: Ty<'tcx>, mut f: F) { + let mut emit_impl = |impl_def_id: DefId| { + if !self.impl_is_default(impl_def_id) { + f(impl_def_id); + } + }; + let impls = self.trait_impls_of(def_id); for &impl_def_id in impls.blanket_impls.iter() { - f(impl_def_id); + emit_impl(impl_def_id); } // simplify_type(.., false) basically replaces type parameters and @@ -126,13 +132,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { - f(impl_def_id); + emit_impl(impl_def_id); } } } else { for v in impls.non_blanket_impls.values() { for &impl_def_id in v { - f(impl_def_id); + emit_impl(impl_def_id); } } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 8b7c9d505bc..37d1c568515 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1230,12 +1230,8 @@ define_print! { define_print! { ('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) { debug { - 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) + write!(f, "TraitPredicate({:?})", + self.trait_ref) } display { print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref)) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 0851075a092..f16187797d4 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -618,18 +618,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { 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, .. } | @@ -690,10 +678,7 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap(); - if !tcx.sess.has_errors() { - // continue only if no errors are encountered during monomorphization - visit_instance_use(tcx, instance, is_direct_call, output); - } + visit_instance_use(tcx, instance, is_direct_call, output); } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index dc42aa8dc1a..1139ea5fbd3 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1378,10 +1378,7 @@ pub struct Bounds<'tcx> { } impl<'a, 'gcx, 'tcx> Bounds<'tcx> { - pub fn predicates(&self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - param_ty: Ty<'tcx>, - default_impl_check: ty::DefaultImplCheck) + pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>) -> Vec> { let mut vec = Vec::new(); @@ -1405,16 +1402,7 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { } for bound_trait_ref in &self.trait_bounds { - 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() - } - ); + vec.push(bound_trait_ref.to_predicate()); } for projection in &self.projection_bounds { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index d4180183aef..4aed688027f 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -189,13 +189,7 @@ 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: Vec = - assumptions_in_impl_context.predicates - .iter() - .map(|predicate| { - predicate.change_default_impl_check(ty::DefaultImplCheck::No) - .unwrap_or(predicate.clone()) - }).collect(); + let assumptions_in_impl_context = assumptions_in_impl_context.predicates; // An earlier version of this code attempted to do this checking // via the traits::fulfill machinery. However, it ran into trouble @@ -217,9 +211,7 @@ 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.change_default_impl_check(ty::DefaultImplCheck::No) - .unwrap_or(predicate.clone())) { + if !assumptions_in_impl_context.contains(&predicate) { 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) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9c233a7a15d..78113bdcc0e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -25,7 +25,6 @@ use errors::{DiagnosticBuilder, DiagnosticId}; 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>, @@ -346,28 +345,10 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { 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 - }; - + let impl_is_default = fcx.tcx.impl_is_default(item_def_id); for obligation in obligations { let register = match obligation.predicate { - ty::Predicate::Trait(..) => { - if impl_not_implement_trait && - !obligation.predicate.has_param_types() { - false - } else { - true - } - } + ty::Predicate::Trait(..) => !impl_is_default, _ => true }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 40d69855c49..d5328a18c22 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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, ty::DefaultImplCheck::No); + let superbounds1 = superbounds1.predicates(tcx, self_param_ty); // Convert any explicit superbounds in the where clause, // e.g. `trait Foo where Self : Bar`: @@ -694,11 +694,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::GenericPredicates { parent: None, - predicates: superbounds.iter() - .map(|predicate| { - predicate.change_default_impl_check(ty::DefaultImplCheck::Yes) - .unwrap_or(predicate.clone()) - }).collect() + predicates: superbounds } } @@ -1368,39 +1364,17 @@ 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) => { - 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 - } - } + NodeTraitItem(item) => &item.generics, + NodeImplItem(item) => &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) | @@ -1441,7 +1415,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, ty::DefaultImplCheck::No); + let predicates = bounds.predicates(tcx, anon_ty); debug!("explicit_predicates_of: predicates={:?}", predicates); @@ -1502,7 +1476,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ¶m.bounds, SizedByDefault::Yes, param.span); - predicates.extend(bounds.predicates(tcx, param_ty, default_impl_check)); + predicates.extend(bounds.predicates(tcx, param_ty)); } // Add in the bounds that appear in the where-clause @@ -1522,16 +1496,8 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, poly_trait_ref, ty, &mut projections); - 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() - } - ); + + predicates.push(trait_ref.to_predicate()); for projection in &projections { predicates.push(projection.to_predicate()); @@ -1586,7 +1552,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, SizedByDefault::Yes, trait_item.span); - bounds.predicates(tcx, assoc_ty, ty::DefaultImplCheck::No).into_iter() + bounds.predicates(tcx, assoc_ty).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 deleted file mode 100644 index 263f316f3c8..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait.rs +++ /dev/null @@ -1,16 +0,0 @@ -// 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 or the MIT license -// , 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/specialization-default-projection.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs deleted file mode 100644 index ad55f44255b..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Make sure we can't project defaulted associated types - -trait Foo { - type Assoc; -} - -default impl Foo for T { - type Assoc = (); -} - -impl Foo for u8 { - type Assoc = String; -} - -fn generic() -> ::Assoc { - // `T` could be some downstream crate type that specializes (or, - // for that matter, `u8`). - - () //~ ERROR mismatched types -} - -fn monomorphic() -> () { - // Even though we know that `()` is not specialized in a - // downstream crate, typeck refuses to project here. - - generic::<()>() //~ ERROR mismatched types -} - -fn main() { - // No error here, we CAN project from `u8`, as there is no `default` - // in that impl. - let s: String = generic::(); - println!("{}", s); // bad news if this all compiles -} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs deleted file mode 100644 index 7353f7ac8c5..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// It should not be possible to use the concrete value of a defaulted -// associated type in the impl defining it -- otherwise, what happens -// if it's overridden? - -#![feature(specialization)] - -trait Example { - type Output; - fn generate(self) -> Self::Output; -} - -default impl Example for T { - type Output = Box; - fn generate(self) -> Self::Output { - Box::new(self) //~ ERROR mismatched types - } -} - -impl Example for bool { - type Output = bool; - fn generate(self) -> bool { self } -} - -fn trouble(t: T) -> Box { - Example::generate(t) //~ ERROR mismatched types -} - -fn weaponize() -> bool { - let b: Box = trouble(true); - *b -} - -fn main() { - weaponize(); -} 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 deleted file mode 100644 index 54f6690aa9f..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate-impl.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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 or the MIT license -// , 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 deleted file mode 100644 index 8e2de42a099..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented-cross-crate.rs +++ /dev/null @@ -1,30 +0,0 @@ -// 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 or the MIT license -// , 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 deleted file mode 100644 index d0db6e996d8..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-method-not-implemented.rs +++ /dev/null @@ -1,30 +0,0 @@ -// 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 or the MIT license -// , 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 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 deleted file mode 100644 index 81b85f58998..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-casting.rs +++ /dev/null @@ -1,47 +0,0 @@ -// 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 or the MIT license -// , 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>, -} - -impl Screen { - pub fn run(&self) { - for component in self.components.iter() { - component.draw(); - } - } -} - -default impl 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-impl-item.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs deleted file mode 100644 index 51a6a9e2c6b..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-impl-item.rs +++ /dev/null @@ -1,38 +0,0 @@ -// 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 or the MIT license -// , 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 Foo for T { - fn foo_one(&self) -> &'static str { - "generic" - } -} - -struct FooS; - -impl FooS{ - fn 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 deleted file mode 100644 index 3444dea39c2..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-super-trait.rs +++ /dev/null @@ -1,40 +0,0 @@ -// 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 or the MIT license -// , 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 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 deleted file mode 100644 index 6af69e89316..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-trait-item.rs +++ /dev/null @@ -1,34 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -trait Foo { - fn dummy(&self, t: T); -} - -trait Bar { - fn method(&self) where A: Foo; -} - -struct S; -struct X; - -default impl Foo for X {} - -impl Bar for isize { - fn method(&self) where X: Foo { - } -} - -fn main() { - 1.method::(); - //~^ ERROR the trait bound `X: Foo` 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 deleted file mode 100644 index a2ea087220f..00000000000 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-vec.rs +++ /dev/null @@ -1,48 +0,0 @@ -// 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 or the MIT license -// , 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, -} - -impl Screen - 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/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs similarity index 74% rename from src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs rename to src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 00cceeb4db3..323ff7b2db9 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-bounds-fn.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,8 +8,6 @@ // 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 { @@ -17,18 +15,17 @@ trait Foo { fn foo_two(&self) -> &'static str; } +struct MyStruct; + default impl Foo for T { fn foo_one(&self) -> &'static str { "generic" } } -fn foo(x: T) -> &'static str { - x.foo_one() -} - -struct MyStruct; +impl Foo for MyStruct {} +//~^ ERROR not all trait items implemented, missing: `foo_two` [E0046] fn main() { - println!("{:?}", foo(MyStruct)); -} + println!("{}", MyStruct.foo_one()); +} \ No newline at end of file diff --git a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs similarity index 71% rename from src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs rename to src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs index cee6fcf7d9a..36945e98b08 100644 --- a/src/test/compile-fail/specialization/defaultimpl/auxiliary/foo_trait_default_impl.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,13 +10,21 @@ #![feature(specialization)] -pub trait Foo { +trait Foo { fn foo_one(&self) -> &'static str; fn foo_two(&self) -> &'static str; } +struct MyStruct; + default impl Foo for T { fn foo_one(&self) -> &'static str { "generic" } } + + +fn main() { + println!("{}", MyStruct.foo_one()); + //~^ ERROR no method named `foo_one` found for type `MyStruct` in the current scope +} \ No newline at end of file diff --git a/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs b/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs deleted file mode 100644 index b99ba3d0f1c..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/assoc-fns.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that non-method associated functions can be specialized - -#![feature(specialization)] - -trait Foo { - fn mk() -> Self; -} - -default impl Foo for T { - fn mk() -> T { - T::default() - } -} - -impl Foo for Vec { - fn mk() -> Vec { - vec![0] - } -} - -fn main() { - let v1: Vec = Foo::mk(); - let v2: Vec = Foo::mk(); - - assert!(v1.len() == 0); - assert!(v2.len() == 1); -} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs deleted file mode 100644 index 71dd7c99009..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -pub trait Foo { - fn foo(&self) -> &'static str; -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic" - } -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone" - } -} - -default impl Foo for (T, U) where T: Clone, U: Clone { - fn foo(&self) -> &'static str { - "generic pair" - } -} - -default impl Foo for (T, T) { - fn foo(&self) -> &'static str { - "generic uniform pair" - } -} - -default impl Foo for (u8, u32) { - fn foo(&self) -> &'static str { - "(u8, u32)" - } -} - -default impl Foo for (u8, u8) { - fn foo(&self) -> &'static str { - "(u8, u8)" - } -} - -default impl Foo for Vec { - fn foo(&self) -> &'static str { - "generic Vec" - } -} - -impl Foo for Vec { - fn foo(&self) -> &'static str { - "Vec" - } -} - -impl Foo for String { - fn foo(&self) -> &'static str { - "String" - } -} - -impl Foo for i32 { - fn foo(&self) -> &'static str { - "i32" - } -} - -pub trait MyMarker {} -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone + MyMarker" - } -} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs deleted file mode 100644 index 9d0ea64fed4..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/auxiliary/cross_crate_defaults.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -#![feature(specialization)] - -// First, test only use of explicit `default` items: - -pub trait Foo { - fn foo(&self) -> bool; -} - -default impl Foo for T { - fn foo(&self) -> bool { false } -} - -impl Foo for i32 {} - -impl Foo for i64 { - fn foo(&self) -> bool { true } -} - -// Next, test mixture of explicit `default` and provided methods: - -pub trait Bar { - fn bar(&self) -> i32 { 0 } -} - -impl Bar for T {} // use the provided method - -impl Bar for i32 { - fn bar(&self) -> i32 { 1 } -} -impl<'a> Bar for &'a str {} - -default impl Bar for Vec { - fn bar(&self) -> i32 { 2 } -} -impl Bar for Vec {} -impl Bar for Vec { - fn bar(&self) -> i32 { 3 } -} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs deleted file mode 100644 index 752b0190ea6..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/auxiliary/foo_trait.rs +++ /dev/null @@ -1,30 +0,0 @@ -// 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 or the MIT license -// , 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 Foo for T { - fn foo_one(&self) -> &'static str { - "generic" - } -} - -default impl 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/basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs deleted file mode 100644 index 7daecc842f3..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/basics-unsafe.rs +++ /dev/null @@ -1,106 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Tests a variety of basic specialization scenarios and method -// dispatch for them. - -unsafe trait Foo { - fn foo(&self) -> &'static str; -} - -default unsafe impl Foo for T { - fn foo(&self) -> &'static str { - "generic" - } -} - -default unsafe impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone" - } -} - -default unsafe impl Foo for (T, U) where T: Clone, U: Clone { - fn foo(&self) -> &'static str { - "generic pair" - } -} - -default unsafe impl Foo for (T, T) { - fn foo(&self) -> &'static str { - "generic uniform pair" - } -} - -default unsafe impl Foo for (u8, u32) { - fn foo(&self) -> &'static str { - "(u8, u32)" - } -} - -default unsafe impl Foo for (u8, u8) { - fn foo(&self) -> &'static str { - "(u8, u8)" - } -} - -default unsafe impl Foo for Vec { - fn foo(&self) -> &'static str { - "generic Vec" - } -} - -default unsafe impl Foo for Vec { - fn foo(&self) -> &'static str { - "Vec" - } -} - -default unsafe impl Foo for String { - fn foo(&self) -> &'static str { - "String" - } -} - -default unsafe impl Foo for i32 { - fn foo(&self) -> &'static str { - "i32" - } -} - -struct NotClone; - -unsafe trait MyMarker {} -default unsafe impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone + MyMarker" - } -} - -#[derive(Clone)] -struct MarkedAndClone; -unsafe impl MyMarker for MarkedAndClone {} - -fn main() { - assert!(NotClone.foo() == "generic"); - assert!(0u8.foo() == "generic Clone"); - assert!(vec![NotClone].foo() == "generic"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); - assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/basics.rs b/src/test/run-pass/specialization/defaultimpl/basics.rs deleted file mode 100644 index 594f1e4fcdf..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/basics.rs +++ /dev/null @@ -1,106 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Tests a variety of basic specialization scenarios and method -// dispatch for them. - -trait Foo { - fn foo(&self) -> &'static str; -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic" - } -} - -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone" - } -} - -default impl Foo for (T, U) where T: Clone, U: Clone { - fn foo(&self) -> &'static str { - "generic pair" - } -} - -default impl Foo for (T, T) { - fn foo(&self) -> &'static str { - "generic uniform pair" - } -} - -default impl Foo for (u8, u32) { - fn foo(&self) -> &'static str { - "(u8, u32)" - } -} - -default impl Foo for (u8, u8) { - fn foo(&self) -> &'static str { - "(u8, u8)" - } -} - -default impl Foo for Vec { - fn foo(&self) -> &'static str { - "generic Vec" - } -} - -impl Foo for Vec { - fn foo(&self) -> &'static str { - "Vec" - } -} - -impl Foo for String { - fn foo(&self) -> &'static str { - "String" - } -} - -impl Foo for i32 { - fn foo(&self) -> &'static str { - "i32" - } -} - -struct NotClone; - -trait MyMarker {} -default impl Foo for T { - fn foo(&self) -> &'static str { - "generic Clone + MyMarker" - } -} - -#[derive(Clone)] -struct MarkedAndClone; -impl MyMarker for MarkedAndClone {} - -fn main() { - assert!(NotClone.foo() == "generic"); - assert!(0u8.foo() == "generic Clone"); - assert!(vec![NotClone].foo() == "generic"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); - assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs deleted file mode 100644 index 19e1af15bdd..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/cross-crate-defaults.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:cross_crate_defaults.rs - -#![feature(specialization)] - -extern crate cross_crate_defaults; - -use cross_crate_defaults::*; - -struct LocalDefault; -struct LocalOverride; - -impl Foo for LocalDefault {} - -impl Foo for LocalOverride { - fn foo(&self) -> bool { true } -} - -fn test_foo() { - assert!(!0i8.foo()); - assert!(!0i32.foo()); - assert!(0i64.foo()); - - assert!(!LocalDefault.foo()); - assert!(LocalOverride.foo()); -} - -fn test_bar() { - assert!(0u8.bar() == 0); - assert!(0i32.bar() == 1); - assert!("hello".bar() == 0); - assert!(vec![()].bar() == 2); - assert!(vec![0i32].bar() == 2); - assert!(vec![0i64].bar() == 3); -} - -fn main() { - test_foo(); - test_bar(); -} diff --git a/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs deleted file mode 100644 index 67cc694ae12..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/cross-crate-no-gate.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that specialization works even if only the upstream crate enables it - -// aux-build:cross_crate.rs - -extern crate cross_crate; - -use cross_crate::*; - -fn main() { - assert!(0u8.foo() == "generic Clone"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/cross-crate.rs deleted file mode 100644 index f1ad105db8f..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/cross-crate.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:cross_crate.rs - -#![feature(specialization)] - -extern crate cross_crate; - -use cross_crate::*; - -struct NotClone; - -#[derive(Clone)] -struct MarkedAndClone; -impl MyMarker for MarkedAndClone {} - -struct MyType(T); -default impl Foo for MyType { - fn foo(&self) -> &'static str { - "generic MyType" - } -} - -impl Foo for MyType { - fn foo(&self) -> &'static str { - "MyType" - } -} - -struct MyOtherType; -impl Foo for MyOtherType {} - -fn main() { - assert!(NotClone.foo() == "generic"); - assert!(0u8.foo() == "generic Clone"); - assert!(vec![NotClone].foo() == "generic"); - assert!(vec![0u8].foo() == "generic Vec"); - assert!(vec![0i32].foo() == "Vec"); - assert!(0i32.foo() == "i32"); - assert!(String::new().foo() == "String"); - assert!(((), 0).foo() == "generic pair"); - assert!(((), ()).foo() == "generic uniform pair"); - assert!((0u8, 0u32).foo() == "(u8, u32)"); - assert!((0u8, 0u8).foo() == "(u8, u8)"); - assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); - - assert!(MyType(()).foo() == "generic MyType"); - assert!(MyType(0u8).foo() == "MyType"); - assert!(MyOtherType.foo() == "generic"); -} diff --git a/src/test/run-pass/specialization/defaultimpl/default-methods.rs b/src/test/run-pass/specialization/defaultimpl/default-methods.rs deleted file mode 100644 index 4ac9afc1c89..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/default-methods.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Test that default methods are cascaded correctly - -// First, test only use of explicit `default` items: - -trait Foo { - fn foo(&self) -> bool; -} - -// Specialization tree for Foo: -// -// T -// / \ -// i32 i64 - -default impl Foo for T { - fn foo(&self) -> bool { false } -} - -impl Foo for i32 {} - -impl Foo for i64 { - fn foo(&self) -> bool { true } -} - -fn test_foo() { - assert!(!0i8.foo()); - assert!(!0i32.foo()); - assert!(0i64.foo()); -} - -// Next, test mixture of explicit `default` and provided methods: - -trait Bar { - fn bar(&self) -> i32 { 0 } -} - -// Specialization tree for Bar. -// Uses of $ designate that method is provided -// -// $Bar (the trait) -// | -// T -// /|\ -// / | \ -// / | \ -// / | \ -// / | \ -// / | \ -// $i32 &str $Vec -// /\ -// / \ -// Vec $Vec - -// use the provided method -impl Bar for T {} - -impl Bar for i32 { - fn bar(&self) -> i32 { 1 } -} -impl<'a> Bar for &'a str {} - -default impl Bar for Vec { - fn bar(&self) -> i32 { 2 } -} -impl Bar for Vec {} -impl Bar for Vec { - fn bar(&self) -> i32 { 3 } -} - -fn test_bar() { - assert!(0u8.bar() == 0); - assert!(0i32.bar() == 1); - assert!("hello".bar() == 0); - assert!(vec![()].bar() == 2); - assert!(vec![0i32].bar() == 2); - assert!(vec![0i64].bar() == 3); -} - -fn main() { - test_foo(); - test_bar(); -} diff --git a/src/test/run-pass/specialization/defaultimpl/projection-alias.rs b/src/test/run-pass/specialization/defaultimpl/projection-alias.rs deleted file mode 100644 index 2397c3e2bff..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/projection-alias.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(specialization)] - -// Regression test for ICE when combining specialized associated types and type -// aliases - -trait Id_ { - type Out; -} - -type Id = ::Out; - -default impl Id_ for T { - type Out = T; -} - -fn test_proection() { - let x: Id = panic!(); -} - -fn main() { - -} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs deleted file mode 100644 index 4ed37b311ef..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/specialization-trait-bounds.rs +++ /dev/null @@ -1,40 +0,0 @@ -// 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 or the MIT license -// , 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 Foo for T { - fn foo_one(&self) -> &'static str { - "generic one" - } - fn foo_two(&self) -> &'static str { - "generic two" - } -} - -fn foo_one(x: T) -> &'static str { - x.foo_one() -} - -fn foo_two(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.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs similarity index 74% rename from src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs rename to src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 409d2c78e77..f8eb57bad77 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl.rs +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -15,21 +15,20 @@ trait Foo { fn foo_two(&self) -> &'static str; } +struct MyStruct; + default impl Foo for T { fn foo_one(&self) -> &'static str { "generic" } } -default impl Foo for T { +impl Foo for MyStruct { fn foo_two(&self) -> &'static str { - "generic Clone" + self.foo_one() } } -struct MyStruct; - -fn main() { - assert!(MyStruct.foo_one() == "generic"); - assert!(0u8.foo_two() == "generic Clone"); -} +fn main() { + assert!(MyStruct.foo_two() == "generic"); +} \ No newline at end of file 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 deleted file mode 100644 index 5c0547b0341..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method-cross-crate.rs +++ /dev/null @@ -1,25 +0,0 @@ -// 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 or the MIT license -// , 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 deleted file mode 100644 index 254d3bebb90..00000000000 --- a/src/test/run-pass/specialization/defaultimpl/specialization-traits-impl-default-method.rs +++ /dev/null @@ -1,38 +0,0 @@ -// 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 or the MIT license -// , 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 Foo for T { - fn foo_one(&self) -> &'static str { - "generic" - } -} - -default impl 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"); -} From b20bfb1fc283ae3b0c4f3d712919f4fc3522517b Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Tue, 21 Nov 2017 07:27:20 +0000 Subject: [PATCH 3/5] support `default impl` for specialization not skipping any wfchecks on default impls --- src/librustc/infer/mod.rs | 4 +++ src/librustc/traits/select.rs | 29 ++++++++++++------- src/librustc/ty/trait_def.rs | 12 ++------ src/librustc_typeck/check/mod.rs | 18 ++++++++++++ src/librustc_typeck/check/wfcheck.rs | 12 +------- .../defaultimpl/specialization-wfcheck.rs | 18 ++++++++++++ 6 files changed, 63 insertions(+), 30 deletions(-) create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 07c5b319970..a2d5af67516 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -181,6 +181,9 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // obligations within. This is expected to be done 'late enough' // that all type inference variables have been bound and so forth. region_obligations: RefCell)>>, + + // true if trait selection in this context should emit `default impl` candiates + pub emit_defaul_impl_candidates: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -452,6 +455,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), region_obligations: RefCell::new(vec![]), + emit_defaul_impl_candidates: Cell::new(false) })) } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4ed25646d43..b58a154275c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1296,6 +1296,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return false; } + // Using local cache if the infcx can emit `default impls` + if self.infcx.emit_defaul_impl_candidates.get() { + return false; + } + + // Otherwise, we can use the global cache. true } @@ -1714,18 +1720,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - self.probe(|this, snapshot| { /* [1] */ - match this.match_impl(impl_def_id, obligation, snapshot) { - Ok(skol_map) => { - candidates.vec.push(ImplCandidate(impl_def_id)); + if self.infcx().emit_defaul_impl_candidates.get() || + !self.tcx().impl_is_default(impl_def_id) { + self.probe(|this, snapshot| { /* [1] */ + match this.match_impl(impl_def_id, obligation, snapshot) { + Ok(skol_map) => { + candidates.vec.push(ImplCandidate(impl_def_id)); - // NB: we can safely drop the skol map - // since we are in a probe [1] - mem::drop(skol_map); + // NB: we can safely drop the skol map + // since we are in a probe [1] + mem::drop(skol_map); + } + Err(_) => { } } - Err(_) => { } - } - }); + }); + } } ); diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 33972df97fb..0fbf9f1bd58 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -92,16 +92,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self_ty: Ty<'tcx>, mut f: F) { - let mut emit_impl = |impl_def_id: DefId| { - if !self.impl_is_default(impl_def_id) { - f(impl_def_id); - } - }; - let impls = self.trait_impls_of(def_id); for &impl_def_id in impls.blanket_impls.iter() { - emit_impl(impl_def_id); + f(impl_def_id); } // simplify_type(.., false) basically replaces type parameters and @@ -132,13 +126,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { - emit_impl(impl_def_id); + f(impl_def_id); } } } else { for v in impls.non_blanket_impls.values() { for &impl_def_id in v { - emit_impl(impl_def_id); + f(impl_def_id); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4fe2f5b574e..a622f0b6732 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1745,6 +1745,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { + FnCtxt::set_emit_default_impl_candidates(inh, body_id); + FnCtxt { body_id, param_env, @@ -1763,6 +1765,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + fn set_emit_default_impl_candidates(inh: &'a Inherited<'a, 'gcx, 'tcx>, + body_id: ast::NodeId) { + inh.infcx.emit_defaul_impl_candidates.set( + match inh.tcx.hir.find(body_id) { + Some(Node::NodeItem(..)) => { + if inh.tcx.impl_is_default(inh.tcx.hir.local_def_id(body_id)) { + true + } else { + false + } + }, + _ => false + } + ); + } + pub fn sess(&self) -> &Session { &self.tcx.sess } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 78113bdcc0e..3668fc46ddc 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -343,18 +343,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fcx.body_id, &trait_ref, ast_trait_ref.path.span); - - // not registering predicates associcated with a `default impl` - let impl_is_default = fcx.tcx.impl_is_default(item_def_id); for obligation in obligations { - let register = match obligation.predicate { - ty::Predicate::Trait(..) => !impl_is_default, - _ => true - }; - - if register { - fcx.register_predicate(obligation); - } + fcx.register_predicate(obligation); } } None => { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs new file mode 100644 index 00000000000..5f6844d0c82 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -0,0 +1,18 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +trait Foo<'a, T: Eq + 'a> { } + +default impl Foo<'static, U> for () {} +//~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied + +fn main(){} \ No newline at end of file From 2f22a929c6d231d9a9d872ac40b5c9e36daabe38 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Wed, 7 Feb 2018 06:58:01 +0000 Subject: [PATCH 4/5] add Self: Trait<..> inside the param_env of a default impl --- src/librustc/infer/mod.rs | 4 --- src/librustc/traits/select.rs | 27 ++++++++++++++----- src/librustc/ty/instance.rs | 2 +- src/librustc/ty/mod.rs | 25 ++++++++++++++++- src/librustc_typeck/check/mod.rs | 18 ------------- ...ecialization-trait-item-not-implemented.rs | 2 +- .../specialization-trait-not-implemented.rs | 2 +- .../defaultimpl/specialization-wfcheck.rs | 2 +- ...ecialization-trait-item-not-implemented.rs | 2 +- 9 files changed, 49 insertions(+), 35 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index a2d5af67516..07c5b319970 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -181,9 +181,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // obligations within. This is expected to be done 'late enough' // that all type inference variables have been bound and so forth. region_obligations: RefCell)>>, - - // true if trait selection in this context should emit `default impl` candiates - pub emit_defaul_impl_candidates: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -455,7 +452,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), region_obligations: RefCell::new(vec![]), - emit_defaul_impl_candidates: Cell::new(false) })) } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index b58a154275c..aa43bf8ca2e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1296,12 +1296,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return false; } - // Using local cache if the infcx can emit `default impls` - if self.infcx.emit_defaul_impl_candidates.get() { - return false; - } - - // Otherwise, we can use the global cache. true } @@ -1716,11 +1710,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); + // Check if default impls should be emitted. + // default impls are emitted if the param_env is refered to a default impl. + // The param_env should contain a Self: Trait<..> predicate in those cases + let self_trait_is_present:Vec<&ty::Predicate<'tcx>> = + obligation.param_env + .caller_bounds + .iter() + .filter(|predicate| { + match **predicate { + ty::Predicate::Trait(ref trait_predicate) => { + trait_predicate.def_id() == + obligation.predicate.def_id() && + obligation.predicate.0.trait_ref.self_ty() == + trait_predicate.skip_binder().self_ty() + } + _ => false + } + }).collect::>>(); + self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - if self.infcx().emit_defaul_impl_candidates.get() || + if self_trait_is_present.len() > 0 || !self.tcx().impl_is_default(impl_def_id) { self.probe(|this, snapshot| { /* [1] */ match this.match_impl(impl_def_id, obligation, snapshot) { diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 6c727c94f58..63bf52a9bdf 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; -use ty::subst::{Kind, Subst}; +use ty::subst::Kind; use traits; use syntax::abi::Abi; use util::ppaux; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f52f2ea0f9f..52d33c750f8 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2606,8 +2606,31 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { // Compute the bounds on Self and the type parameters. + let mut predicates = tcx.predicates_of(def_id); + match tcx.hir.as_local_node_id(def_id) + .and_then(|node_id| tcx.hir.find(node_id)) + .and_then(|item| { + match item { + hir::map::NodeItem(..) => { + if tcx.impl_is_default(def_id) { + tcx.impl_trait_ref(def_id) + } else { + None + } + } + _ => None + } + }) { + Some(trait_ref) => + predicates.predicates + .push( + trait_ref.to_poly_trait_ref() + .to_predicate() + ), + None => {} + } - let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); + let bounds = predicates.instantiate_identity(tcx); let predicates = bounds.predicates; // Finally, we have to normalize the bounds in the environment, in diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a622f0b6732..4fe2f5b574e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1745,8 +1745,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { - FnCtxt::set_emit_default_impl_candidates(inh, body_id); - FnCtxt { body_id, param_env, @@ -1765,22 +1763,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn set_emit_default_impl_candidates(inh: &'a Inherited<'a, 'gcx, 'tcx>, - body_id: ast::NodeId) { - inh.infcx.emit_defaul_impl_candidates.set( - match inh.tcx.hir.find(body_id) { - Some(Node::NodeItem(..)) => { - if inh.tcx.impl_is_default(inh.tcx.hir.local_def_id(body_id)) { - true - } else { - false - } - }, - _ => false - } - ); - } - pub fn sess(&self) -> &Session { &self.tcx.sess } diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 323ff7b2db9..072507851d7 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -28,4 +28,4 @@ impl Foo for MyStruct {} fn main() { println!("{}", MyStruct.foo_one()); -} \ No newline at end of file +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs index 36945e98b08..d020a677577 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -27,4 +27,4 @@ default impl Foo for T { fn main() { println!("{}", MyStruct.foo_one()); //~^ ERROR no method named `foo_one` found for type `MyStruct` in the current scope -} \ No newline at end of file +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs index 5f6844d0c82..34229737992 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -15,4 +15,4 @@ trait Foo<'a, T: Eq + 'a> { } default impl Foo<'static, U> for () {} //~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied -fn main(){} \ No newline at end of file +fn main(){} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index f8eb57bad77..e11a3021497 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -31,4 +31,4 @@ impl Foo for MyStruct { fn main() { assert!(MyStruct.foo_two() == "generic"); -} \ No newline at end of file +} From 220bb22e1b621ad5a10a44080e3e1872d99f3e9f Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Wed, 14 Feb 2018 17:25:42 +0000 Subject: [PATCH 5/5] add Self: Trait<..> inside the param_env of a default impl --- src/libcore/iter/mod.rs | 6 +-- src/librustc/traits/select.rs | 42 +++++-------------- src/librustc/ty/mod.rs | 25 +---------- src/librustc_typeck/collect.rs | 20 ++++++++- ...ecialization-trait-item-not-implemented.rs | 2 + .../specialization-trait-not-implemented.rs | 4 ++ .../defaultimpl/specialization-wfcheck.rs | 2 + ...ecialization-trait-item-not-implemented.rs | 10 ++++- 8 files changed, 50 insertions(+), 61 deletions(-) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index bf8367d85fd..652e0027383 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -579,15 +579,15 @@ impl<'a, I, T: 'a> FusedIterator for Cloned {} #[doc(hidden)] -default unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned where I: TrustedRandomAccess, T: Clone { - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { self.it.get_unchecked(i).clone() } #[inline] - fn may_have_side_effect() -> bool { true } + default fn may_have_side_effect() -> bool { true } } #[doc(hidden)] diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index aa43bf8ca2e..4ed25646d43 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1710,44 +1710,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - // Check if default impls should be emitted. - // default impls are emitted if the param_env is refered to a default impl. - // The param_env should contain a Self: Trait<..> predicate in those cases - let self_trait_is_present:Vec<&ty::Predicate<'tcx>> = - obligation.param_env - .caller_bounds - .iter() - .filter(|predicate| { - match **predicate { - ty::Predicate::Trait(ref trait_predicate) => { - trait_predicate.def_id() == - obligation.predicate.def_id() && - obligation.predicate.0.trait_ref.self_ty() == - trait_predicate.skip_binder().self_ty() - } - _ => false - } - }).collect::>>(); - self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - if self_trait_is_present.len() > 0 || - !self.tcx().impl_is_default(impl_def_id) { - self.probe(|this, snapshot| { /* [1] */ - match this.match_impl(impl_def_id, obligation, snapshot) { - Ok(skol_map) => { - candidates.vec.push(ImplCandidate(impl_def_id)); + self.probe(|this, snapshot| { /* [1] */ + match this.match_impl(impl_def_id, obligation, snapshot) { + Ok(skol_map) => { + candidates.vec.push(ImplCandidate(impl_def_id)); - // NB: we can safely drop the skol map - // since we are in a probe [1] - mem::drop(skol_map); - } - Err(_) => { } + // NB: we can safely drop the skol map + // since we are in a probe [1] + mem::drop(skol_map); } - }); - } + Err(_) => { } + } + }); } ); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 52d33c750f8..f52f2ea0f9f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2606,31 +2606,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { // Compute the bounds on Self and the type parameters. - let mut predicates = tcx.predicates_of(def_id); - match tcx.hir.as_local_node_id(def_id) - .and_then(|node_id| tcx.hir.find(node_id)) - .and_then(|item| { - match item { - hir::map::NodeItem(..) => { - if tcx.impl_is_default(def_id) { - tcx.impl_trait_ref(def_id) - } else { - None - } - } - _ => None - } - }) { - Some(trait_ref) => - predicates.predicates - .push( - trait_ref.to_poly_trait_ref() - .to_predicate() - ), - None => {} - } - let bounds = predicates.instantiate_identity(tcx); + let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); let predicates = bounds.predicates; // Finally, we have to normalize the bounds in the environment, in diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d5328a18c22..1c8d22e4666 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1364,6 +1364,7 @@ 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 is_default_impl_trait = None; let icx = ItemCtxt::new(tcx, def_id); let no_generics = hir::Generics::empty(); @@ -1373,8 +1374,13 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { + ItemImpl(_, _, defaultness, ref generics, ..) => { + if defaultness.is_default() { + is_default_impl_trait = tcx.impl_trait_ref(def_id); + } + generics + } ItemFn(.., ref generics, _) | - ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -1446,6 +1452,18 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); } + // In default impls, we can assume that the self type implements + // the trait. So in: + // + // default impl Foo for Bar { .. } + // + // we add a default where clause `Foo: Bar`. We do a similar thing for traits + // (see below). Recall that a default impl is not itself an impl, but rather a + // set of defaults that can be incorporated into another impl. + if let Some(trait_ref) = is_default_impl_trait { + predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + } + // Collect the region predicates that were declared inline as // well. In the case of parameters declared on a fn or method, we // have to be careful to only iterate over early-bound regions. diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 072507851d7..eacec2e40f0 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that default impls do not have to supply all items but regular impls do. + #![feature(specialization)] trait Foo { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs index d020a677577..04ddf9ebb17 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that: +// - default impls do not have to supply all items and +// - a default impl does not count as an impl (in this case, an incomplete default impl). + #![feature(specialization)] trait Foo { diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs index 34229737992..445a59a373e 100644 --- a/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-wfcheck.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that a default impl still has to have a WF trait ref. + #![feature(specialization)] trait Foo<'a, T: Eq + 'a> { } diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index e11a3021497..fc731202005 100644 --- a/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/run-pass/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -8,18 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Tests that we can combine a default impl that supplies one method with a +// full impl that supplies the other, and they can invoke one another. + #![feature(specialization)] trait Foo { fn foo_one(&self) -> &'static str; fn foo_two(&self) -> &'static str; + fn foo_three(&self) -> &'static str; } struct MyStruct; default impl Foo for T { fn foo_one(&self) -> &'static str { - "generic" + self.foo_three() } } @@ -27,6 +31,10 @@ impl Foo for MyStruct { fn foo_two(&self) -> &'static str { self.foo_one() } + + fn foo_three(&self) -> &'static str { + "generic" + } } fn main() {