1
Fork 0

Auto merge of #113370 - compiler-errors:rollup-8gvyy8e, r=compiler-errors

Rollup of 8 pull requests

Successful merges:

 - #113010 (rust-installer & rls: remove exclusion from rustfmt & tidy )
 - #113317 ( -Ztrait-solver=next: stop depending on old solver)
 - #113319 (`TypeParameterDefinition` always require a `DefId`)
 - #113320 (Add some extra information to opaque type cycle errors)
 - #113321 (Move `ty::ConstKind` to `rustc_type_ir`)
 - #113337 (Winnow specialized impls during selection in new solver)
 - #113355 (Move most coverage code out of `rustc_codegen_ssa`)
 - #113356 (Add support for NetBSD/riscv64 aka. riscv64gc-unknown-netbsd.)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-07-05 16:08:43 +00:00
commit 5dac6b320b
84 changed files with 1988 additions and 1412 deletions

View file

@ -706,7 +706,6 @@ fn codegen_stmt<'tcx>(
let times = fx
.monomorphize(times)
.eval(fx.tcx, ParamEnv::reveal_all())
.kind()
.try_to_bits(fx.tcx.data_layout.pointer_size)
.unwrap();
if operand.layout().size.bytes() == 0 {

View file

@ -1,69 +1,11 @@
use gccjit::RValue;
use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods};
use rustc_hir::def_id::DefId;
use rustc_middle::mir::coverage::{
CodeRegion,
CounterValueReference,
ExpressionOperandId,
InjectedExpressionId,
Op,
};
use rustc_codegen_ssa::traits::CoverageInfoBuilderMethods;
use rustc_middle::mir::Coverage;
use rustc_middle::ty::Instance;
use crate::builder::Builder;
use crate::context::CodegenCx;
impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn set_function_source_hash(
&mut self,
_instance: Instance<'tcx>,
_function_source_hash: u64,
) -> bool {
unimplemented!();
}
fn add_coverage_counter(&mut self, _instance: Instance<'tcx>, _id: CounterValueReference, _region: CodeRegion) -> bool {
fn add_coverage(&mut self, _instance: Instance<'tcx>, _coverage: &Coverage) {
// TODO(antoyo)
false
}
fn add_coverage_counter_expression(&mut self, _instance: Instance<'tcx>, _id: InjectedExpressionId, _lhs: ExpressionOperandId, _op: Op, _rhs: ExpressionOperandId, _region: Option<CodeRegion>) -> bool {
// TODO(antoyo)
false
}
fn add_coverage_unreachable(&mut self, _instance: Instance<'tcx>, _region: CodeRegion) -> bool {
// TODO(antoyo)
false
}
}
impl<'gcc, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
fn coverageinfo_finalize(&self) {
// TODO(antoyo)
}
fn get_pgo_func_name_var(&self, _instance: Instance<'tcx>) -> RValue<'gcc> {
unimplemented!();
}
/// Functions with MIR-based coverage are normally codegenned _only_ if
/// called. LLVM coverage tools typically expect every function to be
/// defined (even if unused), with at least one call to LLVM intrinsic
/// `instrprof.increment`.
///
/// Codegen a small function that will never be called, with one counter
/// that will never be incremented.
///
/// For used/called functions, the coverageinfo was already added to the
/// `function_coverage_map` (keyed by function `Instance`) during codegen.
/// But in this case, since the unused function was _not_ previously
/// codegenned, collect the coverage `CodeRegion`s from the MIR and add
/// them. The first `CodeRegion` is used to add a single counter, with the
/// same counter ID used in the injected `instrprof.increment` intrinsic
/// call. Since the function is never called, all other `CodeRegion`s can be
/// added as `unreachable_region`s.
fn define_unused_fn(&self, _def_id: DefId) {
unimplemented!();
}
}

View file

@ -1,6 +1,7 @@
pub use super::ffi::*;
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::bug;
use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId,
InjectedExpressionIndex, MappedExpressionIndex, Op,

View file

@ -1,10 +1,10 @@
use crate::common::CodegenCx;
use crate::coverageinfo;
use crate::coverageinfo::map_data::{Counter, CounterExpression};
use crate::llvm;
use llvm::coverageinfo::CounterMappingRegion;
use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression};
use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods};
use rustc_codegen_ssa::traits::ConstMethods;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;

View file

