Skip to content

Commit eed676f

Browse files
authored
Unrolled build for rust-lang#122543
Rollup merge of rust-lang#122543 - WaffleLapkin:never-flags, r=compiler-errors Add `#![rustc_never_type_mode = "..."]` crate-level attribute to allow experimenting Demonstrating how different approaches with the never type work is somewhat hard when you can't actually provide a runnable example. Let's add features that change the fallback behavior. This adds `#![rustc_never_type_mode = "no_fallback"]` and `#![rustc_never_type_mode = "fallback_to_never"]`, but I also plan to add others (in future PRs). cc ``@traviscross`` r? ``@compiler-errors``
2 parents 1ca424c + adfdd27 commit eed676f

File tree

3 files changed

+111
-34
lines changed

3 files changed

+111
-34
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

+7
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
580580
"`may_dangle` has unstable semantics and may be removed in the future",
581581
),
582582

583+
rustc_attr!(
584+
rustc_never_type_mode, Normal, template!(NameValueStr: "fallback_to_unit|fallback_to_niko|fallback_to_never|no_fallback"), ErrorFollowing,
585+
@only_local: true,
586+
"`rustc_never_type_fallback` is used to experiment with never type fallback and work on \
587+
never type stabilization, and will never be stable"
588+
),
589+
583590
// ==========================================================================
584591
// Internal attributes: Runtime related:
585592
// ==========================================================================

compiler/rustc_hir_typeck/src/fallback.rs

+99-34
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,22 @@ use rustc_data_structures::{
44
graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
55
unord::{UnordBag, UnordMap, UnordSet},
66
};
7+
use rustc_hir::def_id::CRATE_DEF_ID;
78
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
89
use rustc_middle::ty::{self, Ty};
10+
use rustc_span::sym;
11+
12+
enum DivergingFallbackBehavior {
13+
/// Always fallback to `()` (aka "always spontaneous decay")
14+
FallbackToUnit,
15+
/// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken.
16+
FallbackToNiko,
17+
/// Always fallback to `!` (which should be equivalent to never falling back + not making
18+
/// never-to-any coercions unless necessary)
19+
FallbackToNever,
20+
/// Don't fallback at all
21+
NoFallback,
22+
}
923

1024
impl<'tcx> FnCtxt<'_, 'tcx> {
1125
/// Performs type inference fallback, setting `FnCtxt::fallback_has_occurred`
@@ -64,7 +78,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
6478
return false;
6579
}
6680

67-
let diverging_fallback = self.calculate_diverging_fallback(&unresolved_variables);
81+
let diverging_behavior = self.diverging_fallback_behavior();
82+
let diverging_fallback =
83+
self.calculate_diverging_fallback(&unresolved_variables, diverging_behavior);
6884

6985
// We do fallback in two passes, to try to generate
7086
// better error messages.
@@ -78,6 +94,32 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
7894
fallback_occurred
7995
}
8096

