Skip to content

Commit 70dfe3f

Browse files
committed
move const param structural match checks to wfcheck
1 parent b287b56 commit 70dfe3f

File tree

7 files changed

+155
-401
lines changed

7 files changed

+155
-401
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,8 +729,8 @@ impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> {
729729
}
730730

731731
pub fn check_wf_new(tcx: TyCtxt<'_>) {
732-
let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
733-
tcx.hir().krate().par_visit_all_item_likes(&visit);
732+
let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
733+
tcx.hir().krate().visit_all_item_likes(&mut visit.as_deep_visitor());
734734
}
735735

736736
fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {

src/librustc_typeck/check/wfcheck.rs

Lines changed: 111 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ 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::itemlikevisit::ParItemLikeVisitor;
9+
use rustc_hir::intravisit as hir_visit;
10+
use rustc_hir::intravisit::Visitor;
1011
use rustc_hir::lang_items;
1112
use rustc_hir::ItemKind;
13+
use rustc_middle::hir::map as hir_map;
1214
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
1315
use rustc_middle::ty::trait_def::TraitSpecializationKind;
1416
use rustc_middle::ty::{
@@ -275,6 +277,95 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
275277
check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
276278
}
277279

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

1295-
impl ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
1296-
fn visit_item(&self, i: &'tcx hir::Item<'tcx>) {
1386+
impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
1387+
type Map = hir_map::Map<'tcx>;
1388+
1389+
fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
1390+
hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
1391+
}
1392+
1393+
fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
12971394
debug!("visit_item: {:?}", i);
12981395
let def_id = self.tcx.hir().local_def_id(i.hir_id);
12991396
self.tcx.ensure().check_item_well_formed(def_id);
1397+
hir_visit::walk_item(self, i);
13001398
}
13011399

1302-
fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem<'tcx>) {
1400+
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
13031401
debug!("visit_trait_item: {:?}", trait_item);
13041402
let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
13051403
self.tcx.ensure().check_trait_item_well_formed(def_id);
1404+
hir_visit::walk_trait_item(self, trait_item);
13061405
}
13071406

1308-
fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem<'tcx>) {
1407+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
13091408
debug!("visit_impl_item: {:?}", impl_item);
13101409
let def_id = self.tcx.hir().local_def_id(impl_item.hir_id);
13111410
self.tcx.ensure().check_impl_item_well_formed(def_id);
1411+
hir_visit::walk_impl_item(self, impl_item);
1412+
}
1413+
1414+
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
1415+
check_param_wf(self.tcx, p);
1416+
// No need to walk further here, there is nothing interesting
1417+
// inside of generic params we don't already check in `check_param_wf`.
13121418
}
13131419
}
13141420

src/librustc_typeck/collect/type_of.rs

Lines changed: 2 additions & 83 deletions
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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// check-pass
2+
#![feature(const_generics)]
3+
#![allow(incomplete_features)]
4+
5+
struct Bar<T>(T);
6+
7+
impl<T> Bar<T> {
8+
const fn value() -> usize {
9+
42
10+
}
11+
}
12+
13+
struct Foo<const N: [u8; Bar::<u32>::value()]>;
14+
15+
fn main() {}

0 commit comments

Comments
 (0)