@ -3,13 +3,13 @@ use crate::llvm;
use crate::abi::Abi;
use crate::builder::Builder;
use crate::common::CodegenCx;
use crate::coverageinfo::map_data::{CounterExpression, FunctionCoverage};
use libc::c_uint;
use llvm::coverageinfo::CounterMappingRegion;
use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, FunctionCoverage};
use rustc_codegen_ssa::traits::{
BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, CoverageInfoMethods,
MiscMethods, StaticMethods,
BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods,
StaticMethods,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
@ -17,16 +17,19 @@ use rustc_hir::def_id::DefId;
use rustc_llvm::RustString;
use rustc_middle::bug;
use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op,
CodeRegion, CounterValueReference, CoverageKind, ExpressionOperandId, InjectedExpressionId, Op,
};
use rustc_middle::mir::Coverage;
use rustc_middle::ty;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::Instance;
use std::cell::RefCell;
use std::ffi::CString;
mod ffi;
pub(crate) mod map_data;
pub mod mapgen;
const UNUSED_FUNCTION_COUNTER_ID: CounterValueReference = CounterValueReference::START;
@ -53,11 +56,17 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
}
}
impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn coverageinfo_finalize(&self) {
// These methods used to be part of trait `CoverageInfoMethods`, which no longer
// exists after most coverage code was moved out of SSA.
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
pub(crate) fn coverageinfo_finalize(&self) {
mapgen::finalize(self)
}
/// For LLVM codegen, returns a function-specific `Value` for a global
/// string, to hold the function name passed to LLVM intrinsic
/// `instrprof.increment()`. The `Value` is only created once per instance.
/// Multiple invocations with the same instance return the same `Value`.
fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
if let Some(coverage_context) = self.coverage_context() {
debug!("getting pgo_func_name_var for instance={:?}", instance);
@ -94,6 +103,54 @@ impl<'ll, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage) {
let bx = self;
let Coverage { kind, code_region } = coverage.clone();
match kind {
CoverageKind::Counter { function_source_hash, id } => {
if bx.set_function_source_hash(instance, function_source_hash) {
// If `set_function_source_hash()` returned true, the coverage map is enabled,
// so continue adding the counter.
if let Some(code_region) = code_region {
// Note: Some counters do not have code regions, but may still be referenced
// from expressions. In that case, don't add the counter to the coverage map,
// but do inject the counter intrinsic.
bx.add_coverage_counter(instance, id, code_region);
}
let coverageinfo = bx.tcx().coverageinfo(instance.def);
let fn_name = bx.get_pgo_func_name_var(instance);
let hash = bx.const_u64(function_source_hash);
let num_counters = bx.const_u32(coverageinfo.num_counters);
let index = bx.const_u32(id.zero_based_index());
debug!(
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
fn_name, hash, num_counters, index,
);
bx.instrprof_increment(fn_name, hash, num_counters, index);
}
}
CoverageKind::Expression { id, lhs, op, rhs } => {
bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region);
}
CoverageKind::Unreachable => {
bx.add_coverage_unreachable(
instance,
code_region.expect("unreachable regions always have code regions"),
);
}
}
}
}
// These methods used to be part of trait `CoverageInfoBuilderMethods`, but
// after moving most coverage code out of SSA they are now just ordinary methods.
impl<'tcx> Builder<'_, '_, 'tcx> {
/// Returns true if the function source hash was added to the coverage map (even if it had
/// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
/// not enabled (a coverage map is not being generated).
fn set_function_source_hash(
&mut self,
instance: Instance<'tcx>,
@ -115,6 +172,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
}
}
/// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_counter(
&mut self,
instance: Instance<'tcx>,
@ -137,6 +196,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
}
}
/// Returns true if the expression was added to the coverage map; false if
/// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
fn add_coverage_counter_expression(
&mut self,
instance: Instance<'tcx>,
@ -163,6 +224,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
}
}
/// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool {
if let Some(coverage_context) = self.coverage_context() {
debug!(

View file

@ -1,7 +1,7 @@
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
use rustc_codegen_ssa::coverageinfo::map as coverage_map;
use crate::coverageinfo::map_data as coverage_map;
use super::debuginfo::{
DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,

View file

@ -1,2 +0,0 @@
pub mod ffi;
pub mod map;

View file

@ -48,7 +48,6 @@ pub mod back;
pub mod base;
pub mod codegen_attrs;
pub mod common;
pub mod coverageinfo;
pub mod debuginfo;
pub mod errors;
pub mod glue;

View file

@ -1,13 +1,12 @@
use crate::traits::*;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::Coverage;
use rustc_middle::mir::SourceScope;
use super::FunctionCx;
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn codegen_coverage(&self, bx: &mut Bx, coverage: Coverage, scope: SourceScope) {
pub fn codegen_coverage(&self, bx: &mut Bx, coverage: &Coverage, scope: SourceScope) {
// Determine the instance that coverage data was originally generated for.
let instance = if let Some(inlined) = scope.inlined_instance(&self.mir.source_scopes) {
self.monomorphize(inlined)
@ -15,41 +14,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.instance
};
let Coverage { kind, code_region } = coverage;
match kind {
CoverageKind::Counter { function_source_hash, id } => {
if bx.set_function_source_hash(instance, function_source_hash) {
// If `set_function_source_hash()` returned true, the coverage map is enabled,
// so continue adding the counter.
if let Some(code_region) = code_region {
// Note: Some counters do not have code regions, but may still be referenced
// from expressions. In that case, don't add the counter to the coverage map,
// but do inject the counter intrinsic.
bx.add_coverage_counter(instance, id, code_region);
}
let coverageinfo = bx.tcx().coverageinfo(instance.def);
let fn_name = bx.get_pgo_func_name_var(instance);
let hash = bx.const_u64(function_source_hash);
let num_counters = bx.const_u32(coverageinfo.num_counters);
let index = bx.const_u32(id.zero_based_index());
debug!(
"codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
fn_name, hash, num_counters, index,
);
bx.instrprof_increment(fn_name, hash, num_counters, index);
}
}
CoverageKind::Expression { id, lhs, op, rhs } => {
bx.add_coverage_counter_expression(instance, id, lhs, op, rhs, code_region);
}
CoverageKind::Unreachable => {
bx.add_coverage_unreachable(
instance,
code_region.expect("unreachable regions always have code regions"),
);
}
}
// Handle the coverage info in a backend-specific way.
bx.add_coverage(instance, coverage);
}
}

View file

@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
mir::StatementKind::Coverage(box ref coverage) => {
self.codegen_coverage(bx, coverage.clone(), statement.source_info.scope);
self.codegen_coverage(bx, coverage, statement.source_info.scope);
}
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
let op_val = self.codegen_operand(bx, op);

View file

@ -1,57 +1,11 @@
use super::BackendTypes;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::Coverage;
use rustc_middle::ty::Instance;
pub trait CoverageInfoMethods<'tcx>: BackendTypes {
fn coverageinfo_finalize(&self);
/// Codegen a small function that will never be called, with one counter
/// that will never be incremented, that gives LLVM coverage tools a
/// function definition it needs in order to resolve coverage map references
/// to unused functions. This is necessary so unused functions will appear
/// as uncovered (coverage execution count `0`) in LLVM coverage reports.
fn define_unused_fn(&self, def_id: DefId);
/// For LLVM codegen, returns a function-specific `Value` for a global
/// string, to hold the function name passed to LLVM intrinsic
/// `instrprof.increment()`. The `Value` is only created once per instance.
/// Multiple invocations with the same instance return the same `Value`.
fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> Self::Value;
}
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
/// Returns true if the function source hash was added to the coverage map (even if it had
/// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
/// not enabled (a coverage map is not being generated).
fn set_function_source_hash(
&mut self,
instance: Instance<'tcx>,
function_source_hash: u64,
) -> bool;
/// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_counter(
&mut self,
instance: Instance<'tcx>,
index: CounterValueReference,
region: CodeRegion,
) -> bool;
/// Returns true if the expression was added to the coverage map; false if
/// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
fn add_coverage_counter_expression(
&mut self,
instance: Instance<'tcx>,
id: InjectedExpressionId,
lhs: ExpressionOperandId,
op: Op,
rhs: ExpressionOperandId,
region: Option<CodeRegion>,
) -> bool;
/// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
/// is not enabled (a coverage map is not being generated).
fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool;
/// Handle the MIR coverage info in a backend-specific way.
///
/// This can potentially be a no-op in backends that don't support
/// coverage instrumentation.
fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage);
}

