Skip to content

Add Clause::ConstArgHasType #107965

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..)
Expand Down
57 changes: 52 additions & 5 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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.
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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(_)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/outlives/explicit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..))
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..))
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/infer/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..)
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_infer/src/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ impl<'tcx> Elaborator<'tcx> {
ty::PredicateKind::AliasEq(..) => {
// No
}
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
// Nothing to elaborate
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..)) |
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_, _, _)
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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(..)
Expand All @@ -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(..)
Expand All @@ -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(..)
Expand Down
11 changes: 7 additions & 4 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
14 changes: 13 additions & 1 deletion compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}

Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_trait_selection/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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 })
}
Expand Down Expand Up @@ -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> {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/traits/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)
}
}
}

Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..)
Expand Down Expand Up @@ -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,
)),
}
}
},
}
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_trait_selection/src/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(..)
Expand Down Expand Up @@ -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(..))
Expand Down
Loading