diff options
Diffstat (limited to 'crates/ra_hir_ty/src/infer')
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 133 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/pat.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 55 |
4 files changed, 166 insertions, 69 deletions
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 4a98e2deb..731b062c2 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -10,15 +10,15 @@ use hir_def::{ | |||
10 | resolver::resolver_for_expr, | 10 | resolver::resolver_for_expr, |
11 | AdtId, AssocContainerId, FieldId, Lookup, | 11 | AdtId, AssocContainerId, FieldId, Lookup, |
12 | }; | 12 | }; |
13 | use hir_expand::name::Name; | 13 | use hir_expand::name::{name, Name}; |
14 | use ra_syntax::ast::RangeOp; | 14 | use ra_syntax::ast::RangeOp; |
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | autoderef, method_resolution, op, | 17 | autoderef, method_resolution, op, |
18 | traits::InEnvironment, | 18 | traits::{FnTrait, InEnvironment}, |
19 | utils::{generics, variant_data, Generics}, | 19 | utils::{generics, variant_data, Generics}, |
20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, | 20 | ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, |
21 | TraitRef, Ty, TypeCtor, Uncertain, | 21 | TraitRef, Ty, TypeCtor, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{ | 24 | use super::{ |
@@ -63,6 +63,56 @@ impl<'a> InferenceContext<'a> { | |||
63 | self.resolve_ty_as_possible(ty) | 63 | self.resolve_ty_as_possible(ty) |
64 | } | 64 | } |
65 | 65 | ||
66 | fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
67 | let krate = self.resolver.krate()?; | ||
68 | let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; | ||
69 | let output_assoc_type = | ||
70 | self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; | ||
71 | let generic_params = generics(self.db.upcast(), fn_once_trait.into()); | ||
72 | if generic_params.len() != 2 { | ||
73 | return None; | ||
74 | } | ||
75 | |||
76 | let mut param_builder = Substs::builder(num_args); | ||
77 | let mut arg_tys = vec![]; | ||
78 | for _ in 0..num_args { | ||
79 | let arg = self.table.new_type_var(); | ||
80 | param_builder = param_builder.push(arg.clone()); | ||
81 | arg_tys.push(arg); | ||
82 | } | ||
83 | let parameters = param_builder.build(); | ||
84 | let arg_ty = Ty::Apply(ApplicationTy { | ||
85 | ctor: TypeCtor::Tuple { cardinality: num_args as u16 }, | ||
86 | parameters, | ||
87 | }); | ||
88 | let substs = | ||
89 | Substs::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build(); | ||
90 | |||
91 | let trait_env = Arc::clone(&self.trait_env); | ||
92 | let implements_fn_trait = | ||
93 | Obligation::Trait(TraitRef { trait_: fn_once_trait, substs: substs.clone() }); | ||
94 | let goal = self.canonicalizer().canonicalize_obligation(InEnvironment { | ||
95 | value: implements_fn_trait.clone(), | ||
96 | environment: trait_env, | ||
97 | }); | ||
98 | if self.db.trait_solve(krate, goal.value).is_some() { | ||
99 | self.obligations.push(implements_fn_trait); | ||
100 | let output_proj_ty = | ||
101 | crate::ProjectionTy { associated_ty: output_assoc_type, parameters: substs }; | ||
102 | let return_ty = self.normalize_projection_ty(output_proj_ty); | ||
103 | Some((arg_tys, return_ty)) | ||
104 | } else { | ||
105 | None | ||
106 | } | ||
107 | } | ||
108 | |||
109 | pub fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
110 | match ty.callable_sig(self.db) { | ||
111 | Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())), | ||
112 | None => self.callable_sig_from_fn_trait(ty, num_args), | ||
113 | } | ||
114 | } | ||
115 | |||
66 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 116 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
67 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 117 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
68 | let ty = match &body[tgt_expr] { | 118 | let ty = match &body[tgt_expr] { |
@@ -90,6 +140,7 @@ impl<'a> InferenceContext<'a> { | |||
90 | // FIXME: Breakable block inference | 140 | // FIXME: Breakable block inference |
91 | self.infer_block(statements, *tail, expected) | 141 | self.infer_block(statements, *tail, expected) |
92 | } | 142 | } |
143 | Expr::Unsafe { body } => self.infer_expr(*body, expected), | ||
93 | Expr::TryBlock { body } => { | 144 | Expr::TryBlock { body } => { |
94 | let _inner = self.infer_expr(*body, expected); | 145 | let _inner = self.infer_expr(*body, expected); |
95 | // FIXME should be std::result::Result<{inner}, _> | 146 | // FIXME should be std::result::Result<{inner}, _> |
@@ -169,7 +220,7 @@ impl<'a> InferenceContext<'a> { | |||
169 | }; | 220 | }; |
170 | sig_tys.push(ret_ty.clone()); | 221 | sig_tys.push(ret_ty.clone()); |
171 | let sig_ty = Ty::apply( | 222 | let sig_ty = Ty::apply( |
172 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, | 223 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1, is_varargs: false }, |
173 | Substs(sig_tys.clone().into()), | 224 | Substs(sig_tys.clone().into()), |
174 | ); | 225 | ); |
175 | let closure_ty = | 226 | let closure_ty = |
@@ -198,14 +249,23 @@ impl<'a> InferenceContext<'a> { | |||
198 | } | 249 | } |
199 | Expr::Call { callee, args } => { | 250 | Expr::Call { callee, args } => { |
200 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); | 251 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); |
201 | let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) { | 252 | let canonicalized = self.canonicalizer().canonicalize_ty(callee_ty.clone()); |
202 | Some(sig) => (sig.params().to_vec(), sig.ret().clone()), | 253 | let mut derefs = autoderef( |
203 | None => { | 254 | self.db, |
204 | // Not callable | 255 | self.resolver.krate(), |
205 | // FIXME: report an error | 256 | InEnvironment { |
206 | (Vec::new(), Ty::Unknown) | 257 | value: canonicalized.value.clone(), |
207 | } | 258 | environment: self.trait_env.clone(), |
208 | }; | 259 | }, |
260 | ); | ||
261 | let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs | ||
262 | .find_map(|callee_deref_ty| { | ||
263 | self.callable_sig( | ||
264 | &canonicalized.decanonicalize_ty(callee_deref_ty.value), | ||
265 | args.len(), | ||
266 | ) | ||
267 | }) | ||
268 | .unwrap_or((Vec::new(), Ty::Unknown)); | ||
209 | self.register_obligations_for_call(&callee_ty); | 269 | self.register_obligations_for_call(&callee_ty); |
210 | self.check_call_arguments(args, ¶m_tys); | 270 | self.check_call_arguments(args, ¶m_tys); |
211 | self.normalize_associated_types_in(ret_ty) | 271 | self.normalize_associated_types_in(ret_ty) |
@@ -345,8 +405,15 @@ impl<'a> InferenceContext<'a> { | |||
345 | .subst(&a_ty.parameters) | 405 | .subst(&a_ty.parameters) |
346 | }) | 406 | }) |
347 | } | 407 | } |
348 | // FIXME: | 408 | TypeCtor::Adt(AdtId::UnionId(u)) => { |
349 | TypeCtor::Adt(AdtId::UnionId(_)) => None, | 409 | self.db.union_data(u).variant_data.field(name).map(|local_id| { |
410 | let field = FieldId { parent: u.into(), local_id }; | ||
411 | self.write_field_resolution(tgt_expr, field); | ||
412 | self.db.field_types(u.into())[field.local_id] | ||
413 | .clone() | ||
414 | .subst(&a_ty.parameters) | ||
415 | }) | ||
416 | } | ||
350 | _ => None, | 417 | _ => None, |
351 | }, | 418 | }, |
352 | _ => None, | 419 | _ => None, |
@@ -426,15 +493,7 @@ impl<'a> InferenceContext<'a> { | |||
426 | match &inner_ty { | 493 | match &inner_ty { |
427 | // Fast path for builtins | 494 | // Fast path for builtins |
428 | Ty::Apply(ApplicationTy { | 495 | Ty::Apply(ApplicationTy { |
429 | ctor: | 496 | ctor: TypeCtor::Int(IntTy { signedness: Signedness::Signed, .. }), |
430 | TypeCtor::Int(Uncertain::Known(IntTy { | ||
431 | signedness: Signedness::Signed, | ||
432 | .. | ||
433 | })), | ||
434 | .. | ||
435 | }) | ||
436 | | Ty::Apply(ApplicationTy { | ||
437 | ctor: TypeCtor::Int(Uncertain::Unknown), | ||
438 | .. | 497 | .. |
439 | }) | 498 | }) |
440 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) | 499 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. }) |
@@ -577,9 +636,7 @@ impl<'a> InferenceContext<'a> { | |||
577 | ); | 636 | ); |
578 | self.infer_expr( | 637 | self.infer_expr( |
579 | *repeat, | 638 | *repeat, |
580 | &Expectation::has_type(Ty::simple(TypeCtor::Int(Uncertain::Known( | 639 | &Expectation::has_type(Ty::simple(TypeCtor::Int(IntTy::usize()))), |
581 | IntTy::usize(), | ||
582 | )))), | ||
583 | ); | 640 | ); |
584 | } | 641 | } |
585 | } | 642 | } |
@@ -592,13 +649,19 @@ impl<'a> InferenceContext<'a> { | |||
592 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) | 649 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) |
593 | } | 650 | } |
594 | Literal::ByteString(..) => { | 651 | Literal::ByteString(..) => { |
595 | let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); | 652 | let byte_type = Ty::simple(TypeCtor::Int(IntTy::u8())); |
596 | let array_type = Ty::apply_one(TypeCtor::Array, byte_type); | 653 | let array_type = Ty::apply_one(TypeCtor::Array, byte_type); |
597 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) | 654 | Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type) |
598 | } | 655 | } |
599 | Literal::Char(..) => Ty::simple(TypeCtor::Char), | 656 | Literal::Char(..) => Ty::simple(TypeCtor::Char), |
600 | Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())), | 657 | Literal::Int(_v, ty) => match ty { |
601 | Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float((*ty).into())), | 658 | Some(int_ty) => Ty::simple(TypeCtor::Int((*int_ty).into())), |
659 | None => self.table.new_integer_var(), | ||
660 | }, | ||
661 | Literal::Float(_v, ty) => match ty { | ||
662 | Some(float_ty) => Ty::simple(TypeCtor::Float((*float_ty).into())), | ||
663 | None => self.table.new_float_var(), | ||
664 | }, | ||
602 | }, | 665 | }, |
603 | }; | 666 | }; |
604 | // use a new type variable if we got Ty::Unknown here | 667 | // use a new type variable if we got Ty::Unknown here |
@@ -727,11 +790,7 @@ impl<'a> InferenceContext<'a> { | |||
727 | for &check_closures in &[false, true] { | 790 | for &check_closures in &[false, true] { |
728 | let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown)); | 791 | let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown)); |
729 | for (&arg, param_ty) in args.iter().zip(param_iter) { | 792 | for (&arg, param_ty) in args.iter().zip(param_iter) { |
730 | let is_closure = match &self.body[arg] { | 793 | let is_closure = matches!(&self.body[arg], Expr::Lambda { .. }); |
731 | Expr::Lambda { .. } => true, | ||
732 | _ => false, | ||
733 | }; | ||
734 | |||
735 | if is_closure != check_closures { | 794 | if is_closure != check_closures { |
736 | continue; | 795 | continue; |
737 | } | 796 | } |
@@ -795,7 +854,7 @@ impl<'a> InferenceContext<'a> { | |||
795 | } | 854 | } |
796 | // add obligation for trait implementation, if this is a trait method | 855 | // add obligation for trait implementation, if this is a trait method |
797 | match def { | 856 | match def { |
798 | CallableDef::FunctionId(f) => { | 857 | CallableDefId::FunctionId(f) => { |
799 | if let AssocContainerId::TraitId(trait_) = | 858 | if let AssocContainerId::TraitId(trait_) = |
800 | f.lookup(self.db.upcast()).container | 859 | f.lookup(self.db.upcast()).container |
801 | { | 860 | { |
@@ -806,7 +865,7 @@ impl<'a> InferenceContext<'a> { | |||
806 | self.obligations.push(Obligation::Trait(TraitRef { trait_, substs })); | 865 | self.obligations.push(Obligation::Trait(TraitRef { trait_, substs })); |
807 | } | 866 | } |
808 | } | 867 | } |
809 | CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {} | 868 | CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {} |
810 | } | 869 | } |
811 | } | 870 | } |
812 | } | 871 | } |
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index 4006f595d..4dd4f9802 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs | |||
@@ -4,7 +4,7 @@ use std::iter::repeat; | |||
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | expr::{BindingAnnotation, Pat, PatId, RecordFieldPat}, | 7 | expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat}, |
8 | path::Path, | 8 | path::Path, |
9 | type_ref::Mutability, | 9 | type_ref::Mutability, |
10 | FieldId, | 10 | FieldId, |
@@ -90,18 +90,7 @@ impl<'a> InferenceContext<'a> { | |||
90 | ) -> Ty { | 90 | ) -> Ty { |
91 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 91 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
92 | 92 | ||
93 | let is_non_ref_pat = match &body[pat] { | 93 | if is_non_ref_pat(&body, pat) { |
94 | Pat::Tuple { .. } | ||
95 | | Pat::Or(..) | ||
96 | | Pat::TupleStruct { .. } | ||
97 | | Pat::Record { .. } | ||
98 | | Pat::Range { .. } | ||
99 | | Pat::Slice { .. } => true, | ||
100 | // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. | ||
101 | Pat::Path(..) | Pat::Lit(..) => true, | ||
102 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, | ||
103 | }; | ||
104 | if is_non_ref_pat { | ||
105 | while let Some((inner, mutability)) = expected.as_reference() { | 94 | while let Some((inner, mutability)) = expected.as_reference() { |
106 | expected = inner; | 95 | expected = inner; |
107 | default_bm = match default_bm { | 96 | default_bm = match default_bm { |
@@ -195,7 +184,7 @@ impl<'a> InferenceContext<'a> { | |||
195 | self.write_pat_ty(pat, bound_ty); | 184 | self.write_pat_ty(pat, bound_ty); |
196 | return inner_ty; | 185 | return inner_ty; |
197 | } | 186 | } |
198 | Pat::Slice { prefix, slice: _slice, suffix } => { | 187 | Pat::Slice { prefix, slice, suffix } => { |
199 | let (container_ty, elem_ty) = match &expected { | 188 | let (container_ty, elem_ty) = match &expected { |
200 | ty_app!(TypeCtor::Array, st) => (TypeCtor::Array, st.as_single().clone()), | 189 | ty_app!(TypeCtor::Array, st) => (TypeCtor::Array, st.as_single().clone()), |
201 | ty_app!(TypeCtor::Slice, st) => (TypeCtor::Slice, st.as_single().clone()), | 190 | ty_app!(TypeCtor::Slice, st) => (TypeCtor::Slice, st.as_single().clone()), |
@@ -206,7 +195,12 @@ impl<'a> InferenceContext<'a> { | |||
206 | self.infer_pat(*pat_id, &elem_ty, default_bm); | 195 | self.infer_pat(*pat_id, &elem_ty, default_bm); |
207 | } | 196 | } |
208 | 197 | ||
209 | Ty::apply_one(container_ty, elem_ty) | 198 | let pat_ty = Ty::apply_one(container_ty, elem_ty); |
199 | if let Some(slice_pat_id) = slice { | ||
200 | self.infer_pat(*slice_pat_id, &pat_ty, default_bm); | ||
201 | } | ||
202 | |||
203 | pat_ty | ||
210 | } | 204 | } |
211 | Pat::Wild => expected.clone(), | 205 | Pat::Wild => expected.clone(), |
212 | Pat::Range { start, end } => { | 206 | Pat::Range { start, end } => { |
@@ -227,3 +221,21 @@ impl<'a> InferenceContext<'a> { | |||
227 | ty | 221 | ty |
228 | } | 222 | } |
229 | } | 223 | } |
224 | |||
225 | fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | ||
226 | match &body[pat] { | ||
227 | Pat::Tuple { .. } | ||
228 | | Pat::TupleStruct { .. } | ||
229 | | Pat::Record { .. } | ||
230 | | Pat::Range { .. } | ||
231 | | Pat::Slice { .. } => true, | ||
232 | Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), | ||
233 | // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. | ||
234 | Pat::Path(..) => true, | ||
235 | Pat::Lit(expr) => match body[*expr] { | ||
236 | Expr::Literal(Literal::String(..)) => false, | ||
237 | _ => true, | ||
238 | }, | ||
239 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, | ||
240 | } | ||
241 | } | ||
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 1c2e56fb0..80d7ed10e 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs | |||
@@ -81,7 +81,7 @@ impl<'a> InferenceContext<'a> { | |||
81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | 81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); |
82 | let substs = Substs::type_params_for_generics(&generics); | 82 | let substs = Substs::type_params_for_generics(&generics); |
83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | 83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); |
84 | if let Some((AdtId::StructId(struct_id), _)) = ty.as_adt() { | 84 | if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { |
85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); | 85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); |
86 | return Some(ty); | 86 | return Some(ty); |
87 | } else { | 87 | } else { |
@@ -95,7 +95,7 @@ impl<'a> InferenceContext<'a> { | |||
95 | // self_subst is just for the parent | 95 | // self_subst is just for the parent |
96 | let parent_substs = self_subst.unwrap_or_else(Substs::empty); | 96 | let parent_substs = self_subst.unwrap_or_else(Substs::empty); |
97 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); | 97 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); |
98 | let substs = Ty::substs_from_path(&ctx, path, typable); | 98 | let substs = Ty::substs_from_path(&ctx, path, typable, true); |
99 | let full_substs = Substs::builder(substs.len()) | 99 | let full_substs = Substs::builder(substs.len()) |
100 | .use_parent_substs(&parent_substs) | 100 | .use_parent_substs(&parent_substs) |
101 | .fill(substs.0[parent_substs.len()..].iter().cloned()) | 101 | .fill(substs.0[parent_substs.len()..].iter().cloned()) |
@@ -141,6 +141,7 @@ impl<'a> InferenceContext<'a> { | |||
141 | def, | 141 | def, |
142 | resolved_segment, | 142 | resolved_segment, |
143 | remaining_segments_for_ty, | 143 | remaining_segments_for_ty, |
144 | true, | ||
144 | ); | 145 | ); |
145 | if let Ty::Unknown = ty { | 146 | if let Ty::Unknown = ty { |
146 | return None; | 147 | return None; |
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index 269495ca0..2e895d911 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -9,7 +9,7 @@ use test_utils::mark; | |||
9 | use super::{InferenceContext, Obligation}; | 9 | use super::{InferenceContext, Obligation}; |
10 | use crate::{ | 10 | use crate::{ |
11 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, | 11 | BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, |
12 | TypeCtor, TypeWalk, | 12 | TyKind, TypeCtor, TypeWalk, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | impl<'a> InferenceContext<'a> { | 15 | impl<'a> InferenceContext<'a> { |
@@ -86,10 +86,20 @@ where | |||
86 | } | 86 | } |
87 | 87 | ||
88 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { | 88 | fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { |
89 | Canonicalized { | 89 | let kinds = self |
90 | value: Canonical { value: result, num_vars: self.free_vars.len() }, | 90 | .free_vars |
91 | free_vars: self.free_vars, | 91 | .iter() |
92 | } | 92 | .map(|v| match v { |
93 | // mapping MaybeNeverTypeVar to the same kind as general ones | ||
94 | // should be fine, because as opposed to int or float type vars, | ||
95 | // they don't restrict what kind of type can go into them, they | ||
96 | // just affect fallback. | ||
97 | InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General, | ||
98 | InferTy::IntVar(_) => TyKind::Integer, | ||
99 | InferTy::FloatVar(_) => TyKind::Float, | ||
100 | }) | ||
101 | .collect(); | ||
102 | Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars } | ||
93 | } | 103 | } |
94 | 104 | ||
95 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { | 105 | pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { |
@@ -131,26 +141,41 @@ impl<T> Canonicalized<T> { | |||
131 | ty | 141 | ty |
132 | } | 142 | } |
133 | 143 | ||
134 | pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Vec<Ty>>) { | 144 | pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Substs>) { |
135 | // the solution may contain new variables, which we need to convert to new inference vars | 145 | // the solution may contain new variables, which we need to convert to new inference vars |
136 | let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect()); | 146 | let new_vars = Substs( |
147 | solution | ||
148 | .kinds | ||
149 | .iter() | ||
150 | .map(|k| match k { | ||
151 | TyKind::General => ctx.table.new_type_var(), | ||
152 | TyKind::Integer => ctx.table.new_integer_var(), | ||
153 | TyKind::Float => ctx.table.new_float_var(), | ||
154 | }) | ||
155 | .collect(), | ||
156 | ); | ||
137 | for (i, ty) in solution.value.into_iter().enumerate() { | 157 | for (i, ty) in solution.value.into_iter().enumerate() { |
138 | let var = self.free_vars[i]; | 158 | let var = self.free_vars[i]; |
139 | // eagerly replace projections in the type; we may be getting types | 159 | // eagerly replace projections in the type; we may be getting types |
140 | // e.g. from where clauses where this hasn't happened yet | 160 | // e.g. from where clauses where this hasn't happened yet |
141 | let ty = ctx.normalize_associated_types_in(ty.subst_bound_vars(&new_vars)); | 161 | let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars)); |
142 | ctx.table.unify(&Ty::Infer(var), &ty); | 162 | ctx.table.unify(&Ty::Infer(var), &ty); |
143 | } | 163 | } |
144 | } | 164 | } |
145 | } | 165 | } |
146 | 166 | ||
147 | pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { | 167 | pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> { |
148 | let mut table = InferenceTable::new(); | 168 | let mut table = InferenceTable::new(); |
149 | let num_vars = ty1.num_vars.max(ty2.num_vars); | 169 | let vars = Substs( |
150 | let vars = | 170 | tys.kinds |
151 | Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); | 171 | .iter() |
152 | let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars); | 172 | // we always use type vars here because we want everything to |
153 | let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars); | 173 | // fallback to Unknown in the end (kind of hacky, as below) |
174 | .map(|_| table.new_type_var()) | ||
175 | .collect(), | ||
176 | ); | ||
177 | let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars); | ||
178 | let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars); | ||
154 | if !table.unify(&ty1_with_vars, &ty2_with_vars) { | 179 | if !table.unify(&ty1_with_vars, &ty2_with_vars) { |
155 | return None; | 180 | return None; |
156 | } | 181 | } |
@@ -162,7 +187,7 @@ pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { | |||
162 | } | 187 | } |
163 | } | 188 | } |
164 | Some( | 189 | Some( |
165 | Substs::builder(ty1.num_vars) | 190 | Substs::builder(tys.kinds.len()) |
166 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) | 191 | .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) |
167 | .build(), | 192 | .build(), |
168 | ) | 193 | ) |