Skip to content

Commit c6030c9

Browse files
authored
Rollup merge of #71973 - lcnr:lazy-norm, r=nikomatsakis
Lazy normalization of constants (Reprise) Continuation of #67890 by @Skinny121. Initial implementation of #60471 for constants. Perform normalization/evaluation of constants lazily, which is known as lazy normalization. Lazy normalization is only enabled when using `#![feature(lazy_normalization_consts)]`, by default constants are still evaluated eagerly as there are currently. Lazy normalization of constants is achieved with a new ConstEquate predicate which type inferences uses to delay checking whether constants are equal to each other until later, avoiding cycle errors. Note this doesn't allow the use of generics within repeat count expressions as that is still evaluated during conversion to mir. There are also quite a few other known problems with lazy normalization which will be fixed in future PRs. r? @nikomatsakis fixes #71922, fixes #71986
2 parents 58e6447 + 9da8a5b commit c6030c9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+669
-145
lines changed

src/librustc_infer/infer/canonical/query_response.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use rustc_middle::arena::ArenaAllocatable;
2525
use rustc_middle::ty::fold::TypeFoldable;
2626
use rustc_middle::ty::relate::TypeRelation;
2727
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
28-
use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt};
28+
use rustc_middle::ty::{self, BoundVar, Const, Ty, TyCtxt};
2929
use std::fmt::Debug;
3030

3131
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
@@ -671,6 +671,13 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
671671
});
672672
}
673673

674+
fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {
675+
span_bug!(
676+
self.cause.span(self.infcx.tcx),
677+
"lazy_normalization_consts: unreachable `const_equate`"
678+
);
679+
}
680+
674681
fn normalization() -> NormalizationStrategy {
675682
NormalizationStrategy::Eager
676683
}

src/librustc_infer/infer/combine.rs

+40-3
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use rustc_hir::def_id::DefId;
3939
use rustc_middle::ty::error::TypeError;
4040
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
4141
use rustc_middle::ty::subst::SubstsRef;
42-
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
42+
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeFoldable};
4343
use rustc_middle::ty::{IntType, UintType};
4444
use rustc_span::{Span, DUMMY_SP};
4545

@@ -126,7 +126,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
126126
b: &'tcx ty::Const<'tcx>,
127127
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>
128128
where
129-
R: TypeRelation<'tcx>,
129+
R: ConstEquateRelation<'tcx>,
130130
{
131131
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
132132
if a == b {
@@ -164,7 +164,22 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
164164
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
165165
return self.unify_const_variable(!a_is_expected, vid, a);
166166
}
167-
167+
(ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => {
168+
// FIXME(#59490): Need to remove the leak check to accomodate
169+
// escaping bound variables here.
170+
if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
171+
relation.const_equate_obligation(a, b);
172+
}
173+
return Ok(b);
174+
}
175+
(_, ty::ConstKind::Unevaluated(..)) if self.tcx.lazy_normalization() => {
176+
// FIXME(#59490): Need to remove the leak check to accomodate
177+
// escaping bound variables here.
178+
if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
179+
relation.const_equate_obligation(a, b);
180+
}
181+
return Ok(a);
182+
}
168183
_ => {}
169184
}
170185

@@ -375,6 +390,20 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
375390
debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
376391
Ok(Generalization { ty, needs_wf })
377392
}
393+
394+
pub fn add_const_equate_obligation(
395+
&mut self,
396+
a_is_expected: bool,
397+
a: &'tcx ty::Const<'tcx>,
398+
b: &'tcx ty::Const<'tcx>,
399+
) {
400+
let predicate = if a_is_expected {
401+
ty::Predicate::ConstEquate(a, b)
402+
} else {
403+
ty::Predicate::ConstEquate(b, a)
404+
};
405+
self.obligations.push(Obligation::new(self.trace.cause.clone(), self.param_env, predicate));
406+
}
378407
}
379408

380409
struct Generalizer<'cx, 'tcx> {
@@ -637,11 +666,19 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
637666
}
638667
}
639668
}
669+
ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(c),
640670
_ => relate::super_relate_consts(self, c, c),
641671
}
642672
}
643673
}
644674

675+
pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
676+
/// Register an obligation that both constants must be equal to each other.
677+
///
678+
/// If they aren't equal then the relation doesn't hold.
679+
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
680+
}
681+
645682
pub trait RelateResultCompare<'tcx, T> {
646683
fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T>
647684
where

src/librustc_infer/infer/equate.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::combine::{CombineFields, RelationDir};
1+
use super::combine::{CombineFields, ConstEquateRelation, RelationDir};
22
use super::Subtype;
33

44
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
@@ -140,3 +140,9 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
140140
}
141141
}
142142
}
143+
144+
impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> {
145+
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
146+
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
147+
}
148+
}

src/librustc_infer/infer/glb.rs

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::lattice::{self, LatticeDir};
33
use super::InferCtxt;
44
use super::Subtype;
55

