Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #21460 from Veykril/push-vyqmuvkouywu
feat: Implement support for `feature(new_range)`
Lukas Wirth 3 months ago
parent eb05888 · parent 75b41dc · commit bb96978
-rw-r--r--crates/hir-def/src/lang_item.rs5
-rw-r--r--crates/hir-expand/src/mod_path.rs4
-rw-r--r--crates/hir-ty/src/infer.rs28
-rw-r--r--crates/hir-ty/src/tests/patterns.rs118
-rw-r--r--crates/hir-ty/src/tests/simple.rs41
-rw-r--r--crates/hir/src/source_analyzer.rs80
-rw-r--r--crates/intern/src/symbol/symbols.rs6
-rw-r--r--crates/test-utils/src/minicore.rs92
8 files changed, 246 insertions, 128 deletions
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index 092ff6e486..51dd55301f 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -499,6 +499,11 @@ language_item_table! { LangItems =>
RangeToInclusive, sym::RangeToInclusive, StructId;
RangeTo, sym::RangeTo, StructId;
+ RangeFromCopy, sym::RangeFromCopy, StructId;
+ RangeInclusiveCopy, sym::RangeInclusiveCopy, StructId;
+ RangeCopy, sym::RangeCopy, StructId;
+ RangeToInclusiveCopy, sym::RangeToInclusiveCopy, StructId;
+
String, sym::String, StructId;
CStr, sym::CStr, StructId;
Ordering, sym::Ordering, EnumId;
diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs
index 1712c28aa8..78228cf82e 100644
--- a/crates/hir-expand/src/mod_path.rs
+++ b/crates/hir-expand/src/mod_path.rs
@@ -423,6 +423,10 @@ macro_rules! __known_path {
(core::ops::RangeTo) => {};
(core::ops::RangeToInclusive) => {};
(core::ops::RangeInclusive) => {};
+ (core::range::Range) => {};
+ (core::range::RangeFrom) => {};
+ (core::range::RangeInclusive) => {};
+ (core::range::RangeToInclusive) => {};
(core::future::Future) => {};
(core::future::IntoFuture) => {};
(core::fmt::Debug) => {};
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index d527a4ae29..35d744e7d1 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -1815,18 +1815,34 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
Some(struct_.into())
}
+ fn has_new_range_feature(&self) -> bool {
+ self.resolver.top_level_def_map().is_unstable_feature_enabled(&sym::new_range)
+ }
+
fn resolve_range(&self) -> Option<AdtId> {
- let struct_ = self.lang_items.Range?;
+ let struct_ = if self.has_new_range_feature() {
+ self.lang_items.RangeCopy?
+ } else {
+ self.lang_items.Range?
+ };
Some(struct_.into())
}
fn resolve_range_inclusive(&self) -> Option<AdtId> {
- let struct_ = self.lang_items.RangeInclusiveStruct?;
+ let struct_ = if self.has_new_range_feature() {
+ self.lang_items.RangeInclusiveCopy?
+ } else {
+ self.lang_items.RangeInclusiveStruct?
+ };
Some(struct_.into())
}
fn resolve_range_from(&self) -> Option<AdtId> {
- let struct_ = self.lang_items.RangeFrom?;
+ let struct_ = if self.has_new_range_feature() {
+ self.lang_items.RangeFromCopy?
+ } else {
+ self.lang_items.RangeFrom?
+ };
Some(struct_.into())
}
@@ -1836,7 +1852,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
}
fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
- let struct_ = self.lang_items.RangeToInclusive?;
+ let struct_ = if self.has_new_range_feature() {
+ self.lang_items.RangeToInclusiveCopy?
+ } else {
+ self.lang_items.RangeToInclusive?
+ };
Some(struct_.into())
}
diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs
index 0b776938c5..8c7d29f993 100644
--- a/crates/hir-ty/src/tests/patterns.rs
+++ b/crates/hir-ty/src/tests/patterns.rs
@@ -13,11 +13,11 @@ fn infer_pattern() {
let a = z;
let (c, d) = (1, "hello");
- for (e, f) in some_iter {
+ for (e, f) in [(0, 1)] {
let g = e;
}
- if let [val] = opt {
+ if let [val] = [y] {
let h = val;
}
@@ -33,7 +33,7 @@ fn infer_pattern() {
"#,
expect![[r#"
8..9 'x': &'? i32
- 17..400 '{ ...o_x; }': ()
+ 17..399 '{ ...o_x; }': ()
27..28 'y': &'? i32
31..32 'x': &'? i32
42..44 '&z': &'? i32
@@ -47,58 +47,62 @@ fn infer_pattern() {
82..94 '(1, "hello")': (i32, &'? str)
83..84 '1': i32
86..93 '"hello"': &'static str
- 101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
- 101..151 'for (e... }': <{unknown} as IntoIterator>::IntoIter
- 101..151 'for (e... }': !
- 101..151 'for (e... }': {unknown}
- 101..151 'for (e... }': &'? mut {unknown}
- 101..151 'for (e... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
- 101..151 'for (e... }': Option<<{unknown} as Iterator>::Item>
- 101..151 'for (e... }': ()
- 101..151 'for (e... }': ()
- 101..151 'for (e... }': ()
- 101..151 'for (e... }': ()
- 105..111 '(e, f)': ({unknown}, {unknown})
- 106..107 'e': {unknown}
- 109..110 'f': {unknown}
- 115..124 'some_iter': {unknown}
- 125..151 '{ ... }': ()
- 139..140 'g': {unknown}
- 143..144 'e': {unknown}
- 157..204 'if let... }': ()
- 160..175 'let [val] = opt': bool
- 164..169 '[val]': [{unknown}]
- 165..168 'val': {unknown}
- 172..175 'opt': [{unknown}]
- 176..204 '{ ... }': ()
- 190..191 'h': {unknown}
- 194..197 'val': {unknown}
- 210..236 'if let...rue {}': ()
- 213..233 'let x ... &true': bool
- 217..225 'x @ true': &'? bool
- 221..225 'true': bool
- 221..225 'true': bool
- 228..233 '&true': &'? bool
- 229..233 'true': bool
- 234..236 '{}': ()
- 246..252 'lambda': impl Fn(u64, u64, i32) -> i32
- 255..287 '|a: u6...b; c }': impl Fn(u64, u64, i32) -> i32
- 256..257 'a': u64
- 264..265 'b': u64
- 267..268 'c': i32
- 275..287 '{ a + b; c }': i32
- 277..278 'a': u64
- 277..282 'a + b': u64
- 281..282 'b': u64
- 284..285 'c': i32
- 298..310 'ref ref_to_x': &'? &'? i32
- 313..314 'x': &'? i32
- 324..333 'mut mut_x': &'? i32
- 336..337 'x': &'? i32
- 347..367 'ref mu...f_to_x': &'? mut &'? i32
- 370..371 'x': &'? i32
- 381..382 'k': &'? mut &'? i32
- 385..397 'mut_ref_to_x': &'? mut &'? i32
+ 101..150 'for (e... }': fn into_iter<[(i32, i32); 1]>([(i32, i32); 1]) -> <[(i32, i32); 1] as IntoIterator>::IntoIter
+ 101..150 'for (e... }': IntoIter<(i32, i32), 1>
+ 101..150 'for (e... }': !
+ 101..150 'for (e... }': IntoIter<(i32, i32), 1>
+ 101..150 'for (e... }': &'? mut IntoIter<(i32, i32), 1>
+ 101..150 'for (e... }': fn next<IntoIter<(i32, i32), 1>>(&'? mut IntoIter<(i32, i32), 1>) -> Option<<IntoIter<(i32, i32), 1> as Iterator>::Item>
+ 101..150 'for (e... }': Option<(i32, i32)>
+ 101..150 'for (e... }': ()
+ 101..150 'for (e... }': ()
+ 101..150 'for (e... }': ()
+ 101..150 'for (e... }': ()
+ 105..111 '(e, f)': (i32, i32)
+ 106..107 'e': i32
+ 109..110 'f': i32
+ 115..123 '[(0, 1)]': [(i32, i32); 1]
+ 116..122 '(0, 1)': (i32, i32)
+ 117..118 '0': i32
+ 120..121 '1': i32
+ 124..150 '{ ... }': ()
+ 138..139 'g': i32
+ 142..143 'e': i32
+ 156..203 'if let... }': ()
+ 159..174 'let [val] = [y]': bool
+ 163..168 '[val]': [&'? i32; 1]
+ 164..167 'val': &'? i32
+ 171..174 '[y]': [&'? i32; 1]
+ 172..173 'y': &'? i32
+ 175..203 '{ ... }': ()
+ 189..190 'h': &'? i32
+ 193..196 'val': &'? i32
+ 209..235 'if let...rue {}': ()
+ 212..232 'let x ... &true': bool
+ 216..224 'x @ true': &'? bool
+ 220..224 'true': bool
+ 220..224 'true': bool
+ 227..232 '&true': &'? bool
+ 228..232 'true': bool
+ 233..235 '{}': ()
+ 245..251 'lambda': impl Fn(u64, u64, i32) -> i32
+ 254..286 '|a: u6...b; c }': impl Fn(u64, u64, i32) -> i32
+ 255..256 'a': u64
+ 263..264 'b': u64
+ 266..267 'c': i32
+ 274..286 '{ a + b; c }': i32
+ 276..277 'a': u64
+ 276..281 'a + b': u64
+ 280..281 'b': u64
+ 283..284 'c': i32
+ 297..309 'ref ref_to_x': &'? &'? i32
+ 312..313 'x': &'? i32
+ 323..332 'mut mut_x': &'? i32
+ 335..336 'x': &'? i32
+ 346..366 'ref mu...f_to_x': &'? mut &'? i32
+ 369..370 'x': &'? i32
+ 380..381 'k': &'? mut &'? i32
+ 384..396 'mut_ref_to_x': &'? mut &'? i32
"#]],
);
}
@@ -380,7 +384,7 @@ fn infer_pattern_match_string_literal() {
fn infer_pattern_match_byte_string_literal() {
check_infer_with_mismatches(
r#"
- //- minicore: index
+ //- minicore: index, range
struct S;
impl<T, const N: usize> core::ops::Index<S> for [T; N] {
type Output = [u8];
@@ -395,7 +399,7 @@ fn infer_pattern_match_byte_string_literal() {
"#,
expect![[r#"
105..109 'self': &'? [T; N]
- 111..116 'index': {unknown}
+ 111..116 'index': RangeFull
157..180 '{ ... }': &'? [u8]
167..174 'loop {}': !
172..174 '{}': ()
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 44450939a6..98503452d3 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -64,20 +64,37 @@ fn type_alias_in_struct_lit() {
#[test]
fn infer_ranges() {
- check_types(
+ check_no_mismatches(
r#"
-//- minicore: range
+//- minicore: range, new_range
+
fn test() {
- let a = ..;
- let b = 1..;
- let c = ..2u32;
- let d = 1..2usize;
- let e = ..=10;
- let f = 'a'..='z';
-
- let t = (a, b, c, d, e, f);
- t;
-} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)
+ let _: core::ops::RangeFull = ..;
+ let _: core::ops::RangeFrom<i32> = 1..;
+ let _: core::ops::RangeTo<u32> = ..2u32;
+ let _: core::ops::Range<usize> = 1..2usize;
+ let _: core::ops::RangeToInclusive<i32> = ..=10;
+ let _: core::ops::RangeInclusive<char> = 'a'..='z';
+}
+"#,
+ );
+}
+
+#[test]
+fn infer_ranges_new_range() {
+ check_no_mismatches(
+ r#"
+//- minicore: range, new_range
+#![feature(new_range)]
+
+fn test() {
+ let _: core::ops::RangeFull = ..;
+ let _: core::range::RangeFrom<i32> = 1..;
+ let _: core::ops::RangeTo<u32> = ..2u32;
+ let _: core::range::Range<usize> = 1..2usize;
+ let _: core::range::RangeToInclusive<i32> = ..=10;
+ let _: core::range::RangeInclusive<char> = 'a'..='z';
+}
"#,
);
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 4e85e299a9..c6f2d151f5 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -532,18 +532,12 @@ impl<'db> SourceAnalyzer<'db> {
db: &'db dyn HirDatabase,
range_pat: &ast::RangePat,
) -> Option<StructId> {
- let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) {
- (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
- (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
- (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
- (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
- (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
-
- (RangeOp::Exclusive, None, None) => return None,
- (RangeOp::Inclusive, None, None) => return None,
- (RangeOp::Inclusive, Some(_), None) => return None,
- };
- self.resolver.resolve_known_struct(db, &path)
+ self.resolve_range_struct(
+ db,
+ range_pat.op_kind()?,
+ range_pat.start().is_some(),
+ range_pat.end().is_some(),
+ )
}
pub(crate) fn resolve_range_expr(
@@ -551,19 +545,59 @@ impl<'db> SourceAnalyzer<'db> {
db: &'db dyn HirDatabase,
range_expr: &ast::RangeExpr,
) -> Option<StructId> {
- let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) {
- (RangeOp::Exclusive, None, None) => path![core::ops::RangeFull],
- (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
- (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
- (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
- (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
- (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
+ self.resolve_range_struct(
+ db,
+ range_expr.op_kind()?,
+ range_expr.start().is_some(),
+ range_expr.end().is_some(),
+ )
+ }
+ fn resolve_range_struct(
+ &self,
+ db: &'db dyn HirDatabase,
+ op_kind: RangeOp,
+ has_start: bool,
+ has_end: bool,
+ ) -> Option<StructId> {
+ let has_new_range =
+ self.resolver.top_level_def_map().is_unstable_feature_enabled(&sym::new_range);
+ let lang_items = self.lang_items(db);
+ match (op_kind, has_start, has_end) {
+ (RangeOp::Exclusive, false, false) => lang_items.RangeFull,
+ (RangeOp::Exclusive, false, true) => lang_items.RangeTo,
+ (RangeOp::Exclusive, true, false) => {
+ if has_new_range {
+ lang_items.RangeFromCopy
+ } else {
+ lang_items.RangeFrom
+ }
+ }
+ (RangeOp::Exclusive, true, true) => {
+ if has_new_range {
+ lang_items.RangeCopy
+ } else {
+ lang_items.Range
+ }
+ }
+ (RangeOp::Inclusive, false, true) => {
+ if has_new_range {
+ lang_items.RangeToInclusiveCopy
+ } else {
+ lang_items.RangeToInclusive
+ }
+ }
+ (RangeOp::Inclusive, true, true) => {
+ if has_new_range {
+ lang_items.RangeInclusiveCopy
+ } else {
+ lang_items.RangeInclusiveStruct
+ }
+ }
// [E0586] inclusive ranges must be bounded at the end
- (RangeOp::Inclusive, None, None) => return None,
- (RangeOp::Inclusive, Some(_), None) => return None,
- };
- self.resolver.resolve_known_struct(db, &path)
+ (RangeOp::Inclusive, false, false) => None,
+ (RangeOp::Inclusive, true, false) => None,
+ }
}
pub(crate) fn resolve_await_to_poll(
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index df4f7aa972..2be4e41f4f 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -526,6 +526,12 @@ define_symbols! {
arbitrary_self_types,
arbitrary_self_types_pointers,
supertrait_item_shadowing,
+ new_range,
+ range,
+ RangeCopy,
+ RangeFromCopy,
+ RangeInclusiveCopy,
+ RangeToInclusiveCopy,
hash,
partial_cmp,
cmp,
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index b96b936583..48c3e89525 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -58,6 +58,7 @@
//! pin:
//! pointee: copy, send, sync, ord, hash, unpin, phantom_data
//! range:
+//! new_range:
//! receiver: deref
//! result:
//! send: sized
@@ -175,7 +176,9 @@ pub mod marker {
// region:clone
impl<T: PointeeSized> Clone for PhantomData<T> {
- fn clone(&self) -> Self { Self }
+ fn clone(&self) -> Self {
+ Self
+ }
}
// endregion:clone
@@ -1128,6 +1131,32 @@ pub mod ops {
// endregion:dispatch_from_dyn
}
+// region:new_range
+pub mod range {
+ #[lang = "RangeCopy"]
+ pub struct Range<Idx> {
+ pub start: Idx,
+ pub end: Idx,
+ }
+
+ #[lang = "RangeFromCopy"]
+ pub struct RangeFrom<Idx> {
+ pub start: Idx,
+ }
+
+ #[lang = "RangeInclusiveCopy"]
+ pub struct RangeInclusive<Idx> {
+ pub start: Idx,
+ pub end: Idx,
+ }
+
+ #[lang = "RangeToInclusiveCopy"]
+ pub struct RangeToInclusive<Idx> {
+ pub end: Idx,
+ }
+}
+// endregion:new_range
+
// region:eq
pub mod cmp {
use crate::marker::PointeeSized;
@@ -1144,7 +1173,9 @@ pub mod cmp {
// region:builtin_impls
impl PartialEq for () {
- fn eq(&self, other: &()) -> bool { true }
+ fn eq(&self, other: &()) -> bool {
+ true
+ }
}
// endregion:builtin_impls
@@ -1567,10 +1598,7 @@ pub mod pin {
}
// endregion:dispatch_from_dyn
// region:coerce_unsized
- impl<Ptr, U> crate::ops::CoerceUnsized<Pin<U>> for Pin<Ptr> where
- Ptr: crate::ops::CoerceUnsized<U>
- {
- }
+ impl<Ptr, U> crate::ops::CoerceUnsized<Pin<U>> for Pin<Ptr> where Ptr: crate::ops::CoerceUnsized<U> {}
// endregion:coerce_unsized
}
// endregion:pin
@@ -1792,9 +1820,9 @@ pub mod iter {
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
}
}
- pub use self::collect::{IntoIterator, FromIterator};
+ pub use self::collect::{FromIterator, IntoIterator};
}
- pub use self::traits::{IntoIterator, FromIterator, Iterator};
+ pub use self::traits::{FromIterator, IntoIterator, Iterator};
}
// endregion:iterator
@@ -2091,30 +2119,30 @@ macro_rules! column {
pub mod prelude {
pub mod v1 {
pub use crate::{
- clone::Clone, // :clone
- cmp::{Eq, PartialEq}, // :eq
- cmp::{Ord, PartialOrd}, // :ord
- convert::AsMut, // :as_mut
- convert::AsRef, // :as_ref
- convert::{From, Into, TryFrom, TryInto}, // :from
- default::Default, // :default
- iter::{IntoIterator, Iterator, FromIterator}, // :iterator
- macros::builtin::{derive, derive_const}, // :derive
- marker::Copy, // :copy
- marker::Send, // :send
- marker::Sized, // :sized
- marker::Sync, // :sync
- mem::drop, // :drop
- mem::size_of, // :size_of
- ops::Drop, // :drop
- ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}, // :async_fn
- ops::{Fn, FnMut, FnOnce}, // :fn
- option::Option::{self, None, Some}, // :option
- panic, // :panic
- result::Result::{self, Err, Ok}, // :result
- str::FromStr, // :str
- fmt::derive::Debug, // :fmt, derive
- hash::derive::Hash, // :hash, derive
+ clone::Clone, // :clone
+ cmp::{Eq, PartialEq}, // :eq
+ cmp::{Ord, PartialOrd}, // :ord
+ convert::AsMut, // :as_mut
+ convert::AsRef, // :as_ref
+ convert::{From, Into, TryFrom, TryInto}, // :from
+ default::Default, // :default
+ fmt::derive::Debug, // :fmt, derive
+ hash::derive::Hash, // :hash, derive
+ iter::{FromIterator, IntoIterator, Iterator}, // :iterator
+ macros::builtin::{derive, derive_const}, // :derive
+ marker::Copy, // :copy
+ marker::Send, // :send
+ marker::Sized, // :sized
+ marker::Sync, // :sync
+ mem::drop, // :drop
+ mem::size_of, // :size_of
+ ops::Drop, // :drop
+ ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}, // :async_fn
+ ops::{Fn, FnMut, FnOnce}, // :fn
+ option::Option::{self, None, Some}, // :option
+ panic, // :panic
+ result::Result::{self, Err, Ok}, // :result
+ str::FromStr, // :str
};
}