Skip to content

Commit 309ca91

Browse files
committed
Always check ConstArgHasType even when otherwise ignoring
1 parent 1c00e98 commit 309ca91

8 files changed

Lines changed: 469 additions & 7 deletions

File tree

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -938,10 +938,10 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
938938
tcx.ensure_ok().type_of(def_id);
939939
tcx.ensure_ok().predicates_of(def_id);
940940
check_type_alias_type_params_are_used(tcx, def_id);
941+
let ty = tcx.type_of(def_id).instantiate_identity();
942+
let span = tcx.def_span(def_id);
941943
if tcx.type_alias_is_lazy(def_id) {
942944
res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
943-
let ty = tcx.type_of(def_id).instantiate_identity();
944-
let span = tcx.def_span(def_id);
945945
let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);
946946
wfcx.register_wf_obligation(
947947
span,
@@ -952,6 +952,27 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
952952
Ok(())
953953
}));
954954
check_variances_for_type_defn(tcx, def_id);
955+
} else {
956+
res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {
957+
// HACK: We sometimes incidentally check that const arguments have the correct
958+
// type as a side effect of the anon const desugaring. To make this "consistent"
959+
// for users we explicitly check `ConstArgHasType` clauses so that const args
960+
// that don't go through an anon const still have their types checked.
961+
//
962+
// We use the unnormalized type as this mirrors the behaviour that we previously
963+
// would have had when all const arguments were anon consts.
964+
if let Some(unnormalized_obligations) = wfcx.unnormalized_obligations(span, ty)
965+
{
966+
let filtered_obligations =
967+
unnormalized_obligations.into_iter().filter(|o| {
968+
matches!(o.predicate.kind().skip_binder(),
969+
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _))
970+
if matches!(ct.kind(), ty::ConstKind::Param(..)))
971+
});
972+
wfcx.ocx.register_obligations(filtered_obligations)
973+
}
974+
Ok(())
975+
}));
955976
}
956977

957978
// Only `Node::Item` and `Node::ForeignItem` still have HIR based

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_hir::lang_items::LangItem;
1313
use rustc_hir::{AmbigArg, ItemKind, find_attr};
1414
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
1515
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin, TyCtxtInferExt};
16+
use rustc_infer::traits::PredicateObligations;
1617
use rustc_lint_defs::builtin::SHADOWING_SUPERTRAIT_ITEMS;
1718
use rustc_macros::LintDiagnostic;
1819
use rustc_middle::mir::interpret::ErrorHandled;
@@ -123,6 +124,20 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
123124
ty::ClauseKind::WellFormed(term),
124125
));
125126
}
127+
128+
pub(super) fn unnormalized_obligations(
129+
&self,
130+
span: Span,
131+
ty: Ty<'tcx>,
132+
) -> Option<PredicateObligations<'tcx>> {
133+
traits::wf::unnormalized_obligations(
134+
self.ocx.infcx,
135+
self.param_env,
136+
ty.into(),
137+
span,
138+
self.body_def_id,
139+
)
140+
}
126141
}
127142

128143
pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
@@ -139,7 +154,12 @@ where
139154

140155
let mut wfcx = WfCheckingCtxt { ocx, body_def_id, param_env };
141156

