Skip to content

Commit 90698b6

Browse files
camsteffencjgillot
authored andcommitted
Refactor Diverges in typeck
Avoid deriving PartialOrd on Diverges since it includes fields which should not affect ordering.
1 parent 04ba50e commit 90698b6

File tree

7 files changed

+54
-57
lines changed

7 files changed

+54
-57
lines changed

compiler/rustc_hir_typeck/src/_match.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_trait_selection::traits::{
1010
};
1111

1212
use crate::coercion::{AsCoercionSite, CoerceMany};
13-
use crate::{Diverges, Expectation, FnCtxt, Needs};
13+
use crate::{DivergeReason, Diverges, Expectation, FnCtxt, Needs};
1414

1515
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1616
#[instrument(skip(self), level = "debug", ret)]
@@ -30,7 +30,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3030

3131
// If there are no arms, that is a diverging match; a special case.
3232
if arms.is_empty() {
33-
self.diverges.set(self.diverges.get() | Diverges::always(expr.span));
33+
self.diverges
34+
.set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span));
3435
return tcx.types.never;
3536
}
3637

@@ -151,13 +152,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
151152
// we can emit a better note. Rather than pointing
152153
// at a diverging expression in an arbitrary arm,
153154
// we can point at the entire `match` expression
154-
if let (Diverges::Always { .. }, hir::MatchSource::Normal) = (all_arms_diverge, match_src) {
155-
all_arms_diverge = Diverges::Always {
156-
span: expr.span,
157-
custom_note: Some(
158-
"any code following this `match` expression is unreachable, as all arms diverge",
159-
),
160-
};
155+
if let (Diverges::Always(..), hir::MatchSource::Normal) = (all_arms_diverge, match_src) {
156+
all_arms_diverge = Diverges::Always(DivergeReason::AllArmsDiverge, expr.span);
161157
}
162158

163159
// We won't diverge unless the scrutinee or all arms diverge.

compiler/rustc_hir_typeck/src/check.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
1515

1616
use crate::coercion::CoerceMany;
1717
use crate::gather_locals::GatherLocalsVisitor;
18-
use crate::{CoroutineTypes, Diverges, FnCtxt};
18+
use crate::{CoroutineTypes, DivergeReason, Diverges, FnCtxt};
1919

2020
/// Helper used for fns and closures. Does the grungy work of checking a function
2121
/// body and returns the function context used for that purpose, since in the case of a fn item
@@ -88,10 +88,8 @@ pub(super) fn check_fn<'a, 'tcx>(
8888
let ty_span = ty.map(|ty| ty.span);
8989
fcx.check_pat_top(param.pat, param_ty, ty_span, None, None);
9090
if param.pat.is_never_pattern() {
91-
fcx.function_diverges_because_of_empty_arguments.set(Diverges::Always {
92-
span: param.pat.span,
93-
custom_note: Some("any code following a never pattern is unreachable"),
94-
});
91+
fcx.function_diverges_because_of_empty_arguments
92+
.set(Diverges::Always(DivergeReason::NeverPattern, param.pat.span));
9593
}
9694

9795
// Check that argument is Sized.
Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,21 @@
11
use std::{cmp, ops};
22

3-
use rustc_span::{Span, DUMMY_SP};
3+
use rustc_span::Span;
44

55
/// Tracks whether executing a node may exit normally (versus
66
/// return/break/panic, which "diverge", leaving dead code in their
77
/// wake). Tracked semi-automatically (through type variables marked
88
/// as diverging), with some manual adjustments for control-flow
99
/// primitives (approximating a CFG).
10-
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
10+
#[derive(Copy, Clone, Debug)]
1111
pub enum Diverges {
1212
/// Potentially unknown, some cases converge,
1313
/// others require a CFG to determine them.
1414
Maybe,
1515

1616
/// Definitely known to diverge and therefore
1717
/// not reach the next sibling or its parent.
18-
Always {
19-
/// The `Span` points to the expression
20-
/// that caused us to diverge
21-
/// (e.g. `return`, `break`, etc).
22-
span: Span,
23-
/// In some cases (e.g. a `match` expression
24-
/// where all arms diverge), we may be
25-
/// able to provide a more informative
26-
/// message to the user.
27-
/// If this is `None`, a default message
28-
/// will be generated, which is suitable
29-
/// for most cases.
30-
custom_note: Option<&'static str>,
31-
},
18+
Always(DivergeReason, Span),
3219

3320
/// Same as `Always` but with a reachability
3421
/// warning already emitted.
@@ -40,14 +27,15 @@ pub enum Diverges {
4027
impl ops::BitAnd for Diverges {
4128
type Output = Self;
4229
fn bitand(self, other: Self) -> Self {
43-
cmp::min(self, other)
30+
cmp::min_by_key(self, other, Self::ordinal)
4431
}
4532
}
4633

4734
impl ops::BitOr for Diverges {
4835
type Output = Self;
4936
fn bitor(self, other: Self) -> Self {
50-
cmp::max(self, other)
37+
// argument order is to prefer `self` if ordinal is equal
38+
cmp::max_by_key(other, self, Self::ordinal)
5139
}
5240
}
5341

@@ -64,15 +52,25 @@ impl ops::BitOrAssign for Diverges {
6452
}
6553

6654
impl Diverges {
67-
/// Creates a `Diverges::Always` with the provided `span` and the default note message.
68-
pub(super) fn always(span: Span) -> Diverges {
69-
Diverges::Always { span, custom_note: None }
55+
pub(super) fn is_always(self) -> bool {
56+
match self {
57+
Self::Maybe => false,
58+
Self::Always(..) | Self::WarnedAlways => true,
59+
}
7060
}
7161

72-
pub(super) fn is_always(self) -> bool {
73-
// Enum comparison ignores the
74-
// contents of fields, so we just
75-
// fill them in with garbage here.
76-
self >= Diverges::Always { span: DUMMY_SP, custom_note: None }
62+
fn ordinal(&self) -> u8 {
63+
match self {
64+
Self::Maybe => 0,
65+
Self::Always { .. } => 1,
66+
Self::WarnedAlways => 2,
67+
}
7768
}
7869
}
70+
71+
#[derive(Clone, Copy, Debug)]
72+
pub enum DivergeReason {
73+
AllArmsDiverge,
74+
NeverPattern,
75+
Other,
76+
}

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectatio
4747
use crate::TupleArgumentsFlag::DontTupleArguments;
4848
use crate::{
4949
cast, fatally_break_rust, report_unexpected_variant_res, type_error_struct, BreakableCtxt,
50-
CoroutineTypes, Diverges, FnCtxt, Needs,
50+
CoroutineTypes, DivergeReason, Diverges, FnCtxt, Needs,
5151
};
5252

5353
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -239,7 +239,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
239239

240240
// Any expression that produces a value of type `!` must have diverged
241241
if ty.is_never() {
242-
self.diverges.set(self.diverges.get() | Diverges::always(expr.span));
242+
self.diverges
243+
.set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span));
243244
}
244245

245246
// Record the type, which applies it effects.
@@ -1307,7 +1308,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13071308
// of a `break` or an outer `break` or `return`.
13081309
self.diverges.set(Diverges::Maybe);
13091310
} else {
1310-
self.diverges.set(self.diverges.get() | Diverges::always(expr.span));
1311+
self.diverges
1312+
.set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span));
13111313
}
13121314

13131315
// If we permit break with a value, then result type is
@@ -1410,7 +1412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14101412
})
14111413
.unwrap_or_else(|| self.next_ty_var(expr.span));
14121414
let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
1413-
assert_eq!(self.diverges.get(), Diverges::Maybe);
1415+
assert!(matches!(self.diverges.get(), Diverges::Maybe));
14141416
for e in args {
14151417
let e_ty = self.check_expr_with_hint(e, coerce_to);
14161418
let cause = self.misc(e.span);

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ use rustc_trait_selection::traits::{
4242
use crate::callee::{self, DeferredCallResolution};
4343
use crate::errors::{self, CtorIsPrivate};
4444
use crate::method::{self, MethodCallee};
45-
use crate::{rvalue_scopes, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy};
45+
use crate::{
46+
rvalue_scopes, BreakableCtxt, DivergeReason, Diverges, Expectation, FnCtxt, LoweredTy,
47+
};
4648

4749
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4850
/// Produces warning on the given node, if the current point in the
4951
/// function is unreachable, and there hasn't been another warning.
5052
pub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str) {
51-
let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() else {
53+
let Diverges::Always(reason, orig_span) = self.diverges.get() else {
5254
return;
5355
};
5456

@@ -79,10 +81,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7981
let msg = format!("unreachable {kind}");
8082
self.tcx().node_span_lint(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
8183
lint.primary_message(msg.clone());
82-
lint.span_label(span, msg).span_label(
83-
orig_span,
84-
custom_note.unwrap_or("any code following this expression is unreachable"),
85-
);
84+
let custom_note = match reason {
85+
DivergeReason::AllArmsDiverge => {
86+
"any code following this `match` expression is unreachable, as all arms diverge"
87+
}
88+
DivergeReason::NeverPattern => "any code following a never pattern is unreachable",
89+
DivergeReason::Other => "any code following this expression is unreachable",
90+
};
91+
lint.span_label(span, msg).span_label(orig_span, custom_note);
8692
})
8793
}
8894

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ use crate::method::MethodCallee;
4040
use crate::Expectation::*;
4141
use crate::TupleArgumentsFlag::*;
4242
use crate::{
43-
errors, struct_span_code_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs,
44-
TupleArgumentsFlag,
43+
errors, struct_span_code_err, BreakableCtxt, DivergeReason, Diverges, Expectation, FnCtxt,
44+
LoweredTy, Needs, TupleArgumentsFlag,
4545
};
4646

4747
#[derive(Clone, Copy, Default)]
@@ -1703,10 +1703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17031703
pub fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) {
17041704
self.check_decl(local.into());
17051705
if local.pat.is_never_pattern() {
1706-
self.diverges.set(Diverges::Always {
1707-
span: local.pat.span,
1708-
custom_note: Some("any code following a never pattern is unreachable"),
1709-
});
1706+
self.diverges.set(Diverges::Always(DivergeReason::NeverPattern, local.pat.span));
17101707
}
17111708
}
17121709

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ use typeck_root_ctxt::TypeckRootCtxt;
6464

6565
use crate::check::check_fn;
6666
use crate::coercion::DynamicCoerceMany;
67-
use crate::diverges::Diverges;
67+
use crate::diverges::{DivergeReason, Diverges};
6868
use crate::expectation::Expectation;
6969
use crate::fn_ctxt::LoweredTy;
7070
use crate::gather_locals::GatherLocalsVisitor;

0 commit comments

Comments
 (0)