From 4547b622d8d29df964fa2914213088b148c498fc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:32 +0200 Subject: Merging upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_const_eval/src/util/aggregate.rs | 3 +- compiler/rustc_const_eval/src/util/call_kind.rs | 22 +-- .../rustc_const_eval/src/util/compare_types.rs | 63 +++++++ compiler/rustc_const_eval/src/util/mod.rs | 4 + compiler/rustc_const_eval/src/util/type_name.rs | 189 +++++++++++++++++++++ 5 files changed, 270 insertions(+), 11 deletions(-) create mode 100644 compiler/rustc_const_eval/src/util/compare_types.rs create mode 100644 compiler/rustc_const_eval/src/util/type_name.rs (limited to 'compiler/rustc_const_eval/src/util') diff --git a/compiler/rustc_const_eval/src/util/aggregate.rs b/compiler/rustc_const_eval/src/util/aggregate.rs index 180a40043..c43de3368 100644 --- a/compiler/rustc_const_eval/src/util/aggregate.rs +++ b/compiler/rustc_const_eval/src/util/aggregate.rs @@ -9,10 +9,11 @@ use std::iter::TrustedLen; /// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields. /// /// Produces something like -/// +/// ```ignore (ilustrative) /// (lhs as Variant).field0 = arg0; // We only have a downcast if this is an enum /// (lhs as Variant).field1 = arg1; /// discriminant(lhs) = variant_index; // If lhs is an enum or generator. +/// ``` pub fn expand_aggregate<'tcx>( orig_lhs: Place<'tcx>, operands: impl Iterator, Ty<'tcx>)> + TrustedLen, diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs index af9d83f06..b38a6c551 100644 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ b/compiler/rustc_const_eval/src/util/call_kind.rs @@ -3,7 +3,7 @@ //! context. use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItemGroup; +use rustc_hir::{lang_items, LangItem}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt}; use rustc_span::symbol::Ident; @@ -26,7 +26,7 @@ impl CallDesugaringKind { match self { Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(), Self::QuestionBranch | Self::TryBlockFromOutput => { - tcx.lang_items().try_trait().unwrap() + tcx.require_lang_item(LangItem::Try, None) } Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), } @@ -74,22 +74,24 @@ pub fn call_kind<'tcx>( } }); - let fn_call = parent - .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p)); + let fn_call = parent.and_then(|p| { + lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) + }); - let operator = (!from_hir_call) - .then(|| parent) - .flatten() - .and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p)); + let operator = if !from_hir_call && let Some(p) = parent { + lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) + } else { + None + }; let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); // Check for a 'special' use of 'self' - // an FnOnce call, an operator (e.g. `<<`), or a // deref coercion. - let kind = if let Some(&trait_id) = fn_call { + let kind = if let Some(trait_id) = fn_call { Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) }) - } else if let Some(&trait_id) = operator { + } else if let Some(trait_id) = operator { Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) }) } else if is_deref { let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs new file mode 100644 index 000000000..be786569c --- /dev/null +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -0,0 +1,63 @@ +//! Routines to check for relations between fully inferred types. +//! +//! FIXME: Move this to a more general place. The utility of this extends to +//! other areas of the compiler as well. + +use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCause; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_trait_selection::traits::ObligationCtxt; + +/// Returns whether the two types are equal up to subtyping. +/// +/// This is used in case we don't know the expected subtyping direction +/// and still want to check whether anything is broken. +pub fn is_equal_up_to_subtyping<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + src: Ty<'tcx>, + dest: Ty<'tcx>, +) -> bool { + // Fast path. + if src == dest { + return true; + } + + // Check for subtyping in either direction. + is_subtype(tcx, param_env, src, dest) || is_subtype(tcx, param_env, dest, src) +} + +/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. +/// +/// This mostly ignores opaque types as it can be used in constraining contexts +/// while still computing the final underlying type. +pub fn is_subtype<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + src: Ty<'tcx>, + dest: Ty<'tcx>, +) -> bool { + if src == dest { + return true; + } + + let mut builder = + tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble); + let infcx = builder.build(); + let ocx = ObligationCtxt::new(&infcx); + let cause = ObligationCause::dummy(); + let src = ocx.normalize(&cause, param_env, src); + let dest = ocx.normalize(&cause, param_env, dest); + match ocx.sub(&cause, param_env, src, dest) { + Ok(()) => {} + Err(_) => return false, + }; + let errors = ocx.select_all_or_error(); + // With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing` + // we would get unification errors because we're unable to look into opaque types, + // even if they're constrained in our current function. + // + // It seems very unlikely that this hides any bugs. + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + errors.is_empty() +} diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 7a05cfd23..76ea5a24e 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -2,11 +2,15 @@ pub mod aggregate; mod alignment; mod call_kind; pub mod collect_writes; +mod compare_types; mod find_self_call; mod might_permit_raw_init; +mod type_name; pub use self::aggregate::expand_aggregate; pub use self::alignment::is_disaligned; pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind}; +pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype}; pub use self::find_self_call::find_self_call; pub use self::might_permit_raw_init::might_permit_raw_init; +pub use self::type_name::type_name; diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs new file mode 100644 index 000000000..14c8c8802 --- /dev/null +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -0,0 +1,189 @@ +use rustc_data_structures::intern::Interned; +use rustc_hir::def_id::CrateNum; +use rustc_hir::definitions::DisambiguatedDefPathData; +use rustc_middle::ty::{ + self, + print::{PrettyPrinter, Print, Printer}, + subst::{GenericArg, GenericArgKind}, + Ty, TyCtxt, +}; +use std::fmt::Write; + +struct AbsolutePathPrinter<'tcx> { + tcx: TyCtxt<'tcx>, + path: String, +} + +impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { + type Error = std::fmt::Error; + + type Path = Self; + type Region = Self; + type Type = Self; + type DynExistential = Self; + type Const = Self; + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn print_region(self, _region: ty::Region<'_>) -> Result { + Ok(self) + } + + fn print_type(mut self, ty: Ty<'tcx>) -> Result { + match *ty.kind() { + // Types without identity. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnPtr(_) + | ty::Never + | ty::Tuple(_) + | ty::Dynamic(_, _, _) => self.pretty_print_type(ty), + + // Placeholders (all printed as `_` to uniformize them). + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { + write!(self, "_")?; + Ok(self) + } + + // Types with identity (print the module path). + ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs) + | ty::FnDef(def_id, substs) + | ty::Opaque(def_id, substs) + | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) + | ty::Closure(def_id, substs) + | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs), + ty::Foreign(def_id) => self.print_def_path(def_id, &[]), + + ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"), + } + } + + fn print_const(self, ct: ty::Const<'tcx>) -> Result { + self.pretty_print_const(ct, false) + } + + fn print_dyn_existential( + self, + predicates: &'tcx ty::List>, + ) -> Result { + self.pretty_print_dyn_existential(predicates) + } + + fn path_crate(mut self, cnum: CrateNum) -> Result { + self.path.push_str(self.tcx.crate_name(cnum).as_str()); + Ok(self) + } + + fn path_qualified( + self, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.pretty_path_qualified(self_ty, trait_ref) + } + + fn path_append_impl( + self, + print_prefix: impl FnOnce(Self) -> Result, + _disambiguated_data: &DisambiguatedDefPathData, + self_ty: Ty<'tcx>, + trait_ref: Option>, + ) -> Result { + self.pretty_path_append_impl( + |mut cx| { + cx = print_prefix(cx)?; + + cx.path.push_str("::"); + + Ok(cx) + }, + self_ty, + trait_ref, + ) + } + + fn path_append( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result { + self = print_prefix(self)?; + + write!(self.path, "::{}", disambiguated_data.data).unwrap(); + + Ok(self) + } + + fn path_generic_args( + mut self, + print_prefix: impl FnOnce(Self) -> Result, + args: &[GenericArg<'tcx>], + ) -> Result { + self = print_prefix(self)?; + let args = + args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_))); + if args.clone().next().is_some() { + self.generic_delimiters(|cx| cx.comma_sep(args)) + } else { + Ok(self) + } + } +} + +impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { + fn should_print_region(&self, _region: ty::Region<'_>) -> bool { + false + } + fn comma_sep(mut self, mut elems: impl Iterator) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error>, + { + if let Some(first) = elems.next() { + self = first.print(self)?; + for elem in elems { + self.path.push_str(", "); + self = elem.print(self)?; + } + } + Ok(self) + } + + fn generic_delimiters( + mut self, + f: impl FnOnce(Self) -> Result, + ) -> Result { + write!(self, "<")?; + + self = f(self)?; + + write!(self, ">")?; + + Ok(self) + } + + fn should_print_verbose(&self) -> bool { + // `std::any::type_name` should never print verbose type names + false + } +} + +impl Write for AbsolutePathPrinter<'_> { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + self.path.push_str(s); + Ok(()) + } +} + +pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String { + AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path +} -- cgit v1.2.3