diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 107779ec3fa1..42724274eb70 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 4ed25646d436..ee6bf4180dda 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 898accb90215..9e0859c67a0a 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 63bf52a9bdf7..0bc092d99eba 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 f52f2ea0f9fc..31cb4a642869 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 0dc1338fff86..122a76ca6253 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 1593b452cdff..542bf12ecddc 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 37d1c568515b..8b7c9d505bc5 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 f16187797d4e..0851075a0924 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 1139ea5fbd36..dc42aa8dc1a5 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 4aed688027f7..d4180183aeff 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 f044b2c711e2..4fe2f5b574e6 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 3668fc46ddc2..9c233a7a15d2 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 d5328a18c224..40d69855c49a 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 000000000000..263f316f3c8f --- /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 000000000000..cee6fcf7d9ad --- /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 000000000000..54f6690aa9f1 --- /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 000000000000..8e2de42a0995 --- /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 000000000000..d0db6e996d81 --- /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 000000000000..81b85f58998c --- /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 000000000000..00cceeb4db3e --- /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 000000000000..51a6a9e2c6bf --- /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 000000000000..3444dea39c20 --- /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 000000000000..6af69e89316a --- /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 000000000000..a2ea087220fb --- /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 000000000000..752b0190ea6c --- /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 000000000000..4ed37b311ef0 --- /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 000000000000..5c0547b03414 --- /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 000000000000..254d3bebb903 --- /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 000000000000..409d2c78e775 --- /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"); +}