diff options
author | Galilée 'Bill' Enguehard <[email protected]> | 2020-05-21 22:27:38 +0100 |
---|---|---|
committer | Galilée 'Bill' Enguehard <[email protected]> | 2020-05-21 22:27:38 +0100 |
commit | 7fece3bdd2450c0807f7dd742239cae95f0cc65e (patch) | |
tree | 866c4db826c959e79c63a6727bdb9f2c61e6fc4f /crates/ra_hir_ty/src/infer | |
parent | db926218b2082077750291f8426ddd28b284cd08 (diff) | |
parent | 59732df8d40dfadc6dcf5951265416576399712a (diff) |
Merge branch 'master' of github.com:rust-analyzer/rust-analyzer into modname_spacing
Diffstat (limited to 'crates/ra_hir_ty/src/infer')
-rw-r--r-- | crates/ra_hir_ty/src/infer/coerce.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 116 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/pat.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 35 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 8 |
5 files changed, 159 insertions, 40 deletions
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 89200255a..2ee9adb16 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | //! See: https://doc.rust-lang.org/nomicon/coercions.html | 5 | //! See: https://doc.rust-lang.org/nomicon/coercions.html |
6 | 6 | ||
7 | use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; | 7 | use hir_def::{lang_item::LangItemTarget, type_ref::Mutability}; |
8 | use test_utils::tested_by; | 8 | use test_utils::mark; |
9 | 9 | ||
10 | use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor}; | 10 | use crate::{autoderef, traits::Solution, Obligation, Substs, TraitRef, Ty, TypeCtor}; |
11 | 11 | ||
@@ -20,21 +20,35 @@ impl<'a> InferenceContext<'a> { | |||
20 | self.coerce_inner(from_ty, &to_ty) | 20 | self.coerce_inner(from_ty, &to_ty) |
21 | } | 21 | } |
22 | 22 | ||
23 | /// Merge two types from different branches, with possible implicit coerce. | 23 | /// Merge two types from different branches, with possible coercion. |
24 | /// | 24 | /// |
25 | /// Note that it is only possible that one type are coerced to another. | 25 | /// Mostly this means trying to coerce one to the other, but |
26 | /// Coercing both types to another least upper bound type is not possible in rustc, | 26 | /// - if we have two function types for different functions, we need to |
27 | /// which will simply result in "incompatible types" error. | 27 | /// coerce both to function pointers; |
28 | /// - if we were concerned with lifetime subtyping, we'd need to look for a | ||
29 | /// least upper bound. | ||
28 | pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { | 30 | pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { |
29 | if self.coerce(ty1, ty2) { | 31 | if self.coerce(ty1, ty2) { |
30 | ty2.clone() | 32 | ty2.clone() |
31 | } else if self.coerce(ty2, ty1) { | 33 | } else if self.coerce(ty2, ty1) { |
32 | ty1.clone() | 34 | ty1.clone() |
33 | } else { | 35 | } else { |
34 | tested_by!(coerce_merge_fail_fallback); | 36 | if let (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnDef(_))) = (ty1, ty2) { |
35 | // For incompatible types, we use the latter one as result | 37 | mark::hit!(coerce_fn_reification); |
36 | // to be better recovery for `if` without `else`. | 38 | // Special case: two function types. Try to coerce both to |
37 | ty2.clone() | 39 | // pointers to have a chance at getting a match. See |
40 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 | ||
41 | let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig"); | ||
42 | let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig"); | ||
43 | let ptr_ty1 = Ty::fn_ptr(sig1); | ||
44 | let ptr_ty2 = Ty::fn_ptr(sig2); | ||
45 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) | ||
46 | } else { | ||
47 | mark::hit!(coerce_merge_fail_fallback); | ||
48 | // For incompatible types, we use the latter one as result | ||
49 | // to be better recovery for `if` without `else`. | ||
50 | ty2.clone() | ||
51 | } | ||
38 | } | 52 | } |
39 | } | 53 | } |
40 | 54 | ||
@@ -84,9 +98,7 @@ impl<'a> InferenceContext<'a> { | |||
84 | match from_ty.callable_sig(self.db) { | 98 | match from_ty.callable_sig(self.db) { |
85 | None => return false, | 99 | None => return false, |
86 | Some(sig) => { | 100 | Some(sig) => { |
87 | let num_args = sig.params_and_return.len() as u16 - 1; | 101 | from_ty = Ty::fn_ptr(sig); |
88 | from_ty = | ||
89 | Ty::apply(TypeCtor::FnPtr { num_args }, Substs(sig.params_and_return)); | ||
90 | } | 102 | } |
91 | } | 103 | } |
92 | } | 104 | } |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index efc60986b..b28724f0e 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Type inference for expressions. | 1 | //! Type inference for expressions. |
2 | 2 | ||
3 | use std::iter::{repeat, repeat_with}; | 3 | use std::iter::{repeat, repeat_with}; |
4 | use std::sync::Arc; | 4 | use std::{mem, sync::Arc}; |
5 | 5 | ||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | builtin_type::Signedness, | 7 | builtin_type::Signedness, |
@@ -21,11 +21,18 @@ use crate::{ | |||
21 | Ty, TypeCtor, Uncertain, | 21 | Ty, TypeCtor, Uncertain, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; | 24 | use super::{ |
25 | BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, | ||
26 | TypeMismatch, | ||
27 | }; | ||
25 | 28 | ||
26 | impl<'a> InferenceContext<'a> { | 29 | impl<'a> InferenceContext<'a> { |
27 | pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 30 | pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
28 | let ty = self.infer_expr_inner(tgt_expr, expected); | 31 | let ty = self.infer_expr_inner(tgt_expr, expected); |
32 | if ty.is_never() { | ||
33 | // Any expression that produces a value of type `!` must have diverged | ||
34 | self.diverges = Diverges::Always; | ||
35 | } | ||
29 | let could_unify = self.unify(&ty, &expected.ty); | 36 | let could_unify = self.unify(&ty, &expected.ty); |
30 | if !could_unify { | 37 | if !could_unify { |
31 | self.result.type_mismatches.insert( | 38 | self.result.type_mismatches.insert( |
@@ -64,34 +71,68 @@ impl<'a> InferenceContext<'a> { | |||
64 | // if let is desugared to match, so this is always simple if | 71 | // if let is desugared to match, so this is always simple if |
65 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 72 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
66 | 73 | ||
74 | let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); | ||
75 | let mut both_arms_diverge = Diverges::Always; | ||
76 | |||
67 | let then_ty = self.infer_expr_inner(*then_branch, &expected); | 77 | let then_ty = self.infer_expr_inner(*then_branch, &expected); |
78 | both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); | ||
68 | let else_ty = match else_branch { | 79 | let else_ty = match else_branch { |
69 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), | 80 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), |
70 | None => Ty::unit(), | 81 | None => Ty::unit(), |
71 | }; | 82 | }; |
83 | both_arms_diverge &= self.diverges; | ||
84 | |||
85 | self.diverges = condition_diverges | both_arms_diverge; | ||
72 | 86 | ||
73 | self.coerce_merge_branch(&then_ty, &else_ty) | 87 | self.coerce_merge_branch(&then_ty, &else_ty) |
74 | } | 88 | } |
75 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), | 89 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), |
90 | Expr::TryBlock { body } => { | ||
91 | let _inner = self.infer_expr(*body, expected); | ||
92 | // FIXME should be std::result::Result<{inner}, _> | ||
93 | Ty::Unknown | ||
94 | } | ||
76 | Expr::Loop { body } => { | 95 | Expr::Loop { body } => { |
96 | self.breakables.push(BreakableContext { | ||
97 | may_break: false, | ||
98 | break_ty: self.table.new_type_var(), | ||
99 | }); | ||
77 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 100 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
78 | // FIXME handle break with value | 101 | |
79 | Ty::simple(TypeCtor::Never) | 102 | let ctxt = self.breakables.pop().expect("breakable stack broken"); |
103 | if ctxt.may_break { | ||
104 | self.diverges = Diverges::Maybe; | ||
105 | } | ||
106 | |||
107 | if ctxt.may_break { | ||
108 | ctxt.break_ty | ||
109 | } else { | ||
110 | Ty::simple(TypeCtor::Never) | ||
111 | } | ||
80 | } | 112 | } |
81 | Expr::While { condition, body } => { | 113 | Expr::While { condition, body } => { |
114 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | ||
82 | // while let is desugared to a match loop, so this is always simple while | 115 | // while let is desugared to a match loop, so this is always simple while |
83 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 116 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
84 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 117 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
118 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
119 | // the body may not run, so it diverging doesn't mean we diverge | ||
120 | self.diverges = Diverges::Maybe; | ||
85 | Ty::unit() | 121 | Ty::unit() |
86 | } | 122 | } |
87 | Expr::For { iterable, body, pat } => { | 123 | Expr::For { iterable, body, pat } => { |
88 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 124 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
89 | 125 | ||
126 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | ||
90 | let pat_ty = | 127 | let pat_ty = |
91 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); | 128 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); |
92 | 129 | ||
93 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); | 130 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); |
131 | |||
94 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 132 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
133 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | ||
134 | // the body may not run, so it diverging doesn't mean we diverge | ||
135 | self.diverges = Diverges::Maybe; | ||
95 | Ty::unit() | 136 | Ty::unit() |
96 | } | 137 | } |
97 | Expr::Lambda { body, args, ret_type, arg_types } => { | 138 | Expr::Lambda { body, args, ret_type, arg_types } => { |
@@ -127,10 +168,12 @@ impl<'a> InferenceContext<'a> { | |||
127 | // infer the body. | 168 | // infer the body. |
128 | self.coerce(&closure_ty, &expected.ty); | 169 | self.coerce(&closure_ty, &expected.ty); |
129 | 170 | ||
130 | let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone()); | 171 | let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); |
172 | let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); | ||
131 | 173 | ||
132 | self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); | 174 | self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); |
133 | 175 | ||
176 | self.diverges = prev_diverges; | ||
134 | self.return_ty = prev_ret_ty; | 177 | self.return_ty = prev_ret_ty; |
135 | 178 | ||
136 | closure_ty | 179 | closure_ty |
@@ -160,7 +203,11 @@ impl<'a> InferenceContext<'a> { | |||
160 | self.table.new_type_var() | 203 | self.table.new_type_var() |
161 | }; | 204 | }; |
162 | 205 | ||
206 | let matchee_diverges = self.diverges; | ||
207 | let mut all_arms_diverge = Diverges::Always; | ||
208 | |||
163 | for arm in arms { | 209 | for arm in arms { |
210 | self.diverges = Diverges::Maybe; | ||
164 | let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); | 211 | let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default()); |
165 | if let Some(guard_expr) = arm.guard { | 212 | if let Some(guard_expr) = arm.guard { |
166 | self.infer_expr( | 213 | self.infer_expr( |
@@ -170,9 +217,12 @@ impl<'a> InferenceContext<'a> { | |||
170 | } | 217 | } |
171 | 218 | ||
172 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); | 219 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); |
220 | all_arms_diverge &= self.diverges; | ||
173 | result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); | 221 | result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); |
174 | } | 222 | } |
175 | 223 | ||
224 | self.diverges = matchee_diverges | all_arms_diverge; | ||
225 | |||
176 | result_ty | 226 | result_ty |
177 | } | 227 | } |
178 | Expr::Path(p) => { | 228 | Expr::Path(p) => { |
@@ -182,10 +232,29 @@ impl<'a> InferenceContext<'a> { | |||
182 | } | 232 | } |
183 | Expr::Continue => Ty::simple(TypeCtor::Never), | 233 | Expr::Continue => Ty::simple(TypeCtor::Never), |
184 | Expr::Break { expr } => { | 234 | Expr::Break { expr } => { |
185 | if let Some(expr) = expr { | 235 | let val_ty = if let Some(expr) = expr { |
186 | // FIXME handle break with value | 236 | self.infer_expr(*expr, &Expectation::none()) |
187 | self.infer_expr(*expr, &Expectation::none()); | 237 | } else { |
238 | Ty::unit() | ||
239 | }; | ||
240 | |||
241 | let last_ty = if let Some(ctxt) = self.breakables.last() { | ||
242 | ctxt.break_ty.clone() | ||
243 | } else { | ||
244 | Ty::Unknown | ||
245 | }; | ||
246 | |||
247 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); | ||
248 | |||
249 | if let Some(ctxt) = self.breakables.last_mut() { | ||
250 | ctxt.break_ty = merged_type; | ||
251 | ctxt.may_break = true; | ||
252 | } else { | ||
253 | self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { | ||
254 | expr: tgt_expr, | ||
255 | }); | ||
188 | } | 256 | } |
257 | |||
189 | Ty::simple(TypeCtor::Never) | 258 | Ty::simple(TypeCtor::Never) |
190 | } | 259 | } |
191 | Expr::Return { expr } => { | 260 | Expr::Return { expr } => { |
@@ -496,8 +565,8 @@ impl<'a> InferenceContext<'a> { | |||
496 | } | 565 | } |
497 | Literal::ByteString(..) => { | 566 | Literal::ByteString(..) => { |
498 | let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); | 567 | let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); |
499 | let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); | 568 | let array_type = Ty::apply_one(TypeCtor::Array, byte_type); |
500 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) | 569 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) |
501 | } | 570 | } |
502 | Literal::Char(..) => Ty::simple(TypeCtor::Char), | 571 | Literal::Char(..) => Ty::simple(TypeCtor::Char), |
503 | Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), | 572 | Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), |
@@ -517,7 +586,6 @@ impl<'a> InferenceContext<'a> { | |||
517 | tail: Option<ExprId>, | 586 | tail: Option<ExprId>, |
518 | expected: &Expectation, | 587 | expected: &Expectation, |
519 | ) -> Ty { | 588 | ) -> Ty { |
520 | let mut diverges = false; | ||
521 | for stmt in statements { | 589 | for stmt in statements { |
522 | match stmt { | 590 | match stmt { |
523 | Statement::Let { pat, type_ref, initializer } => { | 591 | Statement::Let { pat, type_ref, initializer } => { |
@@ -539,9 +607,7 @@ impl<'a> InferenceContext<'a> { | |||
539 | self.infer_pat(*pat, &ty, BindingMode::default()); | 607 | self.infer_pat(*pat, &ty, BindingMode::default()); |
540 | } | 608 | } |
541 | Statement::Expr(expr) => { | 609 | Statement::Expr(expr) => { |
542 | if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) { | 610 | self.infer_expr(*expr, &Expectation::none()); |
543 | diverges = true; | ||
544 | } | ||
545 | } | 611 | } |
546 | } | 612 | } |
547 | } | 613 | } |
@@ -549,14 +615,22 @@ impl<'a> InferenceContext<'a> { | |||
549 | let ty = if let Some(expr) = tail { | 615 | let ty = if let Some(expr) = tail { |
550 | self.infer_expr_coerce(expr, expected) | 616 | self.infer_expr_coerce(expr, expected) |
551 | } else { | 617 | } else { |
552 | self.coerce(&Ty::unit(), expected.coercion_target()); | 618 | // Citing rustc: if there is no explicit tail expression, |
553 | Ty::unit() | 619 | // that is typically equivalent to a tail expression |
620 | // of `()` -- except if the block diverges. In that | ||
621 | // case, there is no value supplied from the tail | ||
622 | // expression (assuming there are no other breaks, | ||
623 | // this implies that the type of the block will be | ||
624 | // `!`). | ||
625 | if self.diverges.is_always() { | ||
626 | // we don't even make an attempt at coercion | ||
627 | self.table.new_maybe_never_type_var() | ||
628 | } else { | ||
629 | self.coerce(&Ty::unit(), expected.coercion_target()); | ||
630 | Ty::unit() | ||
631 | } | ||
554 | }; | 632 | }; |
555 | if diverges { | 633 | ty |
556 | Ty::simple(TypeCtor::Never) | ||
557 | } else { | ||
558 | ty | ||
559 | } | ||
560 | } | 634 | } |
561 | 635 | ||
562 | fn infer_method_call( | 636 | fn infer_method_call( |
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index 54ec870df..4006f595d 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs | |||
@@ -10,7 +10,7 @@ use hir_def::{ | |||
10 | FieldId, | 10 | FieldId, |
11 | }; | 11 | }; |
12 | use hir_expand::name::Name; | 12 | use hir_expand::name::Name; |
13 | use test_utils::tested_by; | 13 | use test_utils::mark; |
14 | 14 | ||
15 | use super::{BindingMode, Expectation, InferenceContext}; | 15 | use super::{BindingMode, Expectation, InferenceContext}; |
16 | use crate::{utils::variant_data, Substs, Ty, TypeCtor}; | 16 | use crate::{utils::variant_data, Substs, Ty, TypeCtor}; |
@@ -111,7 +111,7 @@ impl<'a> InferenceContext<'a> { | |||
111 | } | 111 | } |
112 | } | 112 | } |
113 | } else if let Pat::Ref { .. } = &body[pat] { | 113 | } else if let Pat::Ref { .. } = &body[pat] { |
114 | tested_by!(match_ergonomics_ref); | 114 | mark::hit!(match_ergonomics_ref); |
115 | // When you encounter a `&pat` pattern, reset to Move. | 115 | // When you encounter a `&pat` pattern, reset to Move. |
116 | // This is so that `w` is by value: `let (_, &w) = &(1, &2);` | 116 | // This is so that `w` is by value: `let (_, &w) = &(1, &2);` |
117 | default_bm = BindingMode::Move; | 117 | default_bm = BindingMode::Move; |
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 2b6bc0f79..1c2e56fb0 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs | |||
@@ -5,7 +5,7 @@ use std::iter; | |||
5 | use hir_def::{ | 5 | use hir_def::{ |
6 | path::{Path, PathSegment}, | 6 | path::{Path, PathSegment}, |
7 | resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 7 | resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
8 | AssocContainerId, AssocItemId, Lookup, | 8 | AdtId, AssocContainerId, AssocItemId, EnumVariantId, Lookup, |
9 | }; | 9 | }; |
10 | use hir_expand::name::Name; | 10 | use hir_expand::name::Name; |
11 | 11 | ||
@@ -77,6 +77,18 @@ impl<'a> InferenceContext<'a> { | |||
77 | 77 | ||
78 | it.into() | 78 | it.into() |
79 | } | 79 | } |
80 | ValueNs::ImplSelf(impl_id) => { | ||
81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | ||
82 | let substs = Substs::type_params_for_generics(&generics); | ||
83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | ||
84 | if let Some((AdtId::StructId(struct_id), _)) = ty.as_adt() { | ||
85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); | ||
86 | return Some(ty); | ||
87 | } else { | ||
88 | // FIXME: diagnostic, invalid Self reference | ||
89 | return None; | ||
90 | } | ||
91 | } | ||
80 | }; | 92 | }; |
81 | 93 | ||
82 | let ty = self.db.value_ty(typable); | 94 | let ty = self.db.value_ty(typable); |
@@ -199,6 +211,10 @@ impl<'a> InferenceContext<'a> { | |||
199 | return None; | 211 | return None; |
200 | } | 212 | } |
201 | 213 | ||
214 | if let Some(result) = self.resolve_enum_variant_on_ty(&ty, name, id) { | ||
215 | return Some(result); | ||
216 | } | ||
217 | |||
202 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); | 218 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); |
203 | let krate = self.resolver.krate()?; | 219 | let krate = self.resolver.krate()?; |
204 | let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); | 220 | let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); |
@@ -250,4 +266,21 @@ impl<'a> InferenceContext<'a> { | |||
250 | }, | 266 | }, |
251 | ) | 267 | ) |
252 | } | 268 | } |
269 | |||
270 | fn resolve_enum_variant_on_ty( | ||
271 | &mut self, | ||
272 | ty: &Ty, | ||
273 | name: &Name, | ||
274 | id: ExprOrPatId, | ||
275 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
276 | let (enum_id, subst) = match ty.as_adt() { | ||
277 | Some((AdtId::EnumId(e), subst)) => (e, subst), | ||
278 | _ => return None, | ||
279 | }; | ||
280 | let enum_data = self.db.enum_data(enum_id); | ||
281 | let local_id = enum_data.variant(name)?; | ||
282 | let variant = EnumVariantId { parent: enum_id, local_id }; | ||
283 | self.write_variant_resolution(id, variant.into()); | ||
284 | Some((ValueNs::EnumVariantId(variant), Some(subst.clone()))) | ||
285 | } | ||
253 | } | 286 | } |
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index ab0bc8b70..269495ca0 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -4,7 +4,7 @@ use std::borrow::Cow; | |||
4 | 4 | ||
5 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; | 5 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; |
6 | 6 | ||
7 | use test_utils::tested_by; | 7 | use test_utils::mark; |
8 | 8 | ||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use crate::{ |
@@ -313,7 +313,7 @@ impl InferenceTable { | |||
313 | // more than once | 313 | // more than once |
314 | for i in 0..3 { | 314 | for i in 0..3 { |
315 | if i > 0 { | 315 | if i > 0 { |
316 | tested_by!(type_var_resolves_to_int_var); | 316 | mark::hit!(type_var_resolves_to_int_var); |
317 | } | 317 | } |
318 | match &*ty { | 318 | match &*ty { |
319 | Ty::Infer(tv) => { | 319 | Ty::Infer(tv) => { |
@@ -342,7 +342,7 @@ impl InferenceTable { | |||
342 | Ty::Infer(tv) => { | 342 | Ty::Infer(tv) => { |
343 | let inner = tv.to_inner(); | 343 | let inner = tv.to_inner(); |
344 | if tv_stack.contains(&inner) { | 344 | if tv_stack.contains(&inner) { |
345 | tested_by!(type_var_cycles_resolve_as_possible); | 345 | mark::hit!(type_var_cycles_resolve_as_possible); |
346 | // recursive type | 346 | // recursive type |
347 | return tv.fallback_value(); | 347 | return tv.fallback_value(); |
348 | } | 348 | } |
@@ -369,7 +369,7 @@ impl InferenceTable { | |||
369 | Ty::Infer(tv) => { | 369 | Ty::Infer(tv) => { |
370 | let inner = tv.to_inner(); | 370 | let inner = tv.to_inner(); |
371 | if tv_stack.contains(&inner) { | 371 | if tv_stack.contains(&inner) { |
372 | tested_by!(type_var_cycles_resolve_completely); | 372 | mark::hit!(type_var_cycles_resolve_completely); |
373 | // recursive type | 373 | // recursive type |
374 | return tv.fallback_value(); | 374 | return tv.fallback_value(); |
375 | } | 375 | } |