Skip to content

Commit

Permalink
implement unstable new_range feature
Browse files Browse the repository at this point in the history
for RFC 3550, tracking issue rust-lang#123741
  • Loading branch information
pitaj committed Jan 31, 2025
1 parent e3a0a05 commit 262f124
Show file tree
Hide file tree
Showing 12 changed files with 204 additions and 8 deletions.
35 changes: 28 additions & 7 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Index(el, er, brackets_span) => {
hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span)
}
ExprKind::Range(Some(e1), Some(e2), RangeLimits::Closed) => {
self.lower_expr_range_closed(e.span, e1, e2)
}
ExprKind::Range(e1, e2, lims) => {
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
}
Expand Down Expand Up @@ -1508,15 +1505,39 @@ impl<'hir> LoweringContext<'_, 'hir> {

let lang_item = match (e1, e2, lims) {
(None, None, HalfOpen) => hir::LangItem::RangeFull,
(Some(..), None, HalfOpen) => hir::LangItem::RangeFrom,
(Some(..), None, HalfOpen) => {
if self.tcx.features().new_range() {
hir::LangItem::RangeFromCopy
} else {
hir::LangItem::RangeFrom
}
}
(None, Some(..), HalfOpen) => hir::LangItem::RangeTo,
(Some(..), Some(..), HalfOpen) => hir::LangItem::Range,
(Some(..), Some(..), HalfOpen) => {
if self.tcx.features().new_range() {
hir::LangItem::RangeCopy
} else {
hir::LangItem::Range
}
}
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
(Some(..), Some(..), Closed) => unreachable!(),
(Some(e1), Some(e2), Closed) => {
if self.tcx.features().new_range() {
hir::LangItem::RangeInclusiveCopy
} else {
return self.lower_expr_range_closed(span, e1, e2);
}
}
(start, None, Closed) => {
self.dcx().emit_err(InclusiveRangeWithNoEnd { span });
match start {
Some(..) => hir::LangItem::RangeFrom,
Some(..) => {
if self.tcx.features().new_range() {
hir::LangItem::RangeFromCopy
} else {
hir::LangItem::RangeFrom
}
}
None => hir::LangItem::RangeFull,
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ declare_features! (
(unstable, never_type, "1.13.0", Some(35121)),
/// Allows diverging expressions to fall back to `!` rather than `()`.
(unstable, never_type_fallback, "1.41.0", Some(65992)),
/// Switch `..` syntax to use the new (`Copy + IntoIterator`) range types.
(unstable, new_range, "CURRENT_RUSTC_VERSION", Some(123741)),
/// Allows `#![no_core]`.
(unstable, no_core, "1.3.0", Some(29639)),
/// Allows the use of `no_sanitize` attribute.
Expand Down
41 changes: 40 additions & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2316,6 +2316,18 @@ impl Expr<'_> {
[val2],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeFromCopy, _),
[val1],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeFromCopy, _),
[val2],
StructTailExpr::None,
),
) => val1.expr.equivalent_for_indexing(val2.expr),
(
ExprKind::Struct(
Expand All @@ -2328,6 +2340,30 @@ impl Expr<'_> {
[val2, val4],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeCopy, _),
[val1, val3],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeCopy, _),
[val2, val4],
StructTailExpr::None,
),
)
| (
ExprKind::Struct(
QPath::LangItem(LangItem::RangeInclusiveCopy, _),
[val1, val3],
StructTailExpr::None,
),
ExprKind::Struct(
QPath::LangItem(LangItem::RangeInclusiveCopy, _),
[val2, val4],
StructTailExpr::None,
),
) => {
val1.expr.equivalent_for_indexing(val2.expr)
&& val3.expr.equivalent_for_indexing(val4.expr)
Expand Down Expand Up @@ -2357,7 +2393,10 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
| LangItem::RangeTo
| LangItem::RangeFrom
| LangItem::RangeFull
| LangItem::RangeToInclusive,
| LangItem::RangeToInclusive
| LangItem::RangeCopy
| LangItem::RangeFromCopy
| LangItem::RangeInclusiveCopy,
..
)
),
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,11 @@ language_item_table! {
RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None;
RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None;

// `new_range` types that are `Copy + IntoIterator`
RangeFromCopy, sym::RangeFromCopy, range_from_copy_struct, Target::Struct, GenericRequirement::None;
RangeCopy, sym::RangeCopy, range_copy_struct, Target::Struct, GenericRequirement::None;
RangeInclusiveCopy, sym::RangeInclusiveCopy, range_inclusive_copy_struct, Target::Struct, GenericRequirement::None;

String, sym::String, string, Target::Struct, GenericRequirement::None;
CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2411,6 +2411,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let lang_item = match parent_expr.kind {
ExprKind::Struct(qpath, _, _) => match *qpath {
QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
QPath::LangItem(LangItem::RangeCopy, ..) => Some(LangItem::RangeCopy),
QPath::LangItem(LangItem::RangeInclusiveCopy, ..) => {
Some(LangItem::RangeInclusiveCopy)
}
QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
QPath::LangItem(LangItem::RangeToInclusive, ..) => {
Some(LangItem::RangeToInclusive)
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,12 @@ symbols! {
ProceduralMasqueradeDummyType,
Range,
RangeBounds,
RangeCopy,
RangeFrom,
RangeFromCopy,
RangeFull,
RangeInclusive,
RangeInclusiveCopy,
RangeTo,
RangeToInclusive,
Rc,
Expand Down Expand Up @@ -1367,6 +1370,7 @@ symbols! {
new_lower_hex,
new_octal,
new_pointer,
new_range,
new_unchecked,
new_upper_exp,
new_upper_hex,
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub use crate::ops::{Bound, OneSidedRange, RangeBounds, RangeFull, RangeTo, Rang
/// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 });
/// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum());
/// ```
#[cfg_attr(not(bootstrap), lang = "RangeCopy")]
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
#[unstable(feature = "new_range_api", issue = "125687")]
pub struct Range<Idx> {
Expand Down Expand Up @@ -205,6 +206,7 @@ impl<T> From<legacy::Range<T>> for Range<T> {
/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, end: 5 });
/// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum());
/// ```
#[cfg_attr(not(bootstrap), lang = "RangeInclusiveCopy")]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[unstable(feature = "new_range_api", issue = "125687")]
pub struct RangeInclusive<Idx> {
Expand Down Expand Up @@ -388,6 +390,7 @@ impl<T> From<legacy::RangeInclusive<T>> for RangeInclusive<T> {
/// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 });
/// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum());
/// ```
#[cfg_attr(not(bootstrap), lang = "RangeFromCopy")]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[unstable(feature = "new_range_api", issue = "125687")]
pub struct RangeFrom<Idx> {
Expand Down
9 changes: 9 additions & 0 deletions src/doc/unstable-book/src/language-features/new-range.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# `new_range`

The tracking issue for this feature is: [#123741]

[#123741]: https://github.com/rust-lang/rust/issues/123741

---

Switch the syntaxes `a..`, `a..b`, and `a..=b` to resolve the new range types.
10 changes: 10 additions & 0 deletions tests/ui/feature-gates/feature-gate-new_range.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![feature(new_range_api)]

fn main() {
let a: core::range::RangeFrom<u8> = 1..;
//~^ mismatched types
let b: core::range::Range<u8> = 2..3;
//~^ mismatched types
let c: core::range::RangeInclusive<u8> = 4..=5;
//~^ mismatched types
}
48 changes: 48 additions & 0 deletions tests/ui/feature-gates/feature-gate-new_range.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
error[E0308]: mismatched types
--> $DIR/feature-gate-new_range.rs:4:41
|
LL | let a: core::range::RangeFrom<u8> = 1..;
| -------------------------- ^^^ expected `RangeFrom<u8>`, found `RangeFrom<{integer}>`
| |
| expected due to this
|
= note: expected struct `std::range::RangeFrom<u8>`
found struct `std::ops::RangeFrom<{integer}>`
help: call `Into::into` on this expression to convert `std::ops::RangeFrom<{integer}>` into `std::range::RangeFrom<u8>`
|
LL | let a: core::range::RangeFrom<u8> = 1...into();
| +++++++

error[E0308]: mismatched types
--> $DIR/feature-gate-new_range.rs:6:37
|
LL | let b: core::range::Range<u8> = 2..3;
| ---------------------- ^^^^ expected `Range<u8>`, found `Range<{integer}>`
| |
| expected due to this
|
= note: expected struct `std::range::Range<u8>`
found struct `std::ops::Range<{integer}>`
help: call `Into::into` on this expression to convert `std::ops::Range<{integer}>` into `std::range::Range<u8>`
|
LL | let b: core::range::Range<u8> = 2..3.into();
| +++++++

error[E0308]: mismatched types
--> $DIR/feature-gate-new_range.rs:8:46
|
LL | let c: core::range::RangeInclusive<u8> = 4..=5;
| ------------------------------- ^^^^^ expected `RangeInclusive<u8>`, found `RangeInclusive<{integer}>`
| |
| expected due to this
|
= note: expected struct `std::range::RangeInclusive<u8>`
found struct `std::ops::RangeInclusive<{integer}>`
help: call `Into::into` on this expression to convert `std::ops::RangeInclusive<{integer}>` into `std::range::RangeInclusive<u8>`
|
LL | let c: core::range::RangeInclusive<u8> = 4..=5.into();
| +++++++

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0308`.
27 changes: 27 additions & 0 deletions tests/ui/new-range/disabled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//@ check-pass

#![feature(new_range_api)]

fn main() {
// Unchanged
let a: core::range::RangeFull = ..;
let b: core::range::RangeTo<u8> = ..2;
let c: core::range::RangeToInclusive<u8> = ..=3;

let _: core::ops::RangeFull = a;
let _: core::ops::RangeTo<u8> = b;
let _: core::ops::RangeToInclusive<u8> = c;

// Changed
let a: core::range::legacy::RangeFrom<u8> = 1..;
let b: core::range::legacy::Range<u8> = 2..3;
let c: core::range::legacy::RangeInclusive<u8> = 4..=5;

let a: core::ops::RangeFrom<u8> = a;
let b: core::ops::Range<u8> = b;
let c: core::ops::RangeInclusive<u8> = c;

let _: core::ops::RangeFrom<u8> = a.into_iter();
let _: core::ops::Range<u8> = b.into_iter();
let _: core::ops::RangeInclusive<u8> = c.into_iter();
}
24 changes: 24 additions & 0 deletions tests/ui/new-range/enabled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//@ check-pass

#![feature(new_range_api)]
#![feature(new_range)]

fn main() {
// Unchanged
let a: core::range::RangeFull = ..;
let b: core::range::RangeTo<u8> = ..2;
let c: core::range::RangeToInclusive<u8> = ..=3;

let _: core::ops::RangeFull = a;
let _: core::ops::RangeTo<u8> = b;
let _: core::ops::RangeToInclusive<u8> = c;

// Changed
let a: core::range::RangeFrom<u8> = 1..;
let b: core::range::Range<u8> = 2..3;
let c: core::range::RangeInclusive<u8> = 4..=5;

let _: core::range::IterRangeFrom<u8> = a.into_iter();
let _: core::range::IterRange<u8> = b.into_iter();
let _: core::range::IterRangeInclusive<u8> = c.into_iter();
}

0 comments on commit 262f124

Please sign in to comment.