Skip to content

Commit cb2308d

Browse files
committed
implement wf checking for constants
1 parent d3cba25 commit cb2308d

File tree

1 file changed

+87
-38
lines changed
  • src/librustc_trait_selection/traits

1 file changed

+87
-38
lines changed

src/librustc_trait_selection/traits/wf.rs

Lines changed: 87 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::traits;
44
use rustc_hir as hir;
55
use rustc_hir::def_id::DefId;
66
use rustc_hir::lang_items;
7-
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
7+
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
88
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
99
use rustc_span::Span;
1010
use std::rc::Rc;
@@ -37,14 +37,44 @@ pub fn obligations<'a, 'tcx>(
3737
};
3838

3939
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
40-
wf.compute(ty);
40+
wf.compute(ty.into());
4141
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
4242

4343
let result = wf.normalize();
4444
debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result);
4545
Some(result)
4646
}
4747

48+
/// Returns the set of obligations needed to make the `constant` well-formed.
49+
pub fn const_obligations<'a, 'tcx>(
50+
infcx: &InferCtxt<'a, 'tcx>,
51+
param_env: ty::ParamEnv<'tcx>,
52+
body_id: hir::HirId,
53+
constant: &'tcx ty::Const<'tcx>,
54+
span: Span,
55+
) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
56+
let constant = match constant.val {
57+
ty::ConstKind::Infer(infer) => {
58+
let resolved = infcx.shallow_resolve(infer);
59+
if resolved == infer {
60+
// No progress.
61+
return None;
62+
}
63+
64+
infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ..*constant })
65+
}
66+
_ => constant,
67+
};
68+
69+
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
70+
wf.compute(constant.into());
71+
debug!("wf::const obligations({:?}, body_id={:?}) = {:?}", constant, body_id, wf.out);
72+
73+
let result = wf.normalize();
74+
debug!("wf::const obligations({:?}, body_id={:?}) ~~> {:?}", constant, body_id, result);
75+
Some(result)
76+
}
77+
4878
/// Returns the obligations that make this trait reference
4979
/// well-formed. For example, if there is a trait `Set` defined like
5080
/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
@@ -78,33 +108,36 @@ pub fn predicate_obligations<'a, 'tcx>(
78108
}
79109
ty::PredicateKind::RegionOutlives(..) => {}
80110
ty::PredicateKind::TypeOutlives(t) => {
81-
wf.compute(t.skip_binder().0);
111+
wf.compute(t.skip_binder().0.into());
82112
}
83113
ty::PredicateKind::Projection(t) => {
84114
let t = t.skip_binder(); // (*)
85115
wf.compute_projection(t.projection_ty);
86-
wf.compute(t.ty);
116+
wf.compute(t.ty.into());
87117
}
88118
&ty::PredicateKind::WellFormed(t) => {
89-
wf.compute(t);
119+
wf.compute(t.into());
90120
}
91121
ty::PredicateKind::ObjectSafe(_) => {}
92122
ty::PredicateKind::ClosureKind(..) => {}
93123
ty::PredicateKind::Subtype(data) => {
94-
wf.compute(data.skip_binder().a); // (*)
95-
wf.compute(data.skip_binder().b); // (*)
124+
wf.compute(data.skip_binder().a.into()); // (*)
125+
wf.compute(data.skip_binder().b.into()); // (*)
96126
}
97127
&ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
98128
let obligations = wf.nominal_obligations(def_id, substs);
99129
wf.out.extend(obligations);
100130

101-
for ty in substs.types() {
102-
wf.compute(ty);
131+
for subst in substs.iter().copied() {
132+
wf.compute(subst);
103133
}
104134
}
105135
ty::PredicateKind::ConstEquate(c1, c2) => {
106-
wf.compute(c1.ty);
107-
wf.compute(c2.ty);
136+
wf.compute(c1.ty.into());
137+
wf.compute(c2.ty.into());
138+
}
139+
ty::Predicate::WellFormedConst(constant) => {
140+
wf.compute(constant.into());
108141
}
109142
}
110143

@@ -213,7 +246,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
213246
self.infcx.tcx
214247
}
215248

