Skip to content

Commit f1b86fc

Browse files
committed
make a custom error for overlap with negative impls
1 parent 6c37252 commit f1b86fc

21 files changed

+269
-187
lines changed

src/librustc_error_codes/error_codes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ E0747: include_str!("./error_codes/E0747.md"),
425425
E0748: include_str!("./error_codes/E0748.md"),
426426
E0749: include_str!("./error_codes/E0749.md"),
427427
E0750: include_str!("./error_codes/E0750.md"),
428+
E0751: include_str!("./error_codes/E0751.md"),
428429
;
429430
// E0006, // merged with E0005
430431
// 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: 163 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().def_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().def_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,168 @@ 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 = tcx.sess.source_map().def_span(tcx.span_of_impl(local_impl_def_id).unwrap());
385+
let mut err = struct_span_err!(
386+
tcx.sess,
387+
impl_span,
388+
E0748,
389+
"found both positive and negative implementation of trait `{}`{}:",
390+
overlap.trait_desc,
391+
overlap.self_desc.clone().map_or(String::new(), |ty| format!(" for type `{}`", ty))
392+
);
393+
394+
match tcx.span_of_impl(negative_impl_def_id) {
395+
Ok(span) => {
396+
err.span_label(
397+
tcx.sess.source_map().def_span(span),
398+
"negative implementation here".to_string(),
399+
);
400+
}
401+
Err(cname) => {
402+
err.note(&format!("negative implementation in crate `{}`", cname));
403+
}
404+
}
405+
406+
match tcx.span_of_impl(positive_impl_def_id) {
407+
Ok(span) => {
408+
err.span_label(
409+
tcx.sess.source_map().def_span(span),
410+
"positive implementation here".to_string(),
411+
);
412+
}
413+
Err(cname) => {
414+
err.note(&format!("positive implementation in crate `{}`", cname));
415+
}
416+
}
417+
418+
sg.has_errored = true;
419+
err.emit();
420+
}
421+
422+
fn report_conflicting_impls(
423+
tcx: TyCtxt<'_>,
424+
overlap: OverlapError,
425+
impl_def_id: DefId,
426+
used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
427+
sg: &mut specialization_graph::Graph,
428+
) {
429+
let impl_span = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
430+
431+
// Work to be done after we've built the DiagnosticBuilder. We have to define it
432+
// now because the struct_lint methods don't return back the DiagnosticBuilder
433+
// that's passed in.
434+
let decorate = |err: LintDiagnosticBuilder<'_>| {
435+
let msg = format!(
436+
"conflicting implementations of trait `{}`{}:{}",
437+
overlap.trait_desc,
438+
overlap.self_desc.clone().map_or(String::new(), |ty| { format!(" for type `{}`", ty) }),
439+
match used_to_be_allowed {
440+
Some(FutureCompatOverlapErrorKind::Issue33140) => " (E0119)",
441+
_ => "",
442+
}
443+
);
444+
let mut err = err.build(&msg);
445+
match tcx.span_of_impl(overlap.with_impl) {
446+
Ok(span) => {
447+
err.span_label(
448+
tcx.sess.source_map().def_span(span),
449+
"first implementation here".to_string(),
450+
);
451+
452+
err.span_label(
453+
impl_span,
454+
format!(
455+
"conflicting implementation{}",
456+
overlap.self_desc.map_or(String::new(), |ty| format!(" for `{}`", ty))
457+
),
458+
);
459+
}
460+
Err(cname) => {
461+
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
462+
Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s),
463+
None => format!("conflicting implementation in crate `{}`", cname),
464+
};
465+
err.note(&msg);
466+
}
467+
}
468+
469+
for cause in &overlap.intercrate_ambiguity_causes {
470+
cause.add_intercrate_ambiguity_hint(&mut err);
471+
}
472+
473+
if overlap.involves_placeholder {
474+
coherence::add_placeholder_note(&mut err);
475+
}
476+
err.emit()
477+
};
478+
479+
match used_to_be_allowed {
480+
None => {
481+
sg.has_errored = true;
482+
let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
483+
decorate(LintDiagnosticBuilder::new(err));
484+
}
485+
Some(kind) => {
486+
let lint = match kind {
487+
FutureCompatOverlapErrorKind::Issue33140 => ORDER_DEPENDENT_TRAIT_OBJECTS,
488+
FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
489+
};
490+
tcx.struct_span_lint_hir(
491+
lint,
492+
tcx.hir().as_local_hir_id(impl_def_id).unwrap(),
493+
impl_span,
494+
decorate,
495+
)
496+
}
497+
};
498+
}
499+
417500
/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
418501
/// string.
419502
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)