Change syntax of the never type attribute thingy

Previous:
  ```rust
  #![rustc_never_type_mode = "fallback_to_unit|..."]
  ```

New:
  ```rust
  #![rustc_never_type_options(fallback = "unit|...")]
  ```
This allows adding other options for other never-related experiments.
This commit is contained in:
Maybe Waffle 2024-03-21 19:47:46 +00:00
parent 94b72d6beb
commit 6f2c6efe01
4 changed files with 63 additions and 40 deletions

View File

@ -597,9 +597,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
rustc_attr!( rustc_attr!(
rustc_never_type_mode, Normal, template!(NameValueStr: "fallback_to_unit|fallback_to_niko|fallback_to_never|no_fallback"), ErrorFollowing, rustc_never_type_options,
Normal,
template!(List: r#"/*opt*/ fallback = "unit|niko|never|no""#),
ErrorFollowing,
EncodeCrossCrate::No, EncodeCrossCrate::No,
"`rustc_never_type_fallback` is used to experiment with never type fallback and work on \ "`rustc_never_type_options` is used to experiment with never type fallback and work on \
never type stabilization, and will never be stable" never type stabilization, and will never be stable"
), ),

View File

@ -4,12 +4,11 @@ use rustc_data_structures::{
graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
unord::{UnordBag, UnordMap, UnordSet}, unord::{UnordBag, UnordMap, UnordSet},
}; };
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_span::sym;
enum DivergingFallbackBehavior { #[derive(Copy, Clone)]
pub enum DivergingFallbackBehavior {
/// Always fallback to `()` (aka "always spontaneous decay") /// Always fallback to `()` (aka "always spontaneous decay")
FallbackToUnit, FallbackToUnit,
/// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken. /// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken.
@ -78,9 +77,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
return false; return false;
} }
let diverging_behavior = self.diverging_fallback_behavior(); let diverging_fallback = self
let diverging_fallback = .calculate_diverging_fallback(&unresolved_variables, self.diverging_fallback_behavior);
self.calculate_diverging_fallback(&unresolved_variables, diverging_behavior);
// We do fallback in two passes, to try to generate // We do fallback in two passes, to try to generate
// better error messages. // better error messages.
@ -94,32 +92,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
fallback_occurred fallback_occurred
} }
fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior {
let Some((mode, span)) = self
.tcx
.get_attr(CRATE_DEF_ID, sym::rustc_never_type_mode)
.map(|attr| (attr.value_str().unwrap(), attr.span))
else {
if self.tcx.features().never_type_fallback {
return DivergingFallbackBehavior::FallbackToNiko;
}
return DivergingFallbackBehavior::FallbackToUnit;
};
match mode {
sym::fallback_to_unit => DivergingFallbackBehavior::FallbackToUnit,
sym::fallback_to_niko => DivergingFallbackBehavior::FallbackToNiko,
sym::fallback_to_never => DivergingFallbackBehavior::FallbackToNever,
sym::no_fallback => DivergingFallbackBehavior::NoFallback,
_ => {
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`)"));
DivergingFallbackBehavior::FallbackToUnit
}
}
}
fn fallback_effects(&self) -> bool { fn fallback_effects(&self) -> bool {
let unsolved_effects = self.unsolved_effects(); let unsolved_effects = self.unsolved_effects();

View File

@ -5,7 +5,9 @@ mod checks;
mod suggestions; mod suggestions;
use crate::coercion::DynamicCoerceMany; use crate::coercion::DynamicCoerceMany;
use crate::fallback::DivergingFallbackBehavior;
use crate::{CoroutineTypes, Diverges, EnclosingBreakables, Inherited}; use crate::{CoroutineTypes, Diverges, EnclosingBreakables, Inherited};
use hir::def_id::CRATE_DEF_ID;
use rustc_errors::{DiagCtxt, ErrorGuaranteed}; use rustc_errors::{DiagCtxt, ErrorGuaranteed};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
@ -18,7 +20,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{self, Span, DUMMY_SP}; use rustc_span::{self, sym, Span, DUMMY_SP};
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
@ -108,6 +110,8 @@ pub struct FnCtxt<'a, 'tcx> {
pub(super) inh: &'a Inherited<'tcx>, pub(super) inh: &'a Inherited<'tcx>,
pub(super) fallback_has_occurred: Cell<bool>, pub(super) fallback_has_occurred: Cell<bool>,
pub(super) diverging_fallback_behavior: DivergingFallbackBehavior,
} }
impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -116,6 +120,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
body_id: LocalDefId, body_id: LocalDefId,
) -> FnCtxt<'a, 'tcx> { ) -> FnCtxt<'a, 'tcx> {
let diverging_fallback_behavior = parse_never_type_options_attr(inh.tcx);
FnCtxt { FnCtxt {
body_id, body_id,
param_env, param_env,
@ -131,6 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}), }),
inh, inh,
fallback_has_occurred: Cell::new(false), fallback_has_occurred: Cell::new(false),
diverging_fallback_behavior,
} }
} }
@ -374,3 +380,47 @@ impl<'tcx> LoweredTy<'tcx> {
LoweredTy { raw, normalized } LoweredTy { raw, normalized }
} }
} }
fn parse_never_type_options_attr(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior {
use DivergingFallbackBehavior::*;
// Error handling is dubious here (unwraps), but that's probably fine for an internal attribute.
// Just don't write incorrect attributes <3
let mut fallback = None;
let items = tcx
.get_attr(CRATE_DEF_ID, sym::rustc_never_type_options)
.map(|attr| attr.meta_item_list().unwrap())
.unwrap_or_default();
for item in items {
if item.has_name(sym::fallback) && fallback.is_none() {
let mode = item.value_str().unwrap();
match mode {
sym::unit => fallback = Some(FallbackToUnit),
sym::niko => fallback = Some(FallbackToNiko),
sym::never => fallback = Some(FallbackToNever),
sym::no => fallback = Some(NoFallback),
_ => {
tcx.dcx().span_err(item.span(), format!("unknown never type fallback mode: `{mode}` (supported: `unit`, `niko`, `never` and `no`)"));
}
};
continue;
}
tcx.dcx().span_err(
item.span(),
format!(
"unknown never type option: `{}` (supported: `fallback`)",
item.name_or_empty()
),
);
}
let fallback = fallback.unwrap_or_else(|| {
if tcx.features().never_type_fallback { FallbackToNiko } else { FallbackToUnit }
});
fallback
}

View File

@ -814,9 +814,7 @@ symbols! {
fadd_algebraic, fadd_algebraic,
fadd_fast, fadd_fast,
fake_variadic, fake_variadic,
fallback_to_never, fallback,
fallback_to_niko,
fallback_to_unit,
fdiv_algebraic, fdiv_algebraic,
fdiv_fast, fdiv_fast,
feature, feature,
@ -1227,6 +1225,7 @@ symbols! {
new_v1, new_v1,
new_v1_formatted, new_v1_formatted,
next, next,
niko,
nll, nll,
no, no,
no_builtins, no_builtins,
@ -1235,7 +1234,6 @@ symbols! {
no_crate_inject, no_crate_inject,
no_debug, no_debug,
no_default_passes, no_default_passes,
no_fallback,
no_implicit_prelude, no_implicit_prelude,
no_inline, no_inline,
no_link, no_link,
@ -1553,7 +1551,7 @@ symbols! {
rustc_mir, rustc_mir,
rustc_must_implement_one_of, rustc_must_implement_one_of,
rustc_never_returns_null_ptr, rustc_never_returns_null_ptr,
rustc_never_type_mode, rustc_never_type_options,
rustc_no_mir_inline, rustc_no_mir_inline,
rustc_nonnull_optimization_guaranteed, rustc_nonnull_optimization_guaranteed,
rustc_nounwind, rustc_nounwind,