diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 41b8bb60ef5eaf6c28b2fb19b775b9484c10d063..44d906dada5f05b80974efec0767d407127edd8c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -263,6 +263,16 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { } } + query try_unify_abstract_consts(key: ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>) + )) -> bool { + desc { + |tcx| "trying to unify the generic constants {} and {}", + tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did) + } + } + query mir_drops_elaborated_and_const_checked( key: ty::WithOptConstParam ) -> &'tcx Steal> { diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs index 3f7a20bba2b9add597b91cf99d5dfea170c82f3e..a005990264cf11176443819ad7e8446804e15cb8 100644 --- a/compiler/rustc_middle/src/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -193,6 +193,22 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span { } } +impl<'tcx> Key + for ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>), + ) +{ + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + (self.0).0.did.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + (self.0).0.did.default_span(tcx) + } +} + impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 7d3634a75b0a7c9c41cddf26adaccf0493d0da41..c4df0bba726cb9d0929c355b7f0021e88061c0e0 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -576,7 +576,20 @@ pub fn super_relate_consts>( new_val.map(ty::ConstKind::Value) } - // FIXME(const_generics): this is wrong, as it is a projection + ( + ty::ConstKind::Unevaluated(a_def, a_substs, None), + ty::ConstKind::Unevaluated(b_def, b_substs, None), + ) if tcx.features().const_evaluatable_checked => { + if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { + Ok(a.val) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, a, b))) + } + } + + // While this is slightly incorrect, it shouldn't matter for `min_const_generics` + // and is the better alternative to waiting until `const_evaluatable_checked` can + // be stabilized. ( ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted), ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted), diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 9d74de44d171c8f1be90d671e81ce38df1675962..e14af1a27ef447be9449de339e0187eca81d59b3 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -269,7 +269,27 @@ pub(super) fn mir_abstract_const<'tcx>( } } -pub fn try_unify<'tcx>(tcx: TyCtxt<'tcx>, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool { +pub(super) fn try_unify_abstract_consts<'tcx>( + tcx: TyCtxt<'tcx>, + ((a, a_substs), (b, b_substs)): ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>), + ), +) -> bool { + if let Some(a) = AbstractConst::new(tcx, a, a_substs) { + if let Some(b) = AbstractConst::new(tcx, b, b_substs) { + return try_unify(tcx, a, b); + } + } + + false +} + +pub(super) fn try_unify<'tcx>( + tcx: TyCtxt<'tcx>, + a: AbstractConst<'tcx>, + b: AbstractConst<'tcx>, +) -> bool { match (a.root(), b.root()) { (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { let a_ct = a_ct.subst(tcx, a.substs); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1dd50d69a2195ce73e35bad9fd7ba4891d03a483..5b4314598deb5e43f7f3f6914895bd6b77df7d6d 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -476,6 +476,25 @@ fn process_obligation( ty::PredicateAtom::ConstEquate(c1, c2) => { debug!("equating consts: c1={:?} c2={:?}", c1, c2); + if self.selcx.tcx().features().const_evaluatable_checked { + // FIXME: we probably should only try to unify abstract constants + // if the constants depend on generic parameters. + // + // Let's just see where this breaks :shrug: + if let ( + ty::ConstKind::Unevaluated(a_def, a_substs, None), + ty::ConstKind::Unevaluated(b_def, b_substs, None), + ) = (c1.val, c2.val) + { + if self + .selcx + .tcx() + .try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) + { + return ProcessResult::Changed(vec![]); + } + } + } let stalled_on = &mut pending_obligation.stalled_on; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2f0b66ec8c941f1006b5f9bd4d910f06123c1b67..098336453bc6927d939e1553bf51b87f7e1d4aa6 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -566,6 +566,7 @@ pub fn provide(providers: &mut ty::query::Providers) { ty::WithOptConstParam { did, const_param_did: Some(param_did) }, ) }, + try_unify_abstract_consts: const_evaluatable::try_unify_abstract_consts, ..*providers }; } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr index da8ccdaee414661f554d939f2b7b8f895476a35b..3cac604a7b33a0d1e1b419c2ba87139c29884344 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr @@ -1,10 +1,18 @@ error: generic parameters must not be used inside of non trivial constant values - --> $DIR/simple.rs:8:33 + --> $DIR/simple.rs:8:53 | -LL | type Arr = [u8; N - 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` +LL | fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + | ^ non-trivial anonymous constants must not depend on the parameter `N` | = help: it is currently only allowed to use either `N` or `{ N }` as generic constants -error: aborting due to previous error +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple.rs:8:35 + | +LL | fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs index 27dc6b103200dc696517156b828103735d1bca33..dcf0071cb29b6eb5898367e390d3200939075243 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs @@ -5,10 +5,9 @@ #![feature(const_evaluatable_checked)] #![allow(incomplete_features)] -type Arr = [u8; N - 1]; -//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values - -fn test() -> Arr where Arr: Default { +fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + //[min]~^ ERROR generic parameters + //[min]~| ERROR generic parameters Default::default() }