diff options
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir_def/src/expr.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 30 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/name.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 39 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 50 |
7 files changed, 185 insertions, 1 deletions
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 331736cb2..be1eaa523 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -429,10 +429,19 @@ where | |||
429 | let index = self.collect_expr_opt(e.index()); | 429 | let index = self.collect_expr_opt(e.index()); |
430 | self.alloc_expr(Expr::Index { base, index }, syntax_ptr) | 430 | self.alloc_expr(Expr::Index { base, index }, syntax_ptr) |
431 | } | 431 | } |
432 | ast::Expr::RangeExpr(e) => { | ||
433 | let lhs = e.start().map(|lhs| self.collect_expr(lhs)); | ||
434 | let rhs = e.end().map(|rhs| self.collect_expr(rhs)); | ||
435 | match e.op_kind() { | ||
436 | Some(range_type) => { | ||
437 | self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr) | ||
438 | } | ||
439 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
440 | } | ||
441 | } | ||
432 | 442 | ||
433 | // FIXME implement HIR for these: | 443 | // FIXME implement HIR for these: |
434 | ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | 444 | ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), |
435 | ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
436 | ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) { | 445 | ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) { |
437 | Some((mark, expansion)) => { | 446 | Some((mark, expansion)) => { |
438 | let id = self.collect_expr(expansion); | 447 | let id = self.collect_expr(expansion); |
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index 04c1d8f69..6fad80a8d 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
16 | use ra_arena::{impl_arena_id, RawId}; | 16 | use ra_arena::{impl_arena_id, RawId}; |
17 | use ra_syntax::ast::RangeOp; | ||
17 | 18 | ||
18 | use crate::{ | 19 | use crate::{ |
19 | builtin_type::{BuiltinFloat, BuiltinInt}, | 20 | builtin_type::{BuiltinFloat, BuiltinInt}, |
@@ -130,6 +131,11 @@ pub enum Expr { | |||
130 | rhs: ExprId, | 131 | rhs: ExprId, |
131 | op: Option<BinaryOp>, | 132 | op: Option<BinaryOp>, |
132 | }, | 133 | }, |
134 | Range { | ||
135 | lhs: Option<ExprId>, | ||
136 | rhs: Option<ExprId>, | ||
137 | range_type: RangeOp, | ||
138 | }, | ||
133 | Index { | 139 | Index { |
134 | base: ExprId, | 140 | base: ExprId, |
135 | index: ExprId, | 141 | index: ExprId, |
@@ -288,6 +294,14 @@ impl Expr { | |||
288 | f(*lhs); | 294 | f(*lhs); |
289 | f(*rhs); | 295 | f(*rhs); |
290 | } | 296 | } |
297 | Expr::Range { lhs, rhs, .. } => { | ||
298 | if let Some(lhs) = rhs { | ||
299 | f(*lhs); | ||
300 | } | ||
301 | if let Some(rhs) = lhs { | ||
302 | f(*rhs); | ||
303 | } | ||
304 | } | ||
291 | Expr::Index { base, index } => { | 305 | Expr::Index { base, index } => { |
292 | f(*base); | 306 | f(*base); |
293 | f(*index); | 307 | f(*index); |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 10688df4d..ff252fe44 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -409,6 +409,36 @@ pub mod known { | |||
409 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE]) | 409 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE]) |
410 | } | 410 | } |
411 | 411 | ||
412 | pub fn std_ops_range() -> Path { | ||
413 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_TYPE]) | ||
414 | } | ||
415 | |||
416 | pub fn std_ops_range_from() -> Path { | ||
417 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_FROM_TYPE]) | ||
418 | } | ||
419 | |||
420 | pub fn std_ops_range_full() -> Path { | ||
421 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_FULL_TYPE]) | ||
422 | } | ||
423 | |||
424 | pub fn std_ops_range_inclusive() -> Path { | ||
425 | Path::from_simple_segments( | ||
426 | PathKind::Abs, | ||
427 | vec![name::STD, name::OPS, name::RANGE_INCLUSIVE_TYPE], | ||
428 | ) | ||
429 | } | ||
430 | |||
431 | pub fn std_ops_range_to() -> Path { | ||
432 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::RANGE_TO_TYPE]) | ||
433 | } | ||
434 | |||
435 | pub fn std_ops_range_to_inclusive() -> Path { | ||
436 | Path::from_simple_segments( | ||
437 | PathKind::Abs, | ||
438 | vec![name::STD, name::OPS, name::RANGE_TO_INCLUSIVE_TYPE], | ||
439 | ) | ||
440 | } | ||
441 | |||
412 | pub fn std_result_result() -> Path { | 442 | pub fn std_result_result() -> Path { |
413 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) | 443 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) |
414 | } | 444 | } |
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index 7824489d7..05ba37070 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs | |||
@@ -140,6 +140,12 @@ pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result"); | |||
140 | pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); | 140 | pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); |
141 | pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); | 141 | pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); |
142 | pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); | 142 | pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); |
143 | pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(9, b"RangeFrom"); | ||
144 | pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(9, b"RangeFull"); | ||
145 | pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(14, b"RangeInclusive"); | ||
146 | pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(16, b"RangeToInclusive"); | ||
147 | pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(7, b"RangeTo"); | ||
148 | pub const RANGE_TYPE: Name = Name::new_inline_ascii(5, b"Range"); | ||
143 | 149 | ||
144 | // Builtin Macros | 150 | // Builtin Macros |
145 | pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file"); | 151 | pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file"); |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index f6283ab6d..fe259371f 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -577,6 +577,42 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
577 | let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; | 577 | let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; |
578 | Some(struct_.into()) | 578 | Some(struct_.into()) |
579 | } | 579 | } |
580 | |||
581 | fn resolve_range_full(&self) -> Option<AdtId> { | ||
582 | let path = known::std_ops_range_full(); | ||
583 | let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; | ||
584 | Some(struct_.into()) | ||
585 | } | ||
586 | |||
587 | fn resolve_range(&self) -> Option<AdtId> { | ||
588 | let path = known::std_ops_range(); | ||
589 | let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; | ||
590 | Some(struct_.into()) | ||
591 | } | ||
592 | |||
593 | fn resolve_range_inclusive(&self) -> Option<AdtId> { | ||
594 | let path = known::std_ops_range_inclusive(); | ||
595 | let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; | ||
596 | Some(struct_.into()) | ||
597 | } | ||
598 | |||
599 | fn resolve_range_from(&self) -> Option<AdtId> { | ||
600 | let path = known::std_ops_range_from(); | ||
601 | let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; | ||
602 | Some(struct_.into()) | ||
603 | } | ||
604 | |||
605 | fn resolve_range_to(&self) -> Option<AdtId> { | ||
606 | let path = known::std_ops_range_to(); | ||
607 | let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; | ||
608 | Some(struct_.into()) | ||
609 | } | ||
610 | |||
611 | fn resolve_range_to_inclusive(&self) -> Option<AdtId> { | ||
612 | let path = known::std_ops_range_to_inclusive(); | ||
613 | let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; | ||
614 | Some(struct_.into()) | ||
615 | } | ||
580 | } | 616 | } |
581 | 617 | ||
582 | /// The ID of a type variable. | 618 | /// The ID of a type variable. |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 2f9ca4bbb..4014f4732 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -12,6 +12,7 @@ use hir_def::{ | |||
12 | AdtId, ContainerId, Lookup, StructFieldId, | 12 | AdtId, ContainerId, Lookup, StructFieldId, |
13 | }; | 13 | }; |
14 | use hir_expand::name::{self, Name}; | 14 | use hir_expand::name::{self, Name}; |
15 | use ra_syntax::ast::RangeOp; | ||
15 | 16 | ||
16 | use crate::{ | 17 | use crate::{ |
17 | autoderef, db::HirDatabase, method_resolution, op, traits::InEnvironment, utils::variant_data, | 18 | autoderef, db::HirDatabase, method_resolution, op, traits::InEnvironment, utils::variant_data, |
@@ -415,6 +416,44 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
415 | } | 416 | } |
416 | _ => Ty::Unknown, | 417 | _ => Ty::Unknown, |
417 | }, | 418 | }, |
419 | Expr::Range { lhs, rhs, range_type } => { | ||
420 | let lhs_ty = lhs.map(|e| self.infer_expr(e, &Expectation::none())); | ||
421 | let rhs_expect = lhs_ty | ||
422 | .as_ref() | ||
423 | .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone())); | ||
424 | let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); | ||
425 | match (range_type, lhs_ty, rhs_ty) { | ||
426 | (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { | ||
427 | Some(adt) => Ty::simple(TypeCtor::Adt(adt)), | ||
428 | None => Ty::Unknown, | ||
429 | }, | ||
430 | (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { | ||
431 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
432 | None => Ty::Unknown, | ||
433 | }, | ||
434 | (RangeOp::Inclusive, None, Some(ty)) => { | ||
435 | match self.resolve_range_to_inclusive() { | ||
436 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
437 | None => Ty::Unknown, | ||
438 | } | ||
439 | } | ||
440 | (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { | ||
441 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
442 | None => Ty::Unknown, | ||
443 | }, | ||
444 | (RangeOp::Inclusive, Some(_), Some(ty)) => { | ||
445 | match self.resolve_range_inclusive() { | ||
446 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
447 | None => Ty::Unknown, | ||
448 | } | ||
449 | } | ||
450 | (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { | ||
451 | Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), | ||
452 | None => Ty::Unknown, | ||
453 | }, | ||
454 | (RangeOp::Inclusive, _, None) => Ty::Unknown, | ||
455 | } | ||
456 | } | ||
418 | Expr::Index { base, index } => { | 457 | Expr::Index { base, index } => { |
419 | let _base_ty = self.infer_expr(*base, &Expectation::none()); | 458 | let _base_ty = self.infer_expr(*base, &Expectation::none()); |
420 | let _index_ty = self.infer_expr(*index, &Expectation::none()); | 459 | let _index_ty = self.infer_expr(*index, &Expectation::none()); |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index abbc1546c..4ba87e667 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -222,6 +222,56 @@ mod collections { | |||
222 | } | 222 | } |
223 | 223 | ||
224 | #[test] | 224 | #[test] |
225 | fn infer_ranges() { | ||
226 | let (db, pos) = TestDB::with_position( | ||
227 | r#" | ||
228 | //- /main.rs crate:main deps:std | ||
229 | fn test() { | ||
230 | let a = ..; | ||
231 | let b = 1..; | ||
232 | let c = ..2u32; | ||
233 | let d = 1..2usize; | ||
234 | let e = ..=10; | ||
235 | let f = 'a'..='z'; | ||
236 | |||
237 | let t = (a, b, c, d, e, f); | ||
238 | t<|>; | ||
239 | } | ||
240 | |||
241 | //- /std.rs crate:std | ||
242 | #[prelude_import] use prelude::*; | ||
243 | mod prelude {} | ||
244 | |||
245 | pub mod ops { | ||
246 | pub struct Range<Idx> { | ||
247 | pub start: Idx, | ||
248 | pub end: Idx, | ||
249 | } | ||
250 | pub struct RangeFrom<Idx> { | ||
251 | pub start: Idx, | ||
252 | } | ||
253 | struct RangeFull; | ||
254 | pub struct RangeInclusive<Idx> { | ||
255 | start: Idx, | ||
256 | end: Idx, | ||
257 | is_empty: u8, | ||
258 | } | ||
259 | pub struct RangeTo<Idx> { | ||
260 | pub end: Idx, | ||
261 | } | ||
262 | pub struct RangeToInclusive<Idx> { | ||
263 | pub end: Idx, | ||
264 | } | ||
265 | } | ||
266 | "#, | ||
267 | ); | ||
268 | assert_eq!( | ||
269 | "(RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)", | ||
270 | type_at_pos(&db, pos), | ||
271 | ); | ||
272 | } | ||
273 | |||
274 | #[test] | ||
225 | fn infer_while_let() { | 275 | fn infer_while_let() { |
226 | let (db, pos) = TestDB::with_position( | 276 | let (db, pos) = TestDB::with_position( |
227 | r#" | 277 | r#" |