6+
use crate::infer::combine::ConstEquateRelation;
67
use crate::traits::ObligationCause;
78
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
89
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -116,3 +117,9 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
116117
Ok(())
117118
}
118119
}
120+
121+
impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
122+
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
123+
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
124+
}
125+
}

src/librustc_infer/infer/lub.rs

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::lattice::{self, LatticeDir};
33
use super::InferCtxt;
44
use super::Subtype;
55

6+
use crate::infer::combine::ConstEquateRelation;
67
use crate::traits::ObligationCause;
78
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
89
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -100,6 +101,12 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
100101
}
101102
}
102103

104+
impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
105+
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
106+
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
107+
}
108+
}
109+
103110
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
104111
fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> {
105112
self.fields.infcx

src/librustc_infer/infer/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
14901490
self.report_and_explain_type_error(trace, &err)
14911491
}
14921492

1493+
pub fn report_mismatched_consts(
1494+
&self,
1495+
cause: &ObligationCause<'tcx>,
1496+
expected: &'tcx ty::Const<'tcx>,
1497+
actual: &'tcx ty::Const<'tcx>,
1498+
err: TypeError<'tcx>,
1499+
) -> DiagnosticBuilder<'tcx> {
1500+
let trace = TypeTrace::consts(cause, true, expected, actual);
1501+
self.report_and_explain_type_error(trace, &err)
1502+
}
1503+
14931504
pub fn replace_bound_vars_with_fresh_vars<T>(
14941505
&self,
14951506
span: Span,
@@ -1777,6 +1788,15 @@ impl<'tcx> TypeTrace<'tcx> {
17771788
TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
17781789
}
17791790

1791+
pub fn consts(
1792+
cause: &ObligationCause<'tcx>,
1793+
a_is_expected: bool,
1794+
a: &'tcx ty::Const<'tcx>,
1795+
b: &'tcx ty::Const<'tcx>,
1796+
) -> TypeTrace<'tcx> {
1797+
TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
1798+
}
1799+
17801800
pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> {
17811801
TypeTrace {
17821802
cause: ObligationCause::dummy(),

src/librustc_infer/infer/nll_relate/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
//! thing we relate in chalk are basically domain goals and their
2222
//! constituents)
2323
24+
use crate::infer::combine::ConstEquateRelation;
2425
use crate::infer::InferCtxt;
2526
use crate::infer::{ConstVarValue, ConstVariableValue};
2627
use rustc_data_structures::fx::FxHashMap;
@@ -77,6 +78,8 @@ pub trait TypeRelatingDelegate<'tcx> {
7778
/// delegate.
7879
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
7980

81+
fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
82+
8083
/// Creates a new universe index. Used when instantiating placeholders.
8184
fn create_next_universe(&mut self) -> ty::UniverseIndex;
8285

@@ -715,6 +718,15 @@ where
715718
}
716719
}
717720

721+
impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
722+
where
723+
D: TypeRelatingDelegate<'tcx>,
724+
{
725+
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
726+
self.delegate.const_equate(a, b);
727+
}
728+
}
729+
718730
/// When we encounter a binder like `for<..> fn(..)`, we actually have
719731
/// to walk the `fn` value to find all the values bound by the `for`
720732
/// (these are not explicitly present in the ty representation right
@@ -976,6 +988,7 @@ where
976988
}
977989
}
978990
}
991+
ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a),
979992
_ => relate::super_relate_consts(self, a, a),
980993
}
981994
}

src/librustc_infer/infer/outlives/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ pub fn explicit_outlives_bounds<'tcx>(
1919
| ty::Predicate::ObjectSafe(..)
2020
| ty::Predicate::ClosureKind(..)
2121
| ty::Predicate::TypeOutlives(..)
22-
| ty::Predicate::ConstEvaluatable(..) => None,
22+
| ty::Predicate::ConstEvaluatable(..)
23+
| ty::Predicate::ConstEquate(..) => None,
2324
ty::Predicate::RegionOutlives(ref data) => data
2425
.no_bound_vars()
2526
.map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)),

src/librustc_infer/infer/sub.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::combine::{CombineFields, RelationDir};
22
use super::SubregionOrigin;
33

4+
use crate::infer::combine::ConstEquateRelation;
45
use crate::traits::Obligation;
56
use rustc_middle::ty::fold::TypeFoldable;
67
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
@@ -169,3 +170,9 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
169170
self.fields.higher_ranked_sub(a, b, self.a_is_expected)
170171
}
171172
}
173+
174+
impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> {
175+
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
176+
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
177+
}
178+
}

src/librustc_infer/traits/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub mod util;
1010

1111
use rustc_hir as hir;
1212
use rustc_middle::ty::error::{ExpectedFound, TypeError};
13-
use rustc_middle::ty::{self, Ty};
13+
use rustc_middle::ty::{self, Const, Ty};
1414
use rustc_span::Span;
1515

