Skip to content

Commit f4f5fc3

Browse files
committed
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.
2 parents b5c8c32 + 90c8d6b commit f4f5fc3

File tree

28 files changed

+183
-15
lines changed

28 files changed

+183
-15
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1328,7 +1328,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
13281328
ty::Clause::TypeOutlives(_) => {
13291329
// Do nothing, we deal with regions separately
13301330
}
1331-
ty::Clause::RegionOutlives(_) => bug!(),
1331+
ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(),
13321332
},
13331333
ty::PredicateKind::WellFormed(_)
13341334
| ty::PredicateKind::AliasEq(..)

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use rustc_hir::def::DefKind;
99
use rustc_hir::def_id::{DefId, LocalDefId};
1010
use rustc_hir::intravisit::{self, Visitor};
1111
use rustc_middle::ty::subst::InternalSubsts;
12-
use rustc_middle::ty::ToPredicate;
1312
use rustc_middle::ty::{self, Ty, TyCtxt};
13+
use rustc_middle::ty::{GenericPredicates, ToPredicate};
1414
use rustc_span::symbol::{sym, Ident};
1515
use rustc_span::{Span, DUMMY_SP};
1616

@@ -151,7 +151,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
151151
trace!(?generics);
152152

153153
// Collect the predicates that were written inline by the user on each
154-
// type parameter (e.g., `<T: Foo>`).
154+
// type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates
155+
// for each const parameter.
155156
for param in ast_generics.params {
156157
match param.kind {
157158
// We already dealt with early bound lifetimes above.
@@ -175,7 +176,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
175176
trace!(?predicates);
176177
}
177178
GenericParamKind::Const { .. } => {
178-
// Bounds on const parameters are currently not possible.
179+
let name = param.name.ident().name;
180+
let param_const = ty::ParamConst::new(index, name);
181+
182+
let ct_ty = tcx.type_of(param.def_id.to_def_id()).subst_identity();
183+
184+
let ct = tcx.mk_const(param_const, ct_ty);
185+
186+
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
187+
ty::Clause::ConstArgHasType(ct, ct_ty),
188+
))
189+
.to_predicate(tcx);
190+
predicates.insert((predicate, param.span));
191+
179192
index += 1;
180193
}
181194
}
@@ -439,7 +452,9 @@ pub(super) fn explicit_predicates_of<'tcx>(
439452
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
440453
let parent_def_id = tcx.hir().get_parent_item(hir_id);
441454

442-
if tcx.hir().opt_const_param_default_param_def_id(hir_id).is_some() {
455+
if let Some(defaulted_param_def_id) =
456+
tcx.hir().opt_const_param_default_param_def_id(hir_id)
457+
{
443458
// In `generics_of` we set the generics' parent to be our parent's parent which means that
444459
// we lose out on the predicates of our actual parent if we dont return those predicates here.
445460
// (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>(
452467
//
453468
// In the above code we want the anon const to have predicates in its param env for `T: Trait`
454469
// and we would be calling `explicit_predicates_of(Foo)` here
455-
return tcx.explicit_predicates_of(parent_def_id);
470+
let parent_preds = tcx.explicit_predicates_of(parent_def_id);
471+
472+
// If we dont filter out `ConstArgHasType` predicates then every single defaulted const parameter
473+
// will ICE because of #106994. FIXME(generic_const_exprs): remove this when a more general solution
474+
// to #106994 is implemented.
475+
let filtered_predicates = parent_preds
476+
.predicates
477+
.into_iter()
478+
.filter(|(pred, _)| {
479+
if let ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, _)) =
480+
pred.kind().skip_binder()
481+
{
482+
match ct.kind() {
483+
ty::ConstKind::Param(param_const) => {
484+
let defaulted_param_idx = tcx
485+
.generics_of(parent_def_id)
486+
.param_def_id_to_index[&defaulted_param_def_id.to_def_id()];
487+
param_const.index < defaulted_param_idx
488+
}
489+
_ => bug!(
490+
"`ConstArgHasType` in `predicates_of`\
491+
that isn't a `Param` const"
492+
),
493+
}
494+
} else {
495+
true
496+
}
497+
})
498+
.cloned();
499+
return GenericPredicates {
500+
parent: parent_preds.parent,
501+
predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
502+
};
456503
}
457504

