Skip to content

Commit f5c55ff

Browse files
committed
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
1 parent 29c8276 commit f5c55ff

30 files changed

+870
-33
lines changed

src/librustc/ich/impls_ty.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,8 @@ impl_stable_hash_for!(enum ty::Visibility {
218218
});
219219

220220
impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
221-
impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
221+
impl_stable_hash_for!(enum ty::DefaultImplCheck { Yes, No });
222+
impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref, default_impl_check });
222223
impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 });
223224
impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b });
224225

src/librustc/traits/select.rs

+31-5
Original file line numberDiff line numberDiff line change
@@ -1083,12 +1083,39 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
10831083
}
10841084

10851085
// Treat negative impls as unimplemented
1086-
fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>)
1087-
-> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
1086+
fn filter_negative_and_default_impls<'o>(&self,
1087+
candidate: SelectionCandidate<'tcx>,
1088+
stack: &TraitObligationStack<'o, 'tcx>)
1089+
-> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
1090+
10881091
if let ImplCandidate(def_id) = candidate {
10891092
if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative {
10901093
return Err(Unimplemented)
10911094
}
1095+
1096+
// if def_id is a default impl and it doesn't implement all the trait items,
1097+
// the impl doesn't implement the trait.
1098+
// An `Unimplemented` error is returned only if the default_impl_check is
1099+
// applicable to the trait predicate or the cause of the predicate is an
1100+
// `ObjectCastObligation`
1101+
if self.tcx().impl_is_default(def_id) &&
1102+
!self.tcx().default_impl_implement_all_methods(def_id){
1103+
match stack.obligation.cause.code {
1104+
ObligationCauseCode::ObjectCastObligation(_) => {
1105+
return Err(Unimplemented)
1106+
},
1107+
ObligationCauseCode::ItemObligation(..) |
1108+
ObligationCauseCode::MiscObligation => {
1109+
if let ty::DefaultImplCheck::Yes = stack.obligation
1110+
.predicate
1111+
.skip_binder()
1112+
.default_impl_check {
1113+
return Err(Unimplemented)
1114+
}
1115+
},
1116+
_ => {}
1117+
}
1118+
}
10921119
}
10931120
Ok(Some(candidate))
10941121
}
@@ -1178,9 +1205,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
11781205
// Instead, we select the right impl now but report `Bar does
11791206
// not implement Clone`.
11801207
if candidates.len() == 1 {
1181-
return self.filter_negative_impls(candidates.pop().unwrap());
1208+
return self.filter_negative_and_default_impls(candidates.pop().unwrap(), stack);
11821209
}
1183-
11841210
// Winnow, but record the exact outcome of evaluation, which
11851211
// is needed for specialization.
11861212
let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| {
@@ -1239,7 +1265,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
12391265
}
12401266

12411267
// Just one candidate left.
1242-
self.filter_negative_impls(candidates.pop().unwrap().candidate)
1268+
self.filter_negative_and_default_impls(candidates.pop().unwrap().candidate, stack)
12431269
}
12441270

12451271
fn is_knowable<'o>(&mut self,

src/librustc/traits/util.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
2222
pred: &ty::Predicate<'tcx>)
2323
-> ty::Predicate<'tcx> {
2424
match *pred {
25-
ty::Predicate::Trait(ref data) =>
26-
ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)),
25+
ty::Predicate::Trait(ref data) => {
26+
let anonymized_pred = ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data));
27+
anonymized_pred.change_default_impl_check(ty::DefaultImplCheck::No)
28+
.unwrap_or(anonymized_pred)
29+
}
2730

2831
ty::Predicate::Equate(ref data) =>
2932
ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)),
@@ -554,6 +557,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
554557
pub fn impl_item_is_final(self, node_item: &NodeItem<hir::Defaultness>) -> bool {
555558
node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id())
556559
}
560+
561+
pub fn default_impl_implement_all_methods(self, node_item_def_id: DefId) -> bool {
562+
if let Some(impl_trait_ref) = self.impl_trait_ref(node_item_def_id) {
563+
let trait_def = self.trait_def(impl_trait_ref.def_id);
564+
for trait_item in self.associated_items(impl_trait_ref.def_id) {
565+
let is_implemented = trait_def.ancestors(self, node_item_def_id)
566+
.defs(self, trait_item.name, trait_item.kind, impl_trait_ref.def_id)
567+
.next()
568+
.map(|node_item| !node_item.node.is_from_trait())
569+
.unwrap_or(false);
570+
571+
if !is_implemented {
572+
return false;
573+
}
574+
}
575+
}
576+
true
577+
}
557578
}
558579

559580
pub enum TupleArgumentsFlag { Yes, No }

src/librustc/ty/instance.rs

+119-2
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,19 @@
99
// except according to those terms.
1010

1111
use hir::def_id::DefId;
12-
use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
13-
use ty::subst::Kind;
12+
use ty::{self, Ty, TypeFoldable, Substs, TyCtxt, AssociatedKind, AssociatedItemContainer};
13+
use ty::subst::{Kind, Subst};
1414
use traits;
1515
use syntax::abi::Abi;
1616
use util::ppaux;
1717

