Rollup merge of #132403 - lcnr:typing-mode, r=compiler-errors

continue `TypingMode` refactor

There are still quite a few places which (indirectly) rely on the `Reveal` of a `ParamEnv`, but we're slowly getting there

r? `@compiler-errors`
This commit is contained in:
Jubilee 2024-10-31 17:50:43 -07:00 committed by GitHub
commit c57b351d38
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 155 additions and 105 deletions

View File

@ -16,7 +16,7 @@ use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_middle::ty::adjustment::PointerCoercion; 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::Analysis;
use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::impls::MaybeStorageLive;
use rustc_mir_dataflow::storage::always_storage_live_locals; 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 // 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 // which path expressions are getting called on and which path expressions are only used
// as function pointers. This is required for correctness. // 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 ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args); let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args);

View File

@ -32,14 +32,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self { pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>) -> Self {
let def_id = body.source.def_id().expect_local(); let def_id = body.source.def_id().expect_local();
let param_env = tcx.param_env(def_id); 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()); let const_kind = tcx.hir().body_const_context(body.source.def_id().expect_local());
ConstCx { body, tcx, param_env, const_kind } ConstCx { body, tcx, param_env, const_kind }
} }

View File

@ -12,7 +12,7 @@ use rustc_middle::mir::CallSource;
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
use rustc_middle::ty::{ 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, suggest_constraining_type_param,
}; };
use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind}; use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind};
@ -116,7 +116,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
let obligation = let obligation =
Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); 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 mut selcx = SelectionContext::new(&infcx);
let implsrc = selcx.select(&obligation); let implsrc = selcx.select(&obligation);

View File

