diff options
Diffstat (limited to 'crates/ra_hir_ty/src/infer.rs')
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 79 |
1 files changed, 66 insertions, 13 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index fb7c6cd8c..2876cb141 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -28,7 +28,8 @@ use hir_def::{ | |||
28 | path::{path, Path}, | 28 | path::{path, Path}, |
29 | resolver::{HasResolver, Resolver, TypeNs}, | 29 | resolver::{HasResolver, Resolver, TypeNs}, |
30 | type_ref::{Mutability, TypeRef}, | 30 | type_ref::{Mutability, TypeRef}, |
31 | AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, TraitId, TypeAliasId, VariantId, | 31 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, TraitId, TypeAliasId, |
32 | VariantId, | ||
32 | }; | 33 | }; |
33 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; | 34 | use hir_expand::{diagnostics::DiagnosticSink, name::name}; |
34 | use ra_arena::map::ArenaMap; | 35 | use ra_arena::map::ArenaMap; |
@@ -438,43 +439,95 @@ impl<'a> InferenceContext<'a> { | |||
438 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); | 439 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); |
439 | // FIXME: this should resolve assoc items as well, see this example: | 440 | // FIXME: this should resolve assoc items as well, see this example: |
440 | // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 | 441 | // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 |
441 | return match resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path()) { | 442 | let (resolution, unresolved) = |
442 | Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { | 443 | match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { |
444 | Some(it) => it, | ||
445 | None => return (Ty::Unknown, None), | ||
446 | }; | ||
447 | return match resolution { | ||
448 | TypeNs::AdtId(AdtId::StructId(strukt)) => { | ||
443 | let substs = Ty::substs_from_path(&ctx, path, strukt.into()); | 449 | let substs = Ty::substs_from_path(&ctx, path, strukt.into()); |
444 | let ty = self.db.ty(strukt.into()); | 450 | let ty = self.db.ty(strukt.into()); |
445 | let ty = self.insert_type_vars(ty.subst(&substs)); | 451 | let ty = self.insert_type_vars(ty.subst(&substs)); |
446 | (ty, Some(strukt.into())) | 452 | forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) |
447 | } | 453 | } |
448 | Some(TypeNs::EnumVariantId(var)) => { | 454 | TypeNs::EnumVariantId(var) => { |
449 | let substs = Ty::substs_from_path(&ctx, path, var.into()); | 455 | let substs = Ty::substs_from_path(&ctx, path, var.into()); |
450 | let ty = self.db.ty(var.parent.into()); | 456 | let ty = self.db.ty(var.parent.into()); |
451 | let ty = self.insert_type_vars(ty.subst(&substs)); | 457 | let ty = self.insert_type_vars(ty.subst(&substs)); |
452 | (ty, Some(var.into())) | 458 | forbid_unresolved_segments((ty, Some(var.into())), unresolved) |
453 | } | 459 | } |
454 | Some(TypeNs::SelfType(impl_id)) => { | 460 | TypeNs::SelfType(impl_id) => { |
455 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | 461 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); |
456 | let substs = Substs::type_params_for_generics(&generics); | 462 | let substs = Substs::type_params_for_generics(&generics); |
457 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | 463 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); |
458 | let variant = ty_variant(&ty); | 464 | match unresolved { |
459 | (ty, variant) | 465 | None => { |
466 | let variant = ty_variant(&ty); | ||
467 | (ty, variant) | ||
468 | } | ||
469 | Some(1) => { | ||
470 | let segment = path.mod_path().segments.last().unwrap(); | ||
471 | // this could be an enum variant or associated type | ||
472 | if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { | ||
473 | let enum_data = self.db.enum_data(enum_id); | ||
474 | if let Some(local_id) = enum_data.variant(segment) { | ||
475 | let variant = EnumVariantId { parent: enum_id, local_id }; | ||
476 | return (ty, Some(variant.into())); | ||
477 | } | ||
478 | } | ||
479 | // FIXME potentially resolve assoc type | ||
480 | (Ty::Unknown, None) | ||
481 | } | ||
482 | Some(_) => { | ||
483 | // FIXME diagnostic | ||
484 | (Ty::Unknown, None) | ||
485 | } | ||
486 | } | ||
460 | } | 487 | } |
461 | Some(TypeNs::TypeAliasId(it)) => { | 488 | TypeNs::TypeAliasId(it) => { |
462 | let substs = Substs::build_for_def(self.db, it) | 489 | let substs = Substs::build_for_def(self.db, it) |
463 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) | 490 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) |
464 | .build(); | 491 | .build(); |
465 | let ty = self.db.ty(it.into()).subst(&substs); | 492 | let ty = self.db.ty(it.into()).subst(&substs); |
466 | let variant = ty_variant(&ty); | 493 | let variant = ty_variant(&ty); |
467 | (ty, variant) | 494 | forbid_unresolved_segments((ty, variant), unresolved) |
495 | } | ||
496 | TypeNs::AdtSelfType(_) => { | ||
497 | // FIXME this could happen in array size expressions, once we're checking them | ||
498 | (Ty::Unknown, None) | ||
499 | } | ||
500 | TypeNs::GenericParam(_) => { | ||
501 | // FIXME potentially resolve assoc type | ||
502 | (Ty::Unknown, None) | ||
503 | } | ||
504 | TypeNs::AdtId(AdtId::EnumId(_)) | ||
505 | | TypeNs::AdtId(AdtId::UnionId(_)) | ||
506 | | TypeNs::BuiltinType(_) | ||
507 | | TypeNs::TraitId(_) => { | ||
508 | // FIXME diagnostic | ||
509 | (Ty::Unknown, None) | ||
468 | } | 510 | } |
469 | Some(_) | None => (Ty::Unknown, None), | ||
470 | }; | 511 | }; |
471 | 512 | ||
513 | fn forbid_unresolved_segments( | ||
514 | result: (Ty, Option<VariantId>), | ||
515 | unresolved: Option<usize>, | ||
516 | ) -> (Ty, Option<VariantId>) { | ||
517 | if unresolved.is_none() { | ||
518 | result | ||
519 | } else { | ||
520 | // FIXME diagnostic | ||
521 | (Ty::Unknown, None) | ||
522 | } | ||
523 | } | ||
524 | |||
472 | fn ty_variant(ty: &Ty) -> Option<VariantId> { | 525 | fn ty_variant(ty: &Ty) -> Option<VariantId> { |
473 | ty.as_adt().and_then(|(adt_id, _)| match adt_id { | 526 | ty.as_adt().and_then(|(adt_id, _)| match adt_id { |
474 | AdtId::StructId(s) => Some(VariantId::StructId(s)), | 527 | AdtId::StructId(s) => Some(VariantId::StructId(s)), |
475 | AdtId::UnionId(u) => Some(VariantId::UnionId(u)), | 528 | AdtId::UnionId(u) => Some(VariantId::UnionId(u)), |
476 | AdtId::EnumId(_) => { | 529 | AdtId::EnumId(_) => { |
477 | // Error E0071, expected struct, variant or union type, found enum `Foo` | 530 | // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` |
478 | None | 531 | None |
479 | } | 532 | } |
480 | }) | 533 | }) |