View file

@ -33,7 +33,7 @@ pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAs
pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods};
pub use self::builder::{BuilderMethods, OverflowOp};
pub use self::consts::ConstMethods;
pub use self::coverageinfo::{CoverageInfoBuilderMethods, CoverageInfoMethods};
pub use self::coverageinfo::CoverageInfoBuilderMethods;
pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods};
pub use self::declare::PreDefineMethods;
pub use self::intrinsic::IntrinsicCallMethods;
@ -59,7 +59,6 @@ pub trait CodegenMethods<'tcx>:
+ MiscMethods<'tcx>
+ ConstMethods<'tcx>
+ StaticMethods
+ CoverageInfoMethods<'tcx>
+ DebugInfoMethods<'tcx>
+ AsmMethods<'tcx>
+ PreDefineMethods<'tcx>
@ -75,7 +74,6 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
+ MiscMethods<'tcx>
+ ConstMethods<'tcx>
+ StaticMethods
+ CoverageInfoMethods<'tcx>
+ DebugInfoMethods<'tcx>
+ AsmMethods<'tcx>
+ PreDefineMethods<'tcx>

View file

@ -254,7 +254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
type BreakTy = ty::GenericArg<'tcx>;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
if let Some(origin) = self.0.type_var_origin(ty)
&& let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
&& let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, def_id) =
origin.kind
&& let generics = self.0.tcx.generics_of(self.1)
&& let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)

View file

@ -265,9 +265,9 @@ impl<'tcx> InferCtxt<'tcx> {
kind: UnderspecifiedArgKind::Type {
prefix: "type parameter".into(),
},
parent: def_id.and_then(|def_id| {
InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id)
}),
parent: InferenceDiagnosticsParentData::for_def_id(
self.tcx, def_id,
),
};
}
}

View file

@ -1110,7 +1110,7 @@ impl<'tcx> InferCtxt<'tcx> {
TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(
param.name,
Some(param.def_id),
param.def_id,
),
span,
},

View file

@ -21,29 +21,18 @@ impl<'tcx> InferCtxt<'tcx> {
recursion_depth: usize,
obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Ty<'tcx> {
if self.next_trait_solver() {
// FIXME(-Ztrait-solver=next): Instead of branching here,
// completely change the normalization routine with the new solver.
//
// The new solver correctly handles projection equality so this hack
// is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
// not `PredicateKind::Clause(ClauseKind::Projection(..))` as in the new solver
// `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
return projection_ty.to_ty(self.tcx);
} else {
let def_id = projection_ty.def_id;
let ty_var = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.tcx.def_span(def_id),
});
let projection =
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
)));
let obligation =
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
obligations.push(obligation);
ty_var
}
debug_assert!(!self.next_trait_solver());
let def_id = projection_ty.def_id;
let ty_var = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::NormalizeProjectionType,
span: self.tcx.def_span(def_id),
});
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
)));
let obligation =
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
obligations.push(obligation);
ty_var
}
}

View file

@ -123,7 +123,7 @@ pub enum TypeVariableOriginKind {
NormalizeProjectionType,
TypeInference,
OpaqueTypeInference(DefId),
TypeParameterDefinition(Symbol, Option<DefId>),
TypeParameterDefinition(Symbol, DefId),
/// One of the upvars or closure kind parameters in a `ClosureSubsts`
/// (before it has been determined).

View file

@ -2329,7 +2329,7 @@ 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(ty::Const::new_error(tcx, guar, self.ty())),
@ -2867,7 +2867,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();

View file

@ -588,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)]

View file

@ -1,6 +1,6 @@
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;
@ -14,9 +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]
@ -32,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> {
@ -40,7 +54,7 @@ impl<'tcx> Const<'tcx> {
#[inline]
pub fn kind(self) -> ConstKind<'tcx> {
self.0.kind
self.0.kind.clone()
}
#[inline]
@ -293,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]
@ -307,14 +321,14 @@ 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) => ty::Const::new_value(tcx, val, self.ty()),
Err(guar) => ty::Const::new_error(tcx, guar, self.ty()),
@ -339,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(_))
}

View file

@ -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
}
}
}

View file

@ -108,6 +108,14 @@ 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;

View file

@ -170,7 +170,7 @@ impl<'tcx> InhabitedPredicate<'tcx> {
match self {
Self::ConstIsZero(c) => {
let c = ty::EarlyBinder::bind(c).subst(tcx, substs);
let pred = match c.kind().try_to_target_usize(tcx) {
let pred = match c.try_to_target_usize(tcx) {
Some(0) => Self::True,
Some(1..) => Self::False,
None => Self::ConstIsZero(c),

View file

@ -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)),

View file

@ -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)
),
}

View file

@ -66,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::*;
@ -81,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,
@ -93,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,

View file

@ -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;
@ -241,24 +242,6 @@ 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) => rustc_type_ir::debug_bound_var(f, *debruijn, *var),
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
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 {
@ -728,7 +711,18 @@ 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_ct_from_kind(kind, ty))
} else {
@ -743,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),
}
}
}

View file

@ -33,6 +33,7 @@ use std::ops::{ControlFlow, Deref, Range};
use ty::util::IntTypeExt;
use rustc_type_ir::sty::TyKind::*;
use rustc_type_ir::ConstKind as IrConstKind;
use rustc_type_ir::RegionKind as IrRegionKind;
use rustc_type_ir::TyKind as IrTyKind;
@ -40,6 +41,7 @@ use rustc_type_ir::TyKind as IrTyKind;
#[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)]

View file

@ -1306,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()),

View file