97+
fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior {
98+
let Some((mode, span)) = self
99+
.tcx
100+
.get_attr(CRATE_DEF_ID, sym::rustc_never_type_mode)
101+
.map(|attr| (attr.value_str().unwrap(), attr.span))
102+
else {
103+
if self.tcx.features().never_type_fallback {
104+
return DivergingFallbackBehavior::FallbackToNiko;
105+
}
106+
107+
return DivergingFallbackBehavior::FallbackToUnit;
108+
};
109+
110+
match mode {
111+
sym::fallback_to_unit => DivergingFallbackBehavior::FallbackToUnit,
112+
sym::fallback_to_niko => DivergingFallbackBehavior::FallbackToNiko,
113+
sym::fallback_to_never => DivergingFallbackBehavior::FallbackToNever,
114+
sym::no_fallback => DivergingFallbackBehavior::NoFallback,
115+
_ => {
116+
self.tcx.dcx().span_err(span, format!("unknown never type mode: `{mode}` (supported: `fallback_to_unit`, `fallback_to_niko`, `fallback_to_never` and `no_fallback`)"));
117+
118+
DivergingFallbackBehavior::FallbackToUnit
119+
}
120+
}
121+
}
122+
81123
fn fallback_effects(&self) -> bool {
82124
let unsolved_effects = self.unsolved_effects();
83125

@@ -232,6 +274,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
232274
fn calculate_diverging_fallback(
233275
&self,
234276
unresolved_variables: &[Ty<'tcx>],
277+
behavior: DivergingFallbackBehavior,
235278
) -> UnordMap<Ty<'tcx>, Ty<'tcx>> {
236279
debug!("calculate_diverging_fallback({:?})", unresolved_variables);
237280

@@ -345,39 +388,61 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
345388
output: infer_var_infos.items().any(|info| info.output),
346389
};
347390

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));
391+
use DivergingFallbackBehavior::*;
392+
match behavior {
393+
FallbackToUnit => {
394+
debug!("fallback to () - legacy: {:?}", diverging_vid);
395+
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
396+
}
397+
FallbackToNiko => {
398+
if found_infer_var_info.self_in_trait && found_infer_var_info.output {
399+
// This case falls back to () to ensure that the code pattern in
400+
// tests/ui/never_type/fallback-closure-ret.rs continues to
401+
// compile when never_type_fallback is enabled.
402+
//
403+
// This rule is not readily explainable from first principles,
404+
// but is rather intended as a patchwork fix to ensure code
405+
// which compiles before the stabilization of never type
406+
// fallback continues to work.
407+
//
408+
// Typically this pattern is encountered in a function taking a
409+
// closure as a parameter, where the return type of that closure
410+
// (checked by `relationship.output`) is expected to implement
411+
// some trait (checked by `relationship.self_in_trait`). This
412+
// can come up in non-closure cases too, so we do not limit this
413+
// rule to specifically `FnOnce`.
414+
//
415+
// When the closure's body is something like `panic!()`, the
416+
// return type would normally be inferred to `!`. However, it
417+
// needs to fall back to `()` in order to still compile, as the
418+
// trait is specifically implemented for `()` but not `!`.
419+
//
420+
// For details on the requirements for these relationships to be
421+
// set, see the relationship finding module in
422+
// compiler/rustc_trait_selection/src/traits/relationships.rs.
423+
debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
424+
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
425+
} else if can_reach_non_diverging {
426+
debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
427+
diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
428+
} else {
429+
debug!("fallback to ! - all diverging: {:?}", diverging_vid);
430+
diverging_fallback.insert(diverging_ty, self.tcx.types.never);
431+
}
432+
}
433+
FallbackToNever => {
434+
debug!(
435+
"fallback to ! - `rustc_never_type_mode = \"fallback_to_never\")`: {:?}",
436+
diverging_vid
437+
);
438+
diverging_fallback.insert(diverging_ty, self.tcx.types.never);
439+
}
440+
NoFallback => {
441+
debug!(
442+
"no fallback - `rustc_never_type_mode = \"no_fallback\"`: {:?}",
443+
diverging_vid
444+
);
445+
}
381446
}
382447
}
383448

compiler/rustc_span/src/symbol.rs

+5
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,9 @@ symbols! {
815815
fadd_algebraic,
816816
fadd_fast,
817817
fake_variadic,
818+
fallback_to_never,
819+
fallback_to_niko,
820+
fallback_to_unit,
818821
fdiv_algebraic,
819822
fdiv_fast,
820823
feature,
@@ -1233,6 +1236,7 @@ symbols! {
12331236
no_crate_inject,
12341237
no_debug,
12351238
no_default_passes,
1239+
no_fallback,
12361240
no_implicit_prelude,
12371241
no_inline,
12381242
no_link,
@@ -1551,6 +1555,7 @@ symbols! {
15511555
rustc_mir,
15521556
rustc_must_implement_one_of,
15531557
rustc_never_returns_null_ptr,
1558+
rustc_never_type_mode,
15541559
rustc_no_mir_inline,
15551560
rustc_nonnull_optimization_guaranteed,
15561561
rustc_nounwind,

0 commit comments

Comments
 (0)