Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/removed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ declare_features! (
Some("subsumed by `#![feature(allocator_internals)]`")),
/// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
(removed, negate_unsigned, "1.0.0", Some(29645), None),
/// Allows diverging expressions to fall back to `!` rather than `()`.
(removed, never_type_fallback, "CURRENT_RUSTC_VERSION", Some(65992), Some("removed in favor of unconditional fallback"), 148871),
/// Allows `#[no_coverage]` on functions.
/// The feature was renamed to `coverage_attribute` and the attribute to `#[coverage(on|off)]`
(removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`"), 114656),
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,8 +594,6 @@ declare_features! (
(incomplete, never_patterns, "1.76.0", Some(118155)),
/// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more.
(unstable, never_type, "1.13.0", Some(35121)),
/// Allows diverging expressions to fall back to `!` rather than `()`.
(unstable, never_type_fallback, "1.41.0", Some(65992)),
/// Switch `..` syntax to use the new (`Copy + IntoIterator`) range types.
(unstable, new_range, "1.86.0", Some(123741)),
/// Allows `#![no_core]`.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
// so we can just make the hidden type be `!`.
// For backwards compatibility reasons, we fall back to
// `()` until we the diverging default is changed.
EarlyBinder::bind(Ty::new_diverging_default(tcx))
EarlyBinder::bind(tcx.types.unit)
}
}
DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(owner_def_id) {
Expand Down
296 changes: 51 additions & 245 deletions compiler/rustc_hir_typeck/src/fallback.rs

Large diffs are not rendered by default.

14 changes: 5 additions & 9 deletions compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ pub(crate) struct FnCtxt<'a, 'tcx> {

pub(super) root_ctxt: &'a TypeckRootCtxt<'tcx>,

pub(super) fallback_has_occurred: Cell<bool>,
/// True if a divirging inference variable has been set to `()`/`!` because
/// of never type fallback. This is only used for diagnostics.
pub(super) diverging_fallback_has_occurred: Cell<bool>,

pub(super) diverging_fallback_behavior: DivergingFallbackBehavior,
pub(super) diverging_block_behavior: DivergingBlockBehavior,
Expand Down Expand Up @@ -153,7 +155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
by_id: Default::default(),
}),
root_ctxt,
fallback_has_occurred: Cell::new(false),
diverging_fallback_has_occurred: Cell::new(false),
diverging_fallback_behavior,
diverging_block_behavior,
trait_ascriptions: Default::default(),
Expand Down Expand Up @@ -190,7 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
TypeErrCtxt {
infcx: &self.infcx,
typeck_results: Some(self.typeck_results.borrow()),
fallback_has_occurred: self.fallback_has_occurred.get(),
diverging_fallback_has_occurred: self.diverging_fallback_has_occurred.get(),
normalize_fn_sig: Box::new(|fn_sig| {
if fn_sig.has_escaping_bound_vars() {
return fn_sig;
Expand Down Expand Up @@ -505,11 +507,6 @@ fn default_fallback(tcx: TyCtxt<'_>) -> DivergingFallbackBehavior {
return DivergingFallbackBehavior::ToNever;
}

// `feature(never_type_fallback)`: fallback to `!` or `()` trying to not break stuff
if tcx.features().never_type_fallback() {
return DivergingFallbackBehavior::ContextDependent;
}

// Otherwise: fallback to `()`
DivergingFallbackBehavior::ToUnit
}
Expand All @@ -536,7 +533,6 @@ fn parse_never_type_options_attr(
let mode = item.value_str().unwrap();
match mode {
sym::unit => fallback = Some(DivergingFallbackBehavior::ToUnit),
sym::niko => fallback = Some(DivergingFallbackBehavior::ContextDependent),
sym::never => fallback = Some(DivergingFallbackBehavior::ToNever),
sym::no => fallback = Some(DivergingFallbackBehavior::NoFallback),
_ => {
Expand Down
71 changes: 4 additions & 67 deletions compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,19 @@
use std::cell::{Cell, RefCell};
use std::ops::Deref;

use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_data_structures::unord::UnordSet;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{self as hir, HirId, HirIdMap, LangItem};
use rustc_hir::{self as hir, HirId, HirIdMap};
use rustc_infer::infer::{InferCtxt, InferOk, OpaqueTypeStorageEntries, TyCtxtInferExt};
use rustc_middle::span_bug;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode};
use rustc_span::Span;
use rustc_span::def_id::LocalDefIdMap;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
self, FulfillmentError, PredicateObligation, TraitEngine, TraitEngineExt as _,
};
use tracing::{debug, instrument};
use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine, TraitEngineExt as _};
use tracing::instrument;

use super::callee::DeferredCallResolution;

#[derive(Debug, Default, Copy, Clone)]
pub(crate) struct InferVarInfo {
/// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo`
/// obligation, where:
///
/// * `Foo` is not `Sized`
/// * `(): Foo` may be satisfied
pub self_in_trait: bool,
/// This is true if we identified that this Ty (`?T`) is found in a `<_ as
/// _>::AssocType = ?T`
pub output: bool,
}

/// Data shared between a "typeck root" and its nested bodies,
/// e.g. closures defined within the function. For example:
/// ```ignore (illustrative)
Expand Down Expand Up @@ -83,8 +67,6 @@ pub(crate) struct TypeckRootCtxt<'tcx> {
/// we record that type variable here. This is later used to inform
/// fallback. See the `fallback` module for details.
pub(super) diverging_type_vars: RefCell<UnordSet<Ty<'tcx>>>,

pub(super) infer_var_info: RefCell<UnordMap<ty::TyVid, InferVarInfo>>,
}

impl<'tcx> Deref for TypeckRootCtxt<'tcx> {
Expand Down Expand Up @@ -119,7 +101,6 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
deferred_asm_checks: RefCell::new(Vec::new()),
deferred_repeat_expr_checks: RefCell::new(Vec::new()),
diverging_type_vars: RefCell::new(Default::default()),
infer_var_info: RefCell::new(Default::default()),
}
}

Expand All @@ -129,8 +110,6 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
}

