Skip to content

Commit b3ec1e7

Browse files
committed
Deduplicate diagnostic impl of an orphanck error+lint
Moreover, don't add the error code to the lint warning(!). While helpful, it's quite unconventional.
1 parent 057ed8b commit b3ec1e7

12 files changed

Lines changed: 78 additions & 135 deletions

compiler/rustc_hir_analysis/src/coherence/orphan.rs

Lines changed: 21 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,21 @@ pub(crate) fn orphan_check_impl(
3131
Err(err) => match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) {
3232
Ok(()) => match err {
3333
OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => {
34-
lint_uncovered_ty_params(tcx, uncovered_ty_params, impl_def_id)
34+
let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);
35+
36+
for param_def_id in uncovered_ty_params.uncovered {
37+
let ident = tcx.item_ident(param_def_id);
38+
39+
tcx.emit_node_span_lint(
40+
UNCOVERED_PARAM_IN_PROJECTION,
41+
hir_id,
42+
ident.span,
43+
errors::UncoveredTyParams {
44+
param: ident,
45+
local_ty: uncovered_ty_params.local_ty,
46+
},
47+
);
48+
}
3549
}
3650
OrphanCheckErr::NonLocalInputType(_) => {
3751
bug!("orphanck: shouldn't've gotten non-local input tys in compat mode")
@@ -455,54 +469,18 @@ fn emit_orphan_check_error<'tcx>(
455469
diag.emit()
456470
}
457471
traits::OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
458-
let mut reported = None;
472+
let mut guar = None;
459473
for param_def_id in uncovered {
460-
let name = tcx.item_ident(param_def_id);
461-
let span = name.span;
462-
463-
reported.get_or_insert(match local_ty {
464-
Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
465-
span,
466-
note: (),
467-
param: name,
468-
local_type,
469-
}),
470-
None => tcx.dcx().emit_err(errors::TyParamSome { span, note: (), param: name }),
471-
});
474+
guar.get_or_insert(tcx.dcx().emit_err(errors::UncoveredTyParams {
475+
param: tcx.item_ident(param_def_id),
476+
local_ty,
477+
}));
472478
}
473-
reported.unwrap() // FIXME(fmease): This is very likely reachable.
479+
guar.unwrap()
474480
}
475481
}
476482
}
477483

478-
fn lint_uncovered_ty_params<'tcx>(
479-
tcx: TyCtxt<'tcx>,
480-
UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<TyCtxt<'tcx>, FxIndexSet<DefId>>,
481-
impl_def_id: LocalDefId,
482-
) {
483-
let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);
484-
485-
for param_def_id in uncovered {
486-
let span = tcx.def_ident_span(param_def_id).unwrap();
487-
let name = tcx.item_ident(param_def_id);
488-
489-
match local_ty {
490-
Some(local_type) => tcx.emit_node_span_lint(
491-
UNCOVERED_PARAM_IN_PROJECTION,
492-
hir_id,
493-
span,
494-
errors::TyParamFirstLocalLint { span, note: (), param: name, local_type },
495-
),
496-
None => tcx.emit_node_span_lint(
497-
UNCOVERED_PARAM_IN_PROJECTION,
498-
hir_id,
499-
span,
500-
errors::TyParamSomeLint { span, note: (), param: name },
501-
),
502-
};
503-
}
504-
}
505-
506484
struct UncoveredTyParamCollector<'cx, 'tcx> {
507485
infcx: &'cx InferCtxt<'tcx>,
508486
uncovered_params: FxIndexSet<DefId>,

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 41 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,72 +1498,6 @@ pub struct NoFieldOnType<'tcx> {
14981498
pub field: Ident,
14991499
}
15001500

