Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f6e7f7c

Browse files
camsteffencjgillot
authored andcommittedOct 30, 2024
Refactor Diverges in typeck
Avoid deriving PartialOrd on Diverges since it includes fields which should not affect ordering.
1 parent 298c746 commit f6e7f7c

File tree

7 files changed

+55
-58
lines changed

7 files changed

+55
-58
lines changed
 

‎compiler/rustc_hir_typeck/src/_match.rs‎

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{
1111
use tracing::{debug, instrument};
1212

1313
use crate::coercion::{AsCoercionSite, CoerceMany};
14-
use crate::{Diverges, Expectation, FnCtxt, Needs};
14+
use crate::{DivergeReason, Diverges, Expectation, FnCtxt, Needs};
1515

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

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

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

162158
// 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
@@ -16,7 +16,7 @@ use tracing::{debug, instrument};
1616

1717
use crate::coercion::CoerceMany;
1818
use crate::gather_locals::GatherLocalsVisitor;
19-
use crate::{CoroutineTypes, Diverges, FnCtxt};
19+
use crate::{CoroutineTypes, DivergeReason, Diverges, FnCtxt};
2020

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

9896
// 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::{DUMMY_SP, Span};
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(crate) 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(crate) 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(crate) enum DivergeReason {
73+
AllArmsDiverge,
74+
NeverPattern,
75+
Other,
76+
}

‎compiler/rustc_hir_typeck/src/expr.rs‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ use crate::errors::{
5050
YieldExprOutsideOfCoroutine,
5151
};
5252
use crate::{
53-
BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, cast, fatally_break_rust,
54-
report_unexpected_variant_res, type_error_struct,
53+
BreakableCtxt, CoroutineTypes, DivergeReason, Diverges, FnCtxt, Needs, cast,
54+
fatally_break_rust, report_unexpected_variant_res, type_error_struct,
5555
};
5656

5757
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -246,7 +246,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
246246
// diverging would be unsound since we may never actually read the `!`.
247247
// e.g. `let _ = *never_ptr;` with `never_ptr: *const !`.
248248
if ty.is_never() && self.expr_guaranteed_to_constitute_read_for_never(expr) {
249-
self.diverges.set(self.diverges.get() | Diverges::always(expr.span));
249+
self.diverges
250+
.set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span));
250251
}
251252

252253
// Record the type, which applies it effects.
@@ -1507,7 +1508,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15071508
// of a `break` or an outer `break` or `return`.
15081509
self.diverges.set(Diverges::Maybe);
15091510
} else {
1510-
self.diverges.set(self.diverges.get() | Diverges::always(expr.span));
1511+
self.diverges
1512+
.set(self.diverges.get() | Diverges::Always(DivergeReason::Other, expr.span));
15111513
}
15121514

15131515
// If we permit break with a value, then result type is
@@ -1610,7 +1612,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16101612
})
16111613
.unwrap_or_else(|| self.next_ty_var(expr.span));
16121614
let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
1613-
assert_eq!(self.diverges.get(), Diverges::Maybe);
1615+
assert!(matches!(self.diverges.get(), Diverges::Maybe));
16141616
for e in args {
16151617
let e_ty = self.check_expr_with_hint(e, coerce_to);
16161618
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 tracing::{debug, instrument};
4242
use crate::callee::{self, DeferredCallResolution};
4343
use crate::errors::{self, CtorIsPrivate};
4444
use crate::method::{self, MethodCallee};
45-
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, rvalue_scopes};
45+
use crate::{
46+
BreakableCtxt, DivergeReason, Diverges, Expectation, FnCtxt, LoweredTy, rvalue_scopes,
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
@@ -42,8 +42,8 @@ use crate::method::probe::IsSuggestion;
4242
use crate::method::probe::Mode::MethodCall;
4343
use crate::method::probe::ProbeScope::TraitsInScope;
4444
use crate::{
45-
BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, TupleArgumentsFlag, errors,
46-
struct_span_code_err,
45+
BreakableCtxt, DivergeReason, Diverges, Expectation, FnCtxt, LoweredTy, Needs,
46+
TupleArgumentsFlag, errors, struct_span_code_err,
4747
};
4848

4949
#[derive(Clone, Copy, Default)]
@@ -1761,10 +1761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17611761
fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) {
17621762
self.check_decl(local.into());
17631763
if local.pat.is_never_pattern() {
1764-
self.diverges.set(Diverges::Always {
1765-
span: local.pat.span,
1766-
custom_note: Some("any code following a never pattern is unreachable"),
1767-
});
1764+
self.diverges.set(Diverges::Always(DivergeReason::NeverPattern, local.pat.span));
17681765
}
17691766
}
17701767

‎compiler/rustc_hir_typeck/src/lib.rs‎

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

6262
use crate::check::check_fn;
6363
use crate::coercion::DynamicCoerceMany;
64-
use crate::diverges::Diverges;
64+
use crate::diverges::{DivergeReason, Diverges};
6565
use crate::expectation::Expectation;
6666
use crate::fn_ctxt::LoweredTy;
6767
use crate::gather_locals::GatherLocalsVisitor;

0 commit comments

Comments
 (0)
Please sign in to comment.