(
ty::PredicateKind::ConstEvaluatable(a),
ty::PredicateKind::ConstEvaluatable(b),
- ) => tcx.try_unify_abstract_consts(self_param_env.and((a, b))),
+ ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
(
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
// Explicit `enum` discriminant values must const-evaluate successfully.
if let Some(discr_def_id) = variant.explicit_discr {
- let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id());
-
let cause = traits::ObligationCause::new(
tcx.def_span(discr_def_id),
wfcx.body_id,
cause,
wfcx.param_env,
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
- ty::UnevaluatedConst::new(
- ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
- discr_substs,
- ),
+ ty::Const::from_anon_const(tcx, discr_def_id),
))
.to_predicate(tcx),
));
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
let def_id = self.tcx.hir().local_def_id(c.hir_id);
let ct = ty::Const::from_anon_const(self.tcx, def_id);
- if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
+ if let ty::ConstKind::Unevaluated(_) = ct.kind() {
let span = self.tcx.hir().span(c.hir_id);
self.preds.insert((
- ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
.to_predicate(self.tcx),
span,
));
self.try_eval_usize(tcx, param_env)
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
}
+
+ pub fn is_ct_infer(self) -> bool {
+ matches!(self.kind(), ty::ConstKind::Infer(_))
+ }
}
pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> {
self.add_substs(substs);
}
ty::PredicateKind::ConstEvaluatable(uv) => {
- self.add_unevaluated_const(uv);
+ self.add_const(uv);
}
ty::PredicateKind::ConstEquate(expected, found) => {
self.add_const(expected);
Coerce(CoercePredicate<'tcx>),
/// Constant initializer must evaluate successfully.
- ConstEvaluatable(ty::UnevaluatedConst<'tcx>),
+ ConstEvaluatable(ty::Const<'tcx>),
/// Constants must be equal. The first component is the const that is expected.
ConstEquate(Const<'tcx>, Const<'tcx>),
print_value_path(closure_def_id, &[]),
write("` implements the trait `{}`", kind))
}
- ty::PredicateKind::ConstEvaluatable(uv) => {
- p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated")
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ p!("the constant `", print(ct), "` can be evaluated")
}
ty::PredicateKind::ConstEquate(c1, c2) => {
p!("the constant `", print(c1), "` equals `", print(c2), "`")
ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
}
- ty::PredicateKind::ConstEvaluatable(uv) => {
- write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs)
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ write!(f, "ConstEvaluatable({ct:?})")
}
ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
_ => bug!("expected a const, but found another kind"),
}
}
+
+ pub fn is_non_region_infer(self) -> bool {
+ match self.unpack() {
+ GenericArgKind::Lifetime(_) => false,
+ GenericArgKind::Type(ty) => ty.is_ty_infer(),
+ GenericArgKind::Const(ct) => ct.is_ct_infer(),
+ }
+ }
}
impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
}
}
+impl<'tcx> ty::Const<'tcx> {
+ /// Iterator that walks `self` and any types reachable from
+ /// `self`, in depth-first order. Note that just walks the types
+ /// that appear in `self`, it does not descend into the fields of
+ /// structs or variants. For example:
+ ///
+ /// ```text
+ /// isize => { isize }
+ /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+ /// [isize] => { [isize], isize }
+ /// ```
+ pub fn walk(self) -> TypeWalker<'tcx> {
+ TypeWalker::new(self.into())
+ }
+}
+
/// We push `GenericArg`s on the stack in reverse order so as to
/// maintain a pre-order traversal. As of the time of this
/// writing, the fact that the traversal is pre-order is not
ty.visit_with(self)
}
ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE,
- ty::PredicateKind::ConstEvaluatable(uv)
- if self.def_id_visitor.tcx().features().generic_const_exprs =>
- {
- let tcx = self.def_id_visitor.tcx();
- if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) {
- self.visit_abstract_const_expr(tcx, ct)?;
- }
- ControlFlow::CONTINUE
- }
+ ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self),
ty::PredicateKind::WellFormed(arg) => arg.visit_with(self),
_ => bug!("unexpected predicate: {:?}", predicate),
}
#[instrument(skip(infcx), level = "debug")]
pub fn is_const_evaluatable<'tcx>(
infcx: &InferCtxt<'tcx>,
- uv: ty::UnevaluatedConst<'tcx>,
+ ct: ty::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>,
span: Span,
) -> Result<(), NotConstEvaluatable> {
let tcx = infcx.tcx;
+ let uv = match ct.kind() {
+ ty::ConstKind::Unevaluated(uv) => uv,
+ ty::ConstKind::Param(_)
+ | ty::ConstKind::Bound(_, _)
+ | ty::ConstKind::Placeholder(_)
+ | ty::ConstKind::Value(_)
+ | ty::ConstKind::Error(_) => return Ok(()),
+ ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer),
+ };
if tcx.features().generic_const_exprs {
if let Some(ct) = AbstractConst::new(tcx, uv)? {
for pred in param_env.caller_bounds() {
match pred.kind().skip_binder() {
ty::PredicateKind::ConstEvaluatable(uv) => {
- if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
+ if let Some(b_ct) = AbstractConst::from_const(tcx, uv)? {
let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
// Try to unify with each subtree in the AbstractConst to allow for
}
match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::ConstEvaluatable(uv) => {
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
+ bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
+ };
let mut err =
self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
let const_span = self.tcx.def_span(uv.def.did);
if predicate.references_error() || self.is_tainted_by_errors() {
return;
}
- let subst = data.substs.iter().find(|g| g.has_non_region_infer());
+ let subst = data.walk().find(|g| g.is_non_region_infer());
if let Some(subst) = subst {
let err = self.emit_inference_failure_err(
body_id,
Err(NotConstEvaluatable::MentionsInfer) => {
pending_obligation.stalled_on.clear();
pending_obligation.stalled_on.extend(
- uv.substs
- .iter()
- .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
+ uv.walk().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
);
ProcessResult::Unchanged
}
wf.compute(a.into());
wf.compute(b.into());
}
- ty::PredicateKind::ConstEvaluatable(uv) => {
- let obligations = wf.nominal_obligations(uv.def.did, uv.substs);
- wf.out.extend(obligations);
-
- for arg in uv.substs.iter() {
- wf.compute(arg);
- }
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ wf.compute(ct.into());
}
ty::PredicateKind::ConstEquate(c1, c2) => {
wf.compute(c1.into());
// obligations are handled by the parent (e.g. `ty::Ref`).
GenericArgKind::Lifetime(_) => continue,
- GenericArgKind::Const(constant) => {
- match constant.kind() {
+ GenericArgKind::Const(ct) => {
+ match ct.kind() {
ty::ConstKind::Unevaluated(uv) => {
let obligations = self.nominal_obligations(uv.def.did, uv.substs);
self.out.extend(obligations);
let predicate =
- ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv))
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct))
.to_predicate(self.tcx());
let cause = self.cause(traits::WellFormed(None));
self.out.push(traits::Obligation::with_depth(
cause,
self.recursion_depth,
self.param_env,
- ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into()))
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into()))
.to_predicate(self.tcx()),
));
}