From 4992d2bf79e9da6db759eb8e1715f90f31ec7eb9 Mon Sep 17 00:00:00 2001 From: oxalica Date: Fri, 29 Nov 2019 03:10:16 +0800 Subject: Infer range types --- crates/ra_hir_ty/src/infer.rs | 36 +++++++++++++++++++++++++++ crates/ra_hir_ty/src/infer/expr.rs | 41 +++++++++++++++++++++++++++++++ crates/ra_hir_ty/src/tests.rs | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) (limited to 'crates/ra_hir_ty/src') 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> { let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; Some(struct_.into()) } + + fn resolve_range_full(&self) -> Option { + let path = known::std_ops_range_full(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range(&self) -> Option { + let path = known::std_ops_range(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range_inclusive(&self) -> Option { + let path = known::std_ops_range_inclusive(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range_from(&self) -> Option { + let path = known::std_ops_range_from(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range_to(&self) -> Option { + let path = known::std_ops_range_to(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } + + fn resolve_range_to_inclusive(&self) -> Option { + let path = known::std_ops_range_to_inclusive(); + let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; + Some(struct_.into()) + } } /// 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..a00aa426a 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -415,6 +415,47 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } _ => Ty::Unknown, }, + Expr::RangeFull => match self.resolve_range_full() { + Some(adt) => Ty::simple(TypeCtor::Adt(adt)), + None => Ty::Unknown, + }, + Expr::Range { lhs, rhs } => { + let lhs_ty = self.infer_expr(*lhs, &Expectation::none()); + let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(lhs_ty)); + match self.resolve_range() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), rhs_ty), + None => Ty::Unknown, + } + } + Expr::RangeInclusive { lhs, rhs } => { + let lhs_ty = self.infer_expr(*lhs, &Expectation::none()); + let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(lhs_ty)); + match self.resolve_range_inclusive() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), rhs_ty), + None => Ty::Unknown, + } + } + Expr::RangeFrom { lhs } => { + let ty = self.infer_expr(*lhs, &Expectation::none()); + match self.resolve_range_from() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } + Expr::RangeTo { rhs } => { + let ty = self.infer_expr(*rhs, &Expectation::none()); + match self.resolve_range_to() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } + Expr::RangeToInclusive { rhs } => { + let ty = self.infer_expr(*rhs, &Expectation::none()); + match self.resolve_range_to_inclusive() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } Expr::Index { base, index } => { let _base_ty = self.infer_expr(*base, &Expectation::none()); 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 @@ -221,6 +221,56 @@ mod collections { assert_eq!("&str", type_at_pos(&db, pos)); } +#[test] +fn infer_ranges() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:std +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<|>; +} + +//- /std.rs crate:std +#[prelude_import] use prelude::*; +mod prelude {} + +pub mod ops { + pub struct Range { + pub start: Idx, + pub end: Idx, + } + pub struct RangeFrom { + pub start: Idx, + } + struct RangeFull; + pub struct RangeInclusive { + start: Idx, + end: Idx, + is_empty: u8, + } + pub struct RangeTo { + pub end: Idx, + } + pub struct RangeToInclusive { + pub end: Idx, + } +} +"#, + ); + assert_eq!( + "(RangeFull, RangeFrom, RangeTo, Range, RangeToInclusive, RangeInclusive)", + type_at_pos(&db, pos), + ); +} + #[test] fn infer_while_let() { let (db, pos) = TestDB::with_position( -- cgit v1.2.3 From 2cb684bbce1c487b2efb5a8154afe66e4907ceac Mon Sep 17 00:00:00 2001 From: oxalica Date: Fri, 29 Nov 2019 14:49:12 +0800 Subject: Reduce variants of Expr --- crates/ra_hir_ty/src/infer/expr.rs | 76 +++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 39 deletions(-) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index a00aa426a..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::{ AdtId, ContainerId, Lookup, StructFieldId, }; use hir_expand::name::{self, Name}; +use ra_syntax::ast::RangeOp; use crate::{ autoderef, db::HirDatabase, method_resolution, op, traits::InEnvironment, utils::variant_data, @@ -415,45 +416,42 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } _ => Ty::Unknown, }, - Expr::RangeFull => match self.resolve_range_full() { - Some(adt) => Ty::simple(TypeCtor::Adt(adt)), - None => Ty::Unknown, - }, - Expr::Range { lhs, rhs } => { - let lhs_ty = self.infer_expr(*lhs, &Expectation::none()); - let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(lhs_ty)); - match self.resolve_range() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), rhs_ty), - None => Ty::Unknown, - } - } - Expr::RangeInclusive { lhs, rhs } => { - let lhs_ty = self.infer_expr(*lhs, &Expectation::none()); - let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(lhs_ty)); - match self.resolve_range_inclusive() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), rhs_ty), - None => Ty::Unknown, - } - } - Expr::RangeFrom { lhs } => { - let ty = self.infer_expr(*lhs, &Expectation::none()); - match self.resolve_range_from() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), - None => Ty::Unknown, - } - } - Expr::RangeTo { rhs } => { - let ty = self.infer_expr(*rhs, &Expectation::none()); - match self.resolve_range_to() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), - None => Ty::Unknown, - } - } - Expr::RangeToInclusive { rhs } => { - let ty = self.infer_expr(*rhs, &Expectation::none()); - match self.resolve_range_to_inclusive() { - Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), - None => Ty::Unknown, + Expr::Range { lhs, rhs, range_type } => { + let lhs_ty = lhs.map(|e| self.infer_expr(e, &Expectation::none())); + let rhs_expect = lhs_ty + .as_ref() + .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone())); + let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); + match (range_type, lhs_ty, rhs_ty) { + (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { + Some(adt) => Ty::simple(TypeCtor::Adt(adt)), + None => Ty::Unknown, + }, + (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + }, + (RangeOp::Inclusive, None, Some(ty)) => { + match self.resolve_range_to_inclusive() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } + (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + }, + (RangeOp::Inclusive, Some(_), Some(ty)) => { + match self.resolve_range_inclusive() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + } + } + (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { + Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty), + None => Ty::Unknown, + }, + (RangeOp::Inclusive, _, None) => Ty::Unknown, } } Expr::Index { base, index } => { -- cgit v1.2.3