Skip to content

continue TypingMode refactor #132403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 1, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/check_consts/check.rs
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt, TypingMode};
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
use rustc_mir_dataflow::Analysis;
use rustc_mir_dataflow::impls::MaybeStorageLive;
use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -589,7 +589,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// Typeck only does a "non-const" check since it operates on HIR and cannot distinguish
// which path expressions are getting called on and which path expressions are only used
// as function pointers. This is required for correctness.
let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx));
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);

let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args);
7 changes: 0 additions & 7 deletions compiler/rustc_const_eval/src/check_consts/mod.rs
Original file line number Diff line number Diff line change
@@ -32,14 +32,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self {
let def_id = body.source.def_id().expect_local();
let param_env = tcx.param_env(def_id);
Self::new_with_param_env(tcx, body, param_env)
}

pub fn new_with_param_env(
tcx: TyCtxt<'tcx>,
body: &'mir mir::Body<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local());
ConstCx { body, tcx, param_env, const_kind }
}
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/check_consts/ops.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ use rustc_middle::mir::CallSource;
use rustc_middle::span_bug;
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
use rustc_middle::ty::{
self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, TypingMode,
self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty,
suggest_constraining_type_param,
};
use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind};
@@ -116,7 +116,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
let obligation =
Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);

let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx));
let mut selcx = SelectionContext::new(&infcx);
let implsrc = selcx.select(&obligation);

21 changes: 17 additions & 4 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ use rustc_errors::DiagCtxtHandle;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::at::ToTrace;
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::{ObligationCause, Reveal};
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{
@@ -116,6 +116,7 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> {
/// This test should be symmetric, as it is primarily about layout compatibility.
pub(super) fn mir_assign_valid_types<'tcx>(
tcx: TyCtxt<'tcx>,
typing_mode: TypingMode<'tcx>,
param_env: ParamEnv<'tcx>,
src: TyAndLayout<'tcx>,
dest: TyAndLayout<'tcx>,
@@ -124,7 +125,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
// all normal lifetimes are erased, higher-ranked types with their
// late-bound lifetimes are still around and can lead to type
// differences.
if util::relate_types(tcx, param_env, Variance::Covariant, src.ty, dest.ty) {
if util::relate_types(tcx, typing_mode, param_env, Variance::Covariant, 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
@@ -144,6 +145,7 @@ pub(super) fn mir_assign_valid_types<'tcx>(
#[cfg_attr(not(debug_assertions), inline(always))]
pub(super) fn from_known_layout<'tcx>(
tcx: TyCtxtAt<'tcx>,
typing_mode: TypingMode<'tcx>,
param_env: ParamEnv<'tcx>,
known_layout: Option<TyAndLayout<'tcx>>,
compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
@@ -153,7 +155,13 @@ pub(super) fn from_known_layout<'tcx>(
Some(known_layout) => {
if cfg!(debug_assertions) {
let check_layout = compute()?;
if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) {
if !mir_assign_valid_types(
tcx.tcx,
typing_mode,
param_env,
check_layout,
known_layout,
) {
span_bug!(
tcx.span,
"expected type differs from actual type.\nexpected: {}\nactual: {}",
@@ -203,6 +211,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
}

pub fn typing_mode(&self) -> TypingMode<'tcx> {
debug_assert_eq!(self.param_env.reveal(), Reveal::All);
TypingMode::PostAnalysis
}

/// Returns the span of the currently executed statement/terminator.
/// This is the span typically used for error reporting.
#[inline(always)]
@@ -327,7 +340,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
return true;
}
// Slow path: spin up an inference context to check if these traits are sufficiently equal.
let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env));
let infcx = self.tcx.infer_ctxt().build(self.typing_mode());
let ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::dummy_with_span(self.cur_span());
// equate the two trait refs after normalization
5 changes: 4 additions & 1 deletion compiler/rustc_const_eval/src/interpret/operand.rs
Original file line number Diff line number Diff line change
@@ -773,6 +773,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
)?;
if !mir_assign_valid_types(
*self.tcx,
self.typing_mode(),
self.param_env,
self.layout_of(normalized_place_ty)?,
op.layout,
@@ -832,7 +833,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
})
};
let layout =
from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty).into())?;
from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
self.layout_of(ty).into()
})?;
let imm = match val_val {
mir::ConstValue::Indirect { alloc_id, offset } => {
// This is const data, no mutation allowed.
10 changes: 8 additions & 2 deletions compiler/rustc_const_eval/src/interpret/place.rs
Original file line number Diff line number Diff line change
@@ -540,6 +540,7 @@ where
)?;
if !mir_assign_valid_types(
*self.tcx,
self.typing_mode(),
self.param_env,
self.layout_of(normalized_place_ty)?,
place.layout,
@@ -870,8 +871,13 @@ where
) -> InterpResult<'tcx> {
// We do NOT compare the types for equality, because well-typed code can
// actually "transmute" `&mut T` to `&T` in an assignment without a cast.
let layout_compat =
mir_assign_valid_types(*self.tcx, self.param_env, src.layout(), dest.layout());
let layout_compat = mir_assign_valid_types(
*self.tcx,
self.typing_mode(),
self.param_env,
src.layout(),
dest.layout(),
);
if !allow_transmute && !layout_compat {
span_bug!(
self.cur_span(),
13 changes: 7 additions & 6 deletions compiler/rustc_const_eval/src/interpret/stack.rs
Original file line number Diff line number Diff line change
@@ -596,12 +596,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
return interp_ok(layout);
}

let layout = from_known_layout(self.tcx, self.param_env, layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty =
self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
self.layout_of(local_ty).into()
})?;
let layout =
from_known_layout(self.tcx, self.typing_mode(), self.param_env, layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty =
self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
self.layout_of(local_ty).into()
})?;