1818
use std::fmt;
1919

20+
use syntax_pos::{BytePos, Span};
21+
use syntax::ext::hygiene::SyntaxContext;
22+
use hir::map::Node::NodeTraitItem;
23+
use hir;
24+
2025
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
2126
pub struct Instance<'tcx> {
2227
pub def: InstanceDef<'tcx>,
@@ -260,6 +265,13 @@ fn resolve_associated_item<'a, 'tcx>(
260265
traits::VtableImpl(impl_data) => {
261266
let (def_id, substs) = traits::find_associated_item(
262267
tcx, trait_item, rcvr_substs, &impl_data);
268+
269+
check_unimplemented_trait_item(tcx,
270+
impl_data.impl_def_id,
271+
def_id,
272+
trait_id,
273+
trait_item);
274+
263275
let substs = tcx.erase_regions(&substs);
264276
Some(ty::Instance::new(def_id, substs))
265277
}
@@ -363,3 +375,108 @@ fn fn_once_adapter_instance<'a, 'tcx>(
363375
debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
364376
Instance { def, substs }
365377
}
378+
379+
fn check_unimplemented_trait_item<'a, 'tcx>(
380+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
381+
impl_def_id: DefId,
382+
trait_item_def_id: DefId,
383+
trait_id: DefId,
384+
trait_item: &ty::AssociatedItem)
385+
{
386+
// if trait_item_def_id is a trait item and it doesn't have a default trait implementation
387+
// the resolution has found an unimplemented trait item inside a default impl
388+
if tcx.impl_is_default(impl_def_id) {
389+
let is_unimplemented_trait_item = match tcx.hir.as_local_node_id(trait_item_def_id) {
390+
Some(node_id) =>
391+
match tcx.hir.find(node_id) {
392+
Some(NodeTraitItem(item)) => {
393+
if let hir::TraitItemKind::Method(_,
394+
hir::TraitMethod::Provided(_))
395+
= item.node {
396+
false
397+
} else {
398+
true
399+
}
400+
},
401+
_ => false
402+
}
403+
None => {
404+
let item = tcx.global_tcx().associated_item(trait_item_def_id);
405+
match item.kind {
406+
AssociatedKind::Method => match item.container {
407+
AssociatedItemContainer::TraitContainer(_) => {
408+
!item.defaultness.has_value()
409+
}
410+
_ => false
411+
}
412+
_ => false
413+
}
414+
}
415+
};
416+
417+
if is_unimplemented_trait_item {
418+
let mut err = tcx.sess.struct_err(&format!("the trait method `{}` \
419+
is not implemented",
420+
trait_item.name));
421+
422+
let mut help_messages = Vec::new();
423+
help_messages.push(
424+
if impl_def_id.is_local() {
425+
let item = tcx.hir
426+
.expect_item(
427+
tcx.hir
428+
.as_local_node_id(impl_def_id).unwrap()
429+
);
430+
(item.span, format!("implement it inside this `default impl`"))
431+
} else {
432+
(Span::new (
433+
BytePos(0),
434+
BytePos(0),
435+
SyntaxContext::empty()
436+
),
437+
format!("implement it inside the {} `default impl`",
438+
tcx.item_path_str(impl_def_id)))
439+
}
440+
);
441+
442+
help_messages.push(
443+
if trait_id.is_local() {
444+
let trait_item = tcx.hir
445+
.expect_item(
446+
tcx.hir
447+
.as_local_node_id(trait_id).unwrap()
448+
);
449+
(trait_item.span, format!("provide a default method implementation \
450+
inside this `trait`"))
451+
} else {
452+
(Span::new (
453+
BytePos(0),
454+
BytePos(0),
455+
SyntaxContext::empty()
456+
),
457+
format!("provide a default method implementation \
458+
inside the {} `trait`",
459+
tcx.item_path_str(trait_id)))
460+
}
461+
);
462+
463+
help_messages.sort_by(|&(a,_), &(b,_)| a.partial_cmp(&b).unwrap());
464+
465+
let mut cnjs = vec!["or ", "either "];
466+
help_messages.iter().for_each(|&(span, ref msg)| {
467+
let mut help_msg = String::from(cnjs.pop().unwrap_or(""));
468+
help_msg.push_str(&msg);
469+
470+
if span.data().lo == BytePos(0) && span.data().hi == BytePos(0) {
471+
err.help(&help_msg);
472+
} else {
473+
err.span_help(span, &help_msg);
474+
}
475+
});
476+
477+
err.note(&format!("a `default impl` doesn't need to include all \
478+
items from the trait"));
479+
err.emit();
480+
}
481+
}
482+
}

src/librustc/ty/mod.rs

+37-2
Original file line numberDiff line numberDiff line change
@@ -1070,9 +1070,13 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
10701070
}
10711071
}
10721072

1073+
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
1074+
pub enum DefaultImplCheck { Yes, No, }
1075+
10731076
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
10741077
pub struct TraitPredicate<'tcx> {
1075-
pub trait_ref: TraitRef<'tcx>
1078+
pub trait_ref: TraitRef<'tcx>,
1079+
pub default_impl_check: DefaultImplCheck
10761080
}
10771081
pub type PolyTraitPredicate<'tcx> = ty::Binder<TraitPredicate<'tcx>>;
10781082

@@ -1180,7 +1184,8 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
11801184
assert!(!self.has_escaping_regions());
11811185

11821186
ty::Predicate::Trait(ty::Binder(ty::TraitPredicate {
1183-
trait_ref: self.clone()
1187+
trait_ref: self.clone(),
1188+
default_impl_check: DefaultImplCheck::No
11841189
}))
11851190
}
11861191
}
@@ -1298,6 +1303,36 @@ impl<'tcx> Predicate<'tcx> {
12981303
}
12991304
}
13001305
}
1306+
1307+
pub fn change_default_impl_check(&self, default_impl_check: ty::DefaultImplCheck)
1308+
-> Option<Predicate<'tcx>> {
1309+
match *self {
1310+
Predicate::Trait(ref t) => {
1311+
if t.skip_binder().default_impl_check != default_impl_check {
1312+
Some(
1313+
Predicate::Trait(ty::Binder(ty::TraitPredicate {
1314+
trait_ref: t.skip_binder().trait_ref,
1315+
default_impl_check: default_impl_check
1316+
}))
1317+
)
1318+
} else {
1319+
None
1320+
}
1321+
}
1322+
Predicate::Trait(..) |
1323+
Predicate::Projection(..) |
1324+
Predicate::Equate(..) |
1325+
Predicate::Subtype(..) |
1326+
Predicate::RegionOutlives(..) |
1327+
Predicate::WellFormed(..) |
1328+
Predicate::ObjectSafe(..) |
1329+
Predicate::ClosureKind(..) |
1330+
Predicate::TypeOutlives(..) |
1331+
Predicate::ConstEvaluatable(..) => {
1332+
None
1333+
}
1334+
}
1335+
}
13011336
}
13021337

