aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-11-29 19:34:02 +0000
committerGitHub <[email protected]>2019-11-29 19:34:02 +0000
commit10c8e5eecb97f8f89e599d27df658cbcc3015c8e (patch)
treef93ef014cc82793949e8567634cec341ffc58d62
parent8b278b1ab660df0728508e45e88ac769a2e03a58 (diff)
parent2cb684bbce1c487b2efb5a8154afe66e4907ceac (diff)
Merge #2445
2445: Infer range types r=flodiebold a=oxalica Co-authored-by: oxalica <[email protected]>
-rw-r--r--crates/ra_hir_def/src/body/lower.rs11
-rw-r--r--crates/ra_hir_def/src/expr.rs14
-rw-r--r--crates/ra_hir_def/src/path.rs30
-rw-r--r--crates/ra_hir_expand/src/name.rs6
-rw-r--r--crates/ra_hir_ty/src/infer.rs36
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs39
-rw-r--r--crates/ra_hir_ty/src/tests.rs50
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
15use hir_expand::name::Name; 15use hir_expand::name::Name;
16use ra_arena::{impl_arena_id, RawId}; 16use ra_arena::{impl_arena_id, RawId};
17use ra_syntax::ast::RangeOp;
17 18
18use crate::{ 19use 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");
140pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); 140pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output");
141pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); 141pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target");
142pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); 142pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box");
143pub const RANGE_FROM_TYPE: Name = Name::new_inline_ascii(9, b"RangeFrom");
144pub const RANGE_FULL_TYPE: Name = Name::new_inline_ascii(9, b"RangeFull");
145pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(14, b"RangeInclusive");
146pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(16, b"RangeToInclusive");
147pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(7, b"RangeTo");
148pub const RANGE_TYPE: Name = Name::new_inline_ascii(5, b"Range");
143 149
144// Builtin Macros 150// Builtin Macros
145pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file"); 151pub 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};
14use hir_expand::name::{self, Name}; 14use hir_expand::name::{self, Name};
15use ra_syntax::ast::RangeOp;
15 16
16use crate::{ 17use 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]
225fn infer_ranges() {
226 let (db, pos) = TestDB::with_position(
227 r#"
228//- /main.rs crate:main deps:std
229fn 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::*;
243mod prelude {}
244
245pub 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]
225fn infer_while_let() { 275fn infer_while_let() {
226 let (db, pos) = TestDB::with_position( 276 let (db, pos) = TestDB::with_position(
227 r#" 277 r#"