216-
fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
249+
fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
217250
traits::ObligationCause::new(self.span, self.body_id, code)
218251
}
219252

@@ -300,22 +333,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
300333
}
301334
}
302335

303-
/// Pushes the obligations required for an array length to be WF
304-
/// into `self.out`.
305-
fn compute_array_len(&mut self, constant: ty::Const<'tcx>) {
306-
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val {
307-
assert!(promoted.is_none());
308-
309-
let obligations = self.nominal_obligations(def_id, substs);
310-
self.out.extend(obligations);
311-
312-
let predicate =
313-
ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx());
314-
let cause = self.cause(traits::MiscObligation);
315-
self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
316-
}
317-
}
318-
319336
fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
320337
if !subty.has_escaping_bound_vars() {
321338
let cause = self.cause(cause);
@@ -332,8 +349,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
332349
}
333350

334351
/// Pushes all the predicates needed to validate that `ty` is WF into `out`.
335-
fn compute(&mut self, ty: Ty<'tcx>) {
336-
let mut walker = ty.walk();
352+
fn compute(&mut self, arg: GenericArg<'tcx>) {
353+
let mut walker = arg.walk();
337354
let param_env = self.param_env;
338355
while let Some(arg) = walker.next() {
339356
let ty = match arg.unpack() {
@@ -343,9 +360,43 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
343360
// obligations are handled by the parent (e.g. `ty::Ref`).
344361
GenericArgKind::Lifetime(_) => continue,
345362

346-
// FIXME(eddyb) this is wrong and needs to be replaced
347-
// (see https://github.com/rust-lang/rust/pull/70107).
348-
GenericArgKind::Const(_) => continue,
363+
GenericArgKind::Const(constant) => {
364+
match constant.val {
365+
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
366+
assert!(promoted.is_none());
367+
368+
let obligations = self.nominal_obligations(def_id, substs);
369+
self.out.extend(obligations);
370+
371+
let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx());
372+
let cause = self.cause(traits::MiscObligation);
373+
self.out.push(traits::Obligation::new(
374+
cause,
375+
self.param_env,
376+
predicate,
377+
));
378+
}
379+
ty::ConstKind::Infer(infer) => {
380+
let resolved = self.infcx.shallow_resolve(infer);
381+
// the `InferConst` changed, meaning that we made progress.
382+
if resolved != infer {
383+
let cause = self.cause(traits::MiscObligation);
384+
385+
let resolved_constant = self.infcx.tcx.mk_const(ty::Const {
386+
val: ty::ConstKind::Infer(resolved),
387+
..*constant
388+
});
389+
self.out.push(traits::Obligation::new(
390+
cause,
391+
self.param_env,
392+
ty::PredicateKind::WellFormedConst(resolved_constant).to_predicate(self.tcx()),
393+
));
394+
}
395+
}
396+
_ => (),
397+
}
398+
continue;
399+
}
349400
};
350401

351402
match ty.kind {
@@ -375,10 +426,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
375426
self.require_sized(subty, traits::SliceOrArrayElem);
376427
}
377428

378-
ty::Array(subty, len) => {
429+
ty::Array(subty, _) => {
379430
self.require_sized(subty, traits::SliceOrArrayElem);
380-
// FIXME(eddyb) handle `GenericArgKind::Const` above instead.
381-
self.compute_array_len(*len);
382431
}
383432

384433
ty::Tuple(ref tys) => {
@@ -467,7 +516,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
467516
walker.skip_current_subtree(); // subtree handled below
468517
for upvar_ty in substs.as_closure().upvar_tys() {
469518
// FIXME(eddyb) add the type to `walker` instead of recursing.
470-
self.compute(upvar_ty);
519+
self.compute(upvar_ty.into());
471520
}
472521
}
473522

@@ -540,7 +589,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
540589
} else {
541590
// Yes, resolved, proceed with the result.
542591
// FIXME(eddyb) add the type to `walker` instead of recursing.
543-
self.compute(ty);
592+
self.compute(ty.into());
544593
}
545594
}
546595
}

0 commit comments

Comments
 (0)