diff options
author | Emil Lauridsen <[email protected]> | 2019-12-13 11:44:42 +0000 |
---|---|---|
committer | Emil Lauridsen <[email protected]> | 2019-12-13 11:45:38 +0000 |
commit | 77052090515c1bb2a00236b3a57cdd778e581c8c (patch) | |
tree | 4ce2117829fda26c3bdbac26f73a4a196bfc4e3b /crates | |
parent | 95dc2de8e979264e1c76ce5594e8a63547a7956e (diff) |
Correctly infer - and ! using std::ops::{Neg,Not}
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/name.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 47 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 64 |
5 files changed, 114 insertions, 23 deletions
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index ec9d13e82..50f0cad94 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -342,6 +342,14 @@ pub mod known { | |||
342 | ) | 342 | ) |
343 | } | 343 | } |
344 | 344 | ||
345 | pub fn std_ops_neg() -> Path { | ||
346 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::NEG_TYPE]) | ||
347 | } | ||
348 | |||
349 | pub fn std_ops_not() -> Path { | ||
350 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::NOT_TYPE]) | ||
351 | } | ||
352 | |||
345 | pub fn std_result_result() -> Path { | 353 | pub fn std_result_result() -> Path { |
346 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) | 354 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) |
347 | } | 355 | } |
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index 4f2f702c0..9e68dd98d 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs | |||
@@ -152,6 +152,8 @@ pub const RANGE_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeInclusive") | |||
152 | pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive"); | 152 | pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive"); |
153 | pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo"); | 153 | pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo"); |
154 | pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range"); | 154 | pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range"); |
155 | pub const NEG_TYPE: Name = Name::new_inline_ascii(b"Neg"); | ||
156 | pub const NOT_TYPE: Name = Name::new_inline_ascii(b"Not"); | ||
155 | 157 | ||
156 | // Builtin Macros | 158 | // Builtin Macros |
157 | pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file"); | 159 | pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file"); |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 62d5c8803..a1201b3e4 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -36,8 +36,8 @@ use ra_prof::profile; | |||
36 | use super::{ | 36 | use super::{ |
37 | primitive::{FloatTy, IntTy}, | 37 | primitive::{FloatTy, IntTy}, |
38 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 38 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
39 | ApplicationTy, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, | 39 | ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, |
40 | Uncertain, | 40 | TypeWalk, Uncertain, |
41 | }; | 41 | }; |
42 | use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; | 42 | use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; |
43 | 43 | ||
@@ -433,6 +433,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
433 | self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE) | 433 | self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE) |
434 | } | 434 | } |
435 | 435 | ||
436 | fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> { | ||
437 | let path = known::std_ops_neg(); | ||
438 | let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; | ||
439 | self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) | ||
440 | } | ||
441 | |||
442 | fn resolve_ops_not_output(&self) -> Option<TypeAliasId> { | ||
443 | let path = known::std_ops_not(); | ||
444 | let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; | ||
445 | self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) | ||
446 | } | ||
447 | |||
436 | fn resolve_future_future_output(&self) -> Option<TypeAliasId> { | 448 | fn resolve_future_future_output(&self) -> Option<TypeAliasId> { |
437 | let path = known::std_future_future(); | 449 | let path = known::std_future_future(); |
438 | let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; | 450 | let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 6110f5abd..f8c00a7b4 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -332,31 +332,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
332 | }, | 332 | }, |
333 | UnaryOp::Neg => { | 333 | UnaryOp::Neg => { |
334 | match &inner_ty { | 334 | match &inner_ty { |
335 | Ty::Apply(a_ty) => match a_ty.ctor { | 335 | // Fast path for builtins |
336 | TypeCtor::Int(Uncertain::Unknown) | 336 | Ty::Apply(ApplicationTy { |
337 | | TypeCtor::Int(Uncertain::Known(IntTy { | 337 | ctor: |
338 | signedness: Signedness::Signed, | 338 | TypeCtor::Int(Uncertain::Known(IntTy { |
339 | .. | 339 | signedness: Signedness::Signed, |
340 | })) | 340 | .. |
341 | | TypeCtor::Float(..) => inner_ty, | 341 | })), |
342 | _ => Ty::Unknown, | 342 | .. |
343 | }, | 343 | }) |
344 | Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => { | 344 | | Ty::Apply(ApplicationTy { |
345 | inner_ty | 345 | ctor: TypeCtor::Int(Uncertain::Unknown), |
346 | } | 346 | .. |
347 | // FIXME: resolve ops::Neg trait | 347 | }) |
348 | _ => Ty::Unknown, | 348 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) |
349 | | Ty::Infer(InferTy::IntVar(..)) | ||
350 | | Ty::Infer(InferTy::FloatVar(..)) => inner_ty, | ||
351 | // Otherwise we resolve via the std::ops::Neg trait | ||
352 | _ => self | ||
353 | .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()), | ||
349 | } | 354 | } |
350 | } | 355 | } |
351 | UnaryOp::Not => { | 356 | UnaryOp::Not => { |
352 | match &inner_ty { | 357 | match &inner_ty { |
353 | Ty::Apply(a_ty) => match a_ty.ctor { | 358 | // Fast path for builtins |
354 | TypeCtor::Bool | TypeCtor::Int(_) => inner_ty, | 359 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. }) |
355 | _ => Ty::Unknown, | 360 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(_), .. }) |
356 | }, | 361 | | Ty::Infer(InferTy::IntVar(..)) => inner_ty, |
357 | Ty::Infer(InferTy::IntVar(..)) => inner_ty, | 362 | // Otherwise we resolve via the std::ops::Not trait |
358 | // FIXME: resolve ops::Not trait for inner_ty | 363 | _ => self |
359 | _ => Ty::Unknown, | 364 | .resolve_associated_type(inner_ty, self.resolve_ops_not_output()), |
360 | } | 365 | } |
361 | } | 366 | } |
362 | } | 367 | } |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 93c5f9a15..6139adb72 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -116,6 +116,70 @@ mod collections { | |||
116 | } | 116 | } |
117 | 117 | ||
118 | #[test] | 118 | #[test] |
119 | fn infer_ops_neg() { | ||
120 | let (db, pos) = TestDB::with_position( | ||
121 | r#" | ||
122 | //- /main.rs crate:main deps:std | ||
123 | |||
124 | struct Bar; | ||
125 | struct Foo; | ||
126 | |||
127 | impl std::ops::Neg for Bar { | ||
128 | type Output = Foo; | ||
129 | } | ||
130 | |||
131 | fn test() { | ||
132 | let a = Bar; | ||
133 | let b = -a; | ||
134 | b<|>; | ||
135 | } | ||
136 | |||
137 | //- /std.rs crate:std | ||
138 | |||
139 | #[prelude_import] use ops::*; | ||
140 | mod ops { | ||
141 | pub trait Neg { | ||
142 | type Output; | ||
143 | } | ||
144 | } | ||
145 | "#, | ||
146 | ); | ||
147 | assert_eq!("Foo", type_at_pos(&db, pos)); | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn infer_ops_not() { | ||
152 | let (db, pos) = TestDB::with_position( | ||
153 | r#" | ||
154 | //- /main.rs crate:main deps:std | ||
155 | |||
156 | struct Bar; | ||
157 | struct Foo; | ||
158 | |||
159 | impl std::ops::Not for Bar { | ||
160 | type Output = Foo; | ||
161 | } | ||
162 | |||
163 | fn test() { | ||
164 | let a = Bar; | ||
165 | let b = !a; | ||
166 | b<|>; | ||
167 | } | ||
168 | |||
169 | //- /std.rs crate:std | ||
170 | |||
171 | #[prelude_import] use ops::*; | ||
172 | mod ops { | ||
173 | pub trait Not { | ||
174 | type Output; | ||
175 | } | ||
176 | } | ||
177 | "#, | ||
178 | ); | ||
179 | assert_eq!("Foo", type_at_pos(&db, pos)); | ||
180 | } | ||
181 | |||
182 | #[test] | ||
119 | fn infer_from_bound_1() { | 183 | fn infer_from_bound_1() { |
120 | assert_snapshot!( | 184 | assert_snapshot!( |
121 | infer(r#" | 185 | infer(r#" |