Skip to content

Commit 9587fd7

Browse files
Apply normalization for all projection for const generics
1 parent eed7738 commit 9587fd7

File tree

3 files changed

+157
-153
lines changed

3 files changed

+157
-153
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+126-128
Original file line numberDiff line numberDiff line change
@@ -846,142 +846,140 @@ fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) {
846846
check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig);
847847
}
848848

849-
fn check_param_wf_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, hir_ty: &rustc_hir::Ty<'_>, param_span: Span) {
850-
if tcx.features().adt_const_params {
851-
if let Some(non_structural_match_ty) =
852-
traits::search_for_adt_const_param_violation(param_span, tcx, ty)
853-
{
854-
// We use the same error code in both branches, because this is really the same
855-
// issue: we just special-case the message for type parameters to make it
856-
// clearer.
857-
match non_structural_match_ty.kind() {
858-
ty::Param(_) => {
859-
// Const parameters may not have type parameters as their types,
860-
// because we cannot be sure that the type parameter derives `PartialEq`
861-
// and `Eq` (just implementing them is not enough for `structural_match`).
862-
struct_span_err!(
863-
tcx.sess,
864-
hir_ty.span,
865-
E0741,
866-
"`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
867-
used as the type of a const parameter",
868-
)
869-
.span_label(
870-
hir_ty.span,
871-
format!("`{ty}` may not derive both `PartialEq` and `Eq`"),
872-
)
873-
.note(
874-
"it is not currently possible to use a type parameter as the type of a \
875-
const parameter",
876-
)
877-
.emit();
878-
}
879-
ty::Float(_) => {
880-
struct_span_err!(
881-
tcx.sess,
882-
hir_ty.span,
883-
E0741,
884-
"`{ty}` is forbidden as the type of a const generic parameter",
885-
)
886-
.note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
887-
.emit();
888-
}
889-
ty::FnPtr(_) => {
890-
struct_span_err!(
891-
tcx.sess,
892-
hir_ty.span,
893-
E0741,
894-
"using function pointers as const generic parameters is forbidden",
895-
)
896-
.emit();
897-
}
898-
ty::RawPtr(_) => {
899-
struct_span_err!(
900-
tcx.sess,
901-
hir_ty.span,
902-
E0741,
903-
"using raw pointers as const generic parameters is forbidden",
904-
)
905-
.emit();
906-
}
907-
ty::Projection(ty::ProjectionTy { substs, item_def_id }) => {
908-
let binder_ty = tcx.bound_type_of(*item_def_id);
909-
let ty = binder_ty.subst(tcx, substs);
910-
check_param_wf_ty(tcx, ty, hir_ty, param_span);
911-
}
912-
_ => {
913-
let mut diag = struct_span_err!(
914-
tcx.sess,
915-
hir_ty.span,
916-
E0741,
917-
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
918-
the type of a const parameter",
919-
non_structural_match_ty,
920-
);
921-
922-
if ty == non_structural_match_ty {
923-
diag.span_label(
924-
hir_ty.span,
925-
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
926-
);
927-
}
928-
929-
diag.emit();
930-
}
931-
}
932-
}
933-
} else {
934-
let err_ty_str;
935-
let mut is_ptr = true;
936-
937-
let err = match ty.kind() {
938-
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
939-
ty::FnPtr(_) => Some("function pointers"),
940-
ty::RawPtr(_) => Some("raw pointers"),
941-
_ => {
942-
is_ptr = false;
943-
err_ty_str = format!("`{ty}`");
944-
Some(err_ty_str.as_str())
945-
}
946-
};
947-
948-
if let Some(unsupported_type) = err {
949-
if is_ptr {
950-
tcx.sess.span_err(
951-
hir_ty.span,
952-
&format!(
953-
"using {unsupported_type} as const generic parameters is forbidden",
954-
),
955-
);
956-
} else {
957-
let mut err = tcx.sess.struct_span_err(
958-
hir_ty.span,
959-
&format!(
960-
"{unsupported_type} is forbidden as the type of a const generic parameter",
961-
),
962-
);
963-
err.note("the only supported types are integers, `bool` and `char`");
964-
if tcx.sess.is_nightly_build() {
965-
err.help(
966-
"more complex types are supported with `#![feature(adt_const_params)]`",
967-
);
968-
}
969-
err.emit();
970-
}
971-
}
972-
}
973-
}
974-
975849
fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
976850
match param.kind {
977851
// We currently only check wf of const params here.
978852
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
979853

980854
// Const parameters are well formed if their type is structural match.
981855
hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
982-
let ty = tcx.type_of(param.def_id);
856+
let mut ty = tcx.type_of(param.def_id);
857+
while let ty::Projection(ty::ProjectionTy { substs, item_def_id }) = ty.kind() {
858+
let binder_ty = tcx.bound_type_of(*item_def_id);
859+
ty = binder_ty.subst(tcx, substs);
860+
}
983861

984-
check_param_wf_ty(tcx, ty, hir_ty, param.span);
862+
if tcx.features().adt_const_params {
863+
if let Some(non_structural_match_ty) =
864+
traits::search_for_adt_const_param_violation(param.span, tcx, ty)
865+
{
866+
// We use the same error code in both branches, because this is really the same
867+
// issue: we just special-case the message for type parameters to make it
868+
// clearer.
869+
match non_structural_match_ty.kind() {
870+
ty::Param(_) => {
871+
// Const parameters may not have type parameters as their types,
872+
// because we cannot be sure that the type parameter derives `PartialEq`
873+
// and `Eq` (just implementing them is not enough for `structural_match`).
874+
struct_span_err!(
875+
tcx.sess,
876+
hir_ty.span,
877+
E0741,
878+
"`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
879+
used as the type of a const parameter",
880+
)
881+
.span_label(
882+
hir_ty.span,
883+
format!("`{ty}` may not derive both `PartialEq` and `Eq`"),
884+
)
885+
.note(
886+
"it is not currently possible to use a type parameter as the type of a \
887+
const parameter",
888+
)
889+
.emit();
890+
}
891+
ty::Float(_) => {
892+
struct_span_err!(
893+
tcx.sess,
894+
hir_ty.span,
895+
E0741,
896+
"`{ty}` is forbidden as the type of a const generic parameter",
897+
)
898+
.note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
899+
.emit();
900+
}
901+
ty::FnPtr(_) => {
902+
struct_span_err!(
903+
tcx.sess,
904+
hir_ty.span,
905+
E0741,
906+
"using function pointers as const generic parameters is forbidden",
907+
)
908+
.emit();
909+
}
910+
ty::RawPtr(_) => {
911+
struct_span_err!(
912+
tcx.sess,
913+
hir_ty.span,
914+
E0741,
915+
"using raw pointers as const generic parameters is forbidden",
916+
)
917+
.emit();
918+
}
919+
// Should have been normalized in
920+
// `traits::search_for_adt_const_param_violation`
921+
ty::Projection(_) => unreachable!(),
922+
_ => {
923+
let mut diag = struct_span_err!(
924+
tcx.sess,
925+
hir_ty.span,
926+
E0741,
927+
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
928+
the type of a const parameter",
929+
non_structural_match_ty,
930+
);
931+
932+
if ty == non_structural_match_ty {
933+
diag.span_label(
934+
hir_ty.span,
935+
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
936+
);
937+
}
938+
939+
diag.emit();
940+
}
941+
}
942+
}
943+
} else {
944+
let err_ty_str;
945+
let mut is_ptr = true;
946+
947+
let err = match ty.kind() {
948+
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
949+
ty::FnPtr(_) => Some("function pointers"),
950+
ty::RawPtr(_) => Some("raw pointers"),
951+
_ => {
952+
is_ptr = false;
953+
err_ty_str = format!("`{ty}`");
954+
Some(err_ty_str.as_str())
955+
}
956+
};
957+
958+
if let Some(unsupported_type) = err {
959+
if is_ptr {
960+
tcx.sess.span_err(
961+
hir_ty.span,
962+
&format!(
963+
"using {unsupported_type} as const generic parameters is forbidden",
964+
),
965+
);
966+
} else {
967+
let mut err = tcx.sess.struct_span_err(
968+
hir_ty.span,
969+
&format!(
970+
"{unsupported_type} is forbidden as the type of a const generic parameter",
971+
),
972+
);
973+
err.note("the only supported types are integers, `bool` and `char`");
974+
if tcx.sess.is_nightly_build() {
975+
err.help(
976+
"more complex types are supported with `#![feature(adt_const_params)]`",
977+
);
978+
}
979+
err.emit();
980+
}
981+
}
982+
}
985983
}
986984
}
987985
}

