diff options
Diffstat (limited to 'crates/ra_hir/src/ty/infer.rs')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 176 |
1 files changed, 4 insertions, 172 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 70da7f311..81a8623bf 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -45,13 +45,14 @@ use crate::{ | |||
45 | name, | 45 | name, |
46 | nameres::Namespace, | 46 | nameres::Namespace, |
47 | path::{known, GenericArg, GenericArgs}, | 47 | path::{known, GenericArg, GenericArgs}, |
48 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 48 | resolve::{Resolver, TypeNs}, |
49 | ty::infer::diagnostics::InferenceDiagnostic, | 49 | ty::infer::diagnostics::InferenceDiagnostic, |
50 | type_ref::{Mutability, TypeRef}, | 50 | type_ref::{Mutability, TypeRef}, |
51 | Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField, | 51 | Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | mod unify; | 54 | mod unify; |
55 | mod path; | ||
55 | 56 | ||
56 | /// The entry point of type inference. | 57 | /// The entry point of type inference. |
57 | pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { | 58 | pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { |
@@ -466,175 +467,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
466 | }) | 467 | }) |
467 | } | 468 | } |
468 | 469 | ||
469 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> { | ||
470 | let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind { | ||
471 | if path.segments.is_empty() { | ||
472 | // This can't actually happen syntax-wise | ||
473 | return None; | ||
474 | } | ||
475 | let ty = self.make_ty(type_ref); | ||
476 | let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; | ||
477 | let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); | ||
478 | self.resolve_ty_assoc_item( | ||
479 | ty, | ||
480 | path.segments.last().expect("path had at least one segment"), | ||
481 | id, | ||
482 | )? | ||
483 | } else { | ||
484 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; | ||
485 | |||
486 | match value_or_partial { | ||
487 | ResolveValueResult::ValueNs(it) => (it, None), | ||
488 | ResolveValueResult::Partial(def, remaining_index) => { | ||
489 | self.resolve_assoc_item(def, path, remaining_index, id)? | ||
490 | } | ||
491 | } | ||
492 | }; | ||
493 | |||
494 | let typable: TypableDef = match value { | ||
495 | ValueNs::LocalBinding(pat) => { | ||
496 | let ty = self.result.type_of_pat.get(pat)?.clone(); | ||
497 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); | ||
498 | return Some(ty); | ||
499 | } | ||
500 | ValueNs::Function(it) => it.into(), | ||
501 | ValueNs::Const(it) => it.into(), | ||
502 | ValueNs::Static(it) => it.into(), | ||
503 | ValueNs::Struct(it) => it.into(), | ||
504 | ValueNs::EnumVariant(it) => it.into(), | ||
505 | }; | ||
506 | |||
507 | let mut ty = self.db.type_for_def(typable, Namespace::Values); | ||
508 | if let Some(self_subst) = self_subst { | ||
509 | ty = ty.subst(&self_subst); | ||
510 | } | ||
511 | |||
512 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | ||
513 | let ty = ty.subst(&substs); | ||
514 | let ty = self.insert_type_vars(ty); | ||
515 | let ty = self.normalize_associated_types_in(ty); | ||
516 | Some(ty) | ||
517 | } | ||
518 | |||
519 | fn resolve_assoc_item( | ||
520 | &mut self, | ||
521 | def: TypeNs, | ||
522 | path: &Path, | ||
523 | remaining_index: usize, | ||
524 | id: ExprOrPatId, | ||
525 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
526 | assert!(remaining_index < path.segments.len()); | ||
527 | // there may be more intermediate segments between the resolved one and | ||
528 | // the end. Only the last segment needs to be resolved to a value; from | ||
529 | // the segments before that, we need to get either a type or a trait ref. | ||
530 | |||
531 | let resolved_segment = &path.segments[remaining_index - 1]; | ||
532 | let remaining_segments = &path.segments[remaining_index..]; | ||
533 | let is_before_last = remaining_segments.len() == 1; | ||
534 | |||
535 | match (def, is_before_last) { | ||
536 | (TypeNs::Trait(_trait), true) => { | ||
537 | // FIXME Associated item of trait, e.g. `Default::default` | ||
538 | None | ||
539 | } | ||
540 | (def, _) => { | ||
541 | // Either we already have a type (e.g. `Vec::new`), or we have a | ||
542 | // trait but it's not the last segment, so the next segment | ||
543 | // should resolve to an associated type of that trait (e.g. `<T | ||
544 | // as Iterator>::Item::default`) | ||
545 | let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1]; | ||
546 | let ty = Ty::from_partly_resolved_hir_path( | ||
547 | self.db, | ||
548 | &self.resolver, | ||
549 | def, | ||
550 | resolved_segment, | ||
551 | remaining_segments_for_ty, | ||
552 | ); | ||
553 | if let Ty::Unknown = ty { | ||
554 | return None; | ||
555 | } | ||
556 | |||
557 | let segment = | ||
558 | remaining_segments.last().expect("there should be at least one segment here"); | ||
559 | |||
560 | self.resolve_ty_assoc_item(ty, segment, id) | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | |||
565 | fn resolve_ty_assoc_item( | ||
566 | &mut self, | ||
567 | ty: Ty, | ||
568 | segment: &crate::path::PathSegment, | ||
569 | id: ExprOrPatId, | ||
570 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
571 | if let Ty::Unknown = ty { | ||
572 | return None; | ||
573 | } | ||
574 | |||
575 | let krate = self.resolver.krate()?; | ||
576 | |||
577 | // Find impl | ||
578 | // FIXME: consider trait candidates | ||
579 | let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item { | ||
580 | AssocItem::Function(func) => { | ||
581 | if segment.name == func.name(self.db) { | ||
582 | Some(AssocItem::Function(func)) | ||
583 | } else { | ||
584 | None | ||
585 | } | ||
586 | } | ||
587 | |||
588 | AssocItem::Const(konst) => { | ||
589 | if konst.name(self.db).map_or(false, |n| n == segment.name) { | ||
590 | Some(AssocItem::Const(konst)) | ||
591 | } else { | ||
592 | None | ||
593 | } | ||
594 | } | ||
595 | AssocItem::TypeAlias(_) => None, | ||
596 | })?; | ||
597 | let def = match item { | ||
598 | AssocItem::Function(f) => ValueNs::Function(f), | ||
599 | AssocItem::Const(c) => ValueNs::Const(c), | ||
600 | AssocItem::TypeAlias(_) => unreachable!(), | ||
601 | }; | ||
602 | let substs = self.find_self_types(&def, ty); | ||
603 | |||
604 | self.write_assoc_resolution(id, item); | ||
605 | Some((def, substs)) | ||
606 | } | ||
607 | |||
608 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { | ||
609 | if let ValueNs::Function(func) = def { | ||
610 | // We only do the infer if parent has generic params | ||
611 | let gen = func.generic_params(self.db); | ||
612 | if gen.count_parent_params() == 0 { | ||
613 | return None; | ||
614 | } | ||
615 | |||
616 | let impl_block = func.impl_block(self.db)?.target_ty(self.db); | ||
617 | let impl_block_substs = impl_block.substs()?; | ||
618 | let actual_substs = actual_def_ty.substs()?; | ||
619 | |||
620 | let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()]; | ||
621 | |||
622 | // The following code *link up* the function actual parma type | ||
623 | // and impl_block type param index | ||
624 | impl_block_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| { | ||
625 | if let Ty::Param { idx, .. } = param { | ||
626 | if let Some(s) = new_substs.get_mut(*idx as usize) { | ||
627 | *s = pty.clone(); | ||
628 | } | ||
629 | } | ||
630 | }); | ||
631 | |||
632 | Some(Substs(new_substs.into())) | ||
633 | } else { | ||
634 | None | ||
635 | } | ||
636 | } | ||
637 | |||
638 | fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) { | 470 | fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) { |
639 | let path = match path { | 471 | let path = match path { |
640 | Some(path) => path, | 472 | Some(path) => path, |
@@ -807,7 +639,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
807 | Pat::Path(path) => { | 639 | Pat::Path(path) => { |
808 | // FIXME use correct resolver for the surrounding expression | 640 | // FIXME use correct resolver for the surrounding expression |
809 | let resolver = self.resolver.clone(); | 641 | let resolver = self.resolver.clone(); |
810 | self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) | 642 | self.infer_path(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) |
811 | } | 643 | } |
812 | Pat::Bind { mode, name: _, subpat } => { | 644 | Pat::Bind { mode, name: _, subpat } => { |
813 | let mode = if mode == &BindingAnnotation::Unannotated { | 645 | let mode = if mode == &BindingAnnotation::Unannotated { |
@@ -1121,7 +953,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1121 | Expr::Path(p) => { | 953 | Expr::Path(p) => { |
1122 | // FIXME this could be more efficient... | 954 | // FIXME this could be more efficient... |
1123 | let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); | 955 | let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); |
1124 | self.infer_path_expr(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) | 956 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) |
1125 | } | 957 | } |
1126 | Expr::Continue => Ty::simple(TypeCtor::Never), | 958 | Expr::Continue => Ty::simple(TypeCtor::Never), |
1127 | Expr::Break { expr } => { | 959 | Expr::Break { expr } => { |