diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 7b3c599e8c7ca..c973a8d9a917e 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -558,6 +558,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), // ------------------------------------------------------------------------- // feature-group-end: actual feature gates @@ -575,4 +578,5 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::raw_dylib, sym::const_trait_impl, sym::const_trait_bound_opt_out, + sym::lazy_normalization_consts, ]; diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index 79a0a5076241f..c0f169817e558 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -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> { @@ -675,6 +675,10 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { bug!("should never be invoked with eager normalization") } + fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) { + unimplemented!() + } + fn normalization() -> NormalizationStrategy { NormalizationStrategy::Eager } diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index c630f58abf985..8fb21f6853f28 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -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 { @@ -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); + } _ => {} } @@ -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> { @@ -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(&self, t: T, f: F) -> RelateResult<'tcx, T> where diff --git a/src/librustc_infer/infer/equate.rs b/src/librustc_infer/infer/equate.rs index e05094cda2762..5fcce37768a8c 100644 --- a/src/librustc_infer/infer/equate.rs +++ b/src/librustc_infer/infer/equate.rs @@ -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}; @@ -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); + } +} diff --git a/src/librustc_infer/infer/glb.rs b/src/librustc_infer/infer/glb.rs index f95d74a9340c9..ec219a95b9441 100644 --- a/src/librustc_infer/infer/glb.rs +++ b/src/librustc_infer/infer/glb.rs @@ -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}; @@ -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); + } +} diff --git a/src/librustc_infer/infer/lub.rs b/src/librustc_infer/infer/lub.rs index 492f2b229d36d..a0453db2cb499 100644 --- a/src/librustc_infer/infer/lub.rs +++ b/src/librustc_infer/infer/lub.rs @@ -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}; @@ -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 diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index edaa7a04b34d0..dc78b1bb31ab8 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -1452,6 +1452,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( &self, span: Span, @@ -1738,6 +1749,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(), diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index 44bacfa80e125..4fac5d2dd58b3 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -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 crate::traits::DomainGoal; @@ -82,6 +83,8 @@ pub trait TypeRelatingDelegate<'tcx> { /// be related. Used for lazy normalization. fn push_domain_goal(&mut self, domain_goal: DomainGoal<'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; @@ -603,8 +606,8 @@ where b = self.infcx.shallow_resolve(b); } - match b.val { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { + match (a.val, b.val) { + (_, ty::ConstKind::Infer(InferConst::Var(_))) if D::forbid_inference_vars() => { // Forbid inference variables in the RHS. bug!("unexpected inference var {:?}", b) } @@ -726,6 +729,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 @@ -985,6 +997,9 @@ where } } } + ty::ConstKind::Unevaluated(..) if self.tcx().features().lazy_normalization_consts => { + Ok(a) + } _ => relate::super_relate_consts(self, a, a), } } diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index ed3d860586968..289457e2bd0c2 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -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)), diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index 080af37492d89..1c6ae9cd7e67b 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -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}; @@ -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); + } +} diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 758a0b39d43ee..c16262a8deffb 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -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::*; @@ -80,6 +80,7 @@ pub enum FulfillmentErrorCode<'tcx> { CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeSubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate + CodeConstEquateError(ExpectedFound<&'tcx Const<'tcx>>, TypeError<'tcx>), CodeAmbiguity, } diff --git a/src/librustc_infer/traits/structural_impls.rs b/src/librustc_infer/traits/structural_impls.rs index 595a8cd768390..c48e58c04824e 100644 --- a/src/librustc_infer/traits/structural_impls.rs +++ b/src/librustc_infer/traits/structural_impls.rs @@ -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"), } } diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 4fa74f93ddcb0..e77c4c110056b 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -40,6 +40,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), } } @@ -164,6 +166,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`. } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 84cf2258ac223..65779bbcc3772 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1220,7 +1220,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| { diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 18518e78e3556..161859044641b 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1203,6 +1203,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 @@ -1321,6 +1324,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)) + } } } } @@ -1498,7 +1504,8 @@ impl<'tcx> Predicate<'tcx> { | Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) | Predicate::TypeOutlives(..) - | Predicate::ConstEvaluatable(..) => None, + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => None, } } @@ -1512,7 +1519,8 @@ impl<'tcx> Predicate<'tcx> { | Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) - | Predicate::ConstEvaluatable(..) => None, + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => None, } } } diff --git a/src/librustc_middle/ty/outlives.rs b/src/librustc_middle/ty/outlives.rs index 950539fbb0a16..bbe97153eceb0 100644 --- a/src/librustc_middle/ty/outlives.rs +++ b/src/librustc_middle/ty/outlives.rs @@ -62,6 +62,11 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // in the `subtys` iterator (e.g., when encountering a // projection). match ty.kind { + 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); @@ -139,7 +144,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 diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index a8b7b6a4b97a4..b0f016c8e068b 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2044,6 +2044,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("`")) + } } } diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index 4d668e6ee5977..00b964048334f 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -431,6 +431,9 @@ pub fn super_relate_tys>( let t = relation.relate(&a_t, &b_t)?; match relation.relate(&sz_a, &sz_b) { Ok(sz) => Ok(tcx.mk_ty(ty::Array(t, sz))), + // FIXME(lazy_normalization_consts) Implement improved diagnostics for mismatched array + // length? + Err(err) if relation.tcx().features().lazy_normalization_consts => Err(err), Err(err) => { // Check whether the lengths are both concrete/known values, // but are unequal, for better diagnostics. diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index 0ac4466d34f5c..9da129a28a61e 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -240,6 +240,7 @@ impl fmt::Debug for ty::Predicate<'tcx> { ty::Predicate::ConstEvaluatable(def_id, substs) => { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } + ty::Predicate::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), } } } @@ -492,6 +493,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::ConstEvaluatable(def_id, substs) => { tcx.lift(&substs).map(|substs| ty::Predicate::ConstEvaluatable(def_id, substs)) } + ty::Predicate::ConstEquate(c1, c2) => { + tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::Predicate::ConstEquate(c1, c2)) + } } } } diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs index b9a76057d51f8..2f2e86c136eb8 100644 --- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs @@ -2,7 +2,7 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRe use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Const, Ty}; use rustc_trait_selection::traits::query::Fallible; use rustc_trait_selection::traits::DomainGoal; @@ -104,6 +104,8 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { bug!("should never be invoked with eager normalization") } + fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {} + fn normalization() -> NormalizationStrategy { NormalizationStrategy::Eager } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 8f7a1b948e3fd..393401ddaa911 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -28,7 +28,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | Predicate::TypeOutlives(_) | Predicate::WellFormed(_) | Predicate::Projection(_) - | Predicate::ConstEvaluatable(..) => continue, + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => continue, Predicate::ObjectSafe(_) => { bug!("object safe predicate on function: {:#?}", predicate) } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 54b404e1161b9..794d0499185b4 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -408,6 +408,7 @@ symbols! { label_break_value, lang, lang_items, + lazy_normalization_consts, let_chains, lhs, lib, diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 093873c849a92..0fc9c5ee3fb80 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1264,7 +1264,8 @@ crate fn required_region_bounds( | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::RegionOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => None, ty::Predicate::TypeOutlives(predicate) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f0a157b377076..0d1b3c4520595 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -557,6 +557,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation ) } + + + ty::Predicate::ConstEquate(..) => { + // Errors for `ConstEquate` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + span_bug!( + span, + "const-equate requirement gave wrong error: `{:?}`", + obligation + ) + } } } @@ -1025,6 +1037,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ) .emit(); } + FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => { + self.report_mismatched_consts( + &error.obligation.cause, + expected_found.expected, + expected_found.found, + err.clone(), + ) + .emit(); + } } } diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 49a4b96f8b7a1..c77bf6d42d041 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -3,8 +3,9 @@ use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_infer::traits::{TraitEngine, TraitEngineExt as _}; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; -use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Const, ToPolyTraitRef, Ty, TypeFoldable}; use std::marker::PhantomData; use super::project; @@ -512,6 +513,65 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))), } } + + ty::Predicate::ConstEquate(c1, c2) => { + debug!("equating consts: c1={:?} c2={:?}", c1, c2); + + let stalled_on = &mut pending_obligation.stalled_on; + + let mut evaluate = |c: &'tcx Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val { + match self.selcx.infcx().const_eval_resolve( + obligation.param_env, + def_id, + substs, + promoted, + Some(obligation.cause.span), + ) { + Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)), + Err(ErrorHandled::TooGeneric) => { + stalled_on.append( + &mut substs.types().filter_map(|ty| TyOrConstInferVar::maybe_from_ty(ty)).collect(), + ); + Err(ProcessResult::Unchanged) + } + Err(err) => { + Err(ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err)))) + } + } + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self + .selcx + .infcx() + .at(&obligation.cause, obligation.param_env) + .eq(c1, c2) + { + Ok(_) => ProcessResult::Changed(vec![]), + Err(err) => { + ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError( + ExpectedFound::new(true, c1, c2), + err, + )) + } + } + } + // FIXME(skinny121) How to report both errors if both produces errors? + (Err(result @ ProcessResult::Error(_)), _) + | (_, Err(result @ ProcessResult::Error(_))) => result, + (Err(ProcessResult::Unchanged), _) | (_, Err(ProcessResult::Unchanged)) => { + ProcessResult::Unchanged + } + _ => { + unreachable!("evaluate shouldn't itself return ProcessResult::Changed(..)") + } + } + } } } diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 3cb250891ef93..75bbcfd59d8d9 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -16,8 +16,8 @@ use crate::traits::{self, Obligation, ObligationCause}; use rustc_errors::{Applicability, FatalError}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst}; -use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; +use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst}; +use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness}; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -277,7 +277,8 @@ fn predicates_reference_self( | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => None, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => None, } }) .collect() @@ -309,7 +310,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => false, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => false, }) } @@ -720,51 +722,65 @@ fn contains_illegal_self_type_reference<'tcx>( // object type, and we cannot resolve `Self as SomeOtherTrait` // without knowing what `Self` is. - let mut supertraits: Option>> = None; - let self_ty = tcx.types.self_param; - - let mut walker = ty.walk(); - while let Some(arg) = walker.next() { - if arg == self_ty.into() { - return true; - } - - // Special-case projections (everything else is walked normally). - if let GenericArgKind::Type(ty) = arg.unpack() { - if let ty::Projection(ref data) = ty.kind { - // This is a projected type `::X`. + struct IllegalSelfTypeVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + trait_def_id: DefId, + supertraits: Option>>, + } - // Compute supertraits of current trait lazily. - if supertraits.is_none() { - let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id)); - supertraits = Some(traits::supertraits(tcx, trait_ref).collect()); - } + impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.kind { + ty::Param(_) => t == self.self_ty, + ty::Projection(ref data) => { + // This is a projected type `::X`. + + // Compute supertraits of current trait lazily. + if self.supertraits.is_none() { + let trait_ref = + ty::Binder::bind(ty::TraitRef::identity(self.tcx, self.trait_def_id)); + self.supertraits = Some(traits::supertraits(self.tcx, trait_ref).collect()); + } - // Determine whether the trait reference `Foo as - // SomeTrait` is in fact a supertrait of the - // current trait. In that case, this type is - // legal, because the type `X` will be specified - // in the object type. Note that we can just use - // direct equality here because all of these types - // are part of the formal parameter listing, and - // hence there should be no inference variables. - let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx)); - let is_supertrait_of_current_trait = - supertraits.as_ref().unwrap().contains(&projection_trait_ref); - - if is_supertrait_of_current_trait { - // Do not walk contained types, do not report error, do collect $200. - walker.skip_current_subtree(); + // Determine whether the trait reference `Foo as + // SomeTrait` is in fact a supertrait of the + // current trait. In that case, this type is + // legal, because the type `X` will be specified + // in the object type. Note that we can just use + // direct equality here because all of these types + // are part of the formal parameter listing, and + // hence there should be no inference variables. + let projection_trait_ref = ty::Binder::bind(data.trait_ref(self.tcx)); + let is_supertrait_of_current_trait = + self.supertraits.as_ref().unwrap().contains(&projection_trait_ref); + + if is_supertrait_of_current_trait { + false // do not walk contained types, do not report error, do collect $200 + } else { + t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error + } } - - // DO walk contained types, POSSIBLY reporting an error. + _ => t.super_visit_with(self), // walk contained types, if any } } - // Walk contained types, if any. + fn visit_const(&mut self, _c: &ty::Const<'tcx>) -> bool { + // FIXME Look into the unevaluated constants for object safety violations. + // Do not walk substitutions of unevaluated consts, as they contain `Self`, even + // though the const expression doesn't necessary use it. Currently type variables + // inside array length expressions are forbidden, so they can't break the above + // rules. + false + } } - false + ty.visit_with(&mut IllegalSelfTypeVisitor { + tcx, + self_ty: tcx.types.self_param, + trait_def_id, + supertraits: None, + }) } pub fn provide(providers: &mut ty::query::Providers<'_>) { diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index e4ca7d4cde7dc..2b66d8fd65ca7 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -387,8 +387,11 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - let constant = constant.super_fold_with(self); - constant.eval(self.selcx.tcx(), self.param_env) + if self.selcx.tcx().features().lazy_normalization_consts { + constant + } else { + constant.eval(self.selcx.tcx(), self.param_env) + } } } diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs index 28d59b41e564f..dd9d5c61c819e 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -191,7 +191,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - let constant = constant.super_fold_with(self); constant.eval(self.infcx.tcx, self.param_env) } } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 0a85999c60da7..38c8a5e3f534d 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -42,6 +42,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items; use rustc_index::bit_set::GrowableBitSet; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fast_reject; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; @@ -502,9 +503,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None, ) { Ok(_) => Ok(EvaluatedToOk), + Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), Err(_) => Ok(EvaluatedToErr), } } + + ty::Predicate::ConstEquate(c1, c2) => { + debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2); + + let evaluate = |c: &'tcx ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val { + match self.infcx.const_eval_resolve( + obligation.param_env, + def_id, + substs, + promoted, + Some(obligation.cause.span), + ) { + Ok(val) => Ok(ty::Const::from_value(self.tcx(), val, c.ty)), + Err(ErrorHandled::TooGeneric) => Err(EvaluatedToAmbig), + Err(_) => Err(EvaluatedToErr), + } + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) { + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr), + } + } + (Err(EvaluatedToErr), _) | (_, Err(EvaluatedToErr)) => Ok(EvaluatedToErr), + _ => Ok(EvaluatedToAmbig), + } + } } } diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index d506ddab909e7..073937dd8ceb6 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -91,6 +91,10 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(ty); } } + ty::Predicate::ConstEquate(c1, c2) => { + wf.compute(c1.ty); + wf.compute(c2.ty); + } } wf.normalize() diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 33ecbe72a8c4f..f5bdb9acf205f 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -100,7 +100,8 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ConstEvaluatable(..) => vec![], + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => vec![], ty::Predicate::WellFormed(subty) => { wf_types.push(subty); diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 6cbd505f37ef1..0cd635b6a9e8a 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -103,7 +103,8 @@ impl<'tcx> Lower> for ty::Predicate<'tcx> { | Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) | Predicate::Subtype(..) - | Predicate::ConstEvaluatable(..) => bug!("unexpected predicate {}", self), + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => bug!("unexpected predicate {}", self), } } } diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index ad6c753edff00..ed30ed5313e5c 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -48,6 +48,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool { | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => true, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => true, } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 7e7d84c199676..64557ee00c777 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -804,7 +804,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => None, }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eebc34d3db8ea..25484773a63d9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1633,6 +1633,15 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: DefId, span: r.super_visit_with(self) } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(..) = c.val { + // FIXME This check detect lifetimes within substs which violates this check even + // though the particular substitution is not used within the const. + return false; + } + c.super_visit_with(self) + } } let prohibit_opaque = match item.kind { @@ -3798,6 +3807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Predicate::WellFormed(..) => None, ty::Predicate::ObjectSafe(..) => None, ty::Predicate::ConstEvaluatable(..) => None, + ty::Predicate::ConstEquate(..) => None, // N.B., this predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where // `ClosureType` represents some `Closure`. It can't diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c5e9a288c9ce8..b97da36cea51d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1180,12 +1180,8 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { let parent_id = tcx.hir().get_parent_item(hir_id); Some(tcx.hir().local_def_id(parent_id)) } - // FIXME(#43408) enable this always when we get lazy normalization. Node::AnonConst(_) => { - // HACK(eddyb) this provides the correct generics when - // `feature(const_generics)` is enabled, so that const expressions - // used with const generics, e.g. `Foo<{N+1}>`, can work at all. - if tcx.features().const_generics { + if tcx.features().lazy_normalization_consts { let parent_id = tcx.hir().get_parent_item(hir_id); Some(tcx.hir().local_def_id(parent_id)) } else { diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index 559e478df0604..3a76f89515a53 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -404,6 +404,7 @@ fn trait_predicate_kind<'tcx>( | ty::Predicate::Subtype(_) | ty::Predicate::ObjectSafe(_) | ty::Predicate::ClosureKind(..) - | ty::Predicate::ConstEvaluatable(..) => None, + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => None, } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 168f20771476c..66daf0e7f7d9d 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -58,7 +58,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => (), + | ty::Predicate::ConstEvaluatable(..) + | ty::Predicate::ConstEquate(..) => (), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 03413f67f88fb..bdf110f5e55b7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -488,7 +488,8 @@ impl<'a> Clean> for ty::Predicate<'a> { Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | Predicate::ClosureKind(..) - | Predicate::ConstEvaluatable(..) => panic!("not user writable"), + | Predicate::ConstEvaluatable(..) + | Predicate::ConstEquate(..) => panic!("not user writable"), } } } diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs index d996bf56fcc10..d05fa4aaecc9e 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs @@ -1,5 +1,7 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![feature(lazy_normalization_consts)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash #[allow(dead_code)] struct ArithArrayLen([u32; 0 + N]); diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr index 6ae70c493b1dd..80dd396229356 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr @@ -6,8 +6,14 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default +warning: the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + --> $DIR/array-size-in-generic-struct-param.rs:3:12 + | +LL | #![feature(lazy_normalization_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + error: constant expression depends on a generic parameter - --> $DIR/array-size-in-generic-struct-param.rs:5:38 + --> $DIR/array-size-in-generic-struct-param.rs:7:38 | LL | struct ArithArrayLen([u32; 0 + N]); | ^^^^^^^^^^^^ @@ -15,7 +21,7 @@ LL | struct ArithArrayLen([u32; 0 + N]); = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/array-size-in-generic-struct-param.rs:14:5 + --> $DIR/array-size-in-generic-struct-param.rs:16:5 | LL | arr: [u8; CFG.arr_size], | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-61336-1.rs b/src/test/ui/const-generics/issues/issue-61336-1.rs index 165d3e1c2e601..1f3d0c2a746ee 100644 --- a/src/test/ui/const-generics/issues/issue-61336-1.rs +++ b/src/test/ui/const-generics/issues/issue-61336-1.rs @@ -1,5 +1,7 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![feature(lazy_normalization_consts)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash // build-pass diff --git a/src/test/ui/const-generics/issues/issue-61336-1.stderr b/src/test/ui/const-generics/issues/issue-61336-1.stderr index d48d8ff689462..40c3c1c0972e9 100644 --- a/src/test/ui/const-generics/issues/issue-61336-1.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-1.stderr @@ -6,3 +6,8 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default +warning: the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + --> $DIR/issue-61336-1.rs:3:12 + | +LL | #![feature(lazy_normalization_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-61336-2.rs b/src/test/ui/const-generics/issues/issue-61336-2.rs index c5bf6b6ce94a8..0f4d92a9a8a94 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.rs +++ b/src/test/ui/const-generics/issues/issue-61336-2.rs @@ -1,5 +1,7 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![feature(lazy_normalization_consts)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash fn f(x: T) -> [T; N] { [x; { N }] diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr index ef9e3b86694a8..5fbec5932fb21 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.stderr @@ -6,6 +6,12 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default +warning: the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + --> $DIR/issue-61336-2.rs:3:12 + | +LL | #![feature(lazy_normalization_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/issue-61336-2.rs:9:5 | diff --git a/src/test/ui/const-generics/issues/issue-61336.rs b/src/test/ui/const-generics/issues/issue-61336.rs index 7e84e62d8be42..5b46d95047c75 100644 --- a/src/test/ui/const-generics/issues/issue-61336.rs +++ b/src/test/ui/const-generics/issues/issue-61336.rs @@ -1,5 +1,7 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![feature(lazy_normalization_consts)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash fn f(x: T) -> [T; N] { [x; N] diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr index 88d81c66d1ffe..a65dc551a189c 100644 --- a/src/test/ui/const-generics/issues/issue-61336.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.stderr @@ -6,6 +6,12 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default +warning: the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + --> $DIR/issue-61336.rs:3:12 + | +LL | #![feature(lazy_normalization_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/issue-61336.rs:9:5 | diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs index 64674bb894e1f..cd73cbbb41960 100644 --- a/src/test/ui/const-generics/issues/issue-61747.rs +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -2,6 +2,8 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![feature(lazy_normalization_consts)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash struct Const; diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr index ccf36a7f805ec..42718235d463f 100644 --- a/src/test/ui/const-generics/issues/issue-61747.stderr +++ b/src/test/ui/const-generics/issues/issue-61747.stderr @@ -6,3 +6,9 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default +warning: the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + --> $DIR/issue-61747.rs:5:12 + | +LL | #![feature(lazy_normalization_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs new file mode 100644 index 0000000000000..445862cccdd89 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -0,0 +1,26 @@ +// check-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![feature(lazy_normalization_consts)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + +trait Foo {} + +impl Foo for [(); N] + where + Self:FooImpl<{N==0}> +{} + +trait FooImpl{} + +impl FooImpl for [(); 0] {} + +impl FooImpl for [();N] {} + +fn foo(_: impl Foo) {} + +fn main() { + foo([]); + foo([()]); +} diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr new file mode 100644 index 0000000000000..b35f3ad891d5b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.stderr @@ -0,0 +1,14 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61935.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + --> $DIR/issue-61935.rs:5:12 + | +LL | #![feature(lazy_normalization_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 2e47b4d1882f2..8c1706e5091ba 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -2,6 +2,7 @@ #![allow(incomplete_features, dead_code, unconditional_recursion)] #![feature(const_generics)] +#![feature(lazy_normalization_consts)] fn fact() { fact::<{ N - 1 }>(); diff --git a/src/test/ui/const-generics/issues/issue-67185-1.rs b/src/test/ui/const-generics/issues/issue-67185-1.rs new file mode 100644 index 0000000000000..664dbaeb06791 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-1.rs @@ -0,0 +1,34 @@ +// check-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![feature(lazy_normalization_consts)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + +trait Baz { + type Quaks; +} +impl Baz for u8 { + type Quaks = [u16; 3]; +} + +trait Bar {} +impl Bar for [u16; 3] {} +impl Bar for [[u16; 3]; 2] {} + +trait Foo + where + [::Quaks; 2]: Bar, + ::Quaks: Bar, +{ +} + +struct FooImpl; + +impl Foo for FooImpl {} + +fn f(_: impl Foo) {} + +fn main() { + f(FooImpl) +} diff --git a/src/test/ui/const-generics/issues/issue-67185-1.stderr b/src/test/ui/const-generics/issues/issue-67185-1.stderr new file mode 100644 index 0000000000000..257949340d0f0 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-1.stderr @@ -0,0 +1,14 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-67185-1.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + --> $DIR/issue-67185-1.rs:5:12 + | +LL | #![feature(lazy_normalization_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/issues/issue-67185-2.rs b/src/test/ui/const-generics/issues/issue-67185-2.rs new file mode 100644 index 0000000000000..52c8a5c9de809 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-2.rs @@ -0,0 +1,37 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![feature(lazy_normalization_consts)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + +trait Baz { + type Quaks; +} +impl Baz for u8 { + type Quaks = [u16; 3]; +} + +trait Bar {} +impl Bar for [u16; 4] {} +impl Bar for [[u16; 3]; 3] {} + +trait Foo //~ ERROR the trait bound `[u16; 3]: Bar` is not satisfied [E0277] + //~^ ERROR the trait bound `[[u16; 3]; 2]: Bar` is not satisfied [E0277] + where + [::Quaks; 2]: Bar, + ::Quaks: Bar, +{ +} + +struct FooImpl; + +impl Foo for FooImpl {} +//~^ ERROR the trait bound `[u16; 3]: Bar` is not satisfied [E0277] +//~^^ ERROR the trait bound `[[u16; 3]; 2]: Bar` is not satisfied [E0277] + +fn f(_: impl Foo) {} +//~^ ERROR the trait bound `[u16; 3]: Bar` is not satisfied [E0277] +//~^^ ERROR the trait bound `[[u16; 3]; 2]: Bar` is not satisfied [E0277] + +fn main() { + f(FooImpl) +} diff --git a/src/test/ui/const-generics/issues/issue-67185-2.stderr b/src/test/ui/const-generics/issues/issue-67185-2.stderr new file mode 100644 index 0000000000000..c8620fc268ffb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-2.stderr @@ -0,0 +1,111 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-67185-2.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + --> $DIR/issue-67185-2.rs:3:12 + | +LL | #![feature(lazy_normalization_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_- required by `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_- required by `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/trait-const-args.rs b/src/test/ui/const-generics/trait-const-args.rs new file mode 100644 index 0000000000000..2bb5514d8d71f --- /dev/null +++ b/src/test/ui/const-generics/trait-const-args.rs @@ -0,0 +1,31 @@ +// check-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash +#![feature(lazy_normalization_consts)] +//~^ WARN the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + +struct Const; +trait Foo {} + +impl Foo<{N}> for Const<{N}> {} + +fn foo_impl(_: impl Foo<3>) {} + +fn foo_explicit>(_: T) {} + +fn foo_where(_: T) where T: Foo<3> {} + +fn main() { + // FIXME this causes a stack overflow in rustc + // foo_impl(Const); + foo_impl(Const::<3>); + + // FIXME this causes a stack overflow in rustc + // foo_explicit(Const); + foo_explicit(Const::<3>); + + // FIXME this causes a stack overflow in rustc + // foo_where(Const); + foo_where(Const::<3>); +} diff --git a/src/test/ui/const-generics/trait-const-args.stderr b/src/test/ui/const-generics/trait-const-args.stderr new file mode 100644 index 0000000000000..617b6ad45f7c6 --- /dev/null +++ b/src/test/ui/const-generics/trait-const-args.stderr @@ -0,0 +1,14 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/trait-const-args.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `lazy_normalization_consts` is incomplete and may cause the compiler to crash + --> $DIR/trait-const-args.rs:5:12 + | +LL | #![feature(lazy_normalization_consts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +