Skip to content

Commit 672d009

Browse files
authored
Rollup merge of #75069 - lcnr:type-of-lazy-norm, r=varkor
move const param structural match checks to wfcheck fixes #75047 fixes #74950 We currently check for structural match violations inside of `type_of`. As we need to check the array length when checking if `[NonEq; arr_len]` is structural match, we potentially require the variance of an expression. Computing the variance requires `type_of` for all types though, resulting in a cycle error. r? @varkor @eddyb
2 parents 443e177 + 7542615 commit 672d009

31 files changed

+292
-469
lines changed

Diff for: src/librustc_typeck/check/wfcheck.rs

+135-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
66
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
77
use rustc_hir as hir;
88
use rustc_hir::def_id::{DefId, LocalDefId};
9+
use rustc_hir::intravisit as hir_visit;
10+
use rustc_hir::intravisit::Visitor;
911
use rustc_hir::itemlikevisit::ParItemLikeVisitor;
1012
use rustc_hir::lang_items;
1113
use rustc_hir::ItemKind;
14+
use rustc_middle::hir::map as hir_map;
1215
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
1316
use rustc_middle::ty::trait_def::TraitSpecializationKind;
1417
use rustc_middle::ty::{
@@ -275,6 +278,107 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
275278
check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
276279
}
277280

281+
fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
282+
match param.kind {
283+
// We currently only check wf of const params here.
284+
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
285+
286+
// Const parameters are well formed if their
287+
// type is structural match.
288+
hir::GenericParamKind::Const { ty: hir_ty } => {
289+
let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
290+
291+
let err_ty_str;
292+
let mut is_ptr = true;
293+
let err = if tcx.features().min_const_generics {
294+
match ty.kind {
295+
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
296+
ty::FnPtr(_) => Some("function pointers"),
297+
ty::RawPtr(_) => Some("raw pointers"),
298+
_ => {
299+
is_ptr = false;
300+
err_ty_str = format!("`{}`", ty);
301+
Some(err_ty_str.as_str())
302+
}
303+
}
304+
} else {
305+
match ty.peel_refs().kind {
306+
ty::FnPtr(_) => Some("function pointers"),
307+
ty::RawPtr(_) => Some("raw pointers"),
308+
_ => None,
309+
}
310+
};
311+
if let Some(unsupported_type) = err {
312+
if is_ptr {
313+
tcx.sess.span_err(
314+
hir_ty.span,
315+
&format!(
316+
"using {} as const generic parameters is forbidden",
317+
unsupported_type
318+
),
319+
)
320+
} else {
321+
tcx.sess
322+
.struct_span_err(
323+
hir_ty.span,
324+
&format!(
325+
"{} is forbidden as the type of a const generic parameter",
326+
unsupported_type
327+
),
328+
)
329+
.note("the only supported types are integers, `bool` and `char`")
330+
.note("more complex types are supported with `#[feature(const_generics)]`")
331+
.emit()
332+
}
333+
};
334+
335+
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
336+
.is_some()
337+
{
338+
// We use the same error code in both branches, because this is really the same
339+
// issue: we just special-case the message for type parameters to make it
340+
// clearer.
341+
if let ty::Param(_) = ty.peel_refs().kind {
342+
// Const parameters may not have type parameters as their types,
343+
// because we cannot be sure that the type parameter derives `PartialEq`
344+
// and `Eq` (just implementing them is not enough for `structural_match`).
345+
struct_span_err!(
346+
tcx.sess,
347+
hir_ty.span,
348+
E0741,
349+
"`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
350+
used as the type of a const parameter",
351+
ty,
352+
)
353+
.span_label(
354+
hir_ty.span,
355+
format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
356+
)
357+
.note(
358+
"it is not currently possible to use a type parameter as the type of a \
359+
const parameter",
360+
)
361+
.emit();
362+
} else {
363+
struct_span_err!(
364+
tcx.sess,
365+
hir_ty.span,
366+
E0741,
367+
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
368+
the type of a const parameter",
369+
ty,
370+
)
371+
.span_label(
372+
hir_ty.span,
373+
format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
374+
)
375+
.emit();
376+
}
377+
}
378+
}
379+
}
380+
}
381+
278382
fn check_associated_item(
279383
tcx: TyCtxt<'_>,
280384
item_id: hir::HirId,
@@ -1282,6 +1386,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) {
12821386
fcx.select_all_obligations_or_error();
12831387
}
12841388

