aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/infer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/infer.rs')
-rw-r--r--crates/ra_hir_ty/src/infer.rs148
1 files changed, 132 insertions, 16 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index bd4ef69a0..957d6e0b5 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -22,13 +22,14 @@ use rustc_hash::FxHashMap;
22 22
23use hir_def::{ 23use hir_def::{
24 body::Body, 24 body::Body,
25 data::{ConstData, FunctionData}, 25 data::{ConstData, FunctionData, StaticData},
26 expr::{BindingAnnotation, ExprId, PatId}, 26 expr::{BindingAnnotation, ExprId, PatId},
27 lang_item::LangItemTarget, 27 lang_item::LangItemTarget,
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};
33use hir_expand::{diagnostics::DiagnosticSink, name::name}; 34use hir_expand::{diagnostics::DiagnosticSink, name::name};
34use ra_arena::map::ArenaMap; 35use ra_arena::map::ArenaMap;
@@ -71,7 +72,7 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
71 match def { 72 match def {
72 DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)), 73 DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
73 DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)), 74 DefWithBodyId::FunctionId(f) => ctx.collect_fn(&db.function_data(f)),
74 DefWithBodyId::StaticId(s) => ctx.collect_const(&db.static_data(s)), 75 DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
75 } 76 }
76 77
77 ctx.infer_body(); 78 ctx.infer_body();
@@ -210,6 +211,14 @@ struct InferenceContext<'a> {
210 /// closures, but currently this is the only field that will change there, 211 /// closures, but currently this is the only field that will change there,
211 /// so it doesn't make sense. 212 /// so it doesn't make sense.
212 return_ty: Ty, 213 return_ty: Ty,
214 diverges: Diverges,
215 breakables: Vec<BreakableContext>,
216}
217
218#[derive(Clone, Debug)]
219struct BreakableContext {
220 pub may_break: bool,
221 pub break_ty: Ty,
213} 222}
214 223
215impl<'a> InferenceContext<'a> { 224impl<'a> InferenceContext<'a> {
@@ -224,6 +233,8 @@ impl<'a> InferenceContext<'a> {
224 owner, 233 owner,
225 body: db.body(owner), 234 body: db.body(owner),
226 resolver, 235 resolver,
236 diverges: Diverges::Maybe,
237 breakables: Vec::new(),
227 } 238 }
228 } 239 }
229 240
@@ -429,43 +440,95 @@ impl<'a> InferenceContext<'a> {
429 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); 440 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
430 // FIXME: this should resolve assoc items as well, see this example: 441 // FIXME: this should resolve assoc items as well, see this example:
431 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 442 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
432 return match resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path.mod_path()) { 443 let (resolution, unresolved) =
433 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { 444 match resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
445 Some(it) => it,
446 None => return (Ty::Unknown, None),
447 };
448 return match resolution {
449 TypeNs::AdtId(AdtId::StructId(strukt)) => {
434 let substs = Ty::substs_from_path(&ctx, path, strukt.into()); 450 let substs = Ty::substs_from_path(&ctx, path, strukt.into());
435 let ty = self.db.ty(strukt.into()); 451 let ty = self.db.ty(strukt.into());
436 let ty = self.insert_type_vars(ty.subst(&substs)); 452 let ty = self.insert_type_vars(ty.subst(&substs));
437 (ty, Some(strukt.into())) 453 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
438 } 454 }
439 Some(TypeNs::EnumVariantId(var)) => { 455 TypeNs::EnumVariantId(var) => {
440 let substs = Ty::substs_from_path(&ctx, path, var.into()); 456 let substs = Ty::substs_from_path(&ctx, path, var.into());
441 let ty = self.db.ty(var.parent.into()); 457 let ty = self.db.ty(var.parent.into());
442 let ty = self.insert_type_vars(ty.subst(&substs)); 458 let ty = self.insert_type_vars(ty.subst(&substs));
443 (ty, Some(var.into())) 459 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
444 } 460 }
445 Some(TypeNs::SelfType(impl_id)) => { 461 TypeNs::SelfType(impl_id) => {
446 let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 462 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
447 let substs = Substs::type_params_for_generics(&generics); 463 let substs = Substs::type_params_for_generics(&generics);
448 let ty = self.db.impl_self_ty(impl_id).subst(&substs); 464 let ty = self.db.impl_self_ty(impl_id).subst(&substs);
449 let variant = ty_variant(&ty); 465 match unresolved {
450 (ty, variant) 466 None => {
467 let variant = ty_variant(&ty);
468 (ty, variant)
469 }
470 Some(1) => {
471 let segment = path.mod_path().segments.last().unwrap();
472 // this could be an enum variant or associated type
473 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
474 let enum_data = self.db.enum_data(enum_id);
475 if let Some(local_id) = enum_data.variant(segment) {
476 let variant = EnumVariantId { parent: enum_id, local_id };
477 return (ty, Some(variant.into()));
478 }
479 }
480 // FIXME potentially resolve assoc type
481 (Ty::Unknown, None)
482 }
483 Some(_) => {
484 // FIXME diagnostic
485 (Ty::Unknown, None)
486 }
487 }
451 } 488 }
452 Some(TypeNs::TypeAliasId(it)) => { 489 TypeNs::TypeAliasId(it) => {
453 let substs = Substs::build_for_def(self.db, it) 490 let substs = Substs::build_for_def(self.db, it)
454 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 491 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
455 .build(); 492 .build();
456 let ty = self.db.ty(it.into()).subst(&substs); 493 let ty = self.db.ty(it.into()).subst(&substs);
457 let variant = ty_variant(&ty); 494 let variant = ty_variant(&ty);
458 (ty, variant) 495 forbid_unresolved_segments((ty, variant), unresolved)
496 }
497 TypeNs::AdtSelfType(_) => {
498 // FIXME this could happen in array size expressions, once we're checking them
499 (Ty::Unknown, None)
500 }
501 TypeNs::GenericParam(_) => {
502 // FIXME potentially resolve assoc type
503 (Ty::Unknown, None)
504 }
505 TypeNs::AdtId(AdtId::EnumId(_))
506 | TypeNs::AdtId(AdtId::UnionId(_))
507 | TypeNs::BuiltinType(_)
508 | TypeNs::TraitId(_) => {
509 // FIXME diagnostic
510 (Ty::Unknown, None)
459 } 511 }
460 Some(_) | None => (Ty::Unknown, None),
461 }; 512 };
462 513
514 fn forbid_unresolved_segments(
515 result: (Ty, Option<VariantId>),
516 unresolved: Option<usize>,
517 ) -> (Ty, Option<VariantId>) {
518 if unresolved.is_none() {
519 result
520 } else {
521 // FIXME diagnostic
522 (Ty::Unknown, None)
523 }
524 }
525
463 fn ty_variant(ty: &Ty) -> Option<VariantId> { 526 fn ty_variant(ty: &Ty) -> Option<VariantId> {
464 ty.as_adt().and_then(|(adt_id, _)| match adt_id { 527 ty.as_adt().and_then(|(adt_id, _)| match adt_id {
465 AdtId::StructId(s) => Some(VariantId::StructId(s)), 528 AdtId::StructId(s) => Some(VariantId::StructId(s)),
466 AdtId::UnionId(u) => Some(VariantId::UnionId(u)), 529 AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
467 AdtId::EnumId(_) => { 530 AdtId::EnumId(_) => {
468 // Error E0071, expected struct, variant or union type, found enum `Foo` 531 // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
469 None 532 None
470 } 533 }
471 }) 534 })
@@ -476,6 +539,10 @@ impl<'a> InferenceContext<'a> {
476 self.return_ty = self.make_ty(&data.type_ref); 539 self.return_ty = self.make_ty(&data.type_ref);
477 } 540 }
478 541
542 fn collect_static(&mut self, data: &StaticData) {
543 self.return_ty = self.make_ty(&data.type_ref);
544 }
545
479 fn collect_fn(&mut self, data: &FunctionData) { 546 fn collect_fn(&mut self, data: &FunctionData) {
480 let body = Arc::clone(&self.body); // avoid borrow checker problem 547 let body = Arc::clone(&self.body); // avoid borrow checker problem
481 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver) 548 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
@@ -666,15 +733,57 @@ impl Expectation {
666 } 733 }
667} 734}
668 735
736#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
737enum Diverges {
738 Maybe,
739 Always,
740}
741
742impl Diverges {
743 fn is_always(self) -> bool {
744 self == Diverges::Always
745 }
746}
747
748impl std::ops::BitAnd for Diverges {
749 type Output = Self;
750 fn bitand(self, other: Self) -> Self {
751 std::cmp::min(self, other)
752 }
753}
754
755impl std::ops::BitOr for Diverges {
756 type Output = Self;
757 fn bitor(self, other: Self) -> Self {
758 std::cmp::max(self, other)
759 }
760}
761
762impl std::ops::BitAndAssign for Diverges {
763 fn bitand_assign(&mut self, other: Self) {
764 *self = *self & other;
765 }
766}
767
768impl std::ops::BitOrAssign for Diverges {
769 fn bitor_assign(&mut self, other: Self) {
770 *self = *self | other;
771 }
772}
773
669mod diagnostics { 774mod diagnostics {
670 use hir_def::{expr::ExprId, FunctionId}; 775 use hir_def::{expr::ExprId, FunctionId};
671 use hir_expand::diagnostics::DiagnosticSink; 776 use hir_expand::diagnostics::DiagnosticSink;
672 777
673 use crate::{db::HirDatabase, diagnostics::NoSuchField}; 778 use crate::{
779 db::HirDatabase,
780 diagnostics::{BreakOutsideOfLoop, NoSuchField},
781 };
674 782
675 #[derive(Debug, PartialEq, Eq, Clone)] 783 #[derive(Debug, PartialEq, Eq, Clone)]
676 pub(super) enum InferenceDiagnostic { 784 pub(super) enum InferenceDiagnostic {
677 NoSuchField { expr: ExprId, field: usize }, 785 NoSuchField { expr: ExprId, field: usize },
786 BreakOutsideOfLoop { expr: ExprId },
678 } 787 }
679 788
680 impl InferenceDiagnostic { 789 impl InferenceDiagnostic {
@@ -690,6 +799,13 @@ mod diagnostics {
690 let field = source_map.field_syntax(*expr, *field); 799 let field = source_map.field_syntax(*expr, *field);
691 sink.push(NoSuchField { file: field.file_id, field: field.value }) 800 sink.push(NoSuchField { file: field.file_id, field: field.value })
692 } 801 }
802 InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
803 let (_, source_map) = db.body_with_source_map(owner.into());
804 let ptr = source_map
805 .expr_syntax(*expr)
806 .expect("break outside of loop in synthetic syntax");
807 sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
808 }
693 } 809 }
694 } 810 }
695 } 811 }