@ -126,18 +126,13 @@ where
#[cold]
#[inline(never)]
fn mk_cycle<Q, Qcx>(
query: Q,
qcx: Qcx,
cycle_error: CycleError<Qcx::DepKind>,
handler: HandleCycleError,
) -> Q::Value
fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError<Qcx::DepKind>) -> Q::Value
where
Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
handle_cycle_error(query, qcx, &cycle_error, error, handler)
handle_cycle_error(query, qcx, &cycle_error, error)
}
fn handle_cycle_error<Q, Qcx>(
@ -145,14 +140,13 @@ fn handle_cycle_error<Q, Qcx>(
qcx: Qcx,
cycle_error: &CycleError<Qcx::DepKind>,
mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
handler: HandleCycleError,
) -> Q::Value
where
Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
use HandleCycleError::*;
match handler {
match query.handle_cycle_error() {
Error => {
error.emit();
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle)
@ -277,7 +271,7 @@ where
&qcx.current_query_job(),
span,
);
(mk_cycle(query, qcx, error, query.handle_cycle_error()), None)
(mk_cycle(query, qcx, error), None)
}
#[inline(always)]
@ -314,7 +308,7 @@ where
(v, Some(index))
}
Err(cycle) => (mk_cycle(query, qcx, cycle, query.handle_cycle_error()), None),
Err(cycle) => (mk_cycle(query, qcx, cycle), None),
}
}

View file

@ -6,10 +6,13 @@ pub trait Value<Tcx: DepContext, D: DepKind>: Sized {
}
impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T {
default fn from_cycle_error(tcx: Tcx, _: &[QueryInfo<D>]) -> T {
default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> T {
tcx.sess().abort_if_errors();
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
// non-trivial to define it earlier.
panic!("Value::from_cycle_error called without errors");
panic!(
"<{} as Value>::from_cycle_error called without errors: {cycle:#?}",
std::any::type_name::<T>()
);
}
}

View file

@ -230,7 +230,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
self.write_str("[")?;
self = self.print_type(ty)?;
self.write_str("; ")?;
if let Some(size) = size.kind().try_to_bits(self.tcx().data_layout.pointer_size) {
if let Some(size) = size.try_to_bits(self.tcx().data_layout.pointer_size) {
write!(self, "{size}")?
} else if let ty::ConstKind::Param(param) = size.kind() {
self = param.print(self)?

View file

@ -112,7 +112,7 @@ fn encode_const<'tcx>(
let _ = write!(s, "{value}");
}
if let Some(scalar_int) = c.kind().try_to_scalar_int() {
if let Some(scalar_int) = c.try_to_scalar_int() {
let signed = c.ty().is_signed();
match scalar_int.size().bits() {
8 if signed => push_signed_value(&mut s, scalar_int.try_to_i8().unwrap(), 0),
@ -504,8 +504,7 @@ fn encode_ty<'tcx>(
let _ = write!(
s,
"{}",
&len.kind()
.try_to_scalar()
&len.try_to_scalar()
.unwrap()
.to_u64()
.unwrap_or_else(|_| panic!("failed to convert length to u64"))
@ -815,7 +814,6 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
ty::Array(ty0, len) => {
let len = len
.kind()
.try_to_scalar()
.unwrap()
.to_u64()

View file

@ -651,7 +651,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
.builtin_deref(true)
.expect("tried to dereference on non-ptr type")
.ty;
// FIXME: add an assert that we only do this for valtrees.
// FIXME(const_generics): add an assert that we only do this for valtrees.
let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty);
self = dereferenced_const.print(self)?;
}

View file

@ -1325,6 +1325,7 @@ supported_targets! {
("armv7-unknown-netbsd-eabihf", armv7_unknown_netbsd_eabihf),
("i686-unknown-netbsd", i686_unknown_netbsd),
("powerpc-unknown-netbsd", powerpc_unknown_netbsd),
("riscv64gc-unknown-netbsd", riscv64gc_unknown_netbsd),
("sparc64-unknown-netbsd", sparc64_unknown_netbsd),
("x86_64-unknown-netbsd", x86_64_unknown_netbsd),

View file

@ -0,0 +1,19 @@
use crate::spec::{CodeModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
llvm_target: "riscv64-unknown-netbsd".into(),
pointer_width: 64,
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "riscv64".into(),
options: TargetOptions {
code_model: Some(CodeModel::Medium),
cpu: "generic-rv64".into(),
features: "+m,+a,+f,+d,+c".into(),
llvm_abiname: "lp64d".into(),
max_atomic_width: Some(64),
mcount: "__mcount".into(),
..super::netbsd_base::opts()
},
}
}

View file

@ -52,7 +52,11 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
let mut i = 0;
while i < candidates.len() {
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j])
candidate_should_be_dropped_in_favor_of(
ecx.tcx(),
&candidates[i],
&candidates[j],
)
});
if should_drop_i {
candidates.swap_remove(i);
@ -160,12 +164,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
fn candidate_should_be_dropped_in_favor_of<'tcx>(
tcx: TyCtxt<'tcx>,
victim: &Candidate<'tcx>,
other: &Candidate<'tcx>,
) -> bool {
match (victim.source, other.source) {
(CandidateSource::ParamEnv(i), CandidateSource::ParamEnv(j)) => i >= j,
(CandidateSource::ParamEnv(victim_idx), CandidateSource::ParamEnv(other_idx)) => {
victim_idx >= other_idx
}
(_, CandidateSource::ParamEnv(_)) => true,
(CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => {
tcx.specializes((other_def_id, victim_def_id))
&& other.result.value.certainty == Certainty::Yes
}
_ => false,
}
}

View file

@ -159,6 +159,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
let reveal = self.at.param_env.reveal();
let infcx = self.at.infcx;
debug_assert_eq!(ty, infcx.shallow_resolve(ty));
if !needs_normalization(&ty, reveal) {
return Ok(ty);
}
@ -192,6 +193,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
let reveal = self.at.param_env.reveal();
let infcx = self.at.infcx;
debug_assert_eq!(ct, infcx.shallow_resolve(ct));
if !needs_normalization(&ct, reveal) {
return Ok(ct);
}

View file

@ -30,6 +30,7 @@ use std::fmt::Debug;
use std::iter;
use std::ops::ControlFlow;
use super::query::evaluate_obligation::InferCtxtExt;
use super::NormalizeExt;
/// Whether we do the orphan check relative to this crate or
@ -290,6 +291,20 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
) -> bool {
let infcx = selcx.infcx;
let obligation_guaranteed_to_fail = move |obligation: &PredicateObligation<'tcx>| {
if infcx.next_trait_solver() {
infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply())
} else {
// We use `evaluate_root_obligation` to correctly track
// intercrate ambiguity clauses. We do not need this in the
// new solver.
selcx.evaluate_root_obligation(obligation).map_or(
false, // Overflow has occurred, and treat the obligation as possibly holding.
|result| !result.may_apply(),
)
}
};
let opt_failing_obligation = [&impl1_header.predicates, &impl2_header.predicates]
.into_iter()
.flatten()
@ -297,12 +312,7 @@ fn impl_intersection_has_impossible_obligation<'cx, 'tcx>(
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, predicate)
})
.chain(obligations)
.find(|o| {
selcx.evaluate_root_obligation(o).map_or(
false, // Overflow has occurred, and treat the obligation as possibly holding.
|result| !result.may_apply(),
)
});
.find(obligation_guaranteed_to_fail);
if let Some(failing_obligation) = opt_failing_obligation {
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);

