Skip to content

[BE FAIR DON'T CARE] lazy norm self review #1

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/librustc_feature/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,9 @@ declare_features! (
/// Allow negative trait implementations.
(active, negative_impls, "1.44.0", Some(68318), None),

/// Lazily evaluate constants. Which allows constants to depend on type parameters.
(active, lazy_normalization_consts, "1.44.0", Some(60471), None),

/// Allows the use of `#[target_feature]` on safe functions.
(active, target_feature_11, "1.45.0", Some(69098), None),

Expand All @@ -581,4 +584,5 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::raw_dylib,
sym::const_trait_impl,
sym::const_trait_bound_opt_out,
sym::lazy_normalization_consts,
];
6 changes: 5 additions & 1 deletion src/librustc_infer/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use rustc_middle::arena::ArenaAllocatable;
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> {
Expand Down Expand Up @@ -671,6 +671,10 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
});
}

fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {
unimplemented!()
}

fn normalization() -> NormalizationStrategy {
NormalizationStrategy::Eager
}
Expand Down
39 changes: 37 additions & 2 deletions src/librustc_infer/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
b: &'tcx ty::Const<'tcx>,
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>
where
R: TypeRelation<'tcx>,
R: ConstEquateRelation<'tcx>,
{
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
if a == b {
Expand Down Expand Up @@ -164,7 +164,18 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
return self.unify_const_variable(!a_is_expected, vid, a);
}

(ty::ConstKind::Unevaluated(..), _)
if self.tcx.features().lazy_normalization_consts =>
{
relation.const_equate_obligation(a, b);
return Ok(b);
}
(_, ty::ConstKind::Unevaluated(..))
if self.tcx.features().lazy_normalization_consts =>
{
relation.const_equate_obligation(a, b);
return Ok(a);
}
_ => {}
}

Expand Down Expand Up @@ -375,6 +386,20 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
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> {
Expand Down Expand Up @@ -635,11 +660,21 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
}
}
}
ty::ConstKind::Unevaluated(..) if self.tcx().features().lazy_normalization_consts => {
Ok(c)
}
_ => relate::super_relate_consts(self, c, c),
}
}
}

pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
/// Register an obligation that both constants must be equal to each other.
///
/// If they aren't equal then the relation doesn't hold.
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
}

pub trait RelateResultCompare<'tcx, T> {
fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T>
where
Expand Down
8 changes: 7 additions & 1 deletion src/librustc_infer/infer/equate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::combine::{CombineFields, RelationDir};
use super::combine::{CombineFields, ConstEquateRelation, RelationDir};
use super::Subtype;

use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
Expand Down Expand Up @@ -140,3 +140,9 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
}
}
}

impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> {
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
}
}
7 changes: 7 additions & 0 deletions src/librustc_infer/infer/glb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use super::lattice::{self, LatticeDir};
use super::InferCtxt;
use super::Subtype;

use crate::infer::combine::ConstEquateRelation;
use crate::traits::ObligationCause;
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, Ty, TyCtxt};
Expand Down Expand Up @@ -116,3 +117,9 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
Ok(())
}
}

impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
}
}
7 changes: 7 additions & 0 deletions src/librustc_infer/infer/lub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use super::lattice::{self, LatticeDir};
use super::InferCtxt;
use super::Subtype;

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

impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
}
}

impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> {
self.fields.infcx
Expand Down
20 changes: 20 additions & 0 deletions src/librustc_infer/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1457,6 +1457,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
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,
Expand Down Expand Up @@ -1743,6 +1754,15 @@ impl<'tcx> TypeTrace<'tcx> {
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(),
Expand Down
15 changes: 15 additions & 0 deletions src/librustc_infer/infer/nll_relate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
//! thing we relate in chalk are basically domain goals and their
//! constituents)

use crate::infer::combine::ConstEquateRelation;
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
use rustc_data_structures::fx::FxHashMap;
Expand Down Expand Up @@ -77,6 +78,8 @@ pub trait TypeRelatingDelegate<'tcx> {
/// 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;

Expand Down Expand Up @@ -715,6 +718,15 @@ where
}
}

impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
self.delegate.const_equate(a, b);
}
}

/// When we encounter a binder like `for<..> fn(..)`, we actually have
/// to walk the `fn` value to find all the values bound by the `for`
/// (these are not explicitly present in the ty representation right
Expand Down Expand Up @@ -974,6 +986,9 @@ where
}
}
}
ty::ConstKind::Unevaluated(..) if self.tcx().features().lazy_normalization_consts => {
Ok(a)
}
_ => relate::super_relate_consts(self, a, a),
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_infer/infer/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ pub fn explicit_outlives_bounds<'tcx>(
| 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)),
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_infer/infer/sub.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::combine::{CombineFields, RelationDir};
use super::SubregionOrigin;

use crate::infer::combine::ConstEquateRelation;
use crate::traits::Obligation;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
Expand Down Expand Up @@ -169,3 +170,9 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
self.fields.higher_ranked_sub(a, b, self.a_is_expected)
}
}

impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> {
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
}
}
3 changes: 2 additions & 1 deletion src/librustc_infer/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub mod util;

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::*;
Expand Down Expand Up @@ -80,6 +80,7 @@ pub enum FulfillmentErrorCode<'tcx> {
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,
}

Expand Down
3 changes: 3 additions & 0 deletions src/librustc_infer/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
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"),
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_infer/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pub fn anonymize_predicate<'tcx>(
ty::Predicate::ConstEvaluatable(def_id, substs) => {
ty::Predicate::ConstEvaluatable(def_id, substs)
}

ty::Predicate::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2),
}
}

Expand Down Expand Up @@ -188,6 +190,10 @@ impl Elaborator<'tcx> {
// 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`.
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
ObjectSafe(..) |
ClosureKind(..) |
Subtype(..) |
ConstEvaluatable(..) => continue,
ConstEvaluatable(..) |
ConstEquate(..) => continue,
};
if predicate.is_global() {
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
Expand Down
12 changes: 10 additions & 2 deletions src/librustc_middle/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,9 @@ pub enum Predicate<'tcx> {

/// 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
Expand Down Expand Up @@ -1311,6 +1314,9 @@ impl<'tcx> Predicate<'tcx> {
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))
}
}
}
}
Expand Down Expand Up @@ -1488,7 +1494,8 @@ impl<'tcx> Predicate<'tcx> {
| Predicate::ObjectSafe(..)
| Predicate::ClosureKind(..)
| Predicate::TypeOutlives(..)
| Predicate::ConstEvaluatable(..) => None,
| Predicate::ConstEvaluatable(..)
| Predicate::ConstEquate(..) => None,
}
}

Expand All @@ -1502,7 +1509,8 @@ impl<'tcx> Predicate<'tcx> {
| Predicate::WellFormed(..)
| Predicate::ObjectSafe(..)
| Predicate::ClosureKind(..)
| Predicate::ConstEvaluatable(..) => None,
| Predicate::ConstEvaluatable(..)
| Predicate::ConstEquate(..) => None,
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/librustc_middle/ty/outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
}
}

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);
Expand Down Expand Up @@ -160,7 +165,6 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
ty::Opaque(..) | // OutlivesNominalType (ish)
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
ty::Array(..) | // ...
ty::Slice(..) | // ...
ty::RawPtr(..) | // ...
ty::Ref(..) | // OutlivesReference
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_middle/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2063,6 +2063,13 @@ define_print_and_forward_display! {
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("`"))
}
}
}

Expand Down
Loading