// Layouts of locals are requested a lot, so we cache them.
state.layout.set(Some(layout));
21 changes: 6 additions & 15 deletions compiler/rustc_const_eval/src/util/compare_types.rs
Original file line number Diff line number Diff line change
@@ -8,24 +8,15 @@ use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance};
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>(
/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
pub fn sub_types<'tcx>(
tcx: TyCtxt<'tcx>,
typing_mode: TypingMode<'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.
relate_types(tcx, param_env, Variance::Covariant, src, dest)
|| relate_types(tcx, param_env, Variance::Covariant, dest, src)
relate_types(tcx, typing_mode, param_env, Variance::Covariant, src, dest)
}

/// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
@@ -35,6 +26,7 @@ pub fn is_equal_up_to_subtyping<'tcx>(
/// because we want to check for type equality.
pub fn relate_types<'tcx>(
tcx: TyCtxt<'tcx>,
typing_mode: TypingMode<'tcx>,
param_env: ParamEnv<'tcx>,
variance: Variance,
src: Ty<'tcx>,
@@ -45,8 +37,7 @@ pub fn relate_types<'tcx>(
}

let mut builder = tcx.infer_ctxt().ignoring_regions();
// FIXME(#132279): This should eventually use the already defined hidden types.
let infcx = builder.build(TypingMode::from_param_env(param_env));
let infcx = builder.build(typing_mode);
let ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::dummy();
let src = ocx.normalize(&cause, param_env, src);
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ mod type_name;

pub use self::alignment::{is_disaligned, is_within_packed};
pub use self::check_validity_requirement::check_validity_requirement;
pub use self::compare_types::{is_equal_up_to_subtyping, relate_types};
pub use self::compare_types::{relate_types, sub_types};
pub use self::type_name::type_name;

/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
11 changes: 10 additions & 1 deletion compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths};
use crate::ty::visit::TypeVisitableExt;
use crate::ty::{
self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt,
self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingMode,
UserTypeAnnotationIndex,
};

@@ -452,6 +452,15 @@ impl<'tcx> Body<'tcx> {
self.basic_blocks.as_mut()
}

pub fn typing_mode(&self, _tcx: TyCtxt<'tcx>) -> TypingMode<'tcx> {
match self.phase {
// FIXME(#132279): the MIR is quite clearly inside of a body, so we
// should instead reveal opaques defined by that body here.
MirPhase::Built | MirPhase::Analysis(_) => TypingMode::non_body_analysis(),
MirPhase::Runtime(_) => TypingMode::PostAnalysis,
}
}

#[inline]
pub fn local_kind(&self, local: Local) -> LocalKind {
let index = local.as_usize();
11 changes: 5 additions & 6 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
@@ -19,9 +19,8 @@ use smallvec::SmallVec;

use super::{BasicBlock, Const, Local, UserTypeProjection};
use crate::mir::coverage::CoverageKind;
use crate::traits::Reveal;
use crate::ty::adjustment::PointerCoercion;
use crate::ty::{self, GenericArgsRef, List, Region, Ty, UserTypeAnnotationIndex};
use crate::ty::{self, GenericArgsRef, List, Region, Ty, TyCtxt, UserTypeAnnotationIndex};

/// Represents the "flavors" of MIR.
///
@@ -102,10 +101,10 @@ impl MirPhase {
}
}

pub fn reveal(&self) -> Reveal {
match *self {
MirPhase::Built | MirPhase::Analysis(_) => Reveal::UserFacing,
MirPhase::Runtime(_) => Reveal::All,
pub fn param_env<'tcx>(&self, tcx: TyCtxt<'tcx>, body_def_id: DefId) -> ty::ParamEnv<'tcx> {
match self {
MirPhase::Built | MirPhase::Analysis(_) => tcx.param_env(body_def_id),
MirPhase::Runtime(_) => tcx.param_env_reveal_all_normalized(body_def_id),
}
}
}
27 changes: 21 additions & 6 deletions compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
@@ -244,8 +244,13 @@ impl<'tcx> Inliner<'tcx> {
// Normally, this shouldn't be required, but trait normalization failure can create a
// validation ICE.
let output_type = callee_body.return_ty();
if !util::relate_types(self.tcx, self.param_env, ty::Covariant, output_type, destination_ty)
{
if !util::sub_types(
self.tcx,
caller_body.typing_mode(self.tcx),
self.param_env,
output_type,
destination_ty,
) {
trace!(?output_type, ?destination_ty);
return Err("failed to normalize return type");
}
@@ -275,8 +280,13 @@ impl<'tcx> Inliner<'tcx> {
self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
{
let input_type = callee_body.local_decls[input].ty;
if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty)
{
if !util::sub_types(
self.tcx,
caller_body.typing_mode(self.tcx),
self.param_env,
input_type,
arg_ty,
) {
trace!(?arg_ty, ?input_type);
return Err("failed to normalize tuple argument type");
}
@@ -285,8 +295,13 @@ impl<'tcx> Inliner<'tcx> {
for (arg, input) in args.iter().zip(callee_body.args_iter()) {
let input_type = callee_body.local_decls[input].ty;
let arg_ty = arg.node.ty(&caller_body.local_decls, self.tcx);
if !util::relate_types(self.tcx, self.param_env, ty::Covariant, input_type, arg_ty)
{
if !util::sub_types(
self.tcx,
caller_body.typing_mode(self.tcx),
self.param_env,
input_type,
arg_ty,
) {
trace!(?arg_ty, ?input_type);
return Err("failed to normalize argument type");
}
Loading