142-
if !tcx.features().trivial_bounds() {
157+
// As of now, bounds are only checked on lazy type aliases, they're ignored for most type
158+
// aliases. So, only check for false global bounds if we're not ignoring bounds altogether.
159+
let ignore_bounds =
160+
tcx.def_kind(body_def_id) == DefKind::TyAlias && !tcx.type_alias_is_lazy(body_def_id);
161+
162+
if !ignore_bounds && !tcx.features().trivial_bounds() {
143163
wfcx.check_false_global_bounds()
144164
}
145165
f(&mut wfcx)?;

compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ use std::iter;
88
use rustc_hir as hir;
99
use rustc_hir::def::DefKind;
1010
use rustc_hir::lang_items::LangItem;
11-
use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
11+
use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, PredicateObligations};
1212
use rustc_middle::bug;
1313
use rustc_middle::ty::{
14-
self, GenericArgsRef, Term, TermKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
14+
self, Binder, GenericArgsRef, Term, TermKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
1515
TypeVisitableExt, TypeVisitor,
1616
};
1717
use rustc_session::parse::feature_err;
@@ -942,14 +942,57 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
942942
// FIXME(#27579) RFC also considers adding trait
943943
// obligations that don't refer to Self and
944944
// checking those
945-
if let Some(principal) = data.principal_def_id() {
945+
if let Some(principal) = data.principal() {
946+
let principal_def_id = principal.skip_binder().def_id;
946947
self.out.push(traits::Obligation::with_depth(
947948
tcx,
948949
self.cause(ObligationCauseCode::WellFormed(None)),
949950
self.recursion_depth,
950951
self.param_env,
951-
ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)),
952+
ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal_def_id)),
952953
));
954+
955+
// For the most part we don't add wf predicates corresponding to
956+
// the trait ref's generic arguments which allows code like this
957+
// to compile:
958+
// ```rust
959+
// trait Trait<T: Sized> {}
960+
// fn foo(_: &dyn Trait<[u32]>) {}
961+
// ```
962+
//
963+
// However, we sometimes incidentally check that const arguments
964+
// have the correct type as a side effect of the anon const
965+
// desugaring. To make this "consistent" for users we explicitly
966+
// check `ConstArgHasType` clauses so that const args that don't
967+
// go through an anon const still have their types checked.
968+
let obligations = principal.map_bound(|principal| {
969+
let args = principal.with_self_ty(self.tcx(), t).args;
970+
let obligations = self.nominal_obligations(principal_def_id, args);
971+
obligations
972+
.into_iter()
973+
.filter(|o| {
974+
matches!(o.predicate.kind().skip_binder(),
975+
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _))
976+
if matches!(ct.kind(), ty::ConstKind::Param(..)))
977+
})
978+
.collect::<PredicateObligations<'tcx>>()
979+
}).iter().filter_map(|o| transpose_binder_into_binderless_obligation(tcx, o));
980+
self.out.extend(obligations);
981+
982+
// ConstArgHasType clauses do not have binders. So, convert a
983+
// Binder<PredicateObligation<Binder<T>>> into a PredicateObligation<Binder<T>> by assuming
984+
// no_bound_vars on the inner one (which gets us a Binder<PredicateObligation<T>>), then
985+
// transposing to a PredicateObligation<Binder<T>>.
986+
fn transpose_binder_into_binderless_obligation<'tcx>(
987+
tcx: TyCtxt<'tcx>,
988+
binder_obligation: Binder<'tcx, PredicateObligation<'tcx>>,
989+
) -> Option<PredicateObligation<'tcx>> {
990+
let bound_vars = binder_obligation.bound_vars();
991+
let obligation = binder_obligation.skip_binder();
992+
let predicate = obligation.predicate.kind().no_bound_vars()?;
993+
let binder_predicate = Binder::bind_with_vars(predicate, bound_vars);
994+
Some(obligation.with(tcx, binder_predicate))
995+
}
953996
}
954997

