MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, PointerArithmetic, Provenance,
Scalar, StackPopJump,
};
-use crate::transform::validate;
+use crate::util;
pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
/// Stores the `Machine` instance.
// all normal lifetimes are erased, higher-ranked types with their
// late-bound lifetimes are still around and can lead to type
// differences.
- if validate::is_subtype(tcx, param_env, src.ty, dest.ty) {
+ if util::is_subtype(tcx, param_env, src.ty, dest.ty) {
// Make sure the layout is equal, too -- just to be safe. Miri really
// needs layout equality. For performance reason we skip this check when
// the types are equal. Equal types *can* have different layouts when
use rustc_data_structures::fx::FxHashSet;
use rustc_index::bit_set::BitSet;
-use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
-use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_mir_dataflow::storage::always_storage_live_locals;
use rustc_mir_dataflow::{Analysis, ResultsCursor};
use rustc_target::abi::{Size, VariantIdx};
-use rustc_trait_selection::traits::ObligationCtxt;
#[derive(Copy, Clone, Debug)]
enum EdgeKind {
}
}
-/// 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)
-}
-
-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.clone(), param_env, src);
- let dest = ocx.normalize(cause.clone(), param_env, dest);
- let Ok(infer_ok) = infcx.at(&cause, param_env).sub(src, dest) else {
- return false;
- };
- let () = ocx.register_infer_ok_obligations(infer_ok);
- 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()
-}
struct TypeChecker<'a, 'tcx> {
when: &'a str,
body: &'a Body<'tcx>,
return true;
}
- is_subtype(self.tcx, self.param_env, src, dest)
+ crate::util::is_subtype(self.tcx, self.param_env, src, dest)
}
}
--- /dev/null
+//! 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`.
+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.clone(), param_env, src);
+ let dest = ocx.normalize(cause.clone(), param_env, dest);
+ let Ok(infer_ok) = infcx.at(&cause, param_env).sub(src, dest) else {
+ return false;
+ };
+ let () = ocx.register_infer_ok_obligations(infer_ok);
+ 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()
+}
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;
debug!(?self.ambient_variance);
// In a bivariant context this always succeeds.
- let r = if self.ambient_variance == ty::Variance::Bivariant {
- a
- } else {
- self.relate(a, b)?
- };
+ let r =
+ if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? };
self.ambient_variance = old_ambient_variance;
use rustc_target::spec::abi::Abi;
use crate::simplify::{remove_dead_blocks, CfgSimplifier};
-use crate::validate;
+use crate::util;
use crate::MirPass;
use std::iter;
use std::ops::{Range, RangeFrom};
let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty;
let output_type = callee_body.return_ty();
- if !validate::is_subtype(self.tcx, self.param_env, output_type, destination_ty) {
+ if !util::is_subtype(self.tcx, self.param_env, output_type, destination_ty) {
trace!(?output_type, ?destination_ty);
return Err("failed to normalize return type");
}
arg_tuple_tys.iter().zip(callee_body.args_iter().skip(skipped_args))
{
let input_type = callee_body.local_decls[input].ty;
- if !validate::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
+ if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
trace!(?arg_ty, ?input_type);
return Err("failed to normalize tuple argument type");
}
for (arg, input) in args.iter().zip(callee_body.args_iter()) {
let input_type = callee_body.local_decls[input].ty;
let arg_ty = arg.ty(&caller_body.local_decls, self.tcx);
- if !validate::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
+ if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) {
trace!(?arg_ty, ?input_type);
return Err("failed to normalize argument type");
}
let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) };
let parent_ty = parent.ty(&self.callee_body.local_decls, self.tcx);
let check_equal = |this: &mut Self, f_ty| {
- if !validate::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) {
+ if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) {
trace!(?ty, ?f_ty);
this.validation = Err("failed to normalize projection type");
return;