1389+
#[derive(Clone, Copy)]
12851390
pub struct CheckTypeWellFormedVisitor<'tcx> {
12861391
tcx: TyCtxt<'tcx>,
12871392
}
@@ -1294,21 +1399,49 @@ impl CheckTypeWellFormedVisitor<'tcx> {
12941399

12951400
impl ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
12961401
fn visit_item(&self, i: &'tcx hir::Item<'tcx>) {
1402+
Visitor::visit_item(&mut self.clone(), i);
1403+
}
1404+
1405+
fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem<'tcx>) {
1406+
Visitor::visit_trait_item(&mut self.clone(), trait_item);
1407+
}
1408+
1409+
fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) {
1410+
Visitor::visit_impl_item(&mut self.clone(), impl_item);
1411+
}
1412+
}
1413+
1414+
impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
1415+
type Map = hir_map::Map<'tcx>;
1416+
1417+
fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
1418+
hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
1419+
}
1420+
1421+
fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
12971422
debug!("visit_item: {:?}", i);
12981423
let def_id = self.tcx.hir().local_def_id(i.hir_id);
12991424
self.tcx.ensure().check_item_well_formed(def_id);
1425+
hir_visit::walk_item(self, i);
13001426
}
13011427

1302-
fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem<'tcx>) {
1428+
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
13031429
debug!("visit_trait_item: {:?}", trait_item);
13041430
let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
13051431
self.tcx.ensure().check_trait_item_well_formed(def_id);
1432+
hir_visit::walk_trait_item(self, trait_item);
13061433
}
13071434

1308-
fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) {
1435+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
13091436
debug!("visit_impl_item: {:?}", impl_item);
13101437
let def_id = self.tcx.hir().local_def_id(impl_item.hir_id);
13111438
self.tcx.ensure().check_impl_item_well_formed(def_id);
1439+
hir_visit::walk_impl_item(self, impl_item);
1440+
}
1441+
1442+
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
1443+
check_param_wf(self.tcx, p);
1444+
hir_visit::walk_generic_param(self, p);
13121445
}
13131446
}
13141447

Diff for: src/librustc_typeck/collect/type_of.rs

+2-83
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use rustc_middle::ty::util::IntTypeExt;
1212
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
1313
use rustc_span::symbol::Ident;
1414
use rustc_span::{Span, DUMMY_SP};
15-
use rustc_trait_selection::traits;
1615

1716
use super::ItemCtxt;
1817
use super::{bad_placeholder_type, is_suggestable_infer_ty};
@@ -323,88 +322,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
323322
}
324323