View file

@ -30,7 +30,7 @@ use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::{InferOk, TypeTrace};
use rustc_middle::traits::select::OverflowError;
use rustc_middle::traits::solve::Goal;
use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
use rustc_middle::traits::{DefiningAnchor, SelectionOutputTypeParameterMismatch};
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
@ -1152,6 +1152,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => self.report_opaque_type_auto_trait_leakage(
&obligation,
def_id,
),
TraitNotObjectSafe(did) => {
let violations = self.tcx.object_safety_violations(did);
report_object_safety_error(self.tcx, span, did, violations)
@ -1170,16 +1175,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
// Already reported in the query.
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) => {
// FIXME(eddyb) remove this once `ErrorGuaranteed` becomes a proof token.
self.tcx.sess.delay_span_bug(span, "`ErrorGuaranteed` without an error");
return;
}
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) |
// Already reported.
Overflow(OverflowError::Error(_)) => {
self.tcx.sess.delay_span_bug(span, "`OverflowError` has been reported");
return;
}
Overflow(OverflowError::Error(_)) => return,
Overflow(_) => {
bug!("overflow should be handled before the `report_selection_error` path");
}
@ -1471,6 +1470,12 @@ trait InferCtxtPrivExt<'tcx> {
terr: TypeError<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
fn report_opaque_type_auto_trait_leakage(
&self,
obligation: &PredicateObligation<'tcx>,
def_id: DefId,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
fn report_type_parameter_mismatch_error(
&self,
obligation: &PredicateObligation<'tcx>,
@ -2646,11 +2651,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
if let ty::Param(_) = *ty.kind() {
let infcx = self.infcx;
*self.var_map.entry(ty).or_insert_with(|| {
infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
kind: TypeVariableOriginKind::MiscVariable,
span: DUMMY_SP,
})
})
@ -3192,6 +3197,39 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
}
fn report_opaque_type_auto_trait_leakage(
&self,
obligation: &PredicateObligation<'tcx>,
def_id: DefId,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
format!("opaque type")
}
hir::OpaqueTyOrigin::TyAlias { .. } => {
format!("`{}`", self.tcx.def_path_debug_str(def_id))
}
};
let mut err = self.tcx.sess.struct_span_err(
obligation.cause.span,
format!("cannot check whether the hidden type of {name} satisfies auto traits"),
);
err.span_note(self.tcx.def_span(def_id), "opaque type is declared here");
match self.defining_use_anchor {
DefiningAnchor::Bubble | DefiningAnchor::Error => {}
DefiningAnchor::Bind(bind) => {
err.span_note(
self.tcx.def_ident_span(bind).unwrap_or_else(|| self.tcx.def_span(bind)),
"this item depends on auto traits of the hidden type, \
but may also be registering the hidden type. \
This is not supported right now. \
You can try moving the opaque type and the item that actually registers a hidden type into a new submodule".to_string(),
);
}
};
err
}
fn report_type_parameter_mismatch_error(
&self,
obligation: &PredicateObligation<'tcx>,

View file

@ -278,7 +278,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
if let ty::Array(aty, len) = self_ty.kind() {
flags.push((sym::_Self, Some("[]".to_string())));
let len = len.kind().try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
let len = len.try_to_value().and_then(|v| v.try_to_target_usize(self.tcx));
flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
if let Some(n) = len {
flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));

View file

@ -528,7 +528,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
debug!("equating consts:\nc1= {:?}\nc2= {:?}", c1, c2);
use rustc_hir::def::DefKind;
use ty::ConstKind::Unevaluated;
use ty::Unevaluated;
match (c1.kind(), c2.kind()) {
(Unevaluated(a), Unevaluated(b))
if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>

View file

@ -447,6 +447,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
depth: usize,
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
debug_assert!(!selcx.infcx.next_trait_solver());
AssocTypeNormalizer {
selcx,
param_env,
@ -1122,6 +1123,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Result<Option<Term<'tcx>>, InProgress> {
let infcx = selcx.infcx;
debug_assert!(!selcx.infcx.next_trait_solver());
// Don't use the projection cache in intercrate mode -
// the `infcx` may be re-used between intercrate in non-intercrate
// mode, which could lead to using incorrect cache results.

View file

@ -97,6 +97,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
}
})
} else {
assert!(!self.intercrate);
let c_pred = self.canonicalize_query_keep_static(
param_env.and(obligation.predicate),
&mut _orig_values,

View file

@ -1,3 +1,4 @@
use crate::solve;
use crate::traits::query::NoSolution;
use crate::traits::wf;
use crate::traits::ObligationCtxt;
@ -6,6 +7,7 @@ use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
use rustc_infer::traits::query::OutlivesBound;
use rustc_middle::infer::canonical::CanonicalQueryResponse;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::source_map::DUMMY_SP;
@ -164,19 +166,29 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
// We lazily compute the outlives components as
// `select_all_or_error` constrains inference variables.
let implied_bounds = outlives_bounds
.into_iter()
.flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
let mut implied_bounds = Vec::new();
for ty::OutlivesPredicate(a, r_b) in outlives_bounds {
match a.unpack() {
ty::GenericArgKind::Lifetime(r_a) => {
implied_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a))
}
ty::GenericArgKind::Type(ty_a) => {
let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
let mut ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
// Need to manually normalize in the new solver as `wf::obligations` does not.
if ocx.infcx.next_trait_solver() {
ty_a = solve::deeply_normalize(
ocx.infcx.at(&ObligationCause::dummy(), param_env),
ty_a,
)
.map_err(|_errs| NoSolution)?;
}
let mut components = smallvec![];
push_outlives_components(tcx, ty_a, &mut components);
implied_bounds_from_components(r_b, components)
implied_bounds.extend(implied_bounds_from_components(r_b, components))
}
ty::GenericArgKind::Const(_) => unreachable!(),
})
.collect();
}
}
Ok(implied_bounds)
}

