From f87e58f1948c493aef6d645f339c2b9043e5ba59 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Jan 2025 16:44:08 +0000 Subject: [PATCH] Allow int literals for pattern types with int base types --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 15 +- .../src/builder/expr/as_constant.rs | 7 +- tests/ui/type/pattern_types/literals.rs | 11 +- tests/ui/type/pattern_types/literals.stderr | 139 ++++-------------- tests/ui/type/pattern_types/nested.rs | 4 +- tests/ui/type/pattern_types/nested.stderr | 9 +- 6 files changed, 55 insertions(+), 130 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index db947b6744d..253ba74a191 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1647,7 +1647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast::LitKind::Char(_) => tcx.types.char, ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)), ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)), - ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { + ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) => { let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Int(_) | ty::Uint(_) => Some(ty), // These exist to direct casts like `0x61 as char` to use @@ -1656,6 +1656,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Char => Some(tcx.types.u8), ty::RawPtr(..) => Some(tcx.types.usize), ty::FnDef(..) | ty::FnPtr(..) => Some(tcx.types.usize), + &ty::Pat(base, _) if base.is_integral() => { + let layout = tcx + .layout_of(self.typing_env(self.param_env).as_query_input(ty)) + .ok()?; + assert!(!layout.uninhabited); + + match layout.backend_repr { + rustc_abi::BackendRepr::Scalar(scalar) => { + scalar.valid_range(&tcx).contains(u128::from(i.get())).then_some(ty) + } + _ => unreachable!(), + } + } _ => None, }); opt_ty.unwrap_or_else(|| self.next_int_var()) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 84c9297e658..f743ea60a45 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -117,7 +117,12 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> ConstValue::Scalar(Scalar::from_uint(result, width)) }; - let value = match (lit, ty.kind()) { + let lit_ty = match *ty.kind() { + ty::Pat(base, _) => base, + _ => ty, + }; + + let value = match (lit, lit_ty.kind()) { (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); diff --git a/tests/ui/type/pattern_types/literals.rs b/tests/ui/type/pattern_types/literals.rs index 7ff3fdf0920..97a918645f3 100644 --- a/tests/ui/type/pattern_types/literals.rs +++ b/tests/ui/type/pattern_types/literals.rs @@ -12,27 +12,24 @@ fn out_of_range() -> pattern_type!(u32 is 1..) { fn at_range_start() -> pattern_type!(u32 is 1..) { 1 - //~^ mismatched types } fn in_range() -> pattern_type!(u32 is 1..) { 2 - //~^ mismatched types } fn negative_lit_on_unsigned_ty() -> pattern_type!(u32 is 1..) { -3 - //~^ mismatched types + //~^ ERROR: cannot apply unary operator `-` to type `(u32) is 1..` } fn negative_lit_in_range() -> pattern_type!(i8 is -5..5) { -2 - //~^ mismatched types + //~^ ERROR: cannot apply unary operator `-` to type `(i8) is -5..=4` } fn positive_lit_in_range_of_signed() -> pattern_type!(i8 is -5..5) { 2 - //~^ mismatched types } fn negative_lit_at_range_start() -> pattern_type!(i8 is -5..5) { @@ -42,7 +39,6 @@ fn negative_lit_at_range_start() -> pattern_type!(i8 is -5..5) { fn positive_lit_at_range_end() -> pattern_type!(i8 is -5..5) { 4 - //~^ mismatched types } fn lit_one_beyond_range_end() -> pattern_type!(i8 is -5..5) { @@ -67,12 +63,10 @@ fn char_lit_out_of_range() -> pattern_type!(char is 'a'..'z') { fn lit_at_unsigned_range_inclusive_end() -> pattern_type!(u32 is 0..=1) { 1 - //~^ mismatched types } fn single_element_range() -> pattern_type!(u32 is 0..=0) { 0 - //~^ mismatched types } fn lit_oob_single_element_range() -> pattern_type!(u32 is 0..=0) { @@ -87,7 +81,6 @@ fn lit_oob_single_element_range_exclusive() -> pattern_type!(u32 is 0..1) { fn single_element_range_exclusive() -> pattern_type!(u32 is 0..1) { 0 - //~^ mismatched types } fn empty_range_at_base_type_min() -> pattern_type!(u32 is 0..0) { diff --git a/tests/ui/type/pattern_types/literals.stderr b/tests/ui/type/pattern_types/literals.stderr index ae098728620..5c926742f3c 100644 --- a/tests/ui/type/pattern_types/literals.stderr +++ b/tests/ui/type/pattern_types/literals.stderr @@ -1,29 +1,29 @@ error[E0080]: evaluation of constant value failed - --> $DIR/literals.rs:93:62 + --> $DIR/literals.rs:86:62 | LL | fn empty_range_at_base_type_min() -> pattern_type!(u32 is 0..0) { | ^ evaluation panicked: exclusive range end at minimum value of type error[E0080]: evaluation of constant value failed - --> $DIR/literals.rs:98:63 + --> $DIR/literals.rs:91:63 | LL | fn empty_range_at_base_type_min2() -> pattern_type!(u32 is 0..0) { | ^ evaluation panicked: exclusive range end at minimum value of type error[E0080]: evaluation of constant value failed - --> $DIR/literals.rs:113:65 + --> $DIR/literals.rs:106:65 | LL | fn wraparound_range_at_base_ty_end() -> pattern_type!(u32 is 1..0) { | ^ evaluation panicked: exclusive range end at minimum value of type error[E0080]: evaluation of constant value failed - --> $DIR/literals.rs:118:66 + --> $DIR/literals.rs:111:66 | LL | fn wraparound_range_at_base_ty_end2() -> pattern_type!(u32 is 1..0) { | ^ evaluation panicked: exclusive range end at minimum value of type error[E0080]: evaluation of constant value failed - --> $DIR/literals.rs:123:66 + --> $DIR/literals.rs:116:66 | LL | fn wraparound_range_at_base_ty_end3() -> pattern_type!(u32 is 1..0) { | ^ evaluation panicked: exclusive range end at minimum value of type @@ -39,63 +39,20 @@ LL | 0 = note: expected pattern type `(u32) is 1..` found type `{integer}` -error[E0308]: mismatched types - --> $DIR/literals.rs:14:5 +error[E0600]: cannot apply unary operator `-` to type `(u32) is 1..` + --> $DIR/literals.rs:22:5 | -LL | fn at_range_start() -> pattern_type!(u32 is 1..) { - | ------------------------- expected `(u32) is 1..` because of return type -LL | 1 - | ^ expected `(u32) is 1..`, found integer - | - = note: expected pattern type `(u32) is 1..` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/literals.rs:19:5 - | -LL | fn in_range() -> pattern_type!(u32 is 1..) { - | ------------------------- expected `(u32) is 1..` because of return type -LL | 2 - | ^ expected `(u32) is 1..`, found integer - | - = note: expected pattern type `(u32) is 1..` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/literals.rs:24:5 - | -LL | fn negative_lit_on_unsigned_ty() -> pattern_type!(u32 is 1..) { - | ------------------------- expected `(u32) is 1..` because of return type LL | -3 - | ^^ expected `(u32) is 1..`, found integer - | - = note: expected pattern type `(u32) is 1..` - found type `{integer}` + | ^^ cannot apply unary operator `-` -error[E0308]: mismatched types - --> $DIR/literals.rs:29:5 +error[E0600]: cannot apply unary operator `-` to type `(i8) is -5..=4` + --> $DIR/literals.rs:27:5 | -LL | fn negative_lit_in_range() -> pattern_type!(i8 is -5..5) { - | -------------------------- expected `(i8) is -5..=4` because of return type LL | -2 - | ^^ expected `(i8) is -5..=4`, found integer - | - = note: expected pattern type `(i8) is -5..=4` - found type `{integer}` + | ^^ cannot apply unary operator `-` error[E0308]: mismatched types - --> $DIR/literals.rs:34:5 - | -LL | fn positive_lit_in_range_of_signed() -> pattern_type!(i8 is -5..5) { - | -------------------------- expected `(i8) is -5..=4` because of return type -LL | 2 - | ^ expected `(i8) is -5..=4`, found integer - | - = note: expected pattern type `(i8) is -5..=4` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/literals.rs:39:5 + --> $DIR/literals.rs:36:5 | LL | fn negative_lit_at_range_start() -> pattern_type!(i8 is -5..5) { | -------------------------- expected `(i8) is -5..=4` because of return type @@ -106,18 +63,7 @@ LL | -5 found type `{integer}` error[E0308]: mismatched types - --> $DIR/literals.rs:44:5 - | -LL | fn positive_lit_at_range_end() -> pattern_type!(i8 is -5..5) { - | -------------------------- expected `(i8) is -5..=4` because of return type -LL | 4 - | ^ expected `(i8) is -5..=4`, found integer - | - = note: expected pattern type `(i8) is -5..=4` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/literals.rs:49:5 + --> $DIR/literals.rs:45:5 | LL | fn lit_one_beyond_range_end() -> pattern_type!(i8 is -5..5) { | -------------------------- expected `(i8) is -5..=4` because of return type @@ -128,7 +74,7 @@ LL | 5 found type `{integer}` error[E0308]: mismatched types - --> $DIR/literals.rs:54:5 + --> $DIR/literals.rs:50:5 | LL | fn wrong_lit_kind() -> pattern_type!(u32 is 1..) { | ------------------------- expected `(u32) is 1..` because of return type @@ -139,7 +85,7 @@ LL | '3' found type `char` error[E0308]: mismatched types - --> $DIR/literals.rs:59:5 + --> $DIR/literals.rs:55:5 | LL | fn char_lit_in_range() -> pattern_type!(char is 'a'..'z') { | ------------------------------- expected `(char) is 'a'..='y'` because of return type @@ -150,7 +96,7 @@ LL | 'b' found type `char` error[E0308]: mismatched types - --> $DIR/literals.rs:64:5 + --> $DIR/literals.rs:60:5 | LL | fn char_lit_out_of_range() -> pattern_type!(char is 'a'..'z') { | ------------------------------- expected `(char) is 'a'..='y'` because of return type @@ -161,29 +107,7 @@ LL | 'A' found type `char` error[E0308]: mismatched types - --> $DIR/literals.rs:69:5 - | -LL | fn lit_at_unsigned_range_inclusive_end() -> pattern_type!(u32 is 0..=1) { - | --------------------------- expected `(u32) is 0..=1` because of return type -LL | 1 - | ^ expected `(u32) is 0..=1`, found integer - | - = note: expected pattern type `(u32) is 0..=1` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/literals.rs:74:5 - | -LL | fn single_element_range() -> pattern_type!(u32 is 0..=0) { - | --------------------------- expected `(u32) is 0..=0` because of return type -LL | 0 - | ^ expected `(u32) is 0..=0`, found integer - | - = note: expected pattern type `(u32) is 0..=0` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/literals.rs:79:5 + --> $DIR/literals.rs:73:5 | LL | fn lit_oob_single_element_range() -> pattern_type!(u32 is 0..=0) { | --------------------------- expected `(u32) is 0..=0` because of return type @@ -194,7 +118,7 @@ LL | 1 found type `{integer}` error[E0308]: mismatched types - --> $DIR/literals.rs:84:5 + --> $DIR/literals.rs:78:5 | LL | fn lit_oob_single_element_range_exclusive() -> pattern_type!(u32 is 0..1) { | -------------------------- expected `(u32) is 0..=0` because of return type @@ -204,19 +128,10 @@ LL | 1 = note: expected pattern type `(u32) is 0..=0` found type `{integer}` -error[E0308]: mismatched types - --> $DIR/literals.rs:89:5 - | -LL | fn single_element_range_exclusive() -> pattern_type!(u32 is 0..1) { - | -------------------------- expected `(u32) is 0..=0` because of return type -LL | 0 - | ^ expected `(u32) is 0..=0`, found integer - | - = note: expected pattern type `(u32) is 0..=0` - found type `{integer}` +error: pattern type ranges cannot wrap: 1..=0 error[E0308]: mismatched types - --> $DIR/literals.rs:104:5 + --> $DIR/literals.rs:97:5 | LL | fn empty_range() -> pattern_type!(u32 is 1..1) { | -------------------------- expected `(u32) is 1..=0` because of return type @@ -227,7 +142,7 @@ LL | 0 found type `{integer}` error[E0308]: mismatched types - --> $DIR/literals.rs:109:5 + --> $DIR/literals.rs:102:5 | LL | fn empty_range2() -> pattern_type!(u32 is 1..1) { | -------------------------- expected `(u32) is 1..=0` because of return type @@ -237,8 +152,10 @@ LL | 1 = note: expected pattern type `(u32) is 1..=0` found type `{integer}` +error: pattern type ranges cannot wrap: 2..=0 + error[E0308]: mismatched types - --> $DIR/literals.rs:129:5 + --> $DIR/literals.rs:122:5 | LL | fn wraparound_range() -> pattern_type!(u32 is 2..1) { | -------------------------- expected `(u32) is 2..=0` because of return type @@ -249,7 +166,7 @@ LL | 1 found type `{integer}` error[E0308]: mismatched types - --> $DIR/literals.rs:134:5 + --> $DIR/literals.rs:127:5 | LL | fn lit_in_wraparound_range() -> pattern_type!(u32 is 2..1) { | -------------------------- expected `(u32) is 2..=0` because of return type @@ -260,7 +177,7 @@ LL | 0 found type `{integer}` error[E0308]: mismatched types - --> $DIR/literals.rs:139:5 + --> $DIR/literals.rs:132:5 | LL | fn lit_at_wraparound_range_start() -> pattern_type!(u32 is 2..1) { | -------------------------- expected `(u32) is 2..=0` because of return type @@ -270,7 +187,7 @@ LL | 2 = note: expected pattern type `(u32) is 2..=0` found type `{integer}` -error: aborting due to 27 previous errors +error: aborting due to 22 previous errors -Some errors have detailed explanations: E0080, E0308. +Some errors have detailed explanations: E0080, E0308, E0600. For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/type/pattern_types/nested.rs b/tests/ui/type/pattern_types/nested.rs index 0d8cd22190e..fd950d73291 100644 --- a/tests/ui/type/pattern_types/nested.rs +++ b/tests/ui/type/pattern_types/nested.rs @@ -1,6 +1,6 @@ //! Check that pattern types can only have specific base types -#![feature(pattern_types)] +#![feature(pattern_types, const_trait_impl, pattern_type_range_trait)] #![feature(pattern_type_macro)] use std::pat::pattern_type; @@ -14,7 +14,7 @@ const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!(); // We want to get the most narrowest version that a pattern could be const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); //~^ ERROR: not a valid base type for range patterns -//~| ERROR: mismatched types +//~| ERROR: cannot apply unary operator `-` to type `(i32) is 1..` const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); //~^ ERROR: not a valid base type for range patterns diff --git a/tests/ui/type/pattern_types/nested.stderr b/tests/ui/type/pattern_types/nested.stderr index f79d12bc3f3..bb206d9db3d 100644 --- a/tests/ui/type/pattern_types/nested.stderr +++ b/tests/ui/type/pattern_types/nested.stderr @@ -43,14 +43,11 @@ LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = tod u128 and 5 others -error[E0308]: mismatched types +error[E0600]: cannot apply unary operator `-` to type `(i32) is 1..` --> $DIR/nested.rs:15:67 | LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); - | ^^ expected `(i32) is 1..`, found integer - | - = note: expected pattern type `(i32) is 1..` - found type `{integer}` + | ^^ cannot apply unary operator `-` error[E0277]: `(i32) is 1..` is not a valid base type for range patterns --> $DIR/nested.rs:19:35 @@ -180,5 +177,5 @@ LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!(); error: aborting due to 11 previous errors -Some errors have detailed explanations: E0277, E0308. +Some errors have detailed explanations: E0277, E0308, E0600. For more information about an error, try `rustc --explain E0277`.