compiler/rustc_mir_build/src/thir/constant.rs

+27-13
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,22 @@ use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
33
use rustc_middle::ty::{self, ParamEnv, ScalarInt, Ty, TyCtxt};
44
use rustc_span::DUMMY_SP;
55

6-
fn trunc<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, lit: &ast::LitKind, n: u128) -> Result<ScalarInt, LitToConstError> {
6+
fn trunc<'tcx>(
7+
tcx: TyCtxt<'tcx>,
8+
ty: Ty<'tcx>,
9+
lit: &ast::LitKind,
10+
n: u128,
11+
) -> Result<ScalarInt, LitToConstError> {
712
let param_ty = ParamEnv::reveal_all().and(ty);
8-
let width = tcx
9-
.layout_of(param_ty)
10-
.map_err(|_| {
11-
LitToConstError::Reported(tcx.sess.delay_span_bug(
12-
DUMMY_SP,
13-
format!("couldn't compute width of literal: {:?}", lit),
14-
))
15-
})?
16-
.size;
13+
let width =
14+
tcx.layout_of(param_ty)
15+
.map_err(|_| {
16+
LitToConstError::Reported(tcx.sess.delay_span_bug(
17+
DUMMY_SP,
18+
format!("couldn't compute width of literal: {:?}", lit),
19+
))
20+
})?
21+
.size;
1722
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
1823
let result = width.truncate(n);
1924
trace!("trunc result: {}", result);
@@ -22,7 +27,12 @@ fn trunc<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, lit: &ast::LitKind, n: u128) ->
2227
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
2328
}
2429