View file

@ -388,7 +388,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// `FnPtr`, when we wanted to report that it doesn't implement `Trait`.
#[instrument(level = "trace", skip(self), ret)]
fn reject_fn_ptr_impls(
&self,
&mut self,
impl_def_id: DefId,
obligation: &TraitObligation<'tcx>,
impl_self_ty: Ty<'tcx>,
@ -464,7 +464,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
})),
);
if let Ok(r) = self.infcx.evaluate_obligation(&obligation) {
if let Ok(r) = self.evaluate_root_obligation(&obligation) {
if !r.may_apply() {
return true;
}

View file

@ -67,7 +67,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
AutoImplCandidate => {
let data = self.confirm_auto_impl_candidate(obligation);
let data = self.confirm_auto_impl_candidate(obligation)?;
ImplSource::Builtin(data)
}
@ -376,12 +376,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_auto_impl_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
) -> Vec<PredicateObligation<'tcx>> {
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_auto_impl_candidate");
let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty());
let types = self.constituent_types_for_ty(self_ty);
self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types)
let types = self.constituent_types_for_ty(self_ty)?;
Ok(self.vtable_auto_impl(obligation, obligation.predicate.def_id(), types))
}
/// See `confirm_auto_impl_candidate`.

View file

@ -34,8 +34,6 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::traits::TraitEngine;
use rustc_infer::traits::TraitEngineExt;
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@ -312,6 +310,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
debug_assert!(!self.infcx.next_trait_solver());
// Watch out for overflow. This intentionally bypasses (and does
// not update) the cache.
self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
@ -526,21 +525,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
/// Evaluates whether the obligation `obligation` can be satisfied
/// and returns an `EvaluationResult`. This is meant for the
/// *initial* call.
///
/// Do not use this directly, use `infcx.evaluate_obligation` instead.
pub fn evaluate_root_obligation(
&mut self,
obligation: &PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
debug_assert!(!self.infcx.next_trait_solver());
self.evaluation_probe(|this| {
let goal =
this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
let mut result = if this.infcx.next_trait_solver() {
this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])?
} else {
this.evaluate_predicate_recursively(
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
obligation.clone(),
)?
};
let mut result = this.evaluate_predicate_recursively(
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
obligation.clone(),
)?;
// If the predicate has done any inference, then downgrade the
// result to ambiguous.
if this.infcx.shallow_resolve(goal) != goal {
@ -587,42 +585,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
where
I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
{
if self.infcx.next_trait_solver() {
self.evaluate_predicates_recursively_in_new_solver(predicates)
} else {
let mut result = EvaluatedToOk;
for mut obligation in predicates {
obligation.set_depth_from_parent(stack.depth());
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
if let EvaluatedToErr = eval {
// fast-path - EvaluatedToErr is the top of the lattice,
// so we don't need to look on the other predicates.
return Ok(EvaluatedToErr);
} else {
result = cmp::max(result, eval);
}
let mut result = EvaluatedToOk;
for mut obligation in predicates {
obligation.set_depth_from_parent(stack.depth());
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
if let EvaluatedToErr = eval {
// fast-path - EvaluatedToErr is the top of the lattice,
// so we don't need to look on the other predicates.
return Ok(EvaluatedToErr);
} else {
result = cmp::max(result, eval);
}
Ok(result)
}
}
/// Evaluates the predicates using the new solver when `-Ztrait-solver=next` is enabled
fn evaluate_predicates_recursively_in_new_solver(
&mut self,
predicates: impl IntoIterator<Item = PredicateObligation<'tcx>>,
) -> Result<EvaluationResult, OverflowError> {
let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(self.infcx);
fulfill_cx.register_predicate_obligations(self.infcx, predicates);
// True errors
// FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK?
if !fulfill_cx.select_where_possible(self.infcx).is_empty() {
return Ok(EvaluatedToErr);
}
if !fulfill_cx.select_all_or_error(self.infcx).is_empty() {
return Ok(EvaluatedToAmbig);
}
// Regions and opaques are handled in the `evaluation_probe` by looking at the snapshot
Ok(EvaluatedToOk)
Ok(result)
}
#[instrument(
@ -636,6 +611,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
debug_assert!(!self.infcx.next_trait_solver());
// `previous_stack` stores a `TraitObligation`, while `obligation` is
// a `PredicateObligation`. These are distinct types, so we can't
// use any `Option` combinator method that would force them to be
@ -897,7 +873,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
);
use rustc_hir::def::DefKind;
use ty::ConstKind::Unevaluated;
use ty::Unevaluated;
match (c1.kind(), c2.kind()) {
(Unevaluated(a), Unevaluated(b))
if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>
@ -1179,6 +1155,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
) -> Result<EvaluationResult, OverflowError> {
debug_assert!(!self.infcx.next_trait_solver());
// In intercrate mode, whenever any of the generics are unbound,
// there can always be an impl. Even if there are no impls in
// this crate, perhaps the type would be unified with
@ -2294,8 +2271,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
fn constituent_types_for_ty(
&self,
t: ty::Binder<'tcx, Ty<'tcx>>,
) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
match *t.skip_binder().kind() {
) -> Result<ty::Binder<'tcx, Vec<Ty<'tcx>>>, SelectionError<'tcx>> {
Ok(match *t.skip_binder().kind() {
ty::Uint(_)
| ty::Int(_)
| ty::Bool
@ -2359,12 +2336,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
let ty = self.tcx().type_of(def_id);
if ty.skip_binder().references_error() {
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
}
// We can resolve the `impl Trait` to its concrete type,
// which enforces a DAG between the functions requiring
// the auto trait bounds in question.
t.rebind(vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)])
t.rebind(vec![ty.subst(self.tcx(), substs)])
}
}
})
}
fn collect_predicates_for_types(

View file

@ -302,6 +302,16 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
}
fn normalize(self, infcx: &InferCtxt<'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
// Do not normalize `wf` obligations with the new solver.
//
// The current deep normalization routine with the new solver does not
// handle ambiguity and the new solver correctly deals with unnnormalized goals.
// If the user relies on normalized types, e.g. for `fn implied_outlives_bounds`,
// it is their responsibility to normalize while avoiding ambiguity.
if infcx.next_trait_solver() {
return self.out;
}
let cause = self.cause(traits::WellFormed(None));
let param_env = self.param_env;
let mut obligations = Vec::with_capacity(self.out.len());

View file

@ -57,11 +57,19 @@ pub trait Interner: Sized {
type ParamTy: Clone + Debug + Hash + Ord;
type BoundTy: Clone + Debug + Hash + Ord;
type PlaceholderType: Clone + Debug + Hash + Ord;
type InferTy: Clone + Debug + Hash + Ord;
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
type AllocId: Clone + Debug + Hash + Ord;
type InferConst: Clone + Debug + Hash + Ord;
type AliasConst: Clone + Debug + Hash + Ord;
type PlaceholderConst: Clone + Debug + Hash + Ord;
type ParamConst: Clone + Debug + Hash + Ord;
type BoundConst: Clone + Debug + Hash + Ord;
type InferTy: Clone + Debug + Hash + Ord;
type ValueConst: Clone + Debug + Hash + Ord;
type ExprConst: Clone + Debug + Hash + Ord;
type EarlyBoundRegion: Clone + Debug + Hash + Ord;
type BoundRegion: Clone + Debug + Hash + Ord;
type FreeRegion: Clone + Debug + Hash + Ord;

View file

@ -4,7 +4,7 @@
use crate::fold::{FallibleTypeFolder, TypeFoldable};
use crate::visit::{TypeVisitable, TypeVisitor};
use crate::{FloatTy, IntTy, Interner, UintTy};
use crate::{ConstKind, FloatTy, IntTy, Interner, UintTy};
use rustc_data_structures::functor::IdFunctor;
use rustc_data_structures::sync::Lrc;
use rustc_index::{Idx, IndexVec};
@ -182,3 +182,21 @@ impl fmt::Debug for FloatTy {
write!(f, "{}", self.name_str())
}
}
impl<I: Interner> fmt::Debug for ConstKind<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use ConstKind::*;
match self {
Param(param) => write!(f, "{param:?}"),
Infer(var) => write!(f, "{var:?}"),
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()),
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
Unevaluated(uv) => {
write!(f, "{uv:?}")
}
Value(valtree) => write!(f, "{valtree:?}"),
Error(_) => write!(f, "{{const error}}"),
Expr(expr) => write!(f, "{expr:?}"),
}
}
}