325324
Node::GenericParam(param) => match &param.kind {
326-
GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
327-
GenericParamKind::Const { ty: ref hir_ty, .. } => {
328-
let ty = icx.to_ty(hir_ty);
329-
let err_ty_str;
330-
let err = if tcx.features().min_const_generics {
331-
match ty.kind {
332-
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
333-
ty::FnPtr(_) => Some("function pointers"),
334-
ty::RawPtr(_) => Some("raw pointers"),
335-
_ => {
336-
err_ty_str = format!("`{}`", ty);
337-
Some(err_ty_str.as_str())
338-
}
339-
}
340-
} else {
341-
match ty.peel_refs().kind {
342-
ty::FnPtr(_) => Some("function pointers"),
343-
ty::RawPtr(_) => Some("raw pointers"),
344-
_ => None,
345-
}
346-
};
347-
if let Some(unsupported_type) = err {
348-
let mut err = tcx.sess.struct_span_err(
349-
hir_ty.span,
350-
&format!(
351-
"using {} as const generic parameters is forbidden",
352-
unsupported_type
353-
),
354-
);
355-
356-
if tcx.features().min_const_generics {
357-
err.note("the only supported types are integers, `bool` and `char`")
358-
.note("more complex types are supported with `#[feature(const_generics)]`").emit()
359-
} else {
360-
err.emit();
361-
}
362-
};
363-
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
364-
.is_some()
365-
{
366-
// We use the same error code in both branches, because this is really the same
367-
// issue: we just special-case the message for type parameters to make it
368-
// clearer.
369-
if let ty::Param(_) = ty.peel_refs().kind {
370-
// Const parameters may not have type parameters as their types,
371-
// because we cannot be sure that the type parameter derives `PartialEq`
372-
// and `Eq` (just implementing them is not enough for `structural_match`).
373-
struct_span_err!(
374-
tcx.sess,
375-
hir_ty.span,
376-
E0741,
377-
"`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
378-
used as the type of a const parameter",
379-
ty,
380-
)
381-
.span_label(
382-
hir_ty.span,
383-
format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
384-
)
385-
.note(
386-
"it is not currently possible to use a type parameter as the type of a \
387-
const parameter",
388-
)
389-
.emit();
390-
} else {
391-
struct_span_err!(
392-
tcx.sess,
393-
hir_ty.span,
394-
E0741,
395-
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
396-
the type of a const parameter",
397-
ty,
398-
)
399-
.span_label(
400-
hir_ty.span,
401-
format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
402-
)
403-
.emit();
404-
}
405-
}
406-
ty
407-
}
325+
GenericParamKind::Type { default: Some(ty), .. }
326+
| GenericParamKind::Const { ty, .. } => icx.to_ty(ty),
408327
x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
409328
},
410329

Diff for: src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ LL | arr: [u8; CFG.arr_size],
1414
|
1515
= help: it is currently only allowed to use either `CFG` or `{ CFG }` as generic constants
1616