self.update_infer_var_info(&obligation);

self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation);
}

Expand All @@ -147,46 +126,4 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
self.register_predicates(infer_ok.obligations);
infer_ok.value
}

fn update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>) {
let infer_var_info = &mut self.infer_var_info.borrow_mut();

// (*) binder skipped
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) =
obligation.predicate.kind().skip_binder()
&& let Some(ty) =
self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
&& !self.tcx.is_lang_item(tpred.trait_ref.def_id, LangItem::Sized)
{
let new_self_ty = self.tcx.types.unit;

// Then construct a new obligation with Self = () added
// to the ParamEnv, and see if it holds.
let o = obligation.with(
self.tcx,
obligation.predicate.kind().rebind(
// (*) binder moved here
ty::PredicateKind::Clause(ty::ClauseKind::Trait(
tpred.with_replaced_self_ty(self.tcx, new_self_ty),
)),
),
);
// Don't report overflow errors. Otherwise equivalent to may_hold.
if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o))
&& result.may_apply()
{
infer_var_info.entry(ty).or_default().self_in_trait = true;
}
}

if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) =
obligation.predicate.kind().skip_binder()
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
&& let Some(vid) = predicate.term.as_type().and_then(|ty| ty.ty_vid())
{
debug!("infer_var_info: {:?}.output = true", vid);
infer_var_info.entry(vid).or_default().output = true;
}
}
}
5 changes: 0 additions & 5 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -878,11 +878,6 @@ impl<'tcx> Ty<'tcx> {
Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_)
}

#[inline]
pub fn new_diverging_default(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
if tcx.features().never_type_fallback() { tcx.types.never } else { tcx.types.unit }
}

// lang and diagnostic tys

