aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-12-13 19:49:01 +0000
committerGitHub <[email protected]>2019-12-13 19:49:01 +0000
commit9c9f4635b4eb7d987717b4064a7de789f7983e2a (patch)
treea90ec3dd748d8e4f9fcd6e808bf39c234a25c6d7 /crates
parentebc95af2b5b91239fc1d8a5fc8344ded6f6ef3e4 (diff)
parent77052090515c1bb2a00236b3a57cdd778e581c8c (diff)
Merge #2550
2550: Infer - and ! using std::ops::{Neg, Not} r=flodiebold a=kiljacken Found some low hanging fruit while taking a cursory look at index inferring. Co-authored-by: Emil Lauridsen <[email protected]>
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.rs34
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs101
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs64
5 files changed, 139 insertions, 70 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 d16f1eb46..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
@@ -338,6 +338,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
338 self.table.resolve_ty_shallow(ty) 338 self.table.resolve_ty_shallow(ty)
339 } 339 }
340 340
341 fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
342 match assoc_ty {
343 Some(res_assoc_ty) => {
344 let ty = self.table.new_type_var();
345 let projection = ProjectionPredicate {
346 ty: ty.clone(),
347 projection_ty: ProjectionTy {
348 associated_ty: res_assoc_ty,
349 parameters: Substs::single(inner_ty),
350 },
351 };
352 self.obligations.push(Obligation::Projection(projection));
353 self.resolve_ty_as_possible(ty)
354 }
355 None => Ty::Unknown,
356 }
357 }
358
341 /// Recurses through the given type, normalizing associated types mentioned 359 /// Recurses through the given type, normalizing associated types mentioned
342 /// in it by replacing them by type variables and registering obligations to 360 /// in it by replacing them by type variables and registering obligations to
343 /// resolve later. This should be done once for every type we get from some 361 /// resolve later. This should be done once for every type we get from some
@@ -415,6 +433,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
415 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)
416 } 434 }
417 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
418 fn resolve_future_future_output(&self) -> Option<TypeAliasId> { 448 fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
419 let path = known::std_future_future(); 449 let path = known::std_future_future();
420 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 2c296987c..f8c00a7b4 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -19,8 +19,8 @@ use crate::{
19 method_resolution, op, 19 method_resolution, op,
20 traits::InEnvironment, 20 traits::InEnvironment,
21 utils::{generics, variant_data, Generics}, 21 utils::{generics, variant_data, Generics},
22 CallableDef, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, 22 ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty,
23 TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, 23 TypeCtor, TypeWalk, Uncertain,
24}; 24};
25 25
26use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 26use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
@@ -95,21 +95,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
95 Expr::For { iterable, body, pat } => { 95 Expr::For { iterable, body, pat } => {
96 let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 96 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
97 97
98 let pat_ty = match self.resolve_into_iter_item() { 98 let pat_ty =
99 Some(into_iter_item_alias) => { 99 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
100 let pat_ty = self.table.new_type_var();
101 let projection = ProjectionPredicate {
102 ty: pat_ty.clone(),
103 projection_ty: ProjectionTy {
104 associated_ty: into_iter_item_alias,
105 parameters: Substs::single(iterable_ty),
106 },
107 };
108 self.obligations.push(Obligation::Projection(projection));
109 self.resolve_ty_as_possible(pat_ty)
110 }
111 None => Ty::Unknown,
112 };
113 100
114 self.infer_pat(*pat, &pat_ty, BindingMode::default()); 101 self.infer_pat(*pat, &pat_ty, BindingMode::default());
115 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 102 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
@@ -284,40 +271,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
284 } 271 }
285 Expr::Await { expr } => { 272 Expr::Await { expr } => {
286 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); 273 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
287 let ty = match self.resolve_future_future_output() { 274 let ty =
288 Some(future_future_output_alias) => { 275 self.resolve_associated_type(inner_ty, self.resolve_future_future_output());
289 let ty = self.table.new_type_var();
290 let projection = ProjectionPredicate {
291 ty: ty.clone(),
292 projection_ty: ProjectionTy {
293 associated_ty: future_future_output_alias,
294 parameters: Substs::single(inner_ty),
295 },
296 };
297 self.obligations.push(Obligation::Projection(projection));
298 self.resolve_ty_as_possible(ty)
299 }
300 None => Ty::Unknown,
301 };
302 ty 276 ty
303 } 277 }
304 Expr::Try { expr } => { 278 Expr::Try { expr } => {
305 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); 279 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
306 let ty = match self.resolve_ops_try_ok() { 280 let ty = self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok());
307 Some(ops_try_ok_alias) => {
308 let ty = self.table.new_type_var();
309 let projection = ProjectionPredicate {
310 ty: ty.clone(),
311 projection_ty: ProjectionTy {
312 associated_ty: ops_try_ok_alias,
313 parameters: Substs::single(inner_ty),
314 },
315 };
316 self.obligations.push(Obligation::Projection(projection));
317 self.resolve_ty_as_possible(ty)
318 }
319 None => Ty::Unknown,
320 };
321 ty 281 ty
322 } 282 }
323 Expr::Cast { expr, type_ref } => { 283 Expr::Cast { expr, type_ref } => {
@@ -372,31 +332,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
372 }, 332 },
373 UnaryOp::Neg => { 333 UnaryOp::Neg => {
374 match &inner_ty { 334 match &inner_ty {
375 Ty::Apply(a_ty) => match a_ty.ctor { 335 // Fast path for builtins
376 TypeCtor::Int(Uncertain::Unknown) 336 Ty::Apply(ApplicationTy {
377 | TypeCtor::Int(Uncertain::Known(IntTy { 337 ctor:
378 signedness: Signedness::Signed, 338 TypeCtor::Int(Uncertain::Known(IntTy {
379 .. 339 signedness: Signedness::Signed,
380 })) 340 ..
381 | TypeCtor::Float(..) => inner_ty, 341 })),
382 _ => Ty::Unknown, 342 ..
383 }, 343 })
384 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => { 344 | Ty::Apply(ApplicationTy {
385 inner_ty 345 ctor: TypeCtor::Int(Uncertain::Unknown),
386 } 346 ..
387 // FIXME: resolve ops::Neg trait 347 })
388 _ => 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()),
389 } 354 }
390 } 355 }
391 UnaryOp::Not => { 356 UnaryOp::Not => {
392 match &inner_ty { 357 match &inner_ty {
393 Ty::Apply(a_ty) => match a_ty.ctor { 358 // Fast path for builtins
394 TypeCtor::Bool | TypeCtor::Int(_) => inner_ty, 359 Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })
395 _ => Ty::Unknown, 360 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(_), .. })
396 }, 361 | Ty::Infer(InferTy::IntVar(..)) => inner_ty,
397 Ty::Infer(InferTy::IntVar(..)) => inner_ty, 362 // Otherwise we resolve via the std::ops::Not trait
398 // FIXME: resolve ops::Not trait for inner_ty 363 _ => self
399 _ => Ty::Unknown, 364 .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
400 } 365 }
401 } 366 }
402 } 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#"