View file

@ -876,6 +876,224 @@ where
}
}
/// Represents a constant in Rust.
// #[derive(derive_more::From)]
pub enum ConstKind<I: Interner> {
/// A const generic parameter.
Param(I::ParamConst),
/// Infer the value of the const.
Infer(I::InferConst),
/// Bound const variable, used only when preparing a trait query.
Bound(DebruijnIndex, I::BoundConst),
/// A placeholder const - universally quantified higher-ranked const.
Placeholder(I::PlaceholderConst),
/// An unnormalized const item such as an anon const or assoc const or free const item.
/// Right now anything other than anon consts does not actually work properly but this
/// should
Unevaluated(I::AliasConst),
/// Used to hold computed value.
Value(I::ValueConst),
/// A placeholder for a const which could not be computed; this is
/// propagated to avoid useless error messages.
Error(I::ErrorGuaranteed),
/// Unevaluated non-const-item, used by `feature(generic_const_exprs)` to represent
/// const arguments such as `N + 1` or `foo(N)`
Expr(I::ExprConst),
}
const fn const_kind_discriminant<I: Interner>(value: &ConstKind<I>) -> usize {
match value {
ConstKind::Param(_) => 0,
ConstKind::Infer(_) => 1,
ConstKind::Bound(_, _) => 2,
ConstKind::Placeholder(_) => 3,
ConstKind::Unevaluated(_) => 4,
ConstKind::Value(_) => 5,
ConstKind::Error(_) => 6,
ConstKind::Expr(_) => 7,
}
}
impl<I: Interner> hash::Hash for ConstKind<I> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
const_kind_discriminant(self).hash(state);
match self {
ConstKind::Param(p) => p.hash(state),
ConstKind::Infer(i) => i.hash(state),
ConstKind::Bound(d, b) => {
d.hash(state);
b.hash(state);
}
ConstKind::Placeholder(p) => p.hash(state),
ConstKind::Unevaluated(u) => u.hash(state),
ConstKind::Value(v) => v.hash(state),
ConstKind::Error(e) => e.hash(state),
ConstKind::Expr(e) => e.hash(state),
}
}
}
impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ConstKind<I>
where
I::ParamConst: HashStable<CTX>,
I::InferConst: HashStable<CTX>,
I::BoundConst: HashStable<CTX>,
I::PlaceholderConst: HashStable<CTX>,
I::AliasConst: HashStable<CTX>,
I::ValueConst: HashStable<CTX>,
I::ErrorGuaranteed: HashStable<CTX>,
I::ExprConst: HashStable<CTX>,
{
fn hash_stable(
&self,
hcx: &mut CTX,
hasher: &mut rustc_data_structures::stable_hasher::StableHasher,
) {
const_kind_discriminant(self).hash_stable(hcx, hasher);
match self {
ConstKind::Param(p) => p.hash_stable(hcx, hasher),
ConstKind::Infer(i) => i.hash_stable(hcx, hasher),
ConstKind::Bound(d, b) => {
d.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
}
ConstKind::Placeholder(p) => p.hash_stable(hcx, hasher),
ConstKind::Unevaluated(u) => u.hash_stable(hcx, hasher),
ConstKind::Value(v) => v.hash_stable(hcx, hasher),
ConstKind::Error(e) => e.hash_stable(hcx, hasher),
ConstKind::Expr(e) => e.hash_stable(hcx, hasher),
}
}
}
impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for ConstKind<I>
where
I::ParamConst: Decodable<D>,
I::InferConst: Decodable<D>,
I::BoundConst: Decodable<D>,
I::PlaceholderConst: Decodable<D>,
I::AliasConst: Decodable<D>,
I::ValueConst: Decodable<D>,
I::ErrorGuaranteed: Decodable<D>,
I::ExprConst: Decodable<D>,
{
fn decode(d: &mut D) -> Self {
match Decoder::read_usize(d) {
0 => ConstKind::Param(Decodable::decode(d)),
1 => ConstKind::Infer(Decodable::decode(d)),
2 => ConstKind::Bound(Decodable::decode(d), Decodable::decode(d)),
3 => ConstKind::Placeholder(Decodable::decode(d)),
4 => ConstKind::Unevaluated(Decodable::decode(d)),
5 => ConstKind::Value(Decodable::decode(d)),
6 => ConstKind::Error(Decodable::decode(d)),
7 => ConstKind::Expr(Decodable::decode(d)),
_ => panic!(
"{}",
format!(
"invalid enum variant tag while decoding `{}`, expected 0..{}",
"ConstKind", 8,
)
),
}
}
}
impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for ConstKind<I>
where
I::ParamConst: Encodable<E>,
I::InferConst: Encodable<E>,
I::BoundConst: Encodable<E>,
I::PlaceholderConst: Encodable<E>,
I::AliasConst: Encodable<E>,
I::ValueConst: Encodable<E>,
I::ErrorGuaranteed: Encodable<E>,
I::ExprConst: Encodable<E>,
{
fn encode(&self, e: &mut E) {
let disc = const_kind_discriminant(self);
match self {
ConstKind::Param(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
ConstKind::Infer(i) => e.emit_enum_variant(disc, |e| i.encode(e)),
ConstKind::Bound(d, b) => e.emit_enum_variant(disc, |e| {
d.encode(e);
b.encode(e);
}),
ConstKind::Placeholder(p) => e.emit_enum_variant(disc, |e| p.encode(e)),
ConstKind::Unevaluated(u) => e.emit_enum_variant(disc, |e| u.encode(e)),
ConstKind::Value(v) => e.emit_enum_variant(disc, |e| v.encode(e)),
ConstKind::Error(er) => e.emit_enum_variant(disc, |e| er.encode(e)),
ConstKind::Expr(ex) => e.emit_enum_variant(disc, |e| ex.encode(e)),
}
}
}
impl<I: Interner> PartialOrd for ConstKind<I> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<I: Interner> Ord for ConstKind<I> {
fn cmp(&self, other: &Self) -> Ordering {
const_kind_discriminant(self)
.cmp(&const_kind_discriminant(other))
.then_with(|| match (self, other) {
(ConstKind::Param(p1), ConstKind::Param(p2)) => p1.cmp(p2),
(ConstKind::Infer(i1), ConstKind::Infer(i2)) => i1.cmp(i2),
(ConstKind::Bound(d1, b1), ConstKind::Bound(d2, b2)) => d1.cmp(d2).then_with(|| b1.cmp(b2)),
(ConstKind::Placeholder(p1), ConstKind::Placeholder(p2)) => p1.cmp(p2),
(ConstKind::Unevaluated(u1), ConstKind::Unevaluated(u2)) => u1.cmp(u2),
(ConstKind::Value(v1), ConstKind::Value(v2)) => v1.cmp(v2),
(ConstKind::Error(e1), ConstKind::Error(e2)) => e1.cmp(e2),
(ConstKind::Expr(e1), ConstKind::Expr(e2)) => e1.cmp(e2),
_ => {
debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}");
Ordering::Equal
}
})
}
}
impl<I: Interner> PartialEq for ConstKind<I> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Param(l0), Self::Param(r0)) => l0 == r0,
(Self::Infer(l0), Self::Infer(r0)) => l0 == r0,
(Self::Bound(l0, l1), Self::Bound(r0, r1)) => l0 == r0 && l1 == r1,
(Self::Placeholder(l0), Self::Placeholder(r0)) => l0 == r0,
(Self::Unevaluated(l0), Self::Unevaluated(r0)) => l0 == r0,
(Self::Value(l0), Self::Value(r0)) => l0 == r0,
(Self::Error(l0), Self::Error(r0)) => l0 == r0,
(Self::Expr(l0), Self::Expr(r0)) => l0 == r0,
_ => false,
}
}
}
impl<I: Interner> Eq for ConstKind<I> {}
impl<I: Interner> Clone for ConstKind<I> {
fn clone(&self) -> Self {
match self {
Self::Param(arg0) => Self::Param(arg0.clone()),
Self::Infer(arg0) => Self::Infer(arg0.clone()),
Self::Bound(arg0, arg1) => Self::Bound(arg0.clone(), arg1.clone()),
Self::Placeholder(arg0) => Self::Placeholder(arg0.clone()),
Self::Unevaluated(arg0) => Self::Unevaluated(arg0.clone()),
Self::Value(arg0) => Self::Value(arg0.clone()),
Self::Error(arg0) => Self::Error(arg0.clone()),
Self::Expr(arg0) => Self::Expr(arg0.clone()),
}
}
}
/// Representation of regions. Note that the NLL checker uses a distinct
/// representation of regions. For this reason, it internally replaces all the
/// regions with inference variables -- the index of the variable is then used