the need to evaluate consts eagerly and therefore gets around const eval query cycles.
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> {
});
}
+ 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
}
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
return self.unify_const_variable(!a_is_expected, vid, a);
}
-
_ => {}
}
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> {
}
}
}
+ ty::ConstKind::Unevaluated(..) => Ok(c),
_ => relate::super_relate_consts(self, c, c),
}
}
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;
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>(
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>(
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>(
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,
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(),
/// 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;
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)
}
}
}
}
+ ty::ConstKind::Unevaluated(..) => Ok(a),
_ => relate::super_relate_consts(self, a, a),
}
}
| 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)),
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>(
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::*;
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,
}
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"),
}
}
ty::Predicate::ConstEvaluatable(def_id, substs) => {
ty::Predicate::ConstEvaluatable(def_id, substs)
}
+
+ ty::Predicate::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2),
}
}
// 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`.
}
ObjectSafe(..) |
ClosureKind(..) |
Subtype(..) |
- ConstEvaluatable(..) => continue,
+ ConstEvaluatable(..) |
+ ConstEquate(..) => continue,
};
if predicate.is_global() {
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
/// 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
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))
+ }
}
}
}
| Predicate::ObjectSafe(..)
| Predicate::ClosureKind(..)
| Predicate::TypeOutlives(..)
- | Predicate::ConstEvaluatable(..) => None,
+ | Predicate::ConstEvaluatable(..)
+ | Predicate::ConstEquate(..) => None,
}
}
| Predicate::WellFormed(..)
| Predicate::ObjectSafe(..)
| Predicate::ClosureKind(..)
- | Predicate::ConstEvaluatable(..) => None,
+ | Predicate::ConstEvaluatable(..)
+ | Predicate::ConstEquate(..) => None,
}
}
}
}
}
+ 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);
ty::Opaque(..) | // OutlivesNominalType (ish)
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
- ty::Array(..) | // ...
ty::Slice(..) | // ...
ty::RawPtr(..) | // ...
ty::Ref(..) | // OutlivesReference
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("`"))
+ }
}
}
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)
}
}
}
}
// 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 }))
ty::Predicate::ConstEvaluatable(def_id, substs) => {
write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
}
+ ty::Predicate::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
}
}
}
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))
+ }
}
}
}
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;
}
}
+ fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
+
fn normalization() -> NormalizationStrategy {
NormalizationStrategy::Eager
}
| Predicate::TypeOutlives(_)
| Predicate::WellFormed(_)
| Predicate::Projection(_)
- | Predicate::ConstEvaluatable(..) => continue,
+ | Predicate::ConstEvaluatable(..)
+ | Predicate::ConstEquate(..) => continue,
Predicate::ObjectSafe(_) => {
bug!("object safe predicate on function: {:#?}", predicate)
}
| 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>
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
+ )
+ }
}
}
)
.emit();
}
+ FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => {
+ self.report_mismatched_consts(
+ &error.obligation.cause,
+ expected_found.expected,
+ expected_found.found,
+ err.clone(),
+ )
+ .emit();
+ }
}
}
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;
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(..)")
+ }
+ }
+ }
}
}
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;
| ty::Predicate::RegionOutlives(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
- | ty::Predicate::ConstEvaluatable(..) => None,
+ | ty::Predicate::ConstEvaluatable(..)
+ | ty::Predicate::ConstEquate(..) => None,
}
})
.collect()
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::TypeOutlives(..)
- | ty::Predicate::ConstEvaluatable(..) => false,
+ | ty::Predicate::ConstEvaluatable(..)
+ | ty::Predicate::ConstEquate(..) => false,
})
}
// 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;
-
- let mut walker = ty.walk();
- while let Some(arg) = walker.next() {
- if arg == self_ty.into() {
- return true;
- }
-
- // 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`.
+ struct IllegalSelfTypeVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ self_ty: Ty<'tcx>,
+ trait_def_id: DefId,
+ supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>>,
+ }
- // 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());
- }
+ 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`.
+
+ // 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());
+ }
- // 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();
+ // 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
+ }
}
-
- // 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<'_>) {
_ => 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
_ => 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)
- }
}
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};
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),
+ }
+ }
}
}
wf.compute(ty);
}
}
+ ty::Predicate::ConstEquate(c1, c2) => {
+ wf.compute(c1.ty);
+ wf.compute(c2.ty);
+ }
}
wf.normalize()
| 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);
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
- | ty::Predicate::ConstEvaluatable(..) => true,
+ | ty::Predicate::ConstEvaluatable(..)
+ | ty::Predicate::ConstEquate(..) => true,
}
}
| 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| {
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 {
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
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(..)
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))
}
| ty::Predicate::Subtype(_)
| ty::Predicate::ObjectSafe(_)
| ty::Predicate::ClosureKind(..)
- | ty::Predicate::ConstEvaluatable(..) => None,
+ | ty::Predicate::ConstEvaluatable(..)
+ | ty::Predicate::ConstEquate(..) => None,
}
}
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
- | ty::Predicate::ConstEvaluatable(..) => (),
+ | ty::Predicate::ConstEvaluatable(..)
+ | ty::Predicate::ConstEquate(..) => (),
}
}
Predicate::WellFormed(..)
| Predicate::ObjectSafe(..)
| Predicate::ClosureKind(..)
- | Predicate::ConstEvaluatable(..) => panic!("not user writable"),
+ | Predicate::ConstEvaluatable(..)
+ | Predicate::ConstEquate(..) => panic!("not user writable"),
}
}
}