1616
pub use self::FulfillmentErrorCode::*;
@@ -81,6 +81,7 @@ pub enum FulfillmentErrorCode<'tcx> {
8181
CodeSelectionError(SelectionError<'tcx>),
8282
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
8383
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
84+
CodeConstEquateError(ExpectedFound<&'tcx Const<'tcx>>, TypeError<'tcx>),
8485
CodeAmbiguity,
8586
}
8687

src/librustc_infer/traits/structural_impls.rs

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
4141
super::CodeSubtypeError(ref a, ref b) => {
4242
write!(f, "CodeSubtypeError({:?}, {:?})", a, b)
4343
}
44+
super::CodeConstEquateError(ref a, ref b) => {
45+
write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
46+
}
4447
super::CodeAmbiguity => write!(f, "Ambiguity"),
4548
}
4649
}

src/librustc_infer/traits/util.rs

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ pub fn anonymize_predicate<'tcx>(
4242
ty::Predicate::ConstEvaluatable(def_id, substs) => {
4343
ty::Predicate::ConstEvaluatable(def_id, substs)
4444
}
45+
46+
ty::Predicate::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2),
4547
}
4648
}
4749

@@ -187,6 +189,10 @@ impl Elaborator<'tcx> {
187189
// Currently, we do not elaborate const-evaluatable
188190
// predicates.
189191
}
192+
ty::Predicate::ConstEquate(..) => {
193+
// Currently, we do not elaborate const-equate
194+
// predicates.
195+
}
190196
ty::Predicate::RegionOutlives(..) => {
191197
// Nothing to elaborate from `'a: 'b`.
192198
}

src/librustc_lint/builtin.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1221,7 +1221,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
12211221
ObjectSafe(..) |
12221222
ClosureKind(..) |
12231223
Subtype(..) |
1224-
ConstEvaluatable(..) => continue,
1224+
ConstEvaluatable(..) |
1225+
ConstEquate(..) => continue,
12251226
};
12261227
if predicate.is_global() {
12271228
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {

src/librustc_middle/ty/context.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1339,7 +1339,7 @@ impl<'tcx> TyCtxt<'tcx> {
13391339

13401340
/// What mode(s) of borrowck should we run? AST? MIR? both?
13411341
/// (Also considers the `#![feature(nll)]` setting.)
1342-
pub fn borrowck_mode(&self) -> BorrowckMode {
1342+
pub fn borrowck_mode(self) -> BorrowckMode {
13431343
// Here are the main constraints we need to deal with:
13441344
//
13451345
// 1. An opts.borrowck_mode of `BorrowckMode::Migrate` is
@@ -1369,6 +1369,13 @@ impl<'tcx> TyCtxt<'tcx> {
13691369
self.sess.opts.borrowck_mode
13701370
}
13711371

1372+
/// If `true`, we should use lazy normalization for constants, otherwise
1373+
/// we still evaluate them eagerly.
1374+
#[inline]
1375+
pub fn lazy_normalization(self) -> bool {
1376+
self.features().const_generics
1377+
}
1378+
13721379
#[inline]
13731380
pub fn local_crate_exports_generics(self) -> bool {
13741381
debug_assert!(self.sess.opts.share_generics());

src/librustc_middle/ty/mod.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,9 @@ pub enum Predicate<'tcx> {
10541054

10551055
/// Constant initializer must evaluate successfully.
10561056
ConstEvaluatable(DefId, SubstsRef<'tcx>),
1057+
1058+
/// Constants must be equal. The first component is the const that is expected.
1059+
ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
10571060
}
10581061

10591062
/// The crate outlives map is computed during typeck and contains the
@@ -1172,6 +1175,9 @@ impl<'tcx> Predicate<'tcx> {
11721175
Predicate::ConstEvaluatable(def_id, const_substs) => {
11731176
Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs))
11741177
}
1178+
Predicate::ConstEquate(c1, c2) => {
1179+
Predicate::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs))
1180+
}
11751181
}
11761182
}
11771183
}
@@ -1349,7 +1355,8 @@ impl<'tcx> Predicate<'tcx> {
13491355
| Predicate::ObjectSafe(..)
13501356
| Predicate::ClosureKind(..)
13511357
| Predicate::TypeOutlives(..)
1352-
| Predicate::ConstEvaluatable(..) => None,
1358+
| Predicate::ConstEvaluatable(..)
1359+
| Predicate::ConstEquate(..) => None,
13531360
}
13541361
}
13551362

@@ -1363,7 +1370,8 @@ impl<'tcx> Predicate<'tcx> {
13631370
| Predicate::WellFormed(..)
13641371
| Predicate::ObjectSafe(..)
13651372
| Predicate::ClosureKind(..)
1366-
| Predicate::ConstEvaluatable(..) => None,
1373+
| Predicate::ConstEvaluatable(..)
1374+
| Predicate::ConstEquate(..) => None,
13671375
}
13681376
}
13691377
}

0 commit comments

Comments
 (0)