Skip to content

Commit 9f59db5

Browse files
authored
Rollup merge of rust-lang#71973 - lcnr:lazy-norm, r=nikomatsakis
Lazy normalization of constants (Reprise) Continuation of rust-lang#67890 by @Skinny121. Initial implementation of rust-lang#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 rust-lang#71922, fixes rust-lang#71986
2 parents 9a519d4 + 9da8a5b commit 9f59db5

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

Lines changed: 8 additions & 1 deletion
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

Lines changed: 40 additions & 3 deletions
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

Lines changed: 7 additions & 1 deletion
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

Lines changed: 7 additions & 0 deletions
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

Lines changed: 7 additions & 0 deletions
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

Lines changed: 20 additions & 0 deletions
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

Lines changed: 13 additions & 0 deletions
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 7 additions & 0 deletions
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

Lines changed: 2 additions & 1 deletion
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

0 commit comments

Comments
 (0)