diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 092ff6e48671..51dd55301f44 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 1712c28aa8ab..78228cf82e67 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index d527a4ae29c2..35d744e7d16b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/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 { - 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 { - 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 { - 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 { - 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/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 0b776938c5b3..8c7d29f99371 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/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>(&'? mut IntoIter<(i32, i32), 1>) -> Option< 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 core::ops::Index 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/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 44450939a66d..98503452d348 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/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 -fn test() { - let a = ..; - let b = 1..; - let c = ..2u32; - let d = 1..2usize; - let e = ..=10; - let f = 'a'..='z'; +//- minicore: range, new_range - let t = (a, b, c, d, e, f); - t; -} //^ (RangeFull, RangeFrom, RangeTo, Range, RangeToInclusive, RangeInclusive) +fn test() { + let _: core::ops::RangeFull = ..; + let _: core::ops::RangeFrom = 1..; + let _: core::ops::RangeTo = ..2u32; + let _: core::ops::Range = 1..2usize; + let _: core::ops::RangeToInclusive = ..=10; + let _: core::ops::RangeInclusive = '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 = 1..; + let _: core::ops::RangeTo = ..2u32; + let _: core::range::Range = 1..2usize; + let _: core::range::RangeToInclusive = ..=10; + let _: core::range::RangeInclusive = 'a'..='z'; +} "#, ); } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 4e85e299a97f..c6f2d151f582 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -532,18 +532,12 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, range_pat: &ast::RangePat, ) -> Option { - 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 { - 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 { + 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/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index df4f7aa9729e..2be4e41f4f1a 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index b96b93658369..48c3e8952507 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/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 Clone for PhantomData { - 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 { + pub start: Idx, + pub end: Idx, + } + + #[lang = "RangeFromCopy"] + pub struct RangeFrom { + pub start: Idx, + } + + #[lang = "RangeInclusiveCopy"] + pub struct RangeInclusive { + pub start: Idx, + pub end: Idx, + } + + #[lang = "RangeToInclusiveCopy"] + pub struct RangeToInclusive { + 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 crate::ops::CoerceUnsized> for Pin where - Ptr: crate::ops::CoerceUnsized - { - } + impl crate::ops::CoerceUnsized> for Pin where Ptr: crate::ops::CoerceUnsized {} // endregion:coerce_unsized } // endregion:pin @@ -1792,9 +1820,9 @@ pub mod iter { fn from_iter>(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 }; }