458505
let parent_def_kind = tcx.def_kind(parent_def_id);

compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,16 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
496496
)
497497
.emit();
498498
}
499+
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
500+
// FIXME(min_specialization), FIXME(const_generics):
501+
// It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure
502+
// about the actual rules that would be sound. Can't just always error here because otherwise
503+
// std/core doesn't even compile as they have `const N: usize` in some specializing impls.
504+
//
505+
// While we do not support constructs like `<T, const N: T>` there is probably no risk of
506+
// soundness bugs, but when we support generic const parameter types this will need to be
507+
// revisited.
508+
}
499509
_ => {
500510
tcx.sess
501511
.struct_span_err(span, &format!("cannot specialize on predicate `{}`", predicate))
@@ -517,6 +527,7 @@ fn trait_predicate_kind<'tcx>(
517527
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
518528
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
519529
| ty::PredicateKind::Clause(ty::Clause::Projection(_))
530+
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
520531
| ty::PredicateKind::AliasEq(..)
521532
| ty::PredicateKind::WellFormed(_)
522533
| ty::PredicateKind::Subtype(_)

compiler/rustc_hir_analysis/src/outlives/explicit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
5454

5555
ty::PredicateKind::Clause(ty::Clause::Trait(..))
5656
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
57+
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
5758
| ty::PredicateKind::WellFormed(..)
5859
| ty::PredicateKind::AliasEq(..)
5960
| ty::PredicateKind::ObjectSafe(..)

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
663663

664664
ty::PredicateKind::Clause(ty::Clause::Trait(..))
665665
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
666+
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
666667
| ty::PredicateKind::Subtype(..)
667668
| ty::PredicateKind::Coerce(..)
668669
| ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))

compiler/rustc_hir_typeck/src/method/probe.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
826826
}
827827
}
828828
ty::PredicateKind::Subtype(..)
829+
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
829830
| ty::PredicateKind::Coerce(..)
830831
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
831832
| ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))

compiler/rustc_infer/src/infer/outlives/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub fn explicit_outlives_bounds<'tcx>(
2121
.filter_map(move |kind| match kind {
2222
ty::PredicateKind::Clause(ty::Clause::Projection(..))
2323
| ty::PredicateKind::Clause(ty::Clause::Trait(..))
24+
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
2425
| ty::PredicateKind::AliasEq(..)
2526
| ty::PredicateKind::Coerce(..)
2627
| ty::PredicateKind::Subtype(..)

compiler/rustc_infer/src/traits/util.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ impl<'tcx> Elaborator<'tcx> {
297297
ty::PredicateKind::AliasEq(..) => {
298298
// No
299299
}
300+
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
301+
// Nothing to elaborate
302+
}
300303
}
301304
}
302305
}

compiler/rustc_lint/src/builtin.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,8 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
15951595
Clause(Clause::TypeOutlives(..)) |
15961596
Clause(Clause::RegionOutlives(..)) => "lifetime",
15971597

1598+
// `ConstArgHasType` is never global as `ct` is always a param
1599+
Clause(Clause::ConstArgHasType(..)) |
15981600
// Ignore projections, as they can only be global
15991601
// if the trait bound is global
16001602
Clause(Clause::Projection(..)) |

compiler/rustc_middle/src/ty/flags.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ impl FlagComputation {
251251
self.add_ty(ty);
252252
self.add_region(region);
253253
}
254+
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
255+
self.add_const(ct);
256+
self.add_ty(ty);
257+
}
254258
ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
255259
self.add_ty(a);
256260
self.add_ty(b);

0 commit comments

Comments
 (0)