1501-
// FIXME(fmease): Deduplicate:
1502-
1503-
#[derive(Diagnostic)]
1504-
#[diag("type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`)", code = E0210)]
1505-
#[note(
1506-
"implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type"
1507-
)]
1508-
pub(crate) struct TyParamFirstLocal<'tcx> {
1509-
#[primary_span]
1510-
#[label(
1511-
"type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`)"
1512-
)]
1513-
pub span: Span,
1514-
#[note(
1515-
"in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last"
1516-
)]
1517-
pub note: (),
1518-
pub param: Ident,
1519-
pub local_type: Ty<'tcx>,
1520-
}
1521-
1522-
#[derive(Diagnostic)]
1523-
#[diag("type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`)", code = E0210)]
1524-
#[note(
1525-
"implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type"
1526-
)]
1527-
pub(crate) struct TyParamFirstLocalLint<'tcx> {
1528-
#[label(
1529-
"type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`)"
1530-
)]
1531-
pub span: Span,
1532-
#[note(
1533-
"in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last"
1534-
)]
1535-
pub note: (),
1536-
pub param: Ident,
1537-
pub local_type: Ty<'tcx>,
1538-
}
1539-
1540-
#[derive(Diagnostic)]
1541-
#[diag("type parameter `{$param}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param}>`)", code = E0210)]
1542-
#[note(
1543-
"implementing a foreign trait is only possible if at least one of the types for which it is implemented is local"
1544-
)]
1545-
pub(crate) struct TyParamSome {
1546-
#[primary_span]
1547-
#[label("type parameter `{$param}` must be used as the type parameter for some local type")]
1548-
pub span: Span,
1549-
#[note("only traits defined in the current crate can be implemented for a type parameter")]
1550-
pub note: (),
1551-
pub param: Ident,
1552-
}
1553-
1554-
#[derive(Diagnostic)]
1555-
#[diag("type parameter `{$param}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param}>`)", code = E0210)]
1556-
#[note(
1557-
"implementing a foreign trait is only possible if at least one of the types for which it is implemented is local"
1558-
)]
1559-
pub(crate) struct TyParamSomeLint {
1560-
#[label("type parameter `{$param}` must be used as the type parameter for some local type")]
1561-
pub span: Span,
1562-
#[note("only traits defined in the current crate can be implemented for a type parameter")]
1563-
pub note: (),
1564-
pub param: Ident,
1565-
}
1566-
15671501
#[derive(Diagnostic)]
15681502
pub(crate) enum OnlyCurrentTraits {
15691503
#[diag("only traits defined in the current crate can be implemented for types defined outside of the crate", code = E0117)]
@@ -2048,3 +1982,44 @@ pub(crate) struct PinV2OnPacked {
20481982
pub pin_v2_span: Option<Span>,
20491983
pub adt_name: Symbol,
20501984
}
1985+
1986+
pub(crate) struct UncoveredTyParams<'tcx> {
1987+
pub(crate) param: Ident,
1988+
pub(crate) local_ty: Option<Ty<'tcx>>,
1989+
}
1990+
1991+
impl<G: EmissionGuarantee> Diagnostic<'_, G> for UncoveredTyParams<'_> {
1992+
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
1993+
let Self { param, local_ty } = self;
1994+
1995+
let mut diag = Diag::new(dcx, level, "").with_span(param.span);
1996+
if diag.is_error() {
1997+
diag.code(E0210);
1998+
}
1999+
2000+
let note = "implementing a foreign trait is only possible if at least one of the types for which it is implemented is local";
2001+
if let Some(local_ty) = local_ty {
2002+
let msg = format!(
2003+
"type parameter `{param}` must be covered by another type when it appears before the first local type (`{local_ty}`)"
2004+
);
2005+
diag.primary_message(msg.clone());
2006+
diag.span_label(param.span, msg);
2007+
diag.note(format!(
2008+
"{note}, and no uncovered type parameters appear before that first local type"
2009+
));
2010+
diag.note("in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last");
2011+
} else {
2012+
let msg = format!(
2013+
"type parameter `{param}` must be used as the type parameter for some local type"
2014+
);
2015+
diag.primary_message(format!("{msg} (e.g., `MyStruct<{param}>`)"));
2016+
diag.span_label(param.span, msg);
2017+
diag.note(note);
2018+
diag.note(
2019+
"only traits defined in the current crate can be implemented for a type parameter",
2020+
);
2021+
}
2022+
2023+
diag
2024+
}
2025+
}

