diff options
Diffstat (limited to 'compiler/rustc_middle/src')
75 files changed, 2845 insertions, 2818 deletions
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index a149a61ec..5a320865c 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -27,6 +27,11 @@ macro_rules! arena_types { rustc_middle::mir::Promoted, rustc_middle::mir::Body<'tcx> >, + [decode] closure_debuginfo: + rustc_index::IndexVec< + rustc_target::abi::FieldIdx, + rustc_span::symbol::Symbol, + >, [decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>, [decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<'tcx>, @@ -78,9 +83,9 @@ macro_rules! arena_types { rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::FnSig<'tcx>> >, - [] type_op_normalize_predicate: + [] type_op_normalize_clause: rustc_middle::infer::canonical::Canonical<'tcx, - rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Predicate<'tcx>> + rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Clause<'tcx>> >, [] type_op_normalize_ty: rustc_middle::infer::canonical::Canonical<'tcx, @@ -124,6 +129,7 @@ macro_rules! arena_types { [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>), + [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, ]); ) diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 046186d27..57b2de84b 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,3 +1,7 @@ +use std::borrow::Cow; +use std::fmt; + +use rustc_errors::{DiagnosticArgValue, DiagnosticMessage}; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -88,3 +92,54 @@ pub(super) struct ConstNotUsedTraitAlias { #[primary_span] pub span: Span, } + +pub struct CustomSubdiagnostic<'a> { + pub msg: fn() -> DiagnosticMessage, + pub add_args: + Box<dyn FnOnce(&mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>)) + 'a>, +} + +impl<'a> CustomSubdiagnostic<'a> { + pub fn label(x: fn() -> DiagnosticMessage) -> Self { + Self::label_and_then(x, |_| {}) + } + pub fn label_and_then< + F: FnOnce(&mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>)) + 'a, + >( + msg: fn() -> DiagnosticMessage, + f: F, + ) -> Self { + Self { msg, add_args: Box::new(move |x| f(x)) } + } +} + +impl fmt::Debug for CustomSubdiagnostic<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("CustomSubdiagnostic").finish_non_exhaustive() + } +} + +#[derive(Diagnostic)] +pub enum LayoutError<'tcx> { + #[diag(middle_unknown_layout)] + Unknown { ty: Ty<'tcx> }, + + #[diag(middle_values_too_big)] + Overflow { ty: Ty<'tcx> }, + + #[diag(middle_cannot_be_normalized)] + NormalizationFailure { ty: Ty<'tcx>, failure_ty: String }, + + #[diag(middle_cycle)] + Cycle, +} + +#[derive(Diagnostic)] +#[diag(middle_adjust_for_foreign_abi_error)] +pub struct UnsupportedFnAbi { + pub arch: Symbol, + pub abi: &'static str, +} + +/// Used by `rustc_const_eval` +pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error; diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index d1ddc8fc1..5f2eb890c 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -44,6 +44,7 @@ pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> { } Node::AnonConst(constant) => Some((constant.def_id, constant.body)), + Node::ConstBlock(constant) => Some((constant.def_id, constant.body)), _ => None, } @@ -240,15 +241,8 @@ impl<'hir> Map<'hir> { None => bug!("constructor node without a constructor"), } } - Node::AnonConst(_) => { - let inline = match self.find_parent(hir_id) { - Some(Node::Expr(&Expr { - kind: ExprKind::ConstBlock(ref anon_const), .. - })) if anon_const.hir_id == hir_id => true, - _ => false, - }; - if inline { DefKind::InlineConst } else { DefKind::AnonConst } - } + Node::AnonConst(_) => DefKind::AnonConst, + Node::ConstBlock(_) => DefKind::InlineConst, Node::Field(_) => DefKind::Field, Node::Expr(expr) => match expr.kind { ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure, @@ -1060,6 +1054,7 @@ impl<'hir> Map<'hir> { Node::Variant(variant) => variant.span, Node::Field(field) => field.span, Node::AnonConst(constant) => self.body(constant.body).value.span, + Node::ConstBlock(constant) => self.body(constant.body).value.span, Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, Node::Stmt(stmt) => stmt.span, @@ -1289,6 +1284,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id)) } Some(Node::AnonConst(_)) => node_str("const"), + Some(Node::ConstBlock(_)) => node_str("const"), Some(Node::Expr(_)) => node_str("expr"), Some(Node::ExprField(_)) => node_str("expr field"), Some(Node::Stmt(_)) => node_str("stmt"), @@ -1434,6 +1430,11 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { intravisit::walk_anon_const(self, c) } + fn visit_inline_const(&mut self, c: &'hir ConstBlock) { + self.body_owners.push(c.def_id); + intravisit::walk_inline_const(self, c) + } + fn visit_expr(&mut self, ex: &'hir Expr<'hir>) { if let ExprKind::Closure(closure) = ex.kind { self.body_owners.push(closure.def_id); diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 561713149..d5e8330b3 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -82,15 +82,40 @@ impl CanonicalVarValues<'_> { } pub fn is_identity_modulo_regions(&self) -> bool { - self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() { - ty::GenericArgKind::Lifetime(_) => true, - ty::GenericArgKind::Type(ty) => { - matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv) - } - ty::GenericArgKind::Const(ct) => { - matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv) + let mut var = ty::BoundVar::from_u32(0); + for arg in self.var_values { + match arg.unpack() { + ty::GenericArgKind::Lifetime(r) => { + if let ty::ReLateBound(ty::INNERMOST, br) = *r + && var == br.var + { + var = var + 1; + } else { + // It's ok if this region var isn't unique + } + }, + ty::GenericArgKind::Type(ty) => { + if let ty::Bound(ty::INNERMOST, bt) = *ty.kind() + && var == bt.var + { + var = var + 1; + } else { + return false; + } + } + ty::GenericArgKind::Const(ct) => { + if let ty::ConstKind::Bound(ty::INNERMOST, bc) = ct.kind() + && var == bc + { + var = var + 1; + } else { + return false; + } + } } - }) + } + + true } } @@ -408,22 +433,24 @@ impl<'tcx> CanonicalVarValues<'tcx> { |(i, info)| -> ty::GenericArg<'tcx> { match info.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { - tcx.mk_bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into()).into() + Ty::new_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i).into()) + .into() } CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { let br = ty::BoundRegion { var: ty::BoundVar::from_usize(i), kind: ty::BrAnon(None), }; - tcx.mk_re_late_bound(ty::INNERMOST, br).into() + ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into() } CanonicalVarKind::Const(_, ty) - | CanonicalVarKind::PlaceholderConst(_, ty) => tcx - .mk_const( - ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(i)), - ty, - ) - .into(), + | CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound( + tcx, + ty::INNERMOST, + ty::BoundVar::from_usize(i), + ty, + ) + .into(), } }, )), diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index a873854f0..85fb9214d 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -90,15 +90,15 @@ impl<'tcx> UnifyValue for UnifiedRegion<'tcx> { impl ToType for ty::IntVarValue { fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { - ty::IntType(i) => tcx.mk_mach_int(i), - ty::UintType(i) => tcx.mk_mach_uint(i), + ty::IntType(i) => Ty::new_int(tcx, i), + ty::UintType(i) => Ty::new_uint(tcx, i), } } } impl ToType for ty::FloatVarValue { fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_mach_float(self.0) + Ty::new_float(tcx, self.0) } } @@ -116,7 +116,6 @@ pub enum ConstVariableOriginKind { MiscVariable, ConstInference, ConstParameterDefinition(Symbol, DefId), - SubstitutionPlaceholder, } #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 22ee2a8c5..1b125e8e2 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -48,12 +48,13 @@ #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(control_flow_enum)] +#![feature(trait_upcasting)] #![feature(trusted_step)] #![feature(try_blocks)] #![feature(try_reserve_kind)] #![feature(nonzero_ops)] #![feature(decl_macro)] -#![feature(drain_filter)] +#![feature(extract_if)] #![feature(intra_doc_pointers)] #![feature(yeet_expr)] #![feature(result_option_inspect)] @@ -86,7 +87,7 @@ mod macros; #[macro_use] pub mod arena; -pub(crate) mod error; +pub mod error; pub mod hir; pub mod infer; pub mod lint; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 14343ac11..81c1ae4f6 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -251,7 +251,7 @@ pub fn explain_lint_level_source( } LintLevelSource::Node { name: lint_attr_name, span, reason, .. } => { if let Some(rationale) = reason { - err.note(rationale.as_str()); + err.note(rationale.to_string()); } err.span_note_once(span, "the lint level is defined here"); if lint_attr_name.as_str() != name { @@ -388,10 +388,11 @@ pub fn struct_lint_level( // it'll become a hard error, so we have to emit *something*. Also, // if this lint occurs in the expansion of a macro from an external crate, // allow individual lints to opt-out from being reported. - let not_future_incompatible = - future_incompatible.map(|f| f.reason.edition().is_some()).unwrap_or(true); - if not_future_incompatible && !lint.report_in_external_macro { + let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none()); + + if !incompatible && !lint.report_in_external_macro { err.cancel(); + // Don't continue further, since we don't want to have // `diag_span_note_once` called for a diagnostic that isn't emitted. return; diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index bd859d4d6..d4f023958 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -1,8 +1,7 @@ //! Registering limits: //! * recursion_limit, -//! * move_size_limit, -//! * type_length_limit, and -//! * const_eval_limit +//! * move_size_limit, and +//! * type_length_limit //! //! There are various parts of the compiler that must impose arbitrary limits //! on how deeply they recurse to prevent stack overflow. Users can override @@ -34,12 +33,6 @@ pub fn provide(providers: &mut Providers) { sym::type_length_limit, 1048576, ), - const_eval_limit: get_limit( - tcx.hir().krate_attrs(), - tcx.sess, - sym::const_eval_limit, - 2_000_000, - ), } } diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index f45cf788d..5baeb1ee0 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -4,6 +4,7 @@ use crate::ty::{TyCtxt, Visibility}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_hir::def::DefKind; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -148,13 +149,12 @@ impl EffectiveVisibilities { }; } - pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) { + pub fn check_invariants(&self, tcx: TyCtxt<'_>) { if !cfg!(debug_assertions) { return; } for (&def_id, ev) in &self.map { // More direct visibility levels can never go farther than less direct ones, - // neither of effective visibilities can go farther than nominal visibility, // and all effective visibilities are larger or equal than private visibility. let private_vis = Visibility::Restricted(tcx.parent_module_from_def_id(def_id)); let span = tcx.def_span(def_id.to_def_id()); @@ -175,17 +175,20 @@ impl EffectiveVisibilities { ev.reachable_through_impl_trait ); } - let nominal_vis = tcx.visibility(def_id); - // FIXME: `rustc_privacy` is not yet updated for the new logic and can set - // effective visibilities that are larger than the nominal one. - if !nominal_vis.is_at_least(ev.reachable_through_impl_trait, tcx) && early { - span_bug!( - span, - "{:?}: reachable_through_impl_trait {:?} > nominal {:?}", - def_id, - ev.reachable_through_impl_trait, - nominal_vis - ); + // All effective visibilities except `reachable_through_impl_trait` are limited to + // nominal visibility. For some items nominal visibility doesn't make sense so we + // don't check this condition for them. + if !matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) { + let nominal_vis = tcx.visibility(def_id); + if !nominal_vis.is_at_least(ev.reachable, tcx) { + span_bug!( + span, + "{:?}: reachable {:?} > nominal {:?}", + def_id, + ev.reachable, + nominal_vis + ); + } } } } @@ -212,7 +215,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { pub fn update( &mut self, id: Id, - nominal_vis: Option<Visibility>, + max_vis: Option<Visibility>, lazy_private_vis: impl FnOnce() -> Visibility, inherited_effective_vis: EffectiveVisibility, level: Level, @@ -236,8 +239,8 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level && level != l) { - calculated_effective_vis = if let Some(nominal_vis) = nominal_vis && !nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) { - nominal_vis + calculated_effective_vis = if let Some(max_vis) = max_vis && !max_vis.is_at_least(inherited_effective_vis_at_level, tcx) { + max_vis } else { inherited_effective_vis_at_level } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 6354c0aab..60844c17e 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -104,7 +104,7 @@ pub fn report_unstable( suggestion: Option<(Span, String, String, Applicability)>, is_soft: bool, span: Span, - soft_handler: impl FnOnce(&'static Lint, Span, &str), + soft_handler: impl FnOnce(&'static Lint, Span, String), ) { let msg = match reason { Some(r) => format!("use of unstable library feature '{}': {}", feature, r), @@ -112,7 +112,7 @@ pub fn report_unstable( }; if is_soft { - soft_handler(SOFT_UNSTABLE, span, &msg) + soft_handler(SOFT_UNSTABLE, span, msg) } else { let mut err = feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), msg); @@ -225,7 +225,7 @@ pub fn deprecation_message_and_lint( pub fn early_report_deprecation( lint_buffer: &mut LintBuffer, - message: &str, + message: String, suggestion: Option<Symbol>, lint: &'static Lint, span: Span, @@ -241,7 +241,7 @@ pub fn early_report_deprecation( fn late_report_deprecation( tcx: TyCtxt<'_>, - message: &str, + message: String, suggestion: Option<Symbol>, lint: &'static Lint, span: Span, @@ -396,7 +396,7 @@ impl<'tcx> TyCtxt<'tcx> { late_report_deprecation( self, - &deprecation_message( + deprecation_message( is_in_effect, depr_attr.since, depr_attr.note, @@ -619,7 +619,7 @@ impl<'tcx> TyCtxt<'tcx> { allow_unstable: AllowUnstable, unmarked: impl FnOnce(Span, DefId), ) -> bool { - let soft_handler = |lint, span, msg: &_| { + let soft_handler = |lint, span, msg: String| { self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |lint| lint) }; let eval_result = diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 9d70dbfa0..7722e7b47 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -26,7 +26,7 @@ struct Cache { predecessors: OnceCell<Predecessors>, switch_sources: OnceCell<SwitchSources>, is_cyclic: OnceCell<bool>, - postorder: OnceCell<Vec<BasicBlock>>, + reverse_postorder: OnceCell<Vec<BasicBlock>>, dominators: OnceCell<Dominators<BasicBlock>>, } @@ -62,11 +62,14 @@ impl<'tcx> BasicBlocks<'tcx> { }) } - /// Returns basic blocks in a postorder. + /// Returns basic blocks in a reverse postorder. #[inline] - pub fn postorder(&self) -> &[BasicBlock] { - self.cache.postorder.get_or_init(|| { - Postorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect() + pub fn reverse_postorder(&self) -> &[BasicBlock] { + self.cache.reverse_postorder.get_or_init(|| { + let mut rpo: Vec<_> = + Postorder::new(&self.basic_blocks, START_BLOCK).map(|(bb, _)| bb).collect(); + rpo.reverse(); + rpo }) } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 1a8e48264..b8030d9db 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -296,25 +296,13 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { Allocation::from_bytes(slice, Align::ONE, Mutability::Not) } - /// Try to create an Allocation of `size` bytes, failing if there is not enough memory - /// available to the compiler to do so. - /// - /// If `panic_on_fail` is true, this will never return `Err`. - pub fn uninit<'tcx>(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'tcx, Self> { - let bytes = Bytes::zeroed(size, align).ok_or_else(|| { - // This results in an error that can happen non-deterministically, since the memory - // available to the compiler can change between runs. Normally queries are always - // deterministic. However, we can be non-deterministic here because all uses of const - // evaluation (including ConstProp!) will make compilation fail (via hard error - // or ICE) upon encountering a `MemoryExhausted` error. - if panic_on_fail { - panic!("Allocation::uninit called with panic_on_fail had allocation failure") - } - ty::tls::with(|tcx| { - tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpretation") - }); - InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) - })?; + fn uninit_inner<R>(size: Size, align: Align, fail: impl FnOnce() -> R) -> Result<Self, R> { + // This results in an error that can happen non-deterministically, since the memory + // available to the compiler can change between runs. Normally queries are always + // deterministic. However, we can be non-deterministic here because all uses of const + // evaluation (including ConstProp!) will make compilation fail (via hard error + // or ICE) upon encountering a `MemoryExhausted` error. + let bytes = Bytes::zeroed(size, align).ok_or_else(fail)?; Ok(Allocation { bytes, @@ -325,6 +313,28 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { extra: (), }) } + + /// Try to create an Allocation of `size` bytes, failing if there is not enough memory + /// available to the compiler to do so. + pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> { + Self::uninit_inner(size, align, || { + ty::tls::with(|tcx| { + tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpretation") + }); + InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted).into() + }) + } + + /// Try to create an Allocation of `size` bytes, panics if there is not enough memory + /// available to the compiler to do so. + pub fn uninit(size: Size, align: Align) -> Self { + match Self::uninit_inner(size, align, || { + panic!("Allocation::uninit called with panic_on_fail had allocation failure"); + }) { + Ok(x) => x, + Err(x) => x, + } + } } impl<Bytes: AllocBytes> Allocation<AllocId, (), Bytes> { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 055d8e9a3..2435bc59e 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -5,11 +5,15 @@ use crate::query::TyCtxtAt; use crate::ty::{layout, tls, Ty, ValTree}; use rustc_data_structures::sync::Lock; -use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{ + struct_span_err, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, + IntoDiagnosticArg, +}; use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; use rustc_span::def_id::DefId; -use rustc_target::abi::{call, Align, Size}; +use rustc_target::abi::{call, Align, Size, WrappingRange}; +use std::borrow::Cow; use std::{any::Any, backtrace::Backtrace, fmt}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] @@ -91,21 +95,54 @@ pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>); #[derive(Debug)] struct InterpErrorInfoInner<'tcx> { kind: InterpError<'tcx>, + backtrace: InterpErrorBacktrace, +} + +#[derive(Debug)] +pub struct InterpErrorBacktrace { backtrace: Option<Box<Backtrace>>, } -impl fmt::Display for InterpErrorInfo<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0.kind) +impl InterpErrorBacktrace { + pub fn new() -> InterpErrorBacktrace { + let capture_backtrace = tls::with_opt(|tcx| { + if let Some(tcx) = tcx { + *Lock::borrow(&tcx.sess.ctfe_backtrace) + } else { + CtfeBacktrace::Disabled + } + }); + + let backtrace = match capture_backtrace { + CtfeBacktrace::Disabled => None, + CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())), + CtfeBacktrace::Immediate => { + // Print it now. + let backtrace = Backtrace::force_capture(); + print_backtrace(&backtrace); + None + } + }; + + InterpErrorBacktrace { backtrace } } -} -impl<'tcx> InterpErrorInfo<'tcx> { pub fn print_backtrace(&self) { - if let Some(backtrace) = self.0.backtrace.as_ref() { + if let Some(backtrace) = self.backtrace.as_ref() { print_backtrace(backtrace); } } +} + +impl<'tcx> InterpErrorInfo<'tcx> { + pub fn from_parts(kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace) -> Self { + Self(Box::new(InterpErrorInfoInner { kind, backtrace })) + } + + pub fn into_parts(self) -> (InterpError<'tcx>, InterpErrorBacktrace) { + let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace }) = self; + (kind, backtrace) + } pub fn into_kind(self) -> InterpError<'tcx> { let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self; @@ -130,32 +167,17 @@ impl From<ErrorGuaranteed> for InterpErrorInfo<'_> { impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> { fn from(kind: InterpError<'tcx>) -> Self { - let capture_backtrace = tls::with_opt(|tcx| { - if let Some(tcx) = tcx { - *Lock::borrow(&tcx.sess.ctfe_backtrace) - } else { - CtfeBacktrace::Disabled - } - }); - - let backtrace = match capture_backtrace { - CtfeBacktrace::Disabled => None, - CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())), - CtfeBacktrace::Immediate => { - // Print it now. - let backtrace = Backtrace::force_capture(); - print_backtrace(&backtrace); - None - } - }; - - InterpErrorInfo(Box::new(InterpErrorInfoInner { kind, backtrace })) + InterpErrorInfo(Box::new(InterpErrorInfoInner { + kind, + backtrace: InterpErrorBacktrace::new(), + })) } } /// Error information for when the program we executed turned out not to actually be a valid /// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp /// where we work on generic code or execution does not have all information available. +#[derive(Debug)] pub enum InvalidProgramInfo<'tcx> { /// Resolution can fail if we are in a too generic context. TooGeneric, @@ -174,25 +196,6 @@ pub enum InvalidProgramInfo<'tcx> { UninitUnsizedLocal, } -impl fmt::Display for InvalidProgramInfo<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use InvalidProgramInfo::*; - match self { - TooGeneric => write!(f, "encountered overly generic constant"), - AlreadyReported(_) => { - write!( - f, - "an error has already been reported elsewhere (this should not usually be printed)" - ) - } - Layout(ref err) => write!(f, "{err}"), - FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"), - SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"), - UninitUnsizedLocal => write!(f, "unsized local is used while uninitialized"), - } - } -} - /// Details of why a pointer had to be in-bounds. #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] pub enum CheckInAllocMsg { @@ -208,26 +211,25 @@ pub enum CheckInAllocMsg { InboundsTest, } -impl fmt::Display for CheckInAllocMsg { - /// When this is printed as an error the context looks like this: - /// "{msg}{pointer} is a dangling pointer". - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match *self { - CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ", - CheckInAllocMsg::MemoryAccessTest => "memory access failed: ", - CheckInAllocMsg::PointerArithmeticTest => "out-of-bounds pointer arithmetic: ", - CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ", - CheckInAllocMsg::InboundsTest => "out-of-bounds pointer use: ", - } - ) +#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] +pub enum InvalidMetaKind { + /// Size of a `[T]` is too big + SliceTooBig, + /// Size of a DST is too big + TooBig, +} + +impl IntoDiagnosticArg for InvalidMetaKind { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Borrowed(match self { + InvalidMetaKind::SliceTooBig => "slice_too_big", + InvalidMetaKind::TooBig => "too_big", + })) } } /// Details of an access to uninitialized bytes where it is not allowed. -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct UninitBytesAccess { /// Range of the original memory access. pub access: AllocRange, @@ -242,17 +244,32 @@ pub struct ScalarSizeMismatch { pub data_size: u64, } +macro_rules! impl_into_diagnostic_arg_through_debug { + ($($ty:ty),*$(,)?) => {$( + impl IntoDiagnosticArg for $ty { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(format!("{self:?}"))) + } + } + )*} +} + +// These types have nice `Debug` output so we can just use them in diagnostics. +impl_into_diagnostic_arg_through_debug! { + AllocId, + Pointer, + AllocRange, +} + /// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo { - /// Free-form case. Only for errors that are never caught! +#[derive(Debug)] +pub enum UndefinedBehaviorInfo<'a> { + /// Free-form case. Only for errors that are never caught! Used by miri Ub(String), /// Unreachable code was executed. Unreachable, /// A slice/array index projection went out-of-bounds. - BoundsCheckFailed { - len: u64, - index: u64, - }, + BoundsCheckFailed { len: u64, index: u64 }, /// Something was divided by 0 (x / 0). DivisionByZero, /// Something was "remainded" by 0 (x % 0). @@ -263,8 +280,8 @@ pub enum UndefinedBehaviorInfo { RemainderOverflow, /// Overflowing inbounds pointer arithmetic. PointerArithOverflow, - /// Invalid metadata in a wide pointer (using `str` to avoid allocations). - InvalidMeta(&'static str), + /// Invalid metadata in a wide pointer + InvalidMeta(InvalidMetaKind), /// Reading a C string that does not end within its allocation. UnterminatedCString(Pointer), /// Dereferencing a dangling pointer after it got freed. @@ -281,25 +298,13 @@ pub enum UndefinedBehaviorInfo { /// Using an integer as a pointer in the wrong way. DanglingIntPointer(u64, CheckInAllocMsg), /// Used a pointer with bad alignment. - AlignmentCheckFailed { - required: Align, - has: Align, - }, + AlignmentCheckFailed { required: Align, has: Align }, /// Writing to read-only memory. WriteToReadOnly(AllocId), - // Trying to access the data behind a function pointer. + /// Trying to access the data behind a function pointer. DerefFunctionPointer(AllocId), - // Trying to access the data behind a vtable pointer. + /// Trying to access the data behind a vtable pointer. DerefVTablePointer(AllocId), - /// The value validity check found a problem. - /// Should only be thrown by `validity.rs` and always point out which part of the value - /// is the problem. - ValidationFailure { - /// The "path" to the value in question, e.g. `.0[5].field` for a struct - /// field in the 6th element of an array that is the first element of a tuple. - path: Option<String>, - msg: String, - }, /// Using a non-boolean `u8` as bool. InvalidBool(u8), /// Using a non-character `u32` as character. @@ -320,110 +325,100 @@ pub enum UndefinedBehaviorInfo { ScalarSizeMismatch(ScalarSizeMismatch), /// A discriminant of an uninhabited enum variant is written. UninhabitedEnumVariantWritten, + /// Validation error. + Validation(ValidationErrorInfo<'a>), + // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically + // dispatched + /// A custom (free-form) error, created by `err_ub_custom!`. + Custom(crate::error::CustomSubdiagnostic<'a>), +} + +#[derive(Debug, Clone, Copy)] +pub enum PointerKind { + Ref, + Box, +} + +impl IntoDiagnosticArg for PointerKind { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str( + match self { + Self::Ref => "ref", + Self::Box => "box", + } + .into(), + ) + } } -impl fmt::Display for UndefinedBehaviorInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use UndefinedBehaviorInfo::*; - match self { - Ub(msg) => write!(f, "{msg}"), - Unreachable => write!(f, "entering unreachable code"), - BoundsCheckFailed { ref len, ref index } => { - write!(f, "indexing out of bounds: the len is {len} but the index is {index}") - } - DivisionByZero => write!(f, "dividing by zero"), - RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), - DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"), - RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"), - PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), - InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"), - UnterminatedCString(p) => write!( - f, - "reading a null-terminated string starting at {p:?} with no null found before end of allocation", - ), - PointerUseAfterFree(a) => { - write!(f, "pointer to {a:?} was dereferenced after this allocation got freed") - } - PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size: Size::ZERO, msg } => { - write!( - f, - "{msg}{alloc_id:?} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds", - alloc_size = alloc_size.bytes(), - ) - } - PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => write!( - f, - "{msg}{alloc_id:?} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds", - alloc_size = alloc_size.bytes(), - ptr_size = ptr_size.bytes(), - ptr_size_p = pluralize!(ptr_size.bytes()), - ), - DanglingIntPointer(i, msg) => { - write!( - f, - "{msg}{pointer} is a dangling pointer (it has no provenance)", - pointer = Pointer::<Option<AllocId>>::from_addr_invalid(*i), - ) - } - AlignmentCheckFailed { required, has } => write!( - f, - "accessing memory with alignment {has}, but alignment {required} is required", - has = has.bytes(), - required = required.bytes() - ), - WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"), - DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"), - DerefVTablePointer(a) => write!(f, "accessing {a:?} which contains a vtable"), - ValidationFailure { path: None, msg } => { - write!(f, "constructing invalid value: {msg}") - } - ValidationFailure { path: Some(path), msg } => { - write!(f, "constructing invalid value at {path}: {msg}") - } - InvalidBool(b) => { - write!(f, "interpreting an invalid 8-bit value as a bool: 0x{b:02x}") - } - InvalidChar(c) => { - write!(f, "interpreting an invalid 32-bit value as a char: 0x{c:08x}") - } - InvalidTag(val) => write!(f, "enum value has invalid tag: {val:x}"), - InvalidFunctionPointer(p) => { - write!(f, "using {p:?} as function pointer but it does not point to a function") - } - InvalidVTablePointer(p) => { - write!(f, "using {p:?} as vtable pointer but it does not point to a vtable") - } - InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"), - InvalidUninitBytes(Some((alloc, info))) => write!( - f, - "reading memory at {alloc:?}{access:?}, \ - but memory is uninitialized at {uninit:?}, \ - and this operation requires initialized memory", - access = info.access, - uninit = info.uninit, - ), - InvalidUninitBytes(None) => write!( - f, - "using uninitialized data, but this operation requires initialized memory" - ), - DeadLocal => write!(f, "accessing a dead local variable"), - ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!( - f, - "scalar size mismatch: expected {target_size} bytes but got {data_size} bytes instead", - ), - UninhabitedEnumVariantWritten => { - write!(f, "writing discriminant of an uninhabited enum") - } +#[derive(Debug)] +pub struct ValidationErrorInfo<'tcx> { + pub path: Option<String>, + pub kind: ValidationErrorKind<'tcx>, +} + +#[derive(Debug)] +pub enum ExpectedKind { + Reference, + Box, + RawPtr, + InitScalar, + Bool, + Char, + Float, + Int, + FnPtr, +} + +impl From<PointerKind> for ExpectedKind { + fn from(x: PointerKind) -> ExpectedKind { + match x { + PointerKind::Box => ExpectedKind::Box, + PointerKind::Ref => ExpectedKind::Reference, } } } +#[derive(Debug)] +pub enum ValidationErrorKind<'tcx> { + PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> }, + PtrToStatic { ptr_kind: PointerKind }, + PtrToMut { ptr_kind: PointerKind }, + ExpectedNonPtr { value: String }, + MutableRefInConst, + NullFnPtr, + NeverVal, + NullablePtrOutOfRange { range: WrappingRange, max_value: u128 }, + PtrOutOfRange { range: WrappingRange, max_value: u128 }, + OutOfRange { value: String, range: WrappingRange, max_value: u128 }, + UnsafeCell, + UninhabitedVal { ty: Ty<'tcx> }, + InvalidEnumTag { value: String }, + UninitEnumTag, + UninitStr, + Uninit { expected: ExpectedKind }, + UninitVal, + InvalidVTablePtr { value: String }, + InvalidMetaSliceTooLarge { ptr_kind: PointerKind }, + InvalidMetaTooLarge { ptr_kind: PointerKind }, + UnalignedPtr { ptr_kind: PointerKind, required_bytes: u64, found_bytes: u64 }, + NullPtr { ptr_kind: PointerKind }, + DanglingPtrNoProvenance { ptr_kind: PointerKind, pointer: String }, + DanglingPtrOutOfBounds { ptr_kind: PointerKind }, + DanglingPtrUseAfterFree { ptr_kind: PointerKind }, + InvalidBool { value: String }, + InvalidChar { value: String }, + InvalidFnPtr { value: String }, +} + /// Error information for when the program did something that might (or might not) be correct /// to do according to the Rust spec, but due to limitations in the interpreter, the /// operation could not be carried out. These limitations can differ between CTFE and the /// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses. +#[derive(Debug)] pub enum UnsupportedOpInfo { /// Free-form case. Only for errors that are never caught! + // FIXME still use translatable diagnostics Unsupported(String), // // The variants below are only reachable from CTFE/const prop, miri will never emit them. @@ -442,83 +437,42 @@ pub enum UnsupportedOpInfo { ReadExternStatic(DefId), } -impl fmt::Display for UnsupportedOpInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use UnsupportedOpInfo::*; - match self { - Unsupported(ref msg) => write!(f, "{msg}"), - PartialPointerOverwrite(ptr) => { - write!(f, "unable to overwrite parts of a pointer in memory at {ptr:?}") - } - PartialPointerCopy(ptr) => { - write!(f, "unable to copy parts of a pointer from memory at {ptr:?}") - } - ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"), - ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({did:?})"), - ReadExternStatic(did) => write!(f, "cannot read from extern static ({did:?})"), - } - } -} - /// Error information for when the program exhausted the resources granted to it /// by the interpreter. +#[derive(Debug)] pub enum ResourceExhaustionInfo { /// The stack grew too big. StackFrameLimitReached, - /// The program ran for too long. - /// - /// The exact limit is set by the `const_eval_limit` attribute. - StepLimitReached, /// There is not enough memory (on the host) to perform an allocation. MemoryExhausted, /// The address space (of the target) is full. AddressSpaceFull, } -impl fmt::Display for ResourceExhaustionInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use ResourceExhaustionInfo::*; - match self { - StackFrameLimitReached => { - write!(f, "reached the configured maximum number of stack frames") - } - StepLimitReached => { - write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)") - } - MemoryExhausted => { - write!(f, "tried to allocate more memory than available to compiler") - } - AddressSpaceFull => { - write!(f, "there are no more free addresses in the address space") - } - } - } -} - -/// A trait to work around not having trait object upcasting. -pub trait AsAny: Any { - fn as_any(&self) -> &dyn Any; -} -impl<T: Any> AsAny for T { - #[inline(always)] - fn as_any(&self) -> &dyn Any { - self - } -} - /// A trait for machine-specific errors (or other "machine stop" conditions). -pub trait MachineStopType: AsAny + fmt::Display + Send {} +pub trait MachineStopType: Any + fmt::Debug + Send { + /// The diagnostic message for this error + fn diagnostic_message(&self) -> DiagnosticMessage; + /// Add diagnostic arguments by passing name and value pairs to `adder`, which are passed to + /// fluent for formatting the translated diagnostic message. + fn add_args( + self: Box<Self>, + adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>), + ); +} impl dyn MachineStopType { #[inline(always)] pub fn downcast_ref<T: Any>(&self) -> Option<&T> { - self.as_any().downcast_ref() + let x: &dyn Any = self; + x.downcast_ref() } } +#[derive(Debug)] pub enum InterpError<'tcx> { /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo), + UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo), @@ -534,26 +488,6 @@ pub enum InterpError<'tcx> { pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>; -impl fmt::Display for InterpError<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use InterpError::*; - match *self { - Unsupported(ref msg) => write!(f, "{msg}"), - InvalidProgram(ref msg) => write!(f, "{msg}"), - UndefinedBehavior(ref msg) => write!(f, "{msg}"), - ResourceExhaustion(ref msg) => write!(f, "{msg}"), - MachineStop(ref msg) => write!(f, "{msg}"), - } - } -} - -// Forward `Debug` to `Display`, so it does not look awful. -impl fmt::Debug for InterpError<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - impl InterpError<'_> { /// Some errors do string formatting even if the error is never printed. /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors, @@ -562,7 +496,7 @@ impl InterpError<'_> { matches!( self, InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) - | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. }) + | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Validation { .. }) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) ) } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 3620385fa..2d2cfee1b 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -89,6 +89,30 @@ macro_rules! throw_machine_stop { ($($tt:tt)*) => { do yeet err_machine_stop!($($tt)*) }; } +#[macro_export] +macro_rules! err_ub_custom { + ($msg:expr $(, $($name:ident = $value:expr),* $(,)?)?) => {{ + $( + let ($($name,)*) = ($($value,)*); + )? + err_ub!(Custom( + rustc_middle::error::CustomSubdiagnostic { + msg: || $msg, + add_args: Box::new(move |mut set_arg| { + $($( + set_arg(stringify!($name).into(), rustc_errors::IntoDiagnosticArg::into_diagnostic_arg($name)); + )*)? + }) + } + )) + }}; +} + +#[macro_export] +macro_rules! throw_ub_custom { + ($($tt:tt)*) => { do yeet err_ub_custom!($($tt)*) }; +} + mod allocation; mod error; mod pointer; @@ -119,9 +143,10 @@ use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, - EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, - MachineStopType, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, - UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, + EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, + InvalidProgramInfo, MachineStopType, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, + ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, + ValidationErrorInfo, ValidationErrorKind, }; pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index f53dc8cb0..9c97431f3 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -95,8 +95,15 @@ impl<'tcx> TyCtxt<'tcx> { // used generic parameters is a bug of evaluation, so checking for it // here does feel somewhat sensible. if !self.features().generic_const_exprs && ct.substs.has_non_region_param() { - assert!(matches!(self.def_kind(ct.def), DefKind::AnonConst)); - let mir_body = self.mir_for_ctfe(ct.def); + let def_kind = self.def_kind(instance.def_id()); + assert!( + matches!( + def_kind, + DefKind::InlineConst | DefKind::AnonConst | DefKind::AssocConst + ), + "{cid:?} is {def_kind:?}", + ); + let mir_body = self.mir_for_ctfe(instance.def_id()); if mir_body.is_polymorphic { let Some(local_def_id) = ct.def.as_local() else { return }; self.struct_span_lint_hir( @@ -236,15 +243,3 @@ impl<'tcx> TyCtxtEnsure<'tcx> { self.eval_to_allocation_raw(param_env.and(gid)) } } - -impl<'tcx> TyCtxt<'tcx> { - /// Destructure a mir constant ADT or array into its variant index and its field values. - /// Panics if the destructuring fails, use `try_destructure_mir_constant` for fallible version. - pub fn destructure_mir_constant( - self, - param_env: ty::ParamEnv<'tcx>, - constant: mir::ConstantKind<'tcx>, - ) -> mir::DestructuredConstant<'tcx> { - self.try_destructure_mir_constant(param_env.and(constant)).unwrap() - } -} diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 36dbbe4bf..0416411df 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -97,6 +97,10 @@ impl<'tcx> ConstValue<'tcx> { ConstValue::Scalar(Scalar::from_u64(i)) } + pub fn from_u128(i: u128) -> Self { + ConstValue::Scalar(Scalar::from_u128(i)) + } + pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self { ConstValue::Scalar(Scalar::from_target_usize(i, cx)) } @@ -241,6 +245,11 @@ impl<Prov> Scalar<Prov> { } #[inline] + pub fn from_u128(i: u128) -> Self { + Scalar::Int(i.into()) + } + + #[inline] pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self { Self::from_uint(i, cx.data_layout().pointer_size) } @@ -375,7 +384,8 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { #[inline(always)] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) pub fn assert_bits(self, target_size: Size) -> u128 { - self.to_bits(target_size).unwrap() + self.to_bits(target_size) + .unwrap_or_else(|_| panic!("assertion failed: {self:?} fits {target_size:?}")) } pub fn to_bool(self) -> InterpResult<'tcx, bool> { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 5c71910a9..28c505878 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -3,7 +3,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html use crate::mir::interpret::{ - AllocRange, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, LitToConstInput, Scalar, + AllocRange, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar, }; use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -15,7 +15,7 @@ use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex}; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; use rustc_data_structures::captures::Captures; -use rustc_errors::ErrorGuaranteed; +use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::{self, GeneratorKind, ImplicitSelfKind}; @@ -145,7 +145,7 @@ impl MirPhase { } "analysis" => Self::Analysis(AnalysisPhase::parse(phase)), "runtime" => Self::Runtime(RuntimePhase::parse(phase)), - _ => panic!("Unknown MIR dialect {}", dialect), + _ => bug!("Unknown MIR dialect: '{}'", dialect), } } } @@ -159,7 +159,7 @@ impl AnalysisPhase { match &*phase.to_ascii_lowercase() { "initial" => Self::Initial, "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup, - _ => panic!("Unknown analysis phase {}", phase), + _ => bug!("Unknown analysis phase: '{}'", phase), } } } @@ -174,7 +174,7 @@ impl RuntimePhase { "initial" => Self::Initial, "post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup, "optimized" => Self::Optimized, - _ => panic!("Unknown runtime phase {}", phase), + _ => bug!("Unknown runtime phase: '{}'", phase), } } } @@ -476,7 +476,7 @@ impl<'tcx> Body<'tcx> { /// Returns the return type; it always return first element from `local_decls` array. #[inline] pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> { - ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty) + ty::EarlyBinder::bind(self.local_decls[RETURN_PLACE].ty) } /// Gets the location of the terminator for the given block. @@ -1371,55 +1371,61 @@ impl<O> AssertKind<O> { _ => write!(f, "\"{}\"", self.description()), } } -} -impl<O: fmt::Debug> fmt::Debug for AssertKind<O> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + pub fn diagnostic_message(&self) -> DiagnosticMessage { + use crate::fluent_generated::*; use AssertKind::*; + match self { - BoundsCheck { ref len, ref index } => write!( - f, - "index out of bounds: the length is {:?} but the index is {:?}", - len, index - ), - OverflowNeg(op) => write!(f, "attempt to negate `{:#?}`, which would overflow", op), - DivisionByZero(op) => write!(f, "attempt to divide `{:#?}` by zero", op), - RemainderByZero(op) => write!( - f, - "attempt to calculate the remainder of `{:#?}` with a divisor of zero", - op - ), - Overflow(BinOp::Add, l, r) => { - write!(f, "attempt to compute `{:#?} + {:#?}`, which would overflow", l, r) - } - Overflow(BinOp::Sub, l, r) => { - write!(f, "attempt to compute `{:#?} - {:#?}`, which would overflow", l, r) - } - Overflow(BinOp::Mul, l, r) => { - write!(f, "attempt to compute `{:#?} * {:#?}`, which would overflow", l, r) - } - Overflow(BinOp::Div, l, r) => { - write!(f, "attempt to compute `{:#?} / {:#?}`, which would overflow", l, r) + BoundsCheck { .. } => middle_bounds_check, + Overflow(BinOp::Shl, _, _) => middle_assert_shl_overflow, + Overflow(BinOp::Shr, _, _) => middle_assert_shr_overflow, + Overflow(_, _, _) => middle_assert_op_overflow, + OverflowNeg(_) => middle_assert_overflow_neg, + DivisionByZero(_) => middle_assert_divide_by_zero, + RemainderByZero(_) => middle_assert_remainder_by_zero, + ResumedAfterReturn(GeneratorKind::Async(_)) => middle_assert_async_resume_after_return, + ResumedAfterReturn(GeneratorKind::Gen) => middle_assert_generator_resume_after_return, + ResumedAfterPanic(GeneratorKind::Async(_)) => middle_assert_async_resume_after_panic, + ResumedAfterPanic(GeneratorKind::Gen) => middle_assert_generator_resume_after_panic, + + MisalignedPointerDereference { .. } => middle_assert_misaligned_ptr_deref, + } + } + + pub fn add_args(self, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>)) + where + O: fmt::Debug, + { + use AssertKind::*; + + macro_rules! add { + ($name: expr, $value: expr) => { + adder($name.into(), $value.into_diagnostic_arg()); + }; + } + + match self { + BoundsCheck { len, index } => { + add!("len", format!("{len:?}")); + add!("index", format!("{index:?}")); } - Overflow(BinOp::Rem, l, r) => write!( - f, - "attempt to compute the remainder of `{:#?} % {:#?}`, which would overflow", - l, r - ), - Overflow(BinOp::Shr, _, r) => { - write!(f, "attempt to shift right by `{:#?}`, which would overflow", r) + Overflow(BinOp::Shl | BinOp::Shr, _, val) + | DivisionByZero(val) + | RemainderByZero(val) + | OverflowNeg(val) => { + add!("val", format!("{val:#?}")); } - Overflow(BinOp::Shl, _, r) => { - write!(f, "attempt to shift left by `{:#?}`, which would overflow", r) + Overflow(binop, left, right) => { + add!("op", binop.to_hir_binop().as_str()); + add!("left", format!("{left:#?}")); + add!("right", format!("{right:#?}")); } + ResumedAfterReturn(_) | ResumedAfterPanic(_) => {} MisalignedPointerDereference { required, found } => { - write!( - f, - "misaligned pointer dereference: address must be a multiple of {:?} but is {:?}", - required, found - ) + add!("required", format!("{required:#?}")); + add!("found", format!("{found:#?}")); } - _ => write!(f, "{}", self.description()), } } } @@ -1907,7 +1913,7 @@ impl<'tcx> Operand<'tcx> { substs: impl IntoIterator<Item = GenericArg<'tcx>>, span: Span, ) -> Self { - let ty = tcx.mk_fn_def(def_id, substs); + let ty = Ty::new_fn_def(tcx, def_id, substs); Operand::Constant(Box::new(Constant { span, user_ty: None, @@ -2008,7 +2014,7 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::IntToFloat | CastKind::FnPtrToPtr | CastKind::PtrToPtr - | CastKind::Pointer(_) + | CastKind::PointerCoercion(_) | CastKind::PointerFromExposedAddress | CastKind::DynStar | CastKind::Transmute, @@ -2029,23 +2035,19 @@ impl<'tcx> Rvalue<'tcx> { impl BorrowKind { pub fn mutability(&self) -> Mutability { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => Mutability::Not, + BorrowKind::Shared | BorrowKind::Shallow => Mutability::Not, BorrowKind::Mut { .. } => Mutability::Mut, } } pub fn allows_two_phase_borrow(&self) -> bool { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, - BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, - } - } - - // FIXME: won't be used after diagnostic migration - pub fn describe_mutability(&self) -> &str { - match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable", - BorrowKind::Mut { .. } => "mutable", + BorrowKind::Shared + | BorrowKind::Shallow + | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } => { + false + } + BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true, } } } @@ -2084,7 +2086,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let kind_str = match borrow_kind { BorrowKind::Shared => "", BorrowKind::Shallow => "shallow ", - BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", + BorrowKind::Mut { .. } => "mut ", }; // When printing regions, add trailing space if necessary. @@ -2327,10 +2329,10 @@ impl<'tcx> ConstantKind<'tcx> { pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { match self { Self::Ty(c) => { - if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) { + if let Some(val) = c.try_eval_for_mir(tcx, param_env) { match val { Ok(val) => Self::Val(val, c.ty()), - Err(guar) => Self::Ty(tcx.const_error(self.ty(), guar)), + Err(guar) => Self::Ty(ty::Const::new_error(tcx, guar, self.ty())), } } else { self @@ -2342,7 +2344,9 @@ impl<'tcx> ConstantKind<'tcx> { match tcx.const_eval_resolve(param_env, uneval, None) { Ok(val) => Self::Val(val, ty), Err(ErrorHandled::TooGeneric) => self, - Err(ErrorHandled::Reported(guar)) => Self::Ty(tcx.const_error(ty, guar.into())), + Err(ErrorHandled::Reported(guar)) => { + Self::Ty(ty::Const::new_error(tcx, guar.into(), ty)) + } } } } @@ -2461,51 +2465,6 @@ impl<'tcx> ConstantKind<'tcx> { Self::Val(val, ty) } - #[instrument(skip(tcx), level = "debug", ret)] - pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let body_id = match tcx.hir().get(hir_id) { - hir::Node::AnonConst(ac) => ac.body, - _ => span_bug!( - tcx.def_span(def_id.to_def_id()), - "from_inline_const can only process anonymous constants" - ), - }; - let expr = &tcx.hir().body(body_id).value; - let ty = tcx.typeck(def_id).node_type(hir_id); - - let lit_input = match expr.kind { - hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), - hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { - hir::ExprKind::Lit(ref lit) => { - Some(LitToConstInput { lit: &lit.node, ty, neg: true }) - } - _ => None, - }, - _ => None, - }; - if let Some(lit_input) = lit_input { - // If an error occurred, ignore that it's a literal and leave reporting the error up to - // mir. - match tcx.at(expr.span).lit_to_mir_constant(lit_input) { - Ok(c) => return c, - Err(_) => {} - } - } - - let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); - let parent_substs = - tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id)); - let substs = - ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty }) - .substs; - - let uneval = UnevaluatedConst { def: def_id.to_def_id(), substs, promoted: None }; - debug_assert!(!uneval.has_free_regions()); - - Self::Unevaluated(uneval, ty) - } - /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly /// converted to a constant, everything else becomes `Unevaluated`. #[instrument(skip(tcx), level = "debug", ret)] @@ -2553,7 +2512,7 @@ impl<'tcx> ConstantKind<'tcx> { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - let ty_const = tcx.mk_const(ty::ParamConst::new(index, name), ty); + let ty_const = ty::Const::new_param(tcx, ty::ParamConst::new(index, name), ty); debug!(?ty_const); return Self::Ty(ty_const); @@ -2624,10 +2583,9 @@ pub struct UnevaluatedConst<'tcx> { } impl<'tcx> UnevaluatedConst<'tcx> { - // FIXME: probably should get rid of this method. It's also wrong to - // shrink and then later expand a promoted. #[inline] pub fn shrink(self) -> ty::UnevaluatedConst<'tcx> { + assert_eq!(self.promoted, None); ty::UnevaluatedConst { def: self.def, substs: self.substs } } } @@ -2818,7 +2776,7 @@ impl<'tcx> Display for ConstantKind<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match *self { ConstantKind::Ty(c) => pretty_print_const(c, fmt, true), - ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt, true), + ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt), // FIXME(valtrees): Correctly print mir constants. ConstantKind::Unevaluated(..) => { fmt.write_str("_")?; @@ -2848,13 +2806,16 @@ fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Resul write!(fmt, "b\"{}\"", byte_str.escape_ascii()) } -fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec<ConstantKind<'tcx>>) -> fmt::Result { +fn comma_sep<'tcx>( + fmt: &mut Formatter<'_>, + elems: Vec<(ConstValue<'tcx>, Ty<'tcx>)>, +) -> fmt::Result { let mut first = true; - for elem in elems { + for (ct, ty) in elems { if !first { fmt.write_str(", ")?; } - fmt.write_str(&format!("{}", elem))?; + pretty_print_const_value(ct, ty, fmt)?; first = false; } Ok(()) @@ -2865,7 +2826,6 @@ fn pretty_print_const_value<'tcx>( ct: ConstValue<'tcx>, ty: Ty<'tcx>, fmt: &mut Formatter<'_>, - print_ty: bool, ) -> fmt::Result { use crate::ty::print::PrettyPrinter; @@ -2909,7 +2869,7 @@ fn pretty_print_const_value<'tcx>( } } (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => { - let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap(); + let n = n.try_to_bits(tcx.data_layout.pointer_size).unwrap(); // cast is ok because we already checked for pointer size (32 or 64 bit) above let range = AllocRange { start: offset, size: Size::from_bytes(n) }; let byte_str = alloc.inner().get_bytes_strip_provenance(&tcx, range).unwrap(); @@ -2924,16 +2884,11 @@ fn pretty_print_const_value<'tcx>( // introducing ICEs (e.g. via `layout_of`) from missing bounds. // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` // to be able to destructure the tuple into `(0u8, *mut T)` - // - // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the - // correct `ty::ParamEnv` to allow printing *all* constant values. (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => { let ct = tcx.lift(ct).unwrap(); let ty = tcx.lift(ty).unwrap(); - if let Some(contents) = tcx.try_destructure_mir_constant( - ty::ParamEnv::reveal_all().and(ConstantKind::Val(ct, ty)), - ) { - let fields = contents.fields.to_vec(); + if let Some(contents) = tcx.try_destructure_mir_constant_for_diagnostics((ct, ty)) { + let fields: Vec<(ConstValue<'_>, Ty<'_>)> = contents.fields.to_vec(); match *ty.kind() { ty::Array(..) => { fmt.write_str("[")?; @@ -2972,12 +2927,14 @@ fn pretty_print_const_value<'tcx>( None => { fmt.write_str(" {{ ")?; let mut first = true; - for (field_def, field) in iter::zip(&variant_def.fields, fields) + for (field_def, (ct, ty)) in + iter::zip(&variant_def.fields, fields) { if !first { fmt.write_str(", ")?; } - fmt.write_str(&format!("{}: {}", field_def.name, field))?; + write!(fmt, "{}: ", field_def.name)?; + pretty_print_const_value(ct, ty, fmt)?; first = false; } fmt.write_str(" }}")?; @@ -2987,20 +2944,13 @@ fn pretty_print_const_value<'tcx>( _ => unreachable!(), } return Ok(()); - } else { - // Fall back to debug pretty printing for invalid constants. - fmt.write_str(&format!("{:?}", ct))?; - if print_ty { - fmt.write_str(&format!(": {}", ty))?; - } - return Ok(()); - }; + } } (ConstValue::Scalar(scalar), _) => { let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); cx.print_alloc_ids = true; let ty = tcx.lift(ty).unwrap(); - cx = cx.pretty_print_const_scalar(scalar, ty, print_ty)?; + cx = cx.pretty_print_const_scalar(scalar, ty)?; fmt.write_str(&cx.into_buffer())?; return Ok(()); } @@ -3015,12 +2965,8 @@ fn pretty_print_const_value<'tcx>( // their fields instead of just dumping the memory. _ => {} } - // fallback - fmt.write_str(&format!("{:?}", ct))?; - if print_ty { - fmt.write_str(&format!(": {}", ty))?; - } - Ok(()) + // Fall back to debug pretty printing for invalid constants. + write!(fmt, "{ct:?}: {ty}") }) } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index f31b343c9..ca735d523 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -231,7 +231,7 @@ pub struct CodegenUnit<'tcx> { /// as well as the crate name and disambiguator. name: Symbol, items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>, - size_estimate: Option<usize>, + size_estimate: usize, primary: bool, /// True if this is CGU is used to hold code coverage information for dead code, /// false otherwise. @@ -269,7 +269,7 @@ impl<'tcx> CodegenUnit<'tcx> { CodegenUnit { name, items: Default::default(), - size_estimate: None, + size_estimate: 0, primary: false, is_code_coverage_dead_code_cgu: false, } @@ -291,10 +291,12 @@ impl<'tcx> CodegenUnit<'tcx> { self.primary = true; } + /// The order of these items is non-determinstic. pub fn items(&self) -> &FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> { &self.items } + /// The order of these items is non-determinstic. pub fn items_mut(&mut self) -> &mut FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> { &mut self.items } @@ -318,23 +320,21 @@ impl<'tcx> CodegenUnit<'tcx> { base_n::encode(hash, base_n::CASE_INSENSITIVE) } - pub fn create_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { + pub fn compute_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { // Estimate the size of a codegen unit as (approximately) the number of MIR // statements it corresponds to. - self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum()); + self.size_estimate = self.items.keys().map(|mi| mi.size_estimate(tcx)).sum(); } #[inline] - /// Should only be called if [`create_size_estimate`] has previously been called. + /// Should only be called if [`compute_size_estimate`] has previously been called. /// - /// [`create_size_estimate`]: Self::create_size_estimate + /// [`compute_size_estimate`]: Self::compute_size_estimate pub fn size_estimate(&self) -> usize { + // Items are never zero-sized, so if we have items the estimate must be + // non-zero, unless we forgot to call `compute_size_estimate` first. + assert!(self.items.is_empty() || self.size_estimate != 0); self.size_estimate - .expect("create_size_estimate must be called before getting a size_estimate") - } - - pub fn modify_size_estimate(&mut self, delta: usize) { - *self.size_estimate.as_mut().unwrap() += delta; } pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 62c3d8cf2..ffa7a5400 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -353,14 +353,22 @@ where for statement in &data.statements { extra_data(PassWhere::BeforeLocation(current_location), w)?; let indented_body = format!("{0}{0}{1:?};", INDENT, statement); - writeln!( - w, - "{:A$} // {}{}", - indented_body, - if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, - comment(tcx, statement.source_info, body.span), - A = ALIGN, - )?; + if tcx.sess.opts.unstable_opts.mir_include_spans { + writeln!( + w, + "{:A$} // {}{}", + indented_body, + if tcx.sess.verbose() { + format!("{:?}: ", current_location) + } else { + String::new() + }, + comment(tcx, statement.source_info), + A = ALIGN, + )?; + } else { + writeln!(w, "{}", indented_body)?; + } write_extra(tcx, w, |visitor| { visitor.visit_statement(statement, current_location); @@ -374,14 +382,18 @@ where // Terminator at the bottom. extra_data(PassWhere::BeforeLocation(current_location), w)?; let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); - writeln!( - w, - "{:A$} // {}{}", - indented_terminator, - if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, - comment(tcx, data.terminator().source_info, body.span), - A = ALIGN, - )?; + if tcx.sess.opts.unstable_opts.mir_include_spans { + writeln!( + w, + "{:A$} // {}{}", + indented_terminator, + if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, + comment(tcx, data.terminator().source_info), + A = ALIGN, + )?; + } else { + writeln!(w, "{}", indented_terminator)?; + } write_extra(tcx, w, |visitor| { visitor.visit_terminator(data.terminator(), current_location); @@ -400,10 +412,12 @@ fn write_extra<'tcx, F>(tcx: TyCtxt<'tcx>, write: &mut dyn Write, mut visit_op: where F: FnMut(&mut ExtraComments<'tcx>), { - let mut extra_comments = ExtraComments { tcx, comments: vec![] }; - visit_op(&mut extra_comments); - for comment in extra_comments.comments { - writeln!(write, "{:A$} // {}", "", comment, A = ALIGN)?; + if tcx.sess.opts.unstable_opts.mir_include_spans { + let mut extra_comments = ExtraComments { tcx, comments: vec![] }; + visit_op(&mut extra_comments); + for comment in extra_comments.comments { + writeln!(write, "{:A$} // {}", "", comment, A = ALIGN)?; + } } Ok(()) } @@ -522,13 +536,8 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { } } -fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo, function_span: Span) -> String { - let location = if tcx.sess.opts.unstable_opts.mir_pretty_relative_line_numbers { - tcx.sess.source_map().span_to_relative_line_string(span, function_span) - } else { - tcx.sess.source_map().span_to_embeddable_string(span) - }; - +fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String { + let location = tcx.sess.source_map().span_to_embeddable_string(span); format!("scope {} at {}", scope.index(), location,) } @@ -560,13 +569,17 @@ fn write_scope_tree( var_debug_info.value, ); - writeln!( - w, - "{0:1$} // in {2}", - indented_debug_info, - ALIGN, - comment(tcx, var_debug_info.source_info, body.span), - )?; + if tcx.sess.opts.unstable_opts.mir_include_spans { + writeln!( + w, + "{0:1$} // in {2}", + indented_debug_info, + ALIGN, + comment(tcx, var_debug_info.source_info), + )?; + } else { + writeln!(w, "{}", indented_debug_info)?; + } } // Local variable types. @@ -594,14 +607,18 @@ fn write_scope_tree( let local_name = if local == RETURN_PLACE { " return place" } else { "" }; - writeln!( - w, - "{0:1$} //{2} in {3}", - indented_decl, - ALIGN, - local_name, - comment(tcx, local_decl.source_info, body.span), - )?; + if tcx.sess.opts.unstable_opts.mir_include_spans { + writeln!( + w, + "{0:1$} //{2} in {3}", + indented_decl, + ALIGN, + local_name, + comment(tcx, local_decl.source_info), + )?; + } else { + writeln!(w, "{}", indented_decl,)?; + } } let Some(children) = scope_tree.get(&parent) else { @@ -627,14 +644,18 @@ fn write_scope_tree( let indented_header = format!("{0:1$}scope {2}{3} {{", "", indent, child.index(), special); - if let Some(span) = span { - writeln!( - w, - "{0:1$} // at {2}", - indented_header, - ALIGN, - tcx.sess.source_map().span_to_embeddable_string(span), - )?; + if tcx.sess.opts.unstable_opts.mir_include_spans { + if let Some(span) = span { + writeln!( + w, + "{0:1$} // at {2}", + indented_header, + ALIGN, + tcx.sess.source_map().span_to_embeddable_string(span), + )?; + } else { + writeln!(w, "{}", indented_header)?; + } } else { writeln!(w, "{}", indented_header)?; } @@ -846,7 +867,7 @@ fn write_allocation_newline( /// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there /// is only one line). Note that your prefix should contain a trailing space as the lines are /// printed directly after it. -fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( +pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( tcx: TyCtxt<'tcx>, alloc: &Allocation<Prov, Extra, Bytes>, w: &mut dyn std::fmt::Write, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 53fd2dd23..613b132ff 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,6 +1,6 @@ //! Values computed by queries that use MIR. -use crate::mir::ConstantKind; +use crate::mir::interpret::ConstValue; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; @@ -9,6 +9,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitMatrix; use rustc_index::{Idx, IndexVec}; +use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use smallvec::SmallVec; @@ -150,6 +151,9 @@ pub struct GeneratorLayout<'tcx> { /// The type of every local stored inside the generator. pub field_tys: IndexVec<GeneratorSavedLocal, GeneratorSavedTy<'tcx>>, + /// The name for debuginfo. + pub field_names: IndexVec<GeneratorSavedLocal, Option<Symbol>>, + /// Which of the above fields are in each variant. Note that one field may /// be stored in multiple variants. pub variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, GeneratorSavedLocal>>, @@ -413,7 +417,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { ty::ReVar(vid) => { let br = ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon(None) }; - tcx.mk_re_late_bound(depth, br) + ty::Region::new_late_bound(tcx, depth, br) } _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"), }); @@ -440,7 +444,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConstant<'tcx> { pub variant: Option<VariantIdx>, - pub fields: &'tcx [ConstantKind<'tcx>], + pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)], } /// Coverage information summarized from a MIR if instrumented for source code coverage (see diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 2165403da..730c55157 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -3,7 +3,7 @@ use rustc_middle::hir; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use rustc_session::config::MirSpanview; -use rustc_span::{BytePos, Pos, Span, SyntaxContext}; +use rustc_span::{BytePos, Pos, Span}; use std::cmp; use std::io::{self, Write}; @@ -15,8 +15,9 @@ const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT B const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` const NEW_LINE_SPAN: &str = "</span>\n<span class=\"line\">"; const HEADER: &str = r#"<!DOCTYPE html> -<html> -<head>"#; +<html lang="en"> +<head> +<meta charset="utf-8">"#; const START_BODY: &str = r#"</head> <body>"#; const FOOTER: &str = r#"</body> @@ -327,7 +328,7 @@ fn compute_block_span(data: &BasicBlockData<'_>, body_span: Span) -> Span { let mut span = data.terminator().source_info.span; for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { // Only combine Spans from the root context, and within the function's body_span. - if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) { + if statement_span.ctxt().is_root() && body_span.contains(statement_span) { span = span.to(statement_span); } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 3e474c1d3..7f1d38203 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -7,7 +7,7 @@ use super::{BasicBlock, Constant, Local, SwitchTargets, UserTypeProjection}; use crate::mir::coverage::{CodeRegion, CoverageKind}; use crate::traits::Reveal; -use crate::ty::adjustment::PointerCast; +use crate::ty::adjustment::PointerCoercion; use crate::ty::subst::SubstsRef; use crate::ty::{self, List, Ty}; use crate::ty::{Region, UserTypeAnnotationIndex}; @@ -182,6 +182,16 @@ pub enum BorrowKind { /// We can also report errors with this kind of borrow differently. Shallow, + /// Data is mutable and not aliasable. + Mut { kind: MutBorrowKind }, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Hash, HashStable)] +pub enum MutBorrowKind { + Default, + /// This borrow arose from method-call auto-ref. (i.e., `adjustment::Adjust::Borrow`) + TwoPhaseBorrow, /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in /// implicit closure bindings. It is needed when the closure is @@ -216,23 +226,14 @@ pub enum BorrowKind { /// user code, if awkward, but extra weird for closures, since the /// borrow is hidden. /// - /// So we introduce a "unique imm" borrow -- the referent is - /// immutable, but not aliasable. This solves the problem. For - /// simplicity, we don't give users the way to express this - /// borrow, it's just used when translating closures. + /// So we introduce a `ClosureCapture` borrow -- user will not have to mark the variable + /// containing the mutable reference as `mut`, as they didn't ever + /// intend to mutate the mutable reference itself. We still mutable capture it in order to + /// mutate the pointed value through it (but not mutating the reference itself). /// - // FIXME(#112072): This is wrong. Unique borrows are mutable borrows except - // that they do not require their pointee to be marked as a mutable. - // They should still be treated as mutable borrows in every other way, - // e.g. for variance or overlap checking. - Unique, - - /// Data is mutable and not aliasable. - Mut { - /// `true` if this borrow arose from method-call auto-ref - /// (i.e., `adjustment::Adjust::Borrow`). - allow_two_phase_borrow: bool, - }, + /// This solves the problem. For simplicity, we don't give users the way to express this + /// borrow, it's just used when translating closures. + ClosureCapture, } /////////////////////////////////////////////////////////////////////////// @@ -512,6 +513,31 @@ pub struct CopyNonOverlapping<'tcx> { pub count: Operand<'tcx>, } +/// Represents how a `TerminatorKind::Call` was constructed, used for diagnostics +#[derive(Clone, Copy, TyEncodable, TyDecodable, Debug, PartialEq, Hash, HashStable)] +#[derive(TypeFoldable, TypeVisitable)] +pub enum CallSource { + /// This came from something such as `a > b` or `a + b`. In THIR, if `from_hir_call` + /// is false then this is the desugaring. + OverloadedOperator, + /// This was from comparison generated by a match, used by const-eval for better errors + /// when the comparison cannot be done in compile time. + /// + /// (see <https://github.com/rust-lang/rust/issues/90237>) + MatchCmp, + /// Other types of desugaring that did not come from the HIR, but we don't care about + /// for diagnostics (yet). + Misc, + /// Normal function call, no special source + Normal, +} + +impl CallSource { + pub fn from_hir_call(self) -> bool { + matches!(self, CallSource::Normal) + } +} + /////////////////////////////////////////////////////////////////////////// // Terminators @@ -638,11 +664,10 @@ pub enum TerminatorKind<'tcx> { target: Option<BasicBlock>, /// Action to be taken if the call unwinds. unwind: UnwindAction, - /// `true` if this is from a call in HIR rather than from an overloaded - /// operator. True for overloaded function call. - from_hir_call: bool, + /// Where this call came from in HIR/THIR. + call_source: CallSource, /// This `Span` is the span of the function, without the dot and receiver - /// (e.g. `foo(a, b)` in `x.foo(a, b)` + /// e.g. `foo(a, b)` in `x.foo(a, b)` fn_span: Span, }, @@ -801,7 +826,8 @@ pub enum UnwindAction { } /// Information about an assertion failure. -#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, TypeFoldable, TypeVisitable)] +#[derive(Clone, Hash, HashStable, PartialEq, Debug)] +#[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub enum AssertKind<O> { BoundsCheck { len: O, index: O }, Overflow(BinOp, O, O), @@ -1204,9 +1230,9 @@ pub enum CastKind { /// An address-to-pointer cast that picks up an exposed provenance. /// See the docs on `from_exposed_addr` for more details. PointerFromExposedAddress, - /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are + /// Pointer related casts that are done by coercions. Note that reference-to-raw-ptr casts are /// translated into `&raw mut/const *r`, i.e., they are not actually casts. - Pointer(PointerCast), + PointerCoercion(PointerCoercion), /// Cast into a dyn* object. DynStar, IntToInt, @@ -1266,19 +1292,30 @@ pub enum UnOp { pub enum BinOp { /// The `+` operator (addition) Add, + /// Like `Add`, but with UB on overflow. (Integers only.) + AddUnchecked, /// The `-` operator (subtraction) Sub, + /// Like `Sub`, but with UB on overflow. (Integers only.) + SubUnchecked, /// The `*` operator (multiplication) Mul, + /// Like `Mul`, but with UB on overflow. (Integers only.) + MulUnchecked, /// The `/` operator (division) /// - /// Division by zero is UB, because the compiler should have inserted checks - /// prior to this. + /// For integer types, division by zero is UB, as is `MIN / -1` for signed. + /// The compiler should have inserted checks prior to this. + /// + /// Floating-point division by zero is safe, and does not need guards. Div, /// The `%` operator (modulus) /// - /// Using zero as the modulus (second operand) is UB, because the compiler - /// should have inserted checks prior to this. + /// For integer types, using zero as the modulus (second operand) is UB, + /// as is `MIN % -1` for signed. + /// The compiler should have inserted checks prior to this. + /// + /// Floating-point remainder by zero is safe, and does not need guards. Rem, /// The `^` operator (bitwise xor) BitXor, @@ -1290,10 +1327,17 @@ pub enum BinOp { /// /// The offset is truncated to the size of the first operand before shifting. Shl, + /// Like `Shl`, but is UB if the RHS >= LHS::BITS + ShlUnchecked, /// The `>>` operator (shift right) /// /// The offset is truncated to the size of the first operand before shifting. + /// + /// This is an arithmetic shift if the LHS is signed + /// and a logical shift if the LHS is unsigned. Shr, + /// Like `Shl`, but is UB if the RHS >= LHS::BITS + ShrUnchecked, /// The `==` operator (equality) Eq, /// The `<` operator (less than) diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 5ca824134..8618a5315 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -95,11 +95,13 @@ impl<'tcx> PlaceTy<'tcx> { ProjectionElem::Subslice { from, to, from_end } => { PlaceTy::from_ty(match self.ty.kind() { ty::Slice(..) => self.ty, - ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), + ty::Array(inner, _) if !from_end => { + Ty::new_array(tcx, *inner, (to - from) as u64) + } ty::Array(inner, size) if from_end => { let size = size.eval_target_usize(tcx, param_env); let len = size - from - to; - tcx.mk_array(*inner, len) + Ty::new_array(tcx, *inner, len) } _ => bug!("cannot subslice non-array type: `{:?}`", self), }) @@ -162,16 +164,16 @@ impl<'tcx> Rvalue<'tcx> { match *self { Rvalue::Use(ref operand) => operand.ty(local_decls, tcx), Rvalue::Repeat(ref operand, count) => { - tcx.mk_array_with_const_len(operand.ty(local_decls, tcx), count) + Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count) } Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did), Rvalue::Ref(reg, bk, ref place) => { let place_ty = place.ty(local_decls, tcx).ty; - tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) + Ty::new_ref(tcx, reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) } Rvalue::AddressOf(mutability, ref place) => { let place_ty = place.ty(local_decls, tcx).ty; - tcx.mk_ptr(ty::TypeAndMut { ty: place_ty, mutbl: mutability }) + Ty::new_ptr(tcx, ty::TypeAndMut { ty: place_ty, mutbl: mutability }) } Rvalue::Len(..) => tcx.types.usize, Rvalue::Cast(.., ty) => ty, @@ -184,7 +186,7 @@ impl<'tcx> Rvalue<'tcx> { let lhs_ty = lhs.ty(local_decls, tcx); let rhs_ty = rhs.ty(local_decls, tcx); let ty = op.ty(tcx, lhs_ty, rhs_ty); - tcx.mk_tup(&[ty, tcx.types.bool]) + Ty::new_tup(tcx, &[ty, tcx.types.bool]) } Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), @@ -192,17 +194,17 @@ impl<'tcx> Rvalue<'tcx> { tcx.types.usize } Rvalue::Aggregate(ref ak, ref ops) => match **ak { - AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), + AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), AggregateKind::Tuple => { - tcx.mk_tup_from_iter(ops.iter().map(|op| op.ty(local_decls, tcx))) + Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx))) } AggregateKind::Adt(did, _, substs, _, _) => tcx.type_of(did).subst(tcx, substs), - AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs), + AggregateKind::Closure(did, substs) => Ty::new_closure(tcx, did, substs), AggregateKind::Generator(did, substs, movability) => { - tcx.mk_generator(did, substs, movability) + Ty::new_generator(tcx, did, substs, movability) } }, - Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty), + Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, } } @@ -235,8 +237,11 @@ impl<'tcx> BinOp { // FIXME: handle SIMD correctly match self { &BinOp::Add + | &BinOp::AddUnchecked | &BinOp::Sub + | &BinOp::SubUnchecked | &BinOp::Mul + | &BinOp::MulUnchecked | &BinOp::Div | &BinOp::Rem | &BinOp::BitXor @@ -246,7 +251,11 @@ impl<'tcx> BinOp { assert_eq!(lhs_ty, rhs_ty); lhs_ty } - &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => { + &BinOp::Shl + | &BinOp::ShlUnchecked + | &BinOp::Shr + | &BinOp::ShrUnchecked + | &BinOp::Offset => { lhs_ty // lhs_ty can be != rhs_ty } &BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => { @@ -262,11 +271,6 @@ impl BorrowKind { BorrowKind::Mut { .. } => hir::Mutability::Mut, BorrowKind::Shared => hir::Mutability::Not, - // We have no type corresponding to a unique imm borrow, so - // use `&mut`. It gives all the capabilities of a `&uniq` - // and hence is a safe "over approximation". - BorrowKind::Unique => hir::Mutability::Mut, - // We have no type corresponding to a shallow borrow, so use // `&` as an approximation. BorrowKind::Shallow => hir::Mutability::Not, @@ -293,7 +297,14 @@ impl BinOp { BinOp::Gt => hir::BinOpKind::Gt, BinOp::Le => hir::BinOpKind::Le, BinOp::Ge => hir::BinOpKind::Ge, - BinOp::Offset => unreachable!(), + BinOp::AddUnchecked + | BinOp::SubUnchecked + | BinOp::MulUnchecked + | BinOp::ShlUnchecked + | BinOp::ShrUnchecked + | BinOp::Offset => { + unreachable!() + } } } } diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 2c6126cdd..1b9c1438f 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -105,7 +105,7 @@ pub struct Terminator<'tcx> { pub kind: TerminatorKind<'tcx>, } -pub type Successors<'a> = impl Iterator<Item = BasicBlock> + 'a; +pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a; pub type SuccessorsMut<'a> = iter::Chain<std::option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>; @@ -272,7 +272,8 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { let unwind = match self.unwind() { // Not needed or included in successors - None | Some(UnwindAction::Continue) | Some(UnwindAction::Cleanup(_)) => None, + None | Some(UnwindAction::Cleanup(_)) => None, + Some(UnwindAction::Continue) => Some("unwind continue"), Some(UnwindAction::Unreachable) => Some("unwind unreachable"), Some(UnwindAction::Terminate) => Some("unwind terminate"), }; diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 7d247eeb6..ec16a8470 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // B C // | | // | | - // D | + // | D // \ / // \ / // E @@ -159,26 +159,26 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { // // When the first call to `traverse_successor` happens, the following happens: // - // [(B, [D]), // `B` taken from the successors of `A`, pushed to the - // // top of the stack along with the successors of `B` - // (A, [C])] + // [(C, [D]), // `C` taken from the successors of `A`, pushed to the + // // top of the stack along with the successors of `C` + // (A, [B])] // - // [(D, [E]), // `D` taken from successors of `B`, pushed to stack - // (B, []), - // (A, [C])] + // [(D, [E]), // `D` taken from successors of `C`, pushed to stack + // (C, []), + // (A, [B])] // // [(E, []), // `E` taken from successors of `D`, pushed to stack // (D, []), - // (B, []), - // (A, [C])] + // (C, []), + // (A, [B])] // // Now that the top of the stack has no successors we can traverse, each item will - // be popped off during iteration until we get back to `A`. This yields [E, D, B]. + // be popped off during iteration until we get back to `A`. This yields [E, D, C]. // - // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but + // When we yield `C` and call `traverse_successor`, we push `B` to the stack, but // since we've already visited `E`, that child isn't added to the stack. The last - // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A] - while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next() { + // two iterations yield `B` and finally `A` for a final traversal of [E, D, C, B, A] + while let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() && let Some(bb) = iter.next_back() { if self.visited.insert(bb) { if let Some(term) = &self.basic_blocks[bb].terminator { self.visit_stack.push((bb, term.successors())); @@ -188,10 +188,6 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { } } -pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> { - Postorder::new(&body.basic_blocks, START_BLOCK) -} - impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { type Item = (BasicBlock, &'a BasicBlockData<'tcx>); @@ -219,6 +215,17 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> { } } +/// Creates an iterator over the `Body`'s basic blocks, that: +/// - returns basic blocks in a postorder, +/// - traverses the `BasicBlocks` CFG cache's reverse postorder backwards, and does not cache the +/// postorder itself. +pub fn postorder<'a, 'tcx>( + body: &'a Body<'tcx>, +) -> impl Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> + ExactSizeIterator + DoubleEndedIterator +{ + reverse_postorder(body).rev() +} + /// Reverse postorder traversal of a graph /// /// Reverse postorder is the reverse order of a postorder traversal. @@ -295,34 +302,12 @@ pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet<BasicBlock> { iter.visited } -#[derive(Clone)] -pub struct ReversePostorderIter<'a, 'tcx> { +/// Creates an iterator over the `Body`'s basic blocks, that: +/// - returns basic blocks in a reverse postorder, +/// - makes use of the `BasicBlocks` CFG cache's reverse postorder. +pub fn reverse_postorder<'a, 'tcx>( body: &'a Body<'tcx>, - blocks: &'a [BasicBlock], - idx: usize, -} - -impl<'a, 'tcx> Iterator for ReversePostorderIter<'a, 'tcx> { - type Item = (BasicBlock, &'a BasicBlockData<'tcx>); - - fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { - if self.idx == 0 { - return None; - } - self.idx -= 1; - - self.blocks.get(self.idx).map(|&bb| (bb, &self.body[bb])) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.idx, Some(self.idx)) - } -} - -impl<'a, 'tcx> ExactSizeIterator for ReversePostorderIter<'a, 'tcx> {} - -pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> { - let blocks = body.basic_blocks.postorder(); - let len = blocks.len(); - ReversePostorderIter { body, blocks, idx: len } +) -> impl Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> + ExactSizeIterator + DoubleEndedIterator +{ + body.basic_blocks.reverse_postorder().iter().map(|&bb| (bb, &body.basic_blocks[bb])) } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 8d44e929a..205dc9ec7 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -519,7 +519,7 @@ macro_rules! make_mir_visitor { destination, target: _, unwind: _, - from_hir_call: _, + call_source: _, fn_span: _ } => { self.visit_operand(func, location); @@ -650,9 +650,6 @@ macro_rules! make_mir_visitor { BorrowKind::Shallow => PlaceContext::NonMutatingUse( NonMutatingUseContext::ShallowBorrow ), - BorrowKind::Unique => PlaceContext::MutatingUse( - MutatingUseContext::Borrow - ), BorrowKind::Mut { .. } => PlaceContext::MutatingUse(MutatingUseContext::Borrow), }; @@ -1136,13 +1133,12 @@ macro_rules! visit_place_fns { fn visit_projection_elem( &mut self, - local: Local, - proj_base: &[PlaceElem<'tcx>], + place_ref: PlaceRef<'tcx>, elem: PlaceElem<'tcx>, context: PlaceContext, location: Location, ) { - self.super_projection_elem(local, proj_base, elem, context, location); + self.super_projection_elem(place_ref, elem, context, location); } fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { @@ -1171,15 +1167,13 @@ macro_rules! visit_place_fns { location: Location, ) { for (base, elem) in place_ref.iter_projections().rev() { - let base_proj = base.projection; - self.visit_projection_elem(place_ref.local, base_proj, elem, context, location); + self.visit_projection_elem(base, elem, context, location); } } fn super_projection_elem( &mut self, - _local: Local, - _proj_base: &[PlaceElem<'tcx>], + _place_ref: PlaceRef<'tcx>, elem: PlaceElem<'tcx>, _context: PlaceContext, location: Location, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index fd02a1613..2c481745d 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -55,6 +55,10 @@ impl<T> EraseType for &'_ ty::List<T> { type Result = [u8; size_of::<*const ()>()]; } +impl<I: rustc_index::Idx, T> EraseType for &'_ rustc_index::IndexSlice<I, T> { + type Result = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()]; +} + impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> { type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()]; } @@ -67,8 +71,8 @@ impl<T> EraseType for Result<&'_ T, traits::CodegenObligationError> { type Result = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()]; } -impl<T> EraseType for Result<&'_ T, ty::layout::FnAbiError<'_>> { - type Result = [u8; size_of::<Result<&'static (), ty::layout::FnAbiError<'static>>>()]; +impl<T> EraseType for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> { + type Result = [u8; size_of::<Result<&'static (), &'static ty::layout::FnAbiError<'static>>>()]; } impl<T> EraseType for Result<(&'_ T, rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed> { @@ -92,15 +96,17 @@ impl EraseType for Result<ty::GenericArg<'_>, traits::query::NoSolution> { type Result = [u8; size_of::<Result<ty::GenericArg<'static>, traits::query::NoSolution>>()]; } -impl EraseType for Result<bool, ty::layout::LayoutError<'_>> { - type Result = [u8; size_of::<Result<bool, ty::layout::LayoutError<'static>>>()]; +impl EraseType for Result<bool, &ty::layout::LayoutError<'_>> { + type Result = [u8; size_of::<Result<bool, &'static ty::layout::LayoutError<'static>>>()]; } -impl EraseType for Result<rustc_target::abi::TyAndLayout<'_, Ty<'_>>, ty::layout::LayoutError<'_>> { +impl EraseType + for Result<rustc_target::abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::LayoutError<'_>> +{ type Result = [u8; size_of::< Result< rustc_target::abi::TyAndLayout<'static, Ty<'static>>, - ty::layout::LayoutError<'static>, + &'static ty::layout::LayoutError<'static>, >, >()]; } @@ -309,7 +315,6 @@ tcx_lifetime! { rustc_middle::mir::interpret::ConstValue, rustc_middle::mir::interpret::GlobalId, rustc_middle::mir::interpret::LitToConstInput, - rustc_middle::traits::ChalkEnvironmentAndGoal, rustc_middle::traits::query::MethodAutoderefStepsResult, rustc_middle::traits::query::type_op::AscribeUserType, rustc_middle::traits::query::type_op::Eq, @@ -317,7 +322,7 @@ tcx_lifetime! { rustc_middle::traits::query::type_op::Subtype, rustc_middle::ty::AdtDef, rustc_middle::ty::AliasTy, - rustc_middle::ty::Clause, + rustc_middle::ty::ClauseKind, rustc_middle::ty::ClosureTypeInfo, rustc_middle::ty::Const, rustc_middle::ty::DestructuredConst, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index fa62b7f32..28e699cd2 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -2,6 +2,7 @@ use crate::infer::canonical::Canonical; use crate::mir; +use crate::mir::interpret::ConstValue; use crate::traits; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::{TyAndLayout, ValidityRequirement}; @@ -317,11 +318,11 @@ impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { } } -impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { +impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector<Self>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - tcx.def_span(self.1.def_id()) + tcx.def_span(self.1.def_id) } } @@ -333,6 +334,14 @@ impl<'tcx> Key for (ty::Const<'tcx>, FieldIdx) { } } +impl<'tcx> Key for (ConstValue<'tcx>, Ty<'tcx>) { + type CacheSelector = DefaultCacheSelector<Self>; + + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> { type CacheSelector = DefaultCacheSelector<Self>; @@ -420,7 +429,7 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { } } -impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> { +impl<'tcx> Key for &'tcx ty::List<ty::Clause<'tcx>> { type CacheSelector = DefaultCacheSelector<Self>; fn default_span(&self, _: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1528be42f..a059590e6 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -39,8 +39,8 @@ use crate::traits::query::{ }; use crate::traits::specialization_graph; use crate::traits::{ - CanonicalChalkEnvironmentAndGoal, CodegenObligationError, EvaluationResult, ImplSource, - ObjectSafetyViolation, ObligationCause, OverflowError, WellFormedLoc, + CodegenObligationError, EvaluationResult, ImplSource, ObjectSafetyViolation, ObligationCause, + OverflowError, WellFormedLoc, }; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; @@ -54,7 +54,7 @@ use crate::ty::{ }; use rustc_arena::TypedArena; use rustc_ast as ast; -use rustc_ast::expand::allocator::AllocatorKind; +use rustc_ast::expand::{allocator::AllocatorKind, StrippedCfgItem}; use rustc_attr as attr; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; @@ -346,7 +346,7 @@ rustc_queries! { /// `key` is the `DefId` of the associated type or opaque type. /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, Span)]> { + query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern @@ -373,7 +373,7 @@ rustc_queries! { /// ``` /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Predicate<'tcx>>> { + query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } } @@ -531,6 +531,19 @@ rustc_queries! { } } + /// Returns names of captured upvars for closures and generators. + /// + /// Here are some examples: + /// - `name__field1__field2` when the upvar is captured by value. + /// - `_ref__name__field` when the upvar is captured by reference. + /// + /// For generators this only contains upvars that are shared by all states. + query closure_saved_names_of_captured_variables(def_id: DefId) -> &'tcx IndexVec<abi::FieldIdx, Symbol> { + arena_cache + desc { |tcx| "computing debuginfo for closure `{}`", tcx.def_path_str(def_id) } + separate_provide_extern + } + query mir_generator_witnesses(key: DefId) -> &'tcx Option<mir::GeneratorLayout<'tcx>> { arena_cache desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) } @@ -868,7 +881,7 @@ rustc_queries! { /// /// Note that we've liberated the late bound regions of function signatures, so /// this can not be used to check whether these types are well formed. - query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> { + query assumed_wf_types(key: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] { desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) } } @@ -1074,19 +1087,13 @@ rustc_queries! { } /// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index - /// and its field values. - query try_destructure_mir_constant( - key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> + /// and its field values. This should only be used for pretty printing. + query try_destructure_mir_constant_for_diagnostics( + key: (ConstValue<'tcx>, Ty<'tcx>) ) -> Option<mir::DestructuredConstant<'tcx>> { desc { "destructuring MIR constant"} - } - - /// Dereference a constant reference or raw pointer and turn the result into a constant - /// again. - query deref_mir_constant( - key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>> - ) -> mir::ConstantKind<'tcx> { - desc { "dereferencing MIR constant" } + no_hash + eval_always } query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { @@ -1100,10 +1107,6 @@ rustc_queries! { desc { "converting literal to const" } } - query lit_to_mir_constant(key: LitToConstInput<'tcx>) -> Result<mir::ConstantKind<'tcx>, LitToConstError> { - desc { "converting literal to mir constant" } - } - query check_match(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> { desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { true } @@ -1275,7 +1278,7 @@ rustc_queries! { } query codegen_select_candidate( - key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) + key: (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> { cache_on_disk_if { true } desc { |tcx| "computing candidate for `{}`", key.1 } @@ -1382,7 +1385,7 @@ rustc_queries! { /// executes in "reveal all" mode, and will normalize the input type. query layout_of( key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> { + ) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> { depth_limit desc { "computing layout of `{}`", key.value } } @@ -1393,7 +1396,7 @@ rustc_queries! { /// instead, where the instance is an `InstanceDef::Virtual`. query fn_abi_of_fn_ptr( key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)> - ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { + ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> { desc { "computing call ABI of `{}` function pointers", key.value.0 } } @@ -1404,7 +1407,7 @@ rustc_queries! { /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`). query fn_abi_of_instance( key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)> - ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> { + ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> { desc { "computing call ABI of `{}`", key.value.0 } } @@ -1487,8 +1490,9 @@ rustc_queries! { desc { "getting traits in scope at a block" } } - query impl_defaultness(def_id: DefId) -> hir::Defaultness { - desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } + /// Returns whether the impl or associated function has the `default` keyword. + query defaultness(def_id: DefId) -> hir::Defaultness { + desc { |tcx| "looking up whether `{}` has `default`", tcx.def_path_str(def_id) } separate_provide_extern feedable } @@ -1915,6 +1919,16 @@ rustc_queries! { } /// Do not call this query directly: invoke `normalize` instead. + query normalize_weak_ty( + goal: CanonicalProjectionGoal<'tcx> + ) -> Result< + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, + NoSolution, + > { + desc { "normalizing `{}`", goal.value.value } + } + + /// Do not call this query directly: invoke `normalize` instead. query normalize_inherent_projection_ty( goal: CanonicalProjectionGoal<'tcx> ) -> Result< @@ -1959,15 +1973,6 @@ rustc_queries! { desc { "evaluating trait selection obligation `{}`", goal.value.value } } - query evaluate_goal( - goal: CanonicalChalkEnvironmentAndGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, - NoSolution - > { - desc { "evaluating trait selection obligation `{}`", goal.value } - } - /// Do not call this query directly: part of the `Eq` type-op query type_op_ascribe_user_type( goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx> @@ -2019,10 +2024,10 @@ rustc_queries! { } /// Do not call this query directly: part of the `Normalize` type-op - query type_op_normalize_predicate( - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>> + query type_op_normalize_clause( + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Clause<'tcx>> ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>, + &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Clause<'tcx>>>, NoSolution, > { desc { "normalizing `{:?}`", goal.value.value.value } @@ -2113,7 +2118,7 @@ rustc_queries! { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } } - query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> { + query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Clause<'tcx>>) -> &'tcx ty::List<ty::Clause<'tcx>> { desc { "revealing opaque types in `{:?}`", key } } @@ -2152,7 +2157,7 @@ rustc_queries! { separate_provide_extern } - query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, ty::layout::LayoutError<'tcx>> { + query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> { desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 } } @@ -2185,6 +2190,19 @@ rustc_queries! { query check_tys_might_be_eq(arg: Canonical<'tcx, (ty::ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>) -> Result<(), NoSolution> { desc { "check whether two const param are definitely not equal to eachother"} } + + /// Get all item paths that were stripped by a `#[cfg]` in a particular crate. + /// Should not be called for the local crate before the resolver outputs are created, as it + /// is only fed there. + query stripped_cfg_items(cnum: CrateNum) -> &'tcx [StrippedCfgItem] { + feedable + desc { "getting cfg-ed out item names" } + separate_provide_extern + } + + query generics_require_sized_self(def_id: DefId) -> bool { + desc { "check whether the item has a `where Self: Sized` bound" } + } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 220118ae5..8751d3b78 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -791,13 +791,6 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> } } -impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] { - #[inline] - fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { - RefDecodable::decode(d) - } -} - impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] { #[inline] fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 813e109c4..e9af5070e 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -18,7 +18,7 @@ use rustc_index::IndexVec; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp}; -use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarSubsts}; use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; @@ -329,9 +329,10 @@ pub enum ExprKind<'tcx> { NeverToAny { source: ExprId, }, - /// A pointer cast. More information can be found in [`PointerCast`]. - Pointer { - cast: PointerCast, + /// A pointer coercion. More information can be found in [`PointerCoercion`]. + /// Pointer casts that cannot be done by coercions are represented by [`ExprKind::Cast`]. + PointerCoercion { + cast: PointerCoercion, source: ExprId, }, /// A `loop` expression. @@ -410,6 +411,10 @@ pub enum ExprKind<'tcx> { Return { value: Option<ExprId>, }, + /// A `become` expression. + Become { + value: ExprId, + }, /// An inline `const` block, e.g. `const {}`. ConstBlock { did: DefId, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 5c7ec31cf..14bc1ac0c 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -65,7 +65,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp Cast { source } => visitor.visit_expr(&visitor.thir()[source]), Use { source } => visitor.visit_expr(&visitor.thir()[source]), NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), - Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + PointerCoercion { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), Let { expr, .. } => { visitor.visit_expr(&visitor.thir()[expr]); } @@ -100,6 +100,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp visitor.visit_expr(&visitor.thir()[value]) } } + Become { value } => visitor.visit_expr(&visitor.thir()[value]), ConstBlock { did: _, substs: _ } => {} Repeat { value, count: _ } => { visitor.visit_expr(&visitor.thir()[value]); diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs deleted file mode 100644 index fcc8f457a..000000000 --- a/compiler/rustc_middle/src/traits/chalk.rs +++ /dev/null @@ -1,396 +0,0 @@ -//! Types required for Chalk-related queries -//! -//! The primary purpose of this file is defining an implementation for the -//! `chalk_ir::interner::Interner` trait. The primary purpose of this trait, as -//! its name suggest, is to provide an abstraction boundary for creating -//! interned Chalk types. - -use rustc_middle::ty::{self, AdtDef, TyCtxt}; - -use rustc_hir::def_id::DefId; -use rustc_target::spec::abi::Abi; - -use std::cmp::Ordering; -use std::fmt; -use std::hash::{Hash, Hasher}; - -#[derive(Copy, Clone)] -pub struct RustInterner<'tcx> { - pub tcx: TyCtxt<'tcx>, -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> Hash for RustInterner<'tcx> { - fn hash<H: Hasher>(&self, _state: &mut H) {} -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> Ord for RustInterner<'tcx> { - fn cmp(&self, _other: &Self) -> Ordering { - Ordering::Equal - } -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> PartialOrd for RustInterner<'tcx> { - fn partial_cmp(&self, _other: &Self) -> Option<Ordering> { - None - } -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> PartialEq for RustInterner<'tcx> { - fn eq(&self, _other: &Self) -> bool { - false - } -} - -/// We don't ever actually need this. It's only required for derives. -impl<'tcx> Eq for RustInterner<'tcx> {} - -impl fmt::Debug for RustInterner<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "RustInterner") - } -} - -// Right now, there is no interning at all. I was running into problems with -// adding interning in `ty/context.rs` for Chalk types with -// `parallel-compiler = true`. -jackh726 -impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { - type InternedType = Box<chalk_ir::TyData<Self>>; - type InternedLifetime = Box<chalk_ir::LifetimeData<Self>>; - type InternedConst = Box<chalk_ir::ConstData<Self>>; - type InternedConcreteConst = ty::ValTree<'tcx>; - type InternedGenericArg = Box<chalk_ir::GenericArgData<Self>>; - type InternedGoal = Box<chalk_ir::GoalData<Self>>; - type InternedGoals = Vec<chalk_ir::Goal<Self>>; - type InternedSubstitution = Vec<chalk_ir::GenericArg<Self>>; - type InternedProgramClause = Box<chalk_ir::ProgramClauseData<Self>>; - type InternedProgramClauses = Vec<chalk_ir::ProgramClause<Self>>; - type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; - type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; - type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; - type InternedVariances = Vec<chalk_ir::Variance>; - type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>; - type DefId = DefId; - type InternedAdtId = AdtDef<'tcx>; - type Identifier = (); - type FnAbi = Abi; - - fn debug_program_clause_implication( - pci: &chalk_ir::ProgramClauseImplication<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - let mut write = || { - write!(fmt, "{:?}", pci.consequence)?; - - let conditions = pci.conditions.interned(); - let constraints = pci.constraints.interned(); - - let conds = conditions.len(); - let consts = constraints.len(); - if conds == 0 && consts == 0 { - return Ok(()); - } - - write!(fmt, " :- ")?; - - if conds != 0 { - for cond in &conditions[..conds - 1] { - write!(fmt, "{:?}, ", cond)?; - } - write!(fmt, "{:?}", conditions[conds - 1])?; - } - - if conds != 0 && consts != 0 { - write!(fmt, " ; ")?; - } - - if consts != 0 { - for constraint in &constraints[..consts - 1] { - write!(fmt, "{:?}, ", constraint)?; - } - write!(fmt, "{:?}", constraints[consts - 1])?; - } - - Ok(()) - }; - Some(write()) - } - - fn debug_substitution( - substitution: &chalk_ir::Substitution<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - Some(write!(fmt, "{:?}", substitution.interned())) - } - - fn debug_separator_trait_ref( - separator_trait_ref: &chalk_ir::SeparatorTraitRef<'_, Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - let substitution = &separator_trait_ref.trait_ref.substitution; - let parameters = substitution.interned(); - Some(write!( - fmt, - "{:?}{}{:?}{:?}", - parameters[0], - separator_trait_ref.separator, - separator_trait_ref.trait_ref.trait_id, - chalk_ir::debug::Angle(¶meters[1..]) - )) - } - - fn debug_quantified_where_clauses( - clauses: &chalk_ir::QuantifiedWhereClauses<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - Some(write!(fmt, "{:?}", clauses.interned())) - } - - fn debug_ty(ty: &chalk_ir::Ty<Self>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { - match &ty.interned().kind { - chalk_ir::TyKind::Ref(chalk_ir::Mutability::Not, lifetime, ty) => { - Some(write!(fmt, "(&{:?} {:?})", lifetime, ty)) - } - chalk_ir::TyKind::Ref(chalk_ir::Mutability::Mut, lifetime, ty) => { - Some(write!(fmt, "(&{:?} mut {:?})", lifetime, ty)) - } - chalk_ir::TyKind::Array(ty, len) => Some(write!(fmt, "[{:?}; {:?}]", ty, len)), - chalk_ir::TyKind::Slice(ty) => Some(write!(fmt, "[{:?}]", ty)), - chalk_ir::TyKind::Tuple(len, substs) => Some( - try { - write!(fmt, "(")?; - for (idx, substitution) in substs.interned().iter().enumerate() { - if idx == *len && *len != 1 { - // Don't add a trailing comma if the tuple has more than one element - write!(fmt, "{:?}", substitution)?; - } else { - write!(fmt, "{:?},", substitution)?; - } - } - write!(fmt, ")")?; - }, - ), - _ => None, - } - } - - fn debug_alias( - alias_ty: &chalk_ir::AliasTy<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - match alias_ty { - chalk_ir::AliasTy::Projection(projection_ty) => { - Self::debug_projection_ty(projection_ty, fmt) - } - chalk_ir::AliasTy::Opaque(opaque_ty) => Self::debug_opaque_ty(opaque_ty, fmt), - } - } - - fn debug_projection_ty( - projection_ty: &chalk_ir::ProjectionTy<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - Some(write!( - fmt, - "projection: {:?} {:?}", - projection_ty.associated_ty_id, projection_ty.substitution, - )) - } - - fn debug_opaque_ty( - opaque_ty: &chalk_ir::OpaqueTy<Self>, - fmt: &mut fmt::Formatter<'_>, - ) -> Option<fmt::Result> { - Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id)) - } - - fn intern_ty(self, ty: chalk_ir::TyKind<Self>) -> Self::InternedType { - let flags = ty.compute_flags(self); - Box::new(chalk_ir::TyData { kind: ty, flags: flags }) - } - - fn ty_data(self, ty: &Self::InternedType) -> &chalk_ir::TyData<Self> { - ty - } - - fn intern_lifetime(self, lifetime: chalk_ir::LifetimeData<Self>) -> Self::InternedLifetime { - Box::new(lifetime) - } - - fn lifetime_data(self, lifetime: &Self::InternedLifetime) -> &chalk_ir::LifetimeData<Self> { - &lifetime - } - - fn intern_const(self, constant: chalk_ir::ConstData<Self>) -> Self::InternedConst { - Box::new(constant) - } - - fn const_data(self, constant: &Self::InternedConst) -> &chalk_ir::ConstData<Self> { - &constant - } - - fn const_eq( - self, - _ty: &Self::InternedType, - c1: &Self::InternedConcreteConst, - c2: &Self::InternedConcreteConst, - ) -> bool { - c1 == c2 - } - - fn intern_generic_arg(self, data: chalk_ir::GenericArgData<Self>) -> Self::InternedGenericArg { - Box::new(data) - } - - fn generic_arg_data(self, data: &Self::InternedGenericArg) -> &chalk_ir::GenericArgData<Self> { - &data - } - - fn intern_goal(self, goal: chalk_ir::GoalData<Self>) -> Self::InternedGoal { - Box::new(goal) - } - - fn goal_data(self, goal: &Self::InternedGoal) -> &chalk_ir::GoalData<Self> { - &goal - } - - fn intern_goals<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::Goal<Self>, E>>, - ) -> Result<Self::InternedGoals, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn goals_data(self, goals: &Self::InternedGoals) -> &[chalk_ir::Goal<Self>] { - goals - } - - fn intern_substitution<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::GenericArg<Self>, E>>, - ) -> Result<Self::InternedSubstitution, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn substitution_data( - self, - substitution: &Self::InternedSubstitution, - ) -> &[chalk_ir::GenericArg<Self>] { - substitution - } - - fn intern_program_clause( - self, - data: chalk_ir::ProgramClauseData<Self>, - ) -> Self::InternedProgramClause { - Box::new(data) - } - - fn program_clause_data( - self, - clause: &Self::InternedProgramClause, - ) -> &chalk_ir::ProgramClauseData<Self> { - &clause - } - - fn intern_program_clauses<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, - ) -> Result<Self::InternedProgramClauses, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn program_clauses_data( - self, - clauses: &Self::InternedProgramClauses, - ) -> &[chalk_ir::ProgramClause<Self>] { - clauses - } - - fn intern_quantified_where_clauses<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, - ) -> Result<Self::InternedQuantifiedWhereClauses, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn quantified_where_clauses_data( - self, - clauses: &Self::InternedQuantifiedWhereClauses, - ) -> &[chalk_ir::QuantifiedWhereClause<Self>] { - clauses - } - - fn intern_generic_arg_kinds<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>, - ) -> Result<Self::InternedVariableKinds, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn variable_kinds_data( - self, - parameter_kinds: &Self::InternedVariableKinds, - ) -> &[chalk_ir::VariableKind<Self>] { - parameter_kinds - } - - fn intern_canonical_var_kinds<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>, - ) -> Result<Self::InternedCanonicalVarKinds, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn canonical_var_kinds_data( - self, - canonical_var_kinds: &Self::InternedCanonicalVarKinds, - ) -> &[chalk_ir::CanonicalVarKind<Self>] { - canonical_var_kinds - } - - fn intern_constraints<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>, E>>, - ) -> Result<Self::InternedConstraints, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn constraints_data( - self, - constraints: &Self::InternedConstraints, - ) -> &[chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] { - constraints - } - - fn intern_variances<E>( - self, - data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>, - ) -> Result<Self::InternedVariances, E> { - data.into_iter().collect::<Result<Vec<_>, _>>() - } - - fn variances_data(self, variances: &Self::InternedVariances) -> &[chalk_ir::Variance] { - variances - } -} - -impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> { - type Interner = Self; -} - -/// A chalk environment and goal. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, TypeVisitable)] -pub struct ChalkEnvironmentAndGoal<'tcx> { - pub environment: &'tcx ty::List<ty::Predicate<'tcx>>, - pub goal: ty::Predicate<'tcx>, -} - -impl<'tcx> fmt::Display for ChalkEnvironmentAndGoal<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "environment: {:?}, goal: {}", self.environment, self.goal) - } -} diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 0a903a769..c7d2e4c22 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -2,7 +2,6 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html -mod chalk; pub mod query; pub mod select; pub mod solve; @@ -30,12 +29,8 @@ use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; -pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; - pub use self::ObligationCauseCode::*; -pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner}; - /// Depending on the stage of compilation, we want projection to be /// more or less conservative. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] @@ -445,6 +440,12 @@ pub enum ObligationCauseCode<'tcx> { /// Obligations to prove that a `std::ops::Drop` impl is not stronger than /// the ADT it's being implemented for. DropImpl, + + /// Requirement for a `const N: Ty` to implement `Ty: ConstParamTy` + ConstParam(Ty<'tcx>), + + /// Obligations emitted during the normalization of a weak type alias. + TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId), } /// The 'location' at which we try to perform HIR-based wf checking. @@ -587,6 +588,10 @@ pub enum SelectionError<'tcx> { /// Signaling that an error has already been emitted, to avoid /// multiple errors being shown. ErrorReporting, + /// Computing an opaque type's hidden type caused an error (e.g. a cycle error). + /// We can thus not know whether the hidden type implements an auto trait, so + /// we should not presume anything about it. + OpaqueTypeAutoTraitLeakageUnknown(DefId), } #[derive(Clone, Debug, TypeVisitable, Lift)] @@ -640,12 +645,6 @@ pub enum ImplSource<'tcx, N> { /// ImplSource identifying a particular impl. UserDefined(ImplSourceUserDefinedData<'tcx, N>), - /// ImplSource for auto trait implementations. - /// This carries the information and nested obligations with regards - /// to an auto implementation for a trait `Trait`. The nested obligations - /// ensure the trait implementation holds for all the constituent types. - AutoImpl(ImplSourceAutoImplData<N>), - /// Successful resolution to an obligation provided by the caller /// for some type parameter. The `Vec<N>` represents the /// obligations incurred from normalizing the where-clause (if @@ -653,84 +652,40 @@ pub enum ImplSource<'tcx, N> { Param(Vec<N>, ty::BoundConstness), /// Virtual calls through an object. - Object(ImplSourceObjectData<'tcx, N>), + Object(ImplSourceObjectData<N>), /// Successful resolution for a builtin trait. - Builtin(ImplSourceBuiltinData<N>), + Builtin(Vec<N>), /// ImplSource for trait upcasting coercion - TraitUpcasting(ImplSourceTraitUpcastingData<'tcx, N>), - - /// ImplSource automatically generated for a closure. The `DefId` is the ID - /// of the closure expression. This is an `ImplSource::UserDefined` in spirit, but the - /// impl is generated by the compiler and does not appear in the source. - Closure(ImplSourceClosureData<'tcx, N>), - - /// Same as above, but for a function pointer type with the given signature. - FnPointer(ImplSourceFnPointerData<'tcx, N>), - - /// ImplSource automatically generated for a generator. - Generator(ImplSourceGeneratorData<'tcx, N>), - - /// ImplSource automatically generated for a generator backing an async future. - Future(ImplSourceFutureData<'tcx, N>), - - /// ImplSource for a trait alias. - TraitAlias(ImplSourceTraitAliasData<'tcx, N>), - - /// ImplSource for a `const Drop` implementation. - ConstDestruct(ImplSourceConstDestructData<N>), + TraitUpcasting(ImplSourceTraitUpcastingData<N>), } impl<'tcx, N> ImplSource<'tcx, N> { pub fn nested_obligations(self) -> Vec<N> { match self { ImplSource::UserDefined(i) => i.nested, - ImplSource::Param(n, _) => n, - ImplSource::Builtin(i) => i.nested, - ImplSource::AutoImpl(d) => d.nested, - ImplSource::Closure(c) => c.nested, - ImplSource::Generator(c) => c.nested, - ImplSource::Future(c) => c.nested, + ImplSource::Param(n, _) | ImplSource::Builtin(n) => n, ImplSource::Object(d) => d.nested, - ImplSource::FnPointer(d) => d.nested, - ImplSource::TraitAlias(d) => d.nested, ImplSource::TraitUpcasting(d) => d.nested, - ImplSource::ConstDestruct(i) => i.nested, } } pub fn borrow_nested_obligations(&self) -> &[N] { match self { ImplSource::UserDefined(i) => &i.nested, - ImplSource::Param(n, _) => n, - ImplSource::Builtin(i) => &i.nested, - ImplSource::AutoImpl(d) => &d.nested, - ImplSource::Closure(c) => &c.nested, - ImplSource::Generator(c) => &c.nested, - ImplSource::Future(c) => &c.nested, + ImplSource::Param(n, _) | ImplSource::Builtin(n) => &n, ImplSource::Object(d) => &d.nested, - ImplSource::FnPointer(d) => &d.nested, - ImplSource::TraitAlias(d) => &d.nested, ImplSource::TraitUpcasting(d) => &d.nested, - ImplSource::ConstDestruct(i) => &i.nested, } } pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] { match self { ImplSource::UserDefined(i) => &mut i.nested, - ImplSource::Param(n, _) => n, - ImplSource::Builtin(i) => &mut i.nested, - ImplSource::AutoImpl(d) => &mut d.nested, - ImplSource::Closure(c) => &mut c.nested, - ImplSource::Generator(c) => &mut c.nested, - ImplSource::Future(c) => &mut c.nested, + ImplSource::Param(n, _) | ImplSource::Builtin(n) => n, ImplSource::Object(d) => &mut d.nested, - ImplSource::FnPointer(d) => &mut d.nested, - ImplSource::TraitAlias(d) => &mut d.nested, ImplSource::TraitUpcasting(d) => &mut d.nested, - ImplSource::ConstDestruct(i) => &mut i.nested, } } @@ -745,54 +700,17 @@ impl<'tcx, N> ImplSource<'tcx, N> { nested: i.nested.into_iter().map(f).collect(), }), ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct), - ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData { - nested: i.nested.into_iter().map(f).collect(), - }), + ImplSource::Builtin(n) => ImplSource::Builtin(n.into_iter().map(f).collect()), ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData { - upcast_trait_ref: o.upcast_trait_ref, vtable_base: o.vtable_base, nested: o.nested.into_iter().map(f).collect(), }), - ImplSource::AutoImpl(d) => ImplSource::AutoImpl(ImplSourceAutoImplData { - trait_def_id: d.trait_def_id, - nested: d.nested.into_iter().map(f).collect(), - }), - ImplSource::Closure(c) => ImplSource::Closure(ImplSourceClosureData { - closure_def_id: c.closure_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }), - ImplSource::Generator(c) => ImplSource::Generator(ImplSourceGeneratorData { - generator_def_id: c.generator_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }), - ImplSource::Future(c) => ImplSource::Future(ImplSourceFutureData { - generator_def_id: c.generator_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }), - ImplSource::FnPointer(p) => ImplSource::FnPointer(ImplSourceFnPointerData { - fn_ty: p.fn_ty, - nested: p.nested.into_iter().map(f).collect(), - }), - ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData { - alias_def_id: d.alias_def_id, - substs: d.substs, - nested: d.nested.into_iter().map(f).collect(), - }), ImplSource::TraitUpcasting(d) => { ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData { - upcast_trait_ref: d.upcast_trait_ref, vtable_vptr_slot: d.vtable_vptr_slot, nested: d.nested.into_iter().map(f).collect(), }) } - ImplSource::ConstDestruct(i) => { - ImplSource::ConstDestruct(ImplSourceConstDestructData { - nested: i.nested.into_iter().map(f).collect(), - }) - } } } } @@ -817,47 +735,7 @@ pub struct ImplSourceUserDefinedData<'tcx, N> { #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] #[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceGeneratorData<'tcx, N> { - pub generator_def_id: DefId, - pub substs: SubstsRef<'tcx>, - /// Nested obligations. This can be non-empty if the generator - /// signature contains associated types. - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceFutureData<'tcx, N> { - pub generator_def_id: DefId, - pub substs: SubstsRef<'tcx>, - /// Nested obligations. This can be non-empty if the generator - /// signature contains associated types. - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceClosureData<'tcx, N> { - pub closure_def_id: DefId, - pub substs: SubstsRef<'tcx>, - /// Nested obligations. This can be non-empty if the closure - /// signature contains associated types. - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceAutoImplData<N> { - pub trait_def_id: DefId, - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceTraitUpcastingData<'tcx, N> { - /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. - pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, - +pub struct ImplSourceTraitUpcastingData<N> { /// The vtable is formed by concatenating together the method lists of /// the base object trait and all supertraits, pointers to supertrait vtable will /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable @@ -867,18 +745,9 @@ pub struct ImplSourceTraitUpcastingData<'tcx, N> { pub nested: Vec<N>, } -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceBuiltinData<N> { - pub nested: Vec<N>, -} - #[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, Lift)] #[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceObjectData<'tcx, N> { - /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. - pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, - +pub struct ImplSourceObjectData<N> { /// The vtable is formed by concatenating together the method lists of /// the base object trait and all supertraits, pointers to supertrait vtable will /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods @@ -888,27 +757,6 @@ pub struct ImplSourceObjectData<'tcx, N> { pub nested: Vec<N>, } -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceFnPointerData<'tcx, N> { - pub fn_ty: Ty<'tcx>, - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceConstDestructData<N> { - pub nested: Vec<N>, -} - -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct ImplSourceTraitAliasData<'tcx, N> { - pub alias_def_id: DefId, - pub substs: SubstsRef<'tcx>, - pub nested: Vec<N>, -} - #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum ObjectSafetyViolation { /// `Self: Sized` declared on the trait. @@ -1109,7 +957,7 @@ pub enum CodegenObligationError { FulfillmentError, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum DefiningAnchor { /// `DefId` of the item. Bind(LocalDefId), diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index eae5a280e..60a38747f 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -92,7 +92,7 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; -#[derive(Copy, Clone, Debug, HashStable, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Hash, HashStable, PartialEq, Eq)] pub struct NoSolution; impl<'tcx> From<TypeError<'tcx>> for NoSolution { diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 2c5b64a59..73b332fd8 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -11,6 +11,8 @@ use crate::ty::{ TypeVisitor, }; +pub mod inspect; + pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>; /// A goal is a statement, i.e. `predicate`, we want to prove @@ -18,7 +20,7 @@ pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>; /// /// Most of the time the `param_env` contains the `where`-bounds of the function /// we're currently typechecking while the `predicate` is some trait bound. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct Goal<'tcx, P> { pub predicate: P, pub param_env: ty::ParamEnv<'tcx>, @@ -39,7 +41,7 @@ impl<'tcx, P> Goal<'tcx, P> { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct Response<'tcx> { pub certainty: Certainty, pub var_values: CanonicalVarValues<'tcx>, @@ -47,7 +49,7 @@ pub struct Response<'tcx> { pub external_constraints: ExternalConstraints<'tcx>, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum Certainty { Yes, Maybe(MaybeCause), @@ -86,7 +88,7 @@ impl Certainty { } /// Why we failed to evaluate a goal. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum MaybeCause { /// We failed due to ambiguity. This ambiguity can either /// be a true ambiguity, i.e. there are multiple different answers, @@ -96,7 +98,7 @@ pub enum MaybeCause { Overflow, } -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct QueryInput<'tcx, T> { pub goal: Goal<'tcx, T>, pub anchor: DefiningAnchor, @@ -104,12 +106,12 @@ pub struct QueryInput<'tcx, T> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] pub struct PredefinedOpaquesData<'tcx> { pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>); impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { @@ -132,7 +134,7 @@ pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>; /// solver, merge the two responses again. pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>; -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { @@ -144,7 +146,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. pub region_constraints: QueryRegionConstraints<'tcx>, @@ -226,3 +228,9 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> { self.opaque_types.visit_with(visitor) } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] +pub enum IsNormalizesToHack { + Yes, + No, +} diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs new file mode 100644 index 000000000..527afa005 --- /dev/null +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -0,0 +1,83 @@ +use super::{ + CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution, QueryInput, QueryResult, +}; +use crate::ty; +use format::ProofTreeFormatter; +use std::fmt::{Debug, Write}; + +mod format; + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub enum CacheHit { + Provisional, + Global, +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct GoalEvaluation<'tcx> { + pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, + pub canonicalized_goal: CanonicalInput<'tcx>, + + pub kind: GoalEvaluationKind<'tcx>, + pub is_normalizes_to_hack: IsNormalizesToHack, + pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, + + pub result: QueryResult<'tcx>, +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub enum GoalEvaluationKind<'tcx> { + CacheHit(CacheHit), + Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> }, +} +impl Debug for GoalEvaluation<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_goal_evaluation(self) + } +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct AddedGoalsEvaluation<'tcx> { + pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>, + pub result: Result<Certainty, NoSolution>, +} +impl Debug for AddedGoalsEvaluation<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_nested_goal_evaluation(self) + } +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct GoalEvaluationStep<'tcx> { + pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, + + pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<GoalCandidate<'tcx>>, + + pub result: QueryResult<'tcx>, +} +impl Debug for GoalEvaluationStep<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_evaluation_step(self) + } +} + +#[derive(Eq, PartialEq, Hash, HashStable)] +pub struct GoalCandidate<'tcx> { + pub nested_goal_evaluations: Vec<AddedGoalsEvaluation<'tcx>>, + pub candidates: Vec<GoalCandidate<'tcx>>, + pub kind: CandidateKind<'tcx>, +} + +#[derive(Eq, PartialEq, Debug, Hash, HashStable)] +pub enum CandidateKind<'tcx> { + /// Probe entered when normalizing the self ty during candidate assembly + NormalizedSelfTyAssembly, + /// A normal candidate for proving a goal + Candidate { name: String, result: QueryResult<'tcx> }, +} +impl Debug for GoalCandidate<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ProofTreeFormatter { f, on_newline: true }.format_candidate(self) + } +} diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs new file mode 100644 index 000000000..2ee625674 --- /dev/null +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -0,0 +1,131 @@ +use super::*; + +pub(super) struct ProofTreeFormatter<'a, 'b> { + pub(super) f: &'a mut (dyn Write + 'b), + pub(super) on_newline: bool, +} + +impl Write for ProofTreeFormatter<'_, '_> { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + for line in s.split_inclusive("\n") { + if self.on_newline { + self.f.write_str(" ")?; + } + self.on_newline = line.ends_with("\n"); + self.f.write_str(line)?; + } + + Ok(()) + } +} + +impl ProofTreeFormatter<'_, '_> { + fn nested(&mut self) -> ProofTreeFormatter<'_, '_> { + ProofTreeFormatter { f: self, on_newline: true } + } + + pub(super) fn format_goal_evaluation(&mut self, goal: &GoalEvaluation<'_>) -> std::fmt::Result { + let f = &mut *self.f; + + let goal_text = match goal.is_normalizes_to_hack { + IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL", + IsNormalizesToHack::No => "GOAL", + }; + + writeln!(f, "{}: {:?}", goal_text, goal.uncanonicalized_goal,)?; + writeln!(f, "CANONICALIZED: {:?}", goal.canonicalized_goal)?; + + match &goal.kind { + GoalEvaluationKind::CacheHit(CacheHit::Global) => { + writeln!(f, "GLOBAL CACHE HIT: {:?}", goal.result) + } + GoalEvaluationKind::CacheHit(CacheHit::Provisional) => { + writeln!(f, "PROVISIONAL CACHE HIT: {:?}", goal.result) + } + GoalEvaluationKind::Uncached { revisions } => { + for (n, step) in revisions.iter().enumerate() { + let f = &mut *self.f; + writeln!(f, "REVISION {n}: {:?}", step.result)?; + let mut f = self.nested(); + f.format_evaluation_step(step)?; + } + + let f = &mut *self.f; + writeln!(f, "RESULT: {:?}", goal.result) + } + }?; + + if goal.returned_goals.len() > 0 { + let f = &mut *self.f; + writeln!(f, "NESTED GOALS ADDED TO CALLER: [")?; + let mut f = self.nested(); + for goal in goal.returned_goals.iter() { + writeln!(f, "ADDED GOAL: {:?},", goal)?; + } + writeln!(self.f, "]")?; + } + + Ok(()) + } + + pub(super) fn format_evaluation_step( + &mut self, + evaluation_step: &GoalEvaluationStep<'_>, + ) -> std::fmt::Result { + let f = &mut *self.f; + writeln!(f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?; + + for candidate in &evaluation_step.candidates { + let mut f = self.nested(); + f.format_candidate(candidate)?; + } + for nested_goal_evaluation in &evaluation_step.nested_goal_evaluations { + let mut f = self.nested(); + f.format_nested_goal_evaluation(nested_goal_evaluation)?; + } + + Ok(()) + } + + pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result { + let f = &mut *self.f; + + match &candidate.kind { + CandidateKind::NormalizedSelfTyAssembly => { + writeln!(f, "NORMALIZING SELF TY FOR ASSEMBLY:") + } + CandidateKind::Candidate { name, result } => { + writeln!(f, "CANDIDATE {}: {:?}", name, result) + } + }?; + + let mut f = self.nested(); + for candidate in &candidate.candidates { + f.format_candidate(candidate)?; + } + for nested_evaluations in &candidate.nested_goal_evaluations { + f.format_nested_goal_evaluation(nested_evaluations)?; + } + + Ok(()) + } + + pub(super) fn format_nested_goal_evaluation( + &mut self, + nested_goal_evaluation: &AddedGoalsEvaluation<'_>, + ) -> std::fmt::Result { + let f = &mut *self.f; + writeln!(f, "TRY_EVALUATE_ADDED_GOALS: {:?}", nested_goal_evaluation.result)?; + + for (n, revision) in nested_goal_evaluation.evaluations.iter().enumerate() { + let f = &mut *self.f; + writeln!(f, "REVISION {n}")?; + let mut f = self.nested(); + for goal_evaluation in revision { + f.format_goal_evaluation(goal_evaluation)?; + } + } + + Ok(()) + } +} diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index c016f7227..dc2cd2035 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -228,7 +228,7 @@ impl<'tcx> Ancestors<'tcx> { if let Some(item) = node.item(tcx, trait_item_def_id) { if finalizing_node.is_none() { let is_specializable = item.defaultness(tcx).is_default() - || tcx.impl_defaultness(node.def_id()).is_default(); + || tcx.defaultness(node.def_id()).is_default(); if !is_specializable { finalizing_node = Some(node); diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index 6acb7745d..a703e3c95 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -9,15 +9,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { match *self { super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v), - super::ImplSource::AutoImpl(ref t) => write!(f, "{:?}", t), - - super::ImplSource::Closure(ref d) => write!(f, "{:?}", d), - - super::ImplSource::Generator(ref d) => write!(f, "{:?}", d), - - super::ImplSource::Future(ref d) => write!(f, "{:?}", d), - - super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d), + super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d), super::ImplSource::Object(ref d) => write!(f, "{:?}", d), @@ -25,13 +17,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { write!(f, "ImplSourceParamData({:?}, {:?})", n, ct) } - super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d), - - super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d), - super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d), - - super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d), } } } @@ -46,90 +32,22 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceUserDefinedData<'tcx, } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceGeneratorData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "ImplSourceGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})", - self.generator_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceFutureData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "ImplSourceFutureData(generator_def_id={:?}, substs={:?}, nested={:?})", - self.generator_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceClosureData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "ImplSourceClosureData(closure_def_id={:?}, substs={:?}, nested={:?})", - self.closure_def_id, self.substs, self.nested - ) - } -} - -impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceBuiltinData<N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ImplSourceBuiltinData(nested={:?})", self.nested) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "ImplSourceTraitUpcastingData(upcast={:?}, vtable_vptr_slot={:?}, nested={:?})", - self.upcast_trait_ref, self.vtable_vptr_slot, self.nested - ) - } -} - -impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "ImplSourceAutoImplData(trait_def_id={:?}, nested={:?})", - self.trait_def_id, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<'tcx, N> { +impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "ImplSourceObjectData(upcast={:?}, vtable_base={}, nested={:?})", - self.upcast_trait_ref, self.vtable_base, self.nested + "ImplSourceTraitUpcastingData(vtable_vptr_slot={:?}, nested={:?})", + self.vtable_vptr_slot, self.nested ) } } -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceFnPointerData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ImplSourceFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, N> { +impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "ImplSourceTraitAliasData(alias_def_id={:?}, substs={:?}, nested={:?})", - self.alias_def_id, self.substs, self.nested + "ImplSourceObjectData(vtable_base={}, nested={:?})", + self.vtable_base, self.nested ) } } - -impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDestructData<N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ImplSourceConstDestructData(nested={:?})", self.nested) - } -} diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index d54b8c599..05c06efaf 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -25,9 +25,7 @@ impl<'tcx> Elaborator<'tcx> { .super_predicates_of(trait_ref.def_id()) .predicates .into_iter() - .flat_map(|(pred, _)| { - pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_pred() - }) + .flat_map(|(pred, _)| pred.subst_supertrait(self.tcx, &trait_ref).as_trait_clause()) .map(|t| t.map_bound(|pred| pred.trait_ref)) .filter(|supertrait_ref| self.visited.insert(*supertrait_ref)); diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index cbc68fde9..09517200b 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { Err(TypeError::Sorts(relate::expected_found(self, a, b))) } - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(self.tcx().ty_error(guar)), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)), _ => relate::structurally_relate_tys(self, a, b), } diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index a39631da9..ffee7ba28 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -53,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> { fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> { let ct = match c.kind() { ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) { - Err(e) => self.tcx.const_error(c.ty(), e), + Err(e) => ty::Const::new_error(self.tcx, e, c.ty()), Ok(Some(bac)) => { let substs = self.tcx.erase_regions(uv.substs); let bac = bac.subst(self.tcx, substs); diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index cd0f7e8da..76931ceaa 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -6,7 +6,7 @@ use rustc_span::Span; use rustc_target::abi::FieldIdx; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum PointerCast { +pub enum PointerCoercion { /// Go from a fn-item type to a fn-pointer type. ReifyFnPointer, @@ -99,7 +99,7 @@ pub enum Adjust<'tcx> { /// Take the address and produce either a `&` or `*` pointer. Borrow(AutoBorrow<'tcx>), - Pointer(PointerCast), + Pointer(PointerCoercion), /// Cast into a dyn* object. DynStar, @@ -132,7 +132,7 @@ impl<'tcx> OverloadedDeref<'tcx> { .find(|m| m.kind == ty::AssocKind::Fn) .unwrap() .def_id; - tcx.mk_fn_def(method_def_id, [source]) + Ty::new_fn_def(tcx, method_def_id, [source]) } } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 7c5c030c2..e067d2a98 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -573,7 +573,7 @@ impl<'tcx> AdtDef<'tcx> { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer (e.g., issue #31299). pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> { - ty::EarlyBinder(tcx.adt_sized_constraint(self.did())) + ty::EarlyBinder::bind(tcx.adt_sized_constraint(self.did())) } } diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 090b76932..cce609c26 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -48,7 +48,7 @@ impl AssocItem { /// /// [`type_of`]: crate::ty::TyCtxt::type_of pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness { - tcx.impl_defaultness(self.def_id) + tcx.defaultness(self.def_id) } #[inline] diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index be7b2b7ec..bc9273745 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -427,6 +427,8 @@ pub enum BorrowKind { /// immutable, but not aliasable. This solves the problem. For /// simplicity, we don't give users the way to express this /// borrow, it's just used when translating closures. + /// + /// FIXME: Rename this to indicate the borrow is actually not immutable. UniqueImmBorrow, /// Data is mutable and not aliasable. diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 7fc75674d..6adbb44a1 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -128,6 +128,12 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Predicate<'tcx> } } +impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Clause<'tcx> { + fn encode(&self, e: &mut E) { + self.as_predicate().encode(e); + } +} + impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Region<'tcx> { fn encode(&self, e: &mut E) { self.kind().encode(e); @@ -241,6 +247,13 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Clause<'tcx> { + fn decode(decoder: &mut D) -> ty::Clause<'tcx> { + let pred: ty::Predicate<'tcx> = Decodable::decode(decoder); + pred.expect_clause() + } +} + impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for SubstsRef<'tcx> { fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); @@ -264,7 +277,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for mir::Place<'tcx> { impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Region<'tcx> { fn decode(decoder: &mut D) -> Self { - decoder.interner().mk_region_from_kind(Decodable::decode(decoder)) + ty::Region::new_from_kind(decoder.interner(), Decodable::decode(decoder)) } } @@ -331,7 +344,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> { fn decode(decoder: &mut D) -> Self { let consts: ty::ConstData<'tcx> = Decodable::decode(decoder); - decoder.interner().mk_const(consts.kind, consts.ty) + decoder.interner().mk_ct_from_kind(consts.kind, consts.ty) } } @@ -355,16 +368,6 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AdtDef<'tcx> { } } -impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> - for [(ty::Predicate<'tcx>, Span)] -{ - fn decode(decoder: &mut D) -> &'tcx Self { - decoder.interner().arena.alloc_from_iter( - (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(), - ) - } -} - impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] { fn decode(decoder: &mut D) -> &'tcx Self { decoder.interner().arena.alloc_from_iter( @@ -393,11 +396,11 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty } } -impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Predicate<'tcx>> { +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Clause<'tcx>> { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); - decoder.interner().mk_predicates_from_iter( - (0..len).map::<ty::Predicate<'tcx>, _>(|_| Decodable::decode(decoder)), + decoder.interner().mk_clauses_from_iter( + (0..len).map::<ty::Clause<'tcx>, _>(|_| Decodable::decode(decoder)), ) } } @@ -421,7 +424,7 @@ impl_decodable_via_ref! { &'tcx mir::BorrowCheckResult<'tcx>, &'tcx mir::coverage::CodeRegion, &'tcx ty::List<ty::BoundVariableKind>, - &'tcx ty::List<ty::Predicate<'tcx>>, + &'tcx ty::List<ty::Clause<'tcx>>, &'tcx ty::List<FieldIdx>, } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 1a4bd1481..1cbfe99f8 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,7 +1,8 @@ use crate::middle::resolve_bound_vars as rbv; -use crate::mir::interpret::LitToConstInput; -use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; +use crate::mir::interpret::{AllocId, ConstValue, LitToConstInput, Scalar}; +use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_data_structures::intern::Interned; +use rustc_error_messages::MultiSpan; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; @@ -13,8 +14,13 @@ mod valtree; pub use int::*; pub use kind::*; +use rustc_span::ErrorGuaranteed; +use rustc_span::DUMMY_SP; +use rustc_target::abi::Size; pub use valtree::*; +use super::sty::ConstKind; + /// Use this rather than `ConstData`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] @@ -30,6 +36,16 @@ pub struct ConstData<'tcx> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ConstData<'_>, 40); +enum EvalMode { + Typeck, + Mir, +} + +enum EvalResult<'tcx> { + ValTree(ty::ValTree<'tcx>), + ConstVal(ConstValue<'tcx>), +} + impl<'tcx> Const<'tcx> { #[inline] pub fn ty(self) -> Ty<'tcx> { @@ -38,7 +54,98 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn kind(self) -> ConstKind<'tcx> { - self.0.kind + self.0.kind.clone() + } + + #[inline] + pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + tcx.mk_ct_from_kind(kind, ty) + } + + #[inline] + pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Param(param), ty) + } + + #[inline] + pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty) + } + + #[inline] + pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)), ty) + } + + #[inline] + pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(infer), ty) + } + + #[inline] + pub fn new_bound( + tcx: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + var: ty::BoundVar, + ty: Ty<'tcx>, + ) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Bound(debruijn, var), ty) + } + + #[inline] + pub fn new_placeholder( + tcx: TyCtxt<'tcx>, + placeholder: ty::PlaceholderConst<'tcx>, + ty: Ty<'tcx>, + ) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Placeholder(placeholder), ty) + } + + #[inline] + pub fn new_unevaluated( + tcx: TyCtxt<'tcx>, + uv: ty::UnevaluatedConst<'tcx>, + ty: Ty<'tcx>, + ) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Unevaluated(uv), ty) + } + + #[inline] + pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Value(val), ty) + } + + #[inline] + pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Expr(expr), ty) + } + + #[inline] + pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Error(e), ty) + } + + /// Like [Ty::new_error] but for constants. + #[track_caller] + pub fn new_misc_error(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new_error_with_message( + tcx, + ty, + DUMMY_SP, + "ty::ConstKind::Error constructed but no error reported", + ) + } + + /// Like [Ty::new_error_with_message] but for constants. + #[track_caller] + pub fn new_error_with_message<S: Into<MultiSpan>>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + span: S, + msg: &'static str, + ) -> Const<'tcx> { + let reported = tcx.sess.delay_span_bug(span, msg); + Const::new_error(tcx, reported, ty) } /// Literals and const generic parameters are eagerly converted to a constant, everything else @@ -60,7 +167,8 @@ impl<'tcx> Const<'tcx> { match Self::try_eval_lit_or_param(tcx, ty, expr) { Some(v) => v, - None => tcx.mk_const( + None => ty::Const::new_unevaluated( + tcx, ty::UnevaluatedConst { def: def.to_def_id(), substs: InternalSubsts::identity_for_item(tcx, def.to_def_id()), @@ -126,13 +234,19 @@ impl<'tcx> Const<'tcx> { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - Some(tcx.mk_const(ty::ParamConst::new(index, name), param_ty)) + Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty)) + } + Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { + Some(ty::Const::new_bound( + tcx, + debruijn, + ty::BoundVar::from_u32(index), + param_ty, + )) + } + Some(rbv::ResolvedArg::Error(guar)) => { + Some(ty::Const::new_error(tcx, guar, param_ty)) } - Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => Some(tcx.mk_const( - ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)), - param_ty, - )), - Some(rbv::ResolvedArg::Error(guar)) => Some(tcx.const_error(param_ty, guar)), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), } } @@ -155,7 +269,8 @@ impl<'tcx> Const<'tcx> { .layout_of(ty) .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) .size; - tcx.mk_const( + ty::Const::new_value( + tcx, ty::ValTree::from_scalar_int(ScalarInt::try_from_uint(bits, size).unwrap()), ty.value, ) @@ -164,7 +279,7 @@ impl<'tcx> Const<'tcx> { #[inline] /// Creates an interned zst constant. pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self { - tcx.mk_const(ty::ValTree::zst(), ty) + ty::Const::new_value(tcx, ty::ValTree::zst(), ty) } #[inline] @@ -192,12 +307,12 @@ impl<'tcx> Const<'tcx> { assert_eq!(self.ty(), ty); let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; // if `ty` does not depend on generic parameters, use an empty param_env - self.kind().eval(tcx, param_env).try_to_bits(size) + self.eval(tcx, param_env).try_to_bits(size) } #[inline] pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { - self.kind().eval(tcx, param_env).try_to_bool() + self.eval(tcx, param_env).try_to_bool() } #[inline] @@ -206,17 +321,17 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ) -> Option<u64> { - self.kind().eval(tcx, param_env).try_to_target_usize(tcx) + self.eval(tcx, param_env).try_to_target_usize(tcx) } #[inline] /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the /// unevaluated constant. pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> { - if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) { + if let Some(val) = self.try_eval_for_typeck(tcx, param_env) { match val { - Ok(val) => tcx.mk_const(val, self.ty()), - Err(guar) => tcx.const_error(self.ty(), guar), + Ok(val) => ty::Const::new_value(tcx, val, self.ty()), + Err(guar) => ty::Const::new_error(tcx, guar, self.ty()), } } else { // Either the constant isn't evaluatable or ValTree creation failed. @@ -238,6 +353,138 @@ impl<'tcx> Const<'tcx> { .unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) } + #[inline] + /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary + /// return `None`. + // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. + pub fn try_eval_for_mir( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> { + match self.try_eval_inner(tcx, param_env, EvalMode::Mir) { + Some(Ok(EvalResult::ValTree(_))) => unreachable!(), + Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)), + Some(Err(e)) => Some(Err(e)), + None => None, + } + } + + #[inline] + /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary + /// return `None`. + // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. + pub fn try_eval_for_typeck( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> { + match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) { + Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)), + Some(Ok(EvalResult::ConstVal(_))) => unreachable!(), + Some(Err(e)) => Some(Err(e)), + None => None, + } + } + + #[inline] + fn try_eval_inner( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + eval_mode: EvalMode, + ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> { + assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); + if let ConstKind::Unevaluated(unevaluated) = self.kind() { + use crate::mir::interpret::ErrorHandled; + + // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` + // also does later, but we want to do it before checking for + // inference variables. + // Note that we erase regions *before* calling `with_reveal_all_normalized`, + // so that we don't try to invoke this query with + // any region variables. + + // HACK(eddyb) when the query key would contain inference variables, + // attempt using identity substs and `ParamEnv` instead, that will succeed + // when the expression doesn't depend on any parameters. + // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that + // we can call `infcx.const_eval_resolve` which handles inference variables. + let param_env_and = if (param_env, unevaluated).has_non_region_infer() { + tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst { + def: unevaluated.def, + substs: InternalSubsts::identity_for_item(tcx, unevaluated.def), + }) + } else { + tcx.erase_regions(param_env) + .with_reveal_all_normalized(tcx) + .and(tcx.erase_regions(unevaluated)) + }; + + // FIXME(eddyb) maybe the `const_eval_*` methods should take + // `ty::ParamEnvAnd` instead of having them separate. + let (param_env, unevaluated) = param_env_and.into_parts(); + // try to resolve e.g. associated constants to their definition on an impl, and then + // evaluate the const. + match eval_mode { + EvalMode::Typeck => { + match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) { + // NOTE(eddyb) `val` contains no lifetimes/types/consts, + // and we use the original type, so nothing from `substs` + // (which may be identity substs, see above), + // can leak through `val` into the const we return. + Ok(val) => Some(Ok(EvalResult::ValTree(val?))), + Err(ErrorHandled::TooGeneric) => None, + Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), + } + } + EvalMode::Mir => { + match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) { + // NOTE(eddyb) `val` contains no lifetimes/types/consts, + // and we use the original type, so nothing from `substs` + // (which may be identity substs, see above), + // can leak through `val` into the const we return. + Ok(val) => Some(Ok(EvalResult::ConstVal(val))), + Err(ErrorHandled::TooGeneric) => None, + Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), + } + } + } + } else { + None + } + } + + #[inline] + pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> { + if let ConstKind::Value(val) = self.kind() { Some(val) } else { None } + } + + #[inline] + pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { + self.try_to_value()?.try_to_scalar() + } + + #[inline] + pub fn try_to_scalar_int(self) -> Option<ScalarInt> { + self.try_to_value()?.try_to_scalar_int() + } + + #[inline] + pub fn try_to_bits(self, size: Size) -> Option<u128> { + self.try_to_scalar_int()?.to_bits(size).ok() + } + + #[inline] + pub fn try_to_bool(self) -> Option<bool> { + self.try_to_scalar_int()?.try_into().ok() + } + + #[inline] + pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { + self.try_to_value()?.try_to_target_usize(tcx) + } + pub fn is_ct_infer(self) -> bool { matches!(self.kind(), ty::ConstKind::Infer(_)) } @@ -254,5 +501,5 @@ pub fn const_param_default(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBind "`const_param_default` expected a generic parameter with a constant" ), }; - ty::EarlyBinder(Const::from_anon_const(tcx, default_def_id)) + ty::EarlyBinder::bind(Const::from_anon_const(tcx, default_def_id)) } diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index d1dbc531e..1e43fab45 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -1,5 +1,6 @@ use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_target::abi::Size; use std::fmt; @@ -113,6 +114,14 @@ impl std::fmt::Debug for ConstInt { } } +impl IntoDiagnosticArg for ConstInt { + // FIXME this simply uses the Debug impl, but we could probably do better by converting both + // to an inherent method that returns `Cow`. + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(format!("{self:?}").into()) + } +} + /// The raw bytes of a simple value. /// /// This is a packed struct in order to allow this type to be optimally embedded in enums diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 1dd4f8a24..a6bf74911 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,17 +1,11 @@ use super::Const; use crate::mir; -use crate::mir::interpret::{AllocId, ConstValue, Scalar}; use crate::ty::abstract_const::CastKind; -use crate::ty::subst::{InternalSubsts, SubstsRef}; -use crate::ty::ParamEnv; -use crate::ty::{self, List, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::subst::SubstsRef; +use crate::ty::{self, List, Ty}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; -use rustc_target::abi::Size; - -use super::ScalarInt; /// An unevaluated (potentially generic) constant used in the type-system. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] @@ -41,45 +35,6 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -/// Represents a constant in Rust. -#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] -#[derive(derive_more::From)] -pub enum ConstKind<'tcx> { - /// A const generic parameter. - Param(ty::ParamConst), - - /// Infer the value of the const. - Infer(InferConst<'tcx>), - - /// Bound const variable, used only when preparing a trait query. - Bound(ty::DebruijnIndex, ty::BoundVar), - - /// A placeholder const - universally quantified higher-ranked const. - Placeholder(ty::PlaceholderConst<'tcx>), - - /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other - /// variants when the code is monomorphic enough for that. - Unevaluated(UnevaluatedConst<'tcx>), - - /// Used to hold computed value. - Value(ty::ValTree<'tcx>), - - /// A placeholder for a const which could not be computed; this is - /// propagated to avoid useless error messages. - #[from(ignore)] - Error(ErrorGuaranteed), - - /// Expr which contains an expression which has partially evaluated items. - Expr(Expr<'tcx>), -} - -impl<'tcx> From<ty::ConstVid<'tcx>> for ConstKind<'tcx> { - fn from(const_vid: ty::ConstVid<'tcx>) -> Self { - InferConst::Var(const_vid).into() - } -} - #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum Expr<'tcx> { @@ -93,39 +48,7 @@ pub enum Expr<'tcx> { static_assert_size!(Expr<'_>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ConstKind<'_>, 32); - -impl<'tcx> ConstKind<'tcx> { - #[inline] - pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> { - if let ConstKind::Value(val) = self { Some(val) } else { None } - } - - #[inline] - pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { - self.try_to_value()?.try_to_scalar() - } - - #[inline] - pub fn try_to_scalar_int(self) -> Option<ScalarInt> { - self.try_to_value()?.try_to_scalar_int() - } - - #[inline] - pub fn try_to_bits(self, size: Size) -> Option<u128> { - self.try_to_scalar_int()?.to_bits(size).ok() - } - - #[inline] - pub fn try_to_bool(self) -> Option<bool> { - self.try_to_scalar_int()?.try_into().ok() - } - - #[inline] - pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { - self.try_to_value()?.try_to_target_usize(tcx) - } -} +static_assert_size!(super::ConstKind<'_>, 32); /// An inference variable for a const, for use in const generics. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] @@ -144,124 +67,3 @@ impl<CTX> HashStable<CTX> for InferConst<'_> { } } } - -enum EvalMode { - Typeck, - Mir, -} - -enum EvalResult<'tcx> { - ValTree(ty::ValTree<'tcx>), - ConstVal(ConstValue<'tcx>), -} - -impl<'tcx> ConstKind<'tcx> { - #[inline] - /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the - /// unevaluated constant. - pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { - self.try_eval_for_typeck(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value) - } - - #[inline] - /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary - /// return `None`. - // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. - pub fn try_eval_for_mir( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> { - match self.try_eval_inner(tcx, param_env, EvalMode::Mir) { - Some(Ok(EvalResult::ValTree(_))) => unreachable!(), - Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)), - Some(Err(e)) => Some(Err(e)), - None => None, - } - } - - #[inline] - /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary - /// return `None`. - // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged. - pub fn try_eval_for_typeck( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> { - match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) { - Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)), - Some(Ok(EvalResult::ConstVal(_))) => unreachable!(), - Some(Err(e)) => Some(Err(e)), - None => None, - } - } - - #[inline] - fn try_eval_inner( - self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - eval_mode: EvalMode, - ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> { - assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); - if let ConstKind::Unevaluated(unevaluated) = self { - use crate::mir::interpret::ErrorHandled; - - // HACK(eddyb) this erases lifetimes even though `const_eval_resolve` - // also does later, but we want to do it before checking for - // inference variables. - // Note that we erase regions *before* calling `with_reveal_all_normalized`, - // so that we don't try to invoke this query with - // any region variables. - - // HACK(eddyb) when the query key would contain inference variables, - // attempt using identity substs and `ParamEnv` instead, that will succeed - // when the expression doesn't depend on any parameters. - // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that - // we can call `infcx.const_eval_resolve` which handles inference variables. - let param_env_and = if (param_env, unevaluated).has_non_region_infer() { - tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst { - def: unevaluated.def, - substs: InternalSubsts::identity_for_item(tcx, unevaluated.def), - }) - } else { - tcx.erase_regions(param_env) - .with_reveal_all_normalized(tcx) - .and(tcx.erase_regions(unevaluated)) - }; - - // FIXME(eddyb) maybe the `const_eval_*` methods should take - // `ty::ParamEnvAnd` instead of having them separate. - let (param_env, unevaluated) = param_env_and.into_parts(); - // try to resolve e.g. associated constants to their definition on an impl, and then - // evaluate the const. - match eval_mode { - EvalMode::Typeck => { - match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) { - // NOTE(eddyb) `val` contains no lifetimes/types/consts, - // and we use the original type, so nothing from `substs` - // (which may be identity substs, see above), - // can leak through `val` into the const we return. - Ok(val) => Some(Ok(EvalResult::ValTree(val?))), - Err(ErrorHandled::TooGeneric) => None, - Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), - } - } - EvalMode::Mir => { - match tcx.const_eval_resolve(param_env, unevaluated.expand(), None) { - // NOTE(eddyb) `val` contains no lifetimes/types/consts, - // and we use the original type, so nothing from `substs` - // (which may be identity substs, see above), - // can leak through `val` into the const we return. - Ok(val) => Some(Ok(EvalResult::ConstVal(val))), - Err(ErrorHandled::TooGeneric) => None, - Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), - } - } - } - } else { - None - } - } -} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2bde55bc4..035e978f6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -25,10 +25,10 @@ use crate::traits::solve::{ ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, }; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid, - GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, - PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, - TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind, + ImplPolarity, InferTy, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, + Predicate, PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, + TyVid, TypeAndMut, Visibility, }; use crate::ty::{GenericArg, InternalSubsts, SubstsRef}; use rustc_ast::{self as ast, attr}; @@ -70,10 +70,9 @@ use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx} use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; -use rustc_type_ir::{CollectAndApply, DynKind, Interner, TypeFlags}; +use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; use std::any::Any; -use std::assert_matches::debug_assert_matches; use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt; @@ -82,8 +81,6 @@ use std::iter; use std::mem; use std::ops::{Bound, Deref}; -const TINY_CONST_EVAL_LIMIT: Limit = Limit(20); - #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Interner for TyCtxt<'tcx> { type AdtDef = ty::AdtDef<'tcx>; @@ -110,11 +107,29 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type PredicateKind = ty::PredicateKind<'tcx>; type AllocId = crate::mir::interpret::AllocId; + type InferConst = ty::InferConst<'tcx>; + type AliasConst = ty::UnevaluatedConst<'tcx>; + type ParamConst = ty::ParamConst; + type BoundConst = ty::BoundVar; + type PlaceholderConst = ty::PlaceholderConst<'tcx>; + type ValueConst = ty::ValTree<'tcx>; + type ExprConst = ty::Expr<'tcx>; + type EarlyBoundRegion = ty::EarlyBoundRegion; type BoundRegion = ty::BoundRegion; type FreeRegion = ty::FreeRegion; type RegionVid = ty::RegionVid; type PlaceholderRegion = ty::PlaceholderRegion; + + fn ty_and_mut_to_parts( + TypeAndMut { ty, mutbl }: TypeAndMut<'tcx>, + ) -> (Self::Ty, Self::Mutability) { + (ty, mutbl) + } + + fn mutability_is_mut(mutbl: Self::Mutability) -> bool { + mutbl.is_mut() + } } type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; @@ -133,7 +148,7 @@ pub struct CtxtInterners<'tcx> { region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>, predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>, - predicates: InternedSet<'tcx, List<Predicate<'tcx>>>, + clauses: InternedSet<'tcx, List<Clause<'tcx>>>, projs: InternedSet<'tcx, List<ProjectionKind>>, place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, const_: InternedSet<'tcx, ConstData<'tcx>>, @@ -158,7 +173,7 @@ impl<'tcx> CtxtInterners<'tcx> { poly_existential_predicates: Default::default(), canonical_var_infos: Default::default(), predicate: Default::default(), - predicates: Default::default(), + clauses: Default::default(), projs: Default::default(), place_elems: Default::default(), const_: Default::default(), @@ -312,6 +327,8 @@ pub struct CommonLifetimes<'tcx> { pub struct CommonConsts<'tcx> { pub unit: Const<'tcx>, + pub true_: Const<'tcx>, + pub false_: Const<'tcx>, } impl<'tcx> CommonTypes<'tcx> { @@ -409,6 +426,14 @@ impl<'tcx> CommonConsts<'tcx> { kind: ty::ConstKind::Value(ty::ValTree::zst()), ty: types.unit, }), + true_: mk_const(ty::ConstData { + kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::TRUE)), + ty: types.bool, + }), + false_: mk_const(ty::ConstData { + kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::FALSE)), + ty: types.bool, + }), } } } @@ -470,6 +495,17 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { /// [rustc dev guide] for more details. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/ty.html +/// +/// An implementation detail: `TyCtxt` is a wrapper type for [GlobalCtxt], +/// which is the struct that actually holds all the data. `TyCtxt` derefs to +/// `GlobalCtxt`, and in practice `TyCtxt` is passed around everywhere, and all +/// operations are done via `TyCtxt`. A `TyCtxt` is obtained for a `GlobalCtxt` +/// by calling `enter` with a closure `f`. That function creates both the +/// `TyCtxt`, and an `ImplicitCtxt` around it that is put into TLS. Within `f`: +/// - The `ImplicitCtxt` is available implicitly via TLS. +/// - The `TyCtxt` is available explicitly via the `tcx` parameter, and also +/// implicitly within the `ImplicitCtxt`. Explicit access is preferred when +/// possible. #[derive(Copy, Clone)] #[rustc_diagnostic_item = "TyCtxt"] #[rustc_pass_by_value] @@ -485,6 +521,7 @@ impl<'tcx> Deref for TyCtxt<'tcx> { } } +/// See [TyCtxt] for details about this type. pub struct GlobalCtxt<'tcx> { pub arena: &'tcx WorkerLocal<Arena<'tcx>>, pub hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>, @@ -689,82 +726,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed` - #[track_caller] - pub fn ty_error(self, reported: ErrorGuaranteed) -> Ty<'tcx> { - self.mk_ty_from_kind(Error(reported)) - } - - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. - #[track_caller] - pub fn ty_error_misc(self) -> Ty<'tcx> { - self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported") - } - - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to - /// ensure it gets used. - #[track_caller] - pub fn ty_error_with_message<S: Into<MultiSpan>>( - self, - span: S, - msg: impl Into<DiagnosticMessage>, - ) -> Ty<'tcx> { - let reported = self.sess.delay_span_bug(span, msg); - self.mk_ty_from_kind(Error(reported)) - } - - /// Constructs a `RegionKind::ReError` lifetime. - #[track_caller] - pub fn mk_re_error(self, reported: ErrorGuaranteed) -> Region<'tcx> { - self.intern_region(ty::ReError(reported)) - } - - /// Constructs a `RegionKind::ReError` lifetime and registers a `delay_span_bug` to ensure it - /// gets used. - #[track_caller] - pub fn mk_re_error_misc(self) -> Region<'tcx> { - self.mk_re_error_with_message( - DUMMY_SP, - "RegionKind::ReError constructed but no error reported", - ) - } - - /// Constructs a `RegionKind::ReError` lifetime and registers a `delay_span_bug` with the given - /// `msg` to ensure it gets used. - #[track_caller] - pub fn mk_re_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Region<'tcx> { - let reported = self.sess.delay_span_bug(span, msg); - self.mk_re_error(reported) - } - - /// Like [TyCtxt::ty_error] but for constants, with current `ErrorGuaranteed` - #[track_caller] - pub fn const_error(self, ty: Ty<'tcx>, reported: ErrorGuaranteed) -> Const<'tcx> { - self.mk_const(ty::ConstKind::Error(reported), ty) - } - - /// Like [TyCtxt::ty_error] but for constants. - #[track_caller] - pub fn const_error_misc(self, ty: Ty<'tcx>) -> Const<'tcx> { - self.const_error_with_message( - ty, - DUMMY_SP, - "ty::ConstKind::Error constructed but no error reported", - ) - } - - /// Like [TyCtxt::ty_error_with_message] but for constants. - #[track_caller] - pub fn const_error_with_message<S: Into<MultiSpan>>( - self, - ty: Ty<'tcx>, - span: S, - msg: &str, - ) -> Const<'tcx> { - let reported = self.sess.delay_span_bug(span, msg); - self.mk_const(ty::ConstKind::Error(reported), ty) - } - pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool { self.sess.consider_optimizing(|| self.crate_name(LOCAL_CRATE), msg) } @@ -1019,15 +980,6 @@ impl<'tcx> TyCtxt<'tcx> { self.query_system.on_disk_cache.as_ref().map_or(Ok(0), |c| c.serialize(self, encoder)) } - /// If `true`, we should use lazy normalization for constants, otherwise - /// we still evaluate them eagerly. - #[inline] - pub fn lazy_normalization(self) -> bool { - let features = self.features(); - // Note: We only use lazy normalization for generic const expressions. - features.generic_const_exprs - } - #[inline] pub fn local_crate_exports_generics(self) -> bool { debug_assert!(self.sess.opts.share_generics()); @@ -1167,7 +1119,8 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns `&'static core::panic::Location<'static>`. pub fn caller_location_ty(self) -> Ty<'tcx> { - self.mk_imm_ref( + Ty::new_imm_ref( + self, self.lifetimes.re_static, self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) .subst(self, self.mk_substs(&[self.lifetimes.re_static.into()])), @@ -1192,14 +1145,6 @@ impl<'tcx> TyCtxt<'tcx> { self.limits(()).move_size_limit } - pub fn const_eval_limit(self) -> Limit { - if self.sess.opts.unstable_opts.tiny_const_eval_limit { - TINY_CONST_EVAL_LIMIT - } else { - self.limits(()).const_eval_limit - } - } - pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx { iter::once(LOCAL_CRATE) .chain(self.crates(()).iter().copied()) @@ -1210,6 +1155,12 @@ impl<'tcx> TyCtxt<'tcx> { pub fn local_visibility(self, def_id: LocalDefId) -> Visibility { self.visibility(def_id).expect_local() } + + /// Returns the origin of the opaque type `def_id`. + #[instrument(skip(self), level = "trace", ret)] + pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { + self.hir().expect_item(def_id).expect_opaque_ty().origin + } } /// A trait implemented for all `X<'a>` types that can be safely and @@ -1272,10 +1223,11 @@ nop_lift! {region; Region<'a> => Region<'tcx>} nop_lift! {const_; Const<'a> => Const<'tcx>} nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>} nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} +nop_lift! {predicate; Clause<'a> => Clause<'tcx>} nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>} nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>} -nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>} +nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>} nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>} nop_list_lift! {projs; ProjectionKind => ProjectionKind} nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind} @@ -1515,9 +1467,9 @@ macro_rules! direct_interners { // Functions with a `mk_` prefix are intended for use outside this file and // crate. Functions with an `intern_` prefix are intended for use within this -// file only, and have a corresponding `mk_` function. +// crate only, and have a corresponding `mk_` function. direct_interners! { - region: intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, + region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, const_: intern_const(ConstData<'tcx>): Const -> Const<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutS): Layout -> Layout<'tcx>, @@ -1553,7 +1505,7 @@ slice_interners!( type_lists: pub mk_type_list(Ty<'tcx>), canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>), poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>), - predicates: intern_predicates(Predicate<'tcx>), + clauses: intern_clauses(Clause<'tcx>), projs: pub mk_projs(ProjectionKind), place_elems: pub mk_place_elems(PlaceElem<'tcx>), bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), @@ -1566,7 +1518,10 @@ impl<'tcx> TyCtxt<'tcx> { /// unsafe. pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> { assert_eq!(sig.unsafety(), hir::Unsafety::Normal); - self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig })) + Ty::new_fn_ptr( + self, + sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }), + ) } /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` @@ -1585,7 +1540,7 @@ impl<'tcx> TyCtxt<'tcx> { let future_trait = self.require_lang_item(LangItem::Future, None); self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { - let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() else { + let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { return false; }; trait_predicate.trait_ref.def_id == future_trait @@ -1608,9 +1563,7 @@ impl<'tcx> TyCtxt<'tcx> { let generic_predicates = self.super_predicates_of(trait_did); for (predicate, _) in generic_predicates.predicates { - if let ty::PredicateKind::Clause(ty::Clause::Trait(data)) = - predicate.kind().skip_binder() - { + if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() { if set.insert(data.def_id()) { stack.push(data.def_id()); } @@ -1642,18 +1595,6 @@ impl<'tcx> TyCtxt<'tcx> { }) } - // Avoid this in favour of more specific `mk_*` methods, where possible. - #[allow(rustc::usage_of_ty_tykind)] - #[inline] - pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> { - self.interners.intern_ty( - st, - self.sess, - // This is only used to create a stable hashing context. - &self.untracked, - ) - } - #[inline] pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { self.interners.intern_predicate( @@ -1673,174 +1614,6 @@ impl<'tcx> TyCtxt<'tcx> { if pred.kind() != binder { self.mk_predicate(binder) } else { pred } } - pub fn mk_mach_int(self, tm: IntTy) -> Ty<'tcx> { - match tm { - IntTy::Isize => self.types.isize, - IntTy::I8 => self.types.i8, - IntTy::I16 => self.types.i16, - IntTy::I32 => self.types.i32, - IntTy::I64 => self.types.i64, - IntTy::I128 => self.types.i128, - } - } - - pub fn mk_mach_uint(self, tm: UintTy) -> Ty<'tcx> { - match tm { - UintTy::Usize => self.types.usize, - UintTy::U8 => self.types.u8, - UintTy::U16 => self.types.u16, - UintTy::U32 => self.types.u32, - UintTy::U64 => self.types.u64, - UintTy::U128 => self.types.u128, - } - } - - pub fn mk_mach_float(self, tm: FloatTy) -> Ty<'tcx> { - match tm { - FloatTy::F32 => self.types.f32, - FloatTy::F64 => self.types.f64, - } - } - - #[inline] - pub fn mk_static_str(self) -> Ty<'tcx> { - self.mk_imm_ref(self.lifetimes.re_static, self.types.str_) - } - - #[inline] - pub fn mk_adt(self, def: AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - // Take a copy of substs so that we own the vectors inside. - self.mk_ty_from_kind(Adt(def, substs)) - } - - #[inline] - pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> { - self.mk_ty_from_kind(Foreign(def_id)) - } - - fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> { - let adt_def = self.adt_def(wrapper_def_id); - let substs = - InternalSubsts::for_item(self, wrapper_def_id, |param, substs| match param.kind { - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => bug!(), - GenericParamDefKind::Type { has_default, .. } => { - if param.index == 0 { - ty_param.into() - } else { - assert!(has_default); - self.type_of(param.def_id).subst(self, substs).into() - } - } - }); - self.mk_ty_from_kind(Adt(adt_def, substs)) - } - - #[inline] - pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(LangItem::OwnedBox, None); - self.mk_generic_adt(def_id, ty) - } - - #[inline] - pub fn mk_lang_item(self, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> { - let def_id = self.lang_items().get(item)?; - Some(self.mk_generic_adt(def_id, ty)) - } - - #[inline] - pub fn mk_diagnostic_item(self, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> { - let def_id = self.get_diagnostic_item(name)?; - Some(self.mk_generic_adt(def_id, ty)) - } - - #[inline] - pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(LangItem::MaybeUninit, None); - self.mk_generic_adt(def_id, ty) - } - - #[inline] - pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(RawPtr(tm)) - } - - #[inline] - pub fn mk_ref(self, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(Ref(r, tm.ty, tm.mutbl)) - } - - #[inline] - pub fn mk_mut_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut { ty, mutbl: hir::Mutability::Mut }) - } - - #[inline] - pub fn mk_imm_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut { ty, mutbl: hir::Mutability::Not }) - } - - #[inline] - pub fn mk_mut_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Mut }) - } - - #[inline] - pub fn mk_imm_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Not }) - } - - #[inline] - pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty_from_kind(Array(ty, ty::Const::from_target_usize(self, n))) - } - - #[inline] - pub fn mk_array_with_const_len(self, ty: Ty<'tcx>, ct: Const<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(Array(ty, ct)) - } - - #[inline] - pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(Slice(ty)) - } - - #[inline] - pub fn mk_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> { - if ts.is_empty() { - self.types.unit - } else { - self.mk_ty_from_kind(Tuple(self.mk_type_list(&ts))) - } - } - - pub fn mk_tup_from_iter<I, T>(self, iter: I) -> T::Output - where - I: Iterator<Item = T>, - T: CollectAndApply<Ty<'tcx>, Ty<'tcx>>, - { - T::collect_and_apply(iter, |ts| self.mk_tup(ts)) - } - - #[inline] - pub fn mk_unit(self) -> Ty<'tcx> { - self.types.unit - } - - #[inline] - pub fn mk_diverging_default(self) -> Ty<'tcx> { - if self.features().never_type_fallback { self.types.never } else { self.types.unit } - } - - #[inline] - pub fn mk_fn_def( - self, - def_id: DefId, - substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, - ) -> Ty<'tcx> { - let substs = self.check_and_mk_substs(def_id, substs); - self.mk_ty_from_kind(FnDef(def_id, substs)) - } - #[inline(always)] pub(crate) fn check_and_mk_substs( self, @@ -1872,222 +1645,36 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(FnPtr(fty)) - } - - #[inline] - pub fn mk_dynamic( - self, - obj: &'tcx List<PolyExistentialPredicate<'tcx>>, - reg: ty::Region<'tcx>, - repr: DynKind, - ) -> Ty<'tcx> { - self.mk_ty_from_kind(Dynamic(obj, reg, repr)) - } - - #[inline] - pub fn mk_projection( - self, - item_def_id: DefId, - substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, - ) -> Ty<'tcx> { - self.mk_alias(ty::Projection, self.mk_alias_ty(item_def_id, substs)) - } - - #[inline] - pub fn mk_closure(self, closure_id: DefId, closure_substs: SubstsRef<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(Closure(closure_id, closure_substs)) - } - - #[inline] - pub fn mk_generator( - self, - id: DefId, - generator_substs: SubstsRef<'tcx>, - movability: hir::Movability, - ) -> Ty<'tcx> { - self.mk_ty_from_kind(Generator(id, generator_substs, movability)) - } - - #[inline] - pub fn mk_generator_witness(self, types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>) -> Ty<'tcx> { - self.mk_ty_from_kind(GeneratorWitness(types)) - } - - /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes. - pub fn mk_task_context(self) -> Ty<'tcx> { - let context_did = self.require_lang_item(LangItem::Context, None); - let context_adt_ref = self.adt_def(context_did); - let context_substs = self.mk_substs(&[self.lifetimes.re_erased.into()]); - let context_ty = self.mk_adt(context_adt_ref, context_substs); - self.mk_mut_ref(self.lifetimes.re_erased, context_ty) - } - - #[inline] - pub fn mk_generator_witness_mir(self, id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - self.mk_ty_from_kind(GeneratorWitnessMIR(id, substs)) - } - - #[inline] - pub fn mk_const(self, kind: impl Into<ty::ConstKind<'tcx>>, ty: Ty<'tcx>) -> Const<'tcx> { - self.intern_const(ty::ConstData { kind: kind.into(), ty }) - } - - #[inline] - pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> { - // Use a pre-interned one when possible. - self.types - .ty_vars - .get(v.as_usize()) - .copied() - .unwrap_or_else(|| self.mk_ty_from_kind(Infer(TyVar(v)))) - } - - #[inline] - pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> { - self.mk_ty_from_kind(Infer(IntVar(v))) - } - - #[inline] - pub fn mk_float_var(self, v: FloatVid) -> Ty<'tcx> { - self.mk_ty_from_kind(Infer(FloatVar(v))) - } - - #[inline] - pub fn mk_fresh_ty(self, n: u32) -> Ty<'tcx> { - // Use a pre-interned one when possible. - self.types - .fresh_tys - .get(n as usize) - .copied() - .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshTy(n)))) - } - - #[inline] - pub fn mk_fresh_int_ty(self, n: u32) -> Ty<'tcx> { - // Use a pre-interned one when possible. - self.types - .fresh_int_tys - .get(n as usize) - .copied() - .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshIntTy(n)))) - } - - #[inline] - pub fn mk_fresh_float_ty(self, n: u32) -> Ty<'tcx> { - // Use a pre-interned one when possible. - self.types - .fresh_float_tys - .get(n as usize) - .copied() - .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshFloatTy(n)))) + pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + self.intern_const(ty::ConstData { kind, ty }) } + // Avoid this in favour of more specific `Ty::new_*` methods, where possible. + #[allow(rustc::usage_of_ty_tykind)] #[inline] - pub fn mk_ty_param(self, index: u32, name: Symbol) -> Ty<'tcx> { - self.mk_ty_from_kind(Param(ParamTy { index, name })) + pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> { + self.interners.intern_ty( + st, + self.sess, + // This is only used to create a stable hashing context. + &self.untracked, + ) } pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { match param.kind { GenericParamDefKind::Lifetime => { - self.mk_re_early_bound(param.to_early_bound_region_data()).into() - } - GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(), - GenericParamDefKind::Const { .. } => self - .mk_const( - ParamConst { index: param.index, name: param.name }, - self.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into(), - } - } - - #[inline] - pub fn mk_bound(self, index: ty::DebruijnIndex, bound_ty: ty::BoundTy) -> Ty<'tcx> { - self.mk_ty_from_kind(Bound(index, bound_ty)) - } - - #[inline] - pub fn mk_placeholder(self, placeholder: ty::PlaceholderType) -> Ty<'tcx> { - self.mk_ty_from_kind(Placeholder(placeholder)) - } - - #[inline] - pub fn mk_alias(self, kind: ty::AliasKind, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> { - debug_assert_matches!( - (kind, self.def_kind(alias_ty.def_id)), - (ty::Opaque, DefKind::OpaqueTy) - | (ty::Projection | ty::Inherent, DefKind::AssocTy) - | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder) - ); - self.mk_ty_from_kind(Alias(kind, alias_ty)) - } - - #[inline] - pub fn mk_opaque(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { - self.mk_alias(ty::Opaque, self.mk_alias_ty(def_id, substs)) - } - - #[inline] - pub fn mk_re_early_bound(self, early_bound_region: ty::EarlyBoundRegion) -> Region<'tcx> { - self.intern_region(ty::ReEarlyBound(early_bound_region)) - } - - #[inline] - pub fn mk_re_late_bound( - self, - debruijn: ty::DebruijnIndex, - bound_region: ty::BoundRegion, - ) -> Region<'tcx> { - // Use a pre-interned one when possible. - if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region - && let Some(inner) = self.lifetimes.re_late_bounds.get(debruijn.as_usize()) - && let Some(re) = inner.get(var.as_usize()).copied() - { - re - } else { - self.intern_region(ty::ReLateBound(debruijn, bound_region)) - } - } - - #[inline] - pub fn mk_re_free(self, scope: DefId, bound_region: ty::BoundRegionKind) -> Region<'tcx> { - self.intern_region(ty::ReFree(ty::FreeRegion { scope, bound_region })) - } - - #[inline] - pub fn mk_re_var(self, v: ty::RegionVid) -> Region<'tcx> { - // Use a pre-interned one when possible. - self.lifetimes - .re_vars - .get(v.as_usize()) - .copied() - .unwrap_or_else(|| self.intern_region(ty::ReVar(v))) - } - - #[inline] - pub fn mk_re_placeholder(self, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { - self.intern_region(ty::RePlaceholder(placeholder)) - } - - // Avoid this in favour of more specific `mk_re_*` methods, where possible, - // to avoid the cost of the `match`. - pub fn mk_region_from_kind(self, kind: ty::RegionKind<'tcx>) -> Region<'tcx> { - match kind { - ty::ReEarlyBound(region) => self.mk_re_early_bound(region), - ty::ReLateBound(debruijn, region) => self.mk_re_late_bound(debruijn, region), - ty::ReFree(ty::FreeRegion { scope, bound_region }) => { - self.mk_re_free(scope, bound_region) + ty::Region::new_early_bound(self, param.to_early_bound_region_data()).into() } - ty::ReStatic => self.lifetimes.re_static, - ty::ReVar(vid) => self.mk_re_var(vid), - ty::RePlaceholder(region) => self.mk_re_placeholder(region), - ty::ReErased => self.lifetimes.re_erased, - ty::ReError(reported) => self.mk_re_error(reported), + GenericParamDefKind::Type { .. } => Ty::new_param(self, param.index, param.name).into(), + GenericParamDefKind::Const { .. } => ty::Const::new_param( + self, + ParamConst { index: param.index, name: param.name }, + self.type_of(param.def_id) + .no_bound_vars() + .expect("const parameter types cannot be generic"), + ) + .into(), } } @@ -2146,11 +1733,11 @@ impl<'tcx> TyCtxt<'tcx> { self.intern_poly_existential_predicates(eps) } - pub fn mk_predicates(self, preds: &[Predicate<'tcx>]) -> &'tcx List<Predicate<'tcx>> { + pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> { // FIXME consider asking the input slice to be sorted to avoid // re-interning permutations, in which case that would be asserted // here. - self.intern_predicates(preds) + self.intern_clauses(clauses) } pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output @@ -2196,12 +1783,12 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_poly_existential_predicates(xs)) } - pub fn mk_predicates_from_iter<I, T>(self, iter: I) -> T::Output + pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, - T: CollectAndApply<Predicate<'tcx>, &'tcx List<Predicate<'tcx>>>, + T: CollectAndApply<Clause<'tcx>, &'tcx List<Clause<'tcx>>>, { - T::collect_and_apply(iter, |xs| self.mk_predicates(xs)) + T::collect_and_apply(iter, |xs| self.mk_clauses(xs)) } pub fn mk_type_list_from_iter<I, T>(self, iter: I) -> T::Output @@ -2403,10 +1990,18 @@ impl<'tcx> TyCtxt<'tcx> { self.opt_local_def_id_to_hir_id(local_def_id).unwrap() } - pub fn trait_solver_next(self) -> bool { + pub fn next_trait_solver_globally(self) -> bool { self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next } + pub fn next_trait_solver_in_coherence(self) -> bool { + matches!( + self.sess.opts.unstable_opts.trait_solver, + rustc_session::config::TraitSolver::Next + | rustc_session::config::TraitSolver::NextCoherence + ) + } + pub fn lower_impl_trait_in_trait_to_assoc_ty(self) -> bool { self.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty } @@ -2433,21 +2028,6 @@ impl<'tcx> TyCtxt<'tcx> { } } -impl<'tcx> TyCtxtAt<'tcx> { - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. - #[track_caller] - pub fn ty_error_misc(self) -> Ty<'tcx> { - self.tcx.ty_error_with_message(self.span, "TyKind::Error constructed but no error reported") - } - - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to - /// ensure it gets used. - #[track_caller] - pub fn ty_error_with_message(self, msg: impl Into<DiagnosticMessage>) -> Ty<'tcx> { - self.tcx.ty_error_with_message(self.span, msg) - } -} - /// Parameter attributes that can only be determined by examining the body of a function instead /// of just its signature. /// diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 6a29063b8..a0b17c374 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -1,5 +1,6 @@ //! Diagnostics related methods for `Ty`. +use std::borrow::Cow; use std::ops::ControlFlow; use crate::ty::{ @@ -13,8 +14,8 @@ use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnostic use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; -use rustc_hir::WherePredicate; -use rustc_span::Span; +use rustc_hir::{PredicateOrigin, WherePredicate}; +use rustc_span::{BytePos, Span}; use rustc_type_ir::sty::TyKind::*; impl<'tcx> IntoDiagnosticArg for Ty<'tcx> { @@ -155,10 +156,11 @@ enum SuggestChangingConstraintsMessage<'a> { RestrictBoundFurther, RestrictType { ty: &'a str }, RestrictTypeFurther { ty: &'a str }, - RemovingQSized, + RemoveMaybeUnsized, + ReplaceMaybeUnsizedWithSized, } -fn suggest_removing_unsized_bound( +fn suggest_changing_unsized_bound( generics: &hir::Generics<'_>, suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>, param: &hir::GenericParam<'_>, @@ -182,12 +184,25 @@ fn suggest_removing_unsized_bound( if poly.trait_ref.trait_def_id() != def_id { continue; } - let sp = generics.span_for_bound_removal(where_pos, pos); - suggestions.push(( - sp, - String::new(), - SuggestChangingConstraintsMessage::RemovingQSized, - )); + if predicate.origin == PredicateOrigin::ImplTrait && predicate.bounds.len() == 1 { + // For `impl ?Sized` with no other bounds, suggest `impl Sized` instead. + let bound_span = bound.span(); + if bound_span.can_be_used_for_suggestions() { + let question_span = bound_span.with_hi(bound_span.lo() + BytePos(1)); + suggestions.push(( + question_span, + String::new(), + SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized, + )); + } + } else { + let sp = generics.span_for_bound_removal(where_pos, pos); + suggestions.push(( + sp, + String::new(), + SuggestChangingConstraintsMessage::RemoveMaybeUnsized, + )); + } } } } @@ -236,15 +251,12 @@ pub fn suggest_constraining_type_params<'a>( { let mut sized_constraints = - constraints.drain_filter(|(_, def_id)| *def_id == tcx.lang_items().sized_trait()); - if let Some((constraint, def_id)) = sized_constraints.next() { + constraints.extract_if(|(_, def_id)| *def_id == tcx.lang_items().sized_trait()); + if let Some((_, def_id)) = sized_constraints.next() { applicability = Applicability::MaybeIncorrect; - err.span_label( - param.span, - format!("this type parameter needs to be `{}`", constraint), - ); - suggest_removing_unsized_bound(generics, &mut suggestions, param, def_id); + err.span_label(param.span, "this type parameter needs to be `Sized`"); + suggest_changing_unsized_bound(generics, &mut suggestions, param, def_id); } } @@ -384,22 +396,21 @@ pub fn suggest_constraining_type_params<'a>( if suggestions.len() == 1 { let (span, suggestion, msg) = suggestions.pop().unwrap(); - - let s; let msg = match msg { SuggestChangingConstraintsMessage::RestrictBoundFurther => { - "consider further restricting this bound" + Cow::from("consider further restricting this bound") } SuggestChangingConstraintsMessage::RestrictType { ty } => { - s = format!("consider restricting type parameter `{}`", ty); - &s + Cow::from(format!("consider restricting type parameter `{}`", ty)) } SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => { - s = format!("consider further restricting type parameter `{}`", ty); - &s + Cow::from(format!("consider further restricting type parameter `{}`", ty)) + } + SuggestChangingConstraintsMessage::RemoveMaybeUnsized => { + Cow::from("consider removing the `?Sized` bound to make the type parameter `Sized`") } - SuggestChangingConstraintsMessage::RemovingQSized => { - "consider removing the `?Sized` bound to make the type parameter `Sized`" + SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized => { + Cow::from("consider replacing `?Sized` with `Sized`") } }; @@ -548,7 +559,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> { Infer(InferTy::TyVar(_)) if self.infer_suggestable => t, FnDef(def_id, substs) => { - self.tcx.mk_fn_ptr(self.tcx.fn_sig(def_id).subst(self.tcx, substs)) + Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).subst(self.tcx, substs)) } // FIXME(compiler-errors): We could replace these with infer, I guess. diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 49ab9b79e..c794c3fad 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -45,7 +45,6 @@ pub enum TypeError<'tcx> { RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), - RegionsOverlyPolymorphic(BoundRegionKind, Region<'tcx>), RegionsPlaceholderMismatch, Sorts(ExpectedFound<Ty<'tcx>>), @@ -74,7 +73,6 @@ impl TypeError<'_> { match self { TypeError::RegionsDoesNotOutlive(_, _) | TypeError::RegionsInsufficientlyPolymorphic(_, _) - | TypeError::RegionsOverlyPolymorphic(_, _) | TypeError::RegionsPlaceholderMismatch => true, _ => false, } @@ -98,11 +96,6 @@ impl<'tcx> TypeError<'tcx> { } } - let br_string = |br: ty::BoundRegionKind| match br { - ty::BrNamed(_, name) => format!(" {}", name), - _ => String::new(), - }; - match self { CyclicTy(_) => "cyclic type of infinite size".into(), CyclicConst(_) => "encountered a self-referencing constant".into(), @@ -144,11 +137,6 @@ impl<'tcx> TypeError<'tcx> { RegionsInsufficientlyPolymorphic(..) => { "one type is more general than the other".into() } - RegionsOverlyPolymorphic(br, _) => format!( - "expected concrete lifetime, found bound lifetime parameter{}", - br_string(br) - ) - .into(), RegionsPlaceholderMismatch => "one type is more general than the other".into(), ArgumentSorts(values, _) | Sorts(values) => { let expected = values.expected.sort_string(tcx); @@ -228,7 +216,6 @@ impl<'tcx> TypeError<'tcx> { | FieldMisMatch(..) | RegionsDoesNotOutlive(..) | RegionsInsufficientlyPolymorphic(..) - | RegionsOverlyPolymorphic(..) | RegionsPlaceholderMismatch | Traits(_) | ProjectionMismatched(_) @@ -313,6 +300,7 @@ impl<'tcx> Ty<'tcx> { ty::Placeholder(..) => "higher-ranked type".into(), ty::Bound(..) => "bound type variable".into(), ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(), + ty::Alias(ty::Weak, _) => "type alias".into(), ty::Param(_) => "type parameter".into(), ty::Alias(ty::Opaque, ..) => "opaque type".into(), } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index d64875a9f..ff3917947 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -178,7 +178,7 @@ impl FlagComputation { &ty::Alias(kind, data) => { self.add_flags(match kind { - ty::Projection => TypeFlags::HAS_TY_PROJECTION, + ty::Weak | ty::Projection => TypeFlags::HAS_TY_PROJECTION, ty::Inherent => TypeFlags::HAS_TY_INHERENT, ty::Opaque => TypeFlags::HAS_TY_OPAQUE, }); @@ -237,21 +237,24 @@ impl FlagComputation { fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) { match atom { - ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => { self.add_substs(trait_pred.trait_ref.substs); } - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(a, b))) => { + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( + a, + b, + ))) => { self.add_region(a); self.add_region(b); } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty, region, ))) => { self.add_ty(ty); self.add_region(region); } - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { self.add_const(ct); self.add_ty(ty); } @@ -263,30 +266,27 @@ impl FlagComputation { self.add_ty(a); self.add_ty(b); } - ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term, })) => { self.add_alias_ty(projection_ty); self.add_term(term); } - ty::PredicateKind::WellFormed(arg) => { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.add_substs(slice::from_ref(&arg)); } ty::PredicateKind::ObjectSafe(_def_id) => {} ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => { self.add_substs(substs); } - ty::PredicateKind::ConstEvaluatable(uv) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { self.add_const(uv); } ty::PredicateKind::ConstEquate(expected, found) => { self.add_const(expected); self.add_const(found); } - ty::PredicateKind::TypeWellFormedFromEnv(ty) => { - self.add_ty(ty); - } ty::PredicateKind::Ambiguous => {} ty::PredicateKind::AliasRelate(t1, t2, _) => { self.add_term(t1); diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 25890eb15..77cf6bee7 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -213,7 +213,7 @@ where // debruijn index. Then we adjust it to the // correct depth. assert_eq!(debruijn1, ty::INNERMOST); - self.tcx.mk_re_late_bound(debruijn, br) + ty::Region::new_late_bound(self.tcx, debruijn, br) } else { region } @@ -328,7 +328,7 @@ impl<'tcx> TyCtxt<'tcx> { T: TypeFoldable<TyCtxt<'tcx>>, { self.replace_late_bound_regions_uncached(value, |br| { - self.mk_re_free(all_outlive_scope, br.kind) + ty::Region::new_free(self, all_outlive_scope, br.kind) }) } @@ -341,16 +341,21 @@ impl<'tcx> TyCtxt<'tcx> { value, FnMutDelegate { regions: &mut |r: ty::BoundRegion| { - self.mk_re_late_bound( + ty::Region::new_late_bound( + self, ty::INNERMOST, ty::BoundRegion { var: shift_bv(r.var), kind: r.kind }, ) }, types: &mut |t: ty::BoundTy| { - self.mk_bound(ty::INNERMOST, ty::BoundTy { var: shift_bv(t.var), kind: t.kind }) + Ty::new_bound( + self, + ty::INNERMOST, + ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, + ) }, consts: &mut |c, ty: Ty<'tcx>| { - self.mk_const(ty::ConstKind::Bound(ty::INNERMOST, shift_bv(c)), ty) + ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c), ty) }, }, ) @@ -383,7 +388,7 @@ impl<'tcx> TyCtxt<'tcx> { .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(None))) .expect_region(); let br = ty::BoundRegion { var, kind }; - self.tcx.mk_re_late_bound(ty::INNERMOST, br) + ty::Region::new_late_bound(self.tcx, ty::INNERMOST, br) } fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { let entry = self.map.entry(bt.var); @@ -392,14 +397,14 @@ impl<'tcx> TyCtxt<'tcx> { let kind = entry .or_insert_with(|| ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon)) .expect_ty(); - self.tcx.mk_bound(ty::INNERMOST, BoundTy { var, kind }) + Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind }) } fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { let entry = self.map.entry(bv); let index = entry.index(); let var = ty::BoundVar::from_usize(index); let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const(); - self.tcx.mk_const(ty::ConstKind::Bound(ty::INNERMOST, var), ty) + ty::Const::new_bound(self.tcx, ty::INNERMOST, var, ty) } } @@ -451,7 +456,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> { match *r { ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - self.tcx.mk_re_late_bound(debruijn, br) + ty::Region::new_late_bound(self.tcx, debruijn, br) } _ => r, } @@ -461,7 +466,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> { match *ty.kind() { ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - self.tcx.mk_bound(debruijn, bound_ty) + Ty::new_bound(self.tcx, debruijn, bound_ty) } _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self), @@ -474,7 +479,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> { && debruijn >= self.current_index { let debruijn = debruijn.shifted_in(self.amount); - self.tcx.mk_const(ty::ConstKind::Bound(debruijn, bound_ct), ct.ty()) + ty::Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty()) } else { ct.super_fold_with(self) } @@ -492,7 +497,7 @@ pub fn shift_region<'tcx>( ) -> ty::Region<'tcx> { match *region { ty::ReLateBound(debruijn, br) if amount > 0 => { - tcx.mk_re_late_bound(debruijn.shifted_in(amount), br) + ty::Region::new_late_bound(tcx, debruijn.shifted_in(amount), br) } _ => region, } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index b0ffe7829..6c7125c4c 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt}; +use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt}; #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum GenericParamDefKind { @@ -100,11 +100,13 @@ impl GenericParamDef { preceding_substs: &[ty::GenericArg<'tcx>], ) -> ty::GenericArg<'tcx> { match &self.kind { - ty::GenericParamDefKind::Lifetime => tcx.mk_re_error_misc().into(), - ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(), - ty::GenericParamDefKind::Const { .. } => { - tcx.const_error_misc(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into() - } + ty::GenericParamDefKind::Lifetime => ty::Region::new_error_misc(tcx).into(), + ty::GenericParamDefKind::Type { .. } => Ty::new_misc_error(tcx).into(), + ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error( + tcx, + tcx.type_of(self.def_id).subst(tcx, preceding_substs), + ) + .into(), } } } @@ -133,6 +135,9 @@ pub struct Generics { pub has_self: bool, pub has_late_bound_regions: Option<Span>, + + // The index of the host effect when substituted. (i.e. might be index to parent substs) + pub host_effect_index: Option<usize>, } impl<'tcx> Generics { @@ -323,7 +328,7 @@ impl<'tcx> Generics { #[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)] pub struct GenericPredicates<'tcx> { pub parent: Option<DefId>, - pub predicates: &'tcx [(Predicate<'tcx>, Span)], + pub predicates: &'tcx [(Clause<'tcx>, Span)], } impl<'tcx> GenericPredicates<'tcx> { @@ -341,9 +346,8 @@ impl<'tcx> GenericPredicates<'tcx> { &self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, - ) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator - { - EarlyBinder(self.predicates).subst_iter_copied(tcx, substs) + ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator { + EarlyBinder::bind(self.predicates).subst_iter_copied(tcx, substs) } #[instrument(level = "debug", skip(self, tcx))] @@ -358,7 +362,7 @@ impl<'tcx> GenericPredicates<'tcx> { } instantiated .predicates - .extend(self.predicates.iter().map(|(p, _)| EarlyBinder(*p).subst(tcx, substs))); + .extend(self.predicates.iter().map(|(p, _)| EarlyBinder::bind(*p).subst(tcx, substs))); instantiated.spans.extend(self.predicates.iter().map(|(_, sp)| *sp)); } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index ac42d6e05..295cb1464 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -62,7 +62,18 @@ impl<'tcx> InhabitedPredicate<'tcx> { Some(1..) => Ok(false), }, Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod), - Self::GenericType(_) => Ok(true), + // `t` may be a projection, for which `inhabited_predicate` returns a `GenericType`. As + // we have a param_env available, we can do better. + Self::GenericType(t) => { + let normalized_pred = tcx + .try_normalize_erasing_regions(param_env, t) + .map_or(self, |t| t.inhabited_predicate(tcx)); + match normalized_pred { + // We don't have more information than we started with, so consider inhabited. + Self::GenericType(_) => Ok(true), + pred => pred.apply_inner(tcx, param_env, in_module), + } + } Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)), Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)), } @@ -158,8 +169,8 @@ impl<'tcx> InhabitedPredicate<'tcx> { fn subst_opt(self, tcx: TyCtxt<'tcx>, substs: ty::SubstsRef<'tcx>) -> Option<Self> { match self { Self::ConstIsZero(c) => { - let c = ty::EarlyBinder(c).subst(tcx, substs); - let pred = match c.kind().try_to_target_usize(tcx) { + let c = ty::EarlyBinder::bind(c).subst(tcx, substs); + let pred = match c.try_to_target_usize(tcx) { Some(0) => Self::True, Some(1..) => Self::False, None => Self::ConstIsZero(c), @@ -167,7 +178,7 @@ impl<'tcx> InhabitedPredicate<'tcx> { Some(pred) } Self::GenericType(t) => { - Some(ty::EarlyBinder(t).subst(tcx, substs).inhabited_predicate(tcx)) + Some(ty::EarlyBinder::bind(t).subst(tcx, substs).inhabited_predicate(tcx)) } Self::And(&[a, b]) => match a.subst_opt(tcx, substs) { None => b.subst_opt(tcx, substs).map(|b| a.and(tcx, b)), diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 422350284..b92d84152 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -197,7 +197,7 @@ fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedP // If we can evaluate the array length before having a `ParamEnv`, then // we can simplify the predicate. This is an optimization. - Array(ty, len) => match len.kind().try_to_target_usize(tcx) { + Array(ty, len) => match len.try_to_target_usize(tcx) { Some(0) => InhabitedPredicate::True, Some(1..) => ty.inhabited_predicate(tcx), None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)), diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index e641d1ef1..ae57e954f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -410,8 +410,8 @@ impl<'tcx> Instance<'tcx> { ) -> Instance<'tcx> { match ty::Instance::resolve(tcx, param_env, def_id, substs) { Ok(Some(instance)) => instance, - _ => bug!( - "failed to resolve instance for {}", + instance => bug!( + "failed to resolve instance for {}: {instance:#?}", tcx.def_path_str_with_substs(def_id, substs) ), } @@ -552,7 +552,7 @@ impl<'tcx> Instance<'tcx> { tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER); let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller }; - let self_ty = tcx.mk_closure(closure_did, substs); + let self_ty = Ty::new_closure(tcx, closure_did, substs); let sig = substs.as_closure().sig(); let sig = @@ -586,7 +586,7 @@ impl<'tcx> Instance<'tcx> { if let Some(substs) = self.substs_for_mir_body() { v.subst(tcx, substs) } else { - v.skip_binder() + v.subst_identity() } } @@ -680,7 +680,7 @@ fn polymorphize<'tcx>( if substs == polymorphized_substs { ty } else { - self.tcx.mk_closure(def_id, polymorphized_substs) + Ty::new_closure(self.tcx, def_id, polymorphized_substs) } } ty::Generator(def_id, substs, movability) => { @@ -689,7 +689,7 @@ fn polymorphize<'tcx>( if substs == polymorphized_substs { ty } else { - self.tcx.mk_generator(def_id, polymorphized_substs, movability) + Ty::new_generator(self.tcx, def_id, polymorphized_substs, movability) } } _ => ty.super_fold_with(self), diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b5a743cfe..d95b05ef7 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,8 +1,9 @@ -use crate::fluent_generated as fluent; +use crate::error::UnsupportedFnAbi; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::query::TyCtxtAt; use crate::ty::normalize_erasing_regions::NormalizationError; -use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{self, ConstKind, ReprOptions, Ty, TyCtxt, TypeVisitableExt}; +use rustc_error_messages::DiagnosticMessage; use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -14,7 +15,7 @@ use rustc_target::abi::call::FnAbi; use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; -use std::cmp::{self}; +use std::cmp; use std::fmt; use std::num::NonZeroUsize; use std::ops::Bound; @@ -132,7 +133,7 @@ impl PrimitiveExt for Primitive { F32 => tcx.types.f32, F64 => tcx.types.f64, // FIXME(erikdesjardins): handle non-default addrspace ptr sizes - Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()), + Pointer(_) => Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)), } } @@ -214,29 +215,29 @@ pub enum LayoutError<'tcx> { Cycle, } -impl IntoDiagnostic<'_, !> for LayoutError<'_> { - fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> { - let mut diag = handler.struct_fatal(""); +impl<'tcx> LayoutError<'tcx> { + pub fn diagnostic_message(&self) -> DiagnosticMessage { + use crate::fluent_generated::*; + use LayoutError::*; + match self { + Unknown(_) => middle_unknown_layout, + SizeOverflow(_) => middle_values_too_big, + NormalizationFailure(_, _) => middle_cannot_be_normalized, + Cycle => middle_cycle, + } + } + pub fn into_diagnostic(self) -> crate::error::LayoutError<'tcx> { + use crate::error::LayoutError as E; + use LayoutError::*; match self { - LayoutError::Unknown(ty) => { - diag.set_arg("ty", ty); - diag.set_primary_message(fluent::middle_unknown_layout); - } - LayoutError::SizeOverflow(ty) => { - diag.set_arg("ty", ty); - diag.set_primary_message(fluent::middle_values_too_big); - } - LayoutError::NormalizationFailure(ty, e) => { - diag.set_arg("ty", ty); - diag.set_arg("failure_ty", e.get_type_for_failure()); - diag.set_primary_message(fluent::middle_cannot_be_normalized); - } - LayoutError::Cycle => { - diag.set_primary_message(fluent::middle_cycle); + Unknown(ty) => E::Unknown { ty }, + SizeOverflow(ty) => E::Overflow { ty }, + NormalizationFailure(ty, e) => { + E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() } } + Cycle => E::Cycle, } - diag } } @@ -309,7 +310,7 @@ impl<'tcx> SizeSkeleton<'tcx> { ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - ) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> { + ) -> Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>> { debug_assert!(!ty.has_non_region_infer()); // First try computing a static layout. @@ -317,7 +318,13 @@ impl<'tcx> SizeSkeleton<'tcx> { Ok(layout) => { return Ok(SizeSkeleton::Known(layout.size)); } - Err(err) => err, + Err(err @ LayoutError::Unknown(_)) => err, + // We can't extract SizeSkeleton info from other layout errors + Err( + e @ LayoutError::Cycle + | e @ LayoutError::SizeOverflow(_) + | e @ LayoutError::NormalizationFailure(..), + ) => return Err(e), }; match *ty.kind() { @@ -330,11 +337,8 @@ impl<'tcx> SizeSkeleton<'tcx> { Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) } _ => bug!( - "SizeSkeleton::compute({}): layout errored ({}), yet \ - tail `{}` is not a type parameter or a projection", - ty, - err, - tail + "SizeSkeleton::compute({ty}): layout errored ({err:?}), yet \ + tail `{tail}` is not a type parameter or a projection", ), } } @@ -349,13 +353,13 @@ impl<'tcx> SizeSkeleton<'tcx> { let size = s .bytes() .checked_mul(c) - .ok_or_else(|| LayoutError::SizeOverflow(ty))?; + .ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?; return Ok(SizeSkeleton::Known(Size::from_bytes(size))); } let len = tcx.expand_abstract_consts(len); let prev = ty::Const::from_target_usize(tcx, s.bytes()); let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, prev) else { - return Err(LayoutError::SizeOverflow(ty)); + return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty))); }; Ok(SizeSkeleton::Generic(gen_size)) } @@ -363,7 +367,7 @@ impl<'tcx> SizeSkeleton<'tcx> { SizeSkeleton::Generic(g) => { let len = tcx.expand_abstract_consts(len); let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, g) else { - return Err(LayoutError::SizeOverflow(ty)); + return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty))); }; Ok(SizeSkeleton::Generic(gen_size)) } @@ -476,13 +480,11 @@ fn mul_sorted_consts<'tcx>( b: ty::Const<'tcx>, ) -> Option<ty::Const<'tcx>> { use crate::mir::BinOp::Mul; - use ty::ConstKind::Expr; - use ty::Expr::Binop; let mut work = vec![a, b]; let mut done = vec![]; while let Some(n) = work.pop() { - if let Expr(Binop(Mul, l, r)) = n.kind() { + if let ConstKind::Expr(ty::Expr::Binop(Mul, l, r)) = n.kind() { work.push(l); work.push(r) } else { @@ -513,7 +515,7 @@ fn mul_sorted_consts<'tcx>( done.sort_unstable(); // create a single tree from the buffer - done.into_iter().reduce(|acc, n| tcx.mk_const(Expr(Binop(Mul, n, acc)), n.ty())) + done.into_iter().reduce(|acc, n| ty::Const::new_expr(tcx, ty::Expr::Binop(Mul, n, acc), n.ty())) } pub trait HasTyCtxt<'tcx>: HasDataLayout { @@ -668,7 +670,7 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> { MaybeResult::from( tcx.layout_of(self.param_env().and(ty)) - .map_err(|err| self.handle_layout_err(err, span, ty)), + .map_err(|err| self.handle_layout_err(*err, span, ty)), ) } } @@ -676,16 +678,21 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> { impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {} impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { - type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; + type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>; #[inline] - fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> { - err + fn handle_layout_err( + &self, + err: LayoutError<'tcx>, + _: Span, + _: Ty<'tcx>, + ) -> &'tcx LayoutError<'tcx> { + self.tcx.arena.alloc(err) } } impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> { - type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; + type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>; #[inline] fn layout_tcx_at_span(&self) -> Span { @@ -693,8 +700,13 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> { } #[inline] - fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> { - err + fn handle_layout_err( + &self, + err: LayoutError<'tcx>, + _: Span, + _: Ty<'tcx>, + ) -> &'tcx LayoutError<'tcx> { + self.tcx.arena.alloc(err) } } @@ -798,11 +810,11 @@ where // (which may have no non-DST form), and will work as long // as the `Abi` or `FieldsShape` is checked by users. if i == 0 { - let nil = tcx.mk_unit(); + let nil = Ty::new_unit(tcx); let unit_ptr_ty = if this.ty.is_unsafe_ptr() { - tcx.mk_mut_ptr(nil) + Ty::new_mut_ptr(tcx, nil) } else { - tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) + Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil) }; // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing @@ -815,7 +827,11 @@ where } let mk_dyn_vtable = || { - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3)) + Ty::new_imm_ref( + tcx, + tcx.lifetimes.re_static, + Ty::new_array(tcx, tcx.types.usize, 3), + ) /* FIXME: use actual fn pointers Warning: naively computing the number of entries in the vtable by counting the methods on the trait + methods on @@ -824,9 +840,9 @@ where Increase this counter if you tried to implement this but failed to do it without duplicating a lot of code from other places in the compiler: 2 - tcx.mk_tup(&[ - tcx.mk_array(tcx.types.usize, 3), - tcx.mk_array(Option<fn()>), + Ty::new_tup(tcx,&[ + Ty::new_array(tcx,tcx.types.usize, 3), + Ty::new_array(tcx,Option<fn()>), ]) */ }; @@ -838,7 +854,7 @@ where { let metadata = tcx.normalize_erasing_regions( cx.param_env(), - tcx.mk_projection(metadata_def_id, [pointee]), + Ty::new_projection(tcx,metadata_def_id, [pointee]), ); // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it @@ -913,15 +929,14 @@ where ty::Dynamic(_, _, ty::DynStar) => { if i == 0 { - TyMaybeWithLayout::Ty(tcx.mk_mut_ptr(tcx.types.unit)) + TyMaybeWithLayout::Ty(Ty::new_mut_ptr(tcx, tcx.types.unit)) } else if i == 1 { // FIXME(dyn-star) same FIXME as above applies here too - TyMaybeWithLayout::Ty( - tcx.mk_imm_ref( - tcx.lifetimes.re_static, - tcx.mk_array(tcx.types.usize, 3), - ), - ) + TyMaybeWithLayout::Ty(Ty::new_imm_ref( + tcx, + tcx.lifetimes.re_static, + Ty::new_array(tcx, tcx.types.usize, 3), + )) } else { bug!("no field {i} on dyn*") } @@ -940,12 +955,8 @@ where TyMaybeWithLayout::Ty(field_ty) => { cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| { bug!( - "failed to get layout for `{}`: {},\n\ - despite it being a field (#{}) of an existing layout: {:#?}", - field_ty, - e, - i, - this + "failed to get layout for `{field_ty}`: {e:?},\n\ + despite it being a field (#{i}) of an existing layout: {this:#?}", ) }) } @@ -970,10 +981,8 @@ where }) } ty::FnPtr(fn_sig) if offset.bytes() == 0 => { - tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo { - size: layout.size, - align: layout.align.abi, - safe: None, + tcx.layout_of(param_env.and(Ty::new_fn_ptr(tcx, fn_sig))).ok().map(|layout| { + PointeeInfo { size: layout.size, align: layout.align.abi, safe: None } }) } ty::Ref(_, ty, mt) if offset.bytes() == 0 => { @@ -1101,12 +1110,11 @@ where /// /// This takes two primary parameters: /// -/// * `codegen_fn_attr_flags` - these are flags calculated as part of the -/// codegen attrs for a defined function. For function pointers this set of -/// flags is the empty set. This is only applicable for Rust-defined -/// functions, and generally isn't needed except for small optimizations where -/// we try to say a function which otherwise might look like it could unwind -/// doesn't actually unwind (such as for intrinsics and such). +/// * `fn_def_id` - the `DefId` of the function. If this is provided then we can +/// determine more precisely if the function can unwind. If this is not provided +/// then we will only infer whether the function can unwind or not based on the +/// ABI of the function. For example, a function marked with `#[rustc_nounwind]` +/// is known to not unwind even if it's using Rust ABI. /// /// * `abi` - this is the ABI that the function is defined with. This is the /// primary factor for determining whether a function can unwind or not. @@ -1138,11 +1146,6 @@ where /// aborts the process. /// * This affects whether functions have the LLVM `nounwind` attribute, which /// affects various optimizations and codegen. -/// -/// FIXME: this is actually buggy with respect to Rust functions. Rust functions -/// compiled with `-Cpanic=unwind` and referenced from another crate compiled -/// with `-Cpanic=abort` will look like they can't unwind when in fact they -/// might (from a foreign exception or similar). #[inline] #[tracing::instrument(level = "debug", skip(tcx))] pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool { @@ -1250,33 +1253,18 @@ pub enum FnAbiError<'tcx> { AdjustForForeignAbi(call::AdjustForForeignAbiError), } -impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> { - fn from(err: LayoutError<'tcx>) -> Self { - Self::Layout(err) - } -} - -impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> { - fn from(err: call::AdjustForForeignAbiError) -> Self { - Self::AdjustForForeignAbi(err) - } -} - -impl<'tcx> fmt::Display for FnAbiError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl<'a, 'b> IntoDiagnostic<'a, !> for FnAbiError<'b> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> { match self { - Self::Layout(err) => err.fmt(f), - Self::AdjustForForeignAbi(err) => err.fmt(f), + Self::Layout(e) => e.into_diagnostic().into_diagnostic(handler), + Self::AdjustForForeignAbi(call::AdjustForForeignAbiError::Unsupported { + arch, + abi, + }) => UnsupportedFnAbi { arch, abi: abi.name() }.into_diagnostic(handler), } } } -impl IntoDiagnostic<'_, !> for FnAbiError<'_> { - fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> { - handler.struct_fatal(self.to_string()) - } -} - // FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not // just for error handling. #[derive(Debug)] @@ -1324,7 +1312,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { let tcx = self.tcx().at(span); MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err( - |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }), + |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }), )) } @@ -1351,7 +1339,11 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { // However, we don't do this early in order to avoid calling // `def_span` unconditionally (which may have a perf penalty). let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) }; - self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args }) + self.handle_fn_abi_err( + *err, + span, + FnAbiRequest::OfInstance { instance, extra_args }, + ) }), ) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a8d0dca37..aa8bfd317 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -53,7 +53,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; -use rustc_type_ir::WithCachedTypeInfo; pub use subst::*; pub use vtable::*; @@ -67,6 +66,10 @@ use std::{fmt, str}; pub use crate::ty::diagnostics::*; pub use rustc_type_ir::AliasKind::*; +pub use rustc_type_ir::ConstKind::{ + Bound as BoundCt, Error as ErrorCt, Expr as ExprCt, Infer as InferCt, Param as ParamCt, + Placeholder as PlaceholderCt, Unevaluated, Value, +}; pub use rustc_type_ir::DynKind::*; pub use rustc_type_ir::InferTy::*; pub use rustc_type_ir::RegionKind::*; @@ -82,7 +85,7 @@ pub use self::closure::{ CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ - Const, ConstData, ConstInt, ConstKind, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstData, ConstInt, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, @@ -94,7 +97,7 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::BoundRegionKind::*; pub use self::sty::{ AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, - BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, + BoundVariableKind, CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstKind, ConstVid, EarlyBoundRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialPredicate, @@ -145,6 +148,7 @@ mod opaque_types; mod parameterized; mod rvalue_scopes; mod structural_impls; +#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))] mod sty; mod typeck_results; @@ -456,6 +460,11 @@ impl ty::EarlyBoundRegion { } } +/// A statement that can be proven by a trait solver. This includes things that may +/// show up in where clauses, such as trait predicates and projection predicates, +/// and also things that are emitted as part of type checking such as `ObjectSafe` +/// predicate which is emitted when a type is coerced to a trait object. +/// /// Use this rather than `PredicateKind`, whenever possible. #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] @@ -487,11 +496,11 @@ impl<'tcx> Predicate<'tcx> { let kind = self .kind() .map_bound(|kind| match kind { - PredicateKind::Clause(Clause::Trait(TraitPredicate { + PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity, - })) => Some(PredicateKind::Clause(Clause::Trait(TraitPredicate { + })) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity: polarity.flip()?, @@ -505,10 +514,10 @@ impl<'tcx> Predicate<'tcx> { } pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self { - if let PredicateKind::Clause(Clause::Trait(TraitPredicate { trait_ref, constness, polarity })) = self.kind().skip_binder() + if let PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity })) = self.kind().skip_binder() && constness != BoundConstness::NotConst { - self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Clause(Clause::Trait(TraitPredicate { + self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness: BoundConstness::NotConst, polarity, @@ -520,10 +529,10 @@ impl<'tcx> Predicate<'tcx> { #[instrument(level = "debug", skip(tcx), ret)] pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { tcx.trait_is_coinductive(data.def_id()) } - ty::PredicateKind::WellFormed(_) => true, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => true, _ => false, } } @@ -536,21 +545,20 @@ impl<'tcx> Predicate<'tcx> { #[inline] pub fn allow_normalization(self) -> bool { match self.kind().skip_binder() { - PredicateKind::WellFormed(_) => false, - PredicateKind::Clause(Clause::Trait(_)) - | PredicateKind::Clause(Clause::RegionOutlives(_)) - | PredicateKind::Clause(Clause::TypeOutlives(_)) - | PredicateKind::Clause(Clause::Projection(_)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) + PredicateKind::Clause(ClauseKind::WellFormed(_)) => false, + PredicateKind::Clause(ClauseKind::Trait(_)) + | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) + | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) + | PredicateKind::Clause(ClauseKind::Projection(_)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::AliasRelate(..) | PredicateKind::ObjectSafe(_) | PredicateKind::ClosureKind(_, _, _) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) - | PredicateKind::ConstEvaluatable(_) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) | PredicateKind::ConstEquate(_, _) - | PredicateKind::Ambiguous - | PredicateKind::TypeWellFormedFromEnv(_) => true, + | PredicateKind::Ambiguous => true, } } } @@ -561,11 +569,77 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> { } } +impl rustc_errors::IntoDiagnosticArg for Clause<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string())) + } +} + +/// A subset of predicates which can be assumed by the trait solver. They show up in +/// an item's where clauses, hence the name `Clause`, and may either be user-written +/// (such as traits) or may be inserted during lowering. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)] +#[rustc_pass_by_value] +pub struct Clause<'tcx>(Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>); + +impl<'tcx> Clause<'tcx> { + pub fn as_predicate(self) -> Predicate<'tcx> { + Predicate(self.0) + } + + pub fn kind(self) -> Binder<'tcx, ClauseKind<'tcx>> { + self.0.internee.map_bound(|kind| match kind { + PredicateKind::Clause(clause) => clause, + _ => unreachable!(), + }) + } + + pub fn as_trait_clause(self) -> Option<Binder<'tcx, TraitPredicate<'tcx>>> { + let clause = self.kind(); + if let ty::ClauseKind::Trait(trait_clause) = clause.skip_binder() { + Some(clause.rebind(trait_clause)) + } else { + None + } + } + + pub fn as_projection_clause(self) -> Option<Binder<'tcx, ProjectionPredicate<'tcx>>> { + let clause = self.kind(); + if let ty::ClauseKind::Projection(projection_clause) = clause.skip_binder() { + Some(clause.rebind(projection_clause)) + } else { + None + } + } + + pub fn as_type_outlives_clause(self) -> Option<Binder<'tcx, TypeOutlivesPredicate<'tcx>>> { + let clause = self.kind(); + if let ty::ClauseKind::TypeOutlives(o) = clause.skip_binder() { + Some(clause.rebind(o)) + } else { + None + } + } + + pub fn as_region_outlives_clause(self) -> Option<Binder<'tcx, RegionOutlivesPredicate<'tcx>>> { + let clause = self.kind(); + if let ty::ClauseKind::RegionOutlives(o) = clause.skip_binder() { + Some(clause.rebind(o)) + } else { + None + } + } + + pub fn without_const(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + self.as_predicate().without_const(tcx).expect_clause() + } +} + #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. -pub enum Clause<'tcx> { +pub enum ClauseKind<'tcx> { /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. @@ -584,16 +658,19 @@ pub enum Clause<'tcx> { /// Ensures that a const generic argument to a parameter `const N: u8` /// is of type `u8`. ConstArgHasType(Const<'tcx>, Ty<'tcx>), + + /// No syntax: `T` well-formed. + WellFormed(GenericArg<'tcx>), + + /// Constant initializer must evaluate successfully. + ConstEvaluatable(ty::Const<'tcx>), } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum PredicateKind<'tcx> { /// Prove a clause - Clause(Clause<'tcx>), - - /// No syntax: `T` well-formed. - WellFormed(GenericArg<'tcx>), + Clause(ClauseKind<'tcx>), /// Trait must be object-safe. ObjectSafe(DefId), @@ -620,22 +697,14 @@ pub enum PredicateKind<'tcx> { /// logic. Coerce(CoercePredicate<'tcx>), - /// Constant initializer must evaluate successfully. - ConstEvaluatable(ty::Const<'tcx>), - /// Constants must be equal. The first component is the const that is expected. ConstEquate(Const<'tcx>, Const<'tcx>), - /// Represents a type found in the environment that we can use for implied bounds. - /// - /// Only used for Chalk. - TypeWellFormedFromEnv(Ty<'tcx>), - /// A marker predicate that is always ambiguous. /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. Ambiguous, - /// Separate from `Clause::Projection` which is used for normalization in new solver. + /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. /// This predicate requires two terms to be equal to eachother. /// /// Only used for new solver @@ -672,7 +741,7 @@ pub struct CratePredicatesMap<'tcx> { pub predicates: FxHashMap<DefId, &'tcx [(Clause<'tcx>, Span)]>, } -impl<'tcx> Predicate<'tcx> { +impl<'tcx> Clause<'tcx> { /// Performs a substitution suitable for going from a /// poly-trait-ref to supertraits that must hold if that /// poly-trait-ref holds. This is slightly different from a normal @@ -682,7 +751,7 @@ impl<'tcx> Predicate<'tcx> { self, tcx: TyCtxt<'tcx>, trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> Predicate<'tcx> { + ) -> Clause<'tcx> { // The interaction between HRTB and supertraits is not entirely // obvious. Let me walk you (and myself) through an example. // @@ -764,11 +833,17 @@ impl<'tcx> Predicate<'tcx> { let shifted_pred = tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> - let new = EarlyBinder(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); + let new = EarlyBinder::bind(shifted_pred).subst(tcx, trait_ref.skip_binder().substs); // 3) ['x] + ['b] -> ['x, 'b] let bound_vars = tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars)); - tcx.reuse_or_mk_predicate(self, ty::Binder::bind_with_vars(new, bound_vars)) + + // FIXME: Is it really perf sensitive to use reuse_or_mk_predicate here? + tcx.reuse_or_mk_predicate( + self.as_predicate(), + ty::Binder::bind_with_vars(PredicateKind::Clause(new), bound_vars), + ) + .expect_clause() } } @@ -1189,13 +1264,41 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { } } -impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { +impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self))) } } +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + tcx.mk_predicate(self.map_bound(ty::PredicateKind::Clause)) + } +} + +impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { + #[inline(always)] + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self.as_predicate() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ClauseKind<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(self))).expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, ClauseKind<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))).expect_clause() + } +} + impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1203,6 +1306,29 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { } } +impl<'tcx> ToPredicate<'tcx, TraitPredicate<'tcx>> for TraitRef<'tcx> { + #[inline(always)] + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> TraitPredicate<'tcx> { + self.without_const() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { @@ -1211,6 +1337,14 @@ impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { } } +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); + pred.to_predicate(tcx) + } +} + impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> { @@ -1236,31 +1370,45 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for TraitPredicate<'tcx> impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() } } impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::TypeOutlives(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::TypeOutlives(p))).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - self.map_bound(|p| PredicateKind::Clause(Clause::Projection(p))).to_predicate(tcx) + self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() } } impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::Clause(Clause::Trait(self)).to_predicate(tcx) + PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx) } } @@ -1268,63 +1416,76 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(Clause::Projection(..)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) + PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(ClauseKind::Projection(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::Clause(Clause::RegionOutlives(..)) - | PredicateKind::WellFormed(..) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::Clause(Clause::TypeOutlives(..)) - | PredicateKind::ConstEvaluatable(..) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous - | PredicateKind::TypeWellFormedFromEnv(..) => None, + | PredicateKind::Ambiguous => None, } } pub fn to_opt_poly_projection_pred(self) -> Option<PolyProjectionPredicate<'tcx>> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(Clause::Trait(..)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) + PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)), + PredicateKind::Clause(ClauseKind::Trait(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::Clause(Clause::RegionOutlives(..)) - | PredicateKind::WellFormed(..) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::Clause(Clause::TypeOutlives(..)) - | PredicateKind::ConstEvaluatable(..) + | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous - | PredicateKind::TypeWellFormedFromEnv(..) => None, + | PredicateKind::Ambiguous => None, } } pub fn to_opt_type_outlives(self) -> Option<PolyTypeOutlivesPredicate<'tcx>> { let predicate = self.kind(); match predicate.skip_binder() { - PredicateKind::Clause(Clause::TypeOutlives(data)) => Some(predicate.rebind(data)), - PredicateKind::Clause(Clause::Trait(..)) - | PredicateKind::Clause(Clause::ConstArgHasType(..)) - | PredicateKind::Clause(Clause::Projection(..)) + PredicateKind::Clause(ClauseKind::TypeOutlives(data)) => Some(predicate.rebind(data)), + PredicateKind::Clause(ClauseKind::Trait(..)) + | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::Projection(..)) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) - | PredicateKind::Clause(Clause::RegionOutlives(..)) - | PredicateKind::WellFormed(..) + | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) + | PredicateKind::Clause(ClauseKind::WellFormed(..)) | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) - | PredicateKind::ConstEvaluatable(..) + | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous - | PredicateKind::TypeWellFormedFromEnv(..) => None, + | PredicateKind::Ambiguous => None, + } + } + + /// Matches a `PredicateKind::Clause` and turns it into a `Clause`, otherwise returns `None`. + pub fn as_clause(self) -> Option<Clause<'tcx>> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Some(self.expect_clause()), + _ => None, + } + } + + /// Assert that the predicate is a clause. + pub fn expect_clause(self) -> Clause<'tcx> { + match self.kind().skip_binder() { + PredicateKind::Clause(..) => Clause(self.0), + _ => bug!("{self} is not a clause"), } } } @@ -1350,7 +1511,7 @@ impl<'tcx> Predicate<'tcx> { /// [usize:Bar<isize>]]`. #[derive(Clone, Debug, TypeFoldable, TypeVisitable)] pub struct InstantiatedPredicates<'tcx> { - pub predicates: Vec<Predicate<'tcx>>, + pub predicates: Vec<Clause<'tcx>>, pub spans: Vec<Span>, } @@ -1369,9 +1530,9 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> { - type Item = (Predicate<'tcx>, Span); + type Item = (Clause<'tcx>, Span); - type IntoIter = std::iter::Zip<std::vec::IntoIter<Predicate<'tcx>>, std::vec::IntoIter<Span>>; + type IntoIter = std::iter::Zip<std::vec::IntoIter<Clause<'tcx>>, std::vec::IntoIter<Span>>; fn into_iter(self) -> Self::IntoIter { debug_assert_eq!(self.predicates.len(), self.spans.len()); @@ -1380,10 +1541,10 @@ impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> { } impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> { - type Item = (Predicate<'tcx>, Span); + type Item = (Clause<'tcx>, Span); type IntoIter = std::iter::Zip< - std::iter::Copied<std::slice::Iter<'a, Predicate<'tcx>>>, + std::iter::Copied<std::slice::Iter<'a, Clause<'tcx>>>, std::iter::Copied<std::slice::Iter<'a, Span>>, >; @@ -1496,7 +1657,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> { /// identified by both a universe, as well as a name residing within that universe. Distinct bound /// regions/types/consts within the same universe simply have an unknown relationship to one /// another. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(HashStable, TyEncodable, TyDecodable)] pub struct Placeholder<T> { pub universe: UniverseIndex, @@ -1533,7 +1694,7 @@ pub struct ParamEnv<'tcx> { /// want `Reveal::All`. /// /// Note: This is packed, use the reveal() method to access it. - packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, ParamTag, true>, + packed: CopyTaggedPtr<&'tcx List<Clause<'tcx>>, ParamTag, true>, } #[derive(Copy, Clone)] @@ -1599,7 +1760,7 @@ impl<'tcx> ParamEnv<'tcx> { } #[inline] - pub fn caller_bounds(self) -> &'tcx List<Predicate<'tcx>> { + pub fn caller_bounds(self) -> &'tcx List<Clause<'tcx>> { self.packed.pointer() } @@ -1633,7 +1794,7 @@ impl<'tcx> ParamEnv<'tcx> { /// Construct a trait environment with the given set of predicates. #[inline] pub fn new( - caller_bounds: &'tcx List<Predicate<'tcx>>, + caller_bounds: &'tcx List<Clause<'tcx>>, reveal: Reveal, constness: hir::Constness, ) -> Self { @@ -1874,6 +2035,22 @@ impl VariantDef { &self.fields[FieldIdx::from_u32(0)] } + + /// Returns the last field in this variant, if present. + #[inline] + pub fn tail_opt(&self) -> Option<&FieldDef> { + self.fields.raw.last() + } + + /// Returns the last field in this variant. + /// + /// # Panics + /// + /// Panics, if the variant has no fields. + #[inline] + pub fn tail(&self) -> &FieldDef { + self.tail_opt().expect("expected unsized ADT to have a tail field") + } } impl PartialEq for VariantDef { diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 1b336b7bf..b10921eff 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -141,7 +141,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { ) .emit(); - self.interner().mk_re_error(e) + ty::Region::new_error(self.interner(), e) } } } @@ -150,17 +150,17 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { match *ty.kind() { ty::Closure(def_id, substs) => { let substs = self.fold_closure_substs(def_id, substs); - self.tcx.mk_closure(def_id, substs) + Ty::new_closure(self.tcx, def_id, substs) } ty::Generator(def_id, substs, movability) => { let substs = self.fold_closure_substs(def_id, substs); - self.tcx.mk_generator(def_id, substs, movability) + Ty::new_generator(self.tcx, def_id, substs, movability) } ty::GeneratorWitnessMIR(def_id, substs) => { let substs = self.fold_closure_substs(def_id, substs); - self.tcx.mk_generator_witness_mir(def_id, substs) + Ty::new_generator_witness_mir(self.tcx, def_id, substs) } ty::Param(param) => { @@ -186,7 +186,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { .emit(); } - self.interner().ty_error_misc() + Ty::new_misc_error(self.tcx) } } } @@ -216,7 +216,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { }) .emit_unless(self.ignore_errors); - self.interner().const_error(ct.ty(), guar) + ty::Const::new_error(self.tcx, guar, ct.ty()) } } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index a2e77d9cd..cc2b26a5e 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -73,6 +73,7 @@ trivially_parameterized_over_tcx! { ty::fast_reject::SimplifiedType, rustc_ast::Attribute, rustc_ast::DelimArgs, + rustc_ast::expand::StrippedCfgItem<rustc_hir::def_id::DefIndex>, rustc_attr::ConstStability, rustc_attr::DefaultBodyStability, rustc_attr::Deprecation, @@ -128,5 +129,6 @@ parameterized_over_tcx! { ty::Const, ty::Predicate, ty::Clause, + ty::ClauseKind, ty::GeneratorDiagnosticData, } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 64e7480e6..2de0a3f75 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -123,7 +123,7 @@ pub trait Printer<'tcx>: Sized { impl_trait_ref.map(|i| i.subst(self.tcx(), substs)), ) } else { - (self_ty.0, impl_trait_ref.map(|i| i.0)) + (self_ty.subst_identity(), impl_trait_ref.map(|i| i.subst_identity())) }; self.print_impl_path(def_id, substs, self_ty, impl_trait_ref) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index d6c88ea96..96cf36eb9 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -94,6 +94,10 @@ macro_rules! define_helper { $tl.with(|c| c.set(self.0)) } } + + pub fn $name() -> bool { + $tl.with(|c| c.get()) + } )+ } } @@ -184,7 +188,7 @@ impl<'tcx> RegionHighlightMode<'tcx> { /// Convenience wrapper for `highlighting_region`. pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) { - self.highlighting_region(self.tcx.mk_re_var(vid), number) + self.highlighting_region(ty::Region::new_var(self.tcx, vid), number) } /// Returns `Some(n)` with the number to use for the given region, if any. @@ -676,7 +680,7 @@ pub trait PrettyPrinter<'tcx>: p!(")") } ty::FnDef(def_id, substs) => { - if NO_QUERIES.with(|q| q.get()) { + if with_no_queries() { p!(print_def_path(def_id, substs)); } else { let sig = self.tcx().fn_sig(def_id).subst(self.tcx(), substs); @@ -685,29 +689,30 @@ pub trait PrettyPrinter<'tcx>: } ty::FnPtr(ref bare_fn) => p!(print(bare_fn)), ty::Infer(infer_ty) => { - let verbose = self.should_print_verbose(); + if self.should_print_verbose() { + p!(write("{:?}", ty.kind())); + return Ok(self); + } + if let ty::TyVar(ty_vid) = infer_ty { if let Some(name) = self.ty_infer_name(ty_vid) { p!(write("{}", name)) } else { - if verbose { - p!(write("{:?}", infer_ty)) - } else { - p!(write("{}", infer_ty)) - } + p!(write("{}", infer_ty)) } } else { - if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) } + p!(write("{}", infer_ty)) } } ty::Error(_) => p!("{{type error}}"), ty::Param(ref param_ty) => p!(print(param_ty)), ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon => debug_bound_var(&mut self, debruijn, bound_ty.var)?, + ty::BoundTyKind::Anon => { + rustc_type_ir::debug_bound_var(&mut self, debruijn, bound_ty.var)? + } ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() { - true if debruijn == ty::INNERMOST => p!(write("^{}", s)), - true => p!(write("^{}_{}", debruijn.index(), s)), - false => p!(write("{}", s)), + true => p!(write("{:?}", ty.kind())), + false => p!(write("{s}")), }, }, ty::Adt(def, substs) => { @@ -730,8 +735,8 @@ pub trait PrettyPrinter<'tcx>: ty::Foreign(def_id) => { p!(print_def_path(def_id, &[])); } - ty::Alias(ty::Projection | ty::Inherent, ref data) => { - if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get())) + ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ref data) => { + if !(self.should_print_verbose() || with_no_queries()) && self.tcx().is_impl_trait_in_trait(data.def_id) { return self.pretty_print_opaque_impl_type(data.def_id, data.substs); @@ -740,10 +745,11 @@ pub trait PrettyPrinter<'tcx>: } } ty::Placeholder(placeholder) => match placeholder.bound.kind { - ty::BoundTyKind::Anon => { - debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound.var)?; - } - ty::BoundTyKind::Param(_, name) => p!(write("{}", name)), + ty::BoundTyKind::Anon => p!(write("{placeholder:?}")), + ty::BoundTyKind::Param(_, name) => match self.should_print_verbose() { + true => p!(write("{:?}", ty.kind())), + false => p!(write("{name}")), + }, }, ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { // We use verbose printing in 'NO_QUERIES' mode, to @@ -777,7 +783,7 @@ pub trait PrettyPrinter<'tcx>: return Ok(self); } _ => { - if NO_QUERIES.with(|q| q.get()) { + if with_no_queries() { p!(print_def_path(def_id, &[])); return Ok(self); } else { @@ -926,7 +932,7 @@ pub trait PrettyPrinter<'tcx>: let bound_predicate = predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { + ty::ClauseKind::Trait(pred) => { let trait_ref = bound_predicate.rebind(pred.trait_ref); // Don't print + Sized, but rather + ?Sized if absent. @@ -937,7 +943,7 @@ pub trait PrettyPrinter<'tcx>: self.insert_trait_and_projection(trait_ref, None, &mut traits, &mut fn_traits); } - ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { + ty::ClauseKind::Projection(pred) => { let proj_ref = bound_predicate.rebind(pred); let trait_ref = proj_ref.required_poly_trait_ref(tcx); @@ -951,7 +957,7 @@ pub trait PrettyPrinter<'tcx>: &mut fn_traits, ); } - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => { + ty::ClauseKind::TypeOutlives(outlives) => { lifetimes.push(outlives.1); } _ => {} @@ -1222,7 +1228,7 @@ pub trait PrettyPrinter<'tcx>: // in order to place the projections inside the `<...>`. if !resugared { // Use a type that can't appear in defaults of type parameters. - let dummy_cx = cx.tcx().mk_fresh_ty(0); + let dummy_cx = Ty::new_fresh(cx.tcx(), 0); let principal = principal.with_self_ty(cx.tcx(), dummy_cx); let args = cx @@ -1372,11 +1378,9 @@ pub trait PrettyPrinter<'tcx>: } ty::ConstKind::Bound(debruijn, bound_var) => { - debug_bound_var(&mut self, debruijn, bound_var)? + rustc_type_ir::debug_bound_var(&mut self, debruijn, bound_var)? } - ty::ConstKind::Placeholder(placeholder) => { - debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound)?; - }, + ty::ConstKind::Placeholder(placeholder) => p!(write("{placeholder:?}")), // FIXME(generic_const_exprs): // write out some legible representation of an abstract const? ty::ConstKind::Expr(_) => p!("{{const expr}}"), @@ -1389,11 +1393,12 @@ pub trait PrettyPrinter<'tcx>: self, scalar: Scalar, ty: Ty<'tcx>, - print_ty: bool, ) -> Result<Self::Const, Self::Error> { match scalar { - Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty, print_ty), - Scalar::Int(int) => self.pretty_print_const_scalar_int(int, ty, print_ty), + Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty), + Scalar::Int(int) => { + self.pretty_print_const_scalar_int(int, ty, /* print_ty */ true) + } } } @@ -1401,7 +1406,6 @@ pub trait PrettyPrinter<'tcx>: mut self, ptr: Pointer, ty: Ty<'tcx>, - print_ty: bool, ) -> Result<Self::Const, Self::Error> { define_scoped_cx!(self); @@ -1455,7 +1459,7 @@ pub trait PrettyPrinter<'tcx>: _ => {} } // Any pointer values not covered by a branch above - self = self.pretty_print_const_pointer(ptr, ty, print_ty)?; + self = self.pretty_print_const_pointer(ptr, ty)?; Ok(self) } @@ -1523,24 +1527,18 @@ pub trait PrettyPrinter<'tcx>: /// This is overridden for MIR printing because we only want to hide alloc ids from users, not /// from MIR where it is actually useful. fn pretty_print_const_pointer<Prov: Provenance>( - mut self, + self, _: Pointer<Prov>, ty: Ty<'tcx>, - print_ty: bool, ) -> Result<Self::Const, Self::Error> { - if print_ty { - self.typed_value( - |mut this| { - this.write_str("&_")?; - Ok(this) - }, - |this| this.print_type(ty), - ": ", - ) - } else { - self.write_str("&_")?; - Ok(self) - } + self.typed_value( + |mut this| { + this.write_str("&_")?; + Ok(this) + }, + |this| this.print_type(ty), + ": ", + ) } fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> { @@ -1597,7 +1595,8 @@ pub trait PrettyPrinter<'tcx>: } // Aggregates, printed as array/tuple/struct/variant construction syntax. (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => { - let contents = self.tcx().destructure_const(self.tcx().mk_const(valtree, ty)); + let contents = + self.tcx().destructure_const(ty::Const::new_value(self.tcx(), valtree, ty)); let fields = contents.fields.iter().copied(); match *ty.kind() { ty::Array(..) => { @@ -1746,7 +1745,8 @@ impl DerefMut for FmtPrinter<'_, '_> { impl<'a, 'tcx> FmtPrinter<'a, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, ns: Namespace) -> Self { - Self::new_with_limit(tcx, ns, tcx.type_length_limit()) + let limit = if with_no_queries() { Limit::new(1048576) } else { tcx.type_length_limit() }; + Self::new_with_limit(tcx, ns, limit) } pub fn new_with_limit(tcx: TyCtxt<'tcx>, ns: Namespace, type_length_limit: Limit) -> Self { @@ -2150,7 +2150,6 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { self, p: Pointer<Prov>, ty: Ty<'tcx>, - print_ty: bool, ) -> Result<Self::Const, Self::Error> { let print = |mut this: Self| { define_scoped_cx!(this); @@ -2161,11 +2160,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { } Ok(this) }; - if print_ty { - self.typed_value(print, |this| this.print_type(ty), ": ") - } else { - print(self) - } + self.typed_value(print, |this| this.print_type(ty), ": ") } } @@ -2303,7 +2298,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> { }; if let ty::ReLateBound(debruijn1, br) = *region { assert_eq!(debruijn1, ty::INNERMOST); - self.tcx.mk_re_late_bound(self.current_index, br) + ty::Region::new_late_bound(self.tcx, self.current_index, br) } else { region } @@ -2415,7 +2410,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if let Some(lt_idx) = lifetime_idx { if lt_idx > binder_level_idx { let kind = ty::BrNamed(CRATE_DEF_ID.to_def_id(), name); - return tcx.mk_re_late_bound( + return ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, ); @@ -2430,7 +2426,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if let Some(lt_idx) = lifetime_idx { if lt_idx > binder_level_idx { let kind = ty::BrNamed(def_id, name); - return tcx.mk_re_late_bound( + return ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, ); @@ -2443,7 +2440,8 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { if let Some(lt_idx) = lifetime_idx { if lt_idx > binder_level_idx { let kind = br.kind; - return tcx.mk_re_late_bound( + return ty::Region::new_late_bound( + tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }, ); @@ -2458,7 +2456,11 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { start_or_continue(&mut self, "for<", ", "); do_continue(&mut self, name); } - tcx.mk_re_late_bound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }) + ty::Region::new_late_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: br.var, kind }, + ) }; let mut folder = RegionFolder { tcx, @@ -2734,7 +2736,7 @@ define_print_and_forward_display! { ty::ExistentialTraitRef<'tcx> { // Use a type that can't appear in defaults of type parameters. - let dummy_self = cx.tcx().mk_fresh_ty(0); + let dummy_self = Ty::new_fresh(cx.tcx(),0); let trait_ref = self.with_self_ty(cx.tcx(), dummy_self); p!(print(trait_ref.print_only_trait_path())) } @@ -2857,20 +2859,35 @@ define_print_and_forward_display! { p!(print(binder)) } + ty::Clause<'tcx> { + p!(print(self.kind())) + } + + ty::ClauseKind<'tcx> { + match *self { + ty::ClauseKind::Trait(ref data) => { + p!(print(data)) + } + ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)), + ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)), + ty::ClauseKind::Projection(predicate) => p!(print(predicate)), + ty::ClauseKind::ConstArgHasType(ct, ty) => { + p!("the constant `", print(ct), "` has type `", print(ty), "`") + }, + ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"), + ty::ClauseKind::ConstEvaluatable(ct) => { + p!("the constant `", print(ct), "` can be evaluated") + } + } + } + ty::PredicateKind<'tcx> { match *self { - ty::PredicateKind::Clause(ty::Clause::Trait(ref data)) => { + ty::PredicateKind::Clause(data) => { p!(print(data)) } ty::PredicateKind::Subtype(predicate) => p!(print(predicate)), ty::PredicateKind::Coerce(predicate) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => p!(print(predicate)), - ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { - p!("the constant `", print(ct), "` has type `", print(ty), "`") - }, - ty::PredicateKind::WellFormed(arg) => p!(print(arg), " well-formed"), ty::PredicateKind::ObjectSafe(trait_def_id) => { p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe") } @@ -2879,15 +2896,9 @@ define_print_and_forward_display! { print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind) ), - ty::PredicateKind::ConstEvaluatable(ct) => { - p!("the constant `", print(ct), "` can be evaluated") - } ty::PredicateKind::ConstEquate(c1, c2) => { p!("the constant `", print(c1), "` equals `", print(c2), "`") } - ty::PredicateKind::TypeWellFormedFromEnv(ty) => { - p!("the type `", print(ty), "` is found in the environment") - } ty::PredicateKind::Ambiguous => p!("ambiguous"), ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)), } @@ -2980,7 +2991,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N /// /// The implementation uses similar import discovery logic to that of 'use' suggestions. /// -/// See also [`DelayDm`](rustc_error_messages::DelayDm) and [`with_no_trimmed_paths`]. +/// See also [`DelayDm`](rustc_error_messages::DelayDm) and [`with_no_trimmed_paths!`]. fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> { let mut map: FxHashMap<DefId, Symbol> = FxHashMap::default(); @@ -3065,27 +3076,3 @@ pub struct OpaqueFnEntry<'tcx> { fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>, return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>, } - -pub fn debug_bound_var<T: std::fmt::Write>( - fmt: &mut T, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, -) -> Result<(), std::fmt::Error> { - if debruijn == ty::INNERMOST { - write!(fmt, "^{}", var.index()) - } else { - write!(fmt, "^{}_{}", debruijn.index(), var.index()) - } -} - -pub fn debug_placeholder_var<T: std::fmt::Write>( - fmt: &mut T, - universe: ty::UniverseIndex, - bound: ty::BoundVar, -) -> Result<(), std::fmt::Error> { - if universe == ty::UniverseIndex::ROOT { - write!(fmt, "!{}", bound.index()) - } else { - write!(fmt, "!{}_{}", universe.index(), bound.index()) - } -} diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 3bbe6a23b..5741832c9 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -391,13 +391,13 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> { /// Relates `a` and `b` structurally, calling the relation for all nested values. /// Any semantic equality, e.g. of projections, and inference variables have to be /// handled by the caller. +#[instrument(level = "trace", skip(relation), ret)] pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, a: Ty<'tcx>, b: Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> { let tcx = relation.tcx(); - debug!("structurally_relate_tys: a={:?} b={:?}", a, b); match (a.kind(), b.kind()) { (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { // The caller should handle these cases! @@ -408,7 +408,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( bug!("bound types encountered in structurally_relate_tys") } - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error(guar)), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), (&ty::Never, _) | (&ty::Char, _) @@ -428,10 +428,10 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def => { let substs = relation.relate_item_substs(a_def.did(), a_substs, b_substs)?; - Ok(tcx.mk_adt(a_def, substs)) + Ok(Ty::new_adt(tcx, a_def, substs)) } - (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)), + (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr)) if a_repr == b_repr => @@ -439,7 +439,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { relation.relate(a_region, b_region) })?; - Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr)) + Ok(Ty::new_dynamic(tcx, relation.relate(a_obj, b_obj)?, region_bound, a_repr)) } (&ty::Generator(a_id, a_substs, movability), &ty::Generator(b_id, b_substs, _)) @@ -449,7 +449,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // the (anonymous) type of the same generator expression. So // all of their regions should be equated. let substs = relation.relate(a_substs, b_substs)?; - Ok(tcx.mk_generator(a_id, substs, movability)) + Ok(Ty::new_generator(tcx, a_id, substs, movability)) } (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => { @@ -459,7 +459,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( let b_types = b_types.map_bound(GeneratorWitness); // Then remove the GeneratorWitness for the result let types = relation.relate(a_types, b_types)?.map_bound(|witness| witness.0); - Ok(tcx.mk_generator_witness(types)) + Ok(Ty::new_generator_witness(tcx, types)) } (&ty::GeneratorWitnessMIR(a_id, a_substs), &ty::GeneratorWitnessMIR(b_id, b_substs)) @@ -469,7 +469,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // the (anonymous) type of the same generator expression. So // all of their regions should be equated. let substs = relation.relate(a_substs, b_substs)?; - Ok(tcx.mk_generator_witness_mir(a_id, substs)) + Ok(Ty::new_generator_witness_mir(tcx, a_id, substs)) } (&ty::Closure(a_id, a_substs), &ty::Closure(b_id, b_substs)) if a_id == b_id => { @@ -477,12 +477,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // the (anonymous) type of the same closure expression. So // all of their regions should be equated. let substs = relation.relate(a_substs, b_substs)?; - Ok(tcx.mk_closure(a_id, &substs)) + Ok(Ty::new_closure(tcx, a_id, &substs)) } (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => { let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; - Ok(tcx.mk_ptr(mt)) + Ok(Ty::new_ptr(tcx, mt)) } (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { @@ -490,13 +490,13 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; - Ok(tcx.mk_ref(r, mt)) + Ok(Ty::new_ref(tcx, r, mt)) } (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => { let t = relation.relate(a_t, b_t)?; match relation.relate(sz_a, sz_b) { - Ok(sz) => Ok(tcx.mk_array_with_const_len(t, sz)), + Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), Err(err) => { // Check whether the lengths are both concrete/known values, // but are unequal, for better diagnostics. @@ -519,12 +519,15 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Slice(a_t), &ty::Slice(b_t)) => { let t = relation.relate(a_t, b_t)?; - Ok(tcx.mk_slice(t)) + Ok(Ty::new_slice(tcx, t)) } (&ty::Tuple(as_), &ty::Tuple(bs)) => { if as_.len() == bs.len() { - Ok(tcx.mk_tup_from_iter(iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)))?) + Ok(Ty::new_tup_from_iter( + tcx, + iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)), + )?) } else if !(as_.is_empty() || bs.is_empty()) { Err(TypeError::TupleSize(expected_found(relation, as_.len(), bs.len()))) } else { @@ -536,25 +539,16 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( if a_def_id == b_def_id => { let substs = relation.relate_item_substs(a_def_id, a_substs, b_substs)?; - Ok(tcx.mk_fn_def(a_def_id, substs)) + Ok(Ty::new_fn_def(tcx, a_def_id, substs)) } (&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => { let fty = relation.relate(a_fty, b_fty)?; - Ok(tcx.mk_fn_ptr(fty)) - } - - // these two are already handled downstream in case of lazy normalization - (&ty::Alias(ty::Projection, a_data), &ty::Alias(ty::Projection, b_data)) => { - let projection_ty = relation.relate(a_data, b_data)?; - Ok(tcx.mk_projection(projection_ty.def_id, projection_ty.substs)) - } - - (&ty::Alias(ty::Inherent, a_data), &ty::Alias(ty::Inherent, b_data)) => { - let alias_ty = relation.relate(a_data, b_data)?; - Ok(tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(alias_ty.def_id, alias_ty.substs))) + Ok(Ty::new_fn_ptr(tcx, fty)) } + // The substs of opaque types may not all be invariant, so we have + // to treat them separately from other aliases. ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }), @@ -568,7 +562,20 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( b_substs, false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle )?; - Ok(tcx.mk_opaque(a_def_id, substs)) + Ok(Ty::new_opaque(tcx, a_def_id, substs)) + } + + // Alias tend to mostly already be handled downstream due to normalization. + (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => { + // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This if can be removed + // and the assert uncommented once the new desugaring is stable. + if a_kind == b_kind { + let alias_ty = relation.relate(a_data, b_data)?; + // assert_eq!(a_kind, b_kind); + Ok(Ty::new_alias(tcx, a_kind, alias_ty)) + } else { + Err(TypeError::Sorts(expected_found(relation, a, b))) + } } _ => Err(TypeError::Sorts(expected_found(relation, a, b))), @@ -589,17 +596,6 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); - // HACK(const_generics): We still need to eagerly evaluate consts when - // relating them because during `normalize_param_env_or_error`, - // we may relate an evaluated constant in a obligation against - // an unnormalized (i.e. unevaluated) const in the param-env. - // FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants - // these `eval` calls can be removed. - if !tcx.features().generic_const_exprs { - a = a.eval(tcx, relation.param_env()); - b = b.eval(tcx, relation.param_env()); - } - if tcx.features().generic_const_exprs { a = tcx.expand_abstract_consts(a); b = tcx.expand_abstract_consts(b); @@ -634,7 +630,11 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( au.substs, bu.substs, )?; - return Ok(tcx.mk_const(ty::UnevaluatedConst { def: au.def, substs }, a.ty())); + return Ok(ty::Const::new_unevaluated( + tcx, + ty::UnevaluatedConst { def: au.def, substs }, + a.ty(), + )); } // Before calling relate on exprs, it is necessary to ensure that the nested consts // have identical types. @@ -675,8 +675,7 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( } _ => return Err(TypeError::ConstMismatch(expected_found(r, a, b))), }; - let kind = ty::ConstKind::Expr(expr); - return Ok(tcx.mk_const(kind, a.ty())); + return Ok(ty::Const::new_expr(tcx, expr, a.ty())); } _ => false, }; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 16cb6c910..7220d133f 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -11,6 +11,7 @@ use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_hir::def::Namespace; use rustc_index::{Idx, IndexVec}; use rustc_target::abi::TyAndLayout; +use rustc_type_ir::ConstKind; use std::fmt; use std::ops::ControlFlow; @@ -88,7 +89,35 @@ impl fmt::Debug for ty::FreeRegion { impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "({:?}; c_variadic: {})->{:?}", self.inputs(), self.c_variadic, self.output()) + let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = self; + + write!(f, "{}", unsafety.prefix_str())?; + match abi { + rustc_target::spec::abi::Abi::Rust => (), + abi => write!(f, "extern \"{abi:?}\" ")?, + }; + + write!(f, "fn(")?; + let inputs = self.inputs(); + match inputs.len() { + 0 if *c_variadic => write!(f, "...)")?, + 0 => write!(f, ")")?, + _ => { + for ty in &self.inputs()[0..(self.inputs().len() - 1)] { + write!(f, "{ty:?}, ")?; + } + write!(f, "{:?}", self.inputs().last().unwrap())?; + if *c_variadic { + write!(f, "...")?; + } + write!(f, ")")?; + } + } + + match self.output().kind() { + ty::Tuple(list) if list.is_empty() => Ok(()), + _ => write!(f, " -> {:?}", self.output()), + } } } @@ -145,12 +174,22 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { impl<'tcx> fmt::Debug for ty::Clause<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind()) + } +} + +impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ty::Clause::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), - ty::Clause::Trait(ref a) => a.fmt(f), - ty::Clause::RegionOutlives(ref pair) => pair.fmt(f), - ty::Clause::TypeOutlives(ref pair) => pair.fmt(f), - ty::Clause::Projection(ref pair) => pair.fmt(f), + ty::ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), + ty::ClauseKind::Trait(ref a) => a.fmt(f), + ty::ClauseKind::RegionOutlives(ref pair) => pair.fmt(f), + ty::ClauseKind::TypeOutlives(ref pair) => pair.fmt(f), + ty::ClauseKind::Projection(ref pair) => pair.fmt(f), + ty::ClauseKind::WellFormed(ref data) => write!(f, "WellFormed({:?})", data), + ty::ClauseKind::ConstEvaluatable(ct) => { + write!(f, "ConstEvaluatable({ct:?})") + } } } } @@ -161,20 +200,13 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::Clause(ref a) => a.fmt(f), ty::PredicateKind::Subtype(ref pair) => pair.fmt(f), ty::PredicateKind::Coerce(ref pair) => pair.fmt(f), - ty::PredicateKind::WellFormed(data) => write!(f, "WellFormed({:?})", data), ty::PredicateKind::ObjectSafe(trait_def_id) => { write!(f, "ObjectSafe({:?})", trait_def_id) } ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) } - ty::PredicateKind::ConstEvaluatable(ct) => { - write!(f, "ConstEvaluatable({ct:?})") - } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), - ty::PredicateKind::TypeWellFormedFromEnv(ty) => { - write!(f, "TypeWellFormedFromEnv({:?})", ty) - } ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"), ty::PredicateKind::AliasRelate(t1, t2, dir) => { write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})") @@ -210,22 +242,21 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ConstKind<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use ty::ConstKind::*; - match self { - Param(param) => write!(f, "{param:?}"), - Infer(var) => write!(f, "{var:?}"), - Bound(debruijn, var) => ty::print::debug_bound_var(f, *debruijn, *var), - Placeholder(placeholder) => { - ty::print::debug_placeholder_var(f, placeholder.universe, placeholder.bound) - } - Unevaluated(uv) => { - f.debug_tuple("Unevaluated").field(&uv.substs).field(&uv.def).finish() - } - Value(valtree) => write!(f, "{valtree:?}"), - Error(_) => write!(f, "[const error]"), - Expr(expr) => write!(f, "{expr:?}"), +impl fmt::Debug for ty::BoundTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.kind { + ty::BoundTyKind::Anon => write!(f, "{:?}", self.var), + ty::BoundTyKind::Param(_, sym) => write!(f, "{sym:?}"), + } + } +} + +impl<T: fmt::Debug> fmt::Debug for ty::Placeholder<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.universe == ty::UniverseIndex::ROOT { + write!(f, "!{:?}", self.bound) + } else { + write!(f, "!{}_{:?}", self.universe.index(), self.bound) } } } @@ -294,13 +325,14 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::AliasRelationDirection, crate::ty::Placeholder<crate::ty::BoundRegion>, crate::ty::Placeholder<crate::ty::BoundTy>, + crate::ty::Placeholder<ty::BoundVar>, crate::ty::ClosureKind, crate::ty::FreeRegion, crate::ty::InferTy, crate::ty::IntVarValue, crate::ty::ParamConst, crate::ty::ParamTy, - crate::ty::adjustment::PointerCast, + crate::ty::adjustment::PointerCoercion, crate::ty::RegionVid, crate::ty::UniverseIndex, crate::ty::Variance, @@ -310,7 +342,6 @@ TrivialTypeTraversalAndLiftImpls! { interpret::Scalar, rustc_target::abi::Size, ty::BoundVar, - ty::Placeholder<ty::BoundVar>, } TrivialTypeTraversalAndLiftImpls! { @@ -609,12 +640,28 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { } } +// FIXME(clause): This is wonky +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clause<'tcx> { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause()) + } +} + impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { visitor.visit_predicate(*self) } } +impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Clause<'tcx> { + fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + visitor.visit_predicate(self.as_predicate()) + } +} + impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, @@ -634,12 +681,12 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { } } -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Predicate<'tcx>> { +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Clause<'tcx>> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, folder: &mut F, ) -> Result<Self, F::Error> { - ty::util::fold_list(self, folder, |tcx, v| tcx.mk_predicates(v)) + ty::util::fold_list(self, folder, |tcx, v| tcx.mk_clauses(v)) } } @@ -664,9 +711,20 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { folder: &mut F, ) -> Result<Self, F::Error> { let ty = self.ty().try_fold_with(folder)?; - let kind = self.kind().try_fold_with(folder)?; + let kind = match self.kind() { + ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?), + ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?), + ConstKind::Bound(d, b) => { + ConstKind::Bound(d.try_fold_with(folder)?, b.try_fold_with(folder)?) + } + ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?), + ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), + ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), + ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), + ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), + }; if ty != self.ty() || kind != self.kind() { - Ok(folder.interner().mk_const(kind, ty)) + Ok(folder.interner().mk_ct_from_kind(kind, ty)) } else { Ok(self) } @@ -679,7 +737,19 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { visitor: &mut V, ) -> ControlFlow<V::BreakTy> { self.ty().visit_with(visitor)?; - self.kind().visit_with(visitor) + match self.kind() { + ConstKind::Param(p) => p.visit_with(visitor), + ConstKind::Infer(i) => i.visit_with(visitor), + ConstKind::Bound(d, b) => { + d.visit_with(visitor)?; + b.visit_with(visitor) + } + ConstKind::Placeholder(p) => p.visit_with(visitor), + ConstKind::Unevaluated(uv) => uv.visit_with(visitor), + ConstKind::Value(v) => v.visit_with(visitor), + ConstKind::Error(e) => e.visit_with(visitor), + ConstKind::Expr(e) => e.visit_with(visitor), + } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e6d51c4ec..94746fbdc 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -15,16 +15,18 @@ use hir::def::DefKind; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; -use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; +use rustc_error_messages::DiagnosticMessage; +use rustc_errors::{DiagnosticArgValue, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::LangItem; use rustc_index::Idx; use rustc_macros::HashStable; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi::{self, Abi}; +use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::cmp::Ordering; use std::fmt; @@ -33,13 +35,17 @@ use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; use rustc_type_ir::sty::TyKind::*; -use rustc_type_ir::RegionKind as IrRegionKind; use rustc_type_ir::TyKind as IrTyKind; +use rustc_type_ir::{CollectAndApply, ConstKind as IrConstKind}; +use rustc_type_ir::{DynKind, RegionKind as IrRegionKind}; + +use super::GenericParamDefKind; // Re-export the `TyKind` from `rustc_type_ir` here for convenience #[rustc_diagnostic_item = "TyKind"] pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>; pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>; +pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] @@ -568,7 +574,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { let layout = tcx.generator_layout(def_id).unwrap(); layout.variant_fields.iter().map(move |variant| { variant.iter().map(move |field| { - ty::EarlyBinder(layout.field_tys[*field].ty).subst(tcx, self.substs) + ty::EarlyBinder::bind(layout.field_tys[*field].ty).subst(tcx, self.substs) }) }) } @@ -715,7 +721,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> { /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`), /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example). - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { + pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> { use crate::ty::ToPredicate; match self.skip_binder() { ExistentialPredicate::Trait(tr) => { @@ -1007,7 +1013,10 @@ impl BoundVariableKind { /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(HashStable, Lift)] -pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>); +pub struct Binder<'tcx, T> { + value: T, + bound_vars: &'tcx List<BoundVariableKind>, +} impl<'tcx, T> Binder<'tcx, T> where @@ -1023,15 +1032,15 @@ where !value.has_escaping_bound_vars(), "`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder." ); - Binder(value, ty::List::empty()) + Binder { value, bound_vars: ty::List::empty() } } - pub fn bind_with_vars(value: T, vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> { + pub fn bind_with_vars(value: T, bound_vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> { if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(vars); + let mut validator = ValidateBoundVars::new(bound_vars); value.visit_with(&mut validator); } - Binder(value, vars) + Binder { value, bound_vars } } } @@ -1053,30 +1062,30 @@ impl<'tcx, T> Binder<'tcx, T> { /// - comparing the self type of a PolyTraitRef to see if it is equal to /// a type parameter `X`, since the type `X` does not reference any regions pub fn skip_binder(self) -> T { - self.0 + self.value } pub fn bound_vars(&self) -> &'tcx List<BoundVariableKind> { - self.1 + self.bound_vars } pub fn as_ref(&self) -> Binder<'tcx, &T> { - Binder(&self.0, self.1) + Binder { value: &self.value, bound_vars: self.bound_vars } } pub fn as_deref(&self) -> Binder<'tcx, &T::Target> where T: Deref, { - Binder(&self.0, self.1) + Binder { value: &self.value, bound_vars: self.bound_vars } } pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U> where F: FnOnce(&T) -> U, { - let value = f(&self.0); - Binder(value, self.1) + let value = f(&self.value); + Binder { value, bound_vars: self.bound_vars } } pub fn map_bound_ref<F, U: TypeVisitable<TyCtxt<'tcx>>>(&self, f: F) -> Binder<'tcx, U> @@ -1090,12 +1099,13 @@ impl<'tcx, T> Binder<'tcx, T> { where F: FnOnce(T) -> U, { - let value = f(self.0); + let Binder { value, bound_vars } = self; + let value = f(value); if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(self.1); + let mut validator = ValidateBoundVars::new(bound_vars); value.visit_with(&mut validator); } - Binder(value, self.1) + Binder { value, bound_vars } } pub fn try_map_bound<F, U: TypeVisitable<TyCtxt<'tcx>>, E>( @@ -1105,12 +1115,13 @@ impl<'tcx, T> Binder<'tcx, T> { where F: FnOnce(T) -> Result<U, E>, { - let value = f(self.0)?; + let Binder { value, bound_vars } = self; + let value = f(value)?; if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(self.1); + let mut validator = ValidateBoundVars::new(bound_vars); value.visit_with(&mut validator); } - Ok(Binder(value, self.1)) + Ok(Binder { value, bound_vars }) } /// Wraps a `value` in a binder, using the same bound variables as the @@ -1126,11 +1137,7 @@ impl<'tcx, T> Binder<'tcx, T> { where U: TypeVisitable<TyCtxt<'tcx>>, { - if cfg!(debug_assertions) { - let mut validator = ValidateBoundVars::new(self.bound_vars()); - value.visit_with(&mut validator); - } - Binder(value, self.1) + Binder::bind_with_vars(value, self.bound_vars) } /// Unwraps and returns the value within, but only if it contains @@ -1147,7 +1154,7 @@ impl<'tcx, T> Binder<'tcx, T> { where T: TypeVisitable<TyCtxt<'tcx>>, { - if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } + if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } } /// Splits the contents into two things that share the same binder @@ -1160,22 +1167,23 @@ impl<'tcx, T> Binder<'tcx, T> { where F: FnOnce(T) -> (U, V), { - let (u, v) = f(self.0); - (Binder(u, self.1), Binder(v, self.1)) + let Binder { value, bound_vars } = self; + let (u, v) = f(value); + (Binder { value: u, bound_vars }, Binder { value: v, bound_vars }) } } impl<'tcx, T> Binder<'tcx, Option<T>> { pub fn transpose(self) -> Option<Binder<'tcx, T>> { - let bound_vars = self.1; - self.0.map(|v| Binder(v, bound_vars)) + let Binder { value, bound_vars } = self; + value.map(|value| Binder { value, bound_vars }) } } impl<'tcx, T: IntoIterator> Binder<'tcx, T> { pub fn iter(self) -> impl Iterator<Item = ty::Binder<'tcx, T::Item>> { - let bound_vars = self.1; - self.0.into_iter().map(|v| Binder(v, bound_vars)) + let Binder { value, bound_vars } = self; + value.into_iter().map(|value| Binder { value, bound_vars }) } } @@ -1184,7 +1192,7 @@ where T: IntoDiagnosticArg, { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.0.into_diagnostic_arg() + self.value.into_diagnostic_arg() } } @@ -1231,12 +1239,13 @@ impl<'tcx> AliasTy<'tcx> { DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent, DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection, DefKind::OpaqueTy => ty::Opaque, + DefKind::TyAlias => ty::Weak, kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), } } pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_alias(self.kind(tcx), self) + Ty::new_alias(tcx, self.kind(tcx), self) } } @@ -1427,7 +1436,7 @@ impl<'tcx> ParamTy { #[inline] pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - tcx.mk_ty_param(self.index, self.name) + Ty::new_param(tcx, self.index, self.name) } pub fn span_from_generics(&self, tcx: TyCtxt<'tcx>, item_with_generics: DefId) -> Span { @@ -1459,6 +1468,103 @@ impl ParamConst { #[rustc_pass_by_value] pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); +impl<'tcx> Region<'tcx> { + #[inline] + pub fn new_early_bound( + tcx: TyCtxt<'tcx>, + early_bound_region: ty::EarlyBoundRegion, + ) -> Region<'tcx> { + tcx.intern_region(ty::ReEarlyBound(early_bound_region)) + } + + #[inline] + pub fn new_late_bound( + tcx: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + bound_region: ty::BoundRegion, + ) -> Region<'tcx> { + // Use a pre-interned one when possible. + if let ty::BoundRegion { var, kind: ty::BrAnon(None) } = bound_region + && let Some(inner) = tcx.lifetimes.re_late_bounds.get(debruijn.as_usize()) + && let Some(re) = inner.get(var.as_usize()).copied() + { + re + } else { + tcx.intern_region(ty::ReLateBound(debruijn, bound_region)) + } + } + + #[inline] + pub fn new_free( + tcx: TyCtxt<'tcx>, + scope: DefId, + bound_region: ty::BoundRegionKind, + ) -> Region<'tcx> { + tcx.intern_region(ty::ReFree(ty::FreeRegion { scope, bound_region })) + } + + #[inline] + pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::RegionVid) -> Region<'tcx> { + // Use a pre-interned one when possible. + tcx.lifetimes + .re_vars + .get(v.as_usize()) + .copied() + .unwrap_or_else(|| tcx.intern_region(ty::ReVar(v))) + } + + #[inline] + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Region<'tcx> { + tcx.intern_region(ty::RePlaceholder(placeholder)) + } + + /// Constructs a `RegionKind::ReError` region. + #[track_caller] + pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Region<'tcx> { + tcx.intern_region(ty::ReError(reported)) + } + + /// Constructs a `RegionKind::ReError` region and registers a `delay_span_bug` to ensure it + /// gets used. + #[track_caller] + pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> { + Region::new_error_with_message( + tcx, + DUMMY_SP, + "RegionKind::ReError constructed but no error reported", + ) + } + + /// Constructs a `RegionKind::ReError` region and registers a `delay_span_bug` with the given + /// `msg` to ensure it gets used. + #[track_caller] + pub fn new_error_with_message<S: Into<MultiSpan>>( + tcx: TyCtxt<'tcx>, + span: S, + msg: &'static str, + ) -> Region<'tcx> { + let reported = tcx.sess.delay_span_bug(span, msg); + Region::new_error(tcx, reported) + } + + /// Avoid this in favour of more specific `new_*` methods, where possible, + /// to avoid the cost of the `match`. + pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> { + match kind { + ty::ReEarlyBound(region) => Region::new_early_bound(tcx, region), + ty::ReLateBound(debruijn, region) => Region::new_late_bound(tcx, debruijn, region), + ty::ReFree(ty::FreeRegion { scope, bound_region }) => { + Region::new_free(tcx, scope, bound_region) + } + ty::ReStatic => tcx.lifetimes.re_static, + ty::ReVar(vid) => Region::new_var(tcx, vid), + ty::RePlaceholder(region) => Region::new_placeholder(tcx, region), + ty::ReErased => tcx.lifetimes.re_erased, + ty::ReError(reported) => Region::new_error(tcx, reported), + } + } +} + impl<'tcx> Deref for Region<'tcx> { type Target = RegionKind<'tcx>; @@ -1484,7 +1590,7 @@ pub struct EarlyBoundRegion { impl fmt::Debug for EarlyBoundRegion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}, {}", self.index, self.name) + write!(f, "{:?}, {}, {}", self.def_id, self.index, self.name) } } @@ -1511,10 +1617,11 @@ impl Atom for RegionVid { rustc_index::newtype_index! { #[derive(HashStable)] + #[debug_format = "{}"] pub struct BoundVar {} } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct BoundTy { pub var: BoundVar, @@ -1770,6 +1877,390 @@ impl<'tcx> Region<'tcx> { } } +/// Constructors for `Ty` +impl<'tcx> Ty<'tcx> { + // Avoid this in favour of more specific `new_*` methods, where possible. + #[allow(rustc::usage_of_ty_tykind)] + #[inline] + pub fn new(tcx: TyCtxt<'tcx>, st: TyKind<'tcx>) -> Ty<'tcx> { + tcx.mk_ty_from_kind(st) + } + + #[inline] + pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Ty<'tcx> { + Ty::new(tcx, TyKind::Infer(infer)) + } + + #[inline] + pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::TyVid) -> Ty<'tcx> { + // Use a pre-interned one when possible. + tcx.types + .ty_vars + .get(v.as_usize()) + .copied() + .unwrap_or_else(|| Ty::new(tcx, Infer(TyVar(v)))) + } + + #[inline] + pub fn new_int_var(tcx: TyCtxt<'tcx>, v: ty::IntVid) -> Ty<'tcx> { + Ty::new_infer(tcx, IntVar(v)) + } + + #[inline] + pub fn new_float_var(tcx: TyCtxt<'tcx>, v: ty::FloatVid) -> Ty<'tcx> { + Ty::new_infer(tcx, FloatVar(v)) + } + + #[inline] + pub fn new_fresh(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> { + // Use a pre-interned one when possible. + tcx.types + .fresh_tys + .get(n as usize) + .copied() + .unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshTy(n))) + } + + #[inline] + pub fn new_fresh_int(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> { + // Use a pre-interned one when possible. + tcx.types + .fresh_int_tys + .get(n as usize) + .copied() + .unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshIntTy(n))) + } + + #[inline] + pub fn new_fresh_float(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> { + // Use a pre-interned one when possible. + tcx.types + .fresh_float_tys + .get(n as usize) + .copied() + .unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshFloatTy(n))) + } + + #[inline] + pub fn new_param(tcx: TyCtxt<'tcx>, index: u32, name: Symbol) -> Ty<'tcx> { + tcx.mk_ty_from_kind(Param(ParamTy { index, name })) + } + + #[inline] + pub fn new_bound( + tcx: TyCtxt<'tcx>, + index: ty::DebruijnIndex, + bound_ty: ty::BoundTy, + ) -> Ty<'tcx> { + Ty::new(tcx, Bound(index, bound_ty)) + } + + #[inline] + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType) -> Ty<'tcx> { + Ty::new(tcx, Placeholder(placeholder)) + } + + #[inline] + pub fn new_alias( + tcx: TyCtxt<'tcx>, + kind: ty::AliasKind, + alias_ty: ty::AliasTy<'tcx>, + ) -> Ty<'tcx> { + debug_assert_matches!( + (kind, tcx.def_kind(alias_ty.def_id)), + (ty::Opaque, DefKind::OpaqueTy) + | (ty::Projection | ty::Inherent, DefKind::AssocTy) + | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder) + | (ty::Weak, DefKind::TyAlias) + ); + Ty::new(tcx, Alias(kind, alias_ty)) + } + + #[inline] + pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { + Ty::new_alias(tcx, ty::Opaque, tcx.mk_alias_ty(def_id, substs)) + } + + /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed` + pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Ty<'tcx> { + Ty::new(tcx, Error(reported)) + } + + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. + #[track_caller] + pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + Ty::new_error_with_message(tcx, DUMMY_SP, "TyKind::Error constructed but no error reported") + } + + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to + /// ensure it gets used. + #[track_caller] + pub fn new_error_with_message<S: Into<MultiSpan>>( + tcx: TyCtxt<'tcx>, + span: S, + msg: impl Into<DiagnosticMessage>, + ) -> Ty<'tcx> { + let reported = tcx.sess.delay_span_bug(span, msg); + Ty::new(tcx, Error(reported)) + } + + #[inline] + pub fn new_int(tcx: TyCtxt<'tcx>, i: ty::IntTy) -> Ty<'tcx> { + use ty::IntTy::*; + match i { + Isize => tcx.types.isize, + I8 => tcx.types.i8, + I16 => tcx.types.i16, + I32 => tcx.types.i32, + I64 => tcx.types.i64, + I128 => tcx.types.i128, + } + } + + #[inline] + pub fn new_uint(tcx: TyCtxt<'tcx>, ui: ty::UintTy) -> Ty<'tcx> { + use ty::UintTy::*; + match ui { + Usize => tcx.types.usize, + U8 => tcx.types.u8, + U16 => tcx.types.u16, + U32 => tcx.types.u32, + U64 => tcx.types.u64, + U128 => tcx.types.u128, + } + } + + #[inline] + pub fn new_float(tcx: TyCtxt<'tcx>, f: ty::FloatTy) -> Ty<'tcx> { + use ty::FloatTy::*; + match f { + F32 => tcx.types.f32, + F64 => tcx.types.f64, + } + } + + #[inline] + pub fn new_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, Ref(r, tm.ty, tm.mutbl)) + } + + #[inline] + pub fn new_mut_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new_ref(tcx, r, TypeAndMut { ty, mutbl: hir::Mutability::Mut }) + } + + #[inline] + pub fn new_imm_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new_ref(tcx, r, TypeAndMut { ty, mutbl: hir::Mutability::Not }) + } + + #[inline] + pub fn new_ptr(tcx: TyCtxt<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, RawPtr(tm)) + } + + #[inline] + pub fn new_mut_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: hir::Mutability::Mut }) + } + + #[inline] + pub fn new_imm_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: hir::Mutability::Not }) + } + + #[inline] + pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, Adt(def, substs)) + } + + #[inline] + pub fn new_foreign(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { + Ty::new(tcx, Foreign(def_id)) + } + + #[inline] + pub fn new_array(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { + Ty::new(tcx, Array(ty, ty::Const::from_target_usize(tcx, n))) + } + + #[inline] + pub fn new_array_with_const_len( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + ct: ty::Const<'tcx>, + ) -> Ty<'tcx> { + Ty::new(tcx, Array(ty, ct)) + } + + #[inline] + pub fn new_slice(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, Slice(ty)) + } + + #[inline] + pub fn new_tup(tcx: TyCtxt<'tcx>, ts: &[Ty<'tcx>]) -> Ty<'tcx> { + if ts.is_empty() { tcx.types.unit } else { Ty::new(tcx, Tuple(tcx.mk_type_list(&ts))) } + } + + pub fn new_tup_from_iter<I, T>(tcx: TyCtxt<'tcx>, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Ty<'tcx>, Ty<'tcx>>, + { + T::collect_and_apply(iter, |ts| Ty::new_tup(tcx, ts)) + } + + #[inline] + pub fn new_fn_def( + tcx: TyCtxt<'tcx>, + def_id: DefId, + substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, + ) -> Ty<'tcx> { + let substs = tcx.check_and_mk_substs(def_id, substs); + Ty::new(tcx, FnDef(def_id, substs)) + } + + #[inline] + pub fn new_fn_ptr(tcx: TyCtxt<'tcx>, fty: PolyFnSig<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, FnPtr(fty)) + } + + #[inline] + pub fn new_dynamic( + tcx: TyCtxt<'tcx>, + obj: &'tcx List<PolyExistentialPredicate<'tcx>>, + reg: ty::Region<'tcx>, + repr: DynKind, + ) -> Ty<'tcx> { + Ty::new(tcx, Dynamic(obj, reg, repr)) + } + + #[inline] + pub fn new_projection( + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, + ) -> Ty<'tcx> { + Ty::new_alias(tcx, ty::Projection, tcx.mk_alias_ty(item_def_id, substs)) + } + + #[inline] + pub fn new_closure( + tcx: TyCtxt<'tcx>, + def_id: DefId, + closure_substs: SubstsRef<'tcx>, + ) -> Ty<'tcx> { + debug_assert_eq!( + closure_substs.len(), + tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3, + "closure constructed with incorrect substitutions" + ); + Ty::new(tcx, Closure(def_id, closure_substs)) + } + + #[inline] + pub fn new_generator( + tcx: TyCtxt<'tcx>, + def_id: DefId, + generator_substs: SubstsRef<'tcx>, + movability: hir::Movability, + ) -> Ty<'tcx> { + debug_assert_eq!( + generator_substs.len(), + tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, + "generator constructed with incorrect number of substitutions" + ); + Ty::new(tcx, Generator(def_id, generator_substs, movability)) + } + + #[inline] + pub fn new_generator_witness( + tcx: TyCtxt<'tcx>, + types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>, + ) -> Ty<'tcx> { + Ty::new(tcx, GeneratorWitness(types)) + } + + #[inline] + pub fn new_generator_witness_mir( + tcx: TyCtxt<'tcx>, + id: DefId, + substs: SubstsRef<'tcx>, + ) -> Ty<'tcx> { + Ty::new(tcx, GeneratorWitnessMIR(id, substs)) + } + + // misc + + #[inline] + pub fn new_unit(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + tcx.types.unit + } + + #[inline] + pub fn new_static_str(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_) + } + + #[inline] + pub fn new_diverging_default(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + if tcx.features().never_type_fallback { tcx.types.never } else { tcx.types.unit } + } + + // lang and diagnostic tys + + fn new_generic_adt(tcx: TyCtxt<'tcx>, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> { + let adt_def = tcx.adt_def(wrapper_def_id); + let substs = + InternalSubsts::for_item(tcx, wrapper_def_id, |param, substs| match param.kind { + GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => bug!(), + GenericParamDefKind::Type { has_default, .. } => { + if param.index == 0 { + ty_param.into() + } else { + assert!(has_default); + tcx.type_of(param.def_id).subst(tcx, substs).into() + } + } + }); + Ty::new(tcx, Adt(adt_def, substs)) + } + + #[inline] + pub fn new_lang_item(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> { + let def_id = tcx.lang_items().get(item)?; + Some(Ty::new_generic_adt(tcx, def_id, ty)) + } + + #[inline] + pub fn new_diagnostic_item(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> { + let def_id = tcx.get_diagnostic_item(name)?; + Some(Ty::new_generic_adt(tcx, def_id, ty)) + } + + #[inline] + pub fn new_box(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + let def_id = tcx.require_lang_item(LangItem::OwnedBox, None); + Ty::new_generic_adt(tcx, def_id, ty) + } + + #[inline] + pub fn new_maybe_uninit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); + Ty::new_generic_adt(tcx, def_id, ty) + } + + /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes. + pub fn new_task_context(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + let context_did = tcx.require_lang_item(LangItem::Context, None); + let context_adt_ref = tcx.adt_def(context_did); + let context_substs = tcx.mk_substs(&[tcx.lifetimes.re_erased.into()]); + let context_ty = Ty::new_adt(tcx, context_adt_ref, context_substs); + Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, context_ty) + } +} + /// Type utilities impl<'tcx> Ty<'tcx> { #[inline(always)] @@ -2213,7 +2704,7 @@ impl<'tcx> Ty<'tcx> { let assoc_items = tcx.associated_item_def_ids( tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), ); - tcx.mk_projection(assoc_items[0], tcx.mk_substs(&[self.into()])) + Ty::new_projection(tcx, assoc_items[0], tcx.mk_substs(&[self.into()])) } ty::Bool @@ -2366,7 +2857,7 @@ impl<'tcx> Ty<'tcx> { ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)), - ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(), + ty::Adt(def, _substs) => def.sized_constraint(tcx).skip_binder().is_empty(), ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false, diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 43f95635a..4d5f5b865 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -11,6 +11,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; +use rustc_span::sym; use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; @@ -451,6 +452,10 @@ impl<'tcx> InternalSubsts<'tcx> { pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> { tcx.mk_substs_from_iter(self.iter().take(generics.count())) } + + pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> { + self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host)) + } } impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> { @@ -538,15 +543,21 @@ impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for &'tcx /// [`subst_identity`](EarlyBinder::subst_identity) or [`skip_binder`](EarlyBinder::skip_binder). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable)] -pub struct EarlyBinder<T>(pub T); +pub struct EarlyBinder<T> { + value: T, +} /// For early binders, you should first call `subst` before using any visitors. impl<'tcx, T> !TypeFoldable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {} impl<'tcx, T> !TypeVisitable<TyCtxt<'tcx>> for ty::EarlyBinder<T> {} impl<T> EarlyBinder<T> { + pub fn bind(value: T) -> EarlyBinder<T> { + EarlyBinder { value } + } + pub fn as_ref(&self) -> EarlyBinder<&T> { - EarlyBinder(&self.0) + EarlyBinder { value: &self.value } } pub fn map_bound_ref<F, U>(&self, f: F) -> EarlyBinder<U> @@ -560,20 +571,20 @@ impl<T> EarlyBinder<T> { where F: FnOnce(T) -> U, { - let value = f(self.0); - EarlyBinder(value) + let value = f(self.value); + EarlyBinder { value } } pub fn try_map_bound<F, U, E>(self, f: F) -> Result<EarlyBinder<U>, E> where F: FnOnce(T) -> Result<U, E>, { - let value = f(self.0)?; - Ok(EarlyBinder(value)) + let value = f(self.value)?; + Ok(EarlyBinder { value }) } pub fn rebind<U>(&self, value: U) -> EarlyBinder<U> { - EarlyBinder(value) + EarlyBinder { value } } /// Skips the binder and returns the "bound" value. @@ -582,22 +593,26 @@ impl<T> EarlyBinder<T> { /// arguments of an `FnSig`). Otherwise, consider using /// [`subst_identity`](EarlyBinder::subst_identity). /// + /// To skip the binder on `x: &EarlyBinder<T>` to obtain `&T`, leverage + /// [`EarlyBinder::as_ref`](EarlyBinder::as_ref): `x.as_ref().skip_binder()`. + /// /// See also [`Binder::skip_binder`](super::Binder::skip_binder), which is /// the analogous operation on [`super::Binder`]. pub fn skip_binder(self) -> T { - self.0 + self.value } } impl<T> EarlyBinder<Option<T>> { pub fn transpose(self) -> Option<EarlyBinder<T>> { - self.0.map(|v| EarlyBinder(v)) + self.value.map(|value| EarlyBinder { value }) } } impl<T, U> EarlyBinder<(T, U)> { pub fn transpose_tuple2(self) -> (EarlyBinder<T>, EarlyBinder<U>) { - (EarlyBinder(self.0.0), EarlyBinder(self.0.1)) + let EarlyBinder { value: (lhs, rhs) } = self; + (EarlyBinder { value: lhs }, EarlyBinder { value: rhs }) } } @@ -610,13 +625,13 @@ where tcx: TyCtxt<'tcx>, substs: &'s [GenericArg<'tcx>], ) -> SubstIter<'s, 'tcx, I> { - SubstIter { it: self.0.into_iter(), tcx, substs } + SubstIter { it: self.value.into_iter(), tcx, substs } } /// Similar to [`subst_identity`](EarlyBinder::subst_identity), /// but on an iterator of `TypeFoldable` values. pub fn subst_identity_iter(self) -> I::IntoIter { - self.0.into_iter() + self.value.into_iter() } } @@ -633,7 +648,7 @@ where type Item = I::Item; fn next(&mut self) -> Option<Self::Item> { - Some(EarlyBinder(self.it.next()?).subst(self.tcx, self.substs)) + Some(EarlyBinder { value: self.it.next()? }.subst(self.tcx, self.substs)) } fn size_hint(&self) -> (usize, Option<usize>) { @@ -647,7 +662,7 @@ where I::Item: TypeFoldable<TyCtxt<'tcx>>, { fn next_back(&mut self) -> Option<Self::Item> { - Some(EarlyBinder(self.it.next_back()?).subst(self.tcx, self.substs)) + Some(EarlyBinder { value: self.it.next_back()? }.subst(self.tcx, self.substs)) } } @@ -668,13 +683,13 @@ where tcx: TyCtxt<'tcx>, substs: &'s [GenericArg<'tcx>], ) -> SubstIterCopied<'s, 'tcx, I> { - SubstIterCopied { it: self.0.into_iter(), tcx, substs } + SubstIterCopied { it: self.value.into_iter(), tcx, substs } } /// Similar to [`subst_identity`](EarlyBinder::subst_identity), /// but on an iterator of values that deref to a `TypeFoldable`. pub fn subst_identity_iter_copied(self) -> impl Iterator<Item = <I::Item as Deref>::Target> { - self.0.into_iter().map(|v| *v) + self.value.into_iter().map(|v| *v) } } @@ -692,7 +707,7 @@ where type Item = <I::Item as Deref>::Target; fn next(&mut self) -> Option<Self::Item> { - Some(EarlyBinder(*self.it.next()?).subst(self.tcx, self.substs)) + self.it.next().map(|value| EarlyBinder { value: *value }.subst(self.tcx, self.substs)) } fn size_hint(&self) -> (usize, Option<usize>) { @@ -707,7 +722,7 @@ where <I::Item as Deref>::Target: Copy + TypeFoldable<TyCtxt<'tcx>>, { fn next_back(&mut self) -> Option<Self::Item> { - Some(EarlyBinder(*self.it.next_back()?).subst(self.tcx, self.substs)) + self.it.next_back().map(|value| EarlyBinder { value: *value }.subst(self.tcx, self.substs)) } } @@ -725,7 +740,7 @@ pub struct EarlyBinderIter<T> { impl<T: IntoIterator> EarlyBinder<T> { pub fn transpose_iter(self) -> EarlyBinderIter<T::IntoIter> { - EarlyBinderIter { t: self.0.into_iter() } + EarlyBinderIter { t: self.value.into_iter() } } } @@ -733,7 +748,7 @@ impl<T: Iterator> Iterator for EarlyBinderIter<T> { type Item = EarlyBinder<T::Item>; fn next(&mut self) -> Option<Self::Item> { - self.t.next().map(|i| EarlyBinder(i)) + self.t.next().map(|value| EarlyBinder { value }) } fn size_hint(&self) -> (usize, Option<usize>) { @@ -744,7 +759,7 @@ impl<T: Iterator> Iterator for EarlyBinderIter<T> { impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> { pub fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T { let mut folder = SubstFolder { tcx, substs, binders_passed: 0 }; - self.0.fold_with(&mut folder) + self.value.fold_with(&mut folder) } /// Makes the identity substitution `T0 => T0, ..., TN => TN`. @@ -756,12 +771,12 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> { /// - Inside of the body of `foo`, we treat `T` as a placeholder by calling /// `subst_identity` to discharge the `EarlyBinder`. pub fn subst_identity(self) -> T { - self.0 + self.value } /// Returns the inner value, but only if it contains no bound vars. pub fn no_bound_vars(self) -> Option<T> { - if !self.0.has_param() { Some(self.0) } else { None } + if !self.value.has_param() { Some(self.value) } else { None } } } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index e61037e5e..98c70e330 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -52,6 +52,16 @@ pub struct TraitDef { /// List of functions from `#[rustc_must_implement_one_of]` attribute one of which /// must be implemented. pub must_implement_one_of: Option<Box<[Ident]>>, + + /// Whether to add a builtin `dyn Trait: Trait` implementation. + /// This is enabled for all traits except ones marked with + /// `#[rustc_deny_explicit_impl(implement_via_object = false)]`. + pub implement_via_object: bool, + + /// Whether a trait is fully built-in, and any implementation is disallowed. + /// This only applies to built-in traits, and is marked via + /// `#[rustc_deny_explicit_impl(implement_via_object = ...)]`. + pub deny_explicit_impl: bool, } /// Whether this trait is treated specially by the standard library diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index e04dbbff9..8cbffa148 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -155,11 +155,7 @@ pub struct TypeckResults<'tcx> { /// We also store the type here, so that the compiler can use it as a hint /// for figuring out hidden types, even if they are only set in dead code /// (which doesn't show up in MIR). - /// - /// These types are mapped back to the opaque's identity substitutions - /// (with erased regions), which is why we don't associated substs with any - /// of these usages. - pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>, + pub concrete_opaque_types: FxIndexMap<ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index ba0513563..e2e4a2dbd 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1,7 +1,6 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::mir; use crate::query::Providers; use crate::ty::layout::IntegerExt; use crate::ty::{ @@ -11,13 +10,12 @@ use crate::ty::{ use crate::ty::{GenericArgKind, SubstsRef}; use rustc_apfloat::Float as _; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; -use rustc_index::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_session::Limit; use rustc_span::sym; @@ -129,7 +127,7 @@ impl IntTypeExt for IntegerType { impl<'tcx> TyCtxt<'tcx> { /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn type_id_hash(self, ty: Ty<'tcx>) -> Hash64 { + pub fn type_id_hash(self, ty: Ty<'tcx>) -> Hash128 { // We want the type_id be independent of the types free regions, so we // erase them. The erase_regions() call will also anonymize bound // regions, which is desirable too. @@ -173,18 +171,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { - if let ty::Adt(def, substs) = *ty.kind() { - for field in def.all_fields() { - let field_ty = field.ty(self, substs); - if let ty::Error(_) = field_ty.kind() { - return true; - } - } - } - false - } - /// Attempts to returns the deeply last field of nested structures, but /// does not apply any normalization in its search. Returns the same type /// if input `ty` is not a structure at all. @@ -237,14 +223,14 @@ impl<'tcx> TyCtxt<'tcx> { }; let reported = self.sess.emit_err(crate::error::RecursionLimitReached { ty, suggested_limit }); - return self.ty_error(reported); + return Ty::new_error(self, reported); } match *ty.kind() { ty::Adt(def, substs) => { if !def.is_struct() { break; } - match def.non_enum_variant().fields.raw.last() { + match def.non_enum_variant().tail_opt() { Some(field) => { f(); ty = field.ty(self, substs); @@ -318,7 +304,7 @@ impl<'tcx> TyCtxt<'tcx> { (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def && a_def.is_struct() => { - if let Some(f) = a_def.non_enum_variant().fields.raw.last() { + if let Some(f) = a_def.non_enum_variant().tail_opt() { a = f.ty(self, a_substs); b = f.ty(self, b_substs); } else { @@ -624,12 +610,12 @@ impl<'tcx> TyCtxt<'tcx> { closure_substs: SubstsRef<'tcx>, env_region: ty::Region<'tcx>, ) -> Option<Ty<'tcx>> { - let closure_ty = self.mk_closure(closure_def_id, closure_substs); + let closure_ty = Ty::new_closure(self, closure_def_id, closure_substs); let closure_kind_ty = closure_substs.as_closure().kind_ty(); let closure_kind = closure_kind_ty.to_opt_closure_kind()?; let env_ty = match closure_kind { - ty::ClosureKind::Fn => self.mk_imm_ref(env_region, closure_ty), - ty::ClosureKind::FnMut => self.mk_mut_ref(env_region, closure_ty), + ty::ClosureKind::Fn => Ty::new_imm_ref(self, env_region, closure_ty), + ty::ClosureKind::FnMut => Ty::new_mut_ref(self, env_region, closure_ty), ty::ClosureKind::FnOnce => closure_ty, }; Some(env_ty) @@ -670,12 +656,12 @@ impl<'tcx> TyCtxt<'tcx> { pub fn thread_local_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { let static_ty = self.type_of(def_id).subst_identity(); if self.is_mutable_static(def_id) { - self.mk_mut_ptr(static_ty) + Ty::new_mut_ptr(self, static_ty) } else if self.is_foreign_item(def_id) { - self.mk_imm_ptr(static_ty) + Ty::new_imm_ptr(self, static_ty) } else { // FIXME: These things don't *really* have 'static lifetime. - self.mk_imm_ref(self.lifetimes.re_static, static_ty) + Ty::new_imm_ref(self, self.lifetimes.re_static, static_ty) } } @@ -690,11 +676,11 @@ impl<'tcx> TyCtxt<'tcx> { // Make sure that accesses to unsafe statics end up using raw pointers. // For thread-locals, this needs to be kept in sync with `Rvalue::ty`. if self.is_mutable_static(def_id) { - self.mk_mut_ptr(static_ty) + Ty::new_mut_ptr(self, static_ty) } else if self.is_foreign_item(def_id) { - self.mk_imm_ptr(static_ty) + Ty::new_imm_ptr(self, static_ty) } else { - self.mk_imm_ref(self.lifetimes.re_erased, static_ty) + Ty::new_imm_ref(self, self.lifetimes.re_erased, static_ty) } } @@ -709,7 +695,7 @@ impl<'tcx> TyCtxt<'tcx> { .as_ref() .map_or_else(|| [].iter(), |l| l.field_tys.iter()) .filter(|decl| !decl.ignore_for_traits) - .map(|decl| ty::EarlyBinder(decl.ty)) + .map(|decl| ty::EarlyBinder::bind(decl.ty)) } /// Normalizes all opaque types in the given value, replacing them @@ -750,80 +736,6 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - /// Returns names of captured upvars for closures and generators. - /// - /// Here are some examples: - /// - `name__field1__field2` when the upvar is captured by value. - /// - `_ref__name__field` when the upvar is captured by reference. - /// - /// For generators this only contains upvars that are shared by all states. - pub fn closure_saved_names_of_captured_variables( - self, - def_id: DefId, - ) -> SmallVec<[String; 16]> { - let body = self.optimized_mir(def_id); - - body.var_debug_info - .iter() - .filter_map(|var| { - let is_ref = match var.value { - mir::VarDebugInfoContents::Place(place) - if place.local == mir::Local::new(1) => - { - // The projection is either `[.., Field, Deref]` or `[.., Field]`. It - // implies whether the variable is captured by value or by reference. - matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref) - } - _ => return None, - }; - let prefix = if is_ref { "_ref__" } else { "" }; - Some(prefix.to_owned() + var.name.as_str()) - }) - .collect() - } - - // FIXME(eddyb) maybe precompute this? Right now it's computed once - // per generator monomorphization, but it doesn't depend on substs. - pub fn generator_layout_and_saved_local_names( - self, - def_id: DefId, - ) -> ( - &'tcx ty::GeneratorLayout<'tcx>, - IndexVec<mir::GeneratorSavedLocal, Option<rustc_span::Symbol>>, - ) { - let tcx = self; - let body = tcx.optimized_mir(def_id); - let generator_layout = body.generator_layout().unwrap(); - let mut generator_saved_local_names = - IndexVec::from_elem(None, &generator_layout.field_tys); - - let state_arg = mir::Local::new(1); - for var in &body.var_debug_info { - let mir::VarDebugInfoContents::Place(place) = &var.value else { continue }; - if place.local != state_arg { - continue; - } - match place.projection[..] { - [ - // Deref of the `Pin<&mut Self>` state argument. - mir::ProjectionElem::Field(..), - mir::ProjectionElem::Deref, - // Field of a variant of the state. - mir::ProjectionElem::Downcast(_, variant), - mir::ProjectionElem::Field(field, _), - ] => { - let name = &mut generator_saved_local_names - [generator_layout.variant_fields[variant][field]]; - if name.is_none() { - name.replace(var.name); - } - } - _ => {} - } - } - (generator_layout, generator_saved_local_names) - } - /// Query and get an English description for the item's kind. pub fn def_descr(self, def_id: DefId) -> &'static str { self.def_kind_descr(self.def_kind(def_id), def_id) @@ -857,6 +769,26 @@ impl<'tcx> TyCtxt<'tcx> { _ => def_kind.article(), } } + + /// Return `true` if the supplied `CrateNum` is "user-visible," meaning either a [public] + /// dependency, or a [direct] private dependency. This is used to decide whether the crate can + /// be shown in `impl` suggestions. + /// + /// [public]: TyCtxt::is_private_dep + /// [direct]: rustc_session::cstore::ExternCrate::is_direct + pub fn is_user_visible_dep(self, key: CrateNum) -> bool { + // | Private | Direct | Visible | | + // |---------|--------|---------|--------------------| + // | Yes | Yes | Yes | !true || true | + // | No | Yes | Yes | !false || true | + // | Yes | No | No | !true || false | + // | No | No | Yes | !false || false | + !self.is_private_dep(key) + // If `extern_crate` is `None`, then the crate was injected (e.g., by the allocator). + // Treat that kind of crate as "indirect", since it's an implementation detail of + // the language. + || self.extern_crate(key.as_def_id()).map_or(false, |e| e.is_direct()) + } } struct OpaqueTypeExpander<'tcx> { @@ -922,7 +854,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> { let hidden_ty = bty.subst(self.tcx, substs); self.fold_ty(hidden_ty); } - let expanded_ty = self.tcx.mk_generator_witness_mir(def_id, substs); + let expanded_ty = Ty::new_generator_witness_mir(self.tcx, def_id, substs); self.expanded_cache.insert((def_id, substs), expanded_ty); expanded_ty } @@ -964,7 +896,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> { fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { if let ty::PredicateKind::Clause(clause) = p.kind().skip_binder() - && let ty::Clause::Projection(projection_pred) = clause + && let ty::ClauseKind::Projection(projection_pred) = clause { p.kind() .rebind(ty::ProjectionPredicate { @@ -1374,7 +1306,7 @@ pub fn needs_drop_components<'tcx>( ty::Array(elem_ty, size) => { match needs_drop_components(*elem_ty, target_layout) { Ok(v) if v.is_empty() => Ok(v), - res => match size.kind().try_to_bits(target_layout.pointer_size) { + res => match size.try_to_bits(target_layout.pointer_size) { // Arrays of size zero don't need drop, even if their element // type does. Some(0) => Ok(SmallVec::new()), @@ -1487,8 +1419,8 @@ pub struct AlwaysRequiresDrop; /// with their underlying types. pub fn reveal_opaque_types_in_bounds<'tcx>( tcx: TyCtxt<'tcx>, - val: &'tcx ty::List<ty::Predicate<'tcx>>, -) -> &'tcx ty::List<ty::Predicate<'tcx>> { + val: &'tcx ty::List<ty::Clause<'tcx>>, +) -> &'tcx ty::List<ty::Clause<'tcx>> { let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), expanded_cache: FxHashMap::default(), diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index b9b1cd73a..443791d0a 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -73,7 +73,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let ptr_align = tcx.data_layout.pointer_align.abi; let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap(); - let mut vtable = Allocation::uninit(vtable_size, ptr_align, /* panic_on_fail */ true).unwrap(); + let mut vtable = Allocation::uninit(vtable_size, ptr_align); // No need to do any alignment checks on the memory accesses below, because we know the // allocation is correctly aligned as we created it above. Also we're only offsetting by diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index c62c33d4d..b0961d917 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -16,7 +16,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> { fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. - unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error_misc()) } + unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_misc_error(tcx)) } } } @@ -34,7 +34,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self { - let err = tcx.ty_error_misc(); + let err = Ty::new_misc_error(tcx); let arity = if let Some(frame) = stack.get(0) && frame.query.dep_kind == DepKind::fn_sig @@ -96,19 +96,22 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { - ty::EarlyBinder(Ty::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle)) } } impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> { fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { - ty::EarlyBinder(ty::Binder::from_cycle_error(tcx, cycle)) + ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle)) } } -impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, ty::layout::LayoutError<'_>> { +impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> { fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self { - Err(ty::layout::LayoutError::Cycle) + // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under + // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, + // tcx.arena.alloc is pretty much equal to leaking). + Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle))) } } |