summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/util
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_const_eval/src/util
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_const_eval/src/util')
-rw-r--r--compiler/rustc_const_eval/src/util/aggregate.rs3
-rw-r--r--compiler/rustc_const_eval/src/util/call_kind.rs22
-rw-r--r--compiler/rustc_const_eval/src/util/compare_types.rs63
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs4
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs189
5 files changed, 270 insertions, 11 deletions
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<Item = (Operand<'tcx>, 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<Self::Region, Self::Error> {
+ Ok(self)
+ }
+
+ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
+ 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::Const, Self::Error> {
+ self.pretty_print_const(ct, false)
+ }
+
+ fn print_dyn_existential(
+ self,
+ predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
+ ) -> Result<Self::DynExistential, Self::Error> {
+ self.pretty_print_dyn_existential(predicates)
+ }
+
+ fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
+ self.path.push_str(self.tcx.crate_name(cnum).as_str());
+ Ok(self)
+ }
+
+ fn path_qualified(
+ self,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ self.pretty_path_qualified(self_ty, trait_ref)
+ }
+
+ fn path_append_impl(
+ self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ _disambiguated_data: &DisambiguatedDefPathData,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ 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<Self::Path, Self::Error>,
+ disambiguated_data: &DisambiguatedDefPathData,
+ ) -> Result<Self::Path, Self::Error> {
+ 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<Self::Path, Self::Error>,
+ args: &[GenericArg<'tcx>],
+ ) -> Result<Self::Path, Self::Error> {
+ 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<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error>
+ 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<Self, Self::Error>,
+ ) -> Result<Self, Self::Error> {
+ 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
+}