fn new_generic_adt(tcx: TyCtxt<'tcx>, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_trait_selection/src/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub struct TypeErrCtxt<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>,

pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
pub fallback_has_occurred: bool,
pub diverging_fallback_has_occurred: bool,

pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,

Expand All @@ -36,7 +36,7 @@ impl<'tcx> InferCtxt<'tcx> {
TypeErrCtxt {
infcx: self,
typeck_results: None,
fallback_has_occurred: false,
diverging_fallback_has_occurred: false,
normalize_fn_sig: Box::new(|fn_sig| fn_sig),
autoderef_steps: Box::new(|ty| {
debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// variable that used to fallback to `()` now falling back to `!`. Issue a
// note informing about the change in behaviour.
if leaf_trait_predicate.skip_binder().self_ty().is_never()
&& self.fallback_has_occurred
&& self.diverging_fallback_has_occurred
{
let predicate = leaf_trait_predicate.map_bound(|trait_pred| {
trait_pred.with_replaced_self_ty(self.tcx, tcx.types.unit)
Expand All @@ -550,8 +550,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if self.predicate_may_hold(&unit_obligation) {
err.note(
"this error might have been caused by changes to \
Rust's type-inference algorithm (see issue #48950 \
<https://github.com/rust-lang/rust/issues/48950> \
Rust's type-inference algorithm (see issue #148922 \
<https://github.com/rust-lang/rust/issues/148922> \
for more information)",
);
err.help("you might have intended to use the type `()` here instead");
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/binding/empty-types-in-patterns.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//@ run-pass
//@ edition: 2024

#![feature(never_type, never_type_fallback)]
#![feature(never_type)]
#![feature(exhaustive_patterns)]

#![allow(unreachable_patterns)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0277]: the trait bound `(): std::error::Error` is not satisfied
--> $DIR/coerce-issue-49593-box-never.rs:18:5
--> $DIR/coerce-issue-49593-box-never.rs:17:5
|
LL | Box::<_ /* ! */>::new(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
= note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>`

error[E0277]: the trait bound `(): std::error::Error` is not satisfied
--> $DIR/coerce-issue-49593-box-never.rs:24:5
--> $DIR/coerce-issue-49593-box-never.rs:23:5
|
LL | raw_ptr_box::<_ /* ! */>(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
Expand Down
3 changes: 1 addition & 2 deletions tests/ui/coercion/coerce-issue-49593-box-never.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
//@ revisions: nofallback fallback
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

want to rename the revisions to "unit_fallback never_fallback"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a follow up

//@[fallback] edition: 2024
//@[fallback] check-pass

#![feature(never_type)]
#![cfg_attr(fallback, feature(never_type_fallback))]
#![allow(unreachable_code)]

use std::error::Error;
use std::mem;
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/editions/never-type-fallback-breaking.e2024.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0277]: the trait bound `!: Default` is not satisfied
LL | true => Default::default(),
| ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `!`
|
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information)
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 <https://github.com/rust-lang/rust/issues/148922> for more information)
= help: you might have intended to use the type `()` here instead

error[E0277]: the trait bound `!: Default` is not satisfied
Expand All @@ -13,7 +13,7 @@ error[E0277]: the trait bound `!: Default` is not satisfied
LL | deserialize()?;
| ^^^^^^^^^^^^^ the trait `Default` is not implemented for `!`
|
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information)
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 <https://github.com/rust-lang/rust/issues/148922> for more information)
= help: you might have intended to use the type `()` here instead
note: required by a bound in `deserialize`
--> $DIR/never-type-fallback-breaking.rs:31:23
Expand Down Expand Up @@ -50,7 +50,7 @@ error[E0277]: the trait bound `!: Default` is not satisfied
LL | takes_apit(|| Default::default())?;
| ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `!`
|
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information)
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 <https://github.com/rust-lang/rust/issues/148922> for more information)
= help: you might have intended to use the type `()` here instead

error[E0277]: the trait bound `!: Default` is not satisfied
Expand All @@ -61,7 +61,7 @@ LL | takes_apit2(mk()?);
| |
| required by a bound introduced by this call
|
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information)
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 <https://github.com/rust-lang/rust/issues/148922> for more information)
= help: you might have intended to use the type `()` here instead
note: required by a bound in `takes_apit2`
--> $DIR/never-type-fallback-breaking.rs:69:25
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/never_type/defaulted-never-note.fallback.stderr
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied
--> $DIR/defaulted-never-note.rs:31:9
--> $DIR/defaulted-never-note.rs:27:9
|
LL | foo(_x);
| --- ^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!`
| |
| required by a bound introduced by this call
|
help: the trait `ImplementedForUnitButNotNever` is implemented for `()`
--> $DIR/defaulted-never-note.rs:24:1
--> $DIR/defaulted-never-note.rs:20:1
|
LL | impl ImplementedForUnitButNotNever for () {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information)
= note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #148922 <https://github.com/rust-lang/rust/issues/148922> for more information)
= help: you might have intended to use the type `()` here instead
note: required by a bound in `foo`
--> $DIR/defaulted-never-note.rs:26:11
--> $DIR/defaulted-never-note.rs:22:11
|
LL | fn foo<T: ImplementedForUnitButNotNever>(_t: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/never_type/defaulted-never-note.nofallback.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
Future incompatibility report: Future breakage diagnostic:
warning: this function depends on never type fallback being `()`
--> $DIR/defaulted-never-note.rs:29:1
--> $DIR/defaulted-never-note.rs:25:1
|
LL | fn smeg() {
| ^^^^^^^^^
|
= help: specify the types explicitly
note: in edition 2024, the requirement `!: ImplementedForUnitButNotNever` will fail
--> $DIR/defaulted-never-note.rs:31:9
--> $DIR/defaulted-never-note.rs:27:9
|
LL | foo(_x);
| ^^
Expand Down
8 changes: 2 additions & 6 deletions tests/ui/never_type/defaulted-never-note.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
//@ revisions: nofallback fallback
//@[fallback] edition: 2024
//@[nofallback] run-pass
//@[fallback] check-fail

// We need to opt into the `never_type_fallback` feature
// to trigger the requirement that this is testing.
#![cfg_attr(fallback, feature(never_type, never_type_fallback))]

#![allow(unused)]
#![expect(dependency_on_unit_never_type_fallback)]
#![expect(dependency_on_unit_never_type_fallback, unused)]

trait Deserialize: Sized {
fn deserialize() -> Result<Self, String>;
Expand Down
Loading
Loading