diff options
author | Florian Diebold <[email protected]> | 2018-12-29 22:20:12 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-01-04 18:13:50 +0000 |
commit | 538147bf94b4c52a945c975b67e8d557998f9052 (patch) | |
tree | 667dc8e07cc92335de0ae1ca6e5ddcba7db1fa11 /crates | |
parent | d4db61b9a151a2a46c4067e61b0a4b1a9e3c73ec (diff) |
Resolve the Self type
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/name.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 86 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0007_self.txt | 4 |
3 files changed, 71 insertions, 24 deletions
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 51e8b3da8..017caf442 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -51,6 +51,7 @@ impl Name { | |||
51 | "u128" => KnownName::U128, | 51 | "u128" => KnownName::U128, |
52 | "f32" => KnownName::F32, | 52 | "f32" => KnownName::F32, |
53 | "f64" => KnownName::F64, | 53 | "f64" => KnownName::F64, |
54 | "Self" => KnownName::Self_, | ||
54 | _ => return None, | 55 | _ => return None, |
55 | }; | 56 | }; |
56 | Some(name) | 57 | Some(name) |
@@ -84,7 +85,7 @@ impl AsName for ra_db::Dependency { | |||
84 | // const ISIZE: Name = Name::new("isize") | 85 | // const ISIZE: Name = Name::new("isize") |
85 | // ``` | 86 | // ``` |
86 | // but const-fn is not that powerful yet. | 87 | // but const-fn is not that powerful yet. |
87 | #[derive(Debug)] | 88 | #[derive(Debug, PartialEq, Eq)] |
88 | pub(crate) enum KnownName { | 89 | pub(crate) enum KnownName { |
89 | Isize, | 90 | Isize, |
90 | I8, | 91 | I8, |
@@ -102,4 +103,6 @@ pub(crate) enum KnownName { | |||
102 | 103 | ||
103 | F32, | 104 | F32, |
104 | F64, | 105 | F64, |
106 | |||
107 | Self_, | ||
105 | } | 108 | } |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 5ea62a14c..d11f80cff 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 | ||
33 | use crate::{ | 33 | use 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())); | ||
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 { | |||
402 | fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { | 420 | fn 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. |
@@ -499,12 +519,18 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
499 | /// The self param for the current method, if it exists. | 519 | /// The self param for the current method, if it exists. |
500 | self_param: Option<LocalSyntaxPtr>, | 520 | self_param: Option<LocalSyntaxPtr>, |
501 | module: Module, | 521 | module: Module, |
522 | impl_block: Option<ImplBlock>, | ||
502 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 523 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
503 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, | 524 | type_of: FxHashMap<LocalSyntaxPtr, Ty>, |
504 | } | 525 | } |
505 | 526 | ||
506 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 527 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
507 | fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self { | 528 | fn new( |
529 | db: &'a D, | ||
530 | scopes: Arc<FnScopes>, | ||
531 | module: Module, | ||
532 | impl_block: Option<ImplBlock>, | ||
533 | ) -> Self { | ||
508 | InferenceContext { | 534 | InferenceContext { |
509 | type_of: FxHashMap::default(), | 535 | type_of: FxHashMap::default(), |
510 | var_unification_table: InPlaceUnificationTable::new(), | 536 | var_unification_table: InPlaceUnificationTable::new(), |
@@ -512,6 +538,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
512 | db, | 538 | db, |
513 | scopes, | 539 | scopes, |
514 | module, | 540 | module, |
541 | impl_block, | ||
515 | } | 542 | } |
516 | } | 543 | } |
517 | 544 | ||
@@ -835,7 +862,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
835 | } | 862 | } |
836 | ast::Expr::CastExpr(e) => { | 863 | ast::Expr::CastExpr(e) => { |
837 | let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 864 | let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; |
838 | let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?; | 865 | let cast_ty = Ty::from_ast_opt( |
866 | self.db, | ||
867 | &self.module, | ||
868 | self.impl_block.as_ref(), | ||
869 | e.type_ref(), | ||
870 | )?; | ||
839 | let cast_ty = self.insert_type_vars(cast_ty); | 871 | let cast_ty = self.insert_type_vars(cast_ty); |
840 | // TODO do the coercion... | 872 | // TODO do the coercion... |
841 | cast_ty | 873 | cast_ty |
@@ -889,7 +921,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
889 | for stmt in node.statements() { | 921 | for stmt in node.statements() { |
890 | match stmt { | 922 | match stmt { |
891 | ast::Stmt::LetStmt(stmt) => { | 923 | ast::Stmt::LetStmt(stmt) => { |
892 | let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?; | 924 | let decl_ty = Ty::from_ast_opt( |
925 | self.db, | ||
926 | &self.module, | ||
927 | self.impl_block.as_ref(), | ||
928 | stmt.type_ref(), | ||
929 | )?; | ||
893 | let decl_ty = self.insert_type_vars(decl_ty); | 930 | let decl_ty = self.insert_type_vars(decl_ty); |
894 | let ty = if let Some(expr) = stmt.initializer() { | 931 | let ty = if let Some(expr) = stmt.initializer() { |
895 | let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?; | 932 | let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?; |
@@ -921,19 +958,26 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe | |||
921 | let function = Function::new(def_id); // TODO: consts also need inference | 958 | let function = Function::new(def_id); // TODO: consts also need inference |
922 | let scopes = function.scopes(db); | 959 | let scopes = function.scopes(db); |
923 | let module = function.module(db)?; | 960 | let module = function.module(db)?; |
924 | let mut ctx = InferenceContext::new(db, scopes, module); | 961 | let impl_block = function.impl_block(db)?; |
962 | let mut ctx = InferenceContext::new(db, scopes, module, impl_block); | ||
925 | 963 | ||
926 | let syntax = function.syntax(db); | 964 | let syntax = function.syntax(db); |
927 | let node = syntax.borrowed(); | 965 | let node = syntax.borrowed(); |
928 | 966 | ||
929 | if let Some(param_list) = node.param_list() { | 967 | if let Some(param_list) = node.param_list() { |
930 | if let Some(self_param) = param_list.self_param() { | 968 | if let Some(self_param) = param_list.self_param() { |
931 | let self_type = if let Some(impl_block) = function.impl_block(db)? { | 969 | let self_type = if let Some(impl_block) = &ctx.impl_block { |
932 | if let Some(type_ref) = self_param.type_ref() { | 970 | if let Some(type_ref) = self_param.type_ref() { |
933 | let ty = Ty::from_ast(db, &ctx.module, type_ref)?; | 971 | let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?; |
934 | ctx.insert_type_vars(ty) | 972 | ctx.insert_type_vars(ty) |
935 | } else { | 973 | } else { |
936 | let ty = Ty::from_hir(db, &ctx.module, impl_block.target())?; | 974 | // TODO this should be handled by desugaring during HIR conversion |
975 | let ty = Ty::from_hir( | ||
976 | db, | ||
977 | &ctx.module, | ||
978 | ctx.impl_block.as_ref(), | ||
979 | impl_block.target(), | ||
980 | )?; | ||
937 | let ty = match self_param.flavor() { | 981 | let ty = match self_param.flavor() { |
938 | ast::SelfParamFlavor::Owned => ty, | 982 | ast::SelfParamFlavor::Owned => ty, |
939 | ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared), | 983 | ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared), |
@@ -961,7 +1005,7 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe | |||
961 | continue; | 1005 | continue; |
962 | }; | 1006 | }; |
963 | let ty = if let Some(type_ref) = param.type_ref() { | 1007 | let ty = if let Some(type_ref) = param.type_ref() { |
964 | let ty = Ty::from_ast(db, &ctx.module, type_ref)?; | 1008 | let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?; |
965 | ctx.insert_type_vars(ty) | 1009 | ctx.insert_type_vars(ty) |
966 | } else { | 1010 | } else { |
967 | // missing type annotation | 1011 | // missing type annotation |
@@ -972,7 +1016,7 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe | |||
972 | } | 1016 | } |
973 | 1017 | ||
974 | let ret_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) { | 1018 | let ret_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) { |
975 | let ty = Ty::from_ast(db, &ctx.module, type_ref)?; | 1019 | let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?; |
976 | ctx.insert_type_vars(ty) | 1020 | ctx.insert_type_vars(ty) |
977 | } else { | 1021 | } else { |
978 | Ty::unit() | 1022 | Ty::unit() |
diff --git a/crates/ra_hir/src/ty/tests/data/0007_self.txt b/crates/ra_hir/src/ty/tests/data/0007_self.txt index 0dd61da55..db4ba17d0 100644 --- a/crates/ra_hir/src/ty/tests/data/0007_self.txt +++ b/crates/ra_hir/src/ty/tests/data/0007_self.txt | |||
@@ -2,5 +2,5 @@ | |||
2 | [34; 38) 'self': &S | 2 | [34; 38) 'self': &S |
3 | [40; 61) '{ ... }': () | 3 | [40; 61) '{ ... }': () |
4 | [88; 109) '{ ... }': () | 4 | [88; 109) '{ ... }': () |
5 | [98; 102) 'self': &[unknown] | 5 | [98; 102) 'self': &S |
6 | [75; 79) 'self': &[unknown] | 6 | [75; 79) 'self': &S |