@ -3,7 +3,7 @@ use rustc_errors::DiagCtxtHandle;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::at::ToTrace; 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::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
use rustc_middle::query::TyCtxtAt; use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{ 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. /// This test should be symmetric, as it is primarily about layout compatibility.
pub(super) fn mir_assign_valid_types<'tcx>( pub(super) fn mir_assign_valid_types<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
typing_mode: TypingMode<'tcx>,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
src: TyAndLayout<'tcx>, src: TyAndLayout<'tcx>,
dest: 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 // all normal lifetimes are erased, higher-ranked types with their
// late-bound lifetimes are still around and can lead to type // late-bound lifetimes are still around and can lead to type
// differences. // 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 // Make sure the layout is equal, too -- just to be safe. Miri really
// needs layout equality. For performance reason we skip this check when // needs layout equality. For performance reason we skip this check when
// the types are equal. Equal types *can* have different layouts 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))] #[cfg_attr(not(debug_assertions), inline(always))]
pub(super) fn from_known_layout<'tcx>( pub(super) fn from_known_layout<'tcx>(
tcx: TyCtxtAt<'tcx>, tcx: TyCtxtAt<'tcx>,
typing_mode: TypingMode<'tcx>,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
known_layout: Option<TyAndLayout<'tcx>>, known_layout: Option<TyAndLayout<'tcx>>,
compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>, compute: impl FnOnce() -> InterpResult<'tcx, TyAndLayout<'tcx>>,
@ -153,7 +155,13 @@ pub(super) fn from_known_layout<'tcx>(
Some(known_layout) => { Some(known_layout) => {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
let check_layout = compute()?; 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!( span_bug!(
tcx.span, tcx.span,
"expected type differs from actual type.\nexpected: {}\nactual: {}", "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. /// Returns the span of the currently executed statement/terminator.
/// This is the span typically used for error reporting. /// This is the span typically used for error reporting.
#[inline(always)] #[inline(always)]
@ -327,7 +340,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
return true; return true;
} }
// Slow path: spin up an inference context to check if these traits are sufficiently equal. // 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 ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::dummy_with_span(self.cur_span()); let cause = ObligationCause::dummy_with_span(self.cur_span());
// equate the two trait refs after normalization // equate the two trait refs after normalization

View File

@ -773,6 +773,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
)?; )?;
if !mir_assign_valid_types( if !mir_assign_valid_types(
*self.tcx, *self.tcx,
self.typing_mode(),
self.param_env, self.param_env,
self.layout_of(normalized_place_ty)?, self.layout_of(normalized_place_ty)?,
op.layout, op.layout,
@ -832,7 +833,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}) })
}; };
let layout = 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 { let imm = match val_val {
mir::ConstValue::Indirect { alloc_id, offset } => { mir::ConstValue::Indirect { alloc_id, offset } => {
// This is const data, no mutation allowed. // This is const data, no mutation allowed.

View File

@ -540,6 +540,7 @@ where
)?; )?;
if !mir_assign_valid_types( if !mir_assign_valid_types(
*self.tcx, *self.tcx,
self.typing_mode(),
self.param_env, self.param_env,
self.layout_of(normalized_place_ty)?, self.layout_of(normalized_place_ty)?,
place.layout, place.layout,
@ -870,8 +871,13 @@ where
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
// We do NOT compare the types for equality, because well-typed code can // 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. // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
let layout_compat = let layout_compat = mir_assign_valid_types(
mir_assign_valid_types(*self.tcx, self.param_env, src.layout(), dest.layout()); *self.tcx,
self.typing_mode(),
self.param_env,
src.layout(),
dest.layout(),
);
if !allow_transmute && !layout_compat { if !allow_transmute && !layout_compat {
span_bug!( span_bug!(
self.cur_span(), self.cur_span(),

View File

@ -596,7 +596,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
return interp_ok(layout); return interp_ok(layout);
} }
let layout = from_known_layout(self.tcx, self.param_env, layout, || { 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 = frame.body.local_decls[local].ty;
let local_ty = let local_ty =
self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?;

View File

@ -8,24 +8,15 @@ use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance}; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance};
use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::ObligationCtxt;
/// Returns whether the two types are equal up to subtyping. /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`.
/// pub fn sub_types<'tcx>(
/// 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>, tcx: TyCtxt<'tcx>,
typing_mode: TypingMode<'tcx>,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
src: Ty<'tcx>, src: Ty<'tcx>,
dest: Ty<'tcx>, dest: Ty<'tcx>,
) -> bool { ) -> bool {
// Fast path. relate_types(tcx, typing_mode, param_env, Variance::Covariant, src, dest)
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)
} }
/// Returns whether `src` is a subtype of `dest`, i.e. `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. /// because we want to check for type equality.
pub fn relate_types<'tcx>( pub fn relate_types<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
typing_mode: TypingMode<'tcx>,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
variance: Variance, variance: Variance,
src: Ty<'tcx>, src: Ty<'tcx>,
@ -45,8 +37,7 @@ pub fn relate_types<'tcx>(
} }
let mut builder = tcx.infer_ctxt().ignoring_regions(); let mut builder = tcx.infer_ctxt().ignoring_regions();
// FIXME(#132279): This should eventually use the already defined hidden types. let infcx = builder.build(typing_mode);
let infcx = builder.build(TypingMode::from_param_env(param_env));
let ocx = ObligationCtxt::new(&infcx); let ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::dummy(); let cause = ObligationCause::dummy();
let src = ocx.normalize(&cause, param_env, src); let src = ocx.normalize(&cause, param_env, src);

View File

@ -8,7 +8,7 @@ mod type_name;
pub use self::alignment::{is_disaligned, is_within_packed}; pub use self::alignment::{is_disaligned, is_within_packed};
pub use self::check_validity_requirement::check_validity_requirement; 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; pub use self::type_name::type_name;
/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the

View File

@ -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::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths};
use crate::ty::visit::TypeVisitableExt; use crate::ty::visit::TypeVisitableExt;
use crate::ty::{ use crate::ty::{
self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingMode,
UserTypeAnnotationIndex, UserTypeAnnotationIndex,
}; };
@ -452,6 +452,15 @@ impl<'tcx> Body<'tcx> {
self.basic_blocks.as_mut() 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] #[inline]
pub fn local_kind(&self, local: Local) -> LocalKind { pub fn local_kind(&self, local: Local) -> LocalKind {
let index = local.as_usize(); let index = local.as_usize();

View File

@ -19,9 +19,8 @@ use smallvec::SmallVec;
use super::{BasicBlock, Const, Local, UserTypeProjection}; use super::{BasicBlock, Const, Local, UserTypeProjection};
use crate::mir::coverage::CoverageKind; use crate::mir::coverage::CoverageKind;
use crate::traits::Reveal;
use crate::ty::adjustment::PointerCoercion; 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. /// Represents the "flavors" of MIR.
/// ///
@ -102,10 +101,10 @@ impl MirPhase {
} }
} }
pub fn reveal(&self) -> Reveal { pub fn param_env<'tcx>(&self, tcx: TyCtxt<'tcx>, body_def_id: DefId) -> ty::ParamEnv<'tcx> {
match *self { match self {
MirPhase::Built | MirPhase::Analysis(_) => Reveal::UserFacing, MirPhase::Built | MirPhase::Analysis(_) => tcx.param_env(body_def_id),
MirPhase::Runtime(_) => Reveal::All, MirPhase::Runtime(_) => tcx.param_env_reveal_all_normalized(body_def_id),
} }
} }
} }