13031338
/// Represents the bounds declared on a particular set of type

src/librustc/ty/structural_impls.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
278278
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
279279
-> Option<ty::TraitPredicate<'tcx>> {
280280
tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate {
281-
trait_ref,
281+
trait_ref: trait_ref,
282+
default_impl_check: self.default_impl_check
282283
})
283284
}
284285
}
@@ -1127,7 +1128,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> {
11271128
impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
11281129
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
11291130
ty::TraitPredicate {
1130-
trait_ref: self.trait_ref.fold_with(folder)
1131+
trait_ref: self.trait_ref.fold_with(folder),
1132+
default_impl_check: self.default_impl_check
11311133
}
11321134
}
11331135

src/librustc/ty/sty.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,10 @@ impl<'tcx> PolyTraitRef<'tcx> {
582582

583583
pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
584584
// Note that we preserve binding levels
585-
Binder(ty::TraitPredicate { trait_ref: self.0.clone() })
585+
Binder(ty::TraitPredicate {
586+
trait_ref: self.0.clone(),
587+
default_impl_check: ty::DefaultImplCheck::No
588+
})
586589
}
587590
}
588591

src/librustc/util/ppaux.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1230,8 +1230,12 @@ define_print! {
12301230
define_print! {
12311231
('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) {
12321232
debug {
1233-
write!(f, "TraitPredicate({:?})",
1234-
self.trait_ref)
1233+
let default_impl_check_value = match self.default_impl_check {
1234+
ty::DefaultImplCheck::Yes => "default_impl_check: yes",
1235+
ty::DefaultImplCheck::No => "default_impl_check: no",
1236+
};
1237+
write!(f, "TraitPredicate({:?}, {})",
1238+
self.trait_ref, default_impl_check_value)
12351239
}
12361240
display {
12371241
print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref))

src/librustc_mir/monomorphize/collector.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
618618
self.output);
619619
} else {
620620
visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
621+
622+
if tcx.sess.has_errors() {
623+
match func {
624+
&mir::Operand::Consume(_) => {}
625+
&mir::Operand::Constant(ref cst) => {
626+
tcx.sess
627+
.span_note_without_error(cst.span,
628+
"the function call is here");
629+
}
630+
}
631+
tcx.sess.abort_if_errors();
632+
}
621633
}
622634
}
623635
mir::TerminatorKind::Drop { ref location, .. } |
@@ -678,7 +690,10 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
678690
ty::ParamEnv::empty(traits::Reveal::All),
679691
def_id,
680692
substs).unwrap();
681-
visit_instance_use(tcx, instance, is_direct_call, output);
693+
if !tcx.sess.has_errors() {
694+
// continue only if no errors are encountered during monomorphization
695+
visit_instance_use(tcx, instance, is_direct_call, output);
696+
}
682697
}
683698
}
684699

0 commit comments

Comments
 (0)