mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Assume unevaluated consts are equal to the other consts and add ConstEquate obligation. This delays
the need to evaluate consts eagerly and therefore gets around const eval query cycles.
This commit is contained in:
parent
09739c22db
commit
8b14b84933
@ -25,7 +25,7 @@ use rustc_middle::arena::ArenaAllocatable;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
|
||||
use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, BoundVar, Const, Ty, TyCtxt};
|
||||
use std::fmt::Debug;
|
||||
|
||||
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
@ -671,6 +671,13 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
|
||||
});
|
||||
}
|
||||
|
||||
fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {
|
||||
span_bug!(
|
||||
self.cause.span(self.infcx.tcx),
|
||||
"lazy_normalization_consts: unreachable `const_equate`"
|
||||
);
|
||||
}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
NormalizationStrategy::Eager
|
||||
}
|
||||
|
@ -164,7 +164,6 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
||||
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
||||
return self.unify_const_variable(!a_is_expected, vid, a);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@ -375,6 +374,20 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
||||
debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
|
||||
Ok(Generalization { ty, needs_wf })
|
||||
}
|
||||
|
||||
pub fn add_const_equate_obligation(
|
||||
&mut self,
|
||||
a_is_expected: bool,
|
||||
a: &'tcx ty::Const<'tcx>,
|
||||
b: &'tcx ty::Const<'tcx>,
|
||||
) {
|
||||
let predicate = if a_is_expected {
|
||||
ty::Predicate::ConstEquate(a, b)
|
||||
} else {
|
||||
ty::Predicate::ConstEquate(b, a)
|
||||
};
|
||||
self.obligations.push(Obligation::new(self.trace.cause.clone(), self.param_env, predicate));
|
||||
}
|
||||
}
|
||||
|
||||
struct Generalizer<'cx, 'tcx> {
|
||||
@ -637,6 +650,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Unevaluated(..) => Ok(c),
|
||||
_ => relate::super_relate_consts(self, c, c),
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use super::Subtype;
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::TyVar;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, ConstKind, Ty, TyCtxt};
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
@ -119,7 +119,17 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
|
||||
a: &'tcx ty::Const<'tcx>,
|
||||
b: &'tcx ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
||||
self.fields.infcx.super_combine_consts(self, a, b)
|
||||
match (a.val, b.val) {
|
||||
(ConstKind::Unevaluated(..), _) => {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
Ok(b)
|
||||
}
|
||||
(_, ConstKind::Unevaluated(..)) => {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
Ok(a)
|
||||
}
|
||||
_ => self.fields.infcx.super_combine_consts(self, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
fn binders<T>(
|
||||
|
@ -79,7 +79,17 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> {
|
||||
a: &'tcx ty::Const<'tcx>,
|
||||
b: &'tcx ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
||||
self.fields.infcx.super_combine_consts(self, a, b)
|
||||
match (a.val, b.val) {
|
||||
(ty::ConstKind::Unevaluated(..), _) => {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
Ok(b)
|
||||
}
|
||||
(_, ty::ConstKind::Unevaluated(..)) => {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
Ok(a)
|
||||
}
|
||||
_ => self.fields.infcx.super_combine_consts(self, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
fn binders<T>(
|
||||
|
@ -79,7 +79,17 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
|
||||
a: &'tcx ty::Const<'tcx>,
|
||||
b: &'tcx ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
||||
self.fields.infcx.super_combine_consts(self, a, b)
|
||||
match (a.val, b.val) {
|
||||
(ty::ConstKind::Unevaluated(..), _) => {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
Ok(b)
|
||||
}
|
||||
(_, ty::ConstKind::Unevaluated(..)) => {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
Ok(a)
|
||||
}
|
||||
_ => self.fields.infcx.super_combine_consts(self, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
fn binders<T>(
|
||||
|
@ -1490,6 +1490,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
self.report_and_explain_type_error(trace, &err)
|
||||
}
|
||||
|
||||
pub fn report_mismatched_consts(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
expected: &'tcx ty::Const<'tcx>,
|
||||
actual: &'tcx ty::Const<'tcx>,
|
||||
err: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let trace = TypeTrace::consts(cause, true, expected, actual);
|
||||
self.report_and_explain_type_error(trace, &err)
|
||||
}
|
||||
|
||||
pub fn replace_bound_vars_with_fresh_vars<T>(
|
||||
&self,
|
||||
span: Span,
|
||||
@ -1777,6 +1788,15 @@ impl<'tcx> TypeTrace<'tcx> {
|
||||
TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
|
||||
}
|
||||
|
||||
pub fn consts(
|
||||
cause: &ObligationCause<'tcx>,
|
||||
a_is_expected: bool,
|
||||
a: &'tcx ty::Const<'tcx>,
|
||||
b: &'tcx ty::Const<'tcx>,
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
|
||||
}
|
||||
|
||||
pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: ObligationCause::dummy(),
|
||||
|
@ -77,6 +77,8 @@ pub trait TypeRelatingDelegate<'tcx> {
|
||||
/// delegate.
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
|
||||
|
||||
fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
|
||||
|
||||
/// Creates a new universe index. Used when instantiating placeholders.
|
||||
fn create_next_universe(&mut self) -> ty::UniverseIndex;
|
||||
|
||||
@ -592,8 +594,16 @@ where
|
||||
b = self.infcx.shallow_resolve(b);
|
||||
}
|
||||
|
||||
match b.val {
|
||||
ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
|
||||
match (a.val, b.val) {
|
||||
(ty::ConstKind::Unevaluated(..), _) => {
|
||||
self.delegate.const_equate(a, b);
|
||||
Ok(b)
|
||||
}
|
||||
(_, ty::ConstKind::Unevaluated(..)) => {
|
||||
self.delegate.const_equate(a, b);
|
||||
Ok(a)
|
||||
}
|
||||
(_, ty::ConstKind::Infer(InferConst::Var(_))) if D::forbid_inference_vars() => {
|
||||
// Forbid inference variables in the RHS.
|
||||
bug!("unexpected inference var {:?}", b)
|
||||
}
|
||||
@ -976,6 +986,7 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Unevaluated(..) => Ok(a),
|
||||
_ => relate::super_relate_consts(self, a, a),
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ pub fn explicit_outlives_bounds<'tcx>(
|
||||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::TypeOutlives(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
ty::Predicate::RegionOutlives(ref data) => data
|
||||
.no_bound_vars()
|
||||
.map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)),
|
||||
|
@ -155,7 +155,17 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
|
||||
a: &'tcx ty::Const<'tcx>,
|
||||
b: &'tcx ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
||||
self.fields.infcx.super_combine_consts(self, a, b)
|
||||
match (a.val, b.val) {
|
||||
(ty::ConstKind::Unevaluated(..), _) => {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
Ok(b)
|
||||
}
|
||||
(_, ty::ConstKind::Unevaluated(..)) => {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
Ok(a)
|
||||
}
|
||||
_ => self.fields.infcx.super_combine_consts(self, a, b),
|
||||
}
|
||||
}
|
||||
|
||||
fn binders<T>(
|
||||
|
@ -10,7 +10,7 @@ pub mod util;
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Const, Ty};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub use self::FulfillmentErrorCode::*;
|
||||
@ -81,6 +81,7 @@ pub enum FulfillmentErrorCode<'tcx> {
|
||||
CodeSelectionError(SelectionError<'tcx>),
|
||||
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
|
||||
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
|
||||
CodeConstEquateError(ExpectedFound<&'tcx Const<'tcx>>, TypeError<'tcx>),
|
||||
CodeAmbiguity,
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,9 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
|
||||
super::CodeSubtypeError(ref a, ref b) => {
|
||||
write!(f, "CodeSubtypeError({:?}, {:?})", a, b)
|
||||
}
|
||||
super::CodeConstEquateError(ref a, ref b) => {
|
||||
write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
|
||||
}
|
||||
super::CodeAmbiguity => write!(f, "Ambiguity"),
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ pub fn anonymize_predicate<'tcx>(
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs)
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2),
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,6 +189,10 @@ impl Elaborator<'tcx> {
|
||||
// Currently, we do not elaborate const-evaluatable
|
||||
// predicates.
|
||||
}
|
||||
ty::Predicate::ConstEquate(..) => {
|
||||
// Currently, we do not elaborate const-equate
|
||||
// predicates.
|
||||
}
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
// Nothing to elaborate from `'a: 'b`.
|
||||
}
|
||||
|
@ -1221,7 +1221,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
|
||||
ObjectSafe(..) |
|
||||
ClosureKind(..) |
|
||||
Subtype(..) |
|
||||
ConstEvaluatable(..) => continue,
|
||||
ConstEvaluatable(..) |
|
||||
ConstEquate(..) => continue,
|
||||
};
|
||||
if predicate.is_global() {
|
||||
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
|
||||
|
@ -1054,6 +1054,9 @@ pub enum Predicate<'tcx> {
|
||||
|
||||
/// Constant initializer must evaluate successfully.
|
||||
ConstEvaluatable(DefId, SubstsRef<'tcx>),
|
||||
|
||||
/// Constants must be equal. The first component is the const that is expected.
|
||||
ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
|
||||
}
|
||||
|
||||
/// The crate outlives map is computed during typeck and contains the
|
||||
@ -1172,6 +1175,9 @@ impl<'tcx> Predicate<'tcx> {
|
||||
Predicate::ConstEvaluatable(def_id, const_substs) => {
|
||||
Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs))
|
||||
}
|
||||
Predicate::ConstEquate(c1, c2) => {
|
||||
Predicate::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1349,7 +1355,8 @@ impl<'tcx> Predicate<'tcx> {
|
||||
| Predicate::ObjectSafe(..)
|
||||
| Predicate::ClosureKind(..)
|
||||
| Predicate::TypeOutlives(..)
|
||||
| Predicate::ConstEvaluatable(..) => None,
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1363,7 +1370,8 @@ impl<'tcx> Predicate<'tcx> {
|
||||
| Predicate::WellFormed(..)
|
||||
| Predicate::ObjectSafe(..)
|
||||
| Predicate::ClosureKind(..)
|
||||
| Predicate::ConstEvaluatable(..) => None,
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,11 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
|
||||
}
|
||||
}
|
||||
|
||||
ty::Array(element, _) => {
|
||||
// Don't look into the len const as it doesn't affect regions
|
||||
compute_components(tcx, element, out);
|
||||
}
|
||||
|
||||
ty::Closure(_, ref substs) => {
|
||||
for upvar_ty in substs.as_closure().upvar_tys() {
|
||||
compute_components(tcx, upvar_ty, out);
|
||||
@ -158,7 +163,6 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
|
||||
ty::Opaque(..) | // OutlivesNominalType (ish)
|
||||
ty::Foreign(..) | // OutlivesNominalType
|
||||
ty::Str | // OutlivesScalar (ish)
|
||||
ty::Array(..) | // ...
|
||||
ty::Slice(..) | // ...
|
||||
ty::RawPtr(..) | // ...
|
||||
ty::Ref(..) | // OutlivesReference
|
||||
|
@ -2058,6 +2058,13 @@ define_print_and_forward_display! {
|
||||
print_value_path(def_id, substs),
|
||||
write("` can be evaluated"))
|
||||
}
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
p!(write("the constant `"),
|
||||
print(c1),
|
||||
write("` equals `"),
|
||||
print(c2),
|
||||
write("`"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,16 +432,17 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
|
||||
match relation.relate(&sz_a, &sz_b) {
|
||||
Ok(sz) => Ok(tcx.mk_ty(ty::Array(t, sz))),
|
||||
Err(err) => {
|
||||
// Check whether the lengths are both concrete/known values,
|
||||
// but are unequal, for better diagnostics.
|
||||
let sz_a = sz_a.try_eval_usize(tcx, relation.param_env());
|
||||
let sz_b = sz_b.try_eval_usize(tcx, relation.param_env());
|
||||
match (sz_a, sz_b) {
|
||||
(Some(sz_a_val), Some(sz_b_val)) => Err(TypeError::FixedArraySize(
|
||||
expected_found(relation, &sz_a_val, &sz_b_val),
|
||||
)),
|
||||
_ => Err(err),
|
||||
}
|
||||
// // Check whether the lengths are both concrete/known values,
|
||||
// // but are unequal, for better diagnostics.
|
||||
// let sz_a = sz_a.try_eval_usize(tcx, relation.param_env());
|
||||
// let sz_b = sz_b.try_eval_usize(tcx, relation.param_env());
|
||||
// match (sz_a, sz_b) {
|
||||
// (Some(sz_a_val), Some(sz_b_val)) => Err(TypeError::FixedArraySize(
|
||||
// expected_found(relation, &sz_a_val, &sz_b_val),
|
||||
// )),
|
||||
// _ => Err(err),
|
||||
// }
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -604,14 +605,14 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
|
||||
}
|
||||
|
||||
// FIXME(const_generics): this is wrong, as it is a projection
|
||||
(
|
||||
ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
|
||||
ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
|
||||
) if a_def_id == b_def_id && a_promoted == b_promoted => {
|
||||
let substs =
|
||||
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
|
||||
Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
|
||||
}
|
||||
// (
|
||||
// ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
|
||||
// ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
|
||||
// ) if a_def_id == b_def_id && a_promoted == b_promoted => {
|
||||
// let substs =
|
||||
// relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
|
||||
// Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
|
||||
// }
|
||||
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
|
||||
};
|
||||
new_const_val.map(|val| tcx.mk_const(ty::Const { val, ty: a.ty }))
|
||||
|
@ -240,6 +240,7 @@ impl fmt::Debug for ty::Predicate<'tcx> {
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
|
||||
}
|
||||
ty::Predicate::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -492,6 +493,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
tcx.lift(&substs).map(|substs| ty::Predicate::ConstEvaluatable(def_id, substs))
|
||||
}
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::Predicate::ConstEquate(c1, c2))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRe
|
||||
use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Const, Ty};
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
|
||||
use crate::borrow_check::constraints::OutlivesConstraint;
|
||||
@ -99,6 +99,8 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
NormalizationStrategy::Eager
|
||||
}
|
||||
|
@ -28,7 +28,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
|
||||
| Predicate::TypeOutlives(_)
|
||||
| Predicate::WellFormed(_)
|
||||
| Predicate::Projection(_)
|
||||
| Predicate::ConstEvaluatable(..) => continue,
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => continue,
|
||||
Predicate::ObjectSafe(_) => {
|
||||
bug!("object safe predicate on function: {:#?}", predicate)
|
||||
}
|
||||
|
@ -1277,7 +1277,8 @@ crate fn required_region_bounds(
|
||||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::RegionOutlives(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
ty::Predicate::TypeOutlives(predicate) => {
|
||||
// Search for a bound of the form `erased_self_ty
|
||||
// : 'a`, but be wary of something like `for<'a>
|
||||
|
@ -615,6 +615,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
obligation
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
ty::Predicate::ConstEquate(..) => {
|
||||
// Errors for `ConstEquate` predicates show up as
|
||||
// `SelectionError::ConstEvalFailure`,
|
||||
// not `Unimplemented`.
|
||||
span_bug!(
|
||||
span,
|
||||
"const-equate requirement gave wrong error: `{:?}`",
|
||||
obligation
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1092,6 +1104,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => {
|
||||
self.report_mismatched_consts(
|
||||
&error.obligation.cause,
|
||||
expected_found.expected,
|
||||
expected_found.found,
|
||||
err.clone(),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,9 @@ use rustc_data_structures::obligation_forest::ProcessResult;
|
||||
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
|
||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::error::ExpectedFound;
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeFoldable};
|
||||
use rustc_middle::ty::{self, Const, ToPolyTraitRef, Ty, TypeFoldable};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::project;
|
||||
@ -520,6 +521,65 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
||||
Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))),
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
debug!("equating consts: c1={:?} c2={:?}", c1, c2);
|
||||
|
||||
let stalled_on = &mut pending_obligation.stalled_on;
|
||||
|
||||
let mut evaluate = |c: &'tcx Const<'tcx>| {
|
||||
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
|
||||
match self.selcx.infcx().const_eval_resolve(
|
||||
obligation.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
promoted,
|
||||
Some(obligation.cause.span),
|
||||
) {
|
||||
Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)),
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
stalled_on.append(
|
||||
&mut substs.types().filter_map(|ty| TyOrConstInferVar::maybe_from_ty(ty)).collect(),
|
||||
);
|
||||
Err(ProcessResult::Unchanged)
|
||||
}
|
||||
Err(err) => {
|
||||
Err(ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(c)
|
||||
}
|
||||
};
|
||||
|
||||
match (evaluate(c1), evaluate(c2)) {
|
||||
(Ok(c1), Ok(c2)) => {
|
||||
match self
|
||||
.selcx
|
||||
.infcx()
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(c1, c2)
|
||||
{
|
||||
Ok(_) => ProcessResult::Changed(vec![]),
|
||||
Err(err) => {
|
||||
ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
|
||||
ExpectedFound::new(true, c1, c2),
|
||||
err,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME(skinny121) How to report both errors if both produces errors?
|
||||
(Err(result @ ProcessResult::Error(_)), _)
|
||||
| (_, Err(result @ ProcessResult::Error(_))) => result,
|
||||
(Err(ProcessResult::Unchanged), _) | (_, Err(ProcessResult::Unchanged)) => {
|
||||
ProcessResult::Unchanged
|
||||
}
|
||||
_ => {
|
||||
unreachable!("evaluate shouldn't itself return ProcessResult::Changed(..)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,8 @@ use crate::traits::{self, Obligation, ObligationCause};
|
||||
use rustc_errors::{Applicability, FatalError};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
|
||||
use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
|
||||
use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
|
||||
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
@ -281,7 +281,8 @@ fn predicates_reference_self(
|
||||
| ty::Predicate::RegionOutlives(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::Subtype(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
@ -313,7 +314,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::TypeOutlives(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => false,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => false,
|
||||
})
|
||||
}
|
||||
|
||||
@ -724,51 +726,65 @@ fn contains_illegal_self_type_reference<'tcx>(
|
||||
// object type, and we cannot resolve `Self as SomeOtherTrait`
|
||||
// without knowing what `Self` is.
|
||||
|
||||
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
|
||||
let self_ty = tcx.types.self_param;
|
||||
struct IllegalSelfTypeVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>>,
|
||||
}
|
||||
|
||||
let mut walker = ty.walk();
|
||||
while let Some(arg) = walker.next() {
|
||||
if arg == self_ty.into() {
|
||||
return true;
|
||||
}
|
||||
impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
match t.kind {
|
||||
ty::Param(_) => t == self.self_ty,
|
||||
ty::Projection(ref data) => {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
|
||||
// Special-case projections (everything else is walked normally).
|
||||
if let GenericArgKind::Type(ty) = arg.unpack() {
|
||||
if let ty::Projection(ref data) = ty.kind {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
// Compute supertraits of current trait lazily.
|
||||
if self.supertraits.is_none() {
|
||||
let trait_ref =
|
||||
ty::Binder::bind(ty::TraitRef::identity(self.tcx, self.trait_def_id));
|
||||
self.supertraits = Some(traits::supertraits(self.tcx, trait_ref).collect());
|
||||
}
|
||||
|
||||
// Compute supertraits of current trait lazily.
|
||||
if supertraits.is_none() {
|
||||
let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id));
|
||||
supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
|
||||
// Determine whether the trait reference `Foo as
|
||||
// SomeTrait` is in fact a supertrait of the
|
||||
// current trait. In that case, this type is
|
||||
// legal, because the type `X` will be specified
|
||||
// in the object type. Note that we can just use
|
||||
// direct equality here because all of these types
|
||||
// are part of the formal parameter listing, and
|
||||
// hence there should be no inference variables.
|
||||
let projection_trait_ref = ty::Binder::bind(data.trait_ref(self.tcx));
|
||||
let is_supertrait_of_current_trait =
|
||||
self.supertraits.as_ref().unwrap().contains(&projection_trait_ref);
|
||||
|
||||
if is_supertrait_of_current_trait {
|
||||
false // do not walk contained types, do not report error, do collect $200
|
||||
} else {
|
||||
t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
|
||||
}
|
||||
}
|
||||
|
||||
// Determine whether the trait reference `Foo as
|
||||
// SomeTrait` is in fact a supertrait of the
|
||||
// current trait. In that case, this type is
|
||||
// legal, because the type `X` will be specified
|
||||
// in the object type. Note that we can just use
|
||||
// direct equality here because all of these types
|
||||
// are part of the formal parameter listing, and
|
||||
// hence there should be no inference variables.
|
||||
let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx));
|
||||
let is_supertrait_of_current_trait =
|
||||
supertraits.as_ref().unwrap().contains(&projection_trait_ref);
|
||||
|
||||
if is_supertrait_of_current_trait {
|
||||
// Do not walk contained types, do not report error, do collect $200.
|
||||
walker.skip_current_subtree();
|
||||
}
|
||||
|
||||
// DO walk contained types, POSSIBLY reporting an error.
|
||||
_ => t.super_visit_with(self), // walk contained types, if any
|
||||
}
|
||||
}
|
||||
|
||||
// Walk contained types, if any.
|
||||
fn visit_const(&mut self, _c: &ty::Const<'tcx>) -> bool {
|
||||
// FIXME Look into the unevaluated constants for object safety violations.
|
||||
// Do not walk substitutions of unevaluated consts, as they contain `Self`, even
|
||||
// though the const expression doesn't necessary use it. Currently type variables
|
||||
// inside array length expressions are forbidden, so they can't break the above
|
||||
// rules.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
ty.visit_with(&mut IllegalSelfTypeVisitor {
|
||||
tcx,
|
||||
self_ty: tcx.types.self_param,
|
||||
trait_def_id,
|
||||
supertraits: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||
|
@ -386,11 +386,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
let constant = constant.super_fold_with(self);
|
||||
constant.eval(self.selcx.tcx(), self.param_env)
|
||||
}
|
||||
}
|
||||
|
||||
/// The guts of `normalize`: normalize a specific projection like `<T
|
||||
|
@ -201,9 +201,4 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
let constant = constant.super_fold_with(self);
|
||||
constant.eval(self.infcx.tcx, self.param_env)
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::fast_reject;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||
@ -503,9 +504,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
None,
|
||||
) {
|
||||
Ok(_) => Ok(EvaluatedToOk),
|
||||
Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2);
|
||||
|
||||
let evaluate = |c: &'tcx ty::Const<'tcx>| {
|
||||
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
|
||||
match self.infcx.const_eval_resolve(
|
||||
obligation.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
promoted,
|
||||
Some(obligation.cause.span),
|
||||
) {
|
||||
Ok(val) => Ok(ty::Const::from_value(self.tcx(), val, c.ty)),
|
||||
Err(ErrorHandled::TooGeneric) => Err(EvaluatedToAmbig),
|
||||
Err(_) => Err(EvaluatedToErr),
|
||||
}
|
||||
} else {
|
||||
Ok(c)
|
||||
}
|
||||
};
|
||||
|
||||
match (evaluate(c1), evaluate(c2)) {
|
||||
(Ok(c1), Ok(c2)) => {
|
||||
match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) {
|
||||
Ok(_) => Ok(EvaluatedToOk),
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
(Err(EvaluatedToErr), _) | (_, Err(EvaluatedToErr)) => Ok(EvaluatedToErr),
|
||||
_ => Ok(EvaluatedToAmbig),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,6 +102,10 @@ pub fn predicate_obligations<'a, 'tcx>(
|
||||
wf.compute(ty);
|
||||
}
|
||||
}
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
wf.compute(c1.ty);
|
||||
wf.compute(c2.ty);
|
||||
}
|
||||
}
|
||||
|
||||
wf.normalize()
|
||||
|
@ -100,7 +100,8 @@ fn compute_implied_outlives_bounds<'tcx>(
|
||||
| ty::Predicate::Projection(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => vec![],
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => vec![],
|
||||
|
||||
ty::Predicate::WellFormed(subty) => {
|
||||
wf_types.push(subty);
|
||||
|
@ -48,6 +48,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool {
|
||||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::Subtype(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => true,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => true,
|
||||
}
|
||||
}
|
||||
|
@ -810,7 +810,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::TypeOutlives(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
});
|
||||
|
||||
self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
|
||||
|
@ -1648,6 +1648,16 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
|
||||
|
||||
r.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
if let ty::ConstKind::Unevaluated(..) = c.val {
|
||||
// FIXME(lazy_normalization_consts) We currenctly don't detect lifetimes within substs
|
||||
// which would violate this check. Even though the particular substitution is not used
|
||||
// within the const, this should still be fixed.
|
||||
return false;
|
||||
}
|
||||
c.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
let prohibit_opaque = match item.kind {
|
||||
@ -3858,6 +3868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty::Predicate::WellFormed(..) => None,
|
||||
ty::Predicate::ObjectSafe(..) => None,
|
||||
ty::Predicate::ConstEvaluatable(..) => None,
|
||||
ty::Predicate::ConstEquate(..) => None,
|
||||
// N.B., this predicate is created by breaking down a
|
||||
// `ClosureType: FnFoo()` predicate, where
|
||||
// `ClosureType` represents some `Closure`. It can't
|
||||
|
@ -1156,7 +1156,8 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
|
||||
let node = tcx.hir().get(hir_id);
|
||||
let parent_def_id = match node {
|
||||
Node::ImplItem(_)
|
||||
Node::AnonConst(_)
|
||||
| Node::ImplItem(_)
|
||||
| Node::TraitItem(_)
|
||||
| Node::Variant(_)
|
||||
| Node::Ctor(..)
|
||||
@ -1164,34 +1165,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
Some(tcx.hir().local_def_id(parent_id).to_def_id())
|
||||
}
|
||||
// FIXME(#43408) enable this always when we get lazy normalization.
|
||||
Node::AnonConst(_) => {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
let parent_def_id = tcx.hir().local_def_id(parent_id);
|
||||
|
||||
// HACK(eddyb) this provides the correct generics when
|
||||
// `feature(const_generics)` is enabled, so that const expressions
|
||||
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
|
||||
if tcx.features().const_generics {
|
||||
Some(parent_def_id.to_def_id())
|
||||
} else {
|
||||
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
|
||||
match parent_node {
|
||||
// HACK(eddyb) this provides the correct generics for repeat
|
||||
// expressions' count (i.e. `N` in `[x; N]`), and explicit
|
||||
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
|
||||
// as they shouldn't be able to cause query cycle errors.
|
||||
Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
|
||||
| Node::Variant(Variant { disr_expr: Some(ref constant), .. })
|
||||
if constant.hir_id == hir_id =>
|
||||
{
|
||||
Some(parent_def_id.to_def_id())
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
|
||||
Some(tcx.closure_base_def_id(def_id))
|
||||
}
|
||||
|
@ -413,6 +413,7 @@ fn trait_predicate_kind<'tcx>(
|
||||
| ty::Predicate::Subtype(_)
|
||||
| ty::Predicate::ObjectSafe(_)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
||||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::Subtype(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => (),
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,7 +493,8 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
|
||||
Predicate::WellFormed(..)
|
||||
| Predicate::ObjectSafe(..)
|
||||
| Predicate::ClosureKind(..)
|
||||
| Predicate::ConstEvaluatable(..) => panic!("not user writable"),
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => panic!("not user writable"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user