25-
fn get_valtree<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, neg: bool, lit: &ast::LitKind) -> Result<ty::ValTree<'tcx>, LitToConstError> {
30+
fn get_valtree<'tcx>(
31+
tcx: TyCtxt<'tcx>,
32+
ty: Ty<'tcx>,
33+
neg: bool,
34+
lit: &ast::LitKind,
35+
) -> Result<ty::ValTree<'tcx>, LitToConstError> {
2636
Ok(match (lit, &ty.kind()) {
2737
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
2838
let str_bytes = s.as_str().as_bytes();
@@ -42,8 +52,12 @@ fn get_valtree<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, neg: bool, lit: &ast::LitK
4252
ty::ValTree::from_scalar_int((*n).into())
4353
}
4454
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
45-
let scalar_int =
46-
trunc(tcx, ty, lit, if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?;
55+
let scalar_int = trunc(
56+
tcx,
57+
ty,
58+
lit,
59+
if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n },
60+
)?;
4761
ty::ValTree::from_scalar_int(scalar_int)
4862
}
4963
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),

src/test/ui/const-generics/projection-as-arg-const.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
// run-pass
22

3-
#![allow(incomplete_features)] // This is needed for the `adt_const_params` feature.
4-
#![feature(associated_type_defaults)]
3+
pub trait Identity {
4+
type Identity;
5+
}
56

6-
pub trait Identity: Sized {
7+
impl<T> Identity for T {
78
type Identity = Self;
8-
// ^ This is needed because otherwise we get:
9-
// error: internal compiler error: compiler/rustc_hir_analysis/src/collect/type_of.rs:271:17: \
10-
// associated type missing default
11-
// --> test.rs:6:5
12-
// |
13-
// 6 | type Identity;
14-
// | ^^^^^^^^^^^^^^
159
}
1610

17-
impl<T> Identity for T {}
18-
1911
pub fn foo<const X: <i32 as Identity>::Identity>() {
2012
assert!(X == 12);
2113
}

0 commit comments

Comments
 (0)