aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorEmil Lauridsen <[email protected]>2019-12-13 11:44:42 +0000
committerEmil Lauridsen <[email protected]>2019-12-13 11:45:38 +0000
commit77052090515c1bb2a00236b3a57cdd778e581c8c (patch)
tree4ce2117829fda26c3bdbac26f73a4a196bfc4e3b /crates
parent95dc2de8e979264e1c76ce5594e8a63547a7956e (diff)
Correctly infer - and ! using std::ops::{Neg,Not}
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_def/src/path.rs8
-rw-r--r--crates/ra_hir_expand/src/name.rs2
-rw-r--r--crates/ra_hir_ty/src/infer.rs16
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs47
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs64
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")
152pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive"); 152pub const RANGE_TO_INCLUSIVE_TYPE: Name = Name::new_inline_ascii(b"RangeToInclusive");
153pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo"); 153pub const RANGE_TO_TYPE: Name = Name::new_inline_ascii(b"RangeTo");
154pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range"); 154pub const RANGE_TYPE: Name = Name::new_inline_ascii(b"Range");
155pub const NEG_TYPE: Name = Name::new_inline_ascii(b"Neg");
156pub const NOT_TYPE: Name = Name::new_inline_ascii(b"Not");
155 157
156// Builtin Macros 158// Builtin Macros
157pub const FILE_MACRO: Name = Name::new_inline_ascii(b"file"); 159pub 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;
36use super::{ 36use 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};
42use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; 42use 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]
119fn infer_ops_neg() {
120 let (db, pos) = TestDB::with_position(
121 r#"
122//- /main.rs crate:main deps:std
123
124struct Bar;
125struct Foo;
126
127impl std::ops::Neg for Bar {
128 type Output = Foo;
129}
130
131fn test() {
132 let a = Bar;
133 let b = -a;
134 b<|>;
135}
136
137//- /std.rs crate:std
138
139#[prelude_import] use ops::*;
140mod 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]
151fn infer_ops_not() {
152 let (db, pos) = TestDB::with_position(
153 r#"
154//- /main.rs crate:main deps:std
155
156struct Bar;
157struct Foo;
158
159impl std::ops::Not for Bar {
160 type Output = Foo;
161}
162
163fn test() {
164 let a = Bar;
165 let b = !a;
166 b<|>;
167}
168
169//- /std.rs crate:std
170
171#[prelude_import] use ops::*;
172mod 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]
119fn infer_from_bound_1() { 183fn infer_from_bound_1() {
120 assert_snapshot!( 184 assert_snapshot!(
121 infer(r#" 185 infer(r#"