View File

@ -244,8 +244,13 @@ impl<'tcx> Inliner<'tcx> {
// Normally, this shouldn't be required, but trait normalization failure can create a // Normally, this shouldn't be required, but trait normalization failure can create a
// validation ICE. // validation ICE.
let output_type = callee_body.return_ty(); 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); trace!(?output_type, ?destination_ty);
return Err("failed to normalize return type"); 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()) self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter())
{ {
let input_type = callee_body.local_decls[input].ty; 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); trace!(?arg_ty, ?input_type);
return Err("failed to normalize tuple argument 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()) { for (arg, input) in args.iter().zip(callee_body.args_iter()) {
let input_type = callee_body.local_decls[input].ty; let input_type = callee_body.local_decls[input].ty;
let arg_ty = arg.node.ty(&caller_body.local_decls, self.tcx); 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); trace!(?arg_ty, ?input_type);
return Err("failed to normalize argument type"); return Err("failed to normalize argument type");
} }

View File

@ -5,14 +5,14 @@ use rustc_hir::LangItem;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{Obligation, ObligationCause, Reveal}; use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
TypingMode, Variance, Variance,
}; };
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_target::abi::{FIRST_VARIANT, Size}; use rustc_target::abi::{FIRST_VARIANT, Size};
@ -20,7 +20,7 @@ use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::ObligationCtxt;
use rustc_type_ir::Upcast; use rustc_type_ir::Upcast;
use crate::util::{is_within_packed, relate_types}; use crate::util::{self, is_within_packed};
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum EdgeKind { enum EdgeKind {
@ -50,11 +50,7 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
} }
let def_id = body.source.def_id(); let def_id = body.source.def_id();
let mir_phase = self.mir_phase; let mir_phase = self.mir_phase;
let param_env = match mir_phase.reveal() { let param_env = mir_phase.param_env(tcx, def_id);
Reveal::UserFacing => tcx.param_env(def_id),
Reveal::All => tcx.param_env_reveal_all_normalized(def_id),
};
let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) { let can_unwind = if mir_phase <= MirPhase::Runtime(RuntimePhase::Initial) {
// In this case `AbortUnwindingCalls` haven't yet been executed. // In this case `AbortUnwindingCalls` haven't yet been executed.
true true
@ -587,7 +583,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Variance::Covariant Variance::Covariant
}; };
crate::util::relate_types(self.tcx, self.param_env, variance, src, dest) crate::util::relate_types(
self.tcx,
self.body.typing_mode(self.tcx),
self.param_env,
variance,
src,
dest,
)
} }
/// Check that the given predicate definitely holds in the param-env of this MIR body. /// Check that the given predicate definitely holds in the param-env of this MIR body.
@ -606,7 +609,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
return true; return true;
} }
let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env)); let infcx = self.tcx.infer_ctxt().build(self.body.typing_mode(self.tcx));
let ocx = ObligationCtxt::new(&infcx); let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligation(Obligation::new( ocx.register_obligation(Obligation::new(
self.tcx, self.tcx,
@ -798,10 +801,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
} }
} }
ProjectionElem::Subtype(ty) => { ProjectionElem::Subtype(ty) => {
if !relate_types( if !util::sub_types(
self.tcx, self.tcx,
self.body.typing_mode(self.tcx),
self.param_env, self.param_env,
Variance::Covariant,
ty, ty,
place_ref.ty(&self.body.local_decls, self.tcx).ty, place_ref.ty(&self.body.local_decls, self.tcx).ty,
) { ) {

View File

@ -411,7 +411,7 @@ pub fn normalize_param_env_or_error<'tcx>(
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()); let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal());
if !normalize::needs_normalization(&elaborated_env, unnormalized_env.reveal()) { if !elaborated_env.has_aliases() {
return elaborated_env; return elaborated_env;
} }

View File

@ -1,15 +1,16 @@
//! Deeply normalize types using the old trait solver. //! Deeply normalize types using the old trait solver.
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::infer::InferOk;
use rustc_infer::infer::at::At; use rustc_infer::infer::at::At;
use rustc_infer::infer::{InferCtxt, InferOk};
use rustc_infer::traits::{ use rustc_infer::traits::{
FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine, FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
}; };
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt,
TypingMode,
}; };
use tracing::{debug, instrument}; use tracing::{debug, instrument};
@ -109,16 +110,19 @@ where
} }
pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>( pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
infcx: &InferCtxt<'tcx>,
param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
value: &T, value: &T,
reveal: Reveal,
) -> bool { ) -> bool {
let mut flags = ty::TypeFlags::HAS_ALIAS; let mut flags = ty::TypeFlags::HAS_ALIAS;
// Opaques are treated as rigid with `Reveal::UserFacing`, // Opaques are treated as rigid with `Reveal::UserFacing`,
// so we can ignore those. // so we can ignore those.
match reveal { match infcx.typing_mode(param_env_for_debug_assertion) {
Reveal::UserFacing => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE), TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
Reveal::All => {} flags.remove(ty::TypeFlags::HAS_TY_OPAQUE)
}
TypingMode::PostAnalysis => {}
} }
value.has_type_flags(flags) value.has_type_flags(flags)
@ -154,7 +158,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
"Normalizing {value:?} without wrapping in a `Binder`" "Normalizing {value:?} without wrapping in a `Binder`"
); );
if !needs_normalization(&value, self.param_env.reveal()) { if !needs_normalization(self.selcx.infcx, self.param_env, &value) {
value value
} else { } else {
value.fold_with(self) value.fold_with(self)
@ -178,7 +182,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
} }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if !needs_normalization(&ty, self.param_env.reveal()) { if !needs_normalization(self.selcx.infcx, self.param_env, &ty) {
return ty; return ty;
} }
@ -213,10 +217,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
match kind { match kind {
ty::Opaque => { ty::Opaque => {
// Only normalize `impl Trait` outside of type inference, usually in codegen. // Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() { match self.selcx.infcx.typing_mode(self.param_env) {
Reveal::UserFacing => ty.super_fold_with(self), TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
ty.super_fold_with(self)
Reveal::All => { }
TypingMode::PostAnalysis => {
let recursion_limit = self.cx().recursion_limit(); let recursion_limit = self.cx().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) { if !recursion_limit.value_within_limit(self.depth) {
self.selcx.infcx.err_ctxt().report_overflow_error( self.selcx.infcx.err_ctxt().report_overflow_error(
@ -403,7 +408,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
let tcx = self.selcx.tcx(); let tcx = self.selcx.tcx();
if tcx.features().generic_const_exprs() if tcx.features().generic_const_exprs()
|| !needs_normalization(&constant, self.param_env.reveal()) || !needs_normalization(self.selcx.infcx, self.param_env, &constant)
{ {
constant constant
} else { } else {
@ -420,7 +425,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
#[inline] #[inline]
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { if p.allow_normalization() && needs_normalization(self.selcx.infcx, self.param_env, &p) {
p.super_fold_with(self) p.super_fold_with(self)
} else { } else {
p p

View File

@ -16,7 +16,7 @@ use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedD
use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, Term, Ty, TyCtxt, Upcast}; use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
@ -975,12 +975,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// and the obligation is monomorphic, otherwise passes such as // and the obligation is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could // transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations. // get a result which isn't correct for all monomorphizations.
if obligation.param_env.reveal() == Reveal::All { match selcx.infcx.typing_mode(obligation.param_env) {
// NOTE(eddyb) inference variables can resolve to parameters, so TypingMode::Coherence | TypingMode::Analysis { .. } => {
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(trait_ref);
!poly_trait_ref.still_further_specializable()
} else {
debug!( debug!(
assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
?obligation.predicate, ?obligation.predicate,
@ -988,6 +984,13 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
); );
false false
} }
TypingMode::PostAnalysis => {
// NOTE(eddyb) inference variables can resolve to parameters, so
// assume `poly_trait_ref` isn't monomorphic, if it contains any.
let poly_trait_ref = selcx.infcx.resolve_vars_if_possible(trait_ref);
!poly_trait_ref.still_further_specializable()
}
}
} }
} }
ImplSource::Builtin(BuiltinImplSource::Misc, _) => { ImplSource::Builtin(BuiltinImplSource::Misc, _) => {

View File

@ -9,7 +9,7 @@ use rustc_macros::extension;
pub use rustc_middle::traits::query::NormalizationResult; pub use rustc_middle::traits::query::NormalizationResult;
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor, TypingMode};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use tracing::{debug, info, instrument}; use tracing::{debug, info, instrument};
@ -21,7 +21,7 @@ use crate::infer::canonical::OriginalQueryValues;
use crate::infer::{InferCtxt, InferOk}; use crate::infer::{InferCtxt, InferOk};
use crate::traits::normalize::needs_normalization; use crate::traits::normalize::needs_normalization;
use crate::traits::{ use crate::traits::{
BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, Reveal, ScrubbedTraitError, BoundVarReplacer, Normalized, ObligationCause, PlaceholderReplacer, ScrubbedTraitError,
}; };
#[extension(pub trait QueryNormalizeExt<'tcx>)] #[extension(pub trait QueryNormalizeExt<'tcx>)]
@ -89,7 +89,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
} }
} }
if !needs_normalization(&value, self.param_env.reveal()) { if !needs_normalization(self.infcx, self.param_env, &value) {
return Ok(Normalized { value, obligations: PredicateObligations::new() }); return Ok(Normalized { value, obligations: PredicateObligations::new() });
} }
@ -191,7 +191,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !needs_normalization(&ty, self.param_env.reveal()) { if !needs_normalization(self.infcx, self.param_env, &ty) {
return Ok(ty); return Ok(ty);
} }
@ -215,10 +215,12 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
let res = match kind { let res = match kind {
ty::Opaque => { ty::Opaque => {
// Only normalize `impl Trait` outside of type inference, usually in codegen. // Only normalize `impl Trait` outside of type inference, usually in codegen.
match self.param_env.reveal() { match self.infcx.typing_mode(self.param_env) {
Reveal::UserFacing => ty.try_super_fold_with(self)?, TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => {
ty.try_super_fold_with(self)?
}
Reveal::All => { TypingMode::PostAnalysis => {
let args = data.args.try_fold_with(self)?; let args = data.args.try_fold_with(self)?;
let recursion_limit = self.cx().recursion_limit(); let recursion_limit = self.cx().recursion_limit();
@ -332,7 +334,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
&mut self, &mut self,
constant: ty::Const<'tcx>, constant: ty::Const<'tcx>,
) -> Result<ty::Const<'tcx>, Self::Error> { ) -> Result<ty::Const<'tcx>, Self::Error> {
if !needs_normalization(&constant, self.param_env.reveal()) { if !needs_normalization(self.infcx, self.param_env, &constant) {
return Ok(constant); return Ok(constant);
} }
@ -351,7 +353,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
&mut self, &mut self,
p: ty::Predicate<'tcx>, p: ty::Predicate<'tcx>,
) -> Result<ty::Predicate<'tcx>, Self::Error> { ) -> Result<ty::Predicate<'tcx>, Self::Error> {
if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { if p.allow_normalization() && needs_normalization(self.infcx, self.param_env, &p) {
p.try_super_fold_with(self) p.try_super_fold_with(self)
} else { } else {
Ok(p) Ok(p)

View File

@ -12,6 +12,13 @@ use crate::{self as ty, Interner};
/// The current typing mode of an inference context. We unfortunately have some /// The current typing mode of an inference context. We unfortunately have some
/// slightly different typing rules depending on the current context. See the /// slightly different typing rules depending on the current context. See the
/// doc comment for each variant for how and why they are used. /// doc comment for each variant for how and why they are used.
///
/// In most cases you can get the correct typing mode automically via:
/// - `mir::Body::typing_mode`
/// - `rustc_lint::LateContext::typing_mode`
///
/// If neither of these functions are available, feel free to reach out to
/// t-types for help.
#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
pub enum TypingMode<I: Interner> { pub enum TypingMode<I: Interner> {

View File

@ -17,7 +17,7 @@ use rustc_middle::mir::{
}; };
use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause};
use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt, TypingMode}; use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
use rustc_span::Span; use rustc_span::Span;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext};
@ -420,7 +420,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]), TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]),
); );
let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(obligation.param_env)); let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx));
let mut selcx = SelectionContext::new(&infcx); let mut selcx = SelectionContext::new(&infcx);
let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
return false; return false;

View File

@ -362,7 +362,7 @@ fn is_normalizable_helper<'tcx>(
} }
// prevent recursive loops, false-negative is better than endless loop leading to stack overflow // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
cache.insert(ty, false); cache.insert(ty, false);
let infcx = cx.tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
let cause = ObligationCause::dummy(); let cause = ObligationCause::dummy();
let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() { let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
match ty.kind() { match ty.kind() {