17-
error: using `Config` as const generic parameters is forbidden
17+
error: `Config` is forbidden as the type of a const generic parameter
1818
--> $DIR/array-size-in-generic-struct-param.rs:18:21
1919
|
2020
LL | struct B<const CFG: Config> {

Diff for: src/test/ui/const-generics/array-size-in-generic-struct-param.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct Config {
1616
}
1717

1818
struct B<const CFG: Config> {
19-
//[min]~^ ERROR using `Config` as const generic parameters is forbidden
19+
//[min]~^ ERROR `Config` is forbidden
2020
arr: [u8; CFG.arr_size],
2121
//[full]~^ ERROR constant expression depends on a generic parameter
2222
//[min]~^^ ERROR generic parameters must not be used inside of non trivial

Diff for: src/test/ui/const-generics/const-param-elided-lifetime.min.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
2828
LL | fn bar<const N: &u8>() {}
2929
| ^ explicit lifetime name needed here
3030

31-
error: using `&'static u8` as const generic parameters is forbidden
31+
error: `&'static u8` is forbidden as the type of a const generic parameter
3232
--> $DIR/const-param-elided-lifetime.rs:11:19
3333
|
3434
LL | struct A<const N: &u8>;
@@ -37,7 +37,7 @@ LL | struct A<const N: &u8>;
3737
= note: the only supported types are integers, `bool` and `char`
3838
= note: more complex types are supported with `#[feature(const_generics)]`
3939

40-
error: using `&'static u8` as const generic parameters is forbidden
40+
error: `&'static u8` is forbidden as the type of a const generic parameter
4141
--> $DIR/const-param-elided-lifetime.rs:16:15
4242
|
4343
LL | impl<const N: &u8> A<N> {
@@ -46,7 +46,7 @@ LL | impl<const N: &u8> A<N> {
4646
= note: the only supported types are integers, `bool` and `char`
4747
= note: more complex types are supported with `#[feature(const_generics)]`
4848

49-
error: using `&'static u8` as const generic parameters is forbidden
49+
error: `&'static u8` is forbidden as the type of a const generic parameter
5050
--> $DIR/const-param-elided-lifetime.rs:24:15
5151
|
5252
LL | impl<const N: &u8> B for A<N> {}
@@ -55,7 +55,7 @@ LL | impl<const N: &u8> B for A<N> {}
5555
= note: the only supported types are integers, `bool` and `char`
5656
= note: more complex types are supported with `#[feature(const_generics)]`
5757

58-
error: using `&'static u8` as const generic parameters is forbidden
58+
error: `&'static u8` is forbidden as the type of a const generic parameter
5959
--> $DIR/const-param-elided-lifetime.rs:28:17
6060
|
6161
LL | fn bar<const N: &u8>() {}
@@ -64,7 +64,7 @@ LL | fn bar<const N: &u8>() {}
6464
= note: the only supported types are integers, `bool` and `char`
6565
= note: more complex types are supported with `#[feature(const_generics)]`
6666

67-
error: using `&'static u8` as const generic parameters is forbidden
67+
error: `&'static u8` is forbidden as the type of a const generic parameter
6868
--> $DIR/const-param-elided-lifetime.rs:19:21
6969
|
7070
LL | fn foo<const M: &u8>(&self) {}

Diff for: src/test/ui/const-generics/const-param-elided-lifetime.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@
1010

1111
struct A<const N: &u8>;
1212
//~^ ERROR `&` without an explicit lifetime name cannot be used here
13-
//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
13+
//[min]~^^ ERROR `&'static u8` is forbidden
1414
trait B {}
1515

1616
impl<const N: &u8> A<N> {
1717
//~^ ERROR `&` without an explicit lifetime name cannot be used here
18-
//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
18+
//[min]~^^ ERROR `&'static u8` is forbidden
1919
fn foo<const M: &u8>(&self) {}
2020
//~^ ERROR `&` without an explicit lifetime name cannot be used here
21-
//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
21+
//[min]~^^ ERROR `&'static u8` is forbidden
2222
}
2323

2424
impl<const N: &u8> B for A<N> {}
2525
//~^ ERROR `&` without an explicit lifetime name cannot be used here
26-
//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
26+
//[min]~^^ ERROR `&'static u8` is forbidden
2727

2828
fn bar<const N: &u8>() {}
2929
//~^ ERROR `&` without an explicit lifetime name cannot be used here
30-
//[min]~^^ ERROR using `&'static u8` as const generic parameters is forbidden
30+
//[min]~^^ ERROR `&'static u8` is forbidden
3131

3232
fn main() {}

Diff for: src/test/ui/const-generics/const-param-type-depends-on-const-param.min.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ error[E0770]: the type of const parameters must not depend on other generic para
1010
LL | pub struct SelfDependent<const N: [u8; N]>;
1111
| ^ the type must not depend on the parameter `N`
1212

13-
error: using `[u8; _]` as const generic parameters is forbidden
13+
error: `[u8; _]` is forbidden as the type of a const generic parameter
1414
--> $DIR/const-param-type-depends-on-const-param.rs:12:47
1515
|
1616
LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
@@ -19,7 +19,7 @@ LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
1919
= note: the only supported types are integers, `bool` and `char`
2020
= note: more complex types are supported with `#[feature(const_generics)]`
2121

22-
error: using `[u8; _]` as const generic parameters is forbidden
22+
error: `[u8; _]` is forbidden as the type of a const generic parameter
2323
--> $DIR/const-param-type-depends-on-const-param.rs:16:35
2424
|
2525
LL | pub struct SelfDependent<const N: [u8; N]>;

0 commit comments

Comments
 (0)