aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r--crates/ra_hir/src/ty.rs168
1 files changed, 125 insertions, 43 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 719b3f7cd..e33762e0d 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -31,9 +31,10 @@ use ra_syntax::{
31}; 31};
32 32
33use crate::{ 33use crate::{
34 Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, 34 Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock,
35 db::HirDatabase, 35 db::HirDatabase,
36 type_ref::{TypeRef, Mutability}, 36 type_ref::{TypeRef, Mutability},
37 name::KnownName,
37}; 38};
38 39
39/// The ID of a type variable. 40/// The ID of a type variable.
@@ -235,6 +236,7 @@ impl Ty {
235 pub(crate) fn from_hir( 236 pub(crate) fn from_hir(
236 db: &impl HirDatabase, 237 db: &impl HirDatabase,
237 module: &Module, 238 module: &Module,
239 impl_block: Option<&ImplBlock>,
238 type_ref: &TypeRef, 240 type_ref: &TypeRef,
239 ) -> Cancelable<Self> { 241 ) -> Cancelable<Self> {
240 Ok(match type_ref { 242 Ok(match type_ref {
@@ -242,29 +244,29 @@ impl Ty {
242 TypeRef::Tuple(inner) => { 244 TypeRef::Tuple(inner) => {
243 let inner_tys = inner 245 let inner_tys = inner
244 .iter() 246 .iter()
245 .map(|tr| Ty::from_hir(db, module, tr)) 247 .map(|tr| Ty::from_hir(db, module, impl_block, tr))
246 .collect::<Cancelable<Vec<_>>>()?; 248 .collect::<Cancelable<Vec<_>>>()?;
247 Ty::Tuple(inner_tys.into()) 249 Ty::Tuple(inner_tys.into())
248 } 250 }
249 TypeRef::Path(path) => Ty::from_hir_path(db, module, path)?, 251 TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, path)?,
250 TypeRef::RawPtr(inner, mutability) => { 252 TypeRef::RawPtr(inner, mutability) => {
251 let inner_ty = Ty::from_hir(db, module, inner)?; 253 let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
252 Ty::RawPtr(Arc::new(inner_ty), *mutability) 254 Ty::RawPtr(Arc::new(inner_ty), *mutability)
253 } 255 }
254 TypeRef::Array(_inner) => Ty::Unknown, // TODO 256 TypeRef::Array(_inner) => Ty::Unknown, // TODO
255 TypeRef::Slice(inner) => { 257 TypeRef::Slice(inner) => {
256 let inner_ty = Ty::from_hir(db, module, inner)?; 258 let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
257 Ty::Slice(Arc::new(inner_ty)) 259 Ty::Slice(Arc::new(inner_ty))
258 } 260 }
259 TypeRef::Reference(inner, mutability) => { 261 TypeRef::Reference(inner, mutability) => {
260 let inner_ty = Ty::from_hir(db, module, inner)?; 262 let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
261 Ty::Ref(Arc::new(inner_ty), *mutability) 263 Ty::Ref(Arc::new(inner_ty), *mutability)
262 } 264 }
263 TypeRef::Placeholder => Ty::Unknown, 265 TypeRef::Placeholder => Ty::Unknown,
264 TypeRef::Fn(params) => { 266 TypeRef::Fn(params) => {
265 let mut inner_tys = params 267 let mut inner_tys = params
266 .iter() 268 .iter()
267 .map(|tr| Ty::from_hir(db, module, tr)) 269 .map(|tr| Ty::from_hir(db, module, impl_block, tr))
268 .collect::<Cancelable<Vec<_>>>()?; 270 .collect::<Cancelable<Vec<_>>>()?;
269 let return_ty = inner_tys 271 let return_ty = inner_tys
270 .pop() 272 .pop()
@@ -279,9 +281,21 @@ impl Ty {
279 }) 281 })
280 } 282 }
281 283
284 pub(crate) fn from_hir_opt(
285 db: &impl HirDatabase,
286 module: &Module,
287 impl_block: Option<&ImplBlock>,
288 type_ref: Option<&TypeRef>,
289 ) -> Cancelable<Self> {
290 type_ref
291 .map(|t| Ty::from_hir(db, module, impl_block, t))
292 .unwrap_or(Ok(Ty::Unknown))
293 }
294
282 pub(crate) fn from_hir_path( 295 pub(crate) fn from_hir_path(
283 db: &impl HirDatabase, 296 db: &impl HirDatabase,
284 module: &Module, 297 module: &Module,
298 impl_block: Option<&ImplBlock>,
285 path: &Path, 299 path: &Path,
286 ) -> Cancelable<Self> { 300 ) -> Cancelable<Self> {
287 if let Some(name) = path.as_ident() { 301 if let Some(name) = path.as_ident() {
@@ -291,6 +305,8 @@ impl Ty {
291 return Ok(Ty::Uint(uint_ty)); 305 return Ok(Ty::Uint(uint_ty));
292 } else if let Some(float_ty) = primitive::FloatTy::from_name(name) { 306 } else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
293 return Ok(Ty::Float(float_ty)); 307 return Ok(Ty::Float(float_ty));
308 } else if name.as_known_name() == Some(KnownName::Self_) {
309 return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type()));
294 } 310 }
295 } 311 }
296 312
@@ -308,18 +324,20 @@ impl Ty {
308 pub(crate) fn from_ast_opt( 324 pub(crate) fn from_ast_opt(
309 db: &impl HirDatabase, 325 db: &impl HirDatabase,
310 module: &Module, 326 module: &Module,
327 impl_block: Option<&ImplBlock>,
311 node: Option<ast::TypeRef>, 328 node: Option<ast::TypeRef>,
312 ) -> Cancelable<Self> { 329 ) -> Cancelable<Self> {
313 node.map(|n| Ty::from_ast(db, module, n)) 330 node.map(|n| Ty::from_ast(db, module, impl_block, n))
314 .unwrap_or(Ok(Ty::Unknown)) 331 .unwrap_or(Ok(Ty::Unknown))
315 } 332 }
316 333
317 pub(crate) fn from_ast( 334 pub(crate) fn from_ast(
318 db: &impl HirDatabase, 335 db: &impl HirDatabase,
319 module: &Module, 336 module: &Module,
337 impl_block: Option<&ImplBlock>,
320 node: ast::TypeRef, 338 node: ast::TypeRef,
321 ) -> Cancelable<Self> { 339 ) -> Cancelable<Self> {
322 Ty::from_hir(db, module, &TypeRef::from_ast(node)) 340 Ty::from_hir(db, module, impl_block, &TypeRef::from_ast(node))
323 } 341 }
324 342
325 pub fn unit() -> Self { 343 pub fn unit() -> Self {
@@ -402,18 +420,19 @@ impl fmt::Display for Ty {
402fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { 420fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
403 let syntax = f.syntax(db); 421 let syntax = f.syntax(db);
404 let module = f.module(db)?; 422 let module = f.module(db)?;
423 let impl_block = f.impl_block(db)?;
405 let node = syntax.borrowed(); 424 let node = syntax.borrowed();
406 // TODO we ignore type parameters for now 425 // TODO we ignore type parameters for now
407 let input = node 426 let input = node
408 .param_list() 427 .param_list()
409 .map(|pl| { 428 .map(|pl| {
410 pl.params() 429 pl.params()
411 .map(|p| Ty::from_ast_opt(db, &module, p.type_ref())) 430 .map(|p| Ty::from_ast_opt(db, &module, impl_block.as_ref(), p.type_ref()))
412 .collect() 431 .collect()
413 }) 432 })
414 .unwrap_or_else(|| Ok(Vec::new()))?; 433 .unwrap_or_else(|| Ok(Vec::new()))?;
415 let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) { 434 let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) {
416 Ty::from_ast(db, &module, type_ref)? 435 Ty::from_ast(db, &module, impl_block.as_ref(), type_ref)?
417 } else { 436 } else {
418 Ty::unit() 437 Ty::unit()
419 }; 438 };
@@ -467,12 +486,13 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name)
467 ), 486 ),
468 }; 487 };
469 let module = def_id.module(db)?; 488 let module = def_id.module(db)?;
489 let impl_block = def_id.impl_block(db)?;
470 let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) { 490 let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) {
471 tr 491 tr
472 } else { 492 } else {
473 return Ok(Ty::Unknown); 493 return Ok(Ty::Unknown);
474 }; 494 };
475 Ty::from_hir(db, &module, &type_ref) 495 Ty::from_hir(db, &module, impl_block.as_ref(), &type_ref)
476} 496}
477 497
478/// The result of type inference: A mapping from expressions and patterns to types. 498/// The result of type inference: A mapping from expressions and patterns to types.
@@ -496,19 +516,32 @@ impl InferenceResult {
496struct InferenceContext<'a, D: HirDatabase> { 516struct InferenceContext<'a, D: HirDatabase> {
497 db: &'a D, 517 db: &'a D,
498 scopes: Arc<FnScopes>, 518 scopes: Arc<FnScopes>,
519 /// The self param for the current method, if it exists.
520 self_param: Option<LocalSyntaxPtr>,
499 module: Module, 521 module: Module,
522 impl_block: Option<ImplBlock>,
500 var_unification_table: InPlaceUnificationTable<TypeVarId>, 523 var_unification_table: InPlaceUnificationTable<TypeVarId>,
501 type_of: FxHashMap<LocalSyntaxPtr, Ty>, 524 type_of: FxHashMap<LocalSyntaxPtr, Ty>,
525 /// The return type of the function being inferred.
526 return_ty: Ty,
502} 527}
503 528
504impl<'a, D: HirDatabase> InferenceContext<'a, D> { 529impl<'a, D: HirDatabase> InferenceContext<'a, D> {
505 fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self { 530 fn new(
531 db: &'a D,
532 scopes: Arc<FnScopes>,
533 module: Module,
534 impl_block: Option<ImplBlock>,
535 ) -> Self {
506 InferenceContext { 536 InferenceContext {
507 type_of: FxHashMap::default(), 537 type_of: FxHashMap::default(),
508 var_unification_table: InPlaceUnificationTable::new(), 538 var_unification_table: InPlaceUnificationTable::new(),
539 self_param: None, // set during parameter typing
540 return_ty: Ty::Unknown, // set in collect_fn_signature
509 db, 541 db,
510 scopes, 542 scopes,
511 module, 543 module,
544 impl_block,
512 } 545 }
513 } 546 }
514 547
@@ -525,6 +558,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
525 self.type_of.insert(LocalSyntaxPtr::new(node), ty); 558 self.type_of.insert(LocalSyntaxPtr::new(node), ty);
526 } 559 }
527 560
561 fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> {
562 Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref)
563 }
564
565 fn make_ty_opt(&self, type_ref: Option<&TypeRef>) -> Cancelable<Ty> {
566 Ty::from_hir_opt(self.db, &self.module, self.impl_block.as_ref(), type_ref)
567 }
568
528 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 569 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
529 match (ty1, ty2) { 570 match (ty1, ty2) {
530 (Ty::Unknown, ..) => true, 571 (Ty::Unknown, ..) => true,
@@ -628,6 +669,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
628 let ty = self.resolve_ty_as_possible(ty.clone()); 669 let ty = self.resolve_ty_as_possible(ty.clone());
629 return Ok(Some(ty)); 670 return Ok(Some(ty));
630 }; 671 };
672 } else if path.is_self() {
673 // resolve `self` param
674 let self_param = ctry!(self.self_param);
675 let ty = ctry!(self.type_of.get(&self_param));
676 let ty = self.resolve_ty_as_possible(ty.clone());
677 return Ok(Some(ty));
631 }; 678 };
632 679
633 // resolve in module 680 // resolve in module
@@ -826,7 +873,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
826 } 873 }
827 ast::Expr::CastExpr(e) => { 874 ast::Expr::CastExpr(e) => {
828 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; 875 let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
829 let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?; 876 let cast_ty = Ty::from_ast_opt(
877 self.db,
878 &self.module,
879 self.impl_block.as_ref(),
880 e.type_ref(),
881 )?;
830 let cast_ty = self.insert_type_vars(cast_ty); 882 let cast_ty = self.insert_type_vars(cast_ty);
831 // TODO do the coercion... 883 // TODO do the coercion...
832 cast_ty 884 cast_ty
@@ -880,7 +932,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
880 for stmt in node.statements() { 932 for stmt in node.statements() {
881 match stmt { 933 match stmt {
882 ast::Stmt::LetStmt(stmt) => { 934 ast::Stmt::LetStmt(stmt) => {
883 let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?; 935 let decl_ty = Ty::from_ast_opt(
936 self.db,
937 &self.module,
938 self.impl_block.as_ref(),
939 stmt.type_ref(),
940 )?;
884 let decl_ty = self.insert_type_vars(decl_ty); 941 let decl_ty = self.insert_type_vars(decl_ty);
885 let ty = if let Some(expr) = stmt.initializer() { 942 let ty = if let Some(expr) = stmt.initializer() {
886 let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?; 943 let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?;
@@ -906,46 +963,71 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
906 self.write_ty(node.syntax(), ty.clone()); 963 self.write_ty(node.syntax(), ty.clone());
907 Ok(ty) 964 Ok(ty)
908 } 965 }
966
967 fn collect_fn_signature(&mut self, node: ast::FnDef) -> Cancelable<()> {
968 if let Some(param_list) = node.param_list() {
969 if let Some(self_param) = param_list.self_param() {
970 let self_type = if let Some(type_ref) = self_param.type_ref() {
971 let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
972 self.insert_type_vars(ty)
973 } else {
974 // TODO this should be handled by desugaring during HIR conversion
975 let ty = self.make_ty_opt(self.impl_block.as_ref().map(|i| i.target_type()))?;
976 let ty = match self_param.flavor() {
977 ast::SelfParamFlavor::Owned => ty,
978 ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared),
979 ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut),
980 };
981 self.insert_type_vars(ty)
982 };
983 if let Some(self_kw) = self_param.self_kw() {
984 let self_param = LocalSyntaxPtr::new(self_kw.syntax());
985 self.self_param = Some(self_param);
986 self.type_of.insert(self_param, self_type);
987 }
988 }
989 for param in param_list.params() {
990 let pat = if let Some(pat) = param.pat() {
991 pat
992 } else {
993 continue;
994 };
995 let ty = if let Some(type_ref) = param.type_ref() {
996 let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
997 self.insert_type_vars(ty)
998 } else {
999 // missing type annotation
1000 self.new_type_var()
1001 };
1002 self.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
1003 }
1004 }
1005
1006 self.return_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) {
1007 let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
1008 self.insert_type_vars(ty)
1009 } else {
1010 Ty::unit()
1011 };
1012
1013 Ok(())
1014 }
909} 1015}
910 1016
911pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { 1017pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
912 let function = Function::new(def_id); // TODO: consts also need inference 1018 let function = Function::new(def_id); // TODO: consts also need inference
913 let scopes = function.scopes(db); 1019 let scopes = function.scopes(db);
914 let module = function.module(db)?; 1020 let module = function.module(db)?;
915 let mut ctx = InferenceContext::new(db, scopes, module); 1021 let impl_block = function.impl_block(db)?;
1022 let mut ctx = InferenceContext::new(db, scopes, module, impl_block);
916 1023
917 let syntax = function.syntax(db); 1024 let syntax = function.syntax(db);
918 let node = syntax.borrowed(); 1025 let node = syntax.borrowed();
919 1026
920 if let Some(param_list) = node.param_list() { 1027 ctx.collect_fn_signature(node)?;
921 for param in param_list.params() {
922 let pat = if let Some(pat) = param.pat() {
923 pat
924 } else {
925 continue;
926 };
927 if let Some(type_ref) = param.type_ref() {
928 let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
929 let ty = ctx.insert_type_vars(ty);
930 ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
931 } else {
932 // TODO self param
933 let type_var = ctx.new_type_var();
934 ctx.type_of
935 .insert(LocalSyntaxPtr::new(pat.syntax()), type_var);
936 };
937 }
938 }
939
940 let ret_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) {
941 let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
942 ctx.insert_type_vars(ty)
943 } else {
944 Ty::unit()
945 };
946 1028
947 if let Some(block) = node.body() { 1029 if let Some(block) = node.body() {
948 ctx.infer_block(block, &Expectation::has_type(ret_ty))?; 1030 ctx.infer_block(block, &Expectation::has_type(ctx.return_ty.clone()))?;
949 } 1031 }
950 1032
951 Ok(Arc::new(ctx.resolve_all())) 1033 Ok(Arc::new(ctx.resolve_all()))