Skip to content

Commit 6507170

Browse files
committed
make a custom error for overlap with negative impls
1 parent e8a05e2 commit 6507170

21 files changed

+271
-187
lines changed

src/librustc_error_codes/error_codes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ E0747: include_str!("./error_codes/E0747.md"),
427427
E0748: include_str!("./error_codes/E0748.md"),
428428
E0749: include_str!("./error_codes/E0749.md"),
429429
E0750: include_str!("./error_codes/E0750.md"),
430+
E0751: include_str!("./error_codes/E0751.md"),
430431
;
431432
// E0006, // merged with E0005
432433
// E0008, // cannot bind by-move into a pattern guard
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
There are both a positive and negative trait implementation for the same type.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0748
6+
trait MyTrait {}
7+
impl MyTrait for i32 { }
8+
impl !MyTrait for i32 { }
9+
```
10+
11+
Negative implementations are a promise that the trait will never be
12+
implemented for the given types.

src/librustc_trait_selection/traits/specialize/mod.rs

Lines changed: 165 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -324,86 +324,7 @@ pub(super) fn specialization_graph_provider(
324324
};
325325

326326
if let Some(overlap) = overlap {
327-
let impl_span =
328-
tcx.sess.source_map().guess_head_span(tcx.span_of_impl(impl_def_id).unwrap());
329-
330-
// Work to be done after we've built the DiagnosticBuilder. We have to define it
331-
// now because the struct_lint methods don't return back the DiagnosticBuilder
332-
// that's passed in.
333-
let decorate = |err: LintDiagnosticBuilder<'_>| {
334-
let msg = format!(
335-
"conflicting implementations of trait `{}`{}:{}",
336-
overlap.trait_desc,
337-
overlap
338-
.self_desc
339-
.clone()
340-
.map_or(String::new(), |ty| { format!(" for type `{}`", ty) }),
341-
match used_to_be_allowed {
342-
Some(FutureCompatOverlapErrorKind::Issue33140) => " (E0119)",
343-
_ => "",
344-
}
345-
);
346-
let mut err = err.build(&msg);
347-
match tcx.span_of_impl(overlap.with_impl) {
348-
Ok(span) => {
349-
err.span_label(
350-
tcx.sess.source_map().guess_head_span(span),
351-
"first implementation here".to_string(),
352-
);
353-
354-
err.span_label(
355-
impl_span,
356-
format!(
357-
"conflicting implementation{}",
358-
overlap
359-
.self_desc
360-
.map_or(String::new(), |ty| format!(" for `{}`", ty))
361-
),
362-
);
363-
}
364-
Err(cname) => {
365-
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
366-
Some(s) => format!(
367-
"conflicting implementation in crate `{}`:\n- {}",
368-
cname, s
369-
),
370-
None => format!("conflicting implementation in crate `{}`", cname),
371-
};
372-
err.note(&msg);
373-
}
374-
}
375-
376-
for cause in &overlap.intercrate_ambiguity_causes {
377-
cause.add_intercrate_ambiguity_hint(&mut err);
378-
}
379-
380-
if overlap.involves_placeholder {
381-
coherence::add_placeholder_note(&mut err);
382-
}
383-
err.emit()
384-
};
385-
386-
match used_to_be_allowed {
387-
None => {
388-
sg.has_errored = true;
389-
let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
390-
decorate(LintDiagnosticBuilder::new(err));
391-
}
392-
Some(kind) => {
393-
let lint = match kind {
394-
FutureCompatOverlapErrorKind::Issue33140 => {
395-
ORDER_DEPENDENT_TRAIT_OBJECTS
396-
}
397-
FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
398-
};
399-
tcx.struct_span_lint_hir(
400-
lint,
401-
tcx.hir().as_local_hir_id(impl_def_id).unwrap(),
402-
impl_span,
403-
decorate,
404-
)
405-
}
406-
};
327+
report_overlap_conflict(tcx, overlap, impl_def_id, used_to_be_allowed, &mut sg);
407328
}
408329
} else {
409330
let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
@@ -414,6 +335,170 @@ pub(super) fn specialization_graph_provider(
414335
tcx.arena.alloc(sg)
415336
}
416337

338+
fn report_overlap_conflict(
339+
tcx: TyCtxt<'_>,
340+
overlap: OverlapError,
341+
impl_def_id: DefId,
342+
used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
343+
sg: &mut specialization_graph::Graph,
344+
) {
345+
let impl_polarity = tcx.impl_polarity(impl_def_id);
346+
let other_polarity = tcx.impl_polarity(overlap.with_impl);
347+
match (impl_polarity, other_polarity) {
348+
(ty::ImplPolarity::Negative, ty::ImplPolarity::Positive) => {
349+
report_negative_positive_conflict(
350+
tcx,
351+
&overlap,
352+
impl_def_id,
353+
impl_def_id,
354+
overlap.with_impl,
355+
sg,
356+
);
357+
}
358+
359+
(ty::ImplPolarity::Positive, ty::ImplPolarity::Negative) => {
360+
report_negative_positive_conflict(
361+
tcx,
362+
&overlap,
363+
impl_def_id,
364+
overlap.with_impl,
365+
impl_def_id,
366+
sg,
367+
);
368+
}
369+
370+
_ => {
371+
report_conflicting_impls(tcx, overlap, impl_def_id, used_to_be_allowed, sg);
372+
}
373+
}
374+
}
375+
376+
fn report_negative_positive_conflict(
377+
tcx: TyCtxt<'_>,
378+
overlap: &OverlapError,
379+
local_impl_def_id: DefId,
380+
negative_impl_def_id: DefId,
381+
positive_impl_def_id: DefId,
382+
sg: &mut specialization_graph::Graph,
383+
) {
384+
let impl_span =
385+
tcx.sess.source_map().guess_head_span(tcx.span_of_impl(local_impl_def_id).unwrap());
386+
387+
let mut err = struct_span_err!(
388+
tcx.sess,
389+
impl_span,
390+
E0748,
391+
"found both positive and negative implementation of trait `{}`{}:",
392+
overlap.trait_desc,
393+
overlap.self_desc.clone().map_or(String::new(), |ty| format!(" for type `{}`", ty))
394+
);
395+
396+
match tcx.span_of_impl(negative_impl_def_id) {
397+
Ok(span) => {
398+
err.span_label(
399+
tcx.sess.source_map().guess_head_span(span),
400+
"negative implementation here".to_string(),
401+
);
402+
}
403+
Err(cname) => {
404+
err.note(&format!("negative implementation in crate `{}`", cname));
405+
}
406+
}
407+
408+
match tcx.span_of_impl(positive_impl_def_id) {
409+
Ok(span) => {
410+
err.span_label(
411+
tcx.sess.source_map().guess_head_span(span),
412+
"positive implementation here".to_string(),
413+
);
414+
}
415+
Err(cname) => {
416+
err.note(&format!("positive implementation in crate `{}`", cname));
417+
}
418+
}
419+
420+
sg.has_errored = true;
421+
err.emit();
422+
}
423+
424+
fn report_conflicting_impls(
425+
tcx: TyCtxt<'_>,
426+
overlap: OverlapError,
427+
impl_def_id: DefId,
428+
used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
429+
sg: &mut specialization_graph::Graph,
430+
) {
431+
let impl_span = tcx.sess.source_map().guess_head_span(tcx.span_of_impl(impl_def_id).unwrap());
432+
433+
// Work to be done after we've built the DiagnosticBuilder. We have to define it
434+
// now because the struct_lint methods don't return back the DiagnosticBuilder
435+
// that's passed in.
436+
let decorate = |err: LintDiagnosticBuilder<'_>| {
437+
let msg = format!(
438+
"conflicting implementations of trait `{}`{}:{}",
439+
overlap.trait_desc,
440+
overlap.self_desc.clone().map_or(String::new(), |ty| { format!(" for type `{}`", ty) }),
441+
match used_to_be_allowed {
442+
Some(FutureCompatOverlapErrorKind::Issue33140) => " (E0119)",
443+
_ => "",
444+
}
445+
);
446+
let mut err = err.build(&msg);
447+
match tcx.span_of_impl(overlap.with_impl) {
448+
Ok(span) => {
449+
err.span_label(
450+
tcx.sess.source_map().guess_head_span(span),
451+
"first implementation here".to_string(),
452+
);
453+
454+
err.span_label(
455+
impl_span,
456+
format!(
457+
"conflicting implementation{}",
458+
overlap.self_desc.map_or(String::new(), |ty| format!(" for `{}`", ty))
459+
),
460+
);
461+
}
462+
Err(cname) => {
463+
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
464+
Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s),
465+
None => format!("conflicting implementation in crate `{}`", cname),
466+
};
467+
err.note(&msg);
468+
}
469+
}
470+
471+
for cause in &overlap.intercrate_ambiguity_causes {
472+
cause.add_intercrate_ambiguity_hint(&mut err);
473+
}
474+
475+
if overlap.involves_placeholder {
476+
coherence::add_placeholder_note(&mut err);
477+
}
478+
err.emit()
479+
};
480+
481+
match used_to_be_allowed {
482+
None => {
483+
sg.has_errored = true;
484+
let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
485+
decorate(LintDiagnosticBuilder::new(err));
486+
}
487+
Some(kind) => {
488+
let lint = match kind {
489+
FutureCompatOverlapErrorKind::Issue33140 => ORDER_DEPENDENT_TRAIT_OBJECTS,
490+
FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
491+
};
492+
tcx.struct_span_lint_hir(
493+
lint,
494+
tcx.hir().as_local_hir_id(impl_def_id).unwrap(),
495+
impl_span,
496+
decorate,
497+
)
498+
}
499+
};
500+
}
501+
417502
/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
418503
/// string.
419504
fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {

src/test/ui/coherence/coherence-conflicting-negative-trait-impl.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ trait MyTrait {}
66

77
struct TestType<T>(::std::marker::PhantomData<T>);
88

9-
unsafe impl<T: MyTrait+'static> Send for TestType<T> {}
9+
unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
1010

11-
impl<T: MyTrait> !Send for TestType<T> {}
12-
//~^ ERROR conflicting implementations
11+
impl<T: MyTrait> !Send for TestType<T> {} //~ ERROR found both positive and negative implementation
1312

14-
unsafe impl<T:'static> Send for TestType<T> {}
15-
//~^ ERROR conflicting implementations
13+
unsafe impl<T: 'static> Send for TestType<T> {} //~ ERROR conflicting implementations
1614

1715
impl !Send for TestType<i32> {}
1816

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
error[E0119]: conflicting implementations of trait `std::marker::Send` for type `TestType<_>`:
1+
error[E0748]: found both positive and negative implementation of trait `std::marker::Send` for type `TestType<_>`:
22
--> $DIR/coherence-conflicting-negative-trait-impl.rs:11:1
33
|
4-
LL | unsafe impl<T: MyTrait+'static> Send for TestType<T> {}
5-
| ---------------------------------------------------- first implementation here
4+
LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
5+
| ------------------------------------------------------ positive implementation here
66
LL |
77
LL | impl<T: MyTrait> !Send for TestType<T> {}
8-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here
99

1010
error[E0119]: conflicting implementations of trait `std::marker::Send` for type `TestType<_>`:
11-
--> $DIR/coherence-conflicting-negative-trait-impl.rs:14:1
11+
--> $DIR/coherence-conflicting-negative-trait-impl.rs:13:1
1212
|
13-
LL | unsafe impl<T: MyTrait+'static> Send for TestType<T> {}
14-
| ---------------------------------------------------- first implementation here
13+
LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
14+
| ------------------------------------------------------ first implementation here
1515
...
16-
LL | unsafe impl<T:'static> Send for TestType<T> {}
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
16+
LL | unsafe impl<T: 'static> Send for TestType<T> {}
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
1818

1919
error: aborting due to 2 previous errors
2020

21-
For more information about this error, try `rustc --explain E0119`.
21+
Some errors have detailed explanations: E0119, E0748.
22+
For more information about an error, try `rustc --explain E0119`.

0 commit comments

Comments
 (0)