tests/ui/coherence/orphan-check-alias.classic.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`B`)
1+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`B`)
22
--> $DIR/orphan-check-alias.rs:21:6
33
|
44
LL | impl<T> foreign::Trait2<B, T> for <T as Id>::Assoc {
@@ -12,4 +12,3 @@ LL | impl<T> foreign::Trait2<B, T> for <T as Id>::Assoc {
1212

1313
warning: 1 warning emitted
1414

15-
For more information about this error, try `rustc --explain E0210`.

tests/ui/coherence/orphan-check-alias.next.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`B`)
1+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`B`)
22
--> $DIR/orphan-check-alias.rs:21:6
33
|
44
LL | impl<T> foreign::Trait2<B, T> for <T as Id>::Assoc {
@@ -12,4 +12,3 @@ LL | impl<T> foreign::Trait2<B, T> for <T as Id>::Assoc {
1212

1313
warning: 1 warning emitted
1414

15-
For more information about this error, try `rustc --explain E0210`.

tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.classic.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
1+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
22
--> $DIR/orphan-check-projections-not-covering-ambiguity.rs:25:6
33
|
44
LL | impl<T> foreign::Trait1<Local, T> for <T as Project>::Output {}
@@ -12,4 +12,3 @@ LL | impl<T> foreign::Trait1<Local, T> for <T as Project>::Output {}
1212

1313
warning: 1 warning emitted
1414

15-
For more information about this error, try `rustc --explain E0210`.

tests/ui/coherence/orphan-check-projections-not-covering-ambiguity.next.stderr

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
1+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
22
--> $DIR/orphan-check-projections-not-covering-ambiguity.rs:25:6
33
|
44
LL | impl<T> foreign::Trait1<Local, T> for <T as Project>::Output {}
@@ -12,4 +12,3 @@ LL | impl<T> foreign::Trait1<Local, T> for <T as Project>::Output {}
1212

1313
warning: 1 warning emitted
1414

15-
For more information about this error, try `rustc --explain E0210`.

tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.classic.stderr

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
1+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
22
--> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:6
33
|
44
LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
@@ -10,7 +10,7 @@ LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
1010
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
1111
= note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
1212

13-
warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
13+
warning: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
1414
--> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:9
1515
|
1616
LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
@@ -23,4 +23,3 @@ LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
2323

2424
warning: 2 warnings emitted
2525

26-
For more information about this error, try `rustc --explain E0210`.

tests/ui/coherence/orphan-check-projections-not-covering-multiple-params.next.stderr

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
1+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
22
--> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:6
33
|
44
LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
@@ -10,7 +10,7 @@ LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
1010
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
1111
= note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
1212

13-
warning[E0210]: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
13+
warning: type parameter `U` must be covered by another type when it appears before the first local type (`LocalTy`)
1414
--> $DIR/orphan-check-projections-not-covering-multiple-params.rs:17:9
1515
|
1616
LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
@@ -23,4 +23,3 @@ LL | impl<T, U> foreign::Trait0<LocalTy, T, U> for <() as Trait<T, U>>::Assoc {}
2323

2424
warning: 2 warnings emitted
2525

26-
For more information about this error, try `rustc --explain E0210`.

tests/ui/coherence/orphan-check-projections-not-covering.classic.stderr

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
1+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
22
--> $DIR/orphan-check-projections-not-covering.rs:22:6
33
|
44
LL | impl<T> foreign::Trait0<Local, T, ()> for <T as Identity>::Output {}
@@ -10,7 +10,7 @@ LL | impl<T> foreign::Trait0<Local, T, ()> for <T as Identity>::Output {}
1010
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
1111
= note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
1212

13-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
13+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
1414
--> $DIR/orphan-check-projections-not-covering.rs:27:6
1515
|
1616
LL | impl<T> foreign::Trait0<<T as Identity>::Output, Local, T> for Option<T> {}
@@ -21,7 +21,7 @@ LL | impl<T> foreign::Trait0<<T as Identity>::Output, Local, T> for Option<T> {}
2121
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
2222
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
2323

24-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
24+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2525
--> $DIR/orphan-check-projections-not-covering.rs:40:6
2626
|
2727
LL | impl<T: Deferred> foreign::Trait1<Local, T> for <T as Deferred>::Output {}
@@ -34,4 +34,3 @@ LL | impl<T: Deferred> foreign::Trait1<Local, T> for <T as Deferred>::Output {}
3434

3535
warning: 3 warnings emitted
3636

37-
For more information about this error, try `rustc --explain E0210`.

tests/ui/coherence/orphan-check-projections-not-covering.next.stderr

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
1+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
22
--> $DIR/orphan-check-projections-not-covering.rs:22:6
33
|
44
LL | impl<T> foreign::Trait0<Local, T, ()> for <T as Identity>::Output {}
@@ -10,7 +10,7 @@ LL | impl<T> foreign::Trait0<Local, T, ()> for <T as Identity>::Output {}
1010
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
1111
= note: `#[warn(uncovered_param_in_projection)]` (part of `#[warn(future_incompatible)]`) on by default
1212

13-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
13+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
1414
--> $DIR/orphan-check-projections-not-covering.rs:27:6
1515
|
1616
LL | impl<T> foreign::Trait0<<T as Identity>::Output, Local, T> for Option<T> {}
@@ -21,7 +21,7 @@ LL | impl<T> foreign::Trait0<<T as Identity>::Output, Local, T> for Option<T> {}
2121
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
2222
= note: for more information, see issue #124559 <https://github.com/rust-lang/rust/issues/124559>
2323

24-
warning[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
24+
warning: type parameter `T` must be covered by another type when it appears before the first local type (`Local`)
2525
--> $DIR/orphan-check-projections-not-covering.rs:40:6
2626
|
2727
LL | impl<T: Deferred> foreign::Trait1<Local, T> for <T as Deferred>::Output {}
@@ -34,4 +34,3 @@ LL | impl<T: Deferred> foreign::Trait1<Local, T> for <T as Deferred>::Output {}
3434

3535
warning: 3 warnings emitted
3636

37-
For more information about this error, try `rustc --explain E0210`.

0 commit comments

Comments
 (0)