From f232e01af48be499f3caf79388b143fb7e499c80 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 26 Feb 2023 13:19:30 +0000 Subject: [PATCH 01/28] Improve docs of traversable derivation macros --- compiler/rustc_macros/src/lib.rs | 49 ++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 193dbd75fbd57..2c4f17ca68182 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -78,21 +78,52 @@ decl_derive!( [TypeFoldable, attributes(type_foldable)] => /// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported). /// - /// The fold will produce a value of the same struct or enum variant as the input, with - /// each field respectively folded using the `TypeFoldable` implementation for its type. - /// However, if a field of a struct or an enum variant is annotated with - /// `#[type_foldable(identity)]` then that field will retain its incumbent value (and its - /// type is not required to implement `TypeFoldable`). + /// Folds will produce a value of the same struct or enum variant as the input, with each field + /// respectively folded (in definition order) using the `TypeFoldable` implementation for its + /// type. However, if a field of a struct or of an enum variant is annotated with + /// `#[type_foldable(identity)]` then that field will retain its incumbent value (and its type + /// is not required to implement `TypeFoldable`). However use of this attribute is dangerous + /// and should be used with extreme caution: should the type of the annotated field contain + /// (now or in the future) a type that is of interest to a folder, it will not get folded (which + /// may result in unexpected, hard-to-track bugs that could result in unsoundness). + /// + /// If the annotated type has a `'tcx` lifetime parameter, then that will be used as the + /// lifetime for the type context/interner; otherwise the lifetime of the type context/interner + /// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of + /// the annotated type are named. For example, deriving `TypeFoldable` for both `Foo<'a>` and + /// `Bar<'tcx>` will respectively produce: + /// + /// `impl<'a, 'tcx> TypeFoldable> for Foo<'a>` + /// + /// and + /// + /// `impl<'tcx> TypeFoldable> for Bar<'tcx>` type_foldable::type_foldable_derive ); decl_derive!( [TypeVisitable, attributes(type_visitable)] => /// Derives `TypeVisitable` for the annotated `struct` or `enum` (`union` is not supported). /// - /// Each field of the struct or enum variant will be visited in definition order, using the - /// `TypeVisitable` implementation for its type. However, if a field of a struct or an enum - /// variant is annotated with `#[type_visitable(ignore)]` then that field will not be - /// visited (and its type is not required to implement `TypeVisitable`). + /// Each field of the struct or enum variant will be visited (in definition order) using the + /// `TypeVisitable` implementation for its type. However, if a field of a struct or of an enum + /// variant is annotated with `#[type_visitable(ignore)]` then that field will not be visited + /// (and its type is not required to implement `TypeVisitable`). However use of this attribute + /// is dangerous and should be used with extreme caution: should the type of the annotated + /// field (now or in the future) a type that is of interest to a visitor, it will not get + /// visited (which may result in unexpected, hard-to-track bugs that could result in + /// unsoundness). + /// + /// If the annotated type has a `'tcx` lifetime parameter, then that will be used as the + /// lifetime for the type context/interner; otherwise the lifetime of the type context/interner + /// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of + /// the annotated type are named. For example, deriving `TypeVisitable` for both `Foo<'a>` and + /// `Bar<'tcx>` will respectively produce: + /// + /// `impl<'a, 'tcx> TypeVisitable> for Foo<'a>` + /// + /// and + /// + /// `impl<'tcx> TypeVisitable> for Bar<'tcx>` type_visitable::type_visitable_derive ); decl_derive!([Lift, attributes(lift)] => lift::lift_derive); From 6c218fc7b76368ac10289d96f1e8ba4bdf9dc41a Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 26 Feb 2023 13:21:01 +0000 Subject: [PATCH 02/28] Generify traversable derivation macros --- compiler/rustc_macros/src/lib.rs | 7 +- compiler/rustc_macros/src/traversable.rs | 126 ++++++++++++++++++++ compiler/rustc_macros/src/type_foldable.rs | 56 --------- compiler/rustc_macros/src/type_visitable.rs | 52 -------- 4 files changed, 129 insertions(+), 112 deletions(-) create mode 100644 compiler/rustc_macros/src/traversable.rs delete mode 100644 compiler/rustc_macros/src/type_foldable.rs delete mode 100644 compiler/rustc_macros/src/type_visitable.rs diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 2c4f17ca68182..8fac97c0946a5 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -23,8 +23,7 @@ mod newtype; mod query; mod serialize; mod symbols; -mod type_foldable; -mod type_visitable; +mod traversable; #[proc_macro] pub fn current_rustc_version(input: TokenStream) -> TokenStream { @@ -98,7 +97,7 @@ decl_derive!( /// and /// /// `impl<'tcx> TypeFoldable> for Bar<'tcx>` - type_foldable::type_foldable_derive + traversable::traversable_derive:: ); decl_derive!( [TypeVisitable, attributes(type_visitable)] => @@ -124,7 +123,7 @@ decl_derive!( /// and /// /// `impl<'tcx> TypeVisitable> for Bar<'tcx>` - type_visitable::type_visitable_derive + traversable::traversable_derive:: ); decl_derive!([Lift, attributes(lift)] => lift::lift_derive); decl_derive!( diff --git a/compiler/rustc_macros/src/traversable.rs b/compiler/rustc_macros/src/traversable.rs new file mode 100644 index 0000000000000..bdff35a0b037d --- /dev/null +++ b/compiler/rustc_macros/src/traversable.rs @@ -0,0 +1,126 @@ +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::parse_quote; + +pub struct Foldable; +pub struct Visitable; + +/// An abstraction over traversable traits. +pub trait Traversable { + /// The trait that this `Traversable` represents. + fn traversable() -> TokenStream; + + /// The `match` arms for a traversal of this type. + fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream; + + /// The body of an implementation given the match `arms`. + fn impl_body(arms: impl ToTokens) -> TokenStream; +} + +impl Traversable for Foldable { + fn traversable() -> TokenStream { + quote! { ::rustc_middle::ty::fold::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>> } + } + fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream { + structure.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|_, index| { + let bind = &bindings[index]; + + let mut fixed = false; + + // retain value of fields with #[type_foldable(identity)] + bind.ast().attrs.iter().for_each(|x| { + if !x.path().is_ident("type_foldable") { + return; + } + let _ = x.parse_nested_meta(|nested| { + if nested.path.is_ident("identity") { + fixed = true; + } + Ok(()) + }); + }); + + if fixed { + bind.to_token_stream() + } else { + quote! { + ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)? + } + } + }) + }) + } + fn impl_body(arms: impl ToTokens) -> TokenStream { + quote! { + fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>( + self, + __folder: &mut __F + ) -> ::core::result::Result { + ::core::result::Result::Ok(match self { #arms }) + } + } + } +} + +impl Traversable for Visitable { + fn traversable() -> TokenStream { + quote! { ::rustc_middle::ty::visit::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>> } + } + fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream { + // ignore fields with #[type_visitable(ignore)] + structure.filter(|bi| { + let mut ignored = false; + + bi.ast().attrs.iter().for_each(|attr| { + if !attr.path().is_ident("type_visitable") { + return; + } + let _ = attr.parse_nested_meta(|nested| { + if nested.path.is_ident("ignore") { + ignored = true; + } + Ok(()) + }); + }); + + !ignored + }); + + structure.each(|bind| { + quote! { + ::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor)?; + } + }) + } + fn impl_body(arms: impl ToTokens) -> TokenStream { + quote! { + fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>( + &self, + __visitor: &mut __V + ) -> ::std::ops::ControlFlow<__V::BreakTy> { + match self { #arms } + ::std::ops::ControlFlow::Continue(()) + } + } + } +} + +pub fn traversable_derive( + mut structure: synstructure::Structure<'_>, +) -> TokenStream { + if let syn::Data::Union(_) = structure.ast().data { + panic!("cannot derive on union") + } + + structure.add_bounds(synstructure::AddBounds::Generics); + structure.bind_with(|_| synstructure::BindStyle::Move); + + if !structure.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { + structure.add_impl_generic(parse_quote! { 'tcx }); + } + + let arms = T::arms(&mut structure); + structure.bound_impl(T::traversable(), T::impl_body(arms)) +} diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs deleted file mode 100644 index 5ee4d8793135c..0000000000000 --- a/compiler/rustc_macros/src/type_foldable.rs +++ /dev/null @@ -1,56 +0,0 @@ -use quote::{quote, ToTokens}; -use syn::parse_quote; - -pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { - if let syn::Data::Union(_) = s.ast().data { - panic!("cannot derive on union") - } - - if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { - s.add_impl_generic(parse_quote! { 'tcx }); - } - - s.add_bounds(synstructure::AddBounds::Generics); - s.bind_with(|_| synstructure::BindStyle::Move); - let body_fold = s.each_variant(|vi| { - let bindings = vi.bindings(); - vi.construct(|_, index| { - let bind = &bindings[index]; - - let mut fixed = false; - - // retain value of fields with #[type_foldable(identity)] - bind.ast().attrs.iter().for_each(|x| { - if !x.path().is_ident("type_foldable") { - return; - } - let _ = x.parse_nested_meta(|nested| { - if nested.path.is_ident("identity") { - fixed = true; - } - Ok(()) - }); - }); - - if fixed { - bind.to_token_stream() - } else { - quote! { - ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)? - } - } - }) - }); - - s.bound_impl( - quote!(::rustc_middle::ty::fold::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>), - quote! { - fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>( - self, - __folder: &mut __F - ) -> Result { - Ok(match self { #body_fold }) - } - }, - ) -} diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs deleted file mode 100644 index dcd505a105e57..0000000000000 --- a/compiler/rustc_macros/src/type_visitable.rs +++ /dev/null @@ -1,52 +0,0 @@ -use quote::quote; -use syn::parse_quote; - -pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { - if let syn::Data::Union(_) = s.ast().data { - panic!("cannot derive on union") - } - - // ignore fields with #[type_visitable(ignore)] - s.filter(|bi| { - let mut ignored = false; - - bi.ast().attrs.iter().for_each(|attr| { - if !attr.path().is_ident("type_visitable") { - return; - } - let _ = attr.parse_nested_meta(|nested| { - if nested.path.is_ident("ignore") { - ignored = true; - } - Ok(()) - }); - }); - - !ignored - }); - - if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { - s.add_impl_generic(parse_quote! { 'tcx }); - } - - s.add_bounds(synstructure::AddBounds::Generics); - let body_visit = s.each(|bind| { - quote! { - ::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor)?; - } - }); - s.bind_with(|_| synstructure::BindStyle::Move); - - s.bound_impl( - quote!(::rustc_middle::ty::visit::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>), - quote! { - fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>( - &self, - __visitor: &mut __V - ) -> ::std::ops::ControlFlow<__V::BreakTy> { - match *self { #body_visit } - ::std::ops::ControlFlow::Continue(()) - } - }, - ) -} From 7e79b4cd1ff7c447c2b22c37b2cef2b643aeb6a2 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sat, 25 Feb 2023 13:44:15 +0000 Subject: [PATCH 03/28] Automatically skip traversal of trivial fields [Auto-deref specialisation] is introduced to type library traversals, the public API of which is via the `TriviallyTraverses` trait and the `noop_if_trivially_traversable` macro. Traversals invoked via the macro will then be no-ops if the interner "trivially traverses" the type being traversed *without requiring that type to implement the relevant traversable trait*. A further trait, `rustc_middle::ty::TriviallyTraversable`, is then auto-implemented for types that do not contain anything that may be of interest to traversers. A generic implementation of the former trait is then provided for the `TyCtxt` interner to indicate that it "trivially traverses" all such `TriviallyTraversable` types. This indirection is necessary because auto-traits are unstable, whereas the type library is intended to be stabilised. Finally, the traversable derive macros are updated to utilise this specialisation machinery, thereby avoiding any need for trivially traversable fields (of types for which the traits are derived) to implement the traversable traits. [Auto-deref specialisation]: http://lukaskalbertodt.github.io/2019/12/05/generalized-autoref-based-specialization.html --- compiler/rustc_macros/Cargo.toml | 3 + compiler/rustc_macros/src/lib.rs | 34 +- compiler/rustc_macros/src/traversable.rs | 297 ++++++++++++------ .../rustc_macros/src/traversable/tests.rs | 145 +++++++++ compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/mir/query.rs | 2 - compiler/rustc_middle/src/thir.rs | 3 - compiler/rustc_middle/src/ty/context.rs | 18 +- compiler/rustc_middle/src/ty/fold.rs | 5 +- compiler/rustc_middle/src/ty/list.rs | 8 + compiler/rustc_middle/src/ty/mod.rs | 3 +- compiler/rustc_middle/src/ty/visit.rs | 5 +- compiler/rustc_type_ir/src/fold.rs | 41 ++- compiler/rustc_type_ir/src/interner.rs | 19 ++ compiler/rustc_type_ir/src/macros.rs | 29 ++ compiler/rustc_type_ir/src/visit.rs | 37 ++- 16 files changed, 532 insertions(+), 118 deletions(-) create mode 100644 compiler/rustc_macros/src/traversable/tests.rs diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index d8d2bef496404..aeea5cd6e7159 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -13,3 +13,6 @@ quote = "1" syn = { version = "2.0.9", features = ["full"] } synstructure = "0.13.0" # tidy-alphabetical-end + +[dev-dependencies] +syn = { version = "*", features = ["visit-mut"] } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 8fac97c0946a5..235ef44ab4da8 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -74,18 +74,16 @@ decl_derive!([TyEncodable] => serialize::type_encodable_derive); decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive); decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive); decl_derive!( - [TypeFoldable, attributes(type_foldable)] => + [TypeFoldable] => /// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported). /// - /// Folds will produce a value of the same struct or enum variant as the input, with each field - /// respectively folded (in definition order) using the `TypeFoldable` implementation for its - /// type. However, if a field of a struct or of an enum variant is annotated with - /// `#[type_foldable(identity)]` then that field will retain its incumbent value (and its type - /// is not required to implement `TypeFoldable`). However use of this attribute is dangerous - /// and should be used with extreme caution: should the type of the annotated field contain - /// (now or in the future) a type that is of interest to a folder, it will not get folded (which - /// may result in unexpected, hard-to-track bugs that could result in unsoundness). - /// + /// Folds will produce a value of the same struct or enum variant as the input, with trivial + /// fields unchanged and all non-trivial fields respectively folded (in definition order) using + /// the `TypeFoldable` implementation for its type. A field of type `T` is "trivial" if `T` + /// both does not reference any generic type parameters and either + /// - does not reference any `'tcx` lifetime parameter; or + /// - does not contain anything that could be of interest to folders. + /// /// If the annotated type has a `'tcx` lifetime parameter, then that will be used as the /// lifetime for the type context/interner; otherwise the lifetime of the type context/interner /// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of @@ -100,17 +98,15 @@ decl_derive!( traversable::traversable_derive:: ); decl_derive!( - [TypeVisitable, attributes(type_visitable)] => + [TypeVisitable] => /// Derives `TypeVisitable` for the annotated `struct` or `enum` (`union` is not supported). /// - /// Each field of the struct or enum variant will be visited (in definition order) using the - /// `TypeVisitable` implementation for its type. However, if a field of a struct or of an enum - /// variant is annotated with `#[type_visitable(ignore)]` then that field will not be visited - /// (and its type is not required to implement `TypeVisitable`). However use of this attribute - /// is dangerous and should be used with extreme caution: should the type of the annotated - /// field (now or in the future) a type that is of interest to a visitor, it will not get - /// visited (which may result in unexpected, hard-to-track bugs that could result in - /// unsoundness). + /// Each non-trivial field of the struct or enum variant will be visited (in definition order) + /// using the `TypeVisitable` implementation for its type; trivial fields will be ignored. A + /// field of type `T` is "trivial" if `T` both does not reference any generic type parameters + /// and either + /// - does not reference any `'tcx` lifetime parameter; or + /// - does not contain anything that could be of interest to visitors. /// /// If the annotated type has a `'tcx` lifetime parameter, then that will be used as the /// lifetime for the type context/interner; otherwise the lifetime of the type context/interner diff --git a/compiler/rustc_macros/src/traversable.rs b/compiler/rustc_macros/src/traversable.rs index bdff35a0b037d..a77e3b3e19d9f 100644 --- a/compiler/rustc_macros/src/traversable.rs +++ b/compiler/rustc_macros/src/traversable.rs @@ -1,126 +1,247 @@ -use proc_macro2::TokenStream; +use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, ToTokens}; -use syn::parse_quote; +use std::collections::HashSet; +use syn::{parse_quote, visit, Field, Generics, Lifetime}; + +#[cfg(test)] +mod tests; + +/// Generate a type parameter with the given `suffix` that does not conflict with +/// any of the `existing` generics. +fn gen_param(suffix: impl ToString, existing: &Generics) -> Ident { + let mut suffix = suffix.to_string(); + while existing.type_params().any(|t| t.ident == suffix) { + suffix.insert(0, '_'); + } + Ident::new(&suffix, Span::call_site()) +} + +#[derive(Clone, Copy, PartialEq)] +enum Type { + /// Describes a type that is not parameterised by the interner, and therefore cannot + /// be of any interest to traversers. + Trivial, + + /// Describes a type that is parameterised by the interner lifetime `'tcx` but that is + /// otherwise not generic. + NotGeneric, + + /// Describes a type that is generic. + Generic, +} +use Type::*; + +pub struct Interner<'a>(Option<&'a Lifetime>); + +impl<'a> Interner<'a> { + /// Return the `TyCtxt` interner for the given `structure`. + /// + /// If the input represented by `structure` has a `'tcx` lifetime parameter, then that will be used + /// used as the lifetime of the `TyCtxt`. Otherwise a `'tcx` lifetime parameter that is unrelated + /// to the input will be used. + fn resolve(generics: &'a Generics) -> Self { + Self( + generics + .lifetimes() + .find_map(|def| (def.lifetime.ident == "tcx").then_some(&def.lifetime)), + ) + } +} + +impl ToTokens for Interner<'_> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let default = parse_quote! { 'tcx }; + let lt = self.0.unwrap_or(&default); + tokens.extend(quote! { ::rustc_middle::ty::TyCtxt<#lt> }); + } +} pub struct Foldable; pub struct Visitable; /// An abstraction over traversable traits. pub trait Traversable { - /// The trait that this `Traversable` represents. - fn traversable() -> TokenStream; - - /// The `match` arms for a traversal of this type. - fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream; - - /// The body of an implementation given the match `arms`. - fn impl_body(arms: impl ToTokens) -> TokenStream; + /// The trait that this `Traversable` represents, parameterised by `interner`. + fn traversable(interner: &Interner<'_>) -> TokenStream; + + /// Any supertraits that this trait is required to implement. + fn supertraits(interner: &Interner<'_>) -> TokenStream; + + /// A (`noop`) traversal of this trait upon the `bind` expression. + fn traverse(bind: TokenStream, noop: bool, interner: &Interner<'_>) -> TokenStream; + + /// A `match` arm for `variant`, where `f` generates the tokens for each binding. + fn arm( + variant: &synstructure::VariantInfo<'_>, + f: impl FnMut(&synstructure::BindingInfo<'_>) -> TokenStream, + ) -> TokenStream; + + /// The body of an implementation given the `interner`, `traverser` and match expression `body`. + fn impl_body( + interner: Interner<'_>, + traverser: impl ToTokens, + body: impl ToTokens, + ) -> TokenStream; } impl Traversable for Foldable { - fn traversable() -> TokenStream { - quote! { ::rustc_middle::ty::fold::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>> } - } - fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream { - structure.each_variant(|vi| { - let bindings = vi.bindings(); - vi.construct(|_, index| { - let bind = &bindings[index]; - - let mut fixed = false; - - // retain value of fields with #[type_foldable(identity)] - bind.ast().attrs.iter().for_each(|x| { - if !x.path().is_ident("type_foldable") { - return; - } - let _ = x.parse_nested_meta(|nested| { - if nested.path.is_ident("identity") { - fixed = true; - } - Ok(()) - }); - }); - - if fixed { - bind.to_token_stream() - } else { - quote! { - ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)? - } - } - }) - }) + fn traversable(interner: &Interner<'_>) -> TokenStream { + quote! { ::rustc_middle::ty::fold::TypeFoldable<#interner> } + } + fn supertraits(interner: &Interner<'_>) -> TokenStream { + Visitable::traversable(interner) } - fn impl_body(arms: impl ToTokens) -> TokenStream { + fn traverse(bind: TokenStream, noop: bool, interner: &Interner<'_>) -> TokenStream { + if noop { + bind + } else { + quote! { ::rustc_middle::ty::noop_if_trivially_traversable!(#bind.try_fold_with::<#interner>(folder))? } + } + } + fn arm( + variant: &synstructure::VariantInfo<'_>, + mut f: impl FnMut(&synstructure::BindingInfo<'_>) -> TokenStream, + ) -> TokenStream { + let bindings = variant.bindings(); + variant.construct(|_, index| f(&bindings[index])) + } + fn impl_body( + interner: Interner<'_>, + traverser: impl ToTokens, + body: impl ToTokens, + ) -> TokenStream { quote! { - fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>( + fn try_fold_with<#traverser: ::rustc_middle::ty::fold::FallibleTypeFolder<#interner>>( self, - __folder: &mut __F - ) -> ::core::result::Result { - ::core::result::Result::Ok(match self { #arms }) + folder: &mut #traverser + ) -> ::core::result::Result { + ::core::result::Result::Ok(#body) } } } } impl Traversable for Visitable { - fn traversable() -> TokenStream { - quote! { ::rustc_middle::ty::visit::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>> } + fn traversable(interner: &Interner<'_>) -> TokenStream { + quote! { ::rustc_middle::ty::visit::TypeVisitable<#interner> } } - fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream { - // ignore fields with #[type_visitable(ignore)] - structure.filter(|bi| { - let mut ignored = false; - - bi.ast().attrs.iter().for_each(|attr| { - if !attr.path().is_ident("type_visitable") { - return; - } - let _ = attr.parse_nested_meta(|nested| { - if nested.path.is_ident("ignore") { - ignored = true; - } - Ok(()) - }); - }); - - !ignored - }); - - structure.each(|bind| { - quote! { - ::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor)?; - } - }) + fn supertraits(_: &Interner<'_>) -> TokenStream { + quote! { ::core::clone::Clone + ::core::fmt::Debug } + } + fn traverse(bind: TokenStream, noop: bool, interner: &Interner<'_>) -> TokenStream { + if noop { + quote! {} + } else { + quote! { ::rustc_middle::ty::noop_if_trivially_traversable!(#bind.visit_with::<#interner>(visitor))?; } + } } - fn impl_body(arms: impl ToTokens) -> TokenStream { + fn arm( + variant: &synstructure::VariantInfo<'_>, + f: impl FnMut(&synstructure::BindingInfo<'_>) -> TokenStream, + ) -> TokenStream { + variant.bindings().iter().map(f).collect() + } + fn impl_body( + interner: Interner<'_>, + traverser: impl ToTokens, + body: impl ToTokens, + ) -> TokenStream { quote! { - fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>( + fn visit_with<#traverser: ::rustc_middle::ty::visit::TypeVisitor<#interner>>( &self, - __visitor: &mut __V - ) -> ::std::ops::ControlFlow<__V::BreakTy> { - match self { #arms } - ::std::ops::ControlFlow::Continue(()) + visitor: &mut #traverser + ) -> ::core::ops::ControlFlow<#traverser::BreakTy> { + #body + ::core::ops::ControlFlow::Continue(()) } } } } +impl Interner<'_> { + /// We consider a type to be internable if it references either a generic type parameter or, + /// if the interner is `TyCtxt<'tcx>`, the `'tcx` lifetime. + fn type_of<'a>( + &self, + referenced_ty_params: &[&Ident], + fields: impl IntoIterator, + ) -> Type { + use visit::Visit; + + struct Info<'a> { + interner: &'a Lifetime, + contains_interner: bool, + } + + impl Visit<'_> for Info<'_> { + fn visit_lifetime(&mut self, i: &Lifetime) { + if i == self.interner { + self.contains_interner = true; + } else { + visit::visit_lifetime(self, i) + } + } + } + + if !referenced_ty_params.is_empty() { + Generic + } else if let Some(interner) = &self.0 && fields.into_iter().any(|field| { + let mut info = Info { interner, contains_interner: false }; + info.visit_type(&field.ty); + info.contains_interner + }) { + NotGeneric + } else { + Trivial + } + } +} + pub fn traversable_derive( mut structure: synstructure::Structure<'_>, ) -> TokenStream { - if let syn::Data::Union(_) = structure.ast().data { - panic!("cannot derive on union") - } + let ast = structure.ast(); + + let interner = Interner::resolve(&ast.generics); + let traverser = gen_param("T", &ast.generics); + let traversable = T::traversable(&interner); - structure.add_bounds(synstructure::AddBounds::Generics); + structure.underscore_const(true); + structure.add_bounds(synstructure::AddBounds::None); structure.bind_with(|_| synstructure::BindStyle::Move); - if !structure.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { + if interner.0.is_none() { structure.add_impl_generic(parse_quote! { 'tcx }); } - let arms = T::arms(&mut structure); - structure.bound_impl(T::traversable(), T::impl_body(arms)) + // If our derived implementation will be generic over the traversable type, then we must + // constrain it to only those generic combinations that satisfy the traversable trait's + // supertraits. + if ast.generics.type_params().next().is_some() { + let supertraits = T::supertraits(&interner); + structure.add_where_predicate(parse_quote! { Self: #supertraits }); + } + + // We add predicates to each generic field type, rather than to our generic type parameters. + // This results in a "perfect derive", but it can result in trait solver cycles if any type + // parameters are involved in recursive type definitions; fortunately that is not the case (yet). + let mut predicates = HashSet::new(); + let arms = structure.each_variant(|variant| { + T::arm(variant, |bind| { + let ast = bind.ast(); + let field_ty = interner.type_of(&bind.referenced_ty_params(), [ast]); + if field_ty == Generic { + predicates.insert(ast.ty.clone()); + } + T::traverse(bind.into_token_stream(), field_ty == Trivial, &interner) + }) + }); + // the order in which `where` predicates appear in rust source is irrelevant + #[allow(rustc::potential_query_instability)] + for ty in predicates { + structure.add_where_predicate(parse_quote! { #ty: #traversable }); + } + let body = quote! { match self { #arms } }; + + structure.bound_impl(traversable, T::impl_body(interner, traverser, body)) } diff --git a/compiler/rustc_macros/src/traversable/tests.rs b/compiler/rustc_macros/src/traversable/tests.rs new file mode 100644 index 0000000000000..f2f0a4b71cb8b --- /dev/null +++ b/compiler/rustc_macros/src/traversable/tests.rs @@ -0,0 +1,145 @@ +use super::{parse_quote, traversable_derive, Foldable, ToTokens}; +use syn::visit_mut::VisitMut; + +/// A folder that normalizes syn types for comparison in tests. +struct Normalizer; + +/// Generates a folding method for [`Normalizer`] that ensures certain collections +/// are sorted consistently, thus eliminating any non-deterministic output. +macro_rules! normalizing_sort { + ($($method:ident($field:ident in $ty:ty);)*) => {$( + fn $method(&mut self, i: &mut $ty) { + syn::visit_mut::$method(self, i); + let mut vec = std::mem::take(&mut i.$field).into_iter().collect::>(); + vec.sort_unstable_by_key(|x| x.to_token_stream().to_string()); + i.$field = vec.into_iter().collect(); + } + )*}; + } + +impl VisitMut for Normalizer { + // Each of the following fields in the following types can be reordered without + // affecting semantics, and therefore need to be normalized. + normalizing_sort! { + visit_where_clause_mut(predicates in syn::WhereClause); + visit_predicate_lifetime_mut(bounds in syn::PredicateLifetime); + visit_bound_lifetimes_mut(lifetimes in syn::BoundLifetimes); + visit_lifetime_param_mut(bounds in syn::LifetimeParam); + visit_type_param_mut(bounds in syn::TypeParam); + visit_type_impl_trait_mut(bounds in syn::TypeImplTrait); + visit_type_trait_object_mut(bounds in syn::TypeTraitObject); + visit_generics_mut(params in syn::Generics); + } + + fn visit_macro_mut(&mut self, i: &mut syn::Macro) { + syn::visit_mut::visit_macro_mut(self, i); + if i.path.is_ident("noop_if_trivially_traversable") { + let mut expr = i + .parse_body() + .expect("body of `noop_if_trivially_traversable` macro should be an expression"); + self.visit_expr_mut(&mut expr); + i.tokens = expr.into_token_stream(); + } + } + + // For convenience, we also simplify paths by removing absolute crate/module + // references. + fn visit_path_mut(&mut self, i: &mut syn::Path) { + syn::visit_mut::visit_path_mut(self, i); + + let n = if i.leading_colon.is_some() && i.segments.len() >= 2 { + let segment = &i.segments[0]; + if *segment == parse_quote! { rustc_middle } { + if i.segments.len() >= 3 && i.segments[1] == parse_quote! { ty } { + let segment = &i.segments[2]; + if *segment == parse_quote! { fold } || *segment == parse_quote! { visit } { + 3 + } else { + 2 + } + } else { + 1 + } + } else if *segment == parse_quote! { core } { + let segment = &i.segments[1]; + if *segment == parse_quote! { ops } { + 2 + } else if *segment == parse_quote! { result } { + i.segments.len() - 1 + } else { + return; + } + } else { + return; + } + } else { + return; + }; + + *i = syn::Path { + leading_colon: None, + segments: std::mem::take(&mut i.segments).into_iter().skip(n).collect(), + }; + } +} + +#[test] +fn interesting_fields_are_constrained() { + let input = parse_quote! { + struct SomethingInteresting<'a, 'tcx, T>( + T, + T::Assoc, + Const<'tcx>, + Complex<'tcx, T>, + Generic, + Trivial, + TrivialGeneric<'a, Foo>, + ); + }; + + let expected = parse_quote! { + impl<'a, 'tcx, T> TypeFoldable> for SomethingInteresting<'a, 'tcx, T> + where + Complex<'tcx, T>: TypeFoldable>, + Generic: TypeFoldable>, + Self: TypeVisitable>, + T: TypeFoldable>, + T::Assoc: TypeFoldable> + { + fn try_fold_with<_T: FallibleTypeFolder>>(self, folder: &mut _T) -> Result { + Ok(match self { + SomethingInteresting (__binding_0, __binding_1, __binding_2, __binding_3, __binding_4, __binding_5, __binding_6,) => { SomethingInteresting( + noop_if_trivially_traversable!(__binding_0.try_fold_with::< TyCtxt<'tcx> >(folder))?, + noop_if_trivially_traversable!(__binding_1.try_fold_with::< TyCtxt<'tcx> >(folder))?, + noop_if_trivially_traversable!(__binding_2.try_fold_with::< TyCtxt<'tcx> >(folder))?, + noop_if_trivially_traversable!(__binding_3.try_fold_with::< TyCtxt<'tcx> >(folder))?, + noop_if_trivially_traversable!(__binding_4.try_fold_with::< TyCtxt<'tcx> >(folder))?, + __binding_5, + __binding_6, + )} + }) + } + } + }; + + let result = syn::parse2::(traversable_derive::( + synstructure::Structure::new(&input), + )) + .expect("expected compiled code to parse"); + let syn::Expr::Block(syn::ExprBlock { block: syn::Block { stmts, .. }, .. }) = *result.expr + else { + panic!("expected const expr to be a block") + }; + assert_eq!(stmts.len(), 1, "expected const expr to contain a single statement"); + let syn::Stmt::Item(syn::Item::Impl(mut actual)) = stmts.into_iter().next().unwrap() else { + panic!("expected statement in const expr to be an impl") + }; + Normalizer.visit_item_impl_mut(&mut actual); + + assert!( + actual == expected, + "EXPECTED: {}\nACTUAL: {}", + expected.to_token_stream(), + actual.to_token_stream() + ); +} diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 448a3029ae97a..25a102f9bb162 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -64,6 +64,7 @@ #![feature(trait_alias)] #![feature(ptr_alignment_type)] #![feature(macro_metavar_expr)] +#![feature(auto_traits)] #![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] #![allow(internal_features)] diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 0540eb0efd6c9..7fd9a7d1c5396 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -165,8 +165,6 @@ pub struct CoroutineLayout<'tcx> { /// Which saved locals are storage-live at the same time. Locals that do not /// have conflicts with each other are allowed to overlap in the computed /// layout. - #[type_foldable(identity)] - #[type_visitable(ignore)] pub storage_conflicts: BitMatrix, } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3086082fe8d57..334be29596129 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -721,9 +721,7 @@ pub enum PatKind<'tcx> { Binding { mutability: Mutability, name: Symbol, - #[type_visitable(ignore)] mode: BindingMode, - #[type_visitable(ignore)] var: LocalVarId, ty: Ty<'tcx>, subpattern: Option>>, @@ -818,7 +816,6 @@ pub enum PatKind<'tcx> { pub struct PatRange<'tcx> { pub lo: PatRangeBoundary<'tcx>, pub hi: PatRangeBoundary<'tcx>, - #[type_visitable(ignore)] pub end: RangeEnd, pub ty: Ty<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 551c4a15dd0d9..80f907c54dba6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -67,7 +67,7 @@ use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx} use rustc_target::spec::abi; use rustc_type_ir::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; -use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; +use rustc_type_ir::{CollectAndApply, Interner, TriviallyTraverses, TypeFlags}; use std::any::Any; use std::borrow::Borrow; @@ -135,6 +135,22 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } } +/// Marker trait for types that do not need to be traversed by folders or visitors, +/// because they do not contain anything that could be of interest. +/// +/// Manually implementing this trait is DANGEROUS and should NEVER be done, as it +/// can lead to miscompilation. Even if the type for which you wish to implement +/// this trait does not today contain anything of interest to folders or visitors, +/// a field added or changed in future may cause breakage. +pub auto trait TriviallyTraversable {} +impl TriviallyTraverses for TyCtxt<'_> {} + +impl !TriviallyTraversable for Binder<'_, T> {} +impl !TriviallyTraversable for Ty<'_> {} +impl !TriviallyTraversable for ty::Const<'_> {} +impl !TriviallyTraversable for Region<'_> {} +impl !TriviallyTraversable for Predicate<'_> {} + type InternedSet<'tcx, T> = ShardedHashMap, ()>; pub struct CtxtInterners<'tcx> { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 00529a1e066cc..af558ef3c53eb 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -4,7 +4,10 @@ use rustc_hir::def_id::DefId; use std::collections::BTreeMap; -pub use rustc_type_ir::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; +pub use rustc_type_ir::{ + fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}, + Interner, +}; /////////////////////////////////////////////////////////////////////////// // Some sample folders diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 4f9c9d85763a2..28d4a2dc5bd52 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -45,6 +45,14 @@ extern "C" { type OpaqueListContents; } +// Auto-traits are not automatically implemented for extern types[1], so +// we manually implement it here to ensure that `List`s are automatically +// skipped when appropriate (the `data` field will still ensure the auto +// trait is not implemented for the `List` when it is not appropriate). +// +// [1]: https://github.com/rust-lang/rust/issues/43467#issuecomment-1207257995 +impl super::TriviallyTraversable for OpaqueListContents {} + impl List { /// Returns a reference to the (unique, static) empty list. #[inline(always)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e1c616ba0785d..b177b513d0fc3 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -88,7 +88,8 @@ pub use self::consts::{ Const, ConstData, ConstInt, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ - tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, + tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TriviallyTraversable, + TyCtxt, TyCtxtFeed, }; pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams}; pub use self::list::List; diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 8fc5c03027784..90711b4352965 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -5,7 +5,10 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use std::ops::ControlFlow; -pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; +pub use rustc_type_ir::{ + visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, + Interner, +}; pub trait TypeVisitableExt<'tcx>: TypeVisitable> { /// Returns `true` if `self` has any late-bound regions that are either diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index fc56400df1614..24eb19a8c1bd3 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -47,9 +47,10 @@ use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; +use std::marker::PhantomData; use std::mem; -use crate::{visit::TypeVisitable, Interner}; +use crate::{visit::TypeVisitable, Interner, TriviallyTraverses}; /// This trait is implemented for every type that can be folded, /// providing the skeleton of the traversal. @@ -248,6 +249,44 @@ where } } +pub trait SpecTypeFoldable { + type Interner: Interner; + type Item; + fn spec_try_fold_with>( + self, + value: Self::Item, + folder: &mut F, + ) -> Result; +} + +impl> SpecTypeFoldable for PhantomData<(I, T)> { + type Interner = I; + type Item = T; + + #[inline(always)] + fn spec_try_fold_with>( + self, + value: T, + folder: &mut F, + ) -> Result { + value.try_fold_with(folder) + } +} + +impl, T> SpecTypeFoldable for &PhantomData<(I, T)> { + type Interner = I; + type Item = T; + + #[inline(always)] + fn spec_try_fold_with>( + self, + value: T, + _: &mut F, + ) -> Result { + Ok(value) + } +} + /////////////////////////////////////////////////////////////////////////// // Traversal implementations. diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7f75e5b35a204..05140a38cc6a5 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -66,6 +66,25 @@ pub trait Interner: Sized { fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability); } +/// Marker to signify that the interner type `Self` trivially traverses type `T`, +/// which is to say that traversing (folding or visiting) values of type `T` is +/// *guaranteed* to be a no-op because `T` does not contain anything that could be +/// of interest to a traverser (folder or visitor). Per the traverser traits' +/// methods, traversers are only capable of taking an interest in the following +/// five types: +/// +/// * Self::Binder for any type B +/// * Self::Ty +/// * Self::Region +/// * Self::Const +/// * Self::Predicate +// +// If and when implementations of the super-traverser traits are uplifted to +// this library, the `B` above will likely be restricted to types of interest. +// For now, that is an implementation detail of `rustc_middle` and is therefore +// omitted from this library's documentation. +pub trait TriviallyTraverses: Interner {} + /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` /// that produces `T` items. You could combine them with /// `f(&iter.collect::>())`, but this requires allocating memory for the diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index cfed84a35c671..ae36d5b6c58c1 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -52,3 +52,32 @@ TrivialTypeTraversalImpls! { crate::AliasRelationDirection, crate::UniverseIndex, } + +#[macro_export] +macro_rules! noop_if_trivially_traversable { + ($val:tt.try_fold_with::<$interner:ty>($folder:expr)) => {{ + use $crate::fold::SpecTypeFoldable as _; + $crate::noop_if_trivially_traversable!($val.spec_try_fold_with::<$interner>($folder)) + }}; + ($val:tt.visit_with::<$interner:ty>($visitor:expr)) => {{ + use $crate::visit::SpecTypeVisitable as _; + $crate::noop_if_trivially_traversable!($val.spec_visit_with::<$interner>($visitor)) + }}; + ($val:tt.$method:ident::<$interner:ty>($traverser:expr)) => {{ + let val = $val; + + #[allow(unreachable_code)] + let p = 'p: { + use ::core::marker::PhantomData; + + fn unreachable_phantom_constraint(_: T) -> PhantomData<(I, T)> { + unreachable!() + } + + break 'p PhantomData; + unreachable_phantom_constraint::<$interner, _>(val) + }; + + (&&p).$method(val, $traverser) + }}; +} diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 9c7b8156b0437..f4feb2e687e91 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -44,9 +44,10 @@ use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; use std::fmt; +use std::marker::PhantomData; use std::ops::ControlFlow; -use crate::Interner; +use crate::{Interner, TriviallyTraverses}; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. @@ -120,6 +121,40 @@ pub trait TypeVisitor: Sized { } } +pub trait SpecTypeVisitable { + type Interner: Interner; + type Item: ?Sized; + fn spec_visit_with>( + self, + value: &Self::Item, + visitor: &mut V, + ) -> ControlFlow; +} + +impl> SpecTypeVisitable for PhantomData<(I, &T)> { + type Interner = I; + type Item = T; + + #[inline(always)] + fn spec_visit_with>( + self, + value: &T, + visitor: &mut V, + ) -> ControlFlow { + value.visit_with(visitor) + } +} + +impl, T: ?Sized> SpecTypeVisitable for &PhantomData<(I, &T)> { + type Interner = I; + type Item = T; + + #[inline(always)] + fn spec_visit_with>(self, _: &T, _: &mut V) -> ControlFlow { + ControlFlow::Continue(()) + } +} + /////////////////////////////////////////////////////////////////////////// // Traversal implementations. From 15326d2617bb591a011e8e0818780f11da703699 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 26 Feb 2023 00:40:02 +0000 Subject: [PATCH 04/28] Use specialisation in explicit traversable impls --- compiler/rustc_middle/src/ty/mod.rs | 15 +++- .../rustc_middle/src/ty/structural_impls.rs | 73 +++++++++++++------ 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b177b513d0fc3..1ef71eebaf60b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1583,16 +1583,23 @@ impl<'tcx> TypeFoldable> for ParamEnv<'tcx> { folder: &mut F, ) -> Result { Ok(ParamEnv::new( - self.caller_bounds().try_fold_with(folder)?, - self.reveal().try_fold_with(folder)?, + noop_if_trivially_traversable!( + { self.caller_bounds() }.try_fold_with::>(folder) + )?, + noop_if_trivially_traversable!( + { self.reveal() }.try_fold_with::>(folder) + )?, )) } } impl<'tcx> TypeVisitable> for ParamEnv<'tcx> { fn visit_with>>(&self, visitor: &mut V) -> ControlFlow { - self.caller_bounds().visit_with(visitor)?; - self.reveal().visit_with(visitor) + noop_if_trivially_traversable!( + { &self.caller_bounds() }.visit_with::>(visitor) + )?; + noop_if_trivially_traversable!({ &self.reveal() }.visit_with::>(visitor))?; + ControlFlow::Continue(()) } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 6af68bc5dbabb..75721d6abf2cc 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,7 +7,9 @@ use crate::mir::interpret; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; +use crate::ty::{ + self, noop_if_trivially_traversable, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt, +}; use rustc_hir::def::Namespace; use rustc_target::abi::TyAndLayout; use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx}; @@ -770,16 +772,31 @@ impl<'tcx> TypeSuperFoldable> for ty::Const<'tcx> { ) -> Result { let ty = self.ty().try_fold_with(folder)?; let kind = match self.kind() { - ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?), - ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?), - ConstKind::Bound(d, b) => { - ConstKind::Bound(d.try_fold_with(folder)?, b.try_fold_with(folder)?) - } - ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?), - ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), - ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), - ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), - ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), + ConstKind::Param(p) => ConstKind::Param(noop_if_trivially_traversable!( + p.try_fold_with::>(folder) + )?), + ConstKind::Infer(i) => ConstKind::Infer(noop_if_trivially_traversable!( + i.try_fold_with::>(folder) + )?), + ConstKind::Bound(d, b) => ConstKind::Bound( + noop_if_trivially_traversable!(d.try_fold_with::>(folder))?, + noop_if_trivially_traversable!(b.try_fold_with::>(folder))?, + ), + ConstKind::Placeholder(p) => ConstKind::Placeholder(noop_if_trivially_traversable!( + p.try_fold_with::>(folder) + )?), + ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(noop_if_trivially_traversable!( + uv.try_fold_with::>(folder) + )?), + ConstKind::Value(v) => ConstKind::Value(noop_if_trivially_traversable!( + v.try_fold_with::>(folder) + )?), + ConstKind::Error(e) => ConstKind::Error(noop_if_trivially_traversable!( + e.try_fold_with::>(folder) + )?), + ConstKind::Expr(e) => ConstKind::Expr(noop_if_trivially_traversable!( + e.try_fold_with::>(folder) + )?), }; if ty != self.ty() || kind != self.kind() { Ok(folder.interner().mk_ct_from_kind(kind, ty)) @@ -795,18 +812,32 @@ impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { visitor: &mut V, ) -> ControlFlow { self.ty().visit_with(visitor)?; - match self.kind() { - ConstKind::Param(p) => p.visit_with(visitor), - ConstKind::Infer(i) => i.visit_with(visitor), + match &self.kind() { + ConstKind::Param(p) => { + noop_if_trivially_traversable!(p.visit_with::>(visitor)) + } + ConstKind::Infer(i) => { + noop_if_trivially_traversable!(i.visit_with::>(visitor)) + } ConstKind::Bound(d, b) => { - d.visit_with(visitor)?; - b.visit_with(visitor) + noop_if_trivially_traversable!(d.visit_with::>(visitor))?; + noop_if_trivially_traversable!(b.visit_with::>(visitor)) + } + ConstKind::Placeholder(p) => { + noop_if_trivially_traversable!(p.visit_with::>(visitor)) + } + ConstKind::Unevaluated(uv) => { + noop_if_trivially_traversable!(uv.visit_with::>(visitor)) + } + ConstKind::Value(v) => { + noop_if_trivially_traversable!(v.visit_with::>(visitor)) + } + ConstKind::Error(e) => { + noop_if_trivially_traversable!(e.visit_with::>(visitor)) + } + ConstKind::Expr(e) => { + noop_if_trivially_traversable!(e.visit_with::>(visitor)) } - ConstKind::Placeholder(p) => p.visit_with(visitor), - ConstKind::Unevaluated(uv) => uv.visit_with(visitor), - ConstKind::Value(v) => v.visit_with(visitor), - ConstKind::Error(e) => e.visit_with(visitor), - ConstKind::Expr(e) => e.visit_with(visitor), } } } From 3020cbd21b515a9c7917accea7e22dacde639dcc Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Thu, 23 Mar 2023 17:17:19 +0000 Subject: [PATCH 05/28] Enable skipping of derived traversals, with reason --- compiler/rustc_macros/src/lib.rs | 28 +- compiler/rustc_macros/src/traversable.rs | 232 ++++++++++++-- .../rustc_macros/src/traversable/tests.rs | 290 +++++++++++++++--- 3 files changed, 474 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 235ef44ab4da8..3070527602cd4 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -74,7 +74,7 @@ decl_derive!([TyEncodable] => serialize::type_encodable_derive); decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive); decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive); decl_derive!( - [TypeFoldable] => + [TypeFoldable, attributes(skip_traversal)] => /// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported). /// /// Folds will produce a value of the same struct or enum variant as the input, with trivial @@ -83,7 +83,18 @@ decl_derive!( /// both does not reference any generic type parameters and either /// - does not reference any `'tcx` lifetime parameter; or /// - does not contain anything that could be of interest to folders. - /// + /// + /// Non-trivial fields (e.g. of type `T`) can instead be left unchanged by applying + /// `#[skip_traversal(because_trivial)]` to the field definition (or even to a variant + /// definition if it should apply to all fields therein), but the derived implementation will + /// only be applicable if `T` does not contain anything that may be of interest to folders + /// (thus preventing fields from being so-skipped erroneously). + /// + /// In some rare situations, it may be desirable to skip folding of an item or field (or + /// variant) that might otherwise be of interest to folders: **this is dangerous and could lead + /// to miscompilation if user expectations are not met!** Nevertheless, such can be achieved + /// via a `#[skip_traversal(despite_potential_miscompilation_because = ""]` attribute. + /// /// If the annotated type has a `'tcx` lifetime parameter, then that will be used as the /// lifetime for the type context/interner; otherwise the lifetime of the type context/interner /// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of @@ -98,7 +109,7 @@ decl_derive!( traversable::traversable_derive:: ); decl_derive!( - [TypeVisitable] => + [TypeVisitable, attributes(skip_traversal)] => /// Derives `TypeVisitable` for the annotated `struct` or `enum` (`union` is not supported). /// /// Each non-trivial field of the struct or enum variant will be visited (in definition order) @@ -108,6 +119,17 @@ decl_derive!( /// - does not reference any `'tcx` lifetime parameter; or /// - does not contain anything that could be of interest to visitors. /// + /// Non-trivial fields (e.g. of type `T`) can instead be ignored by applying + /// `#[skip_traversal(because_trivial)]` to the field definition (or even to a variant + /// definition if it should apply to all fields therein), but the derived implementation will + /// only be applicable if `T` does not contain anything that may be of interest to visitors + /// (thus preventing fields from being so-skipped erroneously). + /// + /// In some rare situations, it may be desirable to skip visiting of an item or field (or + /// variant) that might otherwise be of interest to visitors: **this is dangerous and could lead + /// to miscompilation if user expectations are not met!** Nevertheless, such can be achieved + /// via a `#[skip_traversal(despite_potential_miscompilation_because = ""]` attribute. + /// /// If the annotated type has a `'tcx` lifetime parameter, then that will be used as the /// lifetime for the type context/interner; otherwise the lifetime of the type context/interner /// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of diff --git a/compiler/rustc_macros/src/traversable.rs b/compiler/rustc_macros/src/traversable.rs index a77e3b3e19d9f..579595b4442ef 100644 --- a/compiler/rustc_macros/src/traversable.rs +++ b/compiler/rustc_macros/src/traversable.rs @@ -1,7 +1,10 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, ToTokens}; -use std::collections::HashSet; -use syn::{parse_quote, visit, Field, Generics, Lifetime}; +use std::collections::{hash_map::Entry, HashMap}; +use syn::{ + meta::ParseNestedMeta, parse::Error, parse_quote, visit, Attribute, Field, Generics, Lifetime, + LitStr, Token, +}; #[cfg(test)] mod tests; @@ -31,6 +34,114 @@ enum Type { } use Type::*; +#[derive(Clone, Copy)] +enum WhenToSkip { + /// No skip_traversal annotation requires the annotated item to be skipped + Never, + + /// A skip_traversal annotation requires the annotated item to be skipped, with its type + /// constrained to TriviallyTraversable + Always(Span), + + /// A `despite_potential_miscompilation_because` annotation is present, thus requiring the + /// annotated item to be forcibly skipped without its type being constrained to + /// TriviallyTraversable + Forced, +} + +impl Default for WhenToSkip { + fn default() -> Self { + Self::Never + } +} + +impl WhenToSkip { + fn is_skipped(&self) -> bool { + !matches!(self, WhenToSkip::Never) + } +} + +impl std::ops::BitOrAssign for WhenToSkip { + fn bitor_assign(&mut self, rhs: Self) { + match self { + Self::Forced => (), + Self::Always(_) => { + if matches!(rhs, Self::Forced) { + *self = Self::Forced; + } + } + Self::Never => *self = rhs, + } + } +} + +impl WhenToSkip { + fn find(&mut self, attrs: &[Attribute], ty: Type) -> Result<(), Error> { + fn parse_reason(meta: &ParseNestedMeta<'_>) -> Result<(), Error> { + if !meta.value()?.parse::()?.value().trim().is_empty() { + Ok(()) + } else { + Err(meta.error("skip reason must be a non-empty string")) + } + } + + let mut found = None; + for attr in attrs { + if attr.path().is_ident("skip_traversal") { + found = Some(attr); + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("despite_potential_miscompilation_because") { + parse_reason(&meta)?; + *self |= Self::Forced; + return Ok(()); + } + + if !IS_TYPE && ty == Generic && meta.path.is_ident("because_trivial") { + *self |= Self::Always(meta.error("").span()); + return Ok(()); + } + + Err(meta.error("unsupported skip reason")) + })?; + } + } + + if let (Self::Never, Some(attr)) = (self, found) { + Err(Error::new_spanned( + attr, + if IS_TYPE { + match ty { + Trivial => { + "trivially traversable types are always skipped, so this attribute is superfluous" + } + _ => { + "\ + Justification must be provided for skipping this potentially interesting type, by specifying\n\ + `despite_potential_miscompilation_because = \"\"`\ + " + } + } + } else { + match ty { + Trivial => { + "trivially traversable fields are always skipped, so this attribute is superfluous" + } + _ => { + "\ + Justification must be provided for skipping potentially interesting fields, by specifying EITHER:\n\ + `because_trivial` if concrete instances do not actually contain anything of interest (enforced by the compiler); OR\n\ + `despite_potential_miscompilation_because = \"\"` in the rare case that a field should always be skipped regardless\ + " + } + } + }, + )) + } else { + Ok(()) + } + } +} + pub struct Interner<'a>(Option<&'a Lifetime>); impl<'a> Interner<'a> { @@ -73,7 +184,7 @@ pub trait Traversable { /// A `match` arm for `variant`, where `f` generates the tokens for each binding. fn arm( variant: &synstructure::VariantInfo<'_>, - f: impl FnMut(&synstructure::BindingInfo<'_>) -> TokenStream, + f: impl FnMut(&synstructure::BindingInfo<'_>) -> Result, ) -> TokenStream; /// The body of an implementation given the `interner`, `traverser` and match expression `body`. @@ -100,10 +211,10 @@ impl Traversable for Foldable { } fn arm( variant: &synstructure::VariantInfo<'_>, - mut f: impl FnMut(&synstructure::BindingInfo<'_>) -> TokenStream, + mut f: impl FnMut(&synstructure::BindingInfo<'_>) -> Result, ) -> TokenStream { let bindings = variant.bindings(); - variant.construct(|_, index| f(&bindings[index])) + variant.construct(|_, index| f(&bindings[index]).unwrap_or_else(Error::into_compile_error)) } fn impl_body( interner: Interner<'_>, @@ -137,9 +248,14 @@ impl Traversable for Visitable { } fn arm( variant: &synstructure::VariantInfo<'_>, - f: impl FnMut(&synstructure::BindingInfo<'_>) -> TokenStream, + f: impl FnMut(&synstructure::BindingInfo<'_>) -> Result, ) -> TokenStream { - variant.bindings().iter().map(f).collect() + variant + .bindings() + .iter() + .map(f) + .collect::>() + .unwrap_or_else(Error::into_compile_error) } fn impl_body( interner: Interner<'_>, @@ -199,49 +315,101 @@ impl Interner<'_> { pub fn traversable_derive( mut structure: synstructure::Structure<'_>, -) -> TokenStream { +) -> Result { + use WhenToSkip::*; + let ast = structure.ast(); let interner = Interner::resolve(&ast.generics); let traverser = gen_param("T", &ast.generics); let traversable = T::traversable(&interner); + let skip_traversal = + |t: &dyn ToTokens| parse_quote! { #interner: ::rustc_middle::ty::TriviallyTraverses<#t> }; + structure.underscore_const(true); structure.add_bounds(synstructure::AddBounds::None); structure.bind_with(|_| synstructure::BindStyle::Move); - if interner.0.is_none() { + let not_generic = if interner.0.is_none() { structure.add_impl_generic(parse_quote! { 'tcx }); - } + Trivial + } else { + NotGeneric + }; // If our derived implementation will be generic over the traversable type, then we must // constrain it to only those generic combinations that satisfy the traversable trait's // supertraits. - if ast.generics.type_params().next().is_some() { + let ty = if ast.generics.type_params().next().is_some() { let supertraits = T::supertraits(&interner); structure.add_where_predicate(parse_quote! { Self: #supertraits }); - } + Generic + } else { + not_generic + }; - // We add predicates to each generic field type, rather than to our generic type parameters. - // This results in a "perfect derive", but it can result in trait solver cycles if any type - // parameters are involved in recursive type definitions; fortunately that is not the case (yet). - let mut predicates = HashSet::new(); - let arms = structure.each_variant(|variant| { - T::arm(variant, |bind| { - let ast = bind.ast(); - let field_ty = interner.type_of(&bind.referenced_ty_params(), [ast]); - if field_ty == Generic { - predicates.insert(ast.ty.clone()); + let mut when_to_skip = WhenToSkip::default(); + when_to_skip.find::(&ast.attrs, ty)?; + let body = if when_to_skip.is_skipped() { + if let Always(_) = when_to_skip { + structure.add_where_predicate(skip_traversal(&::default())); + } + T::traverse(quote! { self }, true, &interner) + } else { + // We add predicates to each generic field type, rather than to our generic type parameters. + // This results in a "perfect derive" that avoids having to propagate `#[skip_traversal]` annotations + // into wrapping types, but it can result in trait solver cycles if any type parameters are involved + // in recursive type definitions; fortunately that is not the case (yet). + let mut predicates = HashMap::<_, (_, _)>::new(); + + let arms = structure.each_variant(|variant| { + let variant_ty = interner.type_of(&variant.referenced_ty_params(), variant.ast().fields); + let mut skipped_variant = WhenToSkip::default(); + if let Err(err) = skipped_variant.find::(variant.ast().attrs, variant_ty) { + return err.into_compile_error(); } - T::traverse(bind.into_token_stream(), field_ty == Trivial, &interner) - }) - }); - // the order in which `where` predicates appear in rust source is irrelevant - #[allow(rustc::potential_query_instability)] - for ty in predicates { - structure.add_where_predicate(parse_quote! { #ty: #traversable }); - } - let body = quote! { match self { #arms } }; + T::arm(variant, |bind| { + let ast = bind.ast(); + let is_skipped = variant_ty == Trivial || { + let field_ty = interner.type_of(&bind.referenced_ty_params(), [ast]); + field_ty == Trivial || { + let mut skipped_field = skipped_variant; + skipped_field.find::(&ast.attrs, field_ty)?; + + match predicates.entry(ast.ty.clone()) { + Entry::Occupied(existing) => match (&mut existing.into_mut().0, skipped_field) { + (Never, Never) | (Never, Forced) | (Forced, Forced) | (Always(_), Always(_)) => (), + (existing @ Forced, Never) => *existing = Never, + (&mut Always(span), _) | (_, Always(span)) => return Err(Error::new(span, format!("\ + This annotation only makes sense if all fields of type `{0}` are annotated identically.\n\ + In particular, the derived impl will only be applicable when `{0}: TriviallyTraversable` and therefore all traversals of `{0}` will be no-ops;\n\ + accordingly it makes no sense for other fields of type `{0}` to omit `#[skip_traversal]` or to include `despite_potential_miscompilation_because`.\ + ", ast.ty.to_token_stream()))), + }, + Entry::Vacant(entry) => { entry.insert((skipped_field, field_ty)); } + } + + skipped_field.is_skipped() + } + }; + + Ok(T::traverse(bind.into_token_stream(), is_skipped, &interner)) + }) + }); + + // the order in which `where` predicates appear in rust source is irrelevant + #[allow(rustc::potential_query_instability)] + for (ty, (when_to_skip, field_ty)) in predicates { + structure.add_where_predicate(match when_to_skip { + Always(_) => skip_traversal(&ty), + // we only need to add traversable predicate for generic types + Never if field_ty == Generic => parse_quote! { #ty: #traversable }, + _ => continue, + }); + } + quote! { match self { #arms } } + }; - structure.bound_impl(traversable, T::impl_body(interner, traverser, body)) + Ok(structure.bound_impl(traversable, T::impl_body(interner, traverser, body))) } diff --git a/compiler/rustc_macros/src/traversable/tests.rs b/compiler/rustc_macros/src/traversable/tests.rs index f2f0a4b71cb8b..e32dcf5261a35 100644 --- a/compiler/rustc_macros/src/traversable/tests.rs +++ b/compiler/rustc_macros/src/traversable/tests.rs @@ -1,4 +1,4 @@ -use super::{parse_quote, traversable_derive, Foldable, ToTokens}; +use super::{parse_quote, traversable_derive, visit, Error, Foldable, ToTokens}; use syn::visit_mut::VisitMut; /// A folder that normalizes syn types for comparison in tests. @@ -83,49 +83,35 @@ impl VisitMut for Normalizer { } } -#[test] -fn interesting_fields_are_constrained() { - let input = parse_quote! { - struct SomethingInteresting<'a, 'tcx, T>( - T, - T::Assoc, - Const<'tcx>, - Complex<'tcx, T>, - Generic, - Trivial, - TrivialGeneric<'a, Foo>, - ); - }; +#[derive(Default, Debug)] +struct ErrorFinder(Vec); - let expected = parse_quote! { - impl<'a, 'tcx, T> TypeFoldable> for SomethingInteresting<'a, 'tcx, T> - where - Complex<'tcx, T>: TypeFoldable>, - Generic: TypeFoldable>, - Self: TypeVisitable>, - T: TypeFoldable>, - T::Assoc: TypeFoldable> - { - fn try_fold_with<_T: FallibleTypeFolder>>(self, folder: &mut _T) -> Result { - Ok(match self { - SomethingInteresting (__binding_0, __binding_1, __binding_2, __binding_3, __binding_4, __binding_5, __binding_6,) => { SomethingInteresting( - noop_if_trivially_traversable!(__binding_0.try_fold_with::< TyCtxt<'tcx> >(folder))?, - noop_if_trivially_traversable!(__binding_1.try_fold_with::< TyCtxt<'tcx> >(folder))?, - noop_if_trivially_traversable!(__binding_2.try_fold_with::< TyCtxt<'tcx> >(folder))?, - noop_if_trivially_traversable!(__binding_3.try_fold_with::< TyCtxt<'tcx> >(folder))?, - noop_if_trivially_traversable!(__binding_4.try_fold_with::< TyCtxt<'tcx> >(folder))?, - __binding_5, - __binding_6, - )} - }) - } +impl ErrorFinder { + fn contains(&self, message: &str) -> bool { + self.0.iter().any(|error| error.starts_with(message)) + } +} + +impl visit::Visit<'_> for ErrorFinder { + fn visit_macro(&mut self, i: &syn::Macro) { + if i.path == parse_quote! { ::core::compile_error } { + self.0.push( + i.parse_body::() + .expect("expected compile_error macro to be invoked with a string literal") + .value(), + ); + } else { + syn::visit::visit_macro(self, i) } - }; + } +} - let result = syn::parse2::(traversable_derive::( - synstructure::Structure::new(&input), - )) - .expect("expected compiled code to parse"); +fn result(input: syn::DeriveInput) -> Result { + traversable_derive::(synstructure::Structure::new(&input)).and_then(syn::parse2) +} + +fn expect_success(input: syn::DeriveInput, expected: syn::ItemImpl) { + let result = result(input).expect("expected compiled code to parse"); let syn::Expr::Block(syn::ExprBlock { block: syn::Block { stmts, .. }, .. }) = *result.expr else { panic!("expected const expr to be a block") @@ -143,3 +129,225 @@ fn interesting_fields_are_constrained() { actual.to_token_stream() ); } + +fn expect_failure(input: syn::DeriveInput, expected: &str) { + let mut actual = ErrorFinder::default(); + match result(input) { + Ok(result) => visit::Visit::visit_item_const(&mut actual, &result), + Err(err) => actual.0.push(err.to_string()), + } + + assert!(actual.contains(expected), "EXPECTED: {expected}...\nACTUAL: {actual:?}"); +} + +macro_rules! expect { + ({$($input:tt)*} => {$($output:tt)*} $($rest:tt)*) => { + expect_success(parse_quote! { $($input)* }, parse_quote! { $($output)* }); + expect! { $($rest)* } + }; + ({$($input:tt)*} => $msg:literal $($rest:tt)*) => { + expect_failure(parse_quote! { $($input)* }, $msg); + expect! { $($rest)* } + }; + () => {}; +} + +#[test] +fn interesting_fields_are_constrained() { + expect! { + { + struct SomethingInteresting<'a, 'tcx, T>( + T, + T::Assoc, + Const<'tcx>, + Complex<'tcx, T>, + Generic, + Trivial, + TrivialGeneric<'a, Foo>, + ); + } => { + impl<'a, 'tcx, T> TypeFoldable> for SomethingInteresting<'a, 'tcx, T> + where + Complex<'tcx, T>: TypeFoldable>, + Generic: TypeFoldable>, + Self: TypeVisitable>, + T: TypeFoldable>, + T::Assoc: TypeFoldable> + { + fn try_fold_with<_T: FallibleTypeFolder>>(self, folder: &mut _T) -> Result { + Ok(match self { + SomethingInteresting (__binding_0, __binding_1, __binding_2, __binding_3, __binding_4, __binding_5, __binding_6,) => { SomethingInteresting( + noop_if_trivially_traversable!(__binding_0.try_fold_with::< TyCtxt<'tcx> >(folder))?, + noop_if_trivially_traversable!(__binding_1.try_fold_with::< TyCtxt<'tcx> >(folder))?, + noop_if_trivially_traversable!(__binding_2.try_fold_with::< TyCtxt<'tcx> >(folder))?, + noop_if_trivially_traversable!(__binding_3.try_fold_with::< TyCtxt<'tcx> >(folder))?, + noop_if_trivially_traversable!(__binding_4.try_fold_with::< TyCtxt<'tcx> >(folder))?, + __binding_5, + __binding_6, + )} + }) + } + } + } + } +} + +#[test] +fn skipping_trivial_type_is_superfluous() { + expect! { + { + #[skip_traversal()] + struct NothingInteresting<'a>; + } => "trivially traversable types are always skipped, so this attribute is superfluous" + } +} + +#[test] +fn skipping_interesting_type_requires_justification() { + expect! { + { + #[skip_traversal()] + struct SomethingInteresting<'tcx>; + } => "Justification must be provided for skipping this potentially interesting type" + + { + #[skip_traversal(because_trivial)] + struct SomethingInteresting<'tcx>; + } => "unsupported skip reason" + + { + #[skip_traversal(despite_potential_miscompilation_because = ".")] + struct SomethingInteresting<'tcx>; + } => { + impl<'tcx> TypeFoldable> for SomethingInteresting<'tcx> { + fn try_fold_with>>(self, folder: &mut T) -> Result { + Ok(self) // no attempt to fold fields + } + } + } + } +} + +#[test] +fn skipping_interesting_field_requires_justification() { + expect! { + { + struct SomethingInteresting<'tcx>( + #[skip_traversal()] + Const<'tcx>, + ); + } => "Justification must be provided for skipping potentially interesting fields" + + { + struct SomethingInteresting<'tcx>( + #[skip_traversal(because_trivial)] + Const<'tcx>, + ); + } => "unsupported skip reason" + + { + struct SomethingInteresting<'tcx>( + #[skip_traversal(despite_potential_miscompilation_because = ".")] + Const<'tcx>, + ); + } => { + impl<'tcx> TypeFoldable> for SomethingInteresting<'tcx> { + fn try_fold_with>>(self, folder: &mut T) -> Result { + Ok(match self { + SomethingInteresting(__binding_0,) => { SomethingInteresting(__binding_0,) } // not folded + }) + } + } + } + } +} + +#[test] +fn skipping_generic_type_requires_justification() { + expect! { + { + #[skip_traversal()] + struct SomethingInteresting; + } => "Justification must be provided for skipping this potentially interesting type" + + { + #[skip_traversal(despite_potential_miscompilation_because = ".")] + struct SomethingInteresting; + } => { + impl<'tcx, T> TypeFoldable> for SomethingInteresting + where + Self: TypeVisitable> + { + fn try_fold_with<_T: FallibleTypeFolder>>(self, folder: &mut _T) -> Result { + Ok(self) // no attempt to fold fields + } + } + } + } +} + +#[test] +fn skipping_generic_field_requires_justification() { + expect! { + { + struct SomethingInteresting( + #[skip_traversal()] + T, + ); + } => "Justification must be provided for skipping potentially interesting fields" + + { + struct SomethingInteresting( + #[skip_traversal(because_trivial)] + T, + ); + } => { + impl<'tcx, T> TypeFoldable> for SomethingInteresting + where + Self: TypeVisitable>, + TyCtxt<'tcx>: TriviallyTraverses // `because_trivial` + { + fn try_fold_with<_T: FallibleTypeFolder>>(self, folder: &mut _T) -> Result { + Ok(match self { + SomethingInteresting(__binding_0,) => { SomethingInteresting(__binding_0,) } // not folded + }) + } + } + } + + { + struct SomethingInteresting( + #[skip_traversal(despite_potential_miscompilation_because = ".")] + T, + ); + } => { + impl<'tcx, T> TypeFoldable> for SomethingInteresting + where + Self: TypeVisitable> // no constraint on T + { + fn try_fold_with<_T: FallibleTypeFolder>>(self, folder: &mut _T) -> Result { + Ok(match self { + SomethingInteresting(__binding_0,) => { SomethingInteresting(__binding_0,) } // not folded + }) + } + } + } + + { + struct SomethingInteresting( + #[skip_traversal(because_trivial)] + T, + T, + ); + } => "This annotation only makes sense if all fields of type `T` are annotated identically" + + { + struct SomethingInteresting( + #[skip_traversal(despite_potential_miscompilation_because = ".")] + T, + #[skip_traversal(because_trivial)] + T, + ); + } => "This annotation only makes sense if all fields of type `T` are annotated identically" + } +} From 07108f90fc2d04494d355252650f3af54046f18c Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sat, 25 Feb 2023 23:07:41 +0000 Subject: [PATCH 06/28] Derive traversable impls for BindingForm BindingForm has been a no-op traversable ever since it was first added in cac6126, but it was modified in 0193d1f to (optionally) contain a Place without its implementations being updated to fold/visit such. By using the derive macro to implement the visitable traits, we ensure that all contained types of interest are folded/visited. --- compiler/rustc_middle/src/mir/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7054cede2d87c..3460d6c646996 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -759,7 +759,7 @@ pub enum LocalKind { ReturnPointer, } -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct VarBindingForm<'tcx> { /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? pub binding_mode: ty::BindingMode, @@ -776,12 +776,16 @@ pub struct VarBindingForm<'tcx> { /// (a) the right-hand side isn't evaluated as a place expression. /// (b) it gives a way to separate this case from the remaining cases /// for diagnostics. + // FIXME: provide actual justification for `#[skip_traversal]`, or else remove + #[skip_traversal( + despite_potential_miscompilation_because = "potential oversight since 0193d1f" + )] pub opt_match_place: Option<(Option>, Span)>, /// The span of the pattern in which this variable was bound. pub pat_span: Span, } -#[derive(Clone, Debug, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub enum BindingForm<'tcx> { /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. Var(VarBindingForm<'tcx>), @@ -791,7 +795,7 @@ pub enum BindingForm<'tcx> { RefForGuard, } -TrivialTypeTraversalImpls! { BindingForm<'tcx> } +TrivialLiftImpls! { BindingForm<'tcx> } mod binding_form_impl { use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; From 8b4785dd794f017225bfdfe5f23b9244c6a58054 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 26 Feb 2023 00:31:37 +0000 Subject: [PATCH 07/28] Derive traversable impls for Obligation Ever since folding was first added in c5754f397, obligations have not folded or visited their causes the ObligationCauseCode potentially containing types that may be of interest to a folder or visitor. By using the derive macro to implement the visitable traits, we ensure that all contained types of interest are folded/visited. --- compiler/rustc_infer/src/traits/mod.rs | 5 ++- .../src/traits/structural_impls.rs | 33 +------------------ 2 files changed, 5 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index a26e676c52175..d760794f1c274 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -36,9 +36,12 @@ pub use rustc_middle::traits::*; /// either identifying an `impl` (e.g., `impl Eq for i32`) that /// satisfies the obligation, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone)] +#[derive(Clone, TypeFoldable, TypeVisitable)] pub struct Obligation<'tcx, T> { /// The reason we have to prove this thing. + // FIXME: provide more detailed justification for `#[skip_traversal]`, or else remove + // see https://github.com/rust-lang/rust/pull/108214#issuecomment-1479424793 + #[skip_traversal(despite_potential_miscompilation_because = "perf")] pub cause: ObligationCause<'tcx>, /// The environment in which we should prove this thing. diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 8a7c59da09ebb..958988e1dcf34 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -1,11 +1,8 @@ use crate::traits; use crate::traits::project::Normalized; -use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use rustc_middle::ty::visit::{TypeVisitable, TypeVisitor}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty; use std::fmt; -use std::ops::ControlFlow; // Structural impls for the structs in `traits`. @@ -58,31 +55,3 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { write!(f, "MismatchedProjectionTypes({:?})", self.err) } } - -/////////////////////////////////////////////////////////////////////////// -// TypeFoldable implementations. - -impl<'tcx, O: TypeFoldable>> TypeFoldable> - for traits::Obligation<'tcx, O> -{ - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - Ok(traits::Obligation { - cause: self.cause, - recursion_depth: self.recursion_depth, - predicate: self.predicate.try_fold_with(folder)?, - param_env: self.param_env.try_fold_with(folder)?, - }) - } -} - -impl<'tcx, O: TypeVisitable>> TypeVisitable> - for traits::Obligation<'tcx, O> -{ - fn visit_with>>(&self, visitor: &mut V) -> ControlFlow { - self.predicate.visit_with(visitor)?; - self.param_env.visit_with(visitor) - } -} From a4ea3be84d422536516444b4c45ae9a561c05d69 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 29 Oct 2023 12:12:37 +0000 Subject: [PATCH 08/28] Derive traversable impls for GenericArgKind --- compiler/rustc_middle/src/ty/generic_args.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 41a1bf04e5f3f..b7518c1f84923 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -47,6 +47,7 @@ const REGION_TAG: usize = 0b01; const CONST_TAG: usize = 0b10; #[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)] +#[derive(Clone, TypeFoldable, TypeVisitable)] pub enum GenericArgKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), @@ -210,21 +211,13 @@ impl<'tcx> TypeFoldable> for GenericArg<'tcx> { self, folder: &mut F, ) -> Result { - match self.unpack() { - GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into), - GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into), - GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into), - } + self.unpack().try_fold_with(folder).map(GenericArgKind::pack) } } impl<'tcx> TypeVisitable> for GenericArg<'tcx> { fn visit_with>>(&self, visitor: &mut V) -> ControlFlow { - match self.unpack() { - GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), - GenericArgKind::Type(ty) => ty.visit_with(visitor), - GenericArgKind::Const(ct) => ct.visit_with(visitor), - } + self.unpack().visit_with(visitor) } } From 17c69dfe14d9c6b9427509247dddcc9a2106a407 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sat, 25 Feb 2023 23:20:07 +0000 Subject: [PATCH 09/28] Simplify traversable impls in solver wrapper types Rather than being concerned with internals of ExternalConstraintsData and PredefinedOpaquesData, we derive traversable impls for those types to which we then delegate. --- compiler/rustc_middle/src/traits/solve.rs | 45 +++-------------------- 1 file changed, 6 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 27a1e64a78bd5..f2b2090ba4204 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,13 +1,10 @@ -use std::ops::ControlFlow; - use rustc_data_structures::intern::Interned; use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; use crate::traits::query::NoSolution; use crate::traits::{Canonical, DefiningAnchor}; use crate::ty::{ - self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, - TypeVisitor, + self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, }; use rustc_span::def_id::DefId; @@ -110,7 +107,7 @@ pub struct QueryInput<'tcx, T> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] pub struct PredefinedOpaquesData<'tcx> { pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, } @@ -167,21 +164,7 @@ impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { self, folder: &mut F, ) -> Result { - Ok(FallibleTypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { - region_constraints: self.region_constraints.clone().try_fold_with(folder)?, - opaque_types: self - .opaque_types - .iter() - .map(|opaque| opaque.try_fold_with(folder)) - .collect::>()?, - })) - } - - fn fold_with>>(self, folder: &mut F) -> Self { - TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { - region_constraints: self.region_constraints.clone().fold_with(folder), - opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), - }) + Ok(folder.interner().mk_external_constraints((*self).clone().try_fold_with(folder)?)) } } @@ -190,9 +173,7 @@ impl<'tcx> TypeVisitable> for ExternalConstraints<'tcx> { &self, visitor: &mut V, ) -> std::ops::ControlFlow { - self.region_constraints.visit_with(visitor)?; - self.opaque_types.visit_with(visitor)?; - ControlFlow::Continue(()) + (**self).visit_with(visitor) } } @@ -206,21 +187,7 @@ impl<'tcx> TypeFoldable> for PredefinedOpaques<'tcx> { self, folder: &mut F, ) -> Result { - Ok(FallibleTypeFolder::interner(folder).mk_predefined_opaques_in_body( - PredefinedOpaquesData { - opaque_types: self - .opaque_types - .iter() - .map(|opaque| opaque.try_fold_with(folder)) - .collect::>()?, - }, - )) - } - - fn fold_with>>(self, folder: &mut F) -> Self { - TypeFolder::interner(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { - opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), - }) + Ok(folder.interner().mk_predefined_opaques_in_body((*self).clone().try_fold_with(folder)?)) } } @@ -229,7 +196,7 @@ impl<'tcx> TypeVisitable> for PredefinedOpaques<'tcx> { &self, visitor: &mut V, ) -> std::ops::ControlFlow { - self.opaque_types.visit_with(visitor) + (**self).visit_with(visitor) } } From 68b4a086df4449399228eb6e18fef72dd758e5d0 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Mon, 20 Mar 2023 10:12:52 +0000 Subject: [PATCH 10/28] Newtype for FakeRead semi-traversable tuple --- .../src/diagnostics/conflict_errors.rs | 13 +++++++------ .../src/diagnostics/explain_borrow.rs | 10 +++++++--- compiler/rustc_borrowck/src/diagnostics/mod.rs | 8 ++++---- compiler/rustc_borrowck/src/invalidation.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 6 +++++- compiler/rustc_middle/src/mir/visit.rs | 2 +- compiler/rustc_mir_build/src/build/cfg.rs | 2 +- .../rustc_mir_dataflow/src/move_paths/builder.rs | 2 +- .../src/coverage/spans/from_mir.rs | 8 ++++---- compiler/rustc_mir_transform/src/remove_zsts.rs | 2 +- .../clippy/clippy_utils/src/qualify_min_const_fn.rs | 4 ++-- 13 files changed, 36 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 247200dcd2695..27393efbade36 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -14,9 +14,9 @@ use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, - FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place, - PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, - VarBindingForm, + FakeReadCause, FakeReadCauseAndPlace, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, + Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, VarBindingForm, }; use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty}; use rustc_middle::util::CallKind; @@ -3010,9 +3010,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> { fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { match statement { - Statement { kind: StatementKind::FakeRead(box (cause, place)), .. } - if *place == self.place => - { + Statement { + kind: StatementKind::FakeRead(box FakeReadCauseAndPlace(cause, place)), + .. + } if *place == self.place => { self.cause = Some(*cause); } _ => (), diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 8a930ca59a334..ff0ca491115d0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor; use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ - Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, - Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, + Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, FakeReadCauseAndPlace, Local, + LocalInfo, Location, Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, }; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, RegionVid, TyCtxt}; @@ -477,7 +477,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let block = &self.body.basic_blocks[location.block]; let kind = if let Some(&Statement { - kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)), + kind: + StatementKind::FakeRead(box FakeReadCauseAndPlace( + FakeReadCause::ForLet(_), + place, + )), .. }) = block.statements.get(location.statement_index) { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 4b95b4783eb4b..94c78eb671422 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,9 +13,9 @@ use rustc_index::IndexSlice; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ - AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location, - Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, + AggregateKind, CallSource, ConstOperand, FakeReadCause, FakeReadCauseAndPlace, Local, + LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, + StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -797,7 +797,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // StatementKind::FakeRead only contains a def_id if they are introduced as a result // of pattern matching within a closure. - if let StatementKind::FakeRead(box (cause, place)) = stmt.kind { + if let StatementKind::FakeRead(box FakeReadCauseAndPlace(cause, place)) = stmt.kind { match cause { FakeReadCause::ForMatchedPlace(Some(closure_def_id)) | FakeReadCause::ForLet(Some(closure_def_id)) => { diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 7b5b52e39b121..e7ce728c10aab 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -62,7 +62,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.mutate_place(location, *lhs, Shallow(None)); } - StatementKind::FakeRead(box (_, _)) => { + StatementKind::FakeRead(_) => { // Only relevant for initialized/liveness/safety checks. } StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 1a74582389d1e..008be6fe3889c 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -629,7 +629,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro self.mutate_place(location, (*lhs, span), Shallow(None), flow_state); } - StatementKind::FakeRead(box (_, place)) => { + StatementKind::FakeRead(box FakeReadCauseAndPlace(_, place)) => { // Read for match doesn't access any memory and is used to // assert that a place is safe and live. So we don't have to // do any checks here. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index debd85dad2e02..6939539ce331f 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -680,7 +680,7 @@ impl Debug for Statement<'_> { use self::StatementKind::*; match self.kind { Assign(box (ref place, ref rv)) => write!(fmt, "{place:?} = {rv:?}"), - FakeRead(box (ref cause, ref place)) => { + FakeRead(box FakeReadCauseAndPlace(ref cause, ref place)) => { write!(fmt, "FakeRead({cause:?}, {place:?})") } Retag(ref kind, ref place) => write!( diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index b6543affc6dbe..ceaf3506090f6 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -288,7 +288,7 @@ pub enum StatementKind<'tcx> { /// When executed at runtime this is a nop. /// /// Disallowed after drop elaboration. - FakeRead(Box<(FakeReadCause, Place<'tcx>)>), + FakeRead(Box>), /// Write the discriminant for a variant to the enum Place. /// @@ -459,6 +459,10 @@ pub enum RetagKind { Default, } +#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)] +#[derive(TypeFoldable, TypeVisitable)] +pub struct FakeReadCauseAndPlace<'tcx>(pub FakeReadCause, pub Place<'tcx>); + /// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)] pub enum FakeReadCause { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 0f0ca3a1420e9..bffc82f4c8c31 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -379,7 +379,7 @@ macro_rules! make_mir_visitor { ) => { self.visit_assign(place, rvalue, location); } - StatementKind::FakeRead(box (_, place)) => { + StatementKind::FakeRead(box FakeReadCauseAndPlace(_, place)) => { self.visit_place( place, PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs index fddcf9de7c7c9..d6bcc4ab7e96d 100644 --- a/compiler/rustc_mir_build/src/build/cfg.rs +++ b/compiler/rustc_mir_build/src/build/cfg.rs @@ -85,7 +85,7 @@ impl<'tcx> CFG<'tcx> { cause: FakeReadCause, place: Place<'tcx>, ) { - let kind = StatementKind::FakeRead(Box::new((cause, place))); + let kind = StatementKind::FakeRead(Box::new(FakeReadCauseAndPlace(cause, place))); let stmt = Statement { source_info, kind }; self.push(block, stmt); } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index ccf3dc7941fed..9765e88c902c8 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -376,7 +376,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { } self.gather_rvalue(rval); } - StatementKind::FakeRead(box (_, place)) => { + StatementKind::FakeRead(box FakeReadCauseAndPlace(_, place)) => { self.create_move_path(*place); } StatementKind::StorageLive(_) => {} diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 6189e5379ea05..7d4d5fd562d41 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,7 +1,7 @@ use rustc_data_structures::captures::Captures; use rustc_middle::mir::{ - self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, + self, AggregateKind, FakeReadCause, FakeReadCauseAndPlace, Rvalue, Statement, StatementKind, + Terminator, TerminatorKind, }; use rustc_span::Span; @@ -120,10 +120,10 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option { // and `_1` is the `Place` for `somenum`. // // If and when the Issue is resolved, remove this special case match pattern: - StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None, + StatementKind::FakeRead(box FakeReadCauseAndPlace(FakeReadCause::ForGuardBinding, _)) => None, // Retain spans from all other statements - StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` + StatementKind::FakeRead(_) // Not including `ForGuardBinding` | StatementKind::Intrinsic(..) | StatementKind::Assign(_) | StatementKind::SetDiscriminant { .. } diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 5aa3c3cfe4dde..a6d940ee5f321 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -113,7 +113,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { | StatementKind::AscribeUserType(box (place, _), _) | StatementKind::Retag(_, box place) | StatementKind::PlaceMention(box place) - | StatementKind::FakeRead(box (_, place)) => Some(place), + | StatementKind::FakeRead(box FakeReadCauseAndPlace(_, place)) => Some(place), StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { Some(local.into()) } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 668ea9fcf3b4b..a11b4286a5ef8 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_middle::mir::{ - Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, + Body, CastKind, FakeReadCauseAndPlace, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; @@ -207,7 +207,7 @@ fn check_statement<'tcx>( check_rvalue(tcx, body, def_id, rval, span) }, - StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body), + StatementKind::FakeRead(box FakeReadCauseAndPlace(_, place)) => check_place(tcx, *place, span, body), // just an assignment StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { check_place(tcx, **place, span, body) From 0fc043db0e762bee56907e70baa35a027e26491f Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Mon, 20 Mar 2023 10:14:57 +0000 Subject: [PATCH 11/28] Newtype for AscribeUserType semi-traversable tuple --- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 5 ++++- compiler/rustc_middle/src/mir/pretty.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 4 ++-- compiler/rustc_middle/src/mir/visit.rs | 2 +- compiler/rustc_mir_build/src/build/expr/as_place.rs | 4 ++-- compiler/rustc_mir_build/src/build/matches/mod.rs | 7 +++++-- compiler/rustc_mir_transform/src/remove_zsts.rs | 2 +- 8 files changed, 17 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 9f30d9d8ba12b..b8fb18c23e60a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1297,7 +1297,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } } - StatementKind::AscribeUserType(box (place, projection), variance) => { + StatementKind::AscribeUserType(box AscribeUserType(place, projection), variance) => { let place_ty = place.ty(body, tcx).ty; if let Err(terr) = self.relate_type_and_user_type( place_ty, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 3460d6c646996..d0390b37b521c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1477,6 +1477,10 @@ impl<'tcx> UserTypeProjections { } } +#[derive(Clone, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] +#[derive(TypeFoldable, TypeVisitable)] +pub struct AscribeUserType<'tcx>(pub Place<'tcx>, pub UserTypeProjection); + /// Encodes the effect of a user-supplied type annotation on the /// subcomponents of a pattern. The effect is determined by applying the /// given list of projections to some underlying base type. Often, @@ -1493,7 +1497,6 @@ impl<'tcx> UserTypeProjections { /// `field[0]` (aka `.0`), indicating that the type of `s` is /// determined by finding the type of the `.0` field from `T`. #[derive(Clone, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] -#[derive(TypeFoldable, TypeVisitable)] pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, pub projs: Vec, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 6939539ce331f..01f25f27c7b7a 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -703,7 +703,7 @@ impl Debug for Statement<'_> { PlaceMention(ref place) => { write!(fmt, "PlaceMention({place:?})") } - AscribeUserType(box (ref place, ref c_ty), ref variance) => { + AscribeUserType(box self::AscribeUserType(ref place, ref c_ty), ref variance) => { write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})") } Coverage(box mir::Coverage { ref kind }) => write!(fmt, "Coverage::{kind:?}"), diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index ceaf3506090f6..dff5ea2ac86a2 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -3,7 +3,7 @@ //! This is in a dedicated file so that changes to this file can be reviewed more carefully. //! The intention is that this file only contains datatype declarations, no code. -use super::{BasicBlock, Const, Local, UserTypeProjection}; +use super::{AscribeUserType, BasicBlock, Const, Local}; use crate::mir::coverage::CoverageKind; use crate::traits::Reveal; @@ -359,7 +359,7 @@ pub enum StatementKind<'tcx> { /// When executed at runtime this is a nop. /// /// Disallowed after drop elaboration. - AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), + AscribeUserType(Box>, ty::Variance), /// Carries control-flow-sensitive information injected by `-Cinstrument-coverage`, /// such as where to generate physical coverage-counter-increments during codegen. diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index bffc82f4c8c31..2436e0e4833c9 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -425,7 +425,7 @@ macro_rules! make_mir_visitor { ); } StatementKind::AscribeUserType( - box (place, user_ty), + box AscribeUserType(place, user_ty), variance ) => { self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location); diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index c6a09f6568a5e..1f5422b372308 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -482,7 +482,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info, kind: StatementKind::AscribeUserType( - Box::new(( + Box::new(AscribeUserType( place, UserTypeProjection { base: annotation_index, projs: vec![] }, )), @@ -509,7 +509,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info, kind: StatementKind::AscribeUserType( - Box::new(( + Box::new(AscribeUserType( Place::from(temp), UserTypeProjection { base: annotation_index, projs: vec![] }, )), diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index a43aae6f44942..14906d21c8cc8 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -586,7 +586,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info: ty_source_info, kind: StatementKind::AscribeUserType( - Box::new((place, UserTypeProjection { base, projs: Vec::new() })), + Box::new(AscribeUserType( + place, + UserTypeProjection { base, projs: Vec::new() }, + )), // We always use invariant as the variance here. This is because the // variance field from the ascription refers to the variance to use // when applying the type to the value being matched, but this @@ -2149,7 +2152,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Statement { source_info, kind: StatementKind::AscribeUserType( - Box::new(( + Box::new(AscribeUserType( ascription.source, UserTypeProjection { base, projs: Vec::new() }, )), diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index a6d940ee5f321..9f617886f8b69 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -110,7 +110,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { } StatementKind::Deinit(box place) | StatementKind::SetDiscriminant { box place, variant_index: _ } - | StatementKind::AscribeUserType(box (place, _), _) + | StatementKind::AscribeUserType(box AscribeUserType(place, _), _) | StatementKind::Retag(_, box place) | StatementKind::PlaceMention(box place) | StatementKind::FakeRead(box FakeReadCauseAndPlace(_, place)) => Some(place), From 867f351cf0bb55c1eb9356b34ebe688fb6497aa2 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Mon, 20 Mar 2023 10:15:53 +0000 Subject: [PATCH 12/28] Newtype for InstanceOfArg semi-traversable tuple --- compiler/rustc_middle/src/query/keys.rs | 8 ++++++++ compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 5 ++++- compiler/rustc_middle/src/ty/mod.rs | 4 +++- compiler/rustc_ty_utils/src/instance.rs | 4 ++-- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 113763450529c..7c23891e80f8a 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -335,6 +335,14 @@ impl<'tcx> Key for (DefId, GenericArgsRef<'tcx>) { } } +impl<'tcx> Key for ty::InstanceOfArg<'tcx> { + type CacheSelector = DefaultCacheSelector; + + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.0.default_span(tcx) + } +} + impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f9ec368361c59..4ec3b47711d9e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2103,7 +2103,7 @@ rustc_queries! { /// from `Ok(None)` to avoid misleading diagnostics when an error /// has already been/will be emitted, for the original cause query resolve_instance( - key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)> + key: ty::ParamEnvAnd<'tcx, ty::InstanceOfArg<'tcx>> ) -> Result>, ErrorGuaranteed> { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index cebefbccc11d1..735f58d1702f4 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -334,6 +334,9 @@ impl<'tcx> fmt::Display for Instance<'tcx> { } } +#[derive(Clone, Copy, Debug, Eq, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] +pub struct InstanceOfArg<'tcx>(pub DefId, pub GenericArgsRef<'tcx>); + impl<'tcx> Instance<'tcx> { pub fn new(def_id: DefId, args: GenericArgsRef<'tcx>) -> Instance<'tcx> { assert!( @@ -400,7 +403,7 @@ impl<'tcx> Instance<'tcx> { // below is more likely to ignore the bounds in scope (e.g. if the only // generic parameters mentioned by `args` were lifetime ones). let args = tcx.erase_regions(args); - tcx.resolve_instance(tcx.erase_regions(param_env.and((def_id, args)))) + tcx.resolve_instance(tcx.erase_regions(param_env.and(InstanceOfArg(def_id, args)))) } pub fn expect_resolve( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1ef71eebaf60b..4a79c9d11be85 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -91,7 +91,9 @@ pub use self::context::{ tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TriviallyTraversable, TyCtxt, TyCtxtFeed, }; -pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams}; +pub use self::instance::{ + Instance, InstanceDef, InstanceOfArg, ShortInstance, UnusedGenericParams, +}; pub use self::list::List; pub use self::parameterized::ParameterizedOverTcx; pub use self::rvalue_scopes::RvalueScopes; diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 1487f40fd9941..d598b93b89bd2 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -14,9 +14,9 @@ use crate::errors::UnexpectedFnPtrAssociatedItem; fn resolve_instance<'tcx>( tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>, + key: ty::ParamEnvAnd<'tcx, ty::InstanceOfArg<'tcx>>, ) -> Result>, ErrorGuaranteed> { - let (param_env, (def_id, args)) = key.into_parts(); + let (param_env, ty::InstanceOfArg(def_id, args)) = key.into_parts(); let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); From 95b0952cbe34c6a6dcf51ea883e9b7b438d4327d Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sat, 25 Feb 2023 15:19:51 +0000 Subject: [PATCH 13/28] Remove superfluous traversable impls --- compiler/rustc_middle/src/hir/place.rs | 2 - compiler/rustc_middle/src/infer/canonical.rs | 5 -- compiler/rustc_middle/src/mir/basic_blocks.rs | 2 - compiler/rustc_middle/src/mir/coverage.rs | 12 ++- .../rustc_middle/src/mir/interpret/error.rs | 2 - compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/mir/query.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 8 +- .../rustc_middle/src/mir/type_foldable.rs | 43 ---------- compiler/rustc_middle/src/traits/mod.rs | 7 +- compiler/rustc_middle/src/traits/select.rs | 2 - compiler/rustc_middle/src/traits/solve.rs | 4 +- .../rustc_middle/src/ty/abstract_const.rs | 4 +- compiler/rustc_middle/src/ty/binding.rs | 2 - compiler/rustc_middle/src/ty/closure.rs | 5 -- compiler/rustc_middle/src/ty/mod.rs | 1 - .../rustc_middle/src/ty/structural_impls.rs | 78 ++----------------- compiler/rustc_type_ir/src/fold.rs | 13 +++- compiler/rustc_type_ir/src/macros.rs | 5 -- compiler/rustc_type_ir/src/visit.rs | 13 +++- 20 files changed, 42 insertions(+), 170 deletions(-) diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 32f3a177508f7..916fd5f3a1300 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -5,7 +5,6 @@ use rustc_hir::HirId; use rustc_target::abi::{FieldIdx, VariantIdx}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub enum PlaceBase { /// A temporary variable. Rvalue, @@ -18,7 +17,6 @@ pub enum PlaceBase { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub enum ProjectionKind { /// A dereference of a pointer, reference or `Box` of the given type. Deref, diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 64b63f4c5eb4f..b85d4d52b5dba 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -364,11 +364,6 @@ impl<'tcx, R> QueryResponse<'tcx, R> { pub type QueryOutlivesConstraint<'tcx> = (ty::OutlivesPredicate, Region<'tcx>>, ConstraintCategory<'tcx>); -TrivialTypeTraversalImpls! { - crate::infer::canonical::Certainty, - crate::infer::canonical::CanonicalTyVarKind, -} - impl<'tcx> CanonicalVarValues<'tcx> { // Given a list of canonical variables, construct a set of values which are // the identity response. diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 3ecd5b9cd3456..739d8926a3e82 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -181,8 +181,6 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> { } } -TrivialTypeTraversalImpls! { Cache } - impl Encodable for Cache { #[inline] fn encode(&self, _s: &mut S) {} diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 08d377a8695f9..beae8b9429426 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -53,7 +53,7 @@ impl ExpressionId { /// but the zero/counter/expression distinction is also useful for representing /// the value of code/gap mappings, and the true/false arms of branch mappings. #[derive(Copy, Clone, PartialEq, Eq)] -#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable)] pub enum CovTerm { Zero, Counter(CounterId), @@ -70,7 +70,7 @@ impl Debug for CovTerm { } } -#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum CoverageKind { /// Marks the point in MIR control flow represented by a coverage counter. /// @@ -102,7 +102,6 @@ impl Debug for CoverageKind { } #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)] -#[derive(TypeFoldable, TypeVisitable)] pub struct CodeRegion { pub file_name: Symbol, pub start_line: u32, @@ -122,7 +121,6 @@ impl Debug for CodeRegion { } #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub enum Op { Subtract, Add, @@ -139,7 +137,7 @@ impl Op { } #[derive(Clone, Debug)] -#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable)] pub struct Expression { pub lhs: CovTerm, pub op: Op, @@ -147,7 +145,7 @@ pub struct Expression { } #[derive(Clone, Debug)] -#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable)] pub struct Mapping { pub code_region: CodeRegion, @@ -164,7 +162,7 @@ pub struct Mapping { /// to be used in conjunction with the individual coverage statements injected /// into the function's basic blocks. #[derive(Clone, Debug)] -#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable)] pub struct FunctionCoverageInfo { pub function_source_hash: u64, pub num_counters: usize, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 44b22e2d38386..8c1cd0b54b154 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -82,8 +82,6 @@ impl Into for ReportedErrorInfo { } } -TrivialTypeTraversalImpls! { ErrorHandled } - pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; /// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed. diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d0390b37b521c..9c8492a240693 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1414,7 +1414,7 @@ pub struct SourceScopeLocalData { /// The first will lead to the constraint `w: &'1 str` (for some /// inferred region `'1`). The second will lead to the constraint `w: /// &'static str`. -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub struct UserTypeProjections { pub contents: Vec<(UserTypeProjection, Span)>, } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 7fd9a7d1c5396..468bf0df0b2fb 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -374,7 +374,7 @@ pub enum ConstraintCategory<'tcx> { } #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] +#[derive(TyEncodable, TyDecodable, HashStable)] pub enum ReturnConstraint { Normal, ClosureUpvar(FieldIdx), diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index dff5ea2ac86a2..a5ab607fa1f72 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -520,7 +520,6 @@ pub enum FakeReadCause { } #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub struct Coverage { pub kind: CoverageKind, } @@ -536,7 +535,6 @@ pub struct CopyNonOverlapping<'tcx> { /// Represents how a `TerminatorKind::Call` was constructed, used for diagnostics #[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, PartialEq, Hash, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub enum CallSource { /// This came from something such as `a > b` or `a + b`. In THIR, if `from_hir_call` /// is false then this is the desugaring. @@ -850,7 +848,6 @@ pub struct SwitchTargets { /// Action to be taken when a stack unwind happens. #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub enum UnwindAction { /// No action is to be taken. Continue unwinding. /// @@ -869,7 +866,6 @@ pub enum UnwindAction { /// The reason we are terminating the process during unwinding. #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub enum UnwindTerminateReason { /// Unwinding is just not possible given the ABI of this function. Abi, @@ -1362,7 +1358,7 @@ pub enum NullOp<'tcx> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TyEncodable, TyDecodable)] pub enum UnOp { /// The `!` operator for logical inversion Not, @@ -1371,7 +1367,7 @@ pub enum UnOp { } #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] +#[derive(TyEncodable, TyDecodable, HashStable)] pub enum BinOp { /// The `+` operator (addition) Add, diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index d5c81b6cd7930..1dedd3f587efb 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -1,51 +1,8 @@ //! `TypeFoldable` implementations for MIR types -use rustc_ast::InlineAsmTemplatePiece; - use super::*; use crate::ty; -TrivialTypeTraversalImpls! { - BlockTailInfo, - MirPhase, - SourceInfo, - FakeReadCause, - RetagKind, - SourceScope, - SourceScopeLocalData, - UserTypeAnnotationIndex, - BorrowKind, - CastKind, - hir::Movability, - BasicBlock, - SwitchTargets, - CoroutineKind, - CoroutineSavedLocal, -} - -TrivialTypeTraversalImpls! { - ConstValue<'tcx>, - NullOp<'tcx>, -} - -impl<'tcx> TypeFoldable> for &'tcx [InlineAsmTemplatePiece] { - fn try_fold_with>>( - self, - _folder: &mut F, - ) -> Result { - Ok(self) - } -} - -impl<'tcx> TypeFoldable> for &'tcx [Span] { - fn try_fold_with>>( - self, - _folder: &mut F, - ) -> Result { - Ok(self) - } -} - impl<'tcx> TypeFoldable> for &'tcx ty::List> { fn try_fold_with>>( self, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 6cd75e0872763..1de07c99071ea 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -471,7 +471,7 @@ pub enum IsConstable { Ctor, } -crate::TrivialTypeTraversalAndLiftImpls! { +crate::TrivialLiftImpls! { IsConstable, } @@ -480,7 +480,6 @@ crate::TrivialTypeTraversalAndLiftImpls! { /// we can walk in order to obtain precise spans for any /// 'nested' types (e.g. `Foo` in `Option`). #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] -#[derive(TypeVisitable, TypeFoldable)] pub enum WellFormedLoc { /// Use the type of the provided definition. Ty(LocalDefId), @@ -757,8 +756,6 @@ pub enum BuiltinImplSource { TupleUnsizing, } -TrivialTypeTraversalImpls! { BuiltinImplSource } - #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum ObjectSafetyViolation { /// `Self: Sized` declared on the trait. @@ -956,7 +953,7 @@ pub enum CodegenObligationError { FulfillmentError, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable)] pub enum DefiningAnchor { /// `DefId` of the item. Bind(LocalDefId), diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index f33421bbaa6c1..6b7f2332093b3 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -309,8 +309,6 @@ impl From for OverflowError { } } -TrivialTypeTraversalImpls! { OverflowError } - impl<'tcx> From for SelectionError<'tcx> { fn from(overflow_error: OverflowError) -> SelectionError<'tcx> { match overflow_error { diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index f2b2090ba4204..4520afe69995a 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -49,7 +49,7 @@ pub struct Response<'tcx> { pub external_constraints: ExternalConstraints<'tcx>, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable)] pub enum Certainty { Yes, Maybe(MaybeCause), @@ -89,7 +89,7 @@ impl Certainty { } /// Why we failed to evaluate a goal. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable)] pub enum MaybeCause { /// We failed due to ambiguity. This ambiguity can either /// be a true ambiguity, i.e. there are multiple different answers, diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index 570f896ba299b..caf3b30268cb0 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -6,7 +6,7 @@ use crate::ty::{ use rustc_errors::ErrorGuaranteed; #[derive(Hash, Debug, Clone, Copy, Ord, PartialOrd, PartialEq, Eq)] -#[derive(TyDecodable, TyEncodable, HashStable, TypeVisitable, TypeFoldable)] +#[derive(TyDecodable, TyEncodable, HashStable)] pub enum CastKind { /// thir::ExprKind::As As, @@ -27,8 +27,6 @@ impl From for NotConstEvaluatable { } } -TrivialTypeTraversalImpls! { NotConstEvaluatable } - pub type BoundAbstractConst<'tcx> = Result>>, ErrorGuaranteed>; impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs index af594bc5f24c8..0bbfe82d3731f 100644 --- a/compiler/rustc_middle/src/ty/binding.rs +++ b/compiler/rustc_middle/src/ty/binding.rs @@ -6,8 +6,6 @@ pub enum BindingMode { BindByValue(Mutability), } -TrivialTypeTraversalImpls! { BindingMode } - impl BindingMode { pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode { match by_ref { diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 74bdd07a1c946..33265335e4ba8 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -23,7 +23,6 @@ use self::BorrowKind::*; pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1); #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub struct UpvarPath { pub hir_id: hir::HirId, } @@ -32,7 +31,6 @@ pub struct UpvarPath { /// the original var ID (that is, the root variable that is referenced /// by the upvar) and the ID of the closure expression. #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub struct UpvarId { pub var_path: UpvarPath, pub closure_expr_id: LocalDefId, @@ -47,7 +45,6 @@ impl UpvarId { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub enum UpvarCapture { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases @@ -314,7 +311,6 @@ pub fn is_ancestor_or_same_capture( /// for a particular capture as well as identifying the part of the source code /// that triggered this capture to occur. #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub struct CaptureInfo { /// Expr Id pointing to use that resulted in selecting the current capture kind /// @@ -393,7 +389,6 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc } #[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)] -#[derive(TypeFoldable, TypeVisitable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. ImmBorrow, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4a79c9d11be85..d90115b2a7e42 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -284,7 +284,6 @@ impl fmt::Display for ImplPolarity { } #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)] -#[derive(TypeFoldable, TypeVisitable)] pub enum Asyncness { Yes, No, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 75721d6abf2cc..228a913d77ef8 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -408,55 +408,22 @@ TrivialLiftImpls! { bool, usize, u64, + ::rustc_hir::Mutability, + crate::ty::ParamConst, + crate::ty::ParamTy, + interpret::Scalar, + interpret::AllocId, + rustc_target::abi::Size, } // For some things about which the type library does not know, or does not // provide any traversal implementations, we need to provide a traversal // implementation (only for TyCtxt<'_> interners). TrivialTypeTraversalImpls! { - ::rustc_target::abi::FieldIdx, - ::rustc_target::abi::VariantIdx, - crate::middle::region::Scope, - crate::ty::FloatTy, - ::rustc_ast::InlineAsmOptions, - ::rustc_ast::InlineAsmTemplatePiece, - ::rustc_ast::NodeId, - ::rustc_span::symbol::Symbol, - ::rustc_hir::def::Res, - ::rustc_hir::def_id::LocalDefId, - ::rustc_hir::HirId, - ::rustc_hir::MatchSource, - ::rustc_target::asm::InlineAsmRegOrRegClass, - crate::mir::coverage::CounterId, - crate::mir::coverage::ExpressionId, crate::mir::Local, - crate::mir::Promoted, - crate::traits::Reveal, - crate::ty::adjustment::AutoBorrowMutability, - crate::ty::AdtKind, crate::ty::BoundConstness, - // Including `BoundRegionKind` is a *bit* dubious, but direct - // references to bound region appear in `ty::Error`, and aren't - // really meant to be folded. In general, we can only fold a fully - // general `Region`. - crate::ty::BoundRegionKind, - crate::ty::AssocItem, - crate::ty::AssocKind, - crate::ty::AliasKind, - crate::ty::Placeholder, - crate::ty::Placeholder, - crate::ty::Placeholder, - crate::ty::FreeRegion, - crate::ty::InferTy, - crate::ty::IntVarValue, - crate::ty::adjustment::PointerCoercion, - crate::ty::RegionVid, - crate::ty::Variance, ::rustc_span::Span, - ::rustc_span::symbol::Ident, ::rustc_errors::ErrorGuaranteed, - ty::BoundVar, - ty::ValTree<'tcx>, } // For some things about which the type library does not know, or does not // provide any traversal implementations, we need to provide a traversal @@ -464,15 +431,9 @@ TrivialTypeTraversalImpls! { // interners). TrivialTypeTraversalAndLiftImpls! { ::rustc_hir::def_id::DefId, - ::rustc_hir::Mutability, ::rustc_hir::Unsafety, ::rustc_target::spec::abi::Abi, crate::ty::ClosureKind, - crate::ty::ParamConst, - crate::ty::ParamTy, - interpret::Scalar, - interpret::AllocId, - rustc_target::abi::Size, } /////////////////////////////////////////////////////////////////////////// @@ -504,15 +465,6 @@ impl<'a, 'tcx> Lift<'tcx> for Term<'a> { /////////////////////////////////////////////////////////////////////////// // Traversal implementations. -impl<'tcx> TypeVisitable> for ty::AdtDef<'tcx> { - fn visit_with>>( - &self, - _visitor: &mut V, - ) -> ControlFlow { - ControlFlow::Continue(()) - } -} - impl<'tcx, T: TypeFoldable>> TypeFoldable> for ty::Binder<'tcx, T> { fn try_fold_with>>( self, @@ -842,24 +794,6 @@ impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { } } -impl<'tcx> TypeFoldable> for InferConst { - fn try_fold_with>>( - self, - _folder: &mut F, - ) -> Result { - Ok(self) - } -} - -impl<'tcx> TypeVisitable> for InferConst { - fn visit_with>>( - &self, - _visitor: &mut V, - ) -> ControlFlow { - ControlFlow::Continue(()) - } -} - impl<'tcx> TypeSuperVisitable> for ty::UnevaluatedConst<'tcx> { fn super_visit_with>>( &self, diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 24eb19a8c1bd3..7f67f7e7a030b 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -288,8 +288,17 @@ impl, T> SpecTypeFoldable for &PhantomData<(I, T)> { } /////////////////////////////////////////////////////////////////////////// -// Traversal implementations. - +// Traversable implementations for upstream types. + +// We provide implementations for 2- and 3-element tuples, however (absent specialisation) +// we can only provide for one case: we choose our implementations to be where all elements +// themselves implement the respective traits; thus if an element is a no-op traversal, it +// must provide explicit implementations even though the auto-deref specialisation would +// normally negate any such need. The derive macros can be used for this purpose however. +// +// Note that if all elements are no-op traversals then the tuple itself will auto-implement +// the `BoringTraversable` trait and these implementations will be bypassed; consequently +// explicit implementations on the element types would not then be required. impl, U: TypeFoldable> TypeFoldable for (T, U) { fn try_fold_with>(self, folder: &mut F) -> Result<(T, U), F::Error> { Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?)) diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index ae36d5b6c58c1..b5d9329a61845 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -44,11 +44,6 @@ TrivialTypeTraversalImpls! { (), bool, usize, - u16, - u32, - u64, - String, - crate::DebruijnIndex, crate::AliasRelationDirection, crate::UniverseIndex, } diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index f4feb2e687e91..c6a4e28ddac1a 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -156,8 +156,17 @@ impl, T: ?Sized> SpecTypeVisitable for &PhantomData<(I, } /////////////////////////////////////////////////////////////////////////// -// Traversal implementations. - +// Traversable implementations for upstream types. + +// We provide implementations for 2- and 3-element tuples, however (absent specialisation) +// we can only provide for one case: we choose our implementations to be where all elements +// themselves implement the respective traits; thus if an element is a no-op traversal, it +// must provide explicit implementations even though the auto-deref specialisation would +// normally negate any such need. The derive macros can be used for this purpose however. +// +// Note that if all elements are no-op traversals then the tuple itself will auto-implement +// the `BoringTraversable` trait and these implementations will be bypassed; consequently +// explicit implementations on the element types would not then be required. impl, U: TypeVisitable> TypeVisitable for (T, U) { fn visit_with>(&self, visitor: &mut V) -> ControlFlow { self.0.visit_with(visitor)?; From 2463fef582e90b9ed1bab2f4c59975cb473b2c66 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Wed, 1 Nov 2023 18:58:50 +0000 Subject: [PATCH 14/28] Remove traversable impl for mir::Local --- compiler/rustc_middle/src/mir/syntax.rs | 2 +- compiler/rustc_middle/src/ty/structural_impls.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index a5ab607fa1f72..ed567c61b3a95 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1033,7 +1033,7 @@ pub enum ProjectionElem { /// /// The `x[i]` is turned into a `Deref` followed by an `Index`, not just an `Index`. The same /// thing is true of the `ConstantIndex` and `Subslice` projections below. - Index(V), + Index(#[skip_traversal(because_trivial)] V), /// These indices are generated by slice patterns. Easiest to explain /// by example: diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 228a913d77ef8..93eee857a78eb 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -420,7 +420,6 @@ TrivialLiftImpls! { // provide any traversal implementations, we need to provide a traversal // implementation (only for TyCtxt<'_> interners). TrivialTypeTraversalImpls! { - crate::mir::Local, crate::ty::BoundConstness, ::rustc_span::Span, ::rustc_errors::ErrorGuaranteed, From 73397feb80ca7d4fd0fcf85e7a9ab7f4609258e3 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Wed, 1 Nov 2023 19:03:44 +0000 Subject: [PATCH 15/28] Remove traversable impl for ErrorGuaranteed --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 3 +-- compiler/rustc_middle/src/ty/structural_impls.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index eb4491b89bf1e..f5784e5fb8662 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -128,8 +128,7 @@ where let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); - wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?; - infcx.tainted_by_errors().error_reported() + wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env) } fn check_well_formed(tcx: TyCtxt<'_>, def_id: hir::OwnerId) -> Result<(), ErrorGuaranteed> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 93eee857a78eb..1626cae8c4bcb 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -422,7 +422,6 @@ TrivialLiftImpls! { TrivialTypeTraversalImpls! { crate::ty::BoundConstness, ::rustc_span::Span, - ::rustc_errors::ErrorGuaranteed, } // For some things about which the type library does not know, or does not // provide any traversal implementations, we need to provide a traversal From 71062433e4825380ce5af2b8d96539367ca57b7c Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sat, 25 Feb 2023 17:41:02 +0000 Subject: [PATCH 16/28] Remove traversable impl for bool --- compiler/rustc_hir_typeck/src/pat.rs | 2 +- compiler/rustc_type_ir/src/macros.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index b30f9b82fbbf7..7232af11b5945 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -567,7 +567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs), _ => span_bug!(span, "Impossible, verified above."), } - if (lhs, rhs).references_error() { + if (lhs.map(|(_, ty, _)| ty), rhs.map(|(_, ty, _)| ty)).references_error() { err.downgrade_to_delayed_bug(); } if self.tcx.sess.teach(&err.get_code().unwrap()) { diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index b5d9329a61845..a5101717cd8c5 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -42,7 +42,6 @@ macro_rules! TrivialTypeTraversalImpls { TrivialTypeTraversalImpls! { (), - bool, usize, crate::AliasRelationDirection, crate::UniverseIndex, From f71523298b65c3cf05b633f21677c0f853d0aff2 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 29 Oct 2023 00:14:31 +0100 Subject: [PATCH 17/28] Remove traversable impl for usize --- compiler/rustc_mir_transform/src/function_item_references.rs | 2 +- compiler/rustc_type_ir/src/macros.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index a42eacbf22b42..24eaefa7c1a4a 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -171,7 +171,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { let ty_params = fn_args.types().map(|ty| format!("{ty}")); let const_params = fn_args.consts().map(|c| format!("{c}")); let params = ty_params.chain(const_params).join(", "); - let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder(); + let num_args = fn_sig.inputs().skip_binder().len(); let variadic = if fn_sig.c_variadic() { ", ..." } else { "" }; let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" }; let sugg = format!( diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index a5101717cd8c5..73dbbcb74ec41 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -42,7 +42,6 @@ macro_rules! TrivialTypeTraversalImpls { TrivialTypeTraversalImpls! { (), - usize, crate::AliasRelationDirection, crate::UniverseIndex, } From 0b97607a6f40dc7cbe09565b546b0f63140936ec Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sat, 25 Feb 2023 19:51:28 +0000 Subject: [PATCH 18/28] Use rustc_type_ir directly in derived traversables --- Cargo.lock | 3 ++ compiler/rustc_infer/Cargo.toml | 1 + compiler/rustc_macros/src/traversable.rs | 14 ++++----- .../rustc_macros/src/traversable/tests.rs | 30 ++++++++++++------- compiler/rustc_trait_selection/Cargo.toml | 1 + compiler/rustc_transmute/Cargo.toml | 2 ++ 6 files changed, 34 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index adaac69af577c..d8f1e320d348f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4032,6 +4032,7 @@ dependencies = [ "rustc_serialize", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec", "tracing", ] @@ -4601,6 +4602,7 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_transmute", + "rustc_type_ir", "smallvec", "tracing", ] @@ -4630,6 +4632,7 @@ dependencies = [ "rustc_middle", "rustc_span", "rustc_target", + "rustc_type_ir", "tracing", ] diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 00251a192264a..5983221f9411f 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -18,6 +18,7 @@ rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_macros/src/traversable.rs b/compiler/rustc_macros/src/traversable.rs index 579595b4442ef..fe6f005dd4061 100644 --- a/compiler/rustc_macros/src/traversable.rs +++ b/compiler/rustc_macros/src/traversable.rs @@ -197,7 +197,7 @@ pub trait Traversable { impl Traversable for Foldable { fn traversable(interner: &Interner<'_>) -> TokenStream { - quote! { ::rustc_middle::ty::fold::TypeFoldable<#interner> } + quote! { ::rustc_type_ir::fold::TypeFoldable<#interner> } } fn supertraits(interner: &Interner<'_>) -> TokenStream { Visitable::traversable(interner) @@ -206,7 +206,7 @@ impl Traversable for Foldable { if noop { bind } else { - quote! { ::rustc_middle::ty::noop_if_trivially_traversable!(#bind.try_fold_with::<#interner>(folder))? } + quote! { ::rustc_type_ir::noop_if_trivially_traversable!(#bind.try_fold_with::<#interner>(folder))? } } } fn arm( @@ -222,7 +222,7 @@ impl Traversable for Foldable { body: impl ToTokens, ) -> TokenStream { quote! { - fn try_fold_with<#traverser: ::rustc_middle::ty::fold::FallibleTypeFolder<#interner>>( + fn try_fold_with<#traverser: ::rustc_type_ir::fold::FallibleTypeFolder<#interner>>( self, folder: &mut #traverser ) -> ::core::result::Result { @@ -234,7 +234,7 @@ impl Traversable for Foldable { impl Traversable for Visitable { fn traversable(interner: &Interner<'_>) -> TokenStream { - quote! { ::rustc_middle::ty::visit::TypeVisitable<#interner> } + quote! { ::rustc_type_ir::visit::TypeVisitable<#interner> } } fn supertraits(_: &Interner<'_>) -> TokenStream { quote! { ::core::clone::Clone + ::core::fmt::Debug } @@ -243,7 +243,7 @@ impl Traversable for Visitable { if noop { quote! {} } else { - quote! { ::rustc_middle::ty::noop_if_trivially_traversable!(#bind.visit_with::<#interner>(visitor))?; } + quote! { ::rustc_type_ir::noop_if_trivially_traversable!(#bind.visit_with::<#interner>(visitor))?; } } } fn arm( @@ -263,7 +263,7 @@ impl Traversable for Visitable { body: impl ToTokens, ) -> TokenStream { quote! { - fn visit_with<#traverser: ::rustc_middle::ty::visit::TypeVisitor<#interner>>( + fn visit_with<#traverser: ::rustc_type_ir::visit::TypeVisitor<#interner>>( &self, visitor: &mut #traverser ) -> ::core::ops::ControlFlow<#traverser::BreakTy> { @@ -325,7 +325,7 @@ pub fn traversable_derive( let traversable = T::traversable(&interner); let skip_traversal = - |t: &dyn ToTokens| parse_quote! { #interner: ::rustc_middle::ty::TriviallyTraverses<#t> }; + |t: &dyn ToTokens| parse_quote! { #interner: ::rustc_type_ir::TriviallyTraverses<#t> }; structure.underscore_const(true); structure.add_bounds(synstructure::AddBounds::None); diff --git a/compiler/rustc_macros/src/traversable/tests.rs b/compiler/rustc_macros/src/traversable/tests.rs index e32dcf5261a35..36ae944715483 100644 --- a/compiler/rustc_macros/src/traversable/tests.rs +++ b/compiler/rustc_macros/src/traversable/tests.rs @@ -49,18 +49,28 @@ impl VisitMut for Normalizer { let n = if i.leading_colon.is_some() && i.segments.len() >= 2 { let segment = &i.segments[0]; - if *segment == parse_quote! { rustc_middle } { - if i.segments.len() >= 3 && i.segments[1] == parse_quote! { ty } { - let segment = &i.segments[2]; - if *segment == parse_quote! { fold } || *segment == parse_quote! { visit } { - 3 - } else { - 2 - } - } else { + if *segment == parse_quote! { rustc_type_ir } { + let segment = &i.segments[1]; + if i.segments.len() > 2 && *segment == parse_quote! { fold } + || *segment == parse_quote! { visit } + { + 2 + } else if *segment == parse_quote! { Interner } + || segment.ident == "TriviallyTraverses" + || *segment == parse_quote! { noop_if_trivially_traversable } + { 1 + } else { + return; + } + } else if *segment == parse_quote! { rustc_middle } { + let segment = &i.segments[1]; + if i.segments.len() > 2 && *segment == parse_quote! { ty } { + 2 + } else { + return; } - } else if *segment == parse_quote! { core } { + } else if i.segments.len() > 2 && *segment == parse_quote! { core } { let segment = &i.segments[1]; if *segment == parse_quote! { ops } { 2 diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 667ee3d4e1c69..807c57b5f799b 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -22,6 +22,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 07420985a851f..43328146fcffe 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -12,6 +12,7 @@ rustc_macros = { path = "../rustc_macros", optional = true} rustc_middle = { path = "../rustc_middle", optional = true} rustc_span = { path = "../rustc_span", optional = true} rustc_target = { path = "../rustc_target", optional = true} +rustc_type_ir = { path = "../rustc_type_ir", optional = true} tracing = "0.1" # tidy-alphabetical-end @@ -23,6 +24,7 @@ rustc = [ "rustc_middle", "rustc_span", "rustc_target", + "rustc_type_ir", ] [dev-dependencies] From 5296463384133be0ab636907b36afdd1c3218fbd Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Tue, 21 Mar 2023 08:49:31 +0000 Subject: [PATCH 19/28] Derive traversables over generic interners --- compiler/rustc_macros/src/lib.rs | 22 +++++------ compiler/rustc_macros/src/traversable.rs | 38 ++++++++++--------- .../rustc_macros/src/traversable/tests.rs | 20 +++++----- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 3070527602cd4..babf9dbe272c6 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -95,13 +95,12 @@ decl_derive!( /// to miscompilation if user expectations are not met!** Nevertheless, such can be achieved /// via a `#[skip_traversal(despite_potential_miscompilation_because = ""]` attribute. /// - /// If the annotated type has a `'tcx` lifetime parameter, then that will be used as the - /// lifetime for the type context/interner; otherwise the lifetime of the type context/interner - /// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of - /// the annotated type are named. For example, deriving `TypeFoldable` for both `Foo<'a>` and - /// `Bar<'tcx>` will respectively produce: + /// The derived implementation will use `TyCtxt<'tcx>` as the interner iff the annotated type + /// has a `'tcx` lifetime parameter; otherwise it will be generic over all interners. It + /// therefore matters how any lifetime parameters of the annotated type are named. For example, + /// deriving `TypeFoldable` for both `Foo<'a>` and `Bar<'tcx>` will respectively produce: /// - /// `impl<'a, 'tcx> TypeFoldable> for Foo<'a>` + /// `impl<'a, I: Interner> TypeFoldable for Foo<'a>` /// /// and /// @@ -130,13 +129,12 @@ decl_derive!( /// to miscompilation if user expectations are not met!** Nevertheless, such can be achieved /// via a `#[skip_traversal(despite_potential_miscompilation_because = ""]` attribute. /// - /// If the annotated type has a `'tcx` lifetime parameter, then that will be used as the - /// lifetime for the type context/interner; otherwise the lifetime of the type context/interner - /// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of - /// the annotated type are named. For example, deriving `TypeVisitable` for both `Foo<'a>` and - /// `Bar<'tcx>` will respectively produce: + /// The derived implementation will use `TyCtxt<'tcx>` as the interner iff the annotated type + /// has a `'tcx` lifetime parameter; otherwise it will be generic over all interners. It + /// therefore matters how any lifetime parameters of the annotated type are named. For example, + /// deriving `TypeVisitable` for both `Foo<'a>` and `Bar<'tcx>` will respectively produce: /// - /// `impl<'a, 'tcx> TypeVisitable> for Foo<'a>` + /// `impl<'a, I: Interner> TypeVisitable for Foo<'a>` /// /// and /// diff --git a/compiler/rustc_macros/src/traversable.rs b/compiler/rustc_macros/src/traversable.rs index fe6f005dd4061..56ac6e3b7030e 100644 --- a/compiler/rustc_macros/src/traversable.rs +++ b/compiler/rustc_macros/src/traversable.rs @@ -142,28 +142,30 @@ impl WhenToSkip { } } -pub struct Interner<'a>(Option<&'a Lifetime>); +pub enum Interner<'a> { + Middle(&'a Lifetime), + Generic(Ident), +} impl<'a> Interner<'a> { - /// Return the `TyCtxt` interner for the given `structure`. + /// Return the interner for the given `structure`. /// - /// If the input represented by `structure` has a `'tcx` lifetime parameter, then that will be used - /// used as the lifetime of the `TyCtxt`. Otherwise a `'tcx` lifetime parameter that is unrelated - /// to the input will be used. - fn resolve(generics: &'a Generics) -> Self { - Self( - generics - .lifetimes() - .find_map(|def| (def.lifetime.ident == "tcx").then_some(&def.lifetime)), - ) + /// If the input represented by `structure` has a `'tcx` lifetime parameter, then `Middle('tcx)` + /// will be returned; otherwise our derived implementation will be generic over a new parameter. + fn resolve(suffix: impl ToString, generics: &'a Generics) -> Self { + generics + .lifetimes() + .find_map(|def| (def.lifetime.ident == "tcx").then_some(Self::Middle(&def.lifetime))) + .unwrap_or_else(|| Self::Generic(gen_param(suffix, generics))) } } impl ToTokens for Interner<'_> { fn to_tokens(&self, tokens: &mut TokenStream) { - let default = parse_quote! { 'tcx }; - let lt = self.0.unwrap_or(&default); - tokens.extend(quote! { ::rustc_middle::ty::TyCtxt<#lt> }); + match self { + Interner::Middle(lt) => tokens.extend(quote! { ::rustc_middle::ty::TyCtxt<#lt> }), + Interner::Generic(ident) => ident.to_tokens(tokens), + } } } @@ -301,7 +303,7 @@ impl Interner<'_> { if !referenced_ty_params.is_empty() { Generic - } else if let Some(interner) = &self.0 && fields.into_iter().any(|field| { + } else if let Interner::Middle(interner) = self && fields.into_iter().any(|field| { let mut info = Info { interner, contains_interner: false }; info.visit_type(&field.ty); info.contains_interner @@ -320,7 +322,7 @@ pub fn traversable_derive( let ast = structure.ast(); - let interner = Interner::resolve(&ast.generics); + let interner = Interner::resolve("I", &ast.generics); let traverser = gen_param("T", &ast.generics); let traversable = T::traversable(&interner); @@ -331,8 +333,8 @@ pub fn traversable_derive( structure.add_bounds(synstructure::AddBounds::None); structure.bind_with(|_| synstructure::BindStyle::Move); - let not_generic = if interner.0.is_none() { - structure.add_impl_generic(parse_quote! { 'tcx }); + let not_generic = if let Interner::Generic(ident) = &interner { + structure.add_impl_generic(parse_quote! { #ident: ::rustc_type_ir::Interner }); Trivial } else { NotGeneric diff --git a/compiler/rustc_macros/src/traversable/tests.rs b/compiler/rustc_macros/src/traversable/tests.rs index 36ae944715483..64f50cffd5543 100644 --- a/compiler/rustc_macros/src/traversable/tests.rs +++ b/compiler/rustc_macros/src/traversable/tests.rs @@ -284,11 +284,11 @@ fn skipping_generic_type_requires_justification() { #[skip_traversal(despite_potential_miscompilation_because = ".")] struct SomethingInteresting; } => { - impl<'tcx, T> TypeFoldable> for SomethingInteresting + impl TypeFoldable for SomethingInteresting where - Self: TypeVisitable> + Self: TypeVisitable { - fn try_fold_with<_T: FallibleTypeFolder>>(self, folder: &mut _T) -> Result { + fn try_fold_with<_T: FallibleTypeFolder>(self, folder: &mut _T) -> Result { Ok(self) // no attempt to fold fields } } @@ -312,12 +312,12 @@ fn skipping_generic_field_requires_justification() { T, ); } => { - impl<'tcx, T> TypeFoldable> for SomethingInteresting + impl TypeFoldable for SomethingInteresting where - Self: TypeVisitable>, - TyCtxt<'tcx>: TriviallyTraverses // `because_trivial` + I: TriviallyTraverses, // `because_trivial` + Self: TypeVisitable { - fn try_fold_with<_T: FallibleTypeFolder>>(self, folder: &mut _T) -> Result { + fn try_fold_with<_T: FallibleTypeFolder>(self, folder: &mut _T) -> Result { Ok(match self { SomethingInteresting(__binding_0,) => { SomethingInteresting(__binding_0,) } // not folded }) @@ -331,11 +331,11 @@ fn skipping_generic_field_requires_justification() { T, ); } => { - impl<'tcx, T> TypeFoldable> for SomethingInteresting + impl TypeFoldable for SomethingInteresting where - Self: TypeVisitable> // no constraint on T + Self: TypeVisitable // no constraint on T { - fn try_fold_with<_T: FallibleTypeFolder>>(self, folder: &mut _T) -> Result { + fn try_fold_with<_T: FallibleTypeFolder>(self, folder: &mut _T) -> Result { Ok(match self { SomethingInteresting(__binding_0,) => { SomethingInteresting(__binding_0,) } // not folded }) From ea5a21092c01ddd7d566e1c31321c3fca705e894 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Mon, 20 Mar 2023 09:57:05 +0000 Subject: [PATCH 20/28] Use Spanned not semi-traversable Span tuples --- Cargo.lock | 1 + .../src/diagnostics/conflict_errors.rs | 6 +- .../src/diagnostics/move_errors.rs | 6 +- .../src/type_check/canonical.rs | 8 +- .../src/debuginfo/create_scope_map.rs | 10 +-- .../src/interpret/eval_context.rs | 6 +- .../rustc_hir_analysis/src/astconv/mod.rs | 2 +- .../src/astconv/object_safety.rs | 8 +- compiler/rustc_hir_analysis/src/bounds.rs | 24 ++--- .../src/check/compare_impl_item.rs | 27 +++--- .../src/check/compare_impl_item/refine.rs | 14 +-- .../rustc_hir_analysis/src/check/dropck.rs | 4 +- compiler/rustc_hir_analysis/src/check/mod.rs | 12 +-- .../rustc_hir_analysis/src/check/wfcheck.rs | 37 ++++---- compiler/rustc_hir_analysis/src/collect.rs | 5 +- .../src/collect/item_bounds.rs | 28 +++--- .../src/collect/predicates_of.rs | 90 +++++++++++-------- .../src/collect/resolve_bound_vars.rs | 4 +- .../src/constrained_generic_params.rs | 6 +- .../src/impl_wf_check/min_specialization.rs | 18 ++-- .../src/outlives/explicit.rs | 8 +- .../rustc_hir_analysis/src/variance/mod.rs | 8 +- compiler/rustc_hir_typeck/src/_match.rs | 4 +- compiler/rustc_hir_typeck/src/callee.rs | 8 +- compiler/rustc_hir_typeck/src/closure.rs | 19 ++-- compiler/rustc_hir_typeck/src/expr.rs | 5 +- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 6 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 2 +- .../rustc_hir_typeck/src/method/confirm.rs | 2 +- .../src/infer/error_reporting/mod.rs | 3 +- .../src/infer/error_reporting/note.rs | 24 ++--- .../rustc_infer/src/infer/opaque_types.rs | 4 +- compiler/rustc_infer/src/traits/util.rs | 49 +++++++++- compiler/rustc_lint/src/builtin.rs | 10 +-- .../src/multiple_supertrait_upcastable.rs | 2 +- .../src/opaque_hidden_inferred_bound.rs | 14 ++- compiler/rustc_lint/src/traits.rs | 8 +- compiler/rustc_lint/src/unused.rs | 4 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 8 +- compiler/rustc_metadata/src/rmeta/mod.rs | 4 +- compiler/rustc_middle/src/mir/mod.rs | 18 ++-- compiler/rustc_middle/src/mir/pretty.rs | 12 ++- compiler/rustc_middle/src/mir/visit.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 6 +- .../rustc_middle/src/query/on_disk_cache.rs | 7 ++ compiler/rustc_middle/src/traits/mod.rs | 4 +- compiler/rustc_middle/src/traits/util.rs | 2 +- compiler/rustc_middle/src/ty/codec.rs | 11 +++ compiler/rustc_middle/src/ty/context.rs | 8 +- compiler/rustc_middle/src/ty/generics.rs | 16 ++-- compiler/rustc_middle/src/ty/mod.rs | 24 +++-- compiler/rustc_middle/src/ty/parameterized.rs | 4 + compiler/rustc_middle/src/ty/print/pretty.rs | 4 +- .../rustc_middle/src/ty/structural_impls.rs | 9 +- compiler/rustc_mir_build/src/build/block.rs | 10 ++- .../rustc_mir_build/src/build/matches/mod.rs | 16 ++-- compiler/rustc_mir_build/src/build/mod.rs | 4 +- compiler/rustc_mir_transform/src/coroutine.rs | 4 +- compiler/rustc_mir_transform/src/inline.rs | 5 +- compiler/rustc_mir_transform/src/lib.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 13 +-- compiler/rustc_smir/src/rustc_smir/mod.rs | 12 +-- compiler/rustc_span/Cargo.toml | 1 + compiler/rustc_span/src/source_map.rs | 1 + .../src/solve/eval_ctxt/select.rs | 6 +- .../project_goals/inherent_projection.rs | 2 +- .../src/solve/project_goals/mod.rs | 4 +- .../src/traits/coherence.rs | 4 +- .../src/traits/engine.rs | 6 +- .../src/traits/error_reporting/ambiguity.rs | 6 +- .../src/traits/error_reporting/suggestions.rs | 18 ++-- .../error_reporting/type_err_ctxt_ext.rs | 9 +- .../rustc_trait_selection/src/traits/mod.rs | 14 +-- .../src/traits/object_safety.rs | 19 ++-- .../src/traits/project.rs | 15 ++-- .../traits/query/type_op/ascribe_user_type.rs | 8 +- .../src/traits/select/candidate_assembly.rs | 4 +- .../src/traits/select/confirmation.rs | 4 +- .../src/traits/select/mod.rs | 6 +- .../src/traits/specialize/mod.rs | 6 +- .../rustc_trait_selection/src/traits/util.rs | 10 +-- .../src/traits/vtable.rs | 6 +- .../rustc_trait_selection/src/traits/wf.rs | 8 +- .../src/normalize_projection_ty.rs | 11 ++- compiler/rustc_ty_utils/src/implied_bounds.rs | 8 +- compiler/rustc_ty_utils/src/opaque_types.rs | 6 +- compiler/rustc_ty_utils/src/sig_types.rs | 24 ++--- compiler/rustc_ty_utils/src/ty.rs | 4 +- src/librustdoc/clean/mod.rs | 12 +-- src/librustdoc/clean/simplify.rs | 4 +- src/tools/clippy/clippy_lints/src/derive.rs | 6 +- .../clippy_lints/src/future_not_send.rs | 4 +- .../src/implied_bounds_in_impls.rs | 4 +- .../src/unit_return_expecting_ord.rs | 12 +-- .../clippy_lints/src/useless_conversion.rs | 6 +- .../clippy/clippy_utils/src/eager_or_lazy.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- src/tools/clippy/clippy_utils/src/ty.rs | 20 ++--- src/tools/miri/src/helpers.rs | 2 +- 100 files changed, 563 insertions(+), 424 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8f1e320d348f..3d2a09eb60a78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4532,6 +4532,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_serialize", + "rustc_type_ir", "scoped-tls", "sha1", "sha2", diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 27393efbade36..eba8c1428ada8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -671,8 +671,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let tcx = self.infcx.tcx; // Find out if the predicates show that the type is a Fn or FnMut - let find_fn_kind_from_did = |(pred, _): (ty::Clause<'tcx>, _)| { - if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() + let find_fn_kind_from_did = |pred: ty::Spanned>| { + if let ty::ClauseKind::Trait(pred) = pred.node.kind().skip_binder() && pred.self_ty() == ty { if Some(pred.def_id()) == tcx.lang_items().fn_trait() { @@ -698,7 +698,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => tcx .explicit_item_bounds(def_id) .iter_instantiated_copied(tcx, args) - .find_map(|(clause, span)| find_fn_kind_from_did((clause, span))), + .find_map(find_fn_kind_from_did), ty::Closure(_, args) => match args.as_closure().kind() { ty::ClosureKind::Fn => Some(hir::Mutability::Not), ty::ClosureKind::FnMut => Some(hir::Mutability::Mut), diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 41d6b98d7cfa9..61622eba17341 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // opt_match_place is None for let [mut] x = ... statements, // whether or not the right-hand side is a place expression if let LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: Some((opt_match_place, match_span)), + opt_match_place: Some(opt_match_place), binding_mode: _, opt_ty_info: _, pat_span: _, @@ -143,8 +143,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { original_path, *move_from, local, - opt_match_place, - match_span, + opt_match_place.node, + opt_match_place.span, stmt_source_info.span, ); return; diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index fc600af1b76f0..9caabb4df1daf 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -99,10 +99,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { instantiated_predicates: ty::InstantiatedPredicates<'tcx>, locations: Locations, ) { - for (predicate, span) in instantiated_predicates { - debug!(?predicate); - let category = ConstraintCategory::Predicate(span); - let predicate = self.normalize_with_category(predicate, locations, category); + for predicate in instantiated_predicates { + debug!(?predicate.node); + let category = ConstraintCategory::Predicate(predicate.span); + let predicate = self.normalize_with_category(predicate.node, locations, category); self.prove_predicate(predicate, locations, category); } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 6a63eda4b993d..37aaeb30bac17 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -90,13 +90,13 @@ fn make_mir_scope<'ll, 'tcx>( let file_metadata = file_metadata(cx, &loc.file); let parent_dbg_scope = match scope_data.inlined { - Some((callee, _)) => { + Some(callee) => { // FIXME(eddyb) this would be `self.monomorphize(&callee)` // if this is moved to `rustc_codegen_ssa::mir::debuginfo`. let callee = cx.tcx.instantiate_and_normalize_erasing_regions( instance.args, ty::ParamEnv::reveal_all(), - ty::EarlyBinder::bind(callee), + ty::EarlyBinder::bind(callee.node), ); debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| { let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); @@ -116,11 +116,11 @@ fn make_mir_scope<'ll, 'tcx>( ) }; - let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { + let inlined_at = scope_data.inlined.map(|callee| { // FIXME(eddyb) this doesn't account for the macro-related // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does. - let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span); - cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span) + let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callee.span); + cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callee.span) }); debug_context.scopes[scope] = DebugScope { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 07cab5e3400ef..ee57a8295f233 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1165,9 +1165,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // If the stacktrace passes through MIR-inlined source scopes, add them. let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc); let mut scope_data = &frame.body.source_scopes[scope]; - while let Some((instance, call_span)) = scope_data.inlined { - frames.push(FrameInfo { span, instance }); - span = call_span; + while let Some(instance) = scope_data.inlined { + frames.push(FrameInfo { span, instance: instance.node }); + span = instance.span; scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()]; } span diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 2fcb45ef8aa12..54fb5e4ecf8ef 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1057,7 +1057,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx, predicates .iter() - .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))), + .filter_map(|p| Some(p.node.as_trait_clause()?.map_bound(|t| t.trait_ref))), assoc_name, ) }, diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 00ff3f836adf3..f16c1b4100259 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -57,15 +57,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut trait_bounds = vec![]; let mut projection_bounds = vec![]; - for (pred, span) in bounds.clauses() { - let bound_pred = pred.kind(); + for pred in bounds.clauses() { + let bound_pred = pred.node.kind(); match bound_pred.skip_binder() { ty::ClauseKind::Trait(trait_pred) => { assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive); - trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span)); + trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), pred.span)); } ty::ClauseKind::Projection(proj) => { - projection_bounds.push((bound_pred.rebind(proj), span)); + projection_bounds.push((bound_pred.rebind(proj), pred.span)); } ty::ClauseKind::TypeOutlives(_) => { // Do nothing, we deal with regions separately diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index b6688e0ce29e0..f2dbd77aeebaf 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -23,7 +23,7 @@ use rustc_span::Span; /// include the self type (e.g., `trait_bounds`) but in others we do not #[derive(Default, PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { - pub clauses: Vec<(ty::Clause<'tcx>, Span)>, + pub clauses: Vec>>, } impl<'tcx> Bounds<'tcx> { @@ -33,8 +33,10 @@ impl<'tcx> Bounds<'tcx> { region: ty::PolyTypeOutlivesPredicate<'tcx>, span: Span, ) { - self.clauses - .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).to_predicate(tcx), span)); + self.clauses.push(ty::Spanned { + node: region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).to_predicate(tcx), + span, + }); } pub fn push_trait_bound( @@ -72,14 +74,14 @@ impl<'tcx> Bounds<'tcx> { span: Span, polarity: ty::ImplPolarity, ) { - self.clauses.push(( - trait_ref + self.clauses.push(ty::Spanned { + node: trait_ref .map_bound(|trait_ref| { ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity }) }) .to_predicate(tcx), span, - )); + }); } pub fn push_projection_bound( @@ -88,20 +90,20 @@ impl<'tcx> Bounds<'tcx> { projection: ty::PolyProjectionPredicate<'tcx>, span: Span, ) { - self.clauses.push(( - projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).to_predicate(tcx), + self.clauses.push(ty::Spanned { + node: projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).to_predicate(tcx), span, - )); + }); } pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) { let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span)); let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]); // Preferable to put this obligation first, since we report better errors for sized ambiguity. - self.clauses.insert(0, (trait_ref.to_predicate(tcx), span)); + self.clauses.insert(0, ty::Spanned { node: trait_ref.to_predicate(tcx), span }); } - pub fn clauses(&self) -> impl Iterator, Span)> + '_ { + pub fn clauses(&self) -> impl Iterator>> + '_ { self.clauses.iter().cloned() } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 857515f971a85..7206a09c4f5db 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -222,7 +222,7 @@ fn compare_method_predicate_entailment<'tcx>( hybrid_preds.predicates.extend( trait_m_predicates .instantiate_own(tcx, trait_to_placeholder_args) - .map(|(predicate, _)| predicate), + .map(|predicate| predicate.node), ); // Construct trait parameter environment and then shift it into the placeholder viewpoint. @@ -238,7 +238,7 @@ fn compare_method_predicate_entailment<'tcx>( debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_args); - for (predicate, span) in impl_m_own_bounds { + for ty::Spanned { node: predicate, span } in impl_m_own_bounds { let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id); let predicate = ocx.normalize(&normalize_cause, param_env, predicate); @@ -691,7 +691,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( .instantiate_identity(tcx) .into_iter() .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_to_placeholder_args)) - .map(|(clause, _)| clause); + .map(|clause| clause.node); let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( tcx, @@ -1009,7 +1009,7 @@ impl<'tcx> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx> { }); self.types.insert(proj.def_id, (infer_ty, proj.args)); // Recurse into bounds - for (pred, pred_span) in self + for ty::Spanned { node: pred, span: pred_span } in self .interner() .explicit_item_bounds(proj.def_id) .iter_instantiated_copied(self.interner(), proj.args) @@ -1963,7 +1963,7 @@ fn compare_const_predicate_entailment<'tcx>( hybrid_preds.predicates.extend( trait_ct_predicates .instantiate_own(tcx, trait_to_impl_args) - .map(|(predicate, _)| predicate), + .map(|predicate| predicate.node), ); let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); @@ -1977,7 +1977,7 @@ fn compare_const_predicate_entailment<'tcx>( let ocx = ObligationCtxt::new(&infcx); let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args); - for (predicate, span) in impl_ct_own_bounds { + for ty::Spanned { node: predicate, span } in impl_ct_own_bounds { let cause = ObligationCause::misc(span, impl_ct_def_id); let predicate = ocx.normalize(&cause, param_env, predicate); @@ -2098,7 +2098,7 @@ fn compare_type_predicate_entailment<'tcx>( hybrid_preds.predicates.extend( trait_ty_predicates .instantiate_own(tcx, trait_to_impl_args) - .map(|(predicate, _)| predicate), + .map(|predicate| predicate.node), ); debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); @@ -2112,7 +2112,7 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); - for (predicate, span) in impl_ty_own_bounds { + for ty::Spanned { node: predicate, span } in impl_ty_own_bounds { let cause = ObligationCause::misc(span, impl_ty_def_id); let predicate = ocx.normalize(&cause, param_env, predicate); @@ -2210,9 +2210,14 @@ pub(super) fn check_type_bounds<'tcx>( let obligations: Vec<_> = tcx .explicit_item_bounds(trait_ty.def_id) .iter_instantiated_copied(tcx, rebased_args) - .map(|(concrete_ty_bound, span)| { - debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); - traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound) + .map(|concrete_ty_bound| { + debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound.node); + traits::Obligation::new( + tcx, + mk_cause(concrete_ty_bound.span), + param_env, + concrete_ty_bound.node, + ) }) .collect(); debug!("check_type_bounds: item_bounds={:?}", obligations); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index bc5029a1d5e47..58706eb584743 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -123,7 +123,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( .instantiate_identity(tcx) .into_iter() .chain(tcx.predicates_of(trait_m.def_id).instantiate_own(tcx, trait_m_to_impl_m_args)) - .map(|(clause, _)| clause); + .map(|clause| clause.node); let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy()); @@ -193,14 +193,14 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( // too, since we *do not* use the trait solver to prove that the RPITIT's // bounds are not stronger -- we're doing a simple, syntactic compatibility // check between bounds. This is strictly forwards compatible, though. - for (clause, span) in impl_bounds { - if !trait_bounds.contains(&clause) { + for clause in impl_bounds { + if !trait_bounds.contains(&clause.node) { report_mismatched_rpitit_signature( tcx, trait_m_sig_with_self_for_diag, trait_m.def_id, impl_m.def_id, - Some(span), + Some(clause.span), ); return; } @@ -220,12 +220,12 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitCollector<'tcx> { && self.tcx.is_impl_trait_in_trait(proj.def_id) { if self.types.insert(proj) { - for (pred, _) in self + for pred in self .tcx .explicit_item_bounds(proj.def_id) .iter_instantiated_copied(self.tcx, proj.args) { - pred.visit_with(self)?; + pred.node.visit_with(self)?; } } ControlFlow::Continue(()) @@ -267,7 +267,7 @@ fn report_mismatched_rpitit_signature<'tcx>( let Some(future_output_ty) = tcx .explicit_item_bounds(future_ty.def_id) .iter_instantiated_copied(tcx, future_ty.args) - .find_map(|(clause, _)| match clause.kind().no_bound_vars()? { + .find_map(|clause| match clause.node.kind().no_bound_vars()? { ty::ClauseKind::Projection(proj) => proj.term.ty(), _ => None, }) diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index dda3f7425697b..f3de3e1db7653 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -132,7 +132,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let param_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args); - for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) { + for ty::Spanned { node: pred, span } in + tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) + { let normalize_cause = traits::ObligationCause::misc(span, adt_def_id); let pred = ocx.normalize(&normalize_cause, param_env, pred); let cause = traits::ObligationCause::new(span, adt_def_id, traits::DropImpl); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 15c5558fc0b0c..d4d630c2175ef 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -305,13 +305,13 @@ fn default_body_is_unstable( /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, - predicates: impl IntoIterator, Span)>, + predicates: impl IntoIterator>>, ) -> (String, String) { let mut types: FxHashMap, Vec> = FxHashMap::default(); let mut projections = vec![]; - for (predicate, _) in predicates { - debug!("predicate {:?}", predicate); - let bound_predicate = predicate.kind(); + for predicate in predicates { + debug!("predicate {:?}", predicate.node); + let bound_predicate = predicate.node.kind(); match bound_predicate.skip_binder() { ty::ClauseKind::Trait(trait_predicate) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); @@ -382,7 +382,7 @@ fn fn_sig_suggestion<'tcx>( tcx: TyCtxt<'tcx>, sig: ty::FnSig<'tcx>, ident: Ident, - predicates: impl IntoIterator, Span)>, + predicates: impl IntoIterator>>, assoc: ty::AssocItem, ) -> String { let args = sig @@ -429,7 +429,7 @@ fn fn_sig_suggestion<'tcx>( output = if let ty::Alias(_, alias_ty) = *output.kind() { tcx.explicit_item_bounds(alias_ty.def_id) .iter_instantiated_copied(tcx, alias_ty.args) - .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty()) + .find_map(|bound| bound.node.as_projection_clause()?.no_bound_vars()?.term.ty()) .unwrap_or_else(|| { span_bug!( ident.span, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f5784e5fb8662..2a06f50cc75cd 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1144,17 +1144,16 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); - let wf_obligations = - bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| { - let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::clause_obligations( - wfcx.infcx, - wfcx.param_env, - wfcx.body_def_id, - normalized_bound, - bound_span, - ) - }); + let wf_obligations = bounds.instantiate_identity_iter_copied().flat_map(|bound| { + let normalized_bound = wfcx.normalize(span, None, bound.node); + traits::wf::clause_obligations( + wfcx.infcx, + wfcx.param_env, + wfcx.body_def_id, + normalized_bound, + bound.span, + ) + }); wfcx.register_obligations(wf_obligations); } @@ -1396,7 +1395,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let default_obligations = predicates .predicates .iter() - .flat_map(|&(pred, sp)| { + .flat_map(|&pred| { #[derive(Default)] struct CountParams { params: FxHashSet, @@ -1423,18 +1422,18 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } } let mut param_count = CountParams::default(); - let has_region = pred.visit_with(&mut param_count).is_break(); - let substituted_pred = ty::EarlyBinder::bind(pred).instantiate(tcx, args); + let has_region = pred.node.visit_with(&mut param_count).is_break(); + let substituted_pred = ty::EarlyBinder::bind(pred.node).instantiate(tcx, args); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region { None - } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) { + } else if predicates.predicates.iter().any(|&p| p.node == substituted_pred) { // Avoid duplication of predicates that contain no parameters, for example. None } else { - Some((substituted_pred, sp)) + Some((substituted_pred, pred.span)) } }) .map(|(pred, sp)| { @@ -1462,8 +1461,8 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); - let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| { - traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp) + let wf_obligations = predicates.into_iter().flat_map(|p| { + traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p.node, p.span) }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); wfcx.register_obligations(obligations); @@ -1869,7 +1868,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { // Check elaborated bounds. let implied_obligations = traits::elaborate(tcx, predicates_with_span); - for (pred, obligation_span) in implied_obligations { + for ty::Spanned { node: pred, span: obligation_span } in implied_obligations { // We lower empty bounds like `Vec:` as // `WellFormed(Vec)`, which will later get checked by // regular WF checking diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 9636c6144461b..d769ec28c77b2 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1493,8 +1493,9 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate "predicates_defined_on: inferred_outlives_of({:?}) = {:?}", def_id, inferred_outlives, ); - let inferred_outlives_iter = - inferred_outlives.iter().map(|(clause, span)| ((*clause).to_predicate(tcx), *span)); + let inferred_outlives_iter = inferred_outlives + .iter() + .map(|(clause, span)| ty::Spanned { node: (*clause).to_predicate(tcx), span: *span }); if result.predicates.is_empty() { result.predicates = tcx.arena.alloc_from_iter(inferred_outlives_iter); } else { diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index d746e6dea7553..692951cd534b7 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -19,7 +19,7 @@ fn associated_type_bounds<'tcx>( assoc_item_def_id: LocalDefId, ast_bounds: &'tcx [hir::GenericBound<'tcx>], span: Span, -) -> &'tcx [(ty::Clause<'tcx>, Span)] { +) -> &'tcx [ty::Spanned>] { let item_ty = Ty::new_projection( tcx, assoc_item_def_id.to_def_id(), @@ -34,17 +34,15 @@ fn associated_type_bounds<'tcx>( let trait_def_id = tcx.local_parent(assoc_item_def_id); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id); - let bounds_from_parent = trait_predicates - .predicates - .iter() - .copied() - .filter(|(pred, _)| match pred.kind().skip_binder() { - ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty, - ty::ClauseKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty, - ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty, - _ => false, - }) - .map(|(clause, span)| (clause, span)); + let bounds_from_parent = + trait_predicates.predicates.iter().copied().filter(|pred| { + match pred.node.kind().skip_binder() { + ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty, + ty::ClauseKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty, + ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty, + _ => false, + } + }); let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent)); debug!( @@ -66,7 +64,7 @@ fn opaque_type_bounds<'tcx>( ast_bounds: &'tcx [hir::GenericBound<'tcx>], item_ty: Ty<'tcx>, span: Span, -) -> &'tcx [(ty::Clause<'tcx>, Span)] { +) -> &'tcx [ty::Spanned>] { ty::print::with_no_queries!({ let icx = ItemCtxt::new(tcx, opaque_def_id); let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All); @@ -81,7 +79,7 @@ fn opaque_type_bounds<'tcx>( pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> { +) -> ty::EarlyBinder<&'_ [ty::Spanned>]> { match tcx.opt_rpitit_info(def_id.to_def_id()) { // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. @@ -153,7 +151,7 @@ pub(super) fn item_bounds( def_id: DefId, ) -> ty::EarlyBinder<&'_ ty::List>> { tcx.explicit_item_bounds(def_id).map_bound(|bounds| { - tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound))) + tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&bound| bound.node))) }) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 104da581e019d..f344d43221789 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{sym, DUMMY_SP}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus @@ -41,8 +41,8 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) { // when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound, // because only implementing `Self: Trait<.., false>` is currently not possible. - Some(( - ty::TraitRef::new( + Some(ty::Spanned { + node: ty::TraitRef::new( tcx, def_id, ty::GenericArgs::for_item(tcx, def_id, |param, _| { @@ -55,7 +55,7 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic ) .to_predicate(tcx), span, - )) + }) } else { None }; @@ -64,10 +64,10 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic .predicates .iter() .copied() - .chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), + .chain(std::iter::once(ty::Spanned { + node: ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), span, - ))) + })) .chain(non_const_bound), ); } @@ -147,7 +147,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We use an `IndexSet` to preserve order of insertion. // Preserving the order of insertion is important here so as not to break UI tests. - let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default(); + let mut predicates: FxIndexSet>> = FxIndexSet::default(); let ast_generics = match node { Node::TraitItem(item) => item.generics, @@ -211,7 +211,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { - predicates.insert((trait_ref.to_predicate(tcx), tcx.def_span(def_id))); + predicates + .insert(ty::Spanned { node: trait_ref.to_predicate(tcx), span: tcx.def_span(def_id) }); } // Collect the predicates that were written inline by the user on each @@ -242,10 +243,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen .no_bound_vars() .expect("const parameters cannot be generic"); let ct = icx.astconv().hir_id_to_bound_const(param.hir_id, ct_ty); - predicates.insert(( - ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx), - param.span, - )); + predicates.insert(ty::Spanned { + node: ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx), + span: param.span, + }); } } } @@ -274,7 +275,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen ty::ClauseKind::WellFormed(ty.into()), bound_vars, ); - predicates.insert((predicate.to_predicate(tcx), span)); + predicates.insert(ty::Spanned { node: predicate.to_predicate(tcx), span }); } } @@ -300,7 +301,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen }; let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) .to_predicate(tcx); - (pred, span) + ty::Spanned { node: pred, span } })) } @@ -358,7 +359,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen fn compute_bidirectional_outlives_predicates<'tcx>( tcx: TyCtxt<'tcx>, opaque_own_params: &[ty::GenericParamDef], - predicates: &mut Vec<(ty::Clause<'tcx>, Span)>, + predicates: &mut Vec>>, ) { for param in opaque_own_params { let orig_lifetime = tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()); @@ -368,16 +369,22 @@ fn compute_bidirectional_outlives_predicates<'tcx>( ty::EarlyBoundRegion { def_id: param.def_id, index: param.index, name: param.name }, ); let span = tcx.def_span(param.def_id); - predicates.push(( - ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_lifetime, dup_lifetime)) - .to_predicate(tcx), + predicates.push(ty::Spanned { + node: ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( + orig_lifetime, + dup_lifetime, + )) + .to_predicate(tcx), span, - )); - predicates.push(( - ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_lifetime, orig_lifetime)) - .to_predicate(tcx), + }); + predicates.push(ty::Spanned { + node: ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( + dup_lifetime, + orig_lifetime, + )) + .to_predicate(tcx), span, - )); + }); } } } @@ -385,10 +392,10 @@ fn compute_bidirectional_outlives_predicates<'tcx>( fn const_evaluatable_predicates_of( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> FxIndexSet<(ty::Clause<'_>, Span)> { +) -> FxIndexSet>> { struct ConstCollector<'tcx> { tcx: TyCtxt<'tcx>, - preds: FxIndexSet<(ty::Clause<'tcx>, Span)>, + preds: FxIndexSet>>, } impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { @@ -396,8 +403,10 @@ fn const_evaluatable_predicates_of( let ct = ty::Const::from_anon_const(self.tcx, c.def_id); if let ty::ConstKind::Unevaluated(_) = ct.kind() { let span = self.tcx.def_span(c.def_id); - self.preds - .insert((ty::ClauseKind::ConstEvaluatable(ct).to_predicate(self.tcx), span)); + self.preds.insert(ty::Spanned { + node: ty::ClauseKind::ConstEvaluatable(ct).to_predicate(self.tcx), + span, + }); } } @@ -486,7 +495,7 @@ pub(super) fn explicit_predicates_of<'tcx>( .predicates .iter() .copied() - .filter(|(pred, _)| match pred.kind().skip_binder() { + .filter(|pred| match pred.node.kind().skip_binder() { ty::ClauseKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()), ty::ClauseKind::Projection(proj) => !is_assoc_item_ty(proj.projection_ty.self_ty()), ty::ClauseKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0), @@ -529,8 +538,10 @@ pub(super) fn explicit_predicates_of<'tcx>( let filtered_predicates = parent_preds .predicates .into_iter() - .filter(|(pred, _)| { - if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() { + .filter(|pred| { + if let ty::ClauseKind::ConstArgHasType(ct, _) = + pred.node.kind().skip_binder() + { match ct.kind() { ty::ConstKind::Param(param_const) => { let defaulted_param_idx = tcx @@ -664,12 +675,12 @@ pub(super) fn implied_predicates_with_filter( // turn, reach indirect supertraits, so we detect cycles now instead of // overflowing during elaboration. if matches!(filter, PredicateFilter::SelfOnly) { - for &(pred, span) in implied_bounds { - debug!("superbound: {:?}", pred); - if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder() + for pred in implied_bounds { + debug!("superbound: {:?}", pred.node); + if let ty::ClauseKind::Trait(bound) = pred.node.kind().skip_binder() && bound.polarity == ty::ImplPolarity::Positive { - tcx.at(span).super_predicates_of(bound.def_id()); + tcx.at(pred.span).super_predicates_of(bound.def_id()); } } } @@ -737,7 +748,10 @@ pub(super) fn type_param_predicates( if param_id == item_hir_id { let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id.to_def_id()); - extend = Some((identity_trait_ref.to_predicate(tcx), item.span)); + extend = Some(ty::Spanned { + node: identity_trait_ref.to_predicate(tcx), + span: item.span, + }); } generics } @@ -762,7 +776,7 @@ pub(super) fn type_param_predicates( PredicateFilter::SelfThatDefines(assoc_name), ) .into_iter() - .filter(|(predicate, _)| match predicate.kind().skip_binder() { + .filter(|predicate| match predicate.node.kind().skip_binder() { ty::ClauseKind::Trait(data) => data.self_ty().is_param(index), _ => false, }), @@ -784,7 +798,7 @@ impl<'tcx> ItemCtxt<'tcx> { param_def_id: LocalDefId, ty: Ty<'tcx>, filter: PredicateFilter, - ) -> Vec<(ty::Clause<'tcx>, Span)> { + ) -> Vec>> { let mut bounds = Bounds::default(); for predicate in ast_generics.predicates { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 6424d1c793112..68794c4ed82d2 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1802,8 +1802,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { break Some((bound_vars.into_iter().collect(), assoc_item)); } let predicates = tcx.super_predicates_that_define_assoc_item((def_id, assoc_name)); - let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { - let bound_predicate = pred.kind(); + let obligations = predicates.predicates.iter().filter_map(|&pred| { + let bound_predicate = pred.node.kind(); match bound_predicate.skip_binder() { ty::ClauseKind::Trait(data) => { // The order here needs to match what we would get from `subst_supertrait` diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index ed5e9dd2b5add..af872addfea0f 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -1,7 +1,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::Span; use std::ops::ControlFlow; #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -151,7 +150,7 @@ pub fn identify_constrained_generic_params<'tcx>( /// think of any. pub fn setup_constraining_predicates<'tcx>( tcx: TyCtxt<'tcx>, - predicates: &mut [(ty::Clause<'tcx>, Span)], + predicates: &mut [ty::Spanned>], impl_trait_ref: Option>, input_parameters: &mut FxHashSet, ) { @@ -187,7 +186,8 @@ pub fn setup_constraining_predicates<'tcx>( for j in i..predicates.len() { // Note that we don't have to care about binders here, // as the impl trait ref never contains any late-bound regions. - if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() { + if let ty::ClauseKind::Projection(projection) = predicates[j].node.kind().skip_binder() + { // Special case: watch out for some kind of sneaky attempt // to project out an associated type defined by this very // trait. diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 7941861fd2f7d..492e634e34856 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -235,8 +235,8 @@ fn unconstrained_parent_impl_args<'tcx>( // what we want here. We want only a list of constrained parameters while // the functions in `cgp` add the constrained parameters to a list of // unconstrained parameters. - for (clause, _) in impl_generic_predicates.predicates.iter() { - if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder() { + for clause in impl_generic_predicates.predicates.iter() { + if let ty::ClauseKind::Projection(proj) = clause.node.kind().skip_binder() { let projection_ty = proj.projection_ty; let projected_ty = proj.term; @@ -354,7 +354,7 @@ fn check_predicates<'tcx>( tcx.predicates_of(impl2_node.def_id()) .instantiate(tcx, impl2_args) .into_iter() - .map(|(c, _s)| c.as_predicate()), + .map(|c| c.node.as_predicate()), ) .collect() }; @@ -378,13 +378,13 @@ fn check_predicates<'tcx>( let always_applicable_traits = impl1_predicates .iter() .copied() - .filter(|&(clause, _span)| { + .filter(|&clause| { matches!( - trait_specialization_kind(tcx, clause), + trait_specialization_kind(tcx, clause.node), Some(TraitSpecializationKind::AlwaysApplicable) ) }) - .map(|(c, _span)| c.as_predicate()); + .map(|c| c.node.as_predicate()); // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity().args { @@ -399,12 +399,12 @@ fn check_predicates<'tcx>( } impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits)); - for (clause, span) in impl1_predicates { + for clause in impl1_predicates { if !impl2_predicates .iter() - .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span)) + .any(|pred2| trait_predicates_eq(tcx, clause.node.as_predicate(), *pred2, clause.span)) { - check_specialization_on(tcx, clause, span) + check_specialization_on(tcx, clause.node, clause.span) } } } diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index a7fca41f86aca..453e66f10e6e8 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -28,14 +28,14 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { let mut required_predicates = RequiredPredicates::default(); // process predicates and convert to `RequiredPredicates` entry, see below - for &(predicate, span) in predicates.predicates { - match predicate.kind().skip_binder() { + for predicate in predicates.predicates { + match predicate.node.kind().skip_binder() { ty::ClauseKind::TypeOutlives(OutlivesPredicate(ty, reg)) => { insert_outlives_predicate( tcx, ty.into(), reg, - span, + predicate.span, &mut required_predicates, ) } @@ -45,7 +45,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { tcx, reg1.into(), reg2, - span, + predicate.span, &mut required_predicates, ) } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 9fb39a0e93b6c..221ed5a710b5b 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -158,15 +158,15 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc let mut collector = OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances }; let id_args = ty::GenericArgs::identity_for_item(tcx, item_def_id); - for (pred, _) in tcx.explicit_item_bounds(item_def_id).iter_instantiated_copied(tcx, id_args) { - debug!(?pred); + for pred in tcx.explicit_item_bounds(item_def_id).iter_instantiated_copied(tcx, id_args) { + debug!(?pred.node); // We only ignore opaque type args if the opaque type is the outermost type. // The opaque type may be nested within itself via recursion in e.g. // type Foo<'a> = impl PartialEq>; // which thus mentions `'a` and should thus accept hidden types that borrow 'a // instead of requiring an additional `+ 'a`. - match pred.kind().skip_binder() { + match pred.node.kind().skip_binder() { ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: ty::TraitRef { def_id: _, args, .. }, polarity: _, @@ -188,7 +188,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc region.visit_with(&mut collector); } _ => { - pred.visit_with(&mut collector); + pred.node.visit_with(&mut collector); } } } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 84e986488a6a4..57bf347082b5d 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -537,12 +537,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } for ty in [first_ty, second_ty] { - for (clause, _) in self + for clause in self .tcx .explicit_item_bounds(rpit_def_id) .iter_instantiated_copied(self.tcx, args) { - let pred = clause.kind().rebind(match clause.kind().skip_binder() { + let pred = clause.node.kind().rebind(match clause.node.kind().skip_binder() { ty::ClauseKind::Trait(trait_pred) => { assert!(matches!( *trait_pred.trait_ref.self_ty().kind(), diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 6b6d1574b2bf6..ab2ae56b29925 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -385,21 +385,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) { let predicates = self.tcx.predicates_of(def_id); let predicates = predicates.instantiate(self.tcx, args); - for (predicate, predicate_span) in predicates { + for predicate in predicates { let obligation = Obligation::new( self.tcx, ObligationCause::dummy_with_span(callee_expr.span), self.param_env, - predicate, + predicate.node, ); let result = self.evaluate_obligation(&obligation); self.tcx .sess .struct_span_err( callee_expr.span, - format!("evaluate({predicate:?}) = {result:?}"), + format!("evaluate({:?}) = {result:?}", predicate.node), ) - .span_label(predicate_span, "predicate") + .span_label(predicate.span, "predicate") .emit(); } } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index a70ead8e57d60..cb57052aa761f 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -179,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx .explicit_item_bounds(def_id) .iter_instantiated_copied(self.tcx, args) - .map(|(c, s)| (c.as_predicate(), s)), + .map(|c| ty::Spanned { node: c.node.as_predicate(), span: c.span }), ), ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { @@ -193,7 +193,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates( Ty::new_var(self.tcx, self.root_var(vid)), - self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)), + self.obligations_for_self_ty(vid) + .map(|obl| ty::Spanned { node: obl.predicate, span: obl.cause.span }), ), ty::FnPtr(sig) => { let expected_sig = ExpectedSig { cause_span: None, sig }; @@ -206,12 +207,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn deduce_closure_signature_from_predicates( &self, expected_ty: Ty<'tcx>, - predicates: impl DoubleEndedIterator, Span)>, + predicates: impl DoubleEndedIterator>>, ) -> (Option>, Option) { let mut expected_sig = None; let mut expected_kind = None; - for (pred, span) in traits::elaborate( + for pred in traits::elaborate( self.tcx, // Reverse the obligations here, since `elaborate_*` uses a stack, // and we want to keep inference generally in the same order of @@ -221,8 +222,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We only care about self bounds .filter_only_self() { - debug!(?pred); - let bound_predicate = pred.kind(); + debug!(?pred.node); + let bound_predicate = pred.node.kind(); // Given a Projection predicate, we can potentially infer // the complete signature. @@ -231,9 +232,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_predicate.skip_binder() { let inferred_sig = self.normalize( - span, + pred.span, self.deduce_sig_from_projection( - Some(span), + Some(pred.span), bound_predicate.rebind(proj_predicate), ), ); @@ -727,7 +728,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .explicit_item_bounds(def_id) .iter_instantiated_copied(self.tcx, args) - .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, + .find_map(|p| get_future_output(p.node.as_predicate(), p.span))?, ty::Error(_) => return None, _ => span_bug!( closure_span, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9f439a2b32aaf..4576183b67624 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -925,7 +925,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let new_cause = ObligationCause::new( cause.span, cause.body_id, - ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))), + ObligationCauseCode::OpaqueReturnType(Some(ty::Spanned { + node: return_expr_ty, + span, + })), ); *cause = new_cause; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index facbeb8badfac..669ef60dbfb56 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -603,7 +603,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Err(expr); } - match impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder() { + match impl_predicates.predicates[impl_predicate_index].node.kind().skip_binder() { ty::ClauseKind::Trait(broken_trait) => { // ... self.blame_specific_part_of_expr_corresponding_to_generic_param( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 33dfa16a651fb..331d749c9839b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1995,12 +1995,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(compiler-errors): This could be problematic if something has two // fn-like predicates with different args, but callable types really never // do that, so it's OK. - for (predicate, span) in instantiated { - if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder() + for predicate in instantiated { + if let ty::ClauseKind::Trait(pred) = predicate.node.kind().skip_binder() && pred.self_ty().peel_refs() == callee_ty && self.tcx.is_fn_trait(pred.def_id()) { - err.span_note(span, "callable defined here"); + err.span_note(predicate.span, "callable defined here"); return; } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index e93d180fc139e..583b3646b634c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -227,7 +227,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { self.param_env.caller_bounds().iter().filter_map(|predicate| { match predicate.kind().skip_binder() { ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => { - Some((predicate, span)) + Some(ty::Spanned { node: predicate, span }) } _ => None, } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 7c73f6a89cdb2..838d7a04eb98c 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -613,7 +613,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ty::ClauseKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => { let span = predicates .iter() - .find_map(|(p, span)| if p == pred { Some(span) } else { None }) + .find_map(|p| (p.node == pred).then_some(p.span)) .unwrap_or(rustc_span::DUMMY_SP); Some((trait_pred, span)) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 26d071a01397a..1e83aa5cdb28a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -407,8 +407,9 @@ impl<'tcx> InferCtxt<'tcx> { let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; self.tcx.explicit_item_bounds(def_id).iter_instantiated_copied(self.tcx, args).find_map( - |(predicate, _)| { + |predicate| { predicate + .node .kind() .map_bound(|kind| match kind { ty::ClauseKind::Projection(projection_predicate) diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 8d3cd23b7fa51..a8e08c7908009 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -316,18 +316,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id) .rebase_onto(self.tcx, impl_def_id, trait_args); - let Ok(trait_predicates) = - self.tcx - .explicit_predicates_of(trait_item_def_id) - .instantiate_own(self.tcx, trait_item_args) - .map(|(pred, _)| { - if pred.is_suggestable(self.tcx, false) { - Ok(pred.to_string()) - } else { - Err(()) - } - }) - .collect::, ()>>() + let Ok(trait_predicates) = self + .tcx + .explicit_predicates_of(trait_item_def_id) + .instantiate_own(self.tcx, trait_item_args) + .map(|pred| { + if pred.node.is_suggestable(self.tcx, false) { + Ok(pred.node.to_string()) + } else { + Err(()) + } + }) + .collect::, ()>>() else { return; }; diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 7a5dec22fe049..b11059a68a4b9 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -597,8 +597,8 @@ impl<'tcx> InferCtxt<'tcx> { let tcx = self.tcx; let item_bounds = tcx.explicit_item_bounds(def_id); - for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) { - let predicate = predicate.fold_with(&mut BottomUpFolder { + for predicate in item_bounds.iter_instantiated_copied(tcx, args) { + let predicate = predicate.node.fold_with(&mut BottomUpFolder { tcx, ty_op: |ty| match *ty.kind() { // We can't normalize associated types from `rustc_infer`, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 3c566e0dd6da6..9d444a84d1ce8 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -3,7 +3,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{self, Obligation, PredicateObligation}; use rustc_data_structures::fx::FxHashSet; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, Spanned, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -165,6 +165,26 @@ impl<'tcx> Elaboratable<'tcx> for ty::Predicate<'tcx> { } } +impl<'tcx> Elaboratable<'tcx> for ty::Spanned> { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.node + } + + fn child(&self, clause: ty::Clause<'tcx>) -> Self { + ty::Spanned { node: clause.as_predicate(), span: self.span } + } + + fn child_with_derived_cause( + &self, + clause: ty::Clause<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + ty::Spanned { node: clause.as_predicate(), span: self.span } + } +} + impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) { fn predicate(&self) -> ty::Predicate<'tcx> { self.0 @@ -185,6 +205,26 @@ impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) { } } +impl<'tcx> Elaboratable<'tcx> for Spanned> { + fn predicate(&self) -> ty::Predicate<'tcx> { + self.node.as_predicate() + } + + fn child(&self, clause: ty::Clause<'tcx>) -> Self { + Spanned { node: clause, span: self.span } + } + + fn child_with_derived_cause( + &self, + clause: ty::Clause<'tcx>, + _span: Span, + _parent_trait_pred: ty::PolyTraitPredicate<'tcx>, + _index: usize, + ) -> Self { + Spanned { node: clause, span: self.span } + } +} + impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) { fn predicate(&self) -> ty::Predicate<'tcx> { self.0.as_predicate() @@ -277,15 +317,16 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { } }; - let obligations = - predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| { + let obligations = predicates.predicates.iter().enumerate().map( + |(index, &Spanned { node: clause, span })| { elaboratable.child_with_derived_cause( clause.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)), span, bound_predicate.rebind(data), index, ) - }); + }, + ); debug!(?data, ?obligations, "super_predicates"); self.extend_deduped(obligations); } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6f6150a4172f5..4835bf9ef0db3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1600,8 +1600,8 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { if cx.tcx.features().trivial_bounds { let predicates = cx.tcx.predicates_of(item.owner_id); - for &(predicate, span) in predicates.predicates { - let predicate_kind_name = match predicate.kind().skip_binder() { + for &predicate in predicates.predicates { + let predicate_kind_name = match predicate.node.kind().skip_binder() { ClauseKind::Trait(..) => "trait", ClauseKind::TypeOutlives(..) | ClauseKind::RegionOutlives(..) => "lifetime", @@ -1616,11 +1616,11 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { // FIXME(generic_const_exprs): `ConstEvaluatable` can be written | ClauseKind::ConstEvaluatable(..) => continue, }; - if predicate.is_global() { + if predicate.node.is_global() { cx.emit_spanned_lint( TRIVIAL_BOUNDS, - span, - BuiltinTrivialBounds { predicate_kind_name, predicate }, + predicate.span, + BuiltinTrivialBounds { predicate_kind_name, predicate: predicate.node }, ); } } diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index dfefaf82fd7da..af82045427277 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { .super_predicates_of(def_id) .predicates .into_iter() - .filter_map(|(pred, _)| pred.as_trait_clause()); + .filter_map(|pred| pred.node.as_trait_clause()); if direct_super_traits_iter.count() > 1 { cx.emit_spanned_lint( MULTIPLE_SUPERTRAIT_UPCASTABLE, diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index c24846ca93988..8404ef3a2f288 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -74,10 +74,8 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds // of the associated type. - for (pred, pred_span) in - cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() - { - let predicate = infcx.instantiate_binder_with_placeholders(pred.kind()); + for pred in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() { + let predicate = infcx.instantiate_binder_with_placeholders(pred.node.kind()); let ty::ClauseKind::Projection(proj) = predicate else { continue; }; @@ -110,12 +108,12 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // For example, in `impl Trait`, for all of the bounds on `Assoc`, // e.g. `type Assoc: OtherTrait`, replace `::Assoc: OtherTrait` // with `impl Send: OtherTrait`. - for (assoc_pred, assoc_pred_span) in cx + for assoc_pred_spanned in cx .tcx .explicit_item_bounds(proj.projection_ty.def_id) .iter_instantiated_copied(cx.tcx, &proj.projection_ty.args) { - let assoc_pred = assoc_pred.fold_with(proj_replacer); + let assoc_pred = assoc_pred_spanned.node.fold_with(proj_replacer); let Ok(assoc_pred) = traits::fully_normalize( infcx, traits::ObligationCause::dummy(), @@ -147,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { }; cx.emit_spanned_lint( OPAQUE_HIDDEN_INFERRED_BOUND, - pred_span, + pred.span, OpaqueHiddenInferredBoundLint { ty: Ty::new_opaque( cx.tcx, @@ -155,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { ty::GenericArgs::identity_for_item(cx.tcx, def_id), ), proj_ty: proj_term, - assoc_pred_span, + assoc_pred_span: assoc_pred_spanned.span, add_bound, }, ); diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index e812493b3dd39..dc5c6a9af1a19 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -90,8 +90,8 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { use rustc_middle::ty::ClauseKind; let predicates = cx.tcx.explicit_predicates_of(item.owner_id); - for &(predicate, span) in predicates.predicates { - let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { + for &predicate in predicates.predicates { + let ClauseKind::Trait(trait_predicate) = predicate.node.kind().skip_binder() else { continue; }; let def_id = trait_predicate.trait_ref.def_id; @@ -103,8 +103,8 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; cx.emit_spanned_lint( DROP_BOUNDS, - span, - DropTraitConstraintsDiag { predicate, tcx: cx.tcx, def_id }, + predicate.span, + DropTraitConstraintsDiag { predicate: predicate.node, tcx: cx.tcx, def_id }, ); } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 355855b8e2b3e..657f9e5515bdd 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -292,10 +292,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ) // We only care about self bounds for the impl-trait .filter_only_self() - .find_map(|(pred, _span)| { + .find_map(|pred| { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::ClauseKind::Trait(ref poly_trait_predicate) = - pred.kind().skip_binder() + pred.node.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 354023cea9e07..3c7a8bf6689b5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -663,6 +663,12 @@ impl<'a, 'tcx> Decodable> for Symbol { } } +impl<'a, 'tcx> Decodable> for &'tcx [ty::Spanned>] { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { + ty::codec::RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx [(ty::Clause<'tcx>, Span)] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self { ty::codec::RefDecodable::decode(d) @@ -1056,7 +1062,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self, index: DefIndex, tcx: TyCtxt<'tcx>, - ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { + ) -> ty::EarlyBinder<&'tcx [ty::Spanned>]> { let lazy = self.root.tables.explicit_item_bounds.get(self, index); let output = if lazy.is_default() { &mut [] diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 9ae5c0af0b248..fac558e6374b5 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -386,7 +386,7 @@ define_tables! { type_alias_is_lazy: Table, attr_flags: Table, def_path_hashes: Table, - explicit_item_bounds: Table, Span)>>, + explicit_item_bounds: Table>>>, inferred_outlives_of: Table, Span)>>, inherent_impls: Table>, associated_types_for_impl_traits_in_associated_fn: Table>, @@ -462,7 +462,7 @@ define_tables! { trait_impl_trait_tys: Table>>>>, doc_link_resolutions: Table>, doc_link_traits_in_scope: Table>, - assumed_wf_types_for_rpitit: Table, Span)>>, + assumed_wf_types_for_rpitit: Table>>>, } #[derive(TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 9c8492a240693..fe47c26ab9055 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -11,7 +11,7 @@ use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex}; -use crate::ty::{GenericArg, GenericArgsRef}; +use crate::ty::{GenericArg, GenericArgsRef, Spanned}; use rustc_data_structures::captures::Captures; use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg}; @@ -593,13 +593,13 @@ impl<'tcx> Body<'tcx> { loop { let scope_data = &self.source_scopes[source_info.scope]; - if let Some((callee, callsite_span)) = scope_data.inlined { + if let Some(callee) = scope_data.inlined { // Stop inside the most nested non-`#[track_caller]` function, // before ever reaching its caller (which is irrelevant). - if !callee.def.requires_caller_location(tcx) { + if !callee.node.def.requires_caller_location(tcx) { return from_span(source_info.span); } - source_info.span = callsite_span; + source_info.span = callee.span; } // Skip past all of the parents with `inlined: None`. @@ -780,7 +780,7 @@ pub struct VarBindingForm<'tcx> { #[skip_traversal( despite_potential_miscompilation_because = "potential oversight since 0193d1f" )] - pub opt_match_place: Option<(Option>, Span)>, + pub opt_match_place: Option>>>, /// The span of the pattern in which this variable was bound. pub pat_span: Span, } @@ -1344,10 +1344,10 @@ impl SourceScope { source_scopes: &IndexSlice>, ) -> Option> { let scope_data = &source_scopes[self]; - if let Some((inlined_instance, _)) = scope_data.inlined { - Some(inlined_instance) + if let Some(inlined_instance) = scope_data.inlined { + Some(inlined_instance.node) } else if let Some(inlined_scope) = scope_data.inlined_parent_scope { - Some(source_scopes[inlined_scope].inlined.unwrap().0) + Some(source_scopes[inlined_scope].inlined.unwrap().node) } else { None } @@ -1362,7 +1362,7 @@ pub struct SourceScopeData<'tcx> { /// Whether this scope is the root of a scope tree of another body, /// inlined into this body by the MIR inliner. /// `ty::Instance` is the callee, and the `Span` is the call site. - pub inlined: Option<(ty::Instance<'tcx>, Span)>, + pub inlined: Option>>, /// Nearest (transitive) parent scope (if any) which is inlined. /// This is an optimization over walking up `parent_scope` diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 01f25f27c7b7a..8632397297849 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -415,14 +415,18 @@ fn write_scope_tree( let child_data = &body.source_scopes[child]; assert_eq!(child_data.parent_scope, Some(parent)); - let (special, span) = if let Some((callee, callsite_span)) = child_data.inlined { + let (special, span) = if let Some(callee) = child_data.inlined { ( format!( " (inlined {}{})", - if callee.def.requires_caller_location(tcx) { "#[track_caller] " } else { "" }, - callee + if callee.node.def.requires_caller_location(tcx) { + "#[track_caller] " + } else { + "" + }, + callee.node ), - Some(callsite_span), + Some(callee.span), ) } else { (String::new(), None) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 2436e0e4833c9..2edbb2e88132e 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -332,7 +332,7 @@ macro_rules! make_mir_visitor { if let Some(parent_scope) = parent_scope { self.visit_source_scope($(& $mutability)? *parent_scope); } - if let Some((callee, callsite_span)) = inlined { + if let Some(Spanned { node: callee, span: callsite_span }) = inlined { let location = Location::START; self.visit_span($(& $mutability)? *callsite_span); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4ec3b47711d9e..7514c21304a67 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -365,7 +365,7 @@ rustc_queries! { /// `key` is the `DefId` of the associated type or opaque type. /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { + query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [ty::Spanned>]> { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern @@ -884,13 +884,13 @@ rustc_queries! { /// /// Note that we've liberated the late bound regions of function signatures, so /// this can not be used to check whether these types are well formed. - query assumed_wf_types(key: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] { + query assumed_wf_types(key: LocalDefId) -> &'tcx [ty::Spanned>] { desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) } } /// We need to store the assumed_wf_types for an RPITIT so that impls of foreign /// traits with return-position impl trait in traits can inherit the right wf types. - query assumed_wf_types_for_rpitit(key: DefId) -> &'tcx [(Ty<'tcx>, Span)] { + query assumed_wf_types_for_rpitit(key: DefId) -> &'tcx [ty::Spanned>] { desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) } separate_provide_extern } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 280f5d0a84caa..c1257400e8086 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -794,6 +794,13 @@ impl<'a, 'tcx> Decodable> } } +impl<'a, 'tcx> Decodable> for &'tcx [ty::Spanned>] { + #[inline] + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { + RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx [(ty::Clause<'tcx>, Span)] { #[inline] fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 1de07c99071ea..5ed16324541d1 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -13,7 +13,7 @@ use crate::infer::canonical::Canonical; use crate::mir::ConstraintCategory; use crate::ty::abstract_const::NotConstEvaluatable; use crate::ty::GenericArgsRef; -use crate::ty::{self, AdtKind, Ty}; +use crate::ty::{self, AdtKind, Spanned, Ty}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; @@ -411,7 +411,7 @@ pub enum ObligationCauseCode<'tcx> { ReturnType, /// Opaque return type of this function - OpaqueReturnType(Option<(Ty<'tcx>, Span)>), + OpaqueReturnType(Option>>), /// Block implicit return BlockTailExpression(hir::HirId, hir::MatchSource), diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index b4054f8ff5edd..12934040d241f 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -26,7 +26,7 @@ impl<'tcx> Elaborator<'tcx> { .super_predicates_of(trait_ref.def_id()) .predicates .into_iter() - .flat_map(|(pred, _)| pred.subst_supertrait(self.tcx, &trait_ref).as_trait_clause()) + .flat_map(|pred| pred.node.subst_supertrait(self.tcx, &trait_ref).as_trait_clause()) .map(|t| t.map_bound(|pred| pred.trait_ref)) .filter(|supertrait_ref| self.visited.insert(*supertrait_ref)); diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 8b67e39667b8d..5a8e2234e7dd0 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -367,6 +367,17 @@ impl<'tcx, D: TyDecoder>> Decodable for AdtDef<'tcx> { } } +impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> + for [ty::Spanned>] +{ + fn decode(decoder: &mut D) -> &'tcx Self { + decoder + .interner() + .arena + .alloc_from_iter((0..decoder.read_usize()).map(|_| Decodable::decode(decoder))) + } +} + impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] { fn decode(decoder: &mut D) -> &'tcx Self { decoder diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 80f907c54dba6..9db12f236303c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1635,8 +1635,8 @@ impl<'tcx> TyCtxt<'tcx> { let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false }; let future_trait = self.require_lang_item(LangItem::Future, None); - self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { - let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { + self.explicit_item_bounds(def_id).skip_binder().iter().any(|&predicate| { + let ty::ClauseKind::Trait(trait_predicate) = predicate.node.kind().skip_binder() else { return false; }; trait_predicate.trait_ref.def_id == future_trait @@ -1658,8 +1658,8 @@ impl<'tcx> TyCtxt<'tcx> { let trait_did = stack.pop()?; let generic_predicates = self.super_predicates_of(trait_did); - for (predicate, _) in generic_predicates.predicates { - if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() { + for predicate in generic_predicates.predicates { + if let ty::ClauseKind::Trait(data) = predicate.node.kind().skip_binder() { if set.insert(data.def_id()) { stack.push(data.def_id()); } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 888ee1d237ae7..75dc15cf6347a 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -6,7 +6,9 @@ use rustc_hir::def_id::DefId; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt}; +use super::{ + Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Spanned, Ty, TyCtxt, +}; #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum GenericParamDefKind { @@ -362,7 +364,7 @@ impl<'tcx> Generics { #[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)] pub struct GenericPredicates<'tcx> { pub parent: Option, - pub predicates: &'tcx [(Clause<'tcx>, Span)], + pub predicates: &'tcx [Spanned>], } impl<'tcx> GenericPredicates<'tcx> { @@ -380,7 +382,7 @@ impl<'tcx> GenericPredicates<'tcx> { &self, tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, - ) -> impl Iterator, Span)> + DoubleEndedIterator + ExactSizeIterator { + ) -> impl Iterator>> + DoubleEndedIterator + ExactSizeIterator { EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args) } @@ -395,9 +397,9 @@ impl<'tcx> GenericPredicates<'tcx> { tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, args); } instantiated.predicates.extend( - self.predicates.iter().map(|(p, _)| EarlyBinder::bind(*p).instantiate(tcx, args)), + self.predicates.iter().map(|p| EarlyBinder::bind(p.node).instantiate(tcx, args)), ); - instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp)); + instantiated.spans.extend(self.predicates.iter().map(|p| p.span)); } pub fn instantiate_identity(&self, tcx: TyCtxt<'tcx>) -> InstantiatedPredicates<'tcx> { @@ -414,7 +416,7 @@ impl<'tcx> GenericPredicates<'tcx> { if let Some(def_id) = self.parent { tcx.predicates_of(def_id).instantiate_identity_into(tcx, instantiated); } - instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p)); - instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s)); + instantiated.predicates.extend(self.predicates.iter().map(|p| p.node)); + instantiated.spans.extend(self.predicates.iter().map(|p| p.span)); } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d90115b2a7e42..44daf67454f45 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -50,6 +50,7 @@ use rustc_serialize::{Decodable, Encodable}; use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; +pub use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; @@ -1384,27 +1385,34 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> { - type Item = (Clause<'tcx>, Span); + type Item = Spanned>; - type IntoIter = std::iter::Zip>, std::vec::IntoIter>; + type IntoIter = std::iter::Map< + std::iter::Zip>, std::vec::IntoIter>, + fn((Clause<'tcx>, Span)) -> Spanned>, + >; fn into_iter(self) -> Self::IntoIter { debug_assert_eq!(self.predicates.len(), self.spans.len()); - std::iter::zip(self.predicates, self.spans) + std::iter::zip(self.predicates, self.spans).map(|(node, span)| Spanned { node, span }) } } impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> { - type Item = (Clause<'tcx>, Span); - - type IntoIter = std::iter::Zip< - std::iter::Copied>>, - std::iter::Copied>, + type Item = Spanned>; + + type IntoIter = std::iter::Map< + std::iter::Zip< + std::iter::Copied>>, + std::iter::Copied>, + >, + fn((Clause<'tcx>, Span)) -> Spanned>, >; fn into_iter(self) -> Self::IntoIter { debug_assert_eq!(self.predicates.len(), self.spans.len()); std::iter::zip(self.predicates.iter().copied(), self.spans.iter().copied()) + .map(|(node, span)| Spanned { node, span }) } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 9afa50cf584c3..703218dfabcd7 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -36,6 +36,10 @@ impl ParameterizedOverTcx for ty::EarlyBinder { type Value<'tcx> = ty::EarlyBinder>; } +impl ParameterizedOverTcx for ty::Spanned { + type Value<'tcx> = ty::Spanned>; +} + #[macro_export] macro_rules! trivially_parameterized_over_tcx { ($($ty:ty),+ $(,)?) => { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index baf160bcc99da..0cf0e35829395 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -916,8 +916,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut is_sized = false; let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new(); - for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) { - let bound_predicate = predicate.kind(); + for predicate in bounds.iter_instantiated_copied(tcx, args) { + let bound_predicate = predicate.node.kind(); match bound_predicate.skip_binder() { ty::ClauseKind::Trait(pred) => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1626cae8c4bcb..cdf6ec75bbe87 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -11,6 +11,7 @@ use crate::ty::{ self, noop_if_trivially_traversable, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt, }; use rustc_hir::def::Namespace; +use rustc_span::source_map::Spanned; use rustc_target::abi::TyAndLayout; use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx}; @@ -421,7 +422,6 @@ TrivialLiftImpls! { // implementation (only for TyCtxt<'_> interners). TrivialTypeTraversalImpls! { crate::ty::BoundConstness, - ::rustc_span::Span, } // For some things about which the type library does not know, or does not // provide any traversal implementations, we need to provide a traversal @@ -460,6 +460,13 @@ impl<'a, 'tcx> Lift<'tcx> for Term<'a> { } } +impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Spanned { + type Lifted = Spanned; + fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + Some(Spanned { node: tcx.lift(self.node)?, span: self.span }) + } +} + /////////////////////////////////////////////////////////////////////////// // Traversal implementations. diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index ab4cd24881f6a..f2ad5e3df5a04 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -232,7 +232,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { remainder_span, pattern, None, - Some((Some(&destination), initializer_span)), + Some(ty::Spanned { + node: Some(&destination), + span: initializer_span, + }), ); this.visit_primary_bindings( pattern, @@ -310,7 +313,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { remainder_span, pattern, None, - Some((None, initializer_span)), + Some(ty::Spanned { + node: None, + span: initializer_span, + }), ); this.expr_into_pattern(block, &pattern, init) // irrefutable pattern diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 14906d21c8cc8..640a8415fc5a0 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -401,8 +401,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // }; // ``` let scrutinee_place = scrutinee_place_builder.try_to_place(this); - let opt_scrutinee_place = - scrutinee_place.as_ref().map(|place| (Some(place), scrutinee_span)); + let opt_scrutinee_place = scrutinee_place + .as_ref() + .map(|place| ty::Spanned { node: Some(place), span: scrutinee_span }); let scope = this.declare_bindings( None, arm.span, @@ -663,7 +664,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` if let Some(place) = initializer.try_to_place(self) { let LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: Some((ref mut match_place, _)), + opt_match_place: Some(ty::Spanned { node: ref mut match_place, .. }), .. })) = **self.local_decls[local].local_info.as_mut().assert_crate_local() else { @@ -700,7 +701,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scope_span: Span, pattern: &Pat<'tcx>, guard: Option<&Guard<'tcx>>, - opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, + opt_match_place: Option>>>, ) -> Option { self.visit_primary_bindings( &pattern, @@ -722,7 +723,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ty, user_ty, ArmHasGuard(guard.is_some()), - opt_match_place.map(|(x, y)| (x.cloned(), y)), + opt_match_place.map(|x| ty::Spanned { node: x.node.cloned(), span: x.span }), pattern.span, ); }, @@ -1858,7 +1859,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut [&mut guard_candidate, &mut otherwise_candidate], ); let expr_place = expr_place_builder.try_to_place(self); - let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); + let opt_expr_place = + expr_place.as_ref().map(|place| ty::Spanned { node: Some(place), span: expr_span }); let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap(); self.break_for_else(otherwise_post_guard_block, else_target, self.source_info(expr_span)); @@ -2274,7 +2276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { var_ty: Ty<'tcx>, user_ty: UserTypeProjections, has_guard: ArmHasGuard, - opt_match_place: Option<(Option>, Span)>, + opt_match_place: Option>>>, pat_span: Span, ) { let tcx = self.tcx; diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 7c729016521b0..a5d615d47e1d6 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -938,7 +938,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { LocalInfo::User(BindingForm::Var(VarBindingForm { binding_mode, opt_ty_info: param.ty_span, - opt_match_place: Some((None, span)), + opt_match_place: Some(ty::Spanned { node: None, span }), pat_span: span, })) }; @@ -950,7 +950,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr.span, &pat, None, - Some((Some(&place), span)), + Some(ty::Spanned { node: Some(&place), span }), ); let place_builder = PlaceBuilder::from(local); unpack!(block = self.place_into_pattern(block, &pat, place_builder, false)); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index fc30a718cbb57..9eb84ac2c792b 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1848,10 +1848,10 @@ fn check_must_not_suspend_ty<'tcx>( // FIXME: support adding the attribute to TAITs ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { let mut has_emitted = false; - for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() { + for &predicate in tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::ClauseKind::Trait(ref poly_trait_predicate) = - predicate.kind().skip_binder() + predicate.node.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 793dcf0d994c3..44bbfd2531d94 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -889,7 +889,10 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { // Mark the outermost callee scope as an inlined one. assert_eq!(scope_data.inlined, None); - scope_data.inlined = Some((self.callsite.callee, self.callsite.source_info.span)); + scope_data.inlined = Some(ty::Spanned { + node: self.callsite.callee, + span: self.callsite.source_info.span, + }); } else if scope_data.inlined_parent_scope.is_none() { // Make it easy to find the scope with `inlined` set above. scope_data.inlined_parent_scope = Some(self.map_scope(OUTERMOST_SOURCE_SCOPE)); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index bf5f0ca7cbd23..236ffc186a6f0 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -449,7 +449,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & .predicates_of(body.source.def_id()) .predicates .iter() - .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); + .filter_map(|p| if p.node.is_global() { Some(p.node) } else { None }); if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) { trace!("found unsatisfiable predicates for {:?}", body.source); // Clear the body to only contain a single `unreachable` statement. diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 4bb7e65747f70..0f5b25ef26859 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -115,7 +115,7 @@ trait DefIdVisitor<'tcx> { } fn visit_clauses( &mut self, - clauses: &[(ty::Clause<'tcx>, Span)], + clauses: &[ty::Spanned>], ) -> ControlFlow { self.skeleton().visit_clauses(clauses) } @@ -168,8 +168,11 @@ where } } - fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> ControlFlow { - clauses.into_iter().try_for_each(|&(clause, _span)| self.visit_clause(clause)) + fn visit_clauses( + &mut self, + clauses: &[ty::Spanned>], + ) -> ControlFlow { + clauses.into_iter().try_for_each(|&clause| self.visit_clause(clause.node)) } } @@ -1225,8 +1228,8 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { self.tcx.types.never, ); - for (clause, _) in bounds.clauses() { - match clause.kind().skip_binder() { + for clause in bounds.clauses() { + match clause.node.kind().skip_binder() { ty::ClauseKind::Trait(trait_predicate) => { if self.visit_trait(trait_predicate.trait_ref).is_break() { return; diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 25bd82bf1ef52..9c20fadf8671f 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -166,10 +166,10 @@ impl<'tcx> Context for TablesWrapper<'tcx> { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates .iter() - .map(|(clause, span)| { + .map(|clause| { ( - clause.as_predicate().kind().skip_binder().stable(&mut *tables), - span.stable(&mut *tables), + clause.node.as_predicate().kind().skip_binder().stable(&mut *tables), + clause.span.stable(&mut *tables), ) }) .collect(), @@ -188,10 +188,10 @@ impl<'tcx> Context for TablesWrapper<'tcx> { parent: parent.map(|did| tables.trait_def(did)), predicates: predicates .iter() - .map(|(clause, span)| { + .map(|clause| { ( - clause.as_predicate().kind().skip_binder().stable(&mut *tables), - span.stable(&mut *tables), + clause.node.as_predicate().kind().skip_binder().stable(&mut *tables), + clause.span.stable(&mut *tables), ) }) .collect(), diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 99de91a068ad3..227cc9142a445 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -12,6 +12,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } +rustc_type_ir = { path = "../rustc_type_ir" } scoped-tls = "1.0" sha1 = "0.10.0" sha2 = "0.10.1" diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index dcf346acb334e..482f26a8a969c 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -68,6 +68,7 @@ mod monotonic { } #[derive(Clone, Encodable, Decodable, Debug, Copy, HashStable_Generic)] +#[derive(Eq, PartialEq, Hash, TypeFoldable, TypeVisitable)] pub struct Spanned { pub node: T, pub span: Span, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 315df06be417c..bf879c6343ab5 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -208,9 +208,9 @@ fn rematch_impl<'tcx>( ); nested.extend( - infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map( - |(pred, _)| Obligation::new(infcx.tcx, ObligationCause::dummy(), goal.param_env, pred), - ), + infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map(|pred| { + Obligation::new(infcx.tcx, ObligationCause::dummy(), goal.param_env, pred.node) + }), ); Ok(Some(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, args, nested }))) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs b/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs index 28fe59b7f6a70..e39ce6cbf5370 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs @@ -42,7 +42,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { tcx.predicates_of(inherent.def_id) .instantiate(tcx, inherent_substs) .into_iter() - .map(|(pred, _)| goal.with(tcx, pred)), + .map(|pred| goal.with(tcx, pred.node)), ); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs index 240141065dcc8..926113cb1214e 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs @@ -137,7 +137,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx.add_goals( tcx.predicates_of(goal.predicate.def_id()) .instantiate_own(tcx, goal.predicate.projection_ty.args) - .map(|(pred, _)| goal.with(tcx, pred)), + .map(|pred| goal.with(tcx, pred.node)), ); then(ecx) @@ -182,7 +182,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx.add_goals( tcx.predicates_of(goal.predicate.def_id()) .instantiate_own(tcx, goal.predicate.projection_ty.args) - .map(|(pred, _)| goal.with(tcx, pred)), + .map(|pred| goal.with(tcx, pred.node)), ); // In case the associated item is hidden due to specialization, we have to diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index dcf5fd869290f..872fb3121c0b4 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -152,7 +152,7 @@ fn fresh_impl_header<'tcx>(infcx: &InferCtxt<'tcx>, impl_def_id: DefId) -> ty::I .predicates_of(impl_def_id) .instantiate(tcx, impl_args) .iter() - .map(|(c, _)| c.as_predicate()) + .map(|c| c.node.as_predicate()) .collect(), } } @@ -416,7 +416,7 @@ fn impl_intersection_has_negative_obligation( plug_infer_with_placeholders(infcx, universe, (impl1_header.impl_args, impl2_header.impl_args)); util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args)) - .any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env)) + .any(|clause| try_prove_negated_where_clause(infcx, clause.node, param_env)) } fn plug_infer_with_placeholders<'tcx>( diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index d9a1a98191d08..6d05d0ddf70cc 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -229,7 +229,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { let tcx = self.infcx.tcx; let mut implied_bounds = FxIndexSet::default(); let mut errors = Vec::new(); - for &(ty, span) in tcx.assumed_wf_types(def_id) { + for &ty in tcx.assumed_wf_types(def_id) { // FIXME(@lcnr): rustc currently does not check wf for types // pre-normalization, meaning that implied bounds are sometimes // incorrect. See #100910 for more details. @@ -242,11 +242,11 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { // sound and then uncomment this line again. // implied_bounds.insert(ty); - let cause = ObligationCause::misc(span, def_id); + let cause = ObligationCause::misc(ty.span, def_id); match self .infcx .at(&cause, param_env) - .deeply_normalize(ty, &mut **self.engine.borrow_mut()) + .deeply_normalize(ty.node, &mut **self.engine.borrow_mut()) { // Insert well-formed types, ignoring duplicates. Ok(normalized) => drop(implied_bounds.insert(normalized)), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index 5bc5a12a8fed3..3d7e9637d9b17 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -82,8 +82,8 @@ pub fn recompute_applicable_impls<'tcx>( let predicates = tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx); - for (pred, span) in elaborate(tcx, predicates.into_iter()) { - let kind = pred.kind(); + for pred in elaborate(tcx, predicates.into_iter()) { + let kind = pred.node.kind(); if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder() && param_env_candidate_may_apply(kind.rebind(trait_pred)) { @@ -92,7 +92,7 @@ pub fn recompute_applicable_impls<'tcx>( { ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id()))) } else { - ambiguities.push(Ambiguity::ParamEnv(span)) + ambiguities.push(Ambiguity::ParamEnv(pred.span)) } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 6b09bc89873ea..035eb07801dfe 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2038,8 +2038,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Find another predicate whose self-type is equal to the expected self type, // but whose args don't match. - let other_pred = predicates.into_iter().enumerate().find(|(other_idx, (pred, _))| { - match pred.kind().skip_binder() { + let other_pred = predicates.into_iter().enumerate().find(|(other_idx, pred)| { + match pred.node.kind().skip_binder() { ty::ClauseKind::Trait(trait_pred) if self.tcx.is_fn_trait(trait_pred.def_id()) && other_idx != idx @@ -2047,12 +2047,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // (i.e. constraining this closure) && expected_self == self.tcx.anonymize_bound_vars( - pred.kind().rebind(trait_pred.self_ty()), + pred.node.kind().rebind(trait_pred.self_ty()), ) // But the args don't match (i.e. incompatible args) && expected_args != self.tcx.anonymize_bound_vars( - pred.kind().rebind(trait_pred.trait_ref.args), + pred.node.kind().rebind(trait_pred.trait_ref.args), ) => { true @@ -2061,9 +2061,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }); // If we found one, then it's very likely the cause of the error. - if let Some((_, (_, other_pred_span))) = other_pred { + if let Some((_, other_pred)) = other_pred { err.span_note( - other_pred_span, + other_pred.span, "closure inferred to have a different signature due to this bound", ); } @@ -3321,10 +3321,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } ObligationCauseCode::OpaqueReturnType(expr_info) => { - if let Some((expr_ty, expr_span)) = expr_info { - let expr_ty = with_forced_trimmed_paths!(self.ty_to_string(expr_ty)); + if let Some(expr) = expr_info { + let expr_ty = with_forced_trimmed_paths!(self.ty_to_string(expr.node)); err.span_label( - expr_span, + expr.span, with_forced_trimmed_paths!(format!( "return type was inferred to be `{expr_ty}` here", )), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index ba2e3d1ae282a..f5c575371841c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1716,8 +1716,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .predicates_of(single.impl_def_id) .instantiate(self.tcx, impl_args) .into_iter() - .map(|(clause, _)| { - Obligation::new(self.tcx, ObligationCause::dummy(), param_env, clause) + .map(|clause| { + Obligation::new( + self.tcx, + ObligationCause::dummy(), + param_env, + clause.node, + ) }), ); if !ocx.select_where_possible().is_empty() { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index fff5510bbfbb0..44874ca891324 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -108,11 +108,11 @@ pub fn predicates_for_generics<'tcx>( param_env: ty::ParamEnv<'tcx>, generic_bounds: ty::InstantiatedPredicates<'tcx>, ) -> impl Iterator> { - generic_bounds.into_iter().enumerate().map(move |(idx, (clause, span))| Obligation { - cause: cause(idx, span), + generic_bounds.into_iter().enumerate().map(move |(idx, clause)| Obligation { + cause: cause(idx, clause.span), recursion_depth: 0, param_env, - predicate: clause.as_predicate(), + predicate: clause.node.as_predicate(), }) } @@ -512,13 +512,13 @@ fn is_impossible_associated_item( let param_env = tcx.param_env(impl_def_id); let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id }; - let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| { - pred.visit_with(&mut visitor).is_continue().then(|| { + let predicates_for_trait = predicates.predicates.iter().filter_map(|pred| { + pred.node.visit_with(&mut visitor).is_continue().then(|| { Obligation::new( tcx, - ObligationCause::dummy_with_span(*span), + ObligationCause::dummy_with_span(pred.span), param_env, - ty::EarlyBinder::bind(*pred).instantiate(tcx, impl_trait_ref.args), + ty::EarlyBinder::bind(pred.node).instantiate(tcx, impl_trait_ref.args), ) }) }); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 17c7f94ee883c..7acb284c8f93a 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -264,7 +264,10 @@ fn predicates_reference_self( predicates .predicates .iter() - .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) + .map(|&predicate| ty::Spanned { + node: predicate.node.subst_supertrait(tcx, &trait_ref), + span: predicate.span, + }) .filter_map(|predicate| predicate_references_self(tcx, predicate)) .collect() } @@ -280,7 +283,7 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span fn predicate_references_self<'tcx>( tcx: TyCtxt<'tcx>, - (predicate, sp): (ty::Clause<'tcx>, Span), + ty::Spanned { node: predicate, span: sp }: ty::Spanned>, ) -> Option { let self_ty = tcx.types.self_param; let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into()); @@ -329,7 +332,7 @@ fn super_predicates_have_non_lifetime_binders( tcx.super_predicates_of(trait_def_id) .predicates .iter() - .filter_map(|(pred, span)| pred.has_non_region_late_bound().then_some(*span)) + .filter_map(|pred| pred.node.has_non_region_late_bound().then_some(pred.span)) .collect() } @@ -556,7 +559,7 @@ fn virtual_call_violations_for_method<'tcx>( // NOTE: This check happens last, because it results in a lint, and not a // hard error. - if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, span)| { + if tcx.predicates_of(method.def_id).predicates.iter().any(|&pred| { // dyn Trait is okay: // // trait Trait { @@ -566,7 +569,7 @@ fn virtual_call_violations_for_method<'tcx>( // because a trait object can't claim to live longer than the concrete // type. If the lifetime bound holds on dyn Trait then it's guaranteed // to hold as well on the concrete type. - if pred.as_type_outlives_clause().is_some() { + if pred.node.as_type_outlives_clause().is_some() { return false; } @@ -586,7 +589,7 @@ fn virtual_call_violations_for_method<'tcx>( if let ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: pred_trait_ref, polarity: ty::ImplPolarity::Positive, - }) = pred.kind().skip_binder() + }) = pred.node.kind().skip_binder() && pred_trait_ref.self_ty() == tcx.types.self_param && tcx.trait_is_auto(pred_trait_ref.def_id) { @@ -597,12 +600,12 @@ fn virtual_call_violations_for_method<'tcx>( if pred_trait_ref.args.len() != 1 { tcx.sess .diagnostic() - .delay_span_bug(span, "auto traits cannot have generic parameters"); + .delay_span_bug(pred.span, "auto traits cannot have generic parameters"); } return false; } - contains_illegal_self_type_reference(tcx, trait_def_id, pred) + contains_illegal_self_type_reference(tcx, trait_def_id, pred.node) }) { errors.push(MethodViolationCode::WhereClauseReferencesSelf); } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 471d10dbdbd82..fd0d2f8898ee7 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -674,7 +674,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx let infcx = self.selcx.infcx; self.obligations.extend( infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( - |(mut predicate, span)| { + |ty::Spanned { node: mut predicate, span }| { if data.has_escaping_bound_vars() { (predicate, ..) = BoundVarReplacer::replace_bound_vars( infcx, @@ -1370,13 +1370,14 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( // Register the obligations arising from the impl and from the associated type itself. let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, args); - for (predicate, span) in predicates { + for predicate in predicates { + let span = predicate.span; let predicate = normalize_with_depth_to( selcx, param_env, cause.clone(), depth + 1, - predicate, + predicate.node, obligations, ); @@ -2446,13 +2447,13 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( let predicates = tcx .predicates_of(obligation.predicate.def_id) .instantiate_own(tcx, obligation.predicate.args); - for (predicate, span) in predicates { + for predicate in predicates { let normalized = normalize_with_depth_to( selcx, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - predicate, + predicate.node, nested, ); @@ -2463,7 +2464,7 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( | super::AscribeUserTypeProvePredicate(..) ) { obligation.cause.clone() - } else if span.is_dummy() { + } else if predicate.span.is_dummy() { ObligationCause::new( obligation.cause.span, obligation.cause.body_id, @@ -2473,7 +2474,7 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( ObligationCause::new( obligation.cause.span, obligation.cause.body_id, - super::BindingObligation(obligation.predicate.def_id, span), + super::BindingObligation(obligation.predicate.def_id, predicate.span), ) }; nested.push(Obligation::with_depth( diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 302b6016e5ea6..0334326b19293 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -100,15 +100,15 @@ fn relate_mir_and_user_args<'tcx>( let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); debug!(?instantiated_predicates); - for (instantiated_predicate, predicate_span) in instantiated_predicates { - let span = if span == DUMMY_SP { predicate_span } else { span }; + for instantiated_predicate in instantiated_predicates { + let span = if span == DUMMY_SP { instantiated_predicate.span } else { span }; let cause = ObligationCause::new( span, CRATE_DEF_ID, - ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), + ObligationCauseCode::AscribeUserTypeProvePredicate(instantiated_predicate.span), ); let instantiated_predicate = - ocx.normalize(&cause.clone(), param_env, instantiated_predicate); + ocx.normalize(&cause.clone(), param_env, instantiated_predicate.node); ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f4b6d3bcfda29..fbdd942622034 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -414,8 +414,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return false; }; - for &(predicate, _) in self.tcx().predicates_of(impl_def_id).predicates { - let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder() else { continue }; + for &predicate in self.tcx().predicates_of(impl_def_id).predicates { + let ty::ClauseKind::Trait(pred) = predicate.node.kind().skip_binder() else { continue }; if fn_ptr_trait != pred.trait_ref.def_id { continue; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4bfa341e3332a..a2c3db3818bc0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -182,13 +182,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let ty::Alias(ty::Projection, ..) = placeholder_self_ty.kind() { let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args); - for (predicate, _) in predicates { + for predicate in predicates { let normalized = normalize_with_depth_to( self, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - predicate, + predicate.node, &mut obligations, ); obligations.push(Obligation::with_depth( diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index cf52e6726a17c..fd275d9d34fee 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2717,7 +2717,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { assert_eq!(predicates.parent, None); let predicates = predicates.instantiate_own(tcx, args); let mut obligations = Vec::with_capacity(predicates.len()); - for (index, (predicate, span)) in predicates.into_iter().enumerate() { + for (index, predicate) in predicates.into_iter().enumerate() { let cause = if Some(parent_trait_pred.def_id()) == tcx.lang_items().coerce_unsized_trait() { cause.clone() @@ -2727,7 +2727,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { derived, impl_or_alias_def_id: def_id, impl_def_predicate_index: Some(index), - span, + span: predicate.span, })) }) }; @@ -2736,7 +2736,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { param_env, cause.clone(), recursion_depth, - predicate, + predicate.node, &mut obligations, ); obligations.push(Obligation { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index efab29743f4e9..8a2bdec37052a 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -494,14 +494,14 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti let mut pretty_predicates = Vec::with_capacity(predicates.len() + types_without_default_bounds.len()); - for (p, _) in predicates { - if let Some(poly_trait_ref) = p.as_trait_clause() { + for p in predicates { + if let Some(poly_trait_ref) = p.node.as_trait_clause() { if Some(poly_trait_ref.def_id()) == sized_trait { types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder()); continue; } } - pretty_predicates.push(p.to_string()); + pretty_predicates.push(p.node.to_string()); } pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized"))); diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index bbde0c82743b4..3c13b58dad3b8 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -127,10 +127,10 @@ impl<'tcx> TraitAliasExpander<'tcx> { let predicates = tcx.implied_predicates_of(trait_ref.def_id()); debug!(?predicates); - let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { - pred.subst_supertrait(tcx, &trait_ref) - .as_trait_clause() - .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span)) + let items = predicates.predicates.iter().rev().filter_map(|pred| { + pred.node.subst_supertrait(tcx, &trait_ref).as_trait_clause().map(|trait_ref| { + item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), pred.span) + }) }); debug!("expand_trait_aliases: items={:?}", items.clone().collect::>()); @@ -186,7 +186,7 @@ impl Iterator for SupertraitDefIds<'_> { predicates .predicates .iter() - .filter_map(|(pred, _)| pred.as_trait_clause()) + .filter_map(|pred| pred.node.as_trait_clause()) .map(|trait_ref| trait_ref.def_id()) .filter(|&super_def_id| visited.insert(super_def_id)), ); diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index f23c100a686c6..a9cbfd5151469 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -123,8 +123,8 @@ fn prepare_vtable_segments_inner<'tcx, T>( .super_predicates_of(inner_most_trait_ref.def_id()) .predicates .into_iter() - .filter_map(move |(pred, _)| { - pred.subst_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() + .filter_map(move |pred| { + pred.node.subst_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() }); // Find an unvisited supertrait @@ -282,7 +282,7 @@ fn vtable_entries<'tcx>( let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args); if impossible_predicates( tcx, - predicates.map(|(predicate, _)| predicate).collect(), + predicates.map(|predicate| predicate.node).collect(), ) { debug!("vtable_entries: predicates do not hold"); return VtblEntry::Vacant; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fe5b625e4836d..8e7bc8a91e2f9 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -825,11 +825,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { debug_assert_eq!(predicates.predicates.len(), origins.len()); iter::zip(predicates, origins.into_iter().rev()) - .map(|((pred, span), origin_def_id)| { - let code = if span.is_dummy() { + .map(|(pred, origin_def_id)| { + let code = if pred.span.is_dummy() { traits::ItemObligation(origin_def_id) } else { - traits::BindingObligation(origin_def_id, span) + traits::BindingObligation(origin_def_id, pred.span) }; let cause = self.cause(code); traits::Obligation::with_depth( @@ -837,7 +837,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, self.param_env, - pred, + pred.node, ) }) .filter(|pred| !pred.has_escaping_bound_vars()) diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 01bb1ca70eb4c..1633029ceaad0 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -82,16 +82,15 @@ fn normalize_weak_ty<'tcx>( tcx.infer_ctxt().enter_canonical_trait_query( &goal, |ocx, ParamEnvAnd { param_env, value: goal }| { - let obligations = tcx.predicates_of(goal.def_id).instantiate_own(tcx, goal.args).map( - |(predicate, span)| { + let obligations = + tcx.predicates_of(goal.def_id).instantiate_own(tcx, goal.args).map(|predicate| { traits::Obligation::new( tcx, - ObligationCause::dummy_with_span(span), + ObligationCause::dummy_with_span(predicate.span), param_env, - predicate, + predicate.node, ) - }, - ); + }); ocx.register_obligations(obligations); let normalized_ty = tcx.type_of(goal.def_id).instantiate(tcx, goal.args); Ok(NormalizationResult { normalized_ty }) diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 5c34df1ed5027..0a7d8c32f2309 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -18,7 +18,7 @@ pub fn provide(providers: &mut Providers) { }; } -fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] { +fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [ty::Spanned>] { match tcx.def_kind(def_id) { DefKind::Fn => { let sig = tcx.fn_sig(def_id).instantiate_identity(); @@ -26,7 +26,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' tcx.arena.alloc_from_iter(itertools::zip_eq( liberated_sig.inputs_and_output, fn_sig_spans(tcx, def_id), - )) + ).map(|(node, span)| ty::Spanned { node, span })) } DefKind::AssocFn => { let sig = tcx.fn_sig(def_id).instantiate_identity(); @@ -36,7 +36,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' assumed_wf_types.extend(itertools::zip_eq( liberated_sig.inputs_and_output, fn_sig_spans(tcx, def_id), - )); + ).map(|(node, span)| ty::Spanned { node, span })); tcx.arena.alloc_slice(&assumed_wf_types) } DefKind::Impl { .. } => { @@ -48,7 +48,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' }; let mut impl_spans = impl_spans(tcx, def_id); - tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap()))) + tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| ty::Spanned { node: ty, span: impl_spans.next().unwrap() })) } DefKind::AssocTy if let Some(data) = tcx.opt_rpitit_info(def_id.to_def_id()) => { match data { diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 9242a1a751bc7..599614ae21f47 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -171,13 +171,13 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { // Collect opaque types nested within the associated type bounds of this opaque type. // We use identity args here, because we already know that the opaque type uses // only generic parameters, and thus substituting would not give us more information. - for (pred, span) in self + for pred in self .tcx .explicit_item_bounds(alias_ty.def_id) .instantiate_identity_iter_copied() { - trace!(?pred); - self.visit_spanned(span, pred); + trace!(?pred.node); + self.visit_spanned(pred.span, pred.node); } } Err(NotUniqueParam::NotParam(arg)) => { diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index ccdc6120196ac..3255f704366a6 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -34,8 +34,8 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) { visitor.visit(hir.span, ty.map_bound(|x| *x))?; } - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { - visitor.visit(span, pred)?; + for pred in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(pred.span, pred.node)?; } } // Walk over the type behind the alias @@ -47,21 +47,21 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( _ => tcx.def_span(item), }; visitor.visit(span, tcx.type_of(item).instantiate_identity()); - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { - visitor.visit(span, pred)?; + for pred in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(pred.span, pred.node)?; } } DefKind::OpaqueTy => { - for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() { - visitor.visit(span, pred)?; + for pred in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() { + visitor.visit(pred.span, pred.node)?; } } // Look at field types DefKind::Struct | DefKind::Union | DefKind::Enum => { let span = tcx.def_ident_span(item).unwrap(); visitor.visit(span, tcx.type_of(item).instantiate_identity()); - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { - visitor.visit(span, pred)?; + for pred in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(pred.span, pred.node)?; } } // These are not part of a public API, they can only appear as hidden types, and there @@ -79,13 +79,13 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( _ => tcx.def_span(item), }; visitor.visit(span, tcx.type_of(item).instantiate_identity()); - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { - visitor.visit(span, pred)?; + for pred in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(pred.span, pred.node)?; } } DefKind::TraitAlias | DefKind::Trait => { - for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { - visitor.visit(span, pred)?; + for pred in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(pred.span, pred.node)?; } } | DefKind::Variant diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index abf3e108ed484..871796b67e72c 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -53,8 +53,8 @@ fn sized_constraint_for_ty<'tcx>( let Some(sized_trait_def_id) = tcx.lang_items().sized_trait() else { return vec![ty] }; let predicates = tcx.predicates_of(adtdef.did()).predicates; - if predicates.iter().any(|(p, _)| { - p.as_trait_clause().is_some_and(|trait_pred| { + if predicates.iter().any(|p| { + p.node.as_trait_clause().is_some_and(|trait_pred| { trait_pred.def_id() == sized_trait_def_id && trait_pred.self_ty().skip_binder() == ty }) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1b7ca7bf7dd0e..bea82dc1b1afe 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -442,7 +442,7 @@ fn clean_projection<'tcx>( .tcx .explicit_item_bounds(ty.skip_binder().def_id) .iter_instantiated_copied(cx.tcx, ty.skip_binder().args) - .map(|(pred, _)| pred) + .map(|pred| pred.node) .collect::>(); return clean_middle_opaque_bounds(cx, bounds); } @@ -787,10 +787,10 @@ fn clean_ty_generics<'tcx>( let where_predicates = preds .predicates .iter() - .flat_map(|(pred, _)| { + .flat_map(|pred| { let mut projection = None; let param_idx = (|| { - let bound_p = pred.kind(); + let bound_p = pred.node.kind(); match bound_p.skip_binder() { ty::ClauseKind::Trait(pred) => { if let ty::Param(param) = pred.self_ty().kind() { @@ -817,7 +817,7 @@ fn clean_ty_generics<'tcx>( if let Some(param_idx) = param_idx && let Some(bounds) = impl_trait.get_mut(¶m_idx.into()) { - let pred = clean_predicate(*pred, cx)?; + let pred = clean_predicate(pred.node, cx)?; bounds.extend( pred.get_bounds() @@ -840,7 +840,7 @@ fn clean_ty_generics<'tcx>( return None; } - Some(pred) + Some(&pred.node) }) .collect::>(); @@ -2269,7 +2269,7 @@ pub(crate) fn clean_middle_ty<'tcx>( .tcx .explicit_item_bounds(def_id) .iter_instantiated_copied(cx.tcx, args) - .map(|(bound, _)| bound) + .map(|bound| bound.node) .collect::>(); let ty = clean_middle_opaque_bounds(cx, bounds); if let Some(count) = cx.current_type_aliases.get_mut(&def_id) { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 627f15e67ac30..aafbac768944a 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -118,8 +118,8 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) predicates .predicates .iter() - .filter_map(|(pred, _)| { - if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() { + .filter_map(|pred| { + if let ty::ClauseKind::Trait(pred) = pred.node.kind().skip_binder() { if pred.trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { None } } else { None diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 3a331564db970..91f0b98239bdf 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -502,8 +502,8 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> .collect::>(); let ty_predicates = tcx.predicates_of(did).predicates; - for (p, _) in ty_predicates { - if let ClauseKind::Trait(p) = p.kind().skip_binder() + for p in ty_predicates { + if let ClauseKind::Trait(p) = p.node.kind().skip_binder() && p.trait_ref.def_id == eq_trait_id && let ty::Param(self_ty) = p.trait_ref.self_ty().kind() { @@ -513,7 +513,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> } ParamEnv::new( - tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain( + tcx.mk_clauses_from_iter(ty_predicates.iter().map(|p| p.node).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { ClauseKind::Trait(TraitPredicate { trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]), diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index eee5b7540ba7e..afe35944d8996 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -66,8 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() { let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; - for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) { - if let Some(trait_pred) = p.as_trait_clause() { + for p in preds.iter_instantiated_copied(cx.tcx, args) { + if let Some(trait_pred) = p.node.as_trait_clause() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; break; diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index ff27a5d666d35..628cd67e5cf5f 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -265,8 +265,8 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args); let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings); - preds.iter().find_map(|(clause, _)| { - if let ClauseKind::Trait(tr) = clause.kind().skip_binder() + preds.iter().find_map(|clause| { + if let ClauseKind::Trait(tr) = clause.node.kind().skip_binder() && tr.def_id() == def_id && is_same_generics( cx.tcx, diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index e76cc65fd46a2..8cdde1b756e65 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -43,10 +43,10 @@ fn get_trait_predicates_for_trait_id<'tcx>( trait_id: Option, ) -> Vec> { let mut preds = Vec::new(); - for (pred, _) in generics.predicates { + for pred in generics.predicates { if_chain! { - if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder(); - let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred)); + if let ClauseKind::Trait(poly_trait_pred) = pred.node.kind().skip_binder(); + let trait_pred = cx.tcx.erase_late_bound_regions(pred.node.kind().rebind(poly_trait_pred)); if let Some(trait_def_id) = trait_id; if trait_def_id == trait_pred.trait_ref.def_id; then { @@ -62,9 +62,9 @@ fn get_projection_pred<'tcx>( generics: GenericPredicates<'tcx>, trait_pred: TraitPredicate<'tcx>, ) -> Option> { - generics.predicates.iter().find_map(|(proj_pred, _)| { - if let ClauseKind::Projection(pred) = proj_pred.kind().skip_binder() { - let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.kind().rebind(pred)); + generics.predicates.iter().find_map(|proj_pred| { + if let ClauseKind::Projection(pred) = proj_pred.node.kind().skip_binder() { + let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.node.kind().rebind(pred)); if projection_pred.projection_ty.args == trait_pred.trait_ref.args { return Some(projection_pred); } diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 28f1d487eb5f5..c096f12c46fbf 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -91,11 +91,11 @@ fn into_iter_bound<'tcx>( let param_env = cx.tcx.param_env(fn_did); let mut into_iter_span = None; - for (pred, span) in cx.tcx.explicit_predicates_of(fn_did).predicates { - if let ty::ClauseKind::Trait(tr) = pred.kind().skip_binder() { + for pred in cx.tcx.explicit_predicates_of(fn_did).predicates { + if let ty::ClauseKind::Trait(tr) = pred.node.kind().skip_binder() { if tr.self_ty().is_param(param_index) { if tr.def_id() == into_iter_did { - into_iter_span = Some(*span); + into_iter_span = Some(pred.span); } else { let tr = cx.tcx.erase_regions(tr); if tr.has_escaping_bound_vars() { diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 0bcefba75a7b8..4d5c2c875b4ee 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -73,7 +73,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: cx.tcx.type_of(x.did).instantiate_identity().peel_refs().kind(), ty::Param(_) ) - }) && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() { + }) && all_predicates_of(cx.tcx, fn_id).all(|pred| match pred.node.kind().skip_binder() { ty::ClauseKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker, _ => true, }) && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_))) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 1181dfc0ef95c..168644901afe8 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2233,7 +2233,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { .predicates_of(did) .predicates .iter() - .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); + .filter_map(|p| p.node.is_global().then_some(p.node)); traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::>()) } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 7eff93881b26e..075e427ff59e5 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::{ TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{sym, Symbol, DUMMY_SP}; use rustc_target::abi::{Size, VariantIdx}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; @@ -96,8 +96,8 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() { - match predicate.kind().skip_binder() { + for predicate in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() { + match predicate.node.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substitutions to find `U`. ty::ClauseKind::Trait(trait_predicate) => { @@ -300,8 +300,8 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { }, ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { - if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() { + for predicate in cx.tcx.explicit_item_bounds(def_id).skip_binder() { + if let ty::ClauseKind::Trait(trait_predicate) = predicate.node.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; } @@ -599,7 +599,7 @@ fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t } /// Gets an iterator over all predicates which apply to the given item. -pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator, Span)> { +pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator>> { let mut next_id = Some(id); iter::from_fn(move || { next_id.take().map(|id| { @@ -777,18 +777,18 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option let mut output = None; let lang_items = cx.tcx.lang_items(); - for (pred, _) in cx + for pred in cx .tcx .explicit_item_bounds(ty.def_id) .iter_instantiated_copied(cx.tcx, ty.args) { - match pred.kind().skip_binder() { + match pred.node.kind().skip_binder() { ty::ClauseKind::Trait(p) if (lang_items.fn_trait() == Some(p.def_id()) || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) => { - let i = pred.kind().rebind(p.trait_ref.args.type_at(1)); + let i = pred.node.kind().rebind(p.trait_ref.args.type_at(1)); if inputs.map_or(false, |inputs| inputs != i) { // Multiple different fn trait impls. Is this even allowed? @@ -801,7 +801,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option // Multiple different fn trait impls. Is this even allowed? return None; } - output = pred.kind().rebind(p.term.ty()).transpose(); + output = pred.node.kind().rebind(p.term.ty()).transpose(); }, _ => (), } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 965cd534d1e5c..87bfe1e0aeea5 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -900,7 +900,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let scope = frame.current_source_info()?.scope; let inlined_parent = frame.body.source_scopes[scope].inlined_parent_scope?; let source = &frame.body.source_scopes[inlined_parent]; - source.inlined.expect("inlined_parent_scope points to scope without inline info").0 + source.inlined.expect("inlined_parent_scope points to scope without inline info").node }; // Fall back to the instance of the function itself. let instance = instance.unwrap_or(frame.instance); From b1f374b11990e9ea032ab4cb10337435c4214d7d Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Tue, 21 Mar 2023 08:49:51 +0000 Subject: [PATCH 21/28] Generify trivial traversables over the interner --- Cargo.lock | 2 ++ compiler/rustc_hir/Cargo.toml | 1 + compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_middle/src/macros.rs | 30 +++++++++++-------- compiler/rustc_middle/src/ty/closure.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 1 + .../rustc_middle/src/ty/structural_impls.rs | 28 +++-------------- compiler/rustc_span/src/def_id.rs | 2 +- compiler/rustc_target/Cargo.toml | 1 + compiler/rustc_target/src/abi/mod.rs | 2 +- compiler/rustc_target/src/spec/abi/mod.rs | 2 +- 11 files changed, 31 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d2a09eb60a78..4c342fa13767d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3918,6 +3918,7 @@ dependencies = [ "rustc_serialize", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec", "tracing", ] @@ -4572,6 +4573,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", + "rustc_type_ir", "serde_json", "tracing", ] diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index a72c4d0f18bc4..120122001110b 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -15,6 +15,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c4e44a6a4e388..c330f3d59f799 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3256,7 +3256,7 @@ impl<'hir> Item<'hir> { } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable, HashStable_Generic)] +#[derive(Encodable, Decodable, HashStable_Generic, TypeFoldable, TypeVisitable)] pub enum Unsafety { Unsafe, Normal, diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index c1884bb8068d7..ee971c2931eab 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -59,10 +59,10 @@ macro_rules! TrivialLiftImpls { /// allocated data** (i.e., don't need to be folded). #[macro_export] macro_rules! TrivialTypeTraversalImpls { - ($($ty:ty),+ $(,)?) => { + ($(for { $($generic:tt)+ } { $interner:ty } { $ty:ty })+) => { $( - impl<'tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty { - fn try_fold_with>>( + impl<$($generic)+> $crate::ty::fold::TypeFoldable<$interner> for $ty { + fn try_fold_with>( self, _: &mut F, ) -> ::std::result::Result { @@ -70,7 +70,7 @@ macro_rules! TrivialTypeTraversalImpls { } #[inline] - fn fold_with>>( + fn fold_with>( self, _: &mut F, ) -> Self { @@ -78,9 +78,9 @@ macro_rules! TrivialTypeTraversalImpls { } } - impl<'tcx> $crate::ty::visit::TypeVisitable<$crate::ty::TyCtxt<'tcx>> for $ty { + impl<$($generic)+> $crate::ty::visit::TypeVisitable<$interner> for $ty { #[inline] - fn visit_with>>( + fn visit_with>( &self, _: &mut F) -> ::std::ops::ControlFlow @@ -90,12 +90,16 @@ macro_rules! TrivialTypeTraversalImpls { } )+ }; -} -#[macro_export] -macro_rules! TrivialTypeTraversalAndLiftImpls { - ($($t:tt)*) => { - TrivialTypeTraversalImpls! { $($t)* } - TrivialLiftImpls! { $($t)* } - } + (for <$tcx:lifetime> { $($ty:ty),+ $(,)? }) => { + TrivialTypeTraversalImpls! { + $(for { $tcx } { $crate::ty::TyCtxt<$tcx> } { $ty })+ + } + }; + + ($($ty:ty),+ $(,)?) => { + TrivialTypeTraversalImpls! { + $(for { I: $crate::ty::Interner } { I } { $ty })+ + } + }; } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 33265335e4ba8..ab0c60d7d1781 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -77,7 +77,7 @@ pub type MinCaptureList<'tcx> = Vec>; /// You can get the environment type of a closure using /// `tcx.closure_env_ty()`. #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub enum ClosureKind { // Warning: Ordering is significant here! The ordering is chosen // because the trait Fn is a subtrait of FnMut and so in turn, and diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 44daf67454f45..e051fa43e0261 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -305,6 +305,7 @@ pub enum Visibility { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum BoundConstness { /// `T: Trait` NotConst, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index cdf6ec75bbe87..bbe72a6142162 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -12,7 +12,6 @@ use crate::ty::{ }; use rustc_hir::def::Namespace; use rustc_span::source_map::Spanned; -use rustc_target::abi::TyAndLayout; use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx}; use std::fmt::{self, Debug}; @@ -409,7 +408,11 @@ TrivialLiftImpls! { bool, usize, u64, + ::rustc_hir::def_id::DefId, ::rustc_hir::Mutability, + ::rustc_hir::Unsafety, + ::rustc_target::spec::abi::Abi, + crate::ty::ClosureKind, crate::ty::ParamConst, crate::ty::ParamTy, interpret::Scalar, @@ -417,23 +420,6 @@ TrivialLiftImpls! { rustc_target::abi::Size, } -// For some things about which the type library does not know, or does not -// provide any traversal implementations, we need to provide a traversal -// implementation (only for TyCtxt<'_> interners). -TrivialTypeTraversalImpls! { - crate::ty::BoundConstness, -} -// For some things about which the type library does not know, or does not -// provide any traversal implementations, we need to provide a traversal -// implementation and a lift implementation (the former only for TyCtxt<'_> -// interners). -TrivialTypeTraversalAndLiftImpls! { - ::rustc_hir::def_id::DefId, - ::rustc_hir::Unsafety, - ::rustc_target::spec::abi::Abi, - crate::ty::ClosureKind, -} - /////////////////////////////////////////////////////////////////////////// // Lift implementations @@ -807,9 +793,3 @@ impl<'tcx> TypeSuperVisitable> for ty::UnevaluatedConst<'tcx> { self.args.visit_with(visitor) } } - -impl<'tcx> TypeVisitable> for TyAndLayout<'tcx, Ty<'tcx>> { - fn visit_with>>(&self, visitor: &mut V) -> ControlFlow { - visitor.visit_ty(self.ty) - } -} diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 595babc26ae68..96d07066f97ff 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -238,7 +238,7 @@ impl Decodable for DefIndex { /// index and a def index. /// /// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`. -#[derive(Clone, PartialEq, Eq, Copy)] +#[derive(Clone, PartialEq, Eq, Copy, TypeFoldable, TypeVisitable)] // Don't derive order on 64-bit big-endian, so we can be consistent regardless of field order. #[cfg_attr(not(all(target_pointer_width = "64", target_endian = "big")), derive(PartialOrd, Ord))] // On below-64 bit systems we can simply use the derived `Hash` impl diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 94dfeb12dc98a..9013f058d3a6b 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -14,6 +14,7 @@ rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } +rustc_type_ir = { path = "../rustc_type_ir" } serde_json = "1.0.59" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index b00567e87c656..118cc96ea3a94 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -131,7 +131,7 @@ impl<'a> Layout<'a> { /// to that obtained from `layout_of(ty)`, as we need to produce /// layouts for which Rust types do not exist, such as enum variants /// or synthetic fields of enums (i.e., discriminants) and fat pointers. -#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic, TypeVisitable)] pub struct TyAndLayout<'a, Ty> { pub ty: Ty, pub layout: Layout<'a>, diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index 4c1f0c01a0411..45e8e62f86754 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -8,7 +8,7 @@ use rustc_span::{Span, Symbol}; mod tests; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)] -#[derive(HashStable_Generic, Encodable, Decodable)] +#[derive(HashStable_Generic, Encodable, Decodable, TypeFoldable, TypeVisitable)] pub enum Abi { // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the // hashing tests. These are used in many places, so giving them stable values reduces test From 361e068e7219c719ce82573a5386e69513a58988 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Fri, 17 Mar 2023 17:02:54 +0000 Subject: [PATCH 22/28] Require explanation of trivial traversable derives --- compiler/rustc_hir/src/hir.rs | 3 ++ compiler/rustc_macros/src/lib.rs | 34 +++++++++++++++---- compiler/rustc_macros/src/traversable.rs | 22 ++++++++++-- .../rustc_macros/src/traversable/tests.rs | 33 ++++++++++++++++-- compiler/rustc_middle/src/ty/closure.rs | 3 ++ compiler/rustc_middle/src/ty/mod.rs | 6 ++++ compiler/rustc_span/src/def_id.rs | 3 ++ compiler/rustc_target/src/spec/abi/mod.rs | 3 ++ 8 files changed, 96 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c330f3d59f799..3ed7ae47e2a97 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3257,6 +3257,9 @@ impl<'hir> Item<'hir> { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable_Generic, TypeFoldable, TypeVisitable)] +#[skip_traversal( + but_impl_despite_trivial_because = "`Unsafety` impls `Relate`, which is a subtrait of `TypeFoldable`." +)] pub enum Unsafety { Unsafe, Normal, diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index babf9dbe272c6..1b4074ef4f3fb 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -90,10 +90,21 @@ decl_derive!( /// only be applicable if `T` does not contain anything that may be of interest to folders /// (thus preventing fields from being so-skipped erroneously). /// + /// By default, `TypeFoldable` cannot be derived on types that contain nothing that may be of + /// interest to folders as such an implementation is wholly superfluous and probably in error. + /// However, on occasion it may nevertheless be necessary to implement `TypeFoldable` for such + /// types even though any such fold will always be a noop (e.g. so that instances can be used + /// in a generic context that is constrained to implementors of the trait); in such situations + /// one can add a `#[skip_traversal(but_impl_despite_trivial_because = ""]` attribute. + /// /// In some rare situations, it may be desirable to skip folding of an item or field (or - /// variant) that might otherwise be of interest to folders: **this is dangerous and could lead - /// to miscompilation if user expectations are not met!** Nevertheless, such can be achieved - /// via a `#[skip_traversal(despite_potential_miscompilation_because = ""]` attribute. + /// variant) that might otherwise be of interest to folders. This can be achieved via a + /// `#[skip_traversal(despite_potential_miscompilation_because = ""]` attribute. + /// Whereas the preceding usages of the `#[skip_traversal]` attribute are guaranteed to be + /// sound by constraining the relevant type to implementors of the `TriviallyTraversable` + /// trait, use of `despite_potential_miscompilation_because` does not add such constraint or + /// provide any such guarantee. **It is therefore dangerous and could lead to miscompilation + /// if user expectations are not met!** /// /// The derived implementation will use `TyCtxt<'tcx>` as the interner iff the annotated type /// has a `'tcx` lifetime parameter; otherwise it will be generic over all interners. It @@ -124,10 +135,21 @@ decl_derive!( /// only be applicable if `T` does not contain anything that may be of interest to visitors /// (thus preventing fields from being so-skipped erroneously). /// + /// By default, `TypeVisitable` cannot be derived on types that contain nothing that may be of + /// interest to visitors as such an implementation is wholly superfluous and probably in error. + /// However, on occasion it may nevertheless be necessary to implement `TypeVisitable` for such + /// types even though any such visit will always be a noop (e.g. so that instances can be used + /// in a generic context that is constrained to implementors of the trait); in such situations + /// one can add a `#[skip_traversal(but_impl_despite_trivial_because = ""]` attribute. + /// /// In some rare situations, it may be desirable to skip visiting of an item or field (or - /// variant) that might otherwise be of interest to visitors: **this is dangerous and could lead - /// to miscompilation if user expectations are not met!** Nevertheless, such can be achieved - /// via a `#[skip_traversal(despite_potential_miscompilation_because = ""]` attribute. + /// variant) that might otherwise be of interest to visitors. This can be achieved via a + /// `#[skip_traversal(despite_potential_miscompilation_because = ""]` attribute. + /// Whereas the preceding usages of the `#[skip_traversal]` attribute are guaranteed to be + /// sound by constraining the relevant type to implementors of the `TriviallyTraversable` + /// trait, use of `despite_potential_miscompilation_because` does not add such constraint or + /// provide any such guarantee. **It is therefore dangerous and could lead to miscompilation + /// if user expectations are not met!** /// /// The derived implementation will use `TyCtxt<'tcx>` as the interner iff the annotated type /// has a `'tcx` lifetime parameter; otherwise it will be generic over all interners. It diff --git a/compiler/rustc_macros/src/traversable.rs b/compiler/rustc_macros/src/traversable.rs index 56ac6e3b7030e..b1ff75282f74c 100644 --- a/compiler/rustc_macros/src/traversable.rs +++ b/compiler/rustc_macros/src/traversable.rs @@ -90,6 +90,15 @@ impl WhenToSkip { if attr.path().is_ident("skip_traversal") { found = Some(attr); attr.parse_nested_meta(|meta| { + if IS_TYPE + && ty == Trivial + && meta.path.is_ident("but_impl_despite_trivial_because") + { + parse_reason(&meta)?; + *self |= Self::Always(meta.error("").span()); + return Ok(()); + } + if meta.path.is_ident("despite_potential_miscompilation_because") { parse_reason(&meta)?; *self |= Self::Forced; @@ -111,9 +120,7 @@ impl WhenToSkip { attr, if IS_TYPE { match ty { - Trivial => { - "trivially traversable types are always skipped, so this attribute is superfluous" - } + Trivial => return Ok(()), // triggers error in caller _ => { "\ Justification must be provided for skipping this potentially interesting type, by specifying\n\ @@ -358,6 +365,15 @@ pub fn traversable_derive( structure.add_where_predicate(skip_traversal(&::default())); } T::traverse(quote! { self }, true, &interner) + } else if ty == Trivial { + return Err(Error::new( + Span::call_site(), + "\ + Traversal of trivial types are no-ops by default, so explicitly deriving the traversable traits for them is rarely necessary.\n\ + If the need has arisen to due the appearance of this type in an anonymous tuple, consider replacing that tuple with a named struct;\n\ + otherwise add `#[skip_traversal(but_impl_despite_trivial_because = \"\")]` to this type.\ + ", + )); } else { // We add predicates to each generic field type, rather than to our generic type parameters. // This results in a "perfect derive" that avoids having to propagate `#[skip_traversal]` annotations diff --git a/compiler/rustc_macros/src/traversable/tests.rs b/compiler/rustc_macros/src/traversable/tests.rs index 64f50cffd5543..9a24ec4f8badf 100644 --- a/compiler/rustc_macros/src/traversable/tests.rs +++ b/compiler/rustc_macros/src/traversable/tests.rs @@ -203,12 +203,41 @@ fn interesting_fields_are_constrained() { } #[test] -fn skipping_trivial_type_is_superfluous() { +fn skipping_trivial_type_requires_justification() { expect! { + { + struct NothingInteresting<'a>; + } => "Traversal of trivial types are no-ops by default" + { #[skip_traversal()] struct NothingInteresting<'a>; - } => "trivially traversable types are always skipped, so this attribute is superfluous" + } => "Traversal of trivial types are no-ops by default" + + { + #[skip_traversal(but_impl_despite_trivial_because = ".", despite_potential_miscompilation_because = ".")] + struct NothingInteresting<'a>; + } => { + impl<'a, I: Interner> TypeFoldable for NothingInteresting<'a> { + fn try_fold_with>(self, folder: &mut T) -> Result { + Ok(self) // no attempt to fold + } + } + } + + { + #[skip_traversal(but_impl_despite_trivial_because = ".")] + struct NothingInteresting<'a>; + } => { + impl<'a, I: Interner> TypeFoldable for NothingInteresting<'a> + where + I: TriviallyTraverses // impl only applies when type actually contains nothing interesting + { + fn try_fold_with>(self, folder: &mut T) -> Result { + Ok(self) // no attempt to fold + } + } + } } } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index ab0c60d7d1781..17efeeed9599b 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -78,6 +78,9 @@ pub type MinCaptureList<'tcx> = Vec>; /// `tcx.closure_env_ty()`. #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable)] +#[skip_traversal( + but_impl_despite_trivial_because = "traversed generically in `rustc_type_ir::PredicateKind`" +)] pub enum ClosureKind { // Warning: Ordering is significant here! The ordering is chosen // because the trait Fn is a subtrait of FnMut and so in turn, and diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e051fa43e0261..9209d21f7e1a8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -251,6 +251,9 @@ pub enum ImplSubject<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)] #[derive(TypeFoldable, TypeVisitable)] +#[skip_traversal(but_impl_despite_trivial_because = " + `ImplPolarity` impls `Relate`, which is a subtrait of `TypeFoldable`. +")] pub enum ImplPolarity { /// `impl Trait for Type` Positive, @@ -306,6 +309,9 @@ pub enum Visibility { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] #[derive(TypeFoldable, TypeVisitable)] +#[skip_traversal(but_impl_despite_trivial_because = " + `BoundConstness` impls `Relate`, which is a subtrait of `TypeFoldable`. +")] pub enum BoundConstness { /// `T: Trait` NotConst, diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 96d07066f97ff..4fd5d4175a015 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -239,6 +239,9 @@ impl Decodable for DefIndex { /// /// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`. #[derive(Clone, PartialEq, Eq, Copy, TypeFoldable, TypeVisitable)] +#[skip_traversal( + but_impl_despite_trivial_because = "traversed generically in `rustc_type_ir::PredicateKind`" +)] // Don't derive order on 64-bit big-endian, so we can be consistent regardless of field order. #[cfg_attr(not(all(target_pointer_width = "64", target_endian = "big")), derive(PartialOrd, Ord))] // On below-64 bit systems we can simply use the derived `Hash` impl diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index 45e8e62f86754..cdb74397cdee6 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -9,6 +9,9 @@ mod tests; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)] #[derive(HashStable_Generic, Encodable, Decodable, TypeFoldable, TypeVisitable)] +#[skip_traversal( + but_impl_despite_trivial_because = "`Abi` impls `Relate`, which is a subtrait of `TypeFoldable`." +)] pub enum Abi { // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the // hashing tests. These are used in many places, so giving them stable values reduces test From f7f7bb9519b7869203f84e939f0e8cf9f0377b35 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 29 Oct 2023 12:10:12 +0000 Subject: [PATCH 23/28] Derive traversable impls for ConstKind --- compiler/rustc_middle/src/ty/consts/kind.rs | 4 ++ .../rustc_middle/src/ty/consts/valtree.rs | 1 + compiler/rustc_middle/src/ty/mod.rs | 2 +- .../rustc_middle/src/ty/structural_impls.rs | 60 +------------------ compiler/rustc_middle/src/ty/sty.rs | 8 ++- compiler/rustc_span/src/lib.rs | 5 +- compiler/rustc_type_ir/src/const_kind.rs | 2 +- 7 files changed, 20 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 4af841fcf9a5f..7a8d7b0783a9d 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -80,6 +80,10 @@ static_assert_size!(super::ConstKind<'_>, 32); /// An inference variable for a const, for use in const generics. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] +#[derive(TypeFoldable, TypeVisitable)] +#[skip_traversal( + but_impl_despite_trivial_because = "traversed generically in `rustc_type_ir::ConstKind`" +)] pub enum InferConst { /// Infer the value of the const. Var(ty::ConstVid), diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index fb7bf78bafe31..4fcce0eb9d3b5 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -17,6 +17,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; /// /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of (nested) `ValTree`. +#[derive(TypeFoldable, TypeVisitable)] pub enum ValTree<'tcx> { /// integers, `bool`, `char` are represented as scalars. /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9209d21f7e1a8..4a1709af03362 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1527,7 +1527,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { /// regions/types/consts within the same universe simply have an unknown relationship to one /// another. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -#[derive(HashStable, TyEncodable, TyDecodable)] +#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub struct Placeholder { pub universe: UniverseIndex, pub bound: T, diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index bbe72a6142162..e67aa4cd129e2 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,9 +7,7 @@ use crate::mir::interpret; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{ - self, noop_if_trivially_traversable, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt, -}; +use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_hir::def::Namespace; use rustc_span::source_map::Spanned; use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx}; @@ -714,33 +712,7 @@ impl<'tcx> TypeSuperFoldable> for ty::Const<'tcx> { folder: &mut F, ) -> Result { let ty = self.ty().try_fold_with(folder)?; - let kind = match self.kind() { - ConstKind::Param(p) => ConstKind::Param(noop_if_trivially_traversable!( - p.try_fold_with::>(folder) - )?), - ConstKind::Infer(i) => ConstKind::Infer(noop_if_trivially_traversable!( - i.try_fold_with::>(folder) - )?), - ConstKind::Bound(d, b) => ConstKind::Bound( - noop_if_trivially_traversable!(d.try_fold_with::>(folder))?, - noop_if_trivially_traversable!(b.try_fold_with::>(folder))?, - ), - ConstKind::Placeholder(p) => ConstKind::Placeholder(noop_if_trivially_traversable!( - p.try_fold_with::>(folder) - )?), - ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(noop_if_trivially_traversable!( - uv.try_fold_with::>(folder) - )?), - ConstKind::Value(v) => ConstKind::Value(noop_if_trivially_traversable!( - v.try_fold_with::>(folder) - )?), - ConstKind::Error(e) => ConstKind::Error(noop_if_trivially_traversable!( - e.try_fold_with::>(folder) - )?), - ConstKind::Expr(e) => ConstKind::Expr(noop_if_trivially_traversable!( - e.try_fold_with::>(folder) - )?), - }; + let kind = self.kind().try_fold_with(folder)?; if ty != self.ty() || kind != self.kind() { Ok(folder.interner().mk_ct_from_kind(kind, ty)) } else { @@ -755,33 +727,7 @@ impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { visitor: &mut V, ) -> ControlFlow { self.ty().visit_with(visitor)?; - match &self.kind() { - ConstKind::Param(p) => { - noop_if_trivially_traversable!(p.visit_with::>(visitor)) - } - ConstKind::Infer(i) => { - noop_if_trivially_traversable!(i.visit_with::>(visitor)) - } - ConstKind::Bound(d, b) => { - noop_if_trivially_traversable!(d.visit_with::>(visitor))?; - noop_if_trivially_traversable!(b.visit_with::>(visitor)) - } - ConstKind::Placeholder(p) => { - noop_if_trivially_traversable!(p.visit_with::>(visitor)) - } - ConstKind::Unevaluated(uv) => { - noop_if_trivially_traversable!(uv.visit_with::>(visitor)) - } - ConstKind::Value(v) => { - noop_if_trivially_traversable!(v.visit_with::>(visitor)) - } - ConstKind::Error(e) => { - noop_if_trivially_traversable!(e.visit_with::>(visitor)) - } - ConstKind::Expr(e) => { - noop_if_trivially_traversable!(e.visit_with::>(visitor)) - } - } + self.kind().visit_with(visitor) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 44592b10d5574..3a9bef553799c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1445,7 +1445,10 @@ impl<'tcx> ParamTy { } #[derive(Copy, Clone, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)] -#[derive(HashStable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] +#[skip_traversal( + but_impl_despite_trivial_because = "traversed generically in `rustc_type_ir::ConstKind`" +)] pub struct ParamConst { pub index: u32, pub name: Symbol, @@ -1618,7 +1621,8 @@ impl Atom for RegionVid { } rustc_index::newtype_index! { - #[derive(HashStable)] + #[derive(HashStable, TypeFoldable, TypeVisitable)] + #[skip_traversal(but_impl_despite_trivial_because = "traversed generically in `rustc_type_ir::ConstKind`")] #[debug_format = "{}"] pub struct BoundVar {} } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index fc13bdff36f5d..09e17ce93d26f 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2247,7 +2247,10 @@ where /// The `()` field is necessary: it is non-`pub`, which means values of this /// type cannot be constructed outside of this crate. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, TypeFoldable, TypeVisitable)] +#[skip_traversal( + but_impl_despite_trivial_because = "traversed generically in `rustc_type_ir::ConstKind`" +)] pub struct ErrorGuaranteed(()); impl ErrorGuaranteed { diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 33782b13ca8f5..704fdc9e41a47 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -7,7 +7,7 @@ use crate::{DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Int use self::ConstKind::*; /// Represents a constant in Rust. -#[derive(derivative::Derivative)] +#[derive(derivative::Derivative, TypeFoldable, TypeVisitable)] #[derivative( Clone(bound = ""), PartialOrd(bound = ""), From 68b69c9234e1757d12d7d98371094c66784b0ed1 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 29 Oct 2023 12:11:16 +0000 Subject: [PATCH 24/28] Derive traversable impls for more type lib kinds --- compiler/rustc_type_ir/src/canonical.rs | 29 +--- compiler/rustc_type_ir/src/macros.rs | 2 - compiler/rustc_type_ir/src/predicate_kind.rs | 131 +------------------ 3 files changed, 3 insertions(+), 159 deletions(-) diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index ace9eade7f69b..abd5d0fc0b624 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -1,17 +1,14 @@ use std::fmt; use std::hash::Hash; -use std::ops::ControlFlow; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use crate::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::visit::{TypeVisitable, TypeVisitor}; use crate::{HashStableContext, Interner, UniverseIndex}; /// A "canonicalized" type `V` is one where all free inference /// variables have been rewritten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. -#[derive(derivative::Derivative)] +#[derive(derivative::Derivative, TypeFoldable, TypeVisitable)] #[derivative(Clone(bound = "V: Clone"), Hash(bound = "V: Hash"))] #[derive(TyEncodable, TyDecodable)] pub struct Canonical { @@ -102,27 +99,3 @@ impl fmt::Debug for Canonical { } impl Copy for Canonical where I::CanonicalVars: Copy {} - -impl> TypeFoldable for Canonical -where - I::CanonicalVars: TypeFoldable, -{ - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(Canonical { - value: self.value.try_fold_with(folder)?, - max_universe: self.max_universe.try_fold_with(folder)?, - variables: self.variables.try_fold_with(folder)?, - }) - } -} - -impl> TypeVisitable for Canonical -where - I::CanonicalVars: TypeVisitable, -{ - fn visit_with>(&self, folder: &mut F) -> ControlFlow { - self.value.visit_with(folder)?; - self.max_universe.visit_with(folder)?; - self.variables.visit_with(folder) - } -} diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 73dbbcb74ec41..b2097d7e31e60 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -42,8 +42,6 @@ macro_rules! TrivialTypeTraversalImpls { TrivialTypeTraversalImpls! { (), - crate::AliasRelationDirection, - crate::UniverseIndex, } #[macro_export] diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 48662d4264235..82f05ed4e4591 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -1,14 +1,11 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use std::fmt; -use std::ops::ControlFlow; -use crate::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::visit::{TypeVisitable, TypeVisitor}; use crate::{HashStableContext, Interner}; /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. -#[derive(derivative::Derivative)] +#[derive(derivative::Derivative, TypeFoldable, TypeVisitable)] #[derivative(Clone(bound = ""), Hash(bound = ""))] #[derive(TyEncodable, TyDecodable)] pub enum ClauseKind { @@ -106,60 +103,7 @@ where } } -impl TypeFoldable for ClauseKind -where - I::Ty: TypeFoldable, - I::Const: TypeFoldable, - I::GenericArg: TypeFoldable, - I::TraitPredicate: TypeFoldable, - I::ProjectionPredicate: TypeFoldable, - I::TypeOutlivesPredicate: TypeFoldable, - I::RegionOutlivesPredicate: TypeFoldable, -{ - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(match self { - ClauseKind::Trait(p) => ClauseKind::Trait(p.try_fold_with(folder)?), - ClauseKind::RegionOutlives(p) => ClauseKind::RegionOutlives(p.try_fold_with(folder)?), - ClauseKind::TypeOutlives(p) => ClauseKind::TypeOutlives(p.try_fold_with(folder)?), - ClauseKind::Projection(p) => ClauseKind::Projection(p.try_fold_with(folder)?), - ClauseKind::ConstArgHasType(c, t) => { - ClauseKind::ConstArgHasType(c.try_fold_with(folder)?, t.try_fold_with(folder)?) - } - ClauseKind::WellFormed(p) => ClauseKind::WellFormed(p.try_fold_with(folder)?), - ClauseKind::ConstEvaluatable(p) => { - ClauseKind::ConstEvaluatable(p.try_fold_with(folder)?) - } - }) - } -} - -impl TypeVisitable for ClauseKind -where - I::Ty: TypeVisitable, - I::Const: TypeVisitable, - I::GenericArg: TypeVisitable, - I::TraitPredicate: TypeVisitable, - I::ProjectionPredicate: TypeVisitable, - I::TypeOutlivesPredicate: TypeVisitable, - I::RegionOutlivesPredicate: TypeVisitable, -{ - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - match self { - ClauseKind::Trait(p) => p.visit_with(visitor), - ClauseKind::RegionOutlives(p) => p.visit_with(visitor), - ClauseKind::TypeOutlives(p) => p.visit_with(visitor), - ClauseKind::Projection(p) => p.visit_with(visitor), - ClauseKind::ConstArgHasType(c, t) => { - c.visit_with(visitor)?; - t.visit_with(visitor) - } - ClauseKind::WellFormed(p) => p.visit_with(visitor), - ClauseKind::ConstEvaluatable(p) => p.visit_with(visitor), - } - } -} - -#[derive(derivative::Derivative)] +#[derive(derivative::Derivative, TypeFoldable, TypeVisitable)] #[derivative(Clone(bound = ""), Hash(bound = ""))] #[derive(TyEncodable, TyDecodable)] pub enum PredicateKind { @@ -289,77 +233,6 @@ where } } -impl TypeFoldable for PredicateKind -where - I::DefId: TypeFoldable, - I::Const: TypeFoldable, - I::GenericArgs: TypeFoldable, - I::Term: TypeFoldable, - I::CoercePredicate: TypeFoldable, - I::SubtypePredicate: TypeFoldable, - I::ClosureKind: TypeFoldable, - ClauseKind: TypeFoldable, -{ - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(match self { - PredicateKind::Clause(c) => PredicateKind::Clause(c.try_fold_with(folder)?), - PredicateKind::ObjectSafe(d) => PredicateKind::ObjectSafe(d.try_fold_with(folder)?), - PredicateKind::ClosureKind(d, g, k) => PredicateKind::ClosureKind( - d.try_fold_with(folder)?, - g.try_fold_with(folder)?, - k.try_fold_with(folder)?, - ), - PredicateKind::Subtype(s) => PredicateKind::Subtype(s.try_fold_with(folder)?), - PredicateKind::Coerce(s) => PredicateKind::Coerce(s.try_fold_with(folder)?), - PredicateKind::ConstEquate(a, b) => { - PredicateKind::ConstEquate(a.try_fold_with(folder)?, b.try_fold_with(folder)?) - } - PredicateKind::Ambiguous => PredicateKind::Ambiguous, - PredicateKind::AliasRelate(a, b, d) => PredicateKind::AliasRelate( - a.try_fold_with(folder)?, - b.try_fold_with(folder)?, - d.try_fold_with(folder)?, - ), - }) - } -} - -impl TypeVisitable for PredicateKind -where - I::DefId: TypeVisitable, - I::Const: TypeVisitable, - I::GenericArgs: TypeVisitable, - I::Term: TypeVisitable, - I::CoercePredicate: TypeVisitable, - I::SubtypePredicate: TypeVisitable, - I::ClosureKind: TypeVisitable, - ClauseKind: TypeVisitable, -{ - fn visit_with>(&self, visitor: &mut V) -> ControlFlow { - match self { - PredicateKind::Clause(p) => p.visit_with(visitor), - PredicateKind::ObjectSafe(d) => d.visit_with(visitor), - PredicateKind::ClosureKind(d, g, k) => { - d.visit_with(visitor)?; - g.visit_with(visitor)?; - k.visit_with(visitor) - } - PredicateKind::Subtype(s) => s.visit_with(visitor), - PredicateKind::Coerce(s) => s.visit_with(visitor), - PredicateKind::ConstEquate(a, b) => { - a.visit_with(visitor)?; - b.visit_with(visitor) - } - PredicateKind::Ambiguous => ControlFlow::Continue(()), - PredicateKind::AliasRelate(a, b, d) => { - a.visit_with(visitor)?; - b.visit_with(visitor)?; - d.visit_with(visitor) - } - } - } -} - #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] #[derive(HashStable_Generic, Encodable, Decodable)] pub enum AliasRelationDirection { From 3858eb34211f6b901b5c1f1677f01fa25d0a374f Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sat, 25 Feb 2023 23:21:49 +0000 Subject: [PATCH 25/28] Remove TrivialTypeTraversal macros --- compiler/rustc_middle/src/macros.rs | 49 ---------------------------- compiler/rustc_type_ir/src/fold.rs | 10 ++++++ compiler/rustc_type_ir/src/macros.rs | 46 -------------------------- compiler/rustc_type_ir/src/visit.rs | 10 ++++++ 4 files changed, 20 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index ee971c2931eab..9f84e0754c2e2 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -54,52 +54,3 @@ macro_rules! TrivialLiftImpls { )+ }; } - -/// Used for types that are `Copy` and which **do not care arena -/// allocated data** (i.e., don't need to be folded). -#[macro_export] -macro_rules! TrivialTypeTraversalImpls { - ($(for { $($generic:tt)+ } { $interner:ty } { $ty:ty })+) => { - $( - impl<$($generic)+> $crate::ty::fold::TypeFoldable<$interner> for $ty { - fn try_fold_with>( - self, - _: &mut F, - ) -> ::std::result::Result { - Ok(self) - } - - #[inline] - fn fold_with>( - self, - _: &mut F, - ) -> Self { - self - } - } - - impl<$($generic)+> $crate::ty::visit::TypeVisitable<$interner> for $ty { - #[inline] - fn visit_with>( - &self, - _: &mut F) - -> ::std::ops::ControlFlow - { - ::std::ops::ControlFlow::Continue(()) - } - } - )+ - }; - - (for <$tcx:lifetime> { $($ty:ty),+ $(,)? }) => { - TrivialTypeTraversalImpls! { - $(for { $tcx } { $crate::ty::TyCtxt<$tcx> } { $ty })+ - } - }; - - ($($ty:ty),+ $(,)?) => { - TrivialTypeTraversalImpls! { - $(for { I: $crate::ty::Interner } { I } { $ty })+ - } - }; -} diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 7f67f7e7a030b..03b29ca17e8e7 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -290,6 +290,16 @@ impl, T> SpecTypeFoldable for &PhantomData<(I, T)> { /////////////////////////////////////////////////////////////////////////// // Traversable implementations for upstream types. +// `()` is (obviously) a no-op traversal and therefore the auto-deref specialisation normally +// negates any need for explicit implementation, however there are implementations of +// `QueryTypeOp` that have have unit `QueryResponse` -- and that associated type must be +// traversable for some generic operations to work upon it. +impl TypeFoldable for () { + fn try_fold_with>(self, _: &mut F) -> Result<(), F::Error> { + Ok(()) + } +} + // We provide implementations for 2- and 3-element tuples, however (absent specialisation) // we can only provide for one case: we choose our implementations to be where all elements // themselves implement the respective traits; thus if an element is a no-op traversal, it diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index b2097d7e31e60..29937ac08a3a4 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -1,49 +1,3 @@ -/// Used for types that are `Copy` and which **do not care arena -/// allocated data** (i.e., don't need to be folded). -macro_rules! TrivialTypeTraversalImpls { - ($($ty:ty,)+) => { - $( - impl $crate::fold::TypeFoldable for $ty { - fn try_fold_with>( - self, - _: &mut F, - ) -> ::std::result::Result { - Ok(self) - } - - #[inline] - fn fold_with>( - self, - _: &mut F, - ) -> Self { - self - } - } - - impl $crate::visit::TypeVisitable for $ty { - #[inline] - fn visit_with>( - &self, - _: &mut F) - -> ::std::ops::ControlFlow - { - ::std::ops::ControlFlow::Continue(()) - } - } - )+ - }; -} - -/////////////////////////////////////////////////////////////////////////// -// Atomic structs -// -// For things that don't carry any arena-allocated data (and are -// copy...), just add them to this list. - -TrivialTypeTraversalImpls! { - (), -} - #[macro_export] macro_rules! noop_if_trivially_traversable { ($val:tt.try_fold_with::<$interner:ty>($folder:expr)) => {{ diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index c6a4e28ddac1a..686e57a435d41 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -158,6 +158,16 @@ impl, T: ?Sized> SpecTypeVisitable for &PhantomData<(I, /////////////////////////////////////////////////////////////////////////// // Traversable implementations for upstream types. +// `()` is (obviously) a no-op traversal and therefore the auto-deref specialisation normally +// negates any need for explicit implementation, however there are implementations of +// `QueryTypeOp` that have have unit `QueryResponse` -- and that associated type must be +// traversable for some generic operations to work upon it. +impl TypeVisitable for () { + fn visit_with>(&self, _: &mut V) -> ControlFlow { + ControlFlow::Continue(()) + } +} + // We provide implementations for 2- and 3-element tuples, however (absent specialisation) // we can only provide for one case: we choose our implementations to be where all elements // themselves implement the respective traits; thus if an element is a no-op traversal, it From cdc7218d19687f295f38faa8be155136ce1af36b Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 26 Feb 2023 00:36:20 +0000 Subject: [PATCH 26/28] Unimpl TypeSuperVisitable for UnevaluatedConst UnevaluatedConst is not a type of any interest to folders or visitors, and therefore should not be "super visitable" at all. --- compiler/rustc_middle/src/ty/structural_impls.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index e67aa4cd129e2..098a39552ef74 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -730,12 +730,3 @@ impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { self.kind().visit_with(visitor) } } - -impl<'tcx> TypeSuperVisitable> for ty::UnevaluatedConst<'tcx> { - fn super_visit_with>>( - &self, - visitor: &mut V, - ) -> ControlFlow { - self.args.visit_with(visitor) - } -} From c9a59582af43e115cc1e0686850b137976bd1ec6 Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 26 Feb 2023 11:46:52 +0000 Subject: [PATCH 27/28] Generify traversals of interned types --- compiler/rustc_data_structures/src/intern.rs | 4 ++ compiler/rustc_middle/src/traits/solve.rs | 54 ++------------------ compiler/rustc_middle/src/ty/context.rs | 14 +++-- compiler/rustc_type_ir/src/fold.rs | 11 +++- compiler/rustc_type_ir/src/visit.rs | 8 ++- 5 files changed, 34 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs index e0f8c350c2a86..7d1482a171b7b 100644 --- a/compiler/rustc_data_structures/src/intern.rs +++ b/compiler/rustc_data_structures/src/intern.rs @@ -24,6 +24,10 @@ mod private { #[rustc_pass_by_value] pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst); +pub trait Internable<'a, I>: Sized { + fn intern(self, interner: I) -> Interned<'a, Self>; +} + impl<'a, T> Interned<'a, T> { /// Create a new `Interned` value. The value referred to *must* be interned /// and thus be unique, and it *must* remain unique in the future. This diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 4520afe69995a..0c6bf273ee23d 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -3,9 +3,7 @@ use rustc_data_structures::intern::Interned; use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; use crate::traits::query::NoSolution; use crate::traits::{Canonical, DefiningAnchor}; -use crate::ty::{ - self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, -}; +use crate::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_span::def_id::DefId; use super::BuiltinImplSource; @@ -112,7 +110,7 @@ pub struct PredefinedOpaquesData<'tcx> { pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable, TypeVisitable, TypeFoldable)] pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>); impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { @@ -135,7 +133,7 @@ pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>; /// solver, merge the two responses again. pub type QueryResult<'tcx> = Result, NoSolution>; -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { @@ -154,52 +152,6 @@ pub struct ExternalConstraintsData<'tcx> { pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, } -// FIXME: Having to clone `region_constraints` for folding feels bad and -// probably isn't great wrt performance. -// -// Not sure how to fix this, maybe we should also intern `opaque_types` and -// `region_constraints` here or something. -impl<'tcx> TypeFoldable> for ExternalConstraints<'tcx> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - Ok(folder.interner().mk_external_constraints((*self).clone().try_fold_with(folder)?)) - } -} - -impl<'tcx> TypeVisitable> for ExternalConstraints<'tcx> { - fn visit_with>>( - &self, - visitor: &mut V, - ) -> std::ops::ControlFlow { - (**self).visit_with(visitor) - } -} - -// FIXME: Having to clone `region_constraints` for folding feels bad and -// probably isn't great wrt performance. -// -// Not sure how to fix this, maybe we should also intern `opaque_types` and -// `region_constraints` here or something. -impl<'tcx> TypeFoldable> for PredefinedOpaques<'tcx> { - fn try_fold_with>>( - self, - folder: &mut F, - ) -> Result { - Ok(folder.interner().mk_predefined_opaques_in_body((*self).clone().try_fold_with(folder)?)) - } -} - -impl<'tcx> TypeVisitable> for PredefinedOpaques<'tcx> { - fn visit_with>>( - &self, - visitor: &mut V, - ) -> std::ops::ControlFlow { - (**self).visit_with(visitor) - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] pub enum IsNormalizesToHack { Yes, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9db12f236303c..e4da893478894 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -34,7 +34,7 @@ use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::intern::Interned; +use rustc_data_structures::intern::{Internable, Interned}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -1549,11 +1549,17 @@ macro_rules! direct_interners { } } + impl<'tcx> Internable<'tcx, TyCtxt<'tcx>> for $ty { + fn intern(self, tcx: TyCtxt<'tcx>) -> Interned<'tcx, Self> { + Interned::new_unchecked(tcx.interners.$name.intern(self, |v| { + InternedInSet(tcx.interners.arena.alloc(v)) + }).0) + } + } + impl<'tcx> TyCtxt<'tcx> { $vis fn $method(self, v: $ty) -> $ret_ty { - $ret_ctor(Interned::new_unchecked(self.interners.$name.intern(v, |v| { - InternedInSet(self.interners.arena.alloc(v)) - }).0)) + $ret_ctor(v.intern(self)) } })+ } diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 03b29ca17e8e7..23794ff346896 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -45,7 +45,10 @@ //! - u.fold_with(folder) //! ``` -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::{ + intern::{Internable, Interned}, + sync::Lrc, +}; use rustc_index::{Idx, IndexVec}; use std::marker::PhantomData; use std::mem; @@ -403,3 +406,9 @@ impl, Ix: Idx> TypeFoldable for IndexVec + TypeFoldable> TypeFoldable for Interned<'a, T> { + fn try_fold_with>(self, folder: &mut F) -> Result { + (*self).clone().try_fold_with(folder).map(|v| v.intern(folder.interner())) + } +} diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 686e57a435d41..f0ff400d49c81 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -41,7 +41,7 @@ //! - u.visit_with(visitor) //! ``` -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::{intern::Interned, sync::Lrc}; use rustc_index::{Idx, IndexVec}; use std::fmt; use std::marker::PhantomData; @@ -250,3 +250,9 @@ impl, Ix: Idx> TypeVisitable for IndexVec> TypeVisitable for Interned<'_, T> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + (**self).visit_with(visitor) + } +} From 419cc6d3f918563dc89d0d21383b4625c214b1ce Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Sun, 29 Oct 2023 12:03:25 +0000 Subject: [PATCH 28/28] Enforce ClosureOutlivesSubjectTy not traversable Previously only enforced via comment, now via negative impls. --- compiler/rustc_middle/src/mir/query.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 468bf0df0b2fb..7be6ecc417cbe 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -399,14 +399,16 @@ pub enum ClosureOutlivesSubject<'tcx> { /// This abstraction is necessary because the type may include `ReVar` regions, /// which is what we use internally within NLL code, and they can't be used in /// a query response. -/// -/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this -/// type is not recognized as a binder for late-bound region. #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub struct ClosureOutlivesSubjectTy<'tcx> { inner: Ty<'tcx>, } +/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this +/// type is not recognized as a binder for late-bound region. +impl<'tcx, I> !ty::TypeFoldable for ClosureOutlivesSubjectTy<'tcx> {} +impl<'tcx, I> !ty::TypeVisitable for ClosureOutlivesSubjectTy<'tcx> {} + impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { /// All regions of `ty` must be of kind `ReVar` and must represent /// universal regions *external* to the closure.