From 0d0aaa1a54d8136524d0cfd4bd6346f8b431afb7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 20 Apr 2026 19:56:55 +1000 Subject: [PATCH 01/21] Some arena macro tweaks. - Improve a comment. - Remove unused `[decode]` annotations on some arenas. - Improve `impl_arena_allocatable_decoder`: - Make the first rule more like the second rule. - Remove unnecessary brackets. - Remove unused support for attributes other than `decode`. --- compiler/rustc_middle/src/arena.rs | 11 +++++------ compiler/rustc_middle/src/ty/codec.rs | 7 +++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index de6a105ee2b7b..e12583f38fe72 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -1,7 +1,7 @@ /// This higher-order macro declares a list of types which can be allocated by `Arena`. /// /// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]` where `T` is the type -/// listed. These impls will appear in the implement_ty_decoder! macro. +/// listed. See the `impl_arena_allocatable_decoder!` macro for more. #[macro_export] macro_rules! arena_types { ($macro:path) => ( @@ -9,8 +9,7 @@ macro_rules! arena_types { [] layout: rustc_abi::LayoutData, [] proxy_coroutine_layout: rustc_middle::mir::CoroutineLayout<'tcx>, [] fn_abi: rustc_target::callconv::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>, - // AdtDef are interned and compared by address - [decode] adt_def: rustc_middle::ty::AdtDefData, + [] adt_def: rustc_middle::ty::AdtDefData, [] steal_thir: rustc_data_structures::steal::Steal>, [] steal_mir: rustc_data_structures::steal::Steal>, [decode] mir: rustc_middle::mir::Body<'tcx>, @@ -27,7 +26,7 @@ macro_rules! arena_types { rustc_middle::mir::Body<'tcx> >, [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, - [decode] borrowck_result: rustc_data_structures::fx::FxIndexMap< + [] borrowck_result: rustc_data_structures::fx::FxIndexMap< rustc_hir::def_id::LocalDefId, rustc_middle::ty::DefinitionSiteHiddenType<'tcx>, >, @@ -100,7 +99,7 @@ macro_rules! arena_types { // (during lowering) and the `rustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::InlineAsmTemplatePiece, [decode] used_trait_imports: rustc_data_structures::unord::UnordSet, - [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet, + [] is_late_bound_map: rustc_data_structures::fx::FxIndexSet, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, [] dep_kind_vtable: rustc_middle::dep_graph::DepKindVTable<'tcx>, @@ -111,7 +110,7 @@ macro_rules! arena_types { rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>> >, [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData>, - [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, + [] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] stripped_cfg_items: rustc_hir::attrs::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, [] features: rustc_feature::Features, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 28bdeabf34dc1..8b1e812582783 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -513,9 +513,8 @@ macro_rules! __impl_decoder_methods { } macro_rules! impl_arena_allocatable_decoder { - ([]$args:tt) => {}; - ([decode $(, $attrs:ident)*] - [$name:ident: $ty:ty]) => { + ([] $name:ident: $ty:ty) => {}; + ([decode] $name:ident: $ty:ty) => { impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty { #[inline] fn decode(decoder: &mut D) -> &'tcx Self { @@ -535,7 +534,7 @@ macro_rules! impl_arena_allocatable_decoder { macro_rules! impl_arena_allocatable_decoders { ([$($a:tt $name:ident: $ty:ty,)*]) => { $( - impl_arena_allocatable_decoder!($a [$name: $ty]); + impl_arena_allocatable_decoder!($a $name: $ty); )* } } From cdefdd054cd04e43aec96d99042f14d01a8b8bb8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Apr 2026 08:54:38 +1000 Subject: [PATCH 02/21] Fix a metadata table name. The table names usually match the name of the corresponding query. The `trait_impl_trait_tys` table is an exception; this commit renames it `collect_return_position_impl_trait_in_trait_tys` to match the query. --- compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 8 +++++--- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index a00fb59963ac2..cbd6afd68473a 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -261,7 +261,8 @@ provide! { tcx, def_id, other, cdata, .coerce_unsized_info .get(cdata, def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) - .process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) } + .process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) + } mir_const_qualif => { table } rendered_const => { table } rendered_precise_capturing_args => { table } @@ -300,10 +301,10 @@ provide! { tcx, def_id, other, cdata, Ok(cdata .root .tables - .trait_impl_trait_tys + .collect_return_position_impl_trait_in_trait_tys .get(cdata, def_id.index) .map(|lazy| lazy.decode((cdata, tcx))) - .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys"))) + .process_decoded(tcx, || panic!("{def_id:?} does not have collect_return_position_impl_trait_in_trait_tys"))) } associated_types_for_impl_traits_in_trait_or_impl => { table } @@ -695,6 +696,7 @@ impl CrateStore for CStore { fn as_any(&self) -> &dyn Any { self } + fn untracked_as_any(&mut self) -> &mut dyn Any { self } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 729a0dda7cf3b..57fe9210c6276 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1628,7 +1628,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { - record!(self.tables.trait_impl_trait_tys[def_id] <- table); + record!(self.tables.collect_return_position_impl_trait_in_trait_tys[def_id] <- table); } if let DefKind::Impl { .. } | DefKind::Trait = def_kind { let table = tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index c7b2eaa15ebfb..a3645a5556bf3 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -466,7 +466,7 @@ define_tables! { macro_definition: Table>, proc_macro: Table, deduced_param_attrs: Table>, - trait_impl_trait_tys: Table>>>>, + collect_return_position_impl_trait_in_trait_tys: Table>>>>, doc_link_resolutions: Table>, doc_link_traits_in_scope: Table>, assumed_wf_types_for_rpitit: Table, Span)>>, From 3b5dd18d9a6b9e738daf4b3918e2eb2414b7e304 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 24 Apr 2026 14:57:56 +1000 Subject: [PATCH 03/21] Fix some comments. - Remove comment about blanket implementation of `FallibleTypeFolder` -- it does not exist. (It probably used to.) - Fix some incorrect name references. - Fix minor grammatical errors. - Fix stale comment on `visit_region` -- it was a no-op once, but no longer. LLM disclosure: Claude Code identified these problems with comments when I asked it to review `fold.rs` and `visit.rs`. I verified the correctness of the problems and made the changes by hand. --- compiler/rustc_type_ir/src/flags.rs | 2 +- compiler/rustc_type_ir/src/fold.rs | 12 ++++-------- compiler/rustc_type_ir/src/visit.rs | 16 ++++++++-------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 50c30f4252703..3debef168cffd 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -139,7 +139,7 @@ bitflags::bitflags! { /// Does this type have any coroutines in it? const HAS_TY_CORO = 1 << 25; - /// Does this have have a `Bound(BoundVarIndexKind::Canonical, _)`? + /// Does this have a `Bound(BoundVarIndexKind::Canonical, _)`? const HAS_CANONICAL_BOUND = 1 << 26; } } diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index d1a50599e8b9c..94d9845594628 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -121,10 +121,6 @@ pub trait TypeSuperFoldable: TypeFoldable { /// default that does an "identity" fold. Implementations of these methods /// often fall back to a `super_fold_with` method if the primary argument /// doesn't satisfy a particular condition. -/// -/// A blanket implementation of [`FallibleTypeFolder`] will defer to -/// the infallible methods of this trait to ensure that the two APIs -/// are coherent. pub trait TypeFolder: Sized { fn cx(&self) -> I; @@ -477,10 +473,10 @@ where /// Folds over the substructure of a type, visiting its component /// types and all regions that occur *free* within it. /// -/// That is, function pointer types and trait object can introduce -/// new bound regions which are not visited by this visitors as +/// That is, function pointer types and trait objects can introduce +/// new bound regions which are not visited by this visitor as /// they are not free; only regions that occur free will be -/// visited by `fld_r`. +/// visited by `fold_region_fn`. pub struct RegionFolder { cx: I, @@ -489,7 +485,7 @@ pub struct RegionFolder { /// binder, it is incremented (via `shift_in`). current_index: ty::DebruijnIndex, - /// Callback invokes for each free region. The `DebruijnIndex` + /// Callback invoked for each free region. The `DebruijnIndex` /// points to the binder *just outside* the ones we have passed /// through. fold_region_fn: F, diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index a078b860be774..6d0b307f013eb 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -67,7 +67,7 @@ pub trait TypeVisitable: fmt::Debug { /// each field/element. /// /// For types of interest (such as `Ty`), the implementation of this method - /// that calls a visitor method specifically for that type (such as + /// calls a visitor method specifically for that type (such as /// `V::visit_ty`). This is where control transfers from `TypeVisitable` to /// `TypeVisitor`. fn visit_with>(&self, visitor: &mut V) -> V::Result; @@ -102,8 +102,8 @@ pub trait TypeVisitor: Sized { t.super_visit_with(self) } - // The default region visitor is a no-op because `Region` is non-recursive - // and has no `super_visit_with` method to call. + // `Region` is non-recursive so the default region visitor has no + // `super_visit_with` method to call. fn visit_region(&mut self, r: I::Region) -> Self::Result { if let ty::ReError(guar) = r.kind() { self.visit_error(guar) @@ -251,10 +251,10 @@ pub trait TypeVisitableExt: TypeVisitable { self.has_vars_bound_at_or_above(binder.shifted_in(1)) } - /// Return `true` if this type has regions that are not a part of the type. - /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)` - /// would return `true`. The latter can occur when traversing through the - /// former. + /// Returns `true` if this type has regions that are not a part of the + /// type. For example, given a `for<'a> fn(&'a i32)` this function returns + /// `false`, while given a `fn(&'a i32)` it returns `true`. The latter can + /// occur when traversing through the former. /// /// See [`HasEscapingVarsVisitor`] for more information. fn has_escaping_bound_vars(&self) -> bool { @@ -571,7 +571,7 @@ impl TypeVisitor for HasEscapingVarsVisitor { // `outer_index`, that means that `ct` contains some content // bound at `outer_index` or above (because // `outer_exclusive_binder` is always 1 higher than the - // content in `t`). Therefore, `t` has some escaping vars. + // content in `ct`). Therefore, `ct` has some escaping vars. if ct.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { From a07a3b1bf15be2d344fca2ea6ad62071ed5e15b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2026 08:39:24 +0200 Subject: [PATCH 04/21] windows/time: avoid being too close to 0 --- library/std/src/sys/time/windows.rs | 7 +++++++ library/std/tests/time.rs | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/time/windows.rs b/library/std/src/sys/time/windows.rs index 2e38dbf5cf288..b2abee4219fe3 100644 --- a/library/std/src/sys/time/windows.rs +++ b/library/std/src/sys/time/windows.rs @@ -35,7 +35,14 @@ impl Instant { let freq = perf_counter::frequency() as u64; let now = perf_counter::now(); + + // We convert now to `u64` to be able to use `Duration`. let instant_nsec = mul_div_u64(now as u64, NANOS_PER_SEC, freq); + // We can add an arbitrary offset to shift the epoch of this clock. We do that to avoid + // being too close to 0 which would lead to underflow when computing times in the past. Also + // see . + let instant_nsec = instant_nsec + (u64::MAX / 4); + Self { t: Duration::from_nanos(instant_nsec) } } diff --git a/library/std/tests/time.rs b/library/std/tests/time.rs index b73e7bc3962eb..d6736e25ace18 100644 --- a/library/std/tests/time.rs +++ b/library/std/tests/time.rs @@ -1,4 +1,5 @@ #![feature(duration_constants)] +#![feature(duration_constructors)] #![feature(time_systemtime_limits)] #![feature(time_saturating_systemtime)] @@ -104,7 +105,8 @@ fn instant_math_is_associative() { #[test] fn instant_duration_since_saturates() { let a = Instant::now(); - assert_eq!((a - Duration::SECOND).duration_since(a), Duration::ZERO); + // This also checks that computing an instant before program startup works. + assert_eq!((a - Duration::from_days(1)).duration_since(a), Duration::ZERO); } #[test] From 3c83d3adc91b253d1e4c500a94244d7ff1f12579 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Tue, 5 May 2026 19:11:16 +0000 Subject: [PATCH 05/21] llvm: Use correct type for splat mask After llvm/llvm-project#195486 , LLVM has explicit handling for null pointers in simd operations instead of using special handling based on zeroes. This causes LLVM with asserts enabled to detect an improperly typed mask passed to splat (if the output vector does not have i32 elements), and can cause SIGSEGV in more complex cases with asserts disabled. --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index dd9ebf298b229..84c1e8e6f3d47 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2086,7 +2086,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } if name == sym::simd_splat { - let (_out_len, out_ty) = require_simd!(ret_ty, SimdReturn); + let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn); require!( args[0].layout.ty == out_ty, @@ -2105,7 +2105,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( // `shufflevector v0, poison, zeroinitializer` // The masks is all zeros, so this splats lane 0 (which has our element in it). - let splat = bx.shuffle_vector(v0, poison_vec, bx.const_null(llret_ty)); + let mask_ty = bx.type_vector(bx.type_i32(), out_len); + let splat = bx.shuffle_vector(v0, poison_vec, bx.const_null(mask_ty)); return Ok(splat); } From 803c7ba50bc1dfd27bd4241edc3619126c9b7350 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 24 Apr 2026 15:08:32 +1000 Subject: [PATCH 06/21] Some fold/visit tweaks. - Introduce `HAS_REGIONS`/`has_regions`, which is true if any regions are present. - Add `fold_clauses` to `Shifter` and `RegionFolder` for consistency. - Simplify `has_type_flags`. - Remove unnecessary local variables in `HasTypeFlagsVisitor` methods. - Use `|=` operator in one place. - Avoid `is_break` in one place for consistency with nearby code. LLM disclosure: Claude Code suggested these changes when I asked it to review `fold.rs` and `visit.rs`. I verified the correctness of the suggestions and made the changes by hand. --- compiler/rustc_type_ir/src/flags.rs | 7 +++++- compiler/rustc_type_ir/src/fold.rs | 34 ++++++++++------------------- compiler/rustc_type_ir/src/visit.rs | 17 ++++++++------- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 3debef168cffd..19c59df0604c3 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -118,6 +118,11 @@ bitflags::bitflags! { /// Does this have any `ReErased` regions? const HAS_RE_ERASED = 1 << 21; + /// Does this have any regions of any kind? + const HAS_REGIONS = TypeFlags::HAS_FREE_REGIONS.bits() + | TypeFlags::HAS_RE_BOUND.bits() + | TypeFlags::HAS_RE_ERASED.bits(); + /// Does this value have parameters/placeholders/inference variables which could be /// replaced later, in a way that would change the results of `impl` specialization? const STILL_FURTHER_SPECIALIZABLE = TypeFlags::HAS_TY_PARAM.bits() @@ -192,7 +197,7 @@ impl FlagComputation { } fn add_flags(&mut self, flags: TypeFlags) { - self.flags = self.flags | flags; + self.flags |= flags; } /// indicates that `self` refers to something at binding level `binder` diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 94d9845594628..0fe68b5256691 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -55,7 +55,7 @@ use tracing::{debug, instrument}; use crate::inherent::*; use crate::visit::{TypeVisitable, TypeVisitableExt as _}; -use crate::{self as ty, BoundVarIndexKind, Interner, TypeFlags}; +use crate::{self as ty, BoundVarIndexKind, Interner}; /// This trait is implemented for every type that can be folded, /// providing the skeleton of the traversal. @@ -433,6 +433,10 @@ impl TypeFolder for Shifter { fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } + + fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { + if c.has_vars_bound_at_or_above(self.current_index) { c.super_fold_with(self) } else { c } + } } pub fn shift_region(cx: I, region: I::Region, amount: u32) -> I::Region { @@ -535,32 +539,18 @@ where } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { - if t.has_type_flags( - TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_RE_BOUND | TypeFlags::HAS_RE_ERASED, - ) { - t.super_fold_with(self) - } else { - t - } + if t.has_regions() { t.super_fold_with(self) } else { t } } fn fold_const(&mut self, ct: I::Const) -> I::Const { - if ct.has_type_flags( - TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_RE_BOUND | TypeFlags::HAS_RE_ERASED, - ) { - ct.super_fold_with(self) - } else { - ct - } + if ct.has_regions() { ct.super_fold_with(self) } else { ct } } fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { - if p.has_type_flags( - TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_RE_BOUND | TypeFlags::HAS_RE_ERASED, - ) { - p.super_fold_with(self) - } else { - p - } + if p.has_regions() { p.super_fold_with(self) } else { p } + } + + fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { + if c.has_regions() { c.super_fold_with(self) } else { c } } } diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 6d0b307f013eb..492c37481298b 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -285,6 +285,10 @@ pub trait TypeVisitableExt: TypeVisitable { self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM) } + fn has_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_REGIONS) + } + fn has_infer_regions(&self) -> bool { self.has_type_flags(TypeFlags::HAS_RE_INFER) } @@ -363,13 +367,12 @@ pub trait TypeVisitableExt: TypeVisitable { impl> TypeVisitableExt for T { fn has_type_flags(&self, flags: TypeFlags) -> bool { - let res = - self.visit_with(&mut HasTypeFlagsVisitor { flags }) == ControlFlow::Break(FoundFlags); - res + self.visit_with(&mut HasTypeFlagsVisitor { flags }) == ControlFlow::Break(FoundFlags) } fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { - self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break() + self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }) + == ControlFlow::Break(FoundEscapingVars) } fn error_reported(&self) -> Result<(), I::ErrorGuaranteed> { @@ -438,8 +441,7 @@ impl TypeVisitor for HasTypeFlagsVisitor { #[inline] fn visit_ty(&mut self, t: I::Ty) -> Self::Result { // Note: no `super_visit_with` call. - let flags = t.flags(); - if flags.intersects(self.flags) { + if t.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { ControlFlow::Continue(()) @@ -449,8 +451,7 @@ impl TypeVisitor for HasTypeFlagsVisitor { #[inline] fn visit_region(&mut self, r: I::Region) -> Self::Result { // Note: no `super_visit_with` call, as usual for `Region`. - let flags = r.flags(); - if flags.intersects(self.flags) { + if r.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { ControlFlow::Continue(()) From 4fe8268ff9724a7a881712f0fc6f7be0f74dc3c0 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 6 May 2026 05:10:26 +0000 Subject: [PATCH 07/21] Refactor `Type::size` field to `TypeId::size` method for `type_info` --- .../src/const_eval/machine.rs | 21 +++- .../src/const_eval/type_info.rs | 19 +--- .../rustc_hir_analysis/src/check/intrinsic.rs | 24 ++--- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/any.rs | 2 +- library/core/src/intrinsics/mod.rs | 9 ++ library/core/src/mem/type_info.rs | 23 ++++- library/coretests/tests/mem/type_info.rs | 98 +++++++++++-------- .../vtable-try-as-dyn.full-debuginfo.stderr | 2 +- .../vtable-try-as-dyn.no-debuginfo.stderr | 2 +- .../reflection/trait_info_of_too_big.stderr | 4 +- 11 files changed, 120 insertions(+), 85 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 50d58e020601d..c7ee14b4b5dda 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow}; use std::hash::Hash; use std::{fmt, mem}; -use rustc_abi::{Align, FIRST_VARIANT, Size}; +use rustc_abi::{Align, FIRST_VARIANT, FieldIdx, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -11,7 +11,7 @@ use rustc_middle::mir::AssertMessage; use rustc_middle::mir::interpret::ReportedErrorInfo; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement}; -use rustc_middle::ty::{self, FieldInfo, Ty, TyCtxt}; +use rustc_middle::ty::{self, FieldInfo, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_target::callconv::FnAbi; @@ -605,6 +605,23 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.write_type_info(ty, dest)?; } + sym::size_of_type_id => { + let ty = ecx.read_type_id(&args[0])?; + let layout = ecx.layout_of(ty)?; + let variant_index = if layout.is_sized() { + let (variant, variant_place) = ecx.downcast(dest, sym::Some)?; + let size_field_place = ecx.project_field(&variant_place, FieldIdx::ZERO)?; + ecx.write_scalar( + ScalarInt::try_from_target_usize(layout.size.bytes(), ecx.tcx.tcx).unwrap(), + &size_field_place, + )?; + variant + } else { + ecx.downcast(dest, sym::None)?.0 + }; + ecx.write_discriminant(variant_index, dest)?; + } + sym::field_offset => { let frt_ty = instance.args.type_at(0); ensure_monomorphic_enough(ecx.tcx.tcx, frt_ty)?; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 7b63ab5bb02e8..7a90ac8287967 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -18,7 +18,7 @@ use crate::interpret::{ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { /// Equivalent to `project_downcast`, but identifies the variant by name instead of index. - fn downcast<'a>( + pub fn downcast<'a>( &self, place: &(impl Writeable<'tcx, CtfeProvenance> + 'a), name: Symbol, @@ -218,23 +218,6 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { }; self.write_discriminant(variant_index, &field_dest)? } - sym::size => { - let layout = self.layout_of(ty)?; - let variant_index = if layout.is_sized() { - let (variant, variant_place) = self.downcast(&field_dest, sym::Some)?; - let size_field_place = - self.project_field(&variant_place, FieldIdx::ZERO)?; - self.write_scalar( - ScalarInt::try_from_target_usize(layout.size.bytes(), self.tcx.tcx) - .unwrap(), - &size_field_place, - )?; - variant - } else { - self.downcast(&field_dest, sym::None)?.0 - }; - self.write_discriminant(variant_index, &field_dest)?; - } other => span_bug!(self.tcx.span, "unknown `Type` field {other}"), } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 7d606439cedc3..d0bb68c5bc33b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -199,6 +199,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::sinf64 | sym::sinf128 | sym::size_of + | sym::size_of_type_id | sym::sqrtf16 | sym::sqrtf32 | sym::sqrtf64 @@ -281,6 +282,7 @@ pub(crate) fn check_intrinsic_type( let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]).skip_norm_wip(); (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) }; + let type_id_ty = || tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); let n_lts = 0; @@ -294,6 +296,7 @@ pub(crate) fn check_intrinsic_type( sym::size_of_val | sym::align_of_val => { (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } + sym::size_of_type_id => (0, 0, vec![type_id_ty()], Ty::new_option(tcx, tcx.types.usize)), sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize), sym::field_offset => (1, 0, vec![], tcx.types.usize), sym::rustc_peek => (1, 0, vec![param(0)], param(0)), @@ -313,16 +316,8 @@ pub(crate) fn check_intrinsic_type( sym::needs_drop => (1, 0, vec![], tcx.types.bool), sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)), - sym::type_id => ( - 1, - 0, - vec![], - tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(), - ), - sym::type_id_eq => { - let type_id = tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); - (0, 0, vec![type_id, type_id], tcx.types.bool) - } + sym::type_id => (1, 0, vec![], type_id_ty()), + sym::type_id_eq => (0, 0, vec![type_id_ty(), type_id_ty()], tcx.types.bool), sym::type_id_vtable => { let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, span); let dyn_metadata_adt_ref = tcx.adt_def(dyn_metadata); @@ -335,17 +330,12 @@ pub(crate) fn check_intrinsic_type( let option_args = tcx.mk_args(&[dyn_ty.into()]); let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args); - ( - 0, - 0, - vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap(); 2], - ret_ty, - ) + (0, 0, vec![type_id_ty(); 2], ret_ty) } sym::type_of => ( 0, 0, - vec![tcx.type_of(tcx.lang_items().type_id().unwrap()).no_bound_vars().unwrap()], + vec![type_id_ty()], tcx.type_of(tcx.lang_items().type_struct().unwrap()).no_bound_vars().unwrap(), ), sym::offload => ( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 695103a249b49..728482bf57413 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1927,6 +1927,7 @@ symbols! { sinf128, size, size_of, + size_of_type_id, size_of_val, sized, sized_hierarchy, diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 7d820403ccb7d..62300d8b70a96 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -839,7 +839,7 @@ impl TypeId { self, trait_represented_by_type_id: TypeId, ) -> Option> { - if self.info().size.is_none() { + if self.size().is_none() { return None; } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c71085ef9f97d..8eaf91dab8dfb 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2937,6 +2937,15 @@ pub const fn type_id_eq(a: crate::any::TypeId, b: crate::any::TypeId) -> bool { a.data == b.data } +/// Gets the size of the type represented by this `TypeId`. +/// +/// The stabilized version of this intrinsic is [`core::any::TypeId::size`]. +#[rustc_intrinsic] +#[unstable(feature = "core_intrinsics", issue = "none")] +pub const fn size_of_type_id(_id: crate::any::TypeId) -> Option { + panic!("`Type::size` can only be called at compile-time") +} + /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// /// This is used to implement functions like `slice::from_raw_parts_mut` and diff --git a/library/core/src/mem/type_info.rs b/library/core/src/mem/type_info.rs index e4d47dedb8606..17c51ccaad858 100644 --- a/library/core/src/mem/type_info.rs +++ b/library/core/src/mem/type_info.rs @@ -2,7 +2,7 @@ //! runtime or const-eval processable way. use crate::any::TypeId; -use crate::intrinsics::{type_id, type_of}; +use crate::intrinsics::{self, type_id, type_of}; use crate::marker::PointeeSized; use crate::ptr::DynMetadata; @@ -14,8 +14,6 @@ use crate::ptr::DynMetadata; pub struct Type { /// Per-type information pub kind: TypeKind, - /// Size of the type. `None` if it is unsized - pub size: Option, } /// Info of a trait implementation, you can retrieve the vtable with [Self::get_vtable] @@ -360,3 +358,22 @@ pub enum Abi { /// C-calling convention ExternC, } + +impl TypeId { + /// Returns the size of the type represented by this `TypeId`. `None` if it is unsized. + /// + /// # Examples + /// + /// ``` + /// #![feature(type_info)] + /// use std::any::TypeId; + /// + /// assert_eq!(const { TypeId::of::().size() }, Some(4)); + /// assert_eq!(const { TypeId::of::<[u8; 16]>().size() }, Some(16)); + /// ``` + #[unstable(feature = "type_info", issue = "146922")] + #[rustc_const_unstable(feature = "type_info", issue = "146922")] + pub const fn size(self) -> Option { + intrinsics::size_of_type_id(self) + } +} diff --git a/library/coretests/tests/mem/type_info.rs b/library/coretests/tests/mem/type_info.rs index 2483b4c2aacd7..e02077b96d35a 100644 --- a/library/coretests/tests/mem/type_info.rs +++ b/library/coretests/tests/mem/type_info.rs @@ -80,8 +80,7 @@ fn test_structs() { reference: &'static u16, } - let Type { kind: Struct(ty), size, .. } = Type::of::() else { panic!() }; - assert!(size == Some(size_of::())); + let Type { kind: Struct(ty), .. } = Type::of::() else { panic!() }; assert!(!ty.non_exhaustive); assert!(ty.fields.len() == 3); assert!(ty.fields[0].name == "first"); @@ -93,6 +92,9 @@ fn test_structs() { assert!(ty.fields[2].name == "reference"); assert!(ty.fields[2].ty == TypeId::of::<&'static u16>()); assert!(ty.fields[2].offset == offset_of!(TestStruct, reference)); + + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); } const { @@ -145,13 +147,15 @@ fn test_unions() { second: u16, } - let Type { kind: Union(ty), size, .. } = Type::of::() else { panic!() }; - assert!(size == Some(size_of::())); + let Type { kind: Union(ty), .. } = Type::of::() else { panic!() }; assert!(ty.fields.len() == 2); assert!(ty.fields[0].name == "first"); assert!(ty.fields[0].offset == offset_of!(TestUnion, first)); assert!(ty.fields[1].name == "second"); assert!(ty.fields[1].offset == offset_of!(TestUnion, second)); + + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); } const { @@ -191,8 +195,7 @@ fn test_enums() { }, } - let Type { kind: Enum(ty), size, .. } = Type::of::() else { panic!() }; - assert!(size == Some(size_of::())); + let Type { kind: Enum(ty), .. } = Type::of::() else { panic!() }; assert!(ty.variants.len() == 3); assert!(ty.variants[0].name == "Some"); @@ -206,15 +209,20 @@ fn test_enums() { assert!(ty.variants[2].name == "Foomp"); assert!(ty.variants[2].non_exhaustive); assert!(ty.variants[2].fields.len() == 2); + + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); } const { - let Type { kind: Enum(ty), size, .. } = Type::of::>() else { panic!() }; - assert!(size == Some(size_of::>())); + let Type { kind: Enum(ty), .. } = Type::of::>() else { panic!() }; assert!(ty.variants.len() == 2); assert!(ty.generics.len() == 1); let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[0] else { panic!() }; assert!(generic_ty == TypeId::of::()); + + let ty_id = TypeId::of::>(); + assert!(ty_id.size() == Some(size_of::>())); } } @@ -222,38 +230,48 @@ fn test_enums() { fn test_primitives() { use TypeKind::*; - let Type { kind: Bool(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(1)); - - let Type { kind: Char(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(4)); - - let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(4)); - assert_eq!(ty.bits, 32); - assert!(ty.signed); - - let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(size_of::())); - assert_eq!(ty.bits as usize, size_of::() * 8); - assert!(ty.signed); - - let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(4)); - assert_eq!(ty.bits, 32); - assert!(!ty.signed); - - let Type { kind: Int(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(size_of::())); - assert_eq!(ty.bits as usize, size_of::() * 8); - assert!(!ty.signed); - - let Type { kind: Float(ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, Some(4)); - assert_eq!(ty.bits, 32); - - let Type { kind: Str(_ty), size, .. } = (const { Type::of::() }) else { panic!() }; - assert_eq!(size, None); + const { + let Type { kind: Bool(_ty), .. } = (const { Type::of::() }) else { panic!() }; + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Char(_ty), .. } = (const { Type::of::() }) else { panic!() }; + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits == 32); + assert!(ty.signed); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits as usize == size_of::() * 8); + assert!(ty.signed); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits == 32); + assert!(!ty.signed); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Int(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits as usize == size_of::() * 8); + assert!(!ty.signed); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Float(ty), .. } = (const { Type::of::() }) else { panic!() }; + assert!(ty.bits == 32); + let ty_id = TypeId::of::(); + assert!(ty_id.size() == Some(size_of::())); + + let Type { kind: Str(_ty), .. } = (const { Type::of::() }) else { panic!() }; + let ty_id = TypeId::of::(); + assert!(ty_id.size() == None); + } } #[test] diff --git a/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr index 700083069cb05..c9c15e2d62c9f 100644 --- a/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr +++ b/tests/ui/limits/vtable-try-as-dyn.full-debuginfo.stderr @@ -6,7 +6,7 @@ note: inside `TypeId::trait_info_of::` --> $SRC_DIR/core/src/any.rs:LL:COL note: inside `TypeId::trait_info_of_trait_type_id` --> $SRC_DIR/core/src/any.rs:LL:COL -note: inside `type_info::::info` +note: inside `type_info::::size` --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL note: the above error was encountered while instantiating `fn try_as_dyn::<[u8; usize::MAX], dyn Trait>` diff --git a/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr index 700083069cb05..c9c15e2d62c9f 100644 --- a/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr +++ b/tests/ui/limits/vtable-try-as-dyn.no-debuginfo.stderr @@ -6,7 +6,7 @@ note: inside `TypeId::trait_info_of::` --> $SRC_DIR/core/src/any.rs:LL:COL note: inside `TypeId::trait_info_of_trait_type_id` --> $SRC_DIR/core/src/any.rs:LL:COL -note: inside `type_info::::info` +note: inside `type_info::::size` --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL note: the above error was encountered while instantiating `fn try_as_dyn::<[u8; usize::MAX], dyn Trait>` diff --git a/tests/ui/reflection/trait_info_of_too_big.stderr b/tests/ui/reflection/trait_info_of_too_big.stderr index fa41d3c9ec90e..b5dc1d3cdb44a 100644 --- a/tests/ui/reflection/trait_info_of_too_big.stderr +++ b/tests/ui/reflection/trait_info_of_too_big.stderr @@ -6,7 +6,7 @@ LL | TypeId::of::<[u8; usize::MAX]>().trait_info_of_trait_type_id(TypeId::of | note: inside `TypeId::trait_info_of_trait_type_id` --> $SRC_DIR/core/src/any.rs:LL:COL -note: inside `type_info::::info` +note: inside `type_info::::size` --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL error[E0080]: values of the type `[u8; usize::MAX]` are too big for the target architecture @@ -19,7 +19,7 @@ note: inside `TypeId::trait_info_of::` --> $SRC_DIR/core/src/any.rs:LL:COL note: inside `TypeId::trait_info_of_trait_type_id` --> $SRC_DIR/core/src/any.rs:LL:COL -note: inside `type_info::::info` +note: inside `type_info::::size` --> $SRC_DIR/core/src/mem/type_info.rs:LL:COL error: aborting due to 2 previous errors From 814fc17cb6c5860b04fde34abc12fa92151d9505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 29 Apr 2026 10:53:45 +0200 Subject: [PATCH 08/21] Deny warnings in rustc crates on stable --- tests/run-make-cargo/rustc-crates-on-stable/rmake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-make-cargo/rustc-crates-on-stable/rmake.rs b/tests/run-make-cargo/rustc-crates-on-stable/rmake.rs index cbc1f24b8c16e..de29abfd7c3a2 100644 --- a/tests/run-make-cargo/rustc-crates-on-stable/rmake.rs +++ b/tests/run-make-cargo/rustc-crates-on-stable/rmake.rs @@ -10,7 +10,7 @@ fn main() { .env("RUSTC_STAGE", "0") .env("RUSTC", rustc_path()) // We want to disallow all nightly features to simulate a stable build - .env("RUSTFLAGS", "-Zallow-features=") + .env("RUSTFLAGS", "-D warnings -Zallow-features=") .arg("build") .arg("--manifest-path") .arg(source_root().join("Cargo.toml")) From 0afe083fd1f0e9fa2c627b8c3155f221675f3d68 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 May 2026 06:31:19 +0200 Subject: [PATCH 09/21] Avoid some global `node_id_to_def_id` lookups in import resolution --- .../rustc_resolve/src/build_reduced_graph.rs | 11 +++++- compiler/rustc_resolve/src/imports.rs | 39 +++++++++++-------- compiler/rustc_resolve/src/lib.rs | 4 +- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 524c9ce8ad5d7..642a618e18676 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -720,13 +720,15 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { decls: Default::default(), nested, id, + def_id: feed.def_id(), }; self.add_import(module_path, kind, use_tree.span(), item, root_span, item.id, vis); } ast::UseTreeKind::Glob(_) => { if !ast::attr::contains_name(&item.attrs, sym::prelude_import) { - let kind = ImportKind::Glob { max_vis: CmCell::new(None), id }; + let kind = + ImportKind::Glob { max_vis: CmCell::new(None), id, def_id: feed.def_id() }; self.add_import(prefix, kind, use_tree.span(), item, root_span, item.id, vis); } else { // Resolve the prelude import early. @@ -1018,7 +1020,12 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { }) .unwrap_or((true, None, self.r.dummy_decl)); let import = self.r.arenas.alloc_import(ImportData { - kind: ImportKind::ExternCrate { source: orig_name, target: orig_ident, id: item.id }, + kind: ImportKind::ExternCrate { + source: orig_name, + target: orig_ident, + id: item.id, + def_id: local_def_id, + }, root_id: item.id, parent_scope, imported_module: CmCell::new(module), diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index e63ab9f21a6ad..4de7a89ba2907 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -16,7 +16,7 @@ use rustc_hir::Attribute; use rustc_hir::attrs::AttributeKind; use rustc_hir::attrs::diagnostic::{CustomDiagnostic, Directive, FormatArgs}; use rustc_hir::def::{self, DefKind, PartialRes}; -use rustc_hir::def_id::{DefId, LocalDefIdMap}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::span_bug; use rustc_middle::ty::{TyCtxt, Visibility}; @@ -90,17 +90,20 @@ pub(crate) enum ImportKind<'ra> { /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree` /// for `a` in this field. id: NodeId, + def_id: LocalDefId, }, Glob { // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. max_vis: CmCell>, id: NodeId, + def_id: LocalDefId, }, ExternCrate { source: Option, target: Ident, id: NodeId, + def_id: LocalDefId, }, MacroUse { /// A field has been added indicating whether it should be reported as a lint, @@ -116,7 +119,7 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use ImportKind::*; match self { - Single { source, target, decls, nested, id, .. } => f + Single { source, target, decls, nested, id, def_id } => f .debug_struct("Single") .field("source", source) .field("target", target) @@ -127,15 +130,20 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { ) .field("nested", nested) .field("id", id) + .field("def_id", def_id) .finish(), - Glob { max_vis, id } => { - f.debug_struct("Glob").field("max_vis", max_vis).field("id", id).finish() - } - ExternCrate { source, target, id } => f + Glob { max_vis, id, def_id } => f + .debug_struct("Glob") + .field("max_vis", max_vis) + .field("id", id) + .field("def_id", def_id) + .finish(), + ExternCrate { source, target, id, def_id } => f .debug_struct("ExternCrate") .field("source", source) .field("target", target) .field("id", id) + .field("def_id", def_id) .finish(), MacroUse { warn_private } => { f.debug_struct("MacroUse").field("warn_private", warn_private).finish() @@ -260,12 +268,11 @@ impl<'ra> ImportData<'ra> { } } - pub(crate) fn simplify(&self, r: &Resolver<'_, '_>) -> Reexport { - let to_def_id = |id| r.local_def_id(id).to_def_id(); + pub(crate) fn simplify(&self) -> Reexport { match self.kind { - ImportKind::Single { id, .. } => Reexport::Single(to_def_id(id)), - ImportKind::Glob { id, .. } => Reexport::Glob(to_def_id(id)), - ImportKind::ExternCrate { id, .. } => Reexport::ExternCrate(to_def_id(id)), + ImportKind::Single { def_id, .. } => Reexport::Single(def_id.to_def_id()), + ImportKind::Glob { def_id, .. } => Reexport::Glob(def_id.to_def_id()), + ImportKind::ExternCrate { def_id, .. } => Reexport::ExternCrate(def_id.to_def_id()), ImportKind::MacroUse { .. } => Reexport::MacroUse, ImportKind::MacroExport => Reexport::MacroExport, } @@ -1267,7 +1274,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (ident, target, bindings, import_id) = match import.kind { ImportKind::Single { source, target, ref decls, id, .. } => (source, target, decls, id), - ImportKind::Glob { ref max_vis, id } => { + ImportKind::Glob { ref max_vis, id, def_id: _ } => { if import.module_path.len() <= 1 { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. @@ -1829,23 +1836,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut children = Vec::new(); let mut ambig_children = Vec::new(); - module.to_module().for_each_child(self, |this, ident, orig_ident_span, _, binding| { + module.to_module().for_each_child(self, |_this, ident, orig_ident_span, _, binding| { let res = binding.res().expect_non_local(); if res != def::Res::Err { let ident = ident.orig(orig_ident_span); let child = |reexport_chain| ModChild { ident, res, vis: binding.vis(), reexport_chain }; if let Some((ambig_binding1, ambig_binding2)) = binding.descent_to_ambiguity() { - let main = child(ambig_binding1.reexport_chain(this)); + let main = child(ambig_binding1.reexport_chain()); let second = ModChild { ident, res: ambig_binding2.res().expect_non_local(), vis: ambig_binding2.vis(), - reexport_chain: ambig_binding2.reexport_chain(this), + reexport_chain: ambig_binding2.reexport_chain(), }; ambig_children.push(AmbigModChild { main, second }) } else { - children.push(child(binding.reexport_chain(this))); + children.push(child(binding.reexport_chain())); } } }); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 1141ac75ce4c0..7f8ff91d3ad68 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1171,11 +1171,11 @@ impl<'ra> DeclData<'ra> { self.res().macro_kinds() } - fn reexport_chain(self: Decl<'ra>, r: &Resolver<'_, '_>) -> SmallVec<[Reexport; 2]> { + fn reexport_chain(self: Decl<'ra>) -> SmallVec<[Reexport; 2]> { let mut reexport_chain = SmallVec::new(); let mut next_binding = self; while let DeclKind::Import { source_decl, import, .. } = next_binding.kind { - reexport_chain.push(import.simplify(r)); + reexport_chain.push(import.simplify()); next_binding = source_decl; } reexport_chain From 191cda55e4e2612e47d1ce06980cb371aa96e776 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 May 2026 06:36:36 +0200 Subject: [PATCH 10/21] Avoid using `id` followed by `local_def_id` if we can just call `def_id` instead --- .../rustc_resolve/src/effective_visibilities.rs | 9 +++------ compiler/rustc_resolve/src/imports.rs | 14 +++++++++++--- compiler/rustc_resolve/src/lib.rs | 3 +-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index b5614106fe997..693e49995c1cc 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -45,10 +45,7 @@ impl Resolver<'_, '_> { fn private_vis_import(&self, decl: Decl<'_>) -> Visibility { let DeclKind::Import { import, .. } = decl.kind else { unreachable!() }; Visibility::Restricted( - import - .id() - .map(|id| self.nearest_normal_mod(self.local_def_id(id))) - .unwrap_or(CRATE_DEF_ID), + import.def_id().map(|id| self.nearest_normal_mod(id)).unwrap_or(CRATE_DEF_ID), ) } @@ -96,8 +93,8 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { // is the maximum value among visibilities of declarations corresponding to that def id. for (decl, eff_vis) in visitor.import_effective_visibilities.iter() { let DeclKind::Import { import, .. } = decl.kind else { unreachable!() }; - if let Some(node_id) = import.id() { - r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) + if let Some(def_id) = import.def_id() { + r.effective_visibilities.update_eff_vis(def_id, eff_vis, r.tcx) } if decl.ambiguity.get().is_some() && eff_vis.is_public_at_level(Level::Reexported) { exported_ambiguities.insert(*decl); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4de7a89ba2907..c778df19818fc 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -268,6 +268,15 @@ impl<'ra> ImportData<'ra> { } } + pub(crate) fn def_id(&self) -> Option { + match self.kind { + ImportKind::Single { def_id, .. } + | ImportKind::Glob { def_id, .. } + | ImportKind::ExternCrate { def_id, .. } => Some(def_id), + ImportKind::MacroUse { .. } | ImportKind::MacroExport => None, + } + } + pub(crate) fn simplify(&self) -> Reexport { match self.kind { ImportKind::Single { def_id, .. } => Reexport::Single(def_id.to_def_id()), @@ -852,8 +861,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if binding.res() != Res::Err && glob_decl.res() != Res::Err && let DeclKind::Import { import: glob_import, .. } = glob_decl.kind - && let Some(glob_import_id) = glob_import.id() - && let glob_import_def_id = self.local_def_id(glob_import_id) + && let Some(glob_import_def_id) = glob_import.def_id() && self.effective_visibilities.is_exported(glob_import_def_id) && glob_decl.vis().is_public() && !binding.vis().is_public() @@ -882,7 +890,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let DeclKind::Import { import, .. } = binding.kind && let Some(binding_id) = import.id() - && let import_def_id = self.local_def_id(binding_id) + && let import_def_id = import.def_id().unwrap() && self.effective_visibilities.is_exported(import_def_id) && let Res::Def(reexported_kind, reexported_def_id) = binding.res() && !matches!(reexported_kind, DefKind::Ctor(..)) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7f8ff91d3ad68..25cb4659758d0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2155,8 +2155,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> &'tcx [LocalDefId] { let mut import_ids: SmallVec<[LocalDefId; 1]> = smallvec![]; while let DeclKind::Import { import, source_decl, .. } = kind { - if let Some(node_id) = import.id() { - let def_id = self.local_def_id(node_id); + if let Some(def_id) = import.def_id() { self.maybe_unused_trait_imports.insert(def_id); import_ids.push(def_id); } From 400240adb4dc4f5fe0bad053d42215583a76e155 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 May 2026 06:15:58 +0200 Subject: [PATCH 11/21] Avoid hitting the global node_id_to_def_id table for unused macros --- compiler/rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 4 ++-- compiler/rustc_resolve/src/macros.rs | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 642a618e18676..da75238bacd56 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1277,7 +1277,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { if !ident.as_str().starts_with('_') { self.r.unused_macros.insert(def_id, (node_id, ident)); let nrules = self.r.local_macro_map[&def_id].nrules; - self.r.unused_macro_rules.insert(node_id, DenseBitSet::new_filled(nrules)); + self.r.unused_macro_rules.insert(node_id, (def_id, DenseBitSet::new_filled(nrules))); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 25cb4659758d0..6f777984e6c03 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1405,8 +1405,8 @@ pub struct Resolver<'ra, 'tcx> { local_macro_def_scopes: FxHashMap> = default::fx_hash_map(), ast_transform_scopes: FxHashMap> = default::fx_hash_map(), unused_macros: FxIndexMap, - /// A map from the macro to all its potentially unused arms. - unused_macro_rules: FxIndexMap>, + /// A map from the macro to all its potentially unused arms and the `LocalDefId` of the macro itself. + unused_macro_rules: FxIndexMap)>, proc_macro_stubs: FxHashSet = default::fx_hash_set(), /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index d4349b9d73a77..27390c0394d22 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -339,7 +339,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn record_macro_rule_usage(&mut self, id: NodeId, rule_i: usize) { - if let Some(rules) = self.unused_macro_rules.get_mut(&id) { + if let Some((_, rules)) = self.unused_macro_rules.get_mut(&id) { rules.remove(rule_i); } } @@ -356,11 +356,10 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { self.unused_macro_rules.swap_remove(&node_id); } - for (&node_id, unused_arms) in self.unused_macro_rules.iter() { + for (&node_id, (def_id, unused_arms)) in self.unused_macro_rules.iter() { if unused_arms.is_empty() { continue; } - let def_id = self.local_def_id(node_id); let m = &self.local_macro_map[&def_id]; let SyntaxExtensionKind::MacroRules(ref m) = m.ext.kind else { continue; From a082567e7b77a4ce6416a4445c9a1e915319c4e9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 May 2026 07:23:24 +0200 Subject: [PATCH 12/21] Follow-up cleanups reusing the now-available `LocalDefId`s --- compiler/rustc_resolve/src/check_unused.rs | 3 +-- compiler/rustc_resolve/src/imports.rs | 18 ++++++++++-------- compiler/rustc_resolve/src/lib.rs | 3 +-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 7e1b1bce3ff74..8ab0087ae6158 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -431,8 +431,7 @@ impl Resolver<'_, '_> { } } } - ImportKind::ExternCrate { id, .. } => { - let def_id = self.local_def_id(id); + ImportKind::ExternCrate { id, def_id, .. } => { if self.extern_crate_map.get(&def_id).is_none_or(|&cnum| { !tcx.is_compiler_builtins(cnum) && !tcx.is_panic_runtime(cnum) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index c778df19818fc..1b9e5d2a2daa6 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -356,13 +356,16 @@ struct UnresolvedImportError { // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;` // are permitted for backward-compatibility under a deprecation lint. -fn pub_use_of_private_extern_crate_hack(import: ImportSummary, decl: Decl<'_>) -> Option { +fn pub_use_of_private_extern_crate_hack( + import: ImportSummary, + decl: Decl<'_>, +) -> Option { match (import.is_single, decl.kind) { (true, DeclKind::Import { import: decl_import, .. }) - if let ImportKind::ExternCrate { id, .. } = decl_import.kind + if let ImportKind::ExternCrate { def_id, .. } = decl_import.kind && import.vis.is_public() => { - Some(id) + Some(def_id) } _ => None, } @@ -1282,7 +1285,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (ident, target, bindings, import_id) = match import.kind { ImportKind::Single { source, target, ref decls, id, .. } => (source, target, decls, id), - ImportKind::Glob { ref max_vis, id, def_id: _ } => { + ImportKind::Glob { ref max_vis, id, def_id } => { if import.module_path.len() <= 1 { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. @@ -1309,7 +1312,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(max_vis) = max_vis.get() && import.vis.greater_than(max_vis, self.tcx) { - let def_id = self.local_def_id(id); self.lint_buffer.buffer_lint( UNUSED_IMPORTS, id, @@ -1629,7 +1631,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(extern_crate_id) = pub_use_of_private_extern_crate_hack(import.summary(), decl) { let ImportKind::Single { id, .. } = import.kind else { unreachable!() }; - let sugg = self.tcx.source_span(self.local_def_id(extern_crate_id)).shrink_to_lo(); + let sugg = self.tcx.source_span(extern_crate_id).shrink_to_lo(); let diagnostic = crate::errors::PrivateExternCrateReexport { ident, sugg }; return Some(BufferedEarlyLint { lint_id: LintId::of(PUB_USE_OF_PRIVATE_EXTERN_CRATE), @@ -1671,7 +1673,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'ra>) -> bool { // This function is only called for single imports. - let ImportKind::Single { source, target, ref decls, id, .. } = import.kind else { + let ImportKind::Single { source, target, ref decls, id, def_id, .. } = import.kind else { unreachable!() }; @@ -1690,7 +1692,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Skip if the import is public or was used through non scope-based resolution, // e.g. through a module-relative path. if self.import_use_map.get(&import) == Some(&Used::Other) - || self.effective_visibilities.is_exported(self.local_def_id(id)) + || self.effective_visibilities.is_exported(def_id) { return false; } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6f777984e6c03..68e1dd9291dfe 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2291,8 +2291,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { #[inline] fn add_to_glob_map(&mut self, import: Import<'_>, name: Symbol) { - if let ImportKind::Glob { id, .. } = import.kind { - let def_id = self.local_def_id(id); + if let ImportKind::Glob { def_id, .. } = import.kind { self.glob_map.entry(def_id).or_default().insert(name); } } From b8e547a8dc5caeee4d3ab8751a2ecb84ff7f244c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 29 Apr 2026 10:53:45 +0200 Subject: [PATCH 13/21] fix warnings in rustc_type_ir --- compiler/rustc_type_ir/src/binder.rs | 12 ++++++++---- compiler/rustc_type_ir/src/ir_print.rs | 9 +++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index b55cbc3164d96..de3e04626f823 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -375,13 +375,17 @@ pub struct EarlyBinder { impl Eq for EarlyBinder {} -/// For early binders, you should first call `instantiate` before using any visitors. +// FIXME(154045): Recommended as per https://github.com/rust-lang/rust/issues/154045, this is so sad :(( #[cfg(feature = "nightly")] -impl !TypeFoldable for ty::EarlyBinder {} +macro_rules! generate { ($( $tt:tt )*) => { $( $tt )* } } -/// For early binders, you should first call `instantiate` before using any visitors. #[cfg(feature = "nightly")] -impl !TypeVisitable for ty::EarlyBinder {} +generate!( + /// For early binders, you should first call `instantiate` before using any visitors. + impl !TypeFoldable for ty::EarlyBinder {} + /// For early binders, you should first call `instantiate` before using any visitors. + impl !TypeVisitable for ty::EarlyBinder {} +); impl EarlyBinder { pub fn bind(value: T) -> EarlyBinder { diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs index 5af2bd811bab4..c6ab804d81c9f 100644 --- a/compiler/rustc_type_ir/src/ir_print.rs +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -1,11 +1,12 @@ use std::fmt; use crate::{ - AliasTerm, AliasTy, Binder, ClosureKind, CoercePredicate, ExistentialProjection, - ExistentialTraitRef, FnSig, HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, - PatternKind, Placeholder, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, - UnevaluatedConst, + AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig, + HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, PatternKind, Placeholder, + ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; +#[cfg(feature = "nightly")] +use crate::{ClosureKind, UnevaluatedConst}; pub trait IrPrint { fn print(t: &T, fmt: &mut fmt::Formatter<'_>) -> fmt::Result; From 3f7bf606f0864fb817abe2c4450696fcbedb060e Mon Sep 17 00:00:00 2001 From: Donnie Pollitz Date: Wed, 6 May 2026 10:57:12 +0200 Subject: [PATCH 14/21] Add Trusty OS to the generic error implementation. Background: * During this refactor, the Trusty OS was not targeted in the cfg_select https://github.com/rust-lang/rust/commit/e259373ce9eca5a10201d74a016a4a2e7ab42ed7 --- library/std/src/sys/io/error/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/io/error/mod.rs b/library/std/src/sys/io/error/mod.rs index 4fca658a7dcaa..cc8cda9aec045 100644 --- a/library/std/src/sys/io/error/mod.rs +++ b/library/std/src/sys/io/error/mod.rs @@ -43,6 +43,7 @@ cfg_select! { target_os = "vexos", target_family = "wasm", target_os = "zkvm", + target_os = "trusty", ) => { mod generic; pub use generic::*; From 7ccd895c0cb52ea8c85cb21990f3cfa87e1c945b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 6 May 2026 13:27:51 +0200 Subject: [PATCH 15/21] add passing test that should fail --- src/tools/compiletest/src/directives/tests.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 56d52982a8211..ad369f9f1b60c 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -632,6 +632,16 @@ fn test_miropt_mode_forbidden_revisions() { parse_early_props(&config, "//@ revisions: CHECK"); } +#[test] +fn test_multiple_revisions_in_directive() { + let directive = "//@ [foo,bar] compile-flags: -Z hello"; + + // The problem: this is seen as a single revision. + let line_directive = line_directive(Utf8Path::new("foo.txt"), LineNumber::ZERO, directive); + assert!(line_directive.is_some()); + assert_eq!(Some("foo,bar"), line_directive.unwrap().revision); +} + #[test] fn test_forbidden_revisions_allowed_in_non_filecheck_dir() { let revisions = ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"]; From 325b0135b8b9bccaa3241c8c5a488bedc96feecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 6 May 2026 13:34:07 +0200 Subject: [PATCH 16/21] prevent directives from having multiple revisions also update the test to make sure there's an error --- src/tools/compiletest/src/directives/line.rs | 14 ++++++++++++++ src/tools/compiletest/src/directives/tests.rs | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/src/tools/compiletest/src/directives/line.rs b/src/tools/compiletest/src/directives/line.rs index 9cc24c98a859d..87e803921a853 100644 --- a/src/tools/compiletest/src/directives/line.rs +++ b/src/tools/compiletest/src/directives/line.rs @@ -30,6 +30,20 @@ pub(crate) fn line_directive<'a>( revision = Some(line_revision); raw_directive = after_close_bracket.trim_start(); + + if line_revision.contains(",") { + let suggestion: Vec<_> = line_revision + .split(",") + .map(|revision| { + format!("{COMPILETEST_DIRECTIVE_PREFIX} [{revision}]: {raw_directive}") + }) + .collect(); + panic!( + "malformed condition directive: multiple revisions aren't supported yet in `{}`, split them like\n{}", + original_line, + suggestion.join("\n"), + ); + } } else { revision = None; raw_directive = after_comment; diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index ad369f9f1b60c..c2d73f95c5446 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -633,6 +633,7 @@ fn test_miropt_mode_forbidden_revisions() { } #[test] +#[should_panic(expected = "malformed condition directive: multiple revisions aren't supported yet")] fn test_multiple_revisions_in_directive() { let directive = "//@ [foo,bar] compile-flags: -Z hello"; @@ -640,6 +641,10 @@ fn test_multiple_revisions_in_directive() { let line_directive = line_directive(Utf8Path::new("foo.txt"), LineNumber::ZERO, directive); assert!(line_directive.is_some()); assert_eq!(Some("foo,bar"), line_directive.unwrap().revision); + + // The solution for now: forbid directives from having multiple revisions. + let config: Config = cfg().build(); + parse_early_props(&config, directive); } #[test] From ccd70c194e5045f841eb669c41bc8eb6623f0c07 Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Wed, 6 May 2026 13:41:52 +0100 Subject: [PATCH 17/21] move coercion tests out of ui/issues into its folder --- .../coerce-bare-fn-returning-zst-to-closure.rs} | 0 .../coerce-mut-ref-to-raw-ptr-borrow-expires.rs} | 0 .../coerce-trait-object-removes-send-bound.rs} | 0 .../variance-coerce-unsized-cycle.rs} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-18539.rs => coercion/coerce-bare-fn-returning-zst-to-closure.rs} (100%) rename tests/ui/{issues/issue-47722.rs => coercion/coerce-mut-ref-to-raw-ptr-borrow-expires.rs} (100%) rename tests/ui/{issues/issue-33387.rs => coercion/coerce-trait-object-removes-send-bound.rs} (100%) rename tests/ui/{issues/issue-41936-variance-coerce-unsized-cycle.rs => coercion/variance-coerce-unsized-cycle.rs} (100%) diff --git a/tests/ui/issues/issue-18539.rs b/tests/ui/coercion/coerce-bare-fn-returning-zst-to-closure.rs similarity index 100% rename from tests/ui/issues/issue-18539.rs rename to tests/ui/coercion/coerce-bare-fn-returning-zst-to-closure.rs diff --git a/tests/ui/issues/issue-47722.rs b/tests/ui/coercion/coerce-mut-ref-to-raw-ptr-borrow-expires.rs similarity index 100% rename from tests/ui/issues/issue-47722.rs rename to tests/ui/coercion/coerce-mut-ref-to-raw-ptr-borrow-expires.rs diff --git a/tests/ui/issues/issue-33387.rs b/tests/ui/coercion/coerce-trait-object-removes-send-bound.rs similarity index 100% rename from tests/ui/issues/issue-33387.rs rename to tests/ui/coercion/coerce-trait-object-removes-send-bound.rs diff --git a/tests/ui/issues/issue-41936-variance-coerce-unsized-cycle.rs b/tests/ui/coercion/variance-coerce-unsized-cycle.rs similarity index 100% rename from tests/ui/issues/issue-41936-variance-coerce-unsized-cycle.rs rename to tests/ui/coercion/variance-coerce-unsized-cycle.rs From c5cf60839d8274a638556e9973d1e26260e924ce Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Wed, 6 May 2026 14:22:01 +0100 Subject: [PATCH 18/21] add issue links and bless --- tests/ui/coercion/coerce-bare-fn-returning-zst-to-closure.rs | 2 ++ tests/ui/coercion/coerce-mut-ref-to-raw-ptr-borrow-expires.rs | 2 ++ tests/ui/coercion/coerce-trait-object-removes-send-bound.rs | 2 ++ tests/ui/coercion/variance-coerce-unsized-cycle.rs | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/ui/coercion/coerce-bare-fn-returning-zst-to-closure.rs b/tests/ui/coercion/coerce-bare-fn-returning-zst-to-closure.rs index 66f0dabb73a25..39d4fa8457147 100644 --- a/tests/ui/coercion/coerce-bare-fn-returning-zst-to-closure.rs +++ b/tests/ui/coercion/coerce-bare-fn-returning-zst-to-closure.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/18539 + //@ run-pass // Test that coercing bare fn's that return a zero sized type to // a closure doesn't cause an LLVM ERROR diff --git a/tests/ui/coercion/coerce-mut-ref-to-raw-ptr-borrow-expires.rs b/tests/ui/coercion/coerce-mut-ref-to-raw-ptr-borrow-expires.rs index da08b8addda90..c9089b970c834 100644 --- a/tests/ui/coercion/coerce-mut-ref-to-raw-ptr-borrow-expires.rs +++ b/tests/ui/coercion/coerce-mut-ref-to-raw-ptr-borrow-expires.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/47722 + //@ check-pass // Tests that automatic coercions from &mut T to *mut T diff --git a/tests/ui/coercion/coerce-trait-object-removes-send-bound.rs b/tests/ui/coercion/coerce-trait-object-removes-send-bound.rs index 5d323612e411c..e7186d045a156 100644 --- a/tests/ui/coercion/coerce-trait-object-removes-send-bound.rs +++ b/tests/ui/coercion/coerce-trait-object-removes-send-bound.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/33387 + //@ run-pass #![feature(rustc_attrs)] diff --git a/tests/ui/coercion/variance-coerce-unsized-cycle.rs b/tests/ui/coercion/variance-coerce-unsized-cycle.rs index 2a2b88410959c..91e16edd645b6 100644 --- a/tests/ui/coercion/variance-coerce-unsized-cycle.rs +++ b/tests/ui/coercion/variance-coerce-unsized-cycle.rs @@ -1,6 +1,6 @@ //@ check-pass #![allow(dead_code)] -// Regression test for #41936. The coerce-unsized trait check in +// Regression test for https://github.com/rust-lang/rust/issues/41936. The coerce-unsized trait check in // coherence was using subtyping, which triggered variance // computation, which failed because it required type info for fields // that had not (yet) been computed. From ff25d8acf3978326f5662c072880b5566477fefc Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 9 Apr 2026 06:26:24 +0300 Subject: [PATCH 19/21] Use special DefIds for aliases Like we do for other things for better experience in rust-analyzer. It's possible now that the `AliasTyKind` and `AliasTermKind` contains the DefId. It does require a few `try_into().unwrap()`s since in the solver's `consider_X_candidate()` only get an untyped `DefId`. It's possible to reduce that considerably if we'd pass them the typed def id as a parameter, but I don't know what will be the impact on perf. --- .../src/ty/context/impl_interner.rs | 37 ++- .../rustc_next_trait_solver/src/delegate.rs | 4 +- .../src/solve/assembly/structural_traits.rs | 20 +- .../src/solve/eval_ctxt/mod.rs | 6 +- .../rustc_next_trait_solver/src/solve/mod.rs | 4 +- .../src/solve/normalizes_to/anon_const.rs | 1 + .../src/solve/normalizes_to/free_alias.rs | 10 +- .../src/solve/normalizes_to/inherent.rs | 19 +- .../src/solve/normalizes_to/mod.rs | 234 +++++++++--------- .../src/solve/normalizes_to/opaque_types.rs | 10 +- .../src/solve/trait_goals.rs | 2 +- compiler/rustc_type_ir/src/generic_visit.rs | 1 + compiler/rustc_type_ir/src/inherent.rs | 25 +- compiler/rustc_type_ir/src/interner.rs | 67 ++++- compiler/rustc_type_ir/src/lang_items.rs | 5 +- compiler/rustc_type_ir/src/opaque_ty.rs | 2 +- compiler/rustc_type_ir/src/predicate.rs | 120 ++++----- compiler/rustc_type_ir/src/relate.rs | 5 +- compiler/rustc_type_ir/src/solve/mod.rs | 2 +- compiler/rustc_type_ir/src/ty_kind.rs | 26 +- 20 files changed, 357 insertions(+), 243 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index bacddb6808290..1ab8aa7027528 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -8,7 +8,7 @@ use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_span::{DUMMY_SP, Span, Symbol}; -use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; +use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::{CollectAndApply, Interner, TypeFoldable, Unnormalized, search_graph}; use crate::dep_graph::{DepKind, DepNodeIndex}; @@ -39,6 +39,20 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type AdtId = DefId; type ImplId = DefId; type UnevaluatedConstId = DefId; + type TraitAssocTyId = DefId; + type TraitAssocConstId = DefId; + type TraitAssocTermId = DefId; + type OpaqueTyId = DefId; + type LocalOpaqueTyId = LocalDefId; + type FreeTyAliasId = DefId; + type FreeConstAliasId = DefId; + type FreeTermAliasId = DefId; + type ImplOrTraitAssocTyId = DefId; + type ImplOrTraitAssocConstId = DefId; + type ImplOrTraitAssocTermId = DefId; + type InherentAssocTyId = DefId; + type InherentAssocConstId = DefId; + type InherentAssocTermId = DefId; type Span = Span; type GenericArgs = ty::GenericArgsRef<'tcx>; @@ -288,7 +302,15 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_type_list_from_iter(args) } - fn parent(self, def_id: DefId) -> DefId { + fn projection_parent(self, def_id: Self::TraitAssocTermId) -> Self::TraitId { + self.parent(def_id) + } + + fn impl_or_trait_assoc_term_parent(self, def_id: Self::ImplOrTraitAssocTyId) -> DefId { + self.parent(def_id) + } + + fn inherent_alias_term_parent(self, def_id: Self::InherentAssocTermId) -> Self::ImplId { self.parent(def_id) } @@ -446,7 +468,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { !self.codegen_fn_attrs(def_id).target_features.is_empty() } - fn require_lang_item(self, lang_item: SolverLangItem) -> DefId { + fn require_projection_lang_item(self, lang_item: SolverProjectionLangItem) -> DefId { self.require_lang_item(solver_lang_item_to_lang_item(lang_item), DUMMY_SP) } @@ -458,7 +480,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.require_lang_item(solver_adt_lang_item_to_lang_item(lang_item), DUMMY_SP) } - fn is_lang_item(self, def_id: DefId, lang_item: SolverLangItem) -> bool { + fn is_projection_lang_item(self, def_id: DefId, lang_item: SolverProjectionLangItem) -> bool { self.is_lang_item(def_id, solver_lang_item_to_lang_item(lang_item)) } @@ -478,7 +500,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.is_sizedness_trait(def_id) } - fn as_lang_item(self, def_id: DefId) -> Option { + fn as_projection_lang_item(self, def_id: DefId) -> Option { lang_item_to_solver_lang_item(self.lang_items().from_def_id(def_id)?) } @@ -757,7 +779,7 @@ macro_rules! bidirectional_lang_item_map { } bidirectional_lang_item_map! { - SolverLangItem, fn lang_item_to_solver_lang_item, fn solver_lang_item_to_lang_item; + SolverProjectionLangItem, fn lang_item_to_solver_lang_item, fn solver_lang_item_to_lang_item; // tidy-alphabetical-start AsyncFnKindUpvars, @@ -766,7 +788,6 @@ bidirectional_lang_item_map! { CallRefFuture, CoroutineReturn, CoroutineYield, - DynMetadata, FieldBase, FieldType, FutureOutput, @@ -778,6 +799,7 @@ bidirectional_lang_item_map! { SolverAdtLangItem, fn lang_item_to_solver_adt_lang_item, fn solver_adt_lang_item_to_lang_item; // tidy-alphabetical-start + DynMetadata, Option, Poll, // tidy-alphabetical-end @@ -791,7 +813,6 @@ bidirectional_lang_item_map! { AsyncFnKindHelper, AsyncFnMut, AsyncFnOnce, - AsyncFnOnceOutput, AsyncIterator, BikeshedGuaranteedNoDrop, Clone, diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 429206a93dfee..8fd7d6d0471c7 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -69,7 +69,7 @@ pub trait SolverDelegate: Deref + Sized { fn add_item_bounds_for_hidden_type( &self, - def_id: ::DefId, + def_id: ::OpaqueTyId, args: ::GenericArgs, param_env: ::ParamEnv, hidden_ty: ::Ty, @@ -79,7 +79,7 @@ pub trait SolverDelegate: Deref + Sized { fn fetch_eligible_assoc_item( &self, goal_trait_ref: ty::TraitRef, - trait_assoc_def_id: ::DefId, + trait_assoc_def_id: ::TraitAssocTermId, impl_def_id: ::ImplId, ) -> FetchEligibleAssocItemResponse; diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 0bbc6f483104f..0053e25e6365a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -4,7 +4,7 @@ use derive_where::derive_where; use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::inherent::*; -use rustc_type_ir::lang_items::{SolverLangItem, SolverTraitLangItem}; +use rustc_type_ir::lang_items::{SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::solve::inspect::ProbeKind; use rustc_type_ir::{ @@ -106,7 +106,9 @@ where // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - Ok(ty::Binder::dummy(vec![cx.type_of(def_id).instantiate(cx, args).skip_norm_wip()])) + Ok(ty::Binder::dummy(vec![ + cx.type_of(def_id.into()).instantiate(cx, args).skip_norm_wip(), + ])) } } } @@ -541,7 +543,8 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable( let nested = vec![ bound_sig.rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()])).upcast(cx), ]; - let future_output_def_id = cx.require_lang_item(SolverLangItem::FutureOutput); + let future_output_def_id = + cx.require_projection_lang_item(SolverProjectionLangItem::FutureOutput); let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]); Ok(( bound_sig.rebind(AsyncCallableRelevantTypes { @@ -642,7 +646,8 @@ fn coroutine_closure_to_ambiguous_coroutine( args: ty::CoroutineClosureArgs, sig: ty::CoroutineClosureSignature, ) -> I::Ty { - let upvars_projection_def_id = cx.require_lang_item(SolverLangItem::AsyncFnKindUpvars); + let upvars_projection_def_id = + cx.require_projection_lang_item(SolverProjectionLangItem::AsyncFnKindUpvars); let tupled_upvars_ty = Ty::new_projection( cx, upvars_projection_def_id, @@ -920,7 +925,10 @@ where // show up in the bounds, but just ones that come from substituting // `Self` with the dyn type. let proj = proj.with_self_ty(cx, trait_ref.self_ty()); - replace_projection_with.entry(proj.def_id()).or_default().push(bound.rebind(proj)); + replace_projection_with + .entry(proj.def_id().into()) + .or_default() + .push(bound.rebind(proj)); } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index e4d3e881f6afc..a03d3182b9fed 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -702,7 +702,7 @@ where original_typing_mode: TypingMode, parent_opaque_types: &[(OpaqueTypeKey, I::Ty)], ) -> RerunDecision { - let parent_opaque_defids = parent_opaque_types.iter().map(|(key, _)| key.def_id); + let parent_opaque_defids = parent_opaque_types.iter().map(|(key, _)| key.def_id.into()); let opaque_in_storage = |opaques: I::LocalDefIds, defids: SmallCopyList<_>| { if defids.as_ref().is_empty() { RerunDecision::No @@ -1357,7 +1357,7 @@ where pub(super) fn fetch_eligible_assoc_item( &self, goal_trait_ref: ty::TraitRef, - trait_assoc_def_id: I::DefId, + trait_assoc_def_id: I::TraitAssocTermId, impl_def_id: I::ImplId, ) -> FetchEligibleAssocItemResponse { self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id) @@ -1374,7 +1374,7 @@ where pub(super) fn add_item_bounds_for_hidden_type( &mut self, - opaque_def_id: I::DefId, + opaque_def_id: I::OpaqueTyId, opaque_args: I::GenericArgs, param_env: I::ParamEnv, hidden_ty: I::Ty, diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 178a192a66300..5dc3162fbd2a7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -357,7 +357,7 @@ where } } - fn opaque_type_is_rigid(&self, def_id: I::DefId) -> bool { + fn opaque_type_is_rigid(&self, def_id: I::OpaqueTyId) -> bool { match self .typing_mode() // Caller should handle erased mode @@ -370,7 +370,7 @@ where TypingMode::Analysis { defining_opaque_types_and_generators: non_rigid_opaques } | TypingMode::Borrowck { defining_opaque_types: non_rigid_opaques } | TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => { - !def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id)) + !def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id.into())) } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index 72e8d1be5915e..44b8929c45f43 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -13,6 +13,7 @@ where pub(super) fn normalize_anon_const( &mut self, goal: Goal>, + def_id: I::UnevaluatedConstId, ) -> QueryResult { let uv = goal.predicate.alias.expect_ct(self.cx()); self.evaluate_const_and_instantiate_normalizes_to_term(goal, uv) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index 44fe2913b73de..f70f4bede33db 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -32,11 +32,13 @@ where let actual = match free_alias.kind(cx) { ty::AliasTermKind::FreeTy { def_id } => { - cx.type_of(def_id).instantiate(cx, free_alias.args).skip_norm_wip().into() - } - ty::AliasTermKind::FreeConst { def_id } if cx.is_type_const(def_id) => { - cx.const_of_item(def_id).instantiate(cx, free_alias.args).skip_norm_wip().into() + cx.type_of(def_id.into()).instantiate(cx, free_alias.args).skip_norm_wip().into() } + ty::AliasTermKind::FreeConst { def_id } if cx.is_type_const(def_id.into()) => cx + .const_of_item(def_id.into()) + .instantiate(cx, free_alias.args) + .skip_norm_wip() + .into(), ty::AliasTermKind::FreeConst { .. } => { return self.evaluate_const_and_instantiate_normalizes_to_term( goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 00b5fd7fdcbce..d9eeb3e90f95f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -18,18 +18,19 @@ where pub(super) fn normalize_inherent_associated_term( &mut self, goal: Goal>, + def_id: I::InherentAssocTermId, ) -> QueryResult { let cx = self.cx(); let inherent = goal.predicate.alias; - let impl_def_id = cx.parent(inherent.def_id()); - let impl_args = self.fresh_args_for_item(impl_def_id); + let impl_def_id = cx.inherent_alias_term_parent(def_id); + let impl_args = self.fresh_args_for_item(impl_def_id.into()); // Equate impl header and add impl where clauses self.eq( goal.param_env, inherent.self_ty(), - cx.type_of(impl_def_id).instantiate(cx, impl_args).skip_norm_wip(), + cx.type_of(impl_def_id.into()).instantiate(cx, impl_args).skip_norm_wip(), )?; // Equate IAT with the RHS of the project goal @@ -46,7 +47,7 @@ where // to be very careful when changing the impl where-clauses to be productive. self.add_goals( GoalSource::Misc, - cx.predicates_of(inherent.def_id()) + cx.predicates_of(def_id.into()) .iter_instantiated(cx, inherent_args) .map(Unnormalized::skip_norm_wip) .map(|pred| goal.with(cx, pred)), @@ -54,11 +55,13 @@ where let normalized = match inherent.kind(cx) { ty::AliasTermKind::InherentTy { def_id } => { - cx.type_of(def_id).instantiate(cx, inherent_args).skip_norm_wip().into() - } - ty::AliasTermKind::InherentConst { def_id } if cx.is_type_const(def_id) => { - cx.const_of_item(def_id).instantiate(cx, inherent_args).skip_norm_wip().into() + cx.type_of(def_id.into()).instantiate(cx, inherent_args).skip_norm_wip().into() } + ty::AliasTermKind::InherentConst { def_id } if cx.is_type_const(def_id.into()) => cx + .const_of_item(def_id.into()) + .instantiate(cx, inherent_args) + .skip_norm_wip() + .into(), ty::AliasTermKind::InherentConst { .. } => { // FIXME(gca): This is dead code at the moment. It should eventually call // self.evaluate_const like projected consts do in consider_impl_candidate in diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 3b2e13fbb22dc..ce9663666ed90 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -5,7 +5,7 @@ mod opaque_types; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; -use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; +use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::{FetchEligibleAssocItemResponse, RerunReason}; use rustc_type_ir::{ self as ty, FieldInfo, Interner, NormalizesTo, PredicateKind, Unnormalized, Upcast as _, @@ -32,74 +32,79 @@ where goal: Goal>, ) -> QueryResult { debug_assert!(self.term_is_fully_unconstrained(goal)); - let cx = self.cx(); - match goal.predicate.alias.kind(cx) { + match goal.predicate.alias.kind { ty::AliasTermKind::ProjectionTy { .. } | ty::AliasTermKind::ProjectionConst { .. } => { - let trait_ref = goal.predicate.alias.trait_ref(cx); - let (_, proven_via) = - self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { - let trait_goal: Goal> = goal.with(cx, trait_ref); - ecx.compute_trait_goal(trait_goal) - })?; - self.assemble_and_merge_candidates( - proven_via, - goal, - |ecx| { - // FIXME(generic_associated_types): Addresses aggressive inference in #92917. - // - // If this type is a GAT with currently unconstrained arguments, we do not - // want to normalize it via a candidate which only applies for a specific - // instantiation. We could otherwise keep the GAT as rigid and succeed this way. - // See tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs. - // - // This only avoids normalization if a GAT argument is fully unconstrained. - // This is quite arbitrary but fixing it causes some ambiguity, see #125196. - for arg in goal.predicate.alias.own_args(cx).iter() { - let Some(term) = arg.as_term() else { - continue; - }; - match ecx.structurally_normalize_term(goal.param_env, term) { - Ok(term) => { - if term.is_infer() { - return Some( - ecx.evaluate_added_goals_and_make_canonical_response( - Certainty::AMBIGUOUS, - ), - ); - } - } - Err(NoSolution) => return Some(Err(NoSolution)), - } - } - - None - }, - |ecx| { - ecx.probe(|&result| ProbeKind::RigidAlias { result }) - .enter(|this| { - this.structurally_instantiate_normalizes_to_term( - goal, - goal.predicate.alias, - ); - this.evaluate_added_goals_and_make_canonical_response( - Certainty::Yes, - ) - }) - .map_err(Into::into) - }, - ) + self.normalize_associated_term(goal) } - ty::AliasTermKind::InherentTy { .. } | ty::AliasTermKind::InherentConst { .. } => { - self.normalize_inherent_associated_term(goal) + ty::AliasTermKind::InherentTy { def_id } => { + self.normalize_inherent_associated_term(goal, def_id.into()) } - ty::AliasTermKind::OpaqueTy { .. } => self.normalize_opaque_type(goal), + ty::AliasTermKind::InherentConst { def_id } => { + self.normalize_inherent_associated_term(goal, def_id.into()) + } + ty::AliasTermKind::OpaqueTy { def_id } => self.normalize_opaque_type(goal, def_id), ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. } => { self.normalize_free_alias(goal) } - ty::AliasTermKind::UnevaluatedConst { .. } => self.normalize_anon_const(goal), + ty::AliasTermKind::UnevaluatedConst { def_id } => { + self.normalize_anon_const(goal, def_id) + } } } + fn normalize_associated_term(&mut self, goal: Goal>) -> QueryResult { + let cx = self.cx(); + + let trait_ref = goal.predicate.alias.trait_ref(cx); + let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { + let trait_goal: Goal> = goal.with(cx, trait_ref); + ecx.compute_trait_goal(trait_goal) + })?; + self.assemble_and_merge_candidates( + proven_via, + goal, + |ecx| { + // FIXME(generic_associated_types): Addresses aggressive inference in #92917. + // + // If this type is a GAT with currently unconstrained arguments, we do not + // want to normalize it via a candidate which only applies for a specific + // instantiation. We could otherwise keep the GAT as rigid and succeed this way. + // See tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs. + // + // This only avoids normalization if a GAT argument is fully unconstrained. + // This is quite arbitrary but fixing it causes some ambiguity, see #125196. + for arg in goal.predicate.alias.own_args(cx).iter() { + let Some(term) = arg.as_term() else { + continue; + }; + match ecx.structurally_normalize_term(goal.param_env, term) { + Ok(term) => { + if term.is_infer() { + return Some(ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::AMBIGUOUS, + )); + } + } + Err(NoSolution) => return Some(Err(NoSolution)), + } + } + + None + }, + |ecx| { + ecx.probe(|&result| ProbeKind::RigidAlias { result }) + .enter(|this| { + this.structurally_instantiate_normalizes_to_term( + goal, + goal.predicate.alias, + ); + this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + .map_err(Into::into) + }, + ) + } + /// When normalizing an associated item, constrain the expected term to `term`. /// /// We know `term` to always be a fully unconstrained inference variable, so @@ -282,7 +287,7 @@ where let target_item_def_id = match ecx.fetch_eligible_assoc_item( goal_trait_ref, - goal.predicate.def_id(), + goal.predicate.def_id().try_into().unwrap(), impl_def_id, ) { FetchEligibleAssocItemResponse::Found(target_item_def_id) => target_item_def_id, @@ -354,7 +359,7 @@ where } } - let target_container_def_id = cx.parent(target_item_def_id); + let target_container_def_id = cx.impl_or_trait_assoc_term_parent(target_item_def_id); // Getting the right args here is complex, e.g. given: // - a goal ` as Trait>::Assoc` @@ -371,10 +376,10 @@ where impl_def_id, impl_args, impl_trait_ref, - target_container_def_id, + target_container_def_id.into(), )?; - if !cx.check_args_compatible(target_item_def_id, target_args) { + if !cx.check_args_compatible(target_item_def_id.into(), target_args) { return error_response( ecx, cx.delay_bug("associated item has mismatched arguments"), @@ -384,21 +389,21 @@ where // Finally we construct the actual value of the associated type. let term = match goal.predicate.alias.kind(cx) { ty::AliasTermKind::ProjectionTy { .. } => cx - .type_of(target_item_def_id) + .type_of(target_item_def_id.into()) .instantiate(cx, target_args) .skip_norm_wip() .into(), ty::AliasTermKind::ProjectionConst { .. } - if cx.is_type_const(target_item_def_id) => + if cx.is_type_const(target_item_def_id.into()) => { - cx.const_of_item(target_item_def_id) + cx.const_of_item(target_item_def_id.into()) .instantiate(cx, target_args) .skip_norm_wip() .into() } ty::AliasTermKind::ProjectionConst { .. } => { let uv = ty::UnevaluatedConst::new( - target_item_def_id.try_into().unwrap(), + target_item_def_id.into().try_into().unwrap(), target_args, ); return ecx.evaluate_const_and_instantiate_normalizes_to_term(goal, uv); @@ -504,6 +509,7 @@ where goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { let cx = ecx.cx(); + let def_id = goal.predicate.def_id().try_into().unwrap(); let env_region = match goal_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), @@ -531,41 +537,42 @@ where [output_coroutine_ty], ); - let (projection_term, term) = - if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::CallOnceFuture) { - ( - ty::AliasTerm::new( - cx, - cx.alias_term_kind_from_def_id(goal.predicate.def_id()), - [goal.predicate.self_ty(), tupled_inputs_ty], - ), - output_coroutine_ty.into(), - ) - } else if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::CallRefFuture) { - ( - ty::AliasTerm::new( - cx, - cx.alias_term_kind_from_def_id(goal.predicate.def_id()), - [ - I::GenericArg::from(goal.predicate.self_ty()), - tupled_inputs_ty.into(), - env_region.into(), - ], - ), - output_coroutine_ty.into(), - ) - } else if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::AsyncFnOnceOutput) { - ( - ty::AliasTerm::new( - cx, - cx.alias_term_kind_from_def_id(goal.predicate.def_id()), - [goal.predicate.self_ty(), tupled_inputs_ty], - ), - coroutine_return_ty.into(), - ) - } else { - panic!("no such associated type in `AsyncFn*`: {:?}", goal.predicate.def_id()) - }; + let (projection_term, term) = if cx + .is_projection_lang_item(def_id, SolverProjectionLangItem::CallOnceFuture) + { + ( + ty::AliasTerm::new( + cx, + cx.alias_term_kind_from_def_id(goal.predicate.def_id()), + [goal.predicate.self_ty(), tupled_inputs_ty], + ), + output_coroutine_ty.into(), + ) + } else if cx.is_projection_lang_item(def_id, SolverProjectionLangItem::CallRefFuture) { + ( + ty::AliasTerm::new( + cx, + cx.alias_term_kind_from_def_id(goal.predicate.def_id()), + [ + I::GenericArg::from(goal.predicate.self_ty()), + tupled_inputs_ty.into(), + env_region.into(), + ], + ), + output_coroutine_ty.into(), + ) + } else if cx.is_projection_lang_item(def_id, SolverProjectionLangItem::AsyncFnOnceOutput) { + ( + ty::AliasTerm::new( + cx, + cx.alias_term_kind_from_def_id(goal.predicate.def_id()), + [goal.predicate.self_ty(), tupled_inputs_ty], + ), + coroutine_return_ty.into(), + ) + } else { + panic!("no such associated type in `AsyncFn*`: {:?}", goal.predicate.def_id()) + }; let pred = ty::ProjectionPredicate { projection_term, term }.upcast(cx); Self::probe_and_consider_implied_clause( @@ -639,8 +646,8 @@ where goal: Goal, ) -> Result, NoSolution> { let cx = ecx.cx(); - let metadata_def_id = cx.require_lang_item(SolverLangItem::Metadata); - assert_eq!(metadata_def_id, goal.predicate.def_id()); + let metadata_def_id = cx.require_projection_lang_item(SolverProjectionLangItem::Metadata); + assert_eq!(Into::::into(metadata_def_id), goal.predicate.def_id()); let metadata_ty = match goal.predicate.self_ty().kind() { ty::Bool | ty::Char @@ -666,8 +673,8 @@ where ty::Str | ty::Slice(_) => Ty::new_usize(cx), ty::Dynamic(_, _) => { - let dyn_metadata = cx.require_lang_item(SolverLangItem::DynMetadata); - cx.type_of(dyn_metadata) + let dyn_metadata = cx.require_adt_lang_item(SolverAdtLangItem::DynMetadata); + cx.type_of(dyn_metadata.into()) .instantiate(cx, &[I::GenericArg::from(goal.predicate.self_ty())]) .skip_norm_wip() } @@ -865,10 +872,12 @@ where } let coroutine = args.as_coroutine(); + let def_id = goal.predicate.def_id().try_into().unwrap(); - let term = if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::CoroutineReturn) { + let term = if cx.is_projection_lang_item(def_id, SolverProjectionLangItem::CoroutineReturn) + { coroutine.return_ty().into() - } else if cx.is_lang_item(goal.predicate.def_id(), SolverLangItem::CoroutineYield) { + } else if cx.is_projection_lang_item(def_id, SolverProjectionLangItem::CoroutineYield) { coroutine.yield_ty().into() } else { panic!("unexpected associated item `{:?}` for `{self_ty:?}`", goal.predicate.def_id()) @@ -992,9 +1001,10 @@ where else { return Err(NoSolution); }; - let ty = match ecx.cx().as_lang_item(goal.predicate.def_id()) { - Some(SolverLangItem::FieldBase) => base, - Some(SolverLangItem::FieldType) => ty, + let ty = match ecx.cx().as_projection_lang_item(goal.predicate.def_id().try_into().unwrap()) + { + Some(SolverProjectionLangItem::FieldBase) => base, + Some(SolverProjectionLangItem::FieldType) => ty, _ => panic!("unexpected associated type {:?} in `Field`", goal.predicate), }; ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 45dd2f25abd78..f25ac21f4a62b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -17,6 +17,7 @@ where pub(super) fn normalize_opaque_type( &mut self, goal: Goal>, + def_id: I::OpaqueTyId, ) -> QueryResult { let cx = self.cx(); let opaque_ty = goal.predicate.alias; @@ -27,7 +28,7 @@ where // An impossible opaque type bound is the only way this goal will fail // e.g. assigning `impl Copy := NotCopy` self.add_item_bounds_for_hidden_type( - opaque_ty.def_id(), + def_id, opaque_ty.args, goal.param_env, expected, @@ -43,10 +44,9 @@ where defining_opaque_types_and_generators: defining_opaque_types, } | TypingMode::Borrowck { defining_opaque_types } => { - let Some(def_id) = opaque_ty - .def_id() + let Some(def_id) = def_id .as_local() - .filter(|&def_id| defining_opaque_types.contains(&def_id)) + .filter(|&def_id| defining_opaque_types.contains(&def_id.into())) else { // If we're not in the defining scope, treat the alias as rigid. self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); @@ -134,7 +134,7 @@ where TypingMode::PostAnalysis => { // FIXME: Add an assertion that opaque type storage is empty. let actual = - cx.type_of(opaque_ty.def_id()).instantiate(cx, opaque_ty.args).skip_norm_wip(); + cx.type_of(def_id.into()).instantiate(cx, opaque_ty.args).skip_norm_wip(); self.eq(goal.param_env, expected, actual)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 4d5fe3bf69502..a4f35f763e8e2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -242,7 +242,7 @@ where } debug_assert!(ecx.opaque_type_is_rigid(def_id)); - for item_bound in cx.item_self_bounds(def_id).skip_binder() { + for item_bound in cx.item_self_bounds(def_id.into()).skip_binder() { if item_bound .as_trait_clause() .is_some_and(|b| b.def_id() == goal.predicate.def_id()) diff --git a/compiler/rustc_type_ir/src/generic_visit.rs b/compiler/rustc_type_ir/src/generic_visit.rs index 6669168443a4a..6adaf4d158f40 100644 --- a/compiler/rustc_type_ir/src/generic_visit.rs +++ b/compiler/rustc_type_ir/src/generic_visit.rs @@ -212,6 +212,7 @@ trivial_impls!( rustc_hash::FxBuildHasher, crate::TypeFlags, crate::solve::GoalSource, + crate::solve::VisibleForLeakCheck, rustc_abi::ExternAbi, ); diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f63361f5968d2..7ff447a81a284 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -55,7 +55,11 @@ pub trait Ty>: fn new_alias(interner: I, alias_ty: ty::AliasTy) -> Self; - fn new_projection_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self { + fn new_projection_from_args( + interner: I, + def_id: I::TraitAssocTyId, + args: I::GenericArgs, + ) -> Self { Self::new_alias( interner, ty::AliasTy::new_from_args(interner, ty::AliasTyKind::Projection { def_id }, args), @@ -64,7 +68,7 @@ pub trait Ty>: fn new_projection( interner: I, - def_id: I::DefId, + def_id: I::TraitAssocTyId, args: impl IntoIterator>, ) -> Self { Self::new_alias( @@ -637,19 +641,24 @@ pub trait Features: Copy { } #[rust_analyzer::prefer_underscore_import] -pub trait DefId: Copy + Debug + Hash + Eq + TypeFoldable { +pub trait DefId::LocalDefId>: + Copy + Debug + Hash + Eq + TypeFoldable +{ fn is_local(self) -> bool; - fn as_local(self) -> Option; + fn as_local(self) -> Option; } -pub trait SpecificDefId: - DefId + Into + TryFrom +pub trait SpecificDefId::LocalDefId>: + DefId + Into + TryFrom { } -impl + Into + TryFrom> - SpecificDefId for T +impl< + I: Interner, + T: DefId + Into + TryFrom, + Local, +> SpecificDefId for T { } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index e13c4279a68a1..f25bc5fc4e3c9 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -9,7 +9,7 @@ use rustc_index::bit_set::DenseBitSet; use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; -use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; +use crate::lang_items::{SolverAdtLangItem, SolverProjectionLangItem, SolverTraitLangItem}; use crate::relate::Relate; use crate::solve::{ AccessedOpaques, CanonicalInput, Certainty, ExternalConstraintsData, QueryResult, inspect, @@ -56,6 +56,38 @@ pub trait Interner: type AdtId: SpecificDefId; type ImplId: SpecificDefId; type UnevaluatedConstId: SpecificDefId; + type TraitAssocTyId: SpecificDefId + + Into + + TryFrom; + type TraitAssocConstId: SpecificDefId + + Into + + Into + + TryFrom; + type TraitAssocTermId: SpecificDefId; + type OpaqueTyId: SpecificDefId; + type LocalOpaqueTyId: Copy + + Debug + + Hash + + Eq + + Into + + Into + + Into + + TypeFoldable; + type FreeTyAliasId: SpecificDefId + Into; + type FreeConstAliasId: SpecificDefId + + Into + + Into; + type FreeTermAliasId: SpecificDefId; + type ImplOrTraitAssocTyId: SpecificDefId + Into; + type ImplOrTraitAssocConstId: SpecificDefId + + Into + + Into; + type ImplOrTraitAssocTermId: SpecificDefId; + type InherentAssocTyId: SpecificDefId + Into; + type InherentAssocConstId: SpecificDefId + + Into + + Into; + type InherentAssocTermId: SpecificDefId; type Span: Span; type GenericArgs: GenericArgs; @@ -203,8 +235,10 @@ pub trait Interner: ) -> Option; fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; - fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) - -> ty::EarlyBinder; + fn type_of_opaque_hir_typeck( + self, + def_id: Self::LocalOpaqueTyId, + ) -> ty::EarlyBinder; fn is_type_const(self, def_id: Self::DefId) -> bool; fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder; fn anon_const_kind(self, def_id: Self::DefId) -> ty::AnonConstKind; @@ -219,7 +253,7 @@ pub trait Interner: fn trait_ref_and_own_args_for_alias( self, - def_id: Self::DefId, + def_id: Self::TraitAssocTermId, args: Self::GenericArgs, ) -> (ty::TraitRef, Self::GenericArgsSlice); @@ -243,7 +277,12 @@ pub trait Interner: I: Iterator, T: CollectAndApply; - fn parent(self, def_id: Self::DefId) -> Self::DefId; + fn projection_parent(self, def_id: Self::TraitAssocTermId) -> Self::TraitId; + + /// This can be an impl, or a trait if this is a defaulted term. + fn impl_or_trait_assoc_term_parent(self, def_id: Self::ImplOrTraitAssocTermId) -> Self::DefId; + + fn inherent_alias_term_parent(self, def_id: Self::InherentAssocTermId) -> Self::ImplId; fn recursion_limit(self) -> usize; @@ -325,13 +364,20 @@ pub trait Interner: fn has_target_features(self, def_id: Self::FunctionId) -> bool; - fn require_lang_item(self, lang_item: SolverLangItem) -> Self::DefId; + fn require_projection_lang_item( + self, + lang_item: SolverProjectionLangItem, + ) -> Self::TraitAssocTyId; fn require_trait_lang_item(self, lang_item: SolverTraitLangItem) -> Self::TraitId; fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> Self::AdtId; - fn is_lang_item(self, def_id: Self::DefId, lang_item: SolverLangItem) -> bool; + fn is_projection_lang_item( + self, + def_id: Self::TraitAssocTyId, + lang_item: SolverProjectionLangItem, + ) -> bool; fn is_trait_lang_item(self, def_id: Self::TraitId, lang_item: SolverTraitLangItem) -> bool; @@ -341,7 +387,10 @@ pub trait Interner: fn is_sizedness_trait(self, def_id: Self::TraitId) -> bool; - fn as_lang_item(self, def_id: Self::DefId) -> Option; + fn as_projection_lang_item( + self, + def_id: Self::TraitAssocTyId, + ) -> Option; fn as_trait_lang_item(self, def_id: Self::TraitId) -> Option; @@ -360,7 +409,7 @@ pub trait Interner: ); fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, f: impl FnMut(Self::ImplId)); - fn has_item_definition(self, def_id: Self::DefId) -> bool; + fn has_item_definition(self, def_id: Self::ImplOrTraitAssocTermId) -> bool; fn impl_specializes(self, impl_def_id: Self::ImplId, victim_def_id: Self::ImplId) -> bool; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index f1c45a4d98b5e..4ed574a55ece1 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -1,6 +1,6 @@ /// Lang items used by the new trait solver. This can be mapped to whatever internal /// representation of `LangItem`s used in the underlying compiler implementation. -pub enum SolverLangItem { +pub enum SolverProjectionLangItem { // tidy-alphabetical-start AsyncFnKindUpvars, AsyncFnOnceOutput, @@ -8,7 +8,6 @@ pub enum SolverLangItem { CallRefFuture, CoroutineReturn, CoroutineYield, - DynMetadata, FieldBase, FieldType, FutureOutput, @@ -18,6 +17,7 @@ pub enum SolverLangItem { pub enum SolverAdtLangItem { // tidy-alphabetical-start + DynMetadata, Option, Poll, // tidy-alphabetical-end @@ -29,7 +29,6 @@ pub enum SolverTraitLangItem { AsyncFnKindHelper, AsyncFnMut, AsyncFnOnce, - AsyncFnOnceOutput, AsyncIterator, BikeshedGuaranteedNoDrop, Clone, diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index 782a7d30b675b..d050cc2fe05aa 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -13,7 +13,7 @@ use crate::{self as ty, Interner}; derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) )] pub struct OpaqueTypeKey { - pub def_id: I::LocalDefId, + pub def_id: I::LocalOpaqueTyId, pub args: I::GenericArgs, } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 7b815e61cf09e..301cf7dbf1087 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -472,7 +472,7 @@ impl ty::Binder> { derive(Decodable_NoContext, Encodable_NoContext, StableHash_NoContext) )] pub struct ExistentialProjection { - pub def_id: I::DefId, + pub def_id: I::TraitAssocTermId, pub args: I::GenericArgs, pub term: I::Term, @@ -487,17 +487,17 @@ impl Eq for ExistentialProjection {} impl ExistentialProjection { pub fn new_from_args( interner: I, - def_id: I::DefId, + def_id: I::TraitAssocTermId, args: I::GenericArgs, term: I::Term, ) -> ExistentialProjection { - interner.debug_assert_existential_args_compatible(def_id, args); + interner.debug_assert_existential_args_compatible(def_id.into(), args); Self { def_id, args, term, use_existential_projection_new_instead: () } } pub fn new( interner: I, - def_id: I::DefId, + def_id: I::TraitAssocTermId, args: impl IntoIterator>, term: I::Term, ) -> ExistentialProjection { @@ -511,10 +511,10 @@ impl ExistentialProjection { /// then this function would return an `exists T. T: Iterator` existential trait /// reference. pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef { - let def_id = interner.parent(self.def_id); - let args_count = interner.generics_of(def_id).count() - 1; + let def_id = interner.projection_parent(self.def_id); + let args_count = interner.generics_of(def_id.into()).count() - 1; let args = interner.mk_args(&self.args.as_slice()[..args_count]); - ExistentialTraitRef::new_from_args(interner, def_id.try_into().unwrap(), args) + ExistentialTraitRef::new_from_args(interner, def_id, args) } pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { @@ -524,7 +524,7 @@ impl ExistentialProjection { ProjectionPredicate { projection_term: AliasTerm::new( interner, - interner.alias_term_kind_from_def_id(self.def_id), + interner.alias_term_kind_from_def_id(self.def_id.into()), [self_ty.into()].iter().chain(self.args.iter()), ), term: self.term, @@ -536,7 +536,7 @@ impl ExistentialProjection { projection_predicate.projection_term.args.type_at(0); Self { - def_id: projection_predicate.projection_term.def_id(), + def_id: projection_predicate.def_id(), args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]), term: projection_predicate.term, use_existential_projection_new_instead: (), @@ -549,13 +549,13 @@ impl ty::Binder> { self.map_bound(|p| p.with_self_ty(cx, self_ty)) } - pub fn item_def_id(&self) -> I::DefId { + pub fn item_def_id(&self) -> I::TraitAssocTermId { self.skip_binder().def_id } } #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] -#[derive(Lift_Generic)] +#[derive(Lift_Generic, GenericTypeVisitable)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) @@ -570,12 +570,12 @@ pub enum AliasTermKind { /// Note that the `def_id` is not the `DefId` of the `TraitRef` containing this /// associated type, which is in `interner.associated_item(def_id).container`, /// aka. `interner.parent(def_id)`. - ProjectionTy { def_id: I::DefId }, + ProjectionTy { def_id: I::TraitAssocTyId }, /// An associated type in an inherent `impl` /// /// The `def_id` is the `DefId` of the `ImplItem` for the associated type. - InherentTy { def_id: I::DefId }, + InherentTy { def_id: I::InherentAssocTyId }, /// An opaque type (usually from `impl Trait` in type aliases or function return types) /// @@ -585,22 +585,22 @@ pub enum AliasTermKind { /// /// During codegen, `interner.type_of(def_id)` can be used to get the type of the /// underlying type if the type is an opaque. - OpaqueTy { def_id: I::DefId }, + OpaqueTy { def_id: I::OpaqueTyId }, /// A type alias that actually checks its trait bounds. /// /// Currently only used if the type alias references opaque types. /// Can always be normalized away. - FreeTy { def_id: I::DefId }, + FreeTy { def_id: I::FreeTyAliasId }, /// An unevaluated anonymous constants. - UnevaluatedConst { def_id: I::DefId }, + UnevaluatedConst { def_id: I::UnevaluatedConstId }, /// An unevaluated const coming from an associated const. - ProjectionConst { def_id: I::DefId }, + ProjectionConst { def_id: I::TraitAssocConstId }, /// A top level const item not part of a trait or impl. - FreeConst { def_id: I::DefId }, + FreeConst { def_id: I::FreeConstAliasId }, /// An associated const in an inherent `impl` - InherentConst { def_id: I::DefId }, + InherentConst { def_id: I::InherentAssocConstId }, } impl AliasTermKind { @@ -631,17 +631,18 @@ impl AliasTermKind { } } - // FIXME: replace with explicit matches + // FIXME(#156181): replace with explicit matches pub fn def_id(self) -> I::DefId { - let (AliasTermKind::ProjectionTy { def_id } - | AliasTermKind::InherentTy { def_id } - | AliasTermKind::OpaqueTy { def_id } - | AliasTermKind::FreeTy { def_id } - | AliasTermKind::UnevaluatedConst { def_id } - | AliasTermKind::ProjectionConst { def_id } - | AliasTermKind::FreeConst { def_id } - | AliasTermKind::InherentConst { def_id }) = self; - def_id + match self { + AliasTermKind::ProjectionTy { def_id } => def_id.into(), + AliasTermKind::InherentTy { def_id } => def_id.into(), + AliasTermKind::OpaqueTy { def_id } => def_id.into(), + AliasTermKind::FreeTy { def_id } => def_id.into(), + AliasTermKind::UnevaluatedConst { def_id } => def_id.into(), + AliasTermKind::ProjectionConst { def_id } => def_id.into(), + AliasTermKind::FreeConst { def_id } => def_id.into(), + AliasTermKind::InherentConst { def_id } => def_id.into(), + } } } @@ -737,11 +738,11 @@ impl AliasTerm { } pub fn expect_ct(self, interner: I) -> ty::UnevaluatedConst { - let def_id = match self.kind(interner) { - AliasTermKind::InherentConst { def_id } - | AliasTermKind::FreeConst { def_id } - | AliasTermKind::UnevaluatedConst { def_id } - | AliasTermKind::ProjectionConst { def_id } => def_id, + let def = match self.kind(interner) { + AliasTermKind::InherentConst { def_id } => def_id.into(), + AliasTermKind::FreeConst { def_id } => def_id.into(), + AliasTermKind::UnevaluatedConst { def_id } => def_id, + AliasTermKind::ProjectionConst { def_id } => def_id.into(), kind @ (AliasTermKind::ProjectionTy { .. } | AliasTermKind::InherentTy { .. } | AliasTermKind::OpaqueTy { .. } @@ -749,7 +750,7 @@ impl AliasTerm { panic!("Cannot turn `{}` into `UnevaluatedConst`", kind.descr()) } }; - ty::UnevaluatedConst { def: def_id.try_into().unwrap(), args: self.args } + ty::UnevaluatedConst { def, args: self.args } } // FIXME: remove this function (access the field instead) @@ -763,17 +764,14 @@ impl AliasTerm { } pub fn to_term(self, interner: I) -> I::Term { + let unevaluated_const = |def_id| { + I::Const::new_unevaluated(interner, ty::UnevaluatedConst::new(def_id, self.args)).into() + }; let alias_ty_kind = match self.kind(interner) { - AliasTermKind::FreeConst { def_id } - | AliasTermKind::InherentConst { def_id } - | AliasTermKind::UnevaluatedConst { def_id } - | AliasTermKind::ProjectionConst { def_id } => { - return I::Const::new_unevaluated( - interner, - ty::UnevaluatedConst::new(def_id.try_into().unwrap(), self.args), - ) - .into(); - } + AliasTermKind::FreeConst { def_id } => return unevaluated_const(def_id.into()), + AliasTermKind::InherentConst { def_id } => return unevaluated_const(def_id.into()), + AliasTermKind::UnevaluatedConst { def_id } => return unevaluated_const(def_id), + AliasTermKind::ProjectionConst { def_id } => return unevaluated_const(def_id.into()), AliasTermKind::ProjectionTy { def_id } => ty::Projection { def_id }, AliasTermKind::InherentTy { def_id } => ty::Inherent { def_id }, @@ -804,15 +802,25 @@ impl AliasTerm { ) } + fn projection_def_id(self) -> Option { + match self.kind { + AliasTermKind::ProjectionTy { def_id } => Some(def_id.into()), + AliasTermKind::ProjectionConst { def_id } => Some(def_id.into()), + AliasTermKind::InherentTy { .. } + | AliasTermKind::OpaqueTy { .. } + | AliasTermKind::FreeTy { .. } + | AliasTermKind::UnevaluatedConst { .. } + | AliasTermKind::FreeConst { .. } + | AliasTermKind::InherentConst { .. } => None, + } + } + + fn expect_projection_def_id(self) -> I::TraitAssocTermId { + self.projection_def_id().expect("expected a projection") + } + pub fn trait_def_id(self, interner: I) -> I::TraitId { - assert!( - matches!( - self.kind(interner), - AliasTermKind::ProjectionTy { .. } | AliasTermKind::ProjectionConst { .. } - ), - "expected a projection" - ); - interner.parent(self.def_id()).try_into().unwrap() + interner.projection_parent(self.expect_projection_def_id()) } /// Extracts the underlying trait reference and own args from this projection. @@ -820,7 +828,7 @@ impl AliasTerm { /// then this function would return a `T: StreamingIterator` trait reference and /// `['a]` as the own args. pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::GenericArgsSlice) { - interner.trait_ref_and_own_args_for_alias(self.def_id(), self.args) + interner.trait_ref_and_own_args_for_alias(self.expect_projection_def_id(), self.args) } /// Extracts the underlying trait reference from this projection. @@ -918,8 +926,8 @@ impl ProjectionPredicate { self.projection_term.trait_def_id(interner) } - pub fn def_id(self) -> I::DefId { - self.projection_term.def_id() + pub fn def_id(self) -> I::TraitAssocTermId { + self.projection_term.expect_projection_def_id() } } diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 425436dabafb2..51de99e92fcad 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -268,7 +268,10 @@ impl Relate for ty::ExistentialProjection { b: ty::ExistentialProjection, ) -> RelateResult> { if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id, b.def_id))) + Err(TypeError::ProjectionMismatched(ExpectedFound::new( + a.def_id.into(), + b.def_id.into(), + ))) } else { let term = relation.relate_with_variance( ty::Invariant, diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 0634c9b741d38..cf9530378dc7c 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -535,7 +535,7 @@ pub enum BuiltinImplSource { #[derive_where(Copy, Clone, Debug; I: Interner)] pub enum FetchEligibleAssocItemResponse { Err(I::ErrorGuaranteed), - Found(I::DefId), + Found(I::ImplOrTraitAssocTermId), NotFound(TypingMode), NotFoundBecauseErased, } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index a08bd00eeed65..0fc39660015de 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -39,12 +39,12 @@ pub enum AliasTyKind { /// Note that the `def_id` is not the `DefId` of the `TraitRef` containing this /// associated type, which is in `interner.associated_item(def_id).container`, /// aka. `interner.parent(def_id)`. - Projection { def_id: I::DefId }, + Projection { def_id: I::TraitAssocTyId }, /// An associated type in an inherent `impl` /// /// The `def_id` is the `DefId` of the `ImplItem` for the associated type. - Inherent { def_id: I::DefId }, + Inherent { def_id: I::InherentAssocTyId }, /// An opaque type (usually from `impl Trait` in type aliases or function return types) /// @@ -55,13 +55,13 @@ pub enum AliasTyKind { /// /// During codegen, `interner.type_of(def_id)` can be used to get the type of the /// underlying type if the type is an opaque. - Opaque { def_id: I::DefId }, + Opaque { def_id: I::OpaqueTyId }, /// A type alias that actually checks its trait bounds. /// /// Currently only used if the type alias references opaque types. /// Can always be normalized away. - Free { def_id: I::DefId }, + Free { def_id: I::FreeTyAliasId }, } impl AliasTyKind { @@ -79,12 +79,12 @@ impl AliasTyKind { } pub fn def_id(self) -> I::DefId { - let (AliasTyKind::Projection { def_id } - | AliasTyKind::Inherent { def_id } - | AliasTyKind::Opaque { def_id } - | AliasTyKind::Free { def_id }) = self; - - def_id + match self { + AliasTyKind::Projection { def_id } => def_id.into(), + AliasTyKind::Inherent { def_id } => def_id.into(), + AliasTyKind::Opaque { def_id } => def_id.into(), + AliasTyKind::Free { def_id } => def_id.into(), + } } } @@ -506,10 +506,10 @@ impl AliasTy { ) } - pub fn trait_def_id(self, interner: I) -> I::DefId { + pub fn trait_def_id(self, interner: I) -> I::TraitId { let AliasTyKind::Projection { def_id } = self.kind else { panic!("expected a projection") }; - interner.parent(def_id) + interner.projection_parent(def_id.into()) } /// Extracts the underlying trait reference and own args from this projection. @@ -520,7 +520,7 @@ impl AliasTy { pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef, I::GenericArgsSlice) { let AliasTyKind::Projection { def_id } = self.kind else { panic!("expected a projection") }; - interner.trait_ref_and_own_args_for_alias(def_id, self.args) + interner.trait_ref_and_own_args_for_alias(def_id.into(), self.args) } /// Extracts the underlying trait reference from this projection. From aadf600574a3b72a3ba53723f8a6f498557b297f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 6 May 2026 14:41:52 -0700 Subject: [PATCH 20/21] Document wasi-sdk minimum versions for WASI targets This commit updates the documentation for WASI targets in the rustc book to mention a minimum version of wasi-sdk that's required. Closes 155971 --- .../src/platform-support/wasm32-wasip1.md | 19 +++++++++++---- .../src/platform-support/wasm32-wasip2.md | 23 ++++++++----------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1.md b/src/doc/rustc/src/platform-support/wasm32-wasip1.md index eb74edda22de8..16499659291a0 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1.md @@ -70,17 +70,16 @@ be used instead. [`wasi-libc`]: https://github.com/WebAssembly/wasi-libc -## Building the target +## Building the target in rustc -To build this target first acquire a copy of -[`wasi-sdk`](https://github.com/WebAssembly/wasi-sdk/). At this time version 22 -is the minimum needed. +To build this target first acquire a copy of [`wasi-sdk`]. At this time version +33 is the minimum needed. Next configure the `WASI_SDK_PATH` environment variable to point to where this is installed. For example: ```text -export WASI_SDK_PATH=/path/to/wasi-sdk-22.0 +export WASI_SDK_PATH=/path/to/wasi-sdk-33.0 ``` Next be sure to enable LLD when building Rust from source as LLVM's `wasm-ld` @@ -103,6 +102,16 @@ Rust programs can be built for that target: rustc --target wasm32-wasip1 your-code.rs ``` +The `wasm32-wasip1` toolchain comes with a self-contained sysroot meaning that +no external compiler is required when building for this target. Users which +build a `staticlib`, however, or use an external `-Clinker`, are recommended to +use [`wasi-sdk`]. The minimum version required of [`wasi-sdk`] will change over +time as it's updated in Rust and Rust relies on newer features that [`wasi-sdk`] +has. See the documentation above about building the target in rustc for the +minimum known working version. + +[`wasi-sdk`]: https://github.com/WebAssembly/wasi-sdk + ## Cross-compilation This target can be cross-compiled from any hosts. diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip2.md b/src/doc/rustc/src/platform-support/wasm32-wasip2.md index 861083ad4a61a..4b7e84d715769 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip2.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip2.md @@ -27,23 +27,20 @@ are required to support components since this target outputs a component as opposed to a core wasm module. As of the time of this writing Wasmtime 17 and above is able to run this target natively with no extra flags. -## Building the target +## Building the target in rustc -To build this target first acquire a copy of -[`wasi-sdk`](https://github.com/WebAssembly/wasi-sdk/). At this time version 22 -is the minimum needed. +See the documentation for the [building the `wasm32-wasip1` target in +rustc](./wasm32-wasip1.md#building-the-target-in-rustc) for more information. The tl;dr; +is that [`wasi-sdk`] is required, and the `wasm32-wasip1` target documents the +minimum version required. -Next configure the `WASI_SDK_PATH` environment variable to point to where this -is installed. For example: +[`wasi-sdk`]: https://github.com/WebAssembly/wasi-sdk -```text -export WASI_SDK_PATH=/path/to/wasi-sdk-22.0 -``` +## Building Rust programs -Next be sure to enable LLD when building Rust from source as LLVM's `wasm-ld` -driver for LLD is required when linking WebAssembly code together. Rust's build -system will automatically pick up any necessary binaries and programs from -`WASI_SDK_PATH`. +For more information see the documentation [`wasm32-wasip1` +target](./wasm32-wasip1.md#building-rust-programs). Replace `wasm32-wasip1` +target strings with `wasm32-wasip2`, however. ## Testing From f7649e7c4b9dd7522a50a3fbb26f76229e31d721 Mon Sep 17 00:00:00 2001 From: Asuna Date: Wed, 6 May 2026 05:45:52 +0000 Subject: [PATCH 21/21] Rename and move `downcast` to `project_downcast_named` for `InterpCx` --- .../src/const_eval/machine.rs | 4 +- .../src/const_eval/type_info.rs | 60 ++++++++----------- .../src/const_eval/type_info/adt.rs | 12 ++-- .../src/interpret/projection.rs | 17 ++++++ 4 files changed, 49 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index c7ee14b4b5dda..fefbf6adfd132 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -609,7 +609,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { let ty = ecx.read_type_id(&args[0])?; let layout = ecx.layout_of(ty)?; let variant_index = if layout.is_sized() { - let (variant, variant_place) = ecx.downcast(dest, sym::Some)?; + let (variant, variant_place) = ecx.project_downcast_named(dest, sym::Some)?; let size_field_place = ecx.project_field(&variant_place, FieldIdx::ZERO)?; ecx.write_scalar( ScalarInt::try_from_target_usize(layout.size.bytes(), ecx.tcx.tcx).unwrap(), @@ -617,7 +617,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { )?; variant } else { - ecx.downcast(dest, sym::None)?.0 + ecx.project_downcast_named(dest, sym::None)?.0 }; ecx.write_discriminant(variant_index, dest)?; } diff --git a/compiler/rustc_const_eval/src/const_eval/type_info.rs b/compiler/rustc_const_eval/src/const_eval/type_info.rs index 7a90ac8287967..3d8d9592459c4 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info.rs @@ -2,7 +2,7 @@ mod adt; use std::borrow::Cow; -use rustc_abi::{ExternAbi, FieldIdx, VariantIdx}; +use rustc_abi::{ExternAbi, FieldIdx}; use rustc_ast::Mutability; use rustc_hir::LangItem; use rustc_middle::span_bug; @@ -12,27 +12,11 @@ use rustc_span::{Symbol, sym}; use crate::const_eval::CompileTimeMachine; use crate::interpret::{ - CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Projectable, Scalar, - Writeable, interp_ok, + CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Scalar, Writeable, + interp_ok, }; impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { - /// Equivalent to `project_downcast`, but identifies the variant by name instead of index. - pub fn downcast<'a>( - &self, - place: &(impl Writeable<'tcx, CtfeProvenance> + 'a), - name: Symbol, - ) -> InterpResult<'tcx, (VariantIdx, impl Writeable<'tcx, CtfeProvenance> + 'a)> { - let variants = place.layout().ty.ty_adt_def().unwrap().variants(); - let variant_idx = variants - .iter_enumerated() - .find(|(_idx, var)| var.name == name) - .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}")) - .0; - - interp_ok((variant_idx, self.project_downcast(place, variant_idx)?)) - } - // A general method to write an array to a static slice place. fn allocate_fill_and_write_slice_ptr( &mut self, @@ -83,7 +67,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { let variant_index = match ty.kind() { ty::Tuple(fields) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Tuple)?; + self.project_downcast_named(&field_dest, sym::Tuple)?; // project to the single tuple variant field of `type_info::Tuple` struct type let tuple_place = self.project_field(&variant_place, FieldIdx::ZERO)?; assert_eq!( @@ -102,7 +86,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Array(ty, len) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Array)?; + self.project_downcast_named(&field_dest, sym::Array)?; let array_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_array_type_info(array_place, *ty, *len)?; @@ -111,7 +95,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Slice(ty) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Slice)?; + self.project_downcast_named(&field_dest, sym::Slice)?; let slice_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_slice_type_info(slice_place, *ty)?; @@ -123,16 +107,17 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Bool => { let (variant, _variant_place) = - self.downcast(&field_dest, sym::Bool)?; + self.project_downcast_named(&field_dest, sym::Bool)?; variant } ty::Char => { let (variant, _variant_place) = - self.downcast(&field_dest, sym::Char)?; + self.project_downcast_named(&field_dest, sym::Char)?; variant } ty::Int(int_ty) => { - let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?; + let (variant, variant_place) = + self.project_downcast_named(&field_dest, sym::Int)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_int_type_info( place, @@ -142,7 +127,8 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } ty::Uint(uint_ty) => { - let (variant, variant_place) = self.downcast(&field_dest, sym::Int)?; + let (variant, variant_place) = + self.project_downcast_named(&field_dest, sym::Int)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_int_type_info( place, @@ -153,18 +139,19 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Float(float_ty) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Float)?; + self.project_downcast_named(&field_dest, sym::Float)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_float_type_info(place, float_ty.bit_width())?; variant } ty::Str => { - let (variant, _variant_place) = self.downcast(&field_dest, sym::Str)?; + let (variant, _variant_place) = + self.project_downcast_named(&field_dest, sym::Str)?; variant } ty::Ref(_, ty, mutability) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Reference)?; + self.project_downcast_named(&field_dest, sym::Reference)?; let reference_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_reference_type_info(reference_place, *ty, *mutability)?; @@ -173,7 +160,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::RawPtr(ty, mutability) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::Pointer)?; + self.project_downcast_named(&field_dest, sym::Pointer)?; let pointer_place = self.project_field(&variant_place, FieldIdx::ZERO)?; @@ -183,14 +170,14 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { } ty::Dynamic(predicates, region) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::DynTrait)?; + self.project_downcast_named(&field_dest, sym::DynTrait)?; let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?; variant } ty::FnPtr(sig, fn_header) => { let (variant, variant_place) = - self.downcast(&field_dest, sym::FnPtr)?; + self.project_downcast_named(&field_dest, sym::FnPtr)?; let fn_ptr_place = self.project_field(&variant_place, FieldIdx::ZERO)?; @@ -214,7 +201,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(..) - | ty::Error(_) => self.downcast(&field_dest, sym::Other)?.0, + | ty::Error(_) => self.project_downcast_named(&field_dest, sym::Other)?.0, }; self.write_discriminant(variant_index, &field_dest)? } @@ -416,16 +403,17 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { sym::abi => match fn_sig_kind.abi() { ExternAbi::C { .. } => { let (rust_variant, _rust_place) = - self.downcast(&field_place, sym::ExternC)?; + self.project_downcast_named(&field_place, sym::ExternC)?; self.write_discriminant(rust_variant, &field_place)?; } ExternAbi::Rust => { let (rust_variant, _rust_place) = - self.downcast(&field_place, sym::ExternRust)?; + self.project_downcast_named(&field_place, sym::ExternRust)?; self.write_discriminant(rust_variant, &field_place)?; } other_abi => { - let (variant, variant_place) = self.downcast(&field_place, sym::Named)?; + let (variant, variant_place) = + self.project_downcast_named(&field_place, sym::Named)?; let str_place = self.allocate_str_dedup(other_abi.as_str())?; let str_ref = self.mplace_to_imm_ptr(&str_place, None)?; let payload = self.project_field(&variant_place, FieldIdx::ZERO)?; diff --git a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs index 2143313bbbada..9016064de8fd4 100644 --- a/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs +++ b/compiler/rustc_const_eval/src/const_eval/type_info/adt.rs @@ -22,7 +22,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { let (adt_ty, adt_def) = adt; let variant_idx = match adt_def.adt_kind() { AdtKind::Struct => { - let (variant, variant_place) = self.downcast(place, sym::Struct)?; + let (variant, variant_place) = self.project_downcast_named(place, sym::Struct)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_struct_type_info( place, @@ -32,7 +32,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } AdtKind::Union => { - let (variant, variant_place) = self.downcast(place, sym::Union)?; + let (variant, variant_place) = self.project_downcast_named(place, sym::Union)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_union_type_info( place, @@ -42,7 +42,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { variant } AdtKind::Enum => { - let (variant, variant_place) = self.downcast(place, sym::Enum)?; + let (variant, variant_place) = self.project_downcast_named(place, sym::Enum)?; let place = self.project_field(&variant_place, FieldIdx::ZERO)?; self.write_enum_type_info(place, adt, generics)?; variant @@ -219,13 +219,13 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { _region: Region<'tcx>, place: MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { - let (variant_idx, _) = self.downcast(&place, sym::Lifetime)?; + let (variant_idx, _) = self.project_downcast_named(&place, sym::Lifetime)?; self.write_discriminant(variant_idx, &place)?; interp_ok(()) } fn write_generic_type(&mut self, ty: Ty<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { - let (variant_idx, variant_place) = self.downcast(&place, sym::Type)?; + let (variant_idx, variant_place) = self.project_downcast_named(&place, sym::Type)?; let generic_type_place = self.project_field(&variant_place, FieldIdx::ZERO)?; for (field_idx, field_def) in generic_type_place @@ -251,7 +251,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> { fn write_generic_const(&mut self, c: Const<'tcx>, place: MPlaceTy<'tcx>) -> InterpResult<'tcx> { let ConstKind::Value(c) = c.kind() else { bug!("expected a computed const, got {c:?}") }; - let (variant_idx, variant_place) = self.downcast(&place, sym::Const)?; + let (variant_idx, variant_place) = self.project_downcast_named(&place, sym::Const)?; let const_place = self.project_field(&variant_place, FieldIdx::ZERO)?; for (field_idx, field_def) in const_place diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index db72c02e308c0..27f91b2b89b2c 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -14,6 +14,7 @@ use rustc_abi::{self as abi, FieldIdx, Size, VariantIdx}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, mir, span_bug, ty}; +use rustc_span::Symbol; use tracing::{debug, instrument}; use super::{ @@ -227,6 +228,22 @@ where base.offset(Size::ZERO, layout, self) } + /// Equivalent to `project_downcast`, but identifies the variant by name instead of index. + pub fn project_downcast_named>( + &self, + base: &P, + name: Symbol, + ) -> InterpResult<'tcx, (VariantIdx, P)> { + let variants = base.layout().ty.ty_adt_def().unwrap().variants(); + let variant_idx = variants + .iter_enumerated() + .find(|(_idx, var)| var.name == name) + .unwrap_or_else(|| panic!("got {name} but expected one of {variants:#?}")) + .0; + + interp_ok((variant_idx, self.project_downcast(base, variant_idx)?)) + } + /// Compute the offset and field layout for accessing the given index. pub fn project_index>( &self,