Skip to content

Commit 4e02b7a

Browse files
committed
Add feature(no_never_type_fallback) to allow experimenting
1 parent ee03c28 commit 4e02b7a

File tree

5 files changed

+96
-34
lines changed

5 files changed

+96
-34
lines changed

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ declare_features! (
211211
(unstable, multiple_supertrait_upcastable, "1.69.0", None),
212212
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
213213
(internal, negative_bounds, "1.71.0", None),
214+
/// Turns off never type fallback altogether
215+
(unstable, no_never_type_fallback, "CURRENT_RUSTC_VERSION", None), // no tracking issue (yet?)
214216
/// Allows using `#[omit_gdb_pretty_printer_section]`.
215217
(internal, omit_gdb_pretty_printer_section, "1.5.0", None),
216218
/// Set the maximum pattern complexity allowed (not limited by default).

compiler/rustc_hir_typeck/src/fallback.rs

+78-34
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ use rustc_data_structures::{
77
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
88
use rustc_middle::ty::{self, Ty};
99

10+
enum DivergingFallbackBehavior {
11+
/// Always fallback to `()` (aka "always spontaneous decay")
12+
FallbackToUnit,
13+
/// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken.
14+
FallbackToNiko,
15+
/// Don't fallback at all
16+
Nope,
17+
}
18+
1019
impl<'tcx> FnCtxt<'_, 'tcx> {
1120
/// Performs type inference fallback, setting `FnCtxt::fallback_has_occurred`
1221
/// if fallback has occurred.
@@ -64,7 +73,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
6473
return false;
6574
}
6675

67-
let diverging_fallback = self.calculate_diverging_fallback(&unresolved_variables);
76+
let diverging_behavior = self.diverging_fallback_behavior();
77+
let diverging_fallback =
78+
self.calculate_diverging_fallback(&unresolved_variables, diverging_behavior);
6879

6980
// We do fallback in two passes, to try to generate
7081
// better error messages.
@@ -78,6 +89,26 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
7889
fallback_occurred
7990
}
8091

92+
fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior {
93+
let niko = self.tcx.features().never_type_fallback;
94+
let nope = self.tcx.features().no_never_type_fallback;
95+
96+
if niko as u32 + nope as u32 > 1 {
97+
self.tcx.dcx().err("can't enable multiple never type fallback features (`never_type_fallback`, `no_never_type_fallback`)");
98+
return DivergingFallbackBehavior::FallbackToUnit;
99+
}
100+
101+
if niko {
102+
return DivergingFallbackBehavior::FallbackToNiko;
103+
}
104+
105+
if nope {
106+
return DivergingFallbackBehavior::Nope;
107+
}
108+
109+
DivergingFallbackBehavior::FallbackToUnit
110+
}
111+
81112
fn fallback_effects(&self) -> bool {
82113
let unsolved_effects = self.unsolved_effects();
83114

@@ -232,6 +263,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
232263
fn calculate_diverging_fallback(
233264
&self,
234265
unresolved_variables: &[Ty<'tcx>],
266+
behavior: DivergingFallbackBehavior,
235267
) -> UnordMap<Ty<'tcx>, Ty<'tcx>> {
236268
debug!("calculate_diverging_fallback({:?})", unresolved_variables);
237269

@@ -345,39 +377,51 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
345377
output: infer_var_infos.items().any(|info| info.output),
346378
};
347379

348-
if found_infer_var_info.self_in_trait && found_infer_var_info.output {
349-
// This case falls back to () to ensure that the code pattern in
350-
// tests/ui/never_type/fallback-closure-ret.rs continues to
351-
// compile when never_type_fallback is enabled.
352-
//
353-
// This rule is not readily explainable from first principles,
354-
// but is rather intended as a patchwork fix to ensure code
355-
// which compiles before the stabilization of never type
356-
// fallback continues to work.
357-
//
358-
// Typically this pattern is encountered in a function taking a
359-
// closure as a parameter, where the return type of that closure
360-
// (checked by `relationship.output`) is expected to implement
361-
// some trait (checked by `relationship.self_in_trait`). This
362-
// can come up in non-closure cases too, so we do not limit this
363-
// rule to specifically `FnOnce`.
364-
//
365-
// When the closure's body is something like `panic!()`, the
366-
// return type would normally be inferred to `!`. However, it
367-
// needs to fall back to `()` in order to still compile, as the
368-
// trait is specifically implemented for `()` but not `!`.
369-
//
370-
// For details on the requirements for these relationships to be
371-
// set, see the relationship finding module in
372-
// compiler/rustc_trait_selection/src/traits/relationships.rs.
373-
debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
374-
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
375-
} else if can_reach_non_diverging {
376-
debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
377-
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
378-
} else {
379-
debug!("fallback to ! - all diverging: {:?}", diverging_vid);
380-
diverging_fallback.insert(diverging_ty, Ty::new_diverging_default(self.tcx));
380+
use DivergingFallbackBehavior::*;
381+
match behavior {
382+
FallbackToUnit => {
383+
debug!("fallback to () - legacy: {:?}", diverging_vid);
384+
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
385+
}
386+
FallbackToNiko => {
387+
if found_infer_var_info.self_in_trait && found_infer_var_info.output {
388+
// This case falls back to () to ensure that the code pattern in
389+
// tests/ui/never_type/fallback-closure-ret.rs continues to
390+
// compile when never_type_fallback is enabled.
391+
//
392+
// This rule is not readily explainable from first principles,
393+
// but is rather intended as a patchwork fix to ensure code
394+
// which compiles before the stabilization of never type
395+
// fallback continues to work.
396+
//
397+
// Typically this pattern is encountered in a function taking a
398+
// closure as a parameter, where the return type of that closure
399+
// (checked by `relationship.output`) is expected to implement
400+
// some trait (checked by `relationship.self_in_trait`). This
401+
// can come up in non-closure cases too, so we do not limit this
402+
// rule to specifically `FnOnce`.
403+
//
404+
// When the closure's body is something like `panic!()`, the
405+
// return type would normally be inferred to `!`. However, it
406+
// needs to fall back to `()` in order to still compile, as the
407+
// trait is specifically implemented for `()` but not `!`.
408+
//
409+
// For details on the requirements for these relationships to be
410+
// set, see the relationship finding module in
411+
// compiler/rustc_trait_selection/src/traits/relationships.rs.
412+
debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
413+
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
414+
} else if can_reach_non_diverging {
415+
debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
416+
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
417+
} else {
418+
debug!("fallback to ! - all diverging: {:?}", diverging_vid);
419+
diverging_fallback.insert(diverging_ty, self.tcx.types.never);
420+
}
421+
}
422+
Nope => {
423+
debug!("not fallback - `feature(no_never_type_fallback)`: {:?}", diverging_vid);
424+
}
381425
}
382426
}
383427

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,7 @@ symbols! {
12381238
no_link,
12391239
no_main,
12401240
no_mangle,
1241+
no_never_type_fallback,
12411242
no_sanitize,
12421243
no_stack_check,
12431244
no_start,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// There is no test that could fail iif `no_never_type_fallback` is disabled,
2+
// since this feature only ever makes less code compile.
3+
//
4+
// So we silence tidy by not providing a main function here :/
5+
6+
//~ error: `main` function not found
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0601]: `main` function not found in crate `feature_gate_no_never_type_fallback`
2+
--> $DIR/feature-gate-no_never_type_fallback.rs:6:38
3+
|
4+
LL |
5+
| ^ consider adding a `main` function to `$DIR/feature-gate-no_never_type_fallback.rs`
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0601`.

0 commit comments

Comments
 (0)