955998
if !t.has_escaping_bound_vars() {
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
error: the constant `B` is not of type `usize`
2+
--> $DIR/check_const_arg_type_in_free_alias.rs:15:1
3+
|
4+
LL | type ArrLen<const B: bool> = [(); B];
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
6+
|
7+
= note: the length of array `[(); B]` must be type `usize`
8+
9+
error: the constant `B` is not of type `usize`
10+
--> $DIR/check_const_arg_type_in_free_alias.rs:19:1
11+
|
12+
LL | type ConstArg<const B: bool> = Foo<B>;
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
14+
|
15+
note: required by a const generic parameter in `Foo`
16+
--> $DIR/check_const_arg_type_in_free_alias.rs:13:12
17+
|
18+
LL | struct Foo<const N: usize>;
19+
| ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo`
20+
21+
error: the constant `B` is not of type `usize`
22+
--> $DIR/check_const_arg_type_in_free_alias.rs:32:1
23+
|
24+
LL | type Alias<const B: bool> = <() as IdentityWithUnused<B>>::This;
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
26+
|
27+
note: required by a const generic parameter in `IdentityWithUnused`
28+
--> $DIR/check_const_arg_type_in_free_alias.rs:24:26
29+
|
30+
LL | trait IdentityWithUnused<const N: usize> {
31+
| ^^^^^^^^^^^^^^ required by this const generic parameter in `IdentityWithUnused`
32+
33+
error: the constant `B` is not of type `usize`
34+
--> $DIR/check_const_arg_type_in_free_alias.rs:38:1
35+
|
36+
LL | type UseFree<const B: bool> = Free<B>;
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
38+
|
39+
= note: the length of array `[(); B]` must be type `usize`
40+
41+
error: the constant `B` is not of type `usize`
42+
--> $DIR/check_const_arg_type_in_free_alias.rs:58:1
43+
|
44+
LL | type IndirectArr<const B: bool> = Wrap<Wrap<[(); B]>>;
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
46+
|
47+
= note: the length of array `[(); B]` must be type `usize`
48+
49+
error: the constant `B` is not of type `usize`
50+
--> $DIR/check_const_arg_type_in_free_alias.rs:62:1
51+
|
52+
LL | type IndirectConstArg<const B: bool> = Wrap<Wrap<Foo<B>>>;
53+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
54+
|
55+
note: required by a const generic parameter in `Foo`
56+
--> $DIR/check_const_arg_type_in_free_alias.rs:13:12
57+
|
58+
LL | struct Foo<const N: usize>;
59+
| ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo`
60+
61+
error[E0308]: mismatched types
62+
--> $DIR/check_const_arg_type_in_free_alias.rs:17:24
63+
|
64+
LL | type AnonArrLen = [(); true];
65+
| ^^^^ expected `usize`, found `bool`
66+
67+
error[E0308]: mismatched types
68+
--> $DIR/check_const_arg_type_in_free_alias.rs:21:25
69+
|
70+
LL | type AnonConstArg = Foo<true>;
71+
| ^^^^ expected `usize`, found `bool`
72+
73+
error[E0308]: mismatched types
74+
--> $DIR/check_const_arg_type_in_free_alias.rs:34:44
75+
|
76+
LL | type AnonAlias = <() as IdentityWithUnused<true>>::This;
77+
| ^^^^ expected `usize`, found `bool`
78+
79+
error[E0308]: mismatched types
80+
--> $DIR/check_const_arg_type_in_free_alias.rs:40:25
81+
|
82+
LL | type AnonUseFree = Free<true>;
83+
| ^^^^ expected `usize`, found `bool`
84+
85+
error[E0308]: mismatched types
86+
--> $DIR/check_const_arg_type_in_free_alias.rs:53:45
87+
|
88+
LL | type AnonUseFreeIndirectlyCorrect = UseFree<1_usize>;
89+
| ^^^^^^^ expected `bool`, found `usize`
90+
91+
error[E0308]: mismatched types
92+
--> $DIR/check_const_arg_type_in_free_alias.rs:60:39
93+
|
94+
LL | type AnonIndirectArr = Wrap<Wrap<[(); true]>>;
95+
| ^^^^ expected `usize`, found `bool`
96+
97+
error[E0308]: mismatched types
98+
--> $DIR/check_const_arg_type_in_free_alias.rs:64:43
99+
|
100+
LL | type AnonIndirectConstArg = Wrap<Wrap<Foo<true>>>;
101+
| ^^^^ expected `usize`, found `bool`
102+
103+
error: aborting due to 13 previous errors
104+
105+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
error: the constant `B` is not of type `usize`
2+
--> $DIR/check_const_arg_type_in_free_alias.rs:15:1
3+
|
4+
LL | type ArrLen<const B: bool> = [(); B];
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
6+
|
7+
= note: the length of array `[(); B]` must be type `usize`
8+
9+
error[E0308]: mismatched types
10+
--> $DIR/check_const_arg_type_in_free_alias.rs:17:24
11+
|
12+
LL | type AnonArrLen = [(); true];
13+
| ^^^^ expected `usize`, found `bool`
14+
15+
error: the constant `B` is not of type `usize`
16+
--> $DIR/check_const_arg_type_in_free_alias.rs:19:1
17+
|
18+
LL | type ConstArg<const B: bool> = Foo<B>;
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
20+
|
21+
note: required by a const generic parameter in `Foo`
22+
--> $DIR/check_const_arg_type_in_free_alias.rs:13:12
23+
|
24+
LL | struct Foo<const N: usize>;
25+
| ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo`
26+
27+
error[E0308]: mismatched types
28+
--> $DIR/check_const_arg_type_in_free_alias.rs:21:25
29+
|
30+
LL | type AnonConstArg = Foo<true>;
31+
| ^^^^ expected `usize`, found `bool`
32+
33+
error: the constant `B` is not of type `usize`
34+
--> $DIR/check_const_arg_type_in_free_alias.rs:32:1
35+
|
36+
LL | type Alias<const B: bool> = <() as IdentityWithUnused<B>>::This;
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
38+
|
39+
note: required for `()` to implement `IdentityWithUnused<B>`
40+
--> $DIR/check_const_arg_type_in_free_alias.rs:28:25
41+
|
42+
LL | impl<T, const N: usize> IdentityWithUnused<N> for T {
43+
| -------------- ^^^^^^^^^^^^^^^^^^^^^ ^
44+
| |
45+
| unsatisfied trait bound introduced here
46+
47+
error[E0308]: mismatched types
48+
--> $DIR/check_const_arg_type_in_free_alias.rs:34:44
49+
|
50+
LL | type AnonAlias = <() as IdentityWithUnused<true>>::This;
51+
| ^^^^ expected `usize`, found `bool`
52+
53+
error: the constant `B` is not of type `usize`
54+
--> $DIR/check_const_arg_type_in_free_alias.rs:38:1
55+
|
56+
LL | type UseFree<const B: bool> = Free<B>;
57+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
58+
|
59+
note: required by a bound on the type alias `Free`
60+
--> $DIR/check_const_arg_type_in_free_alias.rs:37:11
61+
|
62+
LL | type Free<const N: usize> = [(); N];
63+
| ^^^^^^^^^^^^^^ required by this bound
64+
65+
error[E0308]: mismatched types
66+
--> $DIR/check_const_arg_type_in_free_alias.rs:40:25
67+
|
68+
LL | type AnonUseFree = Free<true>;
69+
| ^^^^ expected `usize`, found `bool`
70+
71+
error: the constant `N` is not of type `bool`
72+
--> $DIR/check_const_arg_type_in_free_alias.rs:51:1
73+
|
74+
LL | type UseFreeIndirectlyCorrect<const N: usize> = UseFree<N>;
75+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `usize`
76+
|
77+
note: required by a bound on the type alias `UseFree`
78+
--> $DIR/check_const_arg_type_in_free_alias.rs:38:14
79+
|
80+
LL | type UseFree<const B: bool> = Free<B>;
81+
| ^^^^^^^^^^^^^ required by this bound
82+
83+
error[E0308]: mismatched types
84+
--> $DIR/check_const_arg_type_in_free_alias.rs:53:45
85+
|
86+
LL | type AnonUseFreeIndirectlyCorrect = UseFree<1_usize>;
87+
| ^^^^^^^ expected `bool`, found `usize`
88+
89+
error: the constant `B` is not of type `usize`
90+
--> $DIR/check_const_arg_type_in_free_alias.rs:58:1
91+
|
92+
LL | type IndirectArr<const B: bool> = Wrap<Wrap<[(); B]>>;
93+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
94+
|
95+
= note: the length of array `[(); B]` must be type `usize`
96+
97+
error[E0308]: mismatched types
98+
--> $DIR/check_const_arg_type_in_free_alias.rs:60:39
99+
|
100+
LL | type AnonIndirectArr = Wrap<Wrap<[(); true]>>;
101+
| ^^^^ expected `usize`, found `bool`
102+
103+
error: the constant `B` is not of type `usize`
104+
--> $DIR/check_const_arg_type_in_free_alias.rs:62:1
105+
|
106+
LL | type IndirectConstArg<const B: bool> = Wrap<Wrap<Foo<B>>>;
107+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
108+
|
109+
note: required by a const generic parameter in `Foo`
110+
--> $DIR/check_const_arg_type_in_free_alias.rs:13:12
111+
|
112+
LL | struct Foo<const N: usize>;
113+
| ^^^^^^^^^^^^^^ required by this const generic parameter in `Foo`
114+
115+
error[E0308]: mismatched types
116+
--> $DIR/check_const_arg_type_in_free_alias.rs:64:43
117+
|
118+
LL | type AnonIndirectConstArg = Wrap<Wrap<Foo<true>>>;
119+
| ^^^^ expected `usize`, found `bool`
120+
121+
error: aborting due to 14 previous errors
122+
123+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)