diff options
| author | bors <bors@rust-lang.org> | 2023-02-17 11:27:21 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-02-17 11:27:21 +0000 |
| commit | f4f5fc3e5cc70b7a43bf7b518c455f3d9bada9e3 (patch) | |
| tree | e42ae3e6952c4e776ce7be5453f5548c04223662 | |
| parent | b5c8c329a7b4f6a12ae72ae41cb834989228221e (diff) | |
| parent | 90c8d6bbe4725ca83e79e73e9cdf1f66840db79f (diff) | |
Auto merge of #107965 - BoxyUwU:add_const_arg_has_type_predicate, r=compiler-errors
Add `Clause::ConstArgHasType` Currently the way that we check that a const arg has the correct type for the const param it is an argument for is by setting the expected type of `typeck` on the anon const of the argument to be the const param's type. In the future for a potential `min_generic_const_exprs` we will allow providing const arguments that do not have an associated anon const that can be typeck'd which will require us to actually check that the const argument has the correct type. While it would potentially be possible to just call `eq` when creating substs this would not work if we support generics of the form `const N: T, T` (the const parameters type referencing generics declared after itself). Additionally having `ConstArgHasType` will allow us to potentially make progress on removing the `ty` field of `Const` which may be desirable. Once progress has been made on this, `ConstArgHasType` will also be helpful in ensuring we do not make mistakes in trait/impl checking by declaring functions with the wrong const parameter types as the checks that the param env is compatible would catch it. (We have messed this up in the past, and with generic const parameter types these checks will get more complex) There is a [document](https://hackmd.io/wuCS6CJBQ9-fWbwaW7nQRw?view) about the types of const generics that may provide some general information on this subject --- This PR shouldn't have any impact on whether code compiles or not on stable, it primarily exists to make progress on unstable const generics features that are desirable.
28 files changed, 183 insertions, 15 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 5bb78d17253..abc33e84139 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1328,7 +1328,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::Clause::TypeOutlives(_) => { // Do nothing, we deal with regions separately } - ty::Clause::RegionOutlives(_) => bug!(), + ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(), }, ty::PredicateKind::WellFormed(_) | ty::PredicateKind::AliasEq(..) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index b67f8ded2a5..2badd66e346 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -9,8 +9,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{GenericPredicates, ToPredicate}; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; @@ -151,7 +151,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP trace!(?generics); // Collect the predicates that were written inline by the user on each - // type parameter (e.g., `<T: Foo>`). + // type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates + // for each const parameter. for param in ast_generics.params { match param.kind { // We already dealt with early bound lifetimes above. @@ -175,7 +176,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP trace!(?predicates); } GenericParamKind::Const { .. } => { - // Bounds on const parameters are currently not possible. + let name = param.name.ident().name; + let param_const = ty::ParamConst::new(index, name); + + let ct_ty = tcx.type_of(param.def_id.to_def_id()).subst_identity(); + + let ct = tcx.mk_const(param_const, ct_ty); + + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( + ty::Clause::ConstArgHasType(ct, ct_ty), + )) + .to_predicate(tcx); + predicates.insert((predicate, param.span)); + index += 1; } } @@ -439,7 +452,9 @@ pub(super) fn explicit_predicates_of<'tcx>( let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let parent_def_id = tcx.hir().get_parent_item(hir_id); - if tcx.hir().opt_const_param_default_param_def_id(hir_id).is_some() { + if let Some(defaulted_param_def_id) = + tcx.hir().opt_const_param_default_param_def_id(hir_id) + { // In `generics_of` we set the generics' parent to be our parent's parent which means that // we lose out on the predicates of our actual parent if we dont return those predicates here. // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) @@ -452,7 +467,39 @@ pub(super) fn explicit_predicates_of<'tcx>( // // In the above code we want the anon const to have predicates in its param env for `T: Trait` // and we would be calling `explicit_predicates_of(Foo)` here - return tcx.explicit_predicates_of(parent_def_id); + let parent_preds = tcx.explicit_predicates_of(parent_def_id); + + // If we dont filter out `ConstArgHasType` predicates then every single defaulted const parameter + // will ICE because of #106994. FIXME(generic_const_exprs): remove this when a more general solution + // to #106994 is implemented. + let filtered_predicates = parent_preds + .predicates + .into_iter() + .filter(|(pred, _)| { + if let ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, _)) = + pred.kind().skip_binder() + { + match ct.kind() { + ty::ConstKind::Param(param_const) => { + let defaulted_param_idx = tcx + .generics_of(parent_def_id) + .param_def_id_to_index[&defaulted_param_def_id.to_def_id()]; + param_const.index < defaulted_param_idx + } + _ => bug!( + "`ConstArgHasType` in `predicates_of`\ + that isn't a `Param` const" + ), + } + } else { + true + } + }) + .cloned(); + return GenericPredicates { + parent: parent_preds.parent, + predicates: { tcx.arena.alloc_from_iter(filtered_predicates) }, + }; } let parent_def_kind = tcx.def_kind(parent_def_id); diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 02f77f9d6af..4741e4b095d 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -496,6 +496,16 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc ) .emit(); } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => { + // FIXME(min_specialization), FIXME(const_generics): + // It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure + // about the actual rules that would be sound. Can't just always error here because otherwise + // std/core doesn't even compile as they have `const N: usize` in some specializing impls. + // + // While we do not support constructs like `<T, const N: T>` there is probably no risk of + // soundness bugs, but when we support generic const parameter types this will need to be + // revisited. + } _ => { tcx.sess .struct_span_err(span, &format!("cannot specialize on predicate `{}`", predicate)) @@ -517,6 +527,7 @@ fn trait_predicate_kind<'tcx>( ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_)) | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) | ty::PredicateKind::Clause(ty::Clause::Projection(_)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::Subtype(_) diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index ecd6849426d..9ee6785970c 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -54,6 +54,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::WellFormed(..) | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::ObjectSafe(..) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index e9c899f95ea..5b641be062b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -663,6 +663,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index ffe04bc7294..0e3a16ac717 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -826,6 +826,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index a8e668d81ea..83f3d5a74fb 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -21,6 +21,7 @@ pub fn explicit_outlives_bounds<'tcx>( .filter_map(move |kind| match kind { ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::Trait(..)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Subtype(..) diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 68b39c5f00f..c1f0a6e9834 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -297,6 +297,9 @@ impl<'tcx> Elaborator<'tcx> { ty::PredicateKind::AliasEq(..) => { // No } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => { + // Nothing to elaborate + } } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 9bbd017c339..11fb1f80a11 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1595,6 +1595,8 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { Clause(Clause::TypeOutlives(..)) | Clause(Clause::RegionOutlives(..)) => "lifetime", + // `ConstArgHasType` is never global as `ct` is always a param + Clause(Clause::ConstArgHasType(..)) | // Ignore projections, as they can only be global // if the trait bound is global Clause(Clause::Projection(..)) | diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index c9aa0ec66d5..91241ff404f 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -251,6 +251,10 @@ impl FlagComputation { self.add_ty(ty); self.add_region(region); } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + self.add_const(ct); + self.add_ty(ty); + } ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => { self.add_ty(a); self.add_ty(b); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d1b686a0b08..4b4f62b67f2 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -552,6 +552,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(Clause::RegionOutlives(_)) | PredicateKind::Clause(Clause::TypeOutlives(_)) | PredicateKind::Clause(Clause::Projection(_)) + | PredicateKind::Clause(Clause::ConstArgHasType(..)) | PredicateKind::AliasEq(..) | PredicateKind::ObjectSafe(_) | PredicateKind::ClosureKind(_, _, _) @@ -590,6 +591,10 @@ pub enum Clause<'tcx> { /// `where <T as TraitRef>::Name == X`, approximately. /// See the `ProjectionPredicate` struct for details. Projection(ProjectionPredicate<'tcx>), + + /// Ensures that a const generic argument to a parameter `const N: u8` + /// is of type `u8`. + ConstArgHasType(Const<'tcx>, Ty<'tcx>), } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] @@ -1193,6 +1198,7 @@ impl<'tcx> Predicate<'tcx> { match predicate.skip_binder() { PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(Clause::Projection(..)) + | PredicateKind::Clause(Clause::ConstArgHasType(..)) | PredicateKind::AliasEq(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) @@ -1213,6 +1219,7 @@ impl<'tcx> Predicate<'tcx> { match predicate.skip_binder() { PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)), PredicateKind::Clause(Clause::Trait(..)) + | PredicateKind::Clause(Clause::ConstArgHasType(..)) | PredicateKind::AliasEq(..) | PredicateKind::Subtype(..) | PredicateKind::Coerce(..) @@ -1233,6 +1240,7 @@ impl<'tcx> Predicate<'tcx> { match predicate.skip_binder() { PredicateKind::Clause(Clause::TypeOutlives(data)) => Some(predicate.rebind(data)), PredicateKind::Clause(Clause::Trait(..)) + | PredicateKind::Clause(Clause::ConstArgHasType(..)) | PredicateKind::Clause(Clause::Projection(..)) | PredicateKind::AliasEq(..) | PredicateKind::Subtype(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 64d218e7e7a..1e59983583b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2822,15 +2822,18 @@ define_print_and_forward_display! { ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => p!(print(predicate)), ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => p!(print(predicate)), ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => p!(print(predicate)), + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + p!("the constant `", print(ct), "` has type `", print(ty), "`") + }, ty::PredicateKind::WellFormed(arg) => p!(print(arg), " well-formed"), ty::PredicateKind::ObjectSafe(trait_def_id) => { p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe") } - ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => { - p!("the closure `", + ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => p!( + "the closure `", print_value_path(closure_def_id, &[]), - write("` implements the trait `{}`", kind)) - } + write("` implements the trait `{}`", kind) + ), ty::PredicateKind::ConstEvaluatable(ct) => { p!("the constant `", print(ct), "` can be evaluated") } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 97ee2b1fc5d..d8dbd04f438 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -147,6 +147,7 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { impl<'tcx> fmt::Debug for ty::Clause<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { + ty::Clause::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), ty::Clause::Trait(ref a) => a.fmt(f), ty::Clause::RegionOutlives(ref pair) => pair.fmt(f), ty::Clause::TypeOutlives(ref pair) => pair.fmt(f), diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 64c7fafa713..58dfca75c65 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -159,9 +159,21 @@ where _region, ))) => ty.visit_with(self), ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) => ControlFlow::Continue(()), + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + ct.visit_with(self)?; + ty.visit_with(self) + } ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::PredicateKind::WellFormed(arg) => arg.visit_with(self), - _ => bug!("unexpected predicate: {:?}", predicate), + + ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::ClosureKind(_, _, _) + | ty::PredicateKind::Subtype(_) + | ty::PredicateKind::Coerce(_) + | ty::PredicateKind::ConstEquate(_, _) + | ty::PredicateKind::TypeWellFormedFromEnv(_) + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::AliasEq(_, _) => bug!("unexpected predicate: {:?}", predicate), } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 28aa3d52705..6890811fd04 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -25,7 +25,7 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::Obligation; use rustc_middle::infer::canonical::Certainty as OldCertainty; use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate, }; @@ -290,6 +290,9 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { self.compute_region_outlives_goal(Goal { param_env, predicate }) } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) + } ty::PredicateKind::Subtype(predicate) => { self.compute_subtype_goal(Goal { param_env, predicate }) } @@ -471,6 +474,16 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } } + + #[instrument(level = "debug", skip(self), ret)] + fn compute_const_arg_has_type_goal( + &mut self, + goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>, + ) -> QueryResult<'tcx> { + let (ct, ty) = goal.predicate; + let nested_goals = self.infcx.eq(goal.param_env, ct.ty(), ty)?; + self.evaluate_all_and_make_canonical_response(nested_goals) + } } impl<'tcx> EvalCtxt<'_, 'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 3adb15cb441..9776cc57af8 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -830,6 +830,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // and these don't correspond to adding any new bounds to // the `ParamEnv`. ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index adc4e950dff..2511e9a955a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1282,6 +1282,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span, "AliasEq predicate should never be the predicate cause of a SelectionError" ), + + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + self.tcx.sess.struct_span_err( + span, + &format!("the constant `{}` is not of type `{}`", ct, ty), + ) + } } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 19d47d33f67..deeed930e50 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -313,6 +313,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_)) | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) @@ -600,6 +601,19 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::AliasEq(..) => { bug!("AliasEq is only used for new solver") } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + match self + .selcx + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(ct.ty(), ty) + { + Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), + Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + )), + } + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 4963f2d75fa..93c3364de8f 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -327,6 +327,10 @@ fn predicate_references_self<'tcx>( // possible alternatives. data.projection_ty.substs[1..].iter().any(has_self_ty).then_some(sp) } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(_ct, ty)) => { + has_self_ty(&ty.into()).then_some(sp) + } + ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"), ty::PredicateKind::WellFormed(..) @@ -362,6 +366,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) } ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index bd0871259c3..e6fc9bb9239 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -993,6 +993,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("AliasEq is only used for new solver") } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + match self.infcx.at(&obligation.cause, obligation.param_env).eq(ct.ty(), ty) { + Ok(inf_ok) => self.evaluate_predicates_recursively( + previous_stack, + inf_ok.into_obligations(), + ), + Err(_) => Ok(EvaluatedToErr), + } + } } }) } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 5cfb6cf332e..6a881c233db 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -163,6 +163,10 @@ pub fn predicate_obligations<'tcx>( ty::TermKind::Const(c) => c.into(), }) } + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { + wf.compute(ct.into()); + wf.compute(ty.into()); + } ty::PredicateKind::WellFormed(arg) => { wf.compute(arg); } @@ -922,6 +926,7 @@ pub(crate) fn required_region_bounds<'tcx>( match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::Trait(..)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::WellFormed(..) diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 9abbd0c5b34..7635f4bfec3 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -117,6 +117,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' )), }, ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) @@ -212,6 +213,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi // We can defer this, but ultimately we'll want to express // some of these in terms of chalk operations. ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) @@ -646,6 +648,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner))) } ty::PredicateKind::WellFormed(_ty) => None, + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::AliasEq(..) @@ -780,6 +783,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru } ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_predicate)) => None, ty::PredicateKind::WellFormed(_ty) => None, + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) | ty::PredicateKind::AliasEq(..) diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 93f9b66e0f8..abf0c1c5f3e 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -99,6 +99,9 @@ fn compute_implied_outlives_bounds<'tcx>( }; match pred { ty::PredicateKind::Clause(ty::Clause::Trait(..)) + // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound + // if we ever support that + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::Clause::Projection(..)) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 07e716cda42..2c18a034050 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -60,6 +60,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => false, ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) | ty::PredicateKind::AliasEq(..) | ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 42276495a51..0c70d31ed60 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -320,6 +320,7 @@ pub(crate) fn clean_predicate<'tcx>( // FIXME(generic_const_exprs): should this do something? ty::PredicateKind::ConstEvaluatable(..) => None, ty::PredicateKind::WellFormed(..) => None, + ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => None, ty::PredicateKind::Subtype(..) | ty::PredicateKind::AliasEq(..) diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 26b1d019749..1a35fe05067 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -30,7 +30,8 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) ty::Clause::RegionOutlives(_) | ty::Clause::TypeOutlives(_) | ty::Clause::Projection(_) - | ty::Clause::Trait(..), + | ty::Clause::Trait(..) + | ty::Clause::ConstArgHasType(..), ) | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::ConstEvaluatable(..) diff --git a/tests/ui/const-generics/nested-type.min.stderr b/tests/ui/const-generics/nested-type.min.stderr index cff02b0d445..257a9e31e14 100644 --- a/tests/ui/const-generics/nested-type.min.stderr +++ b/tests/ui/const-generics/nested-type.min.stderr @@ -1,3 +1,11 @@ +error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17>::value` in constants + --> $DIR/nested-type.rs:15:5 + | +LL | Foo::<17>::value() + | ^^^^^^^^^^^^^^^^^^ + | + = note: calls in constants are limited to constant functions, tuple structs and tuple variants + error: `[u8; { struct Foo<const N: usize>; @@ -24,5 +32,6 @@ LL | | }]>; = note: the only supported types are integers, `bool` and `char` = help: more complex types are supported with `#![feature(adt_const_params)]` -error: aborting due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/const-generics/nested-type.rs b/tests/ui/const-generics/nested-type.rs index 742340f430e..5240f5c3b0b 100644 --- a/tests/ui/const-generics/nested-type.rs +++ b/tests/ui/const-generics/nested-type.rs @@ -13,7 +13,7 @@ struct Foo<const N: [u8; { //[min]~ ERROR `[u8; _]` is forbidden } Foo::<17>::value() - //[full]~^ ERROR cannot call non-const fn + //~^ ERROR cannot call non-const fn }]>; fn main() {} |
