diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 140 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model_impl/module.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir/src/either.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 54 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/scope.rs | 233 | ||||
-rw-r--r-- | crates/ra_hir/src/generics.rs | 37 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 145 | ||||
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 30 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 406 | ||||
-rw-r--r-- | crates/ra_hir/src/traits.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 47 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 243 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 109 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 60 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 115 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 112 |
23 files changed, 1155 insertions, 770 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 9e6170440..8f1ed1086 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -4,14 +4,14 @@ use ra_db::{CrateId, SourceRootId, Edition}; | |||
4 | use ra_syntax::{ast::self, TreeArc}; | 4 | use ra_syntax::{ast::self, TreeArc}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | Name, ScopesWithSourceMap, Ty, HirFileId, ImportSource, | 7 | Name, Ty, HirFileId, Either, |
8 | HirDatabase, DefDatabase, | 8 | HirDatabase, DefDatabase, |
9 | type_ref::TypeRef, | 9 | type_ref::TypeRef, |
10 | nameres::{ModuleScope, Namespace, ImportId, CrateModuleId}, | 10 | nameres::{ModuleScope, Namespace, ImportId, CrateModuleId}, |
11 | expr::{Body, BodySourceMap}, | 11 | expr::{Body, BodySourceMap}, |
12 | ty::InferenceResult, | 12 | ty::InferenceResult, |
13 | adt::{EnumVariantId, StructFieldId, VariantDef}, | 13 | adt::{EnumVariantId, StructFieldId, VariantDef}, |
14 | generics::GenericParams, | 14 | generics::HasGenericParams, |
15 | docs::{Documentation, Docs, docs_from_ast}, | 15 | docs::{Documentation, Docs, docs_from_ast}, |
16 | ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeAliasId}, | 16 | ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeAliasId}, |
17 | impl_block::ImplBlock, | 17 | impl_block::ImplBlock, |
@@ -117,8 +117,14 @@ impl Module { | |||
117 | } | 117 | } |
118 | 118 | ||
119 | /// Returns the syntax of the last path segment corresponding to this import | 119 | /// Returns the syntax of the last path segment corresponding to this import |
120 | pub fn import_source(&self, db: &impl HirDatabase, import: ImportId) -> ImportSource { | 120 | pub fn import_source( |
121 | self.import_source_impl(db, import) | 121 | &self, |
122 | db: &impl HirDatabase, | ||
123 | import: ImportId, | ||
124 | ) -> Either<TreeArc<ast::UseTree>, TreeArc<ast::ExternCrateItem>> { | ||
125 | let (file_id, source) = self.definition_source(db); | ||
126 | let (_, source_map) = db.raw_items_with_source_map(file_id); | ||
127 | source_map.get(&source, import) | ||
122 | } | 128 | } |
123 | 129 | ||
124 | /// Returns the crate this module is part of. | 130 | /// Returns the crate this module is part of. |
@@ -183,12 +189,12 @@ impl Module { | |||
183 | } | 189 | } |
184 | } | 190 | } |
185 | 191 | ||
186 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 192 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { |
187 | let def_map = db.crate_def_map(self.krate); | 193 | let def_map = db.crate_def_map(self.krate); |
188 | Resolver::default().push_module_scope(def_map, self.module_id) | 194 | Resolver::default().push_module_scope(def_map, self.module_id) |
189 | } | 195 | } |
190 | 196 | ||
191 | pub fn declarations(self, db: &impl HirDatabase) -> Vec<ModuleDef> { | 197 | pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> { |
192 | let def_map = db.crate_def_map(self.krate); | 198 | let def_map = db.crate_def_map(self.krate); |
193 | def_map[self.module_id] | 199 | def_map[self.module_id] |
194 | .scope | 200 | .scope |
@@ -293,10 +299,6 @@ impl Struct { | |||
293 | .map(|(id, _)| StructField { parent: (*self).into(), id }) | 299 | .map(|(id, _)| StructField { parent: (*self).into(), id }) |
294 | } | 300 | } |
295 | 301 | ||
296 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { | ||
297 | db.generic_params((*self).into()) | ||
298 | } | ||
299 | |||
300 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | 302 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { |
301 | db.type_for_def((*self).into(), Namespace::Types) | 303 | db.type_for_def((*self).into(), Namespace::Types) |
302 | } | 304 | } |
@@ -307,7 +309,7 @@ impl Struct { | |||
307 | 309 | ||
308 | // FIXME move to a more general type | 310 | // FIXME move to a more general type |
309 | /// Builds a resolver for type references inside this struct. | 311 | /// Builds a resolver for type references inside this struct. |
310 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 312 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
311 | // take the outer scope... | 313 | // take the outer scope... |
312 | let r = self.module(db).resolver(db); | 314 | let r = self.module(db).resolver(db); |
313 | // ...and add generic params, if present | 315 | // ...and add generic params, if present |
@@ -357,17 +359,13 @@ impl Enum { | |||
357 | .map(|(id, _)| EnumVariant { parent: *self, id }) | 359 | .map(|(id, _)| EnumVariant { parent: *self, id }) |
358 | } | 360 | } |
359 | 361 | ||
360 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { | ||
361 | db.generic_params((*self).into()) | ||
362 | } | ||
363 | |||
364 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | 362 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { |
365 | db.type_for_def((*self).into(), Namespace::Types) | 363 | db.type_for_def((*self).into(), Namespace::Types) |
366 | } | 364 | } |
367 | 365 | ||
368 | // FIXME: move to a more general type | 366 | // FIXME: move to a more general type |
369 | /// Builds a resolver for type references inside this struct. | 367 | /// Builds a resolver for type references inside this struct. |
370 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 368 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
371 | // take the outer scope... | 369 | // take the outer scope... |
372 | let r = self.module(db).resolver(db); | 370 | let r = self.module(db).resolver(db); |
373 | // ...and add generic params, if present | 371 | // ...and add generic params, if present |
@@ -444,28 +442,22 @@ impl DefWithBody { | |||
444 | db.infer(*self) | 442 | db.infer(*self) |
445 | } | 443 | } |
446 | 444 | ||
447 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
448 | db.body_with_source_map(*self).1 | ||
449 | } | ||
450 | |||
451 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { | 445 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { |
452 | db.body_hir(*self) | 446 | db.body_hir(*self) |
453 | } | 447 | } |
454 | 448 | ||
449 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
450 | db.body_with_source_map(*self).1 | ||
451 | } | ||
452 | |||
455 | /// Builds a resolver for code inside this item. | 453 | /// Builds a resolver for code inside this item. |
456 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 454 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
457 | match *self { | 455 | match *self { |
458 | DefWithBody::Const(ref c) => c.resolver(db), | 456 | DefWithBody::Const(ref c) => c.resolver(db), |
459 | DefWithBody::Function(ref f) => f.resolver(db), | 457 | DefWithBody::Function(ref f) => f.resolver(db), |
460 | DefWithBody::Static(ref s) => s.resolver(db), | 458 | DefWithBody::Static(ref s) => s.resolver(db), |
461 | } | 459 | } |
462 | } | 460 | } |
463 | |||
464 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { | ||
465 | let scopes = db.expr_scopes(*self); | ||
466 | let source_map = db.body_with_source_map(*self).1; | ||
467 | ScopesWithSourceMap { scopes, source_map } | ||
468 | } | ||
469 | } | 461 | } |
470 | 462 | ||
471 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 463 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -517,7 +509,7 @@ impl Function { | |||
517 | self.signature(db).name.clone() | 509 | self.signature(db).name.clone() |
518 | } | 510 | } |
519 | 511 | ||
520 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 512 | pub(crate) fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
521 | db.body_with_source_map((*self).into()).1 | 513 | db.body_with_source_map((*self).into()).1 |
522 | } | 514 | } |
523 | 515 | ||
@@ -529,12 +521,6 @@ impl Function { | |||
529 | db.type_for_def((*self).into(), Namespace::Values) | 521 | db.type_for_def((*self).into(), Namespace::Values) |
530 | } | 522 | } |
531 | 523 | ||
532 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { | ||
533 | let scopes = db.expr_scopes((*self).into()); | ||
534 | let source_map = db.body_with_source_map((*self).into()).1; | ||
535 | ScopesWithSourceMap { scopes, source_map } | ||
536 | } | ||
537 | |||
538 | pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> { | 524 | pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> { |
539 | db.fn_signature(*self) | 525 | db.fn_signature(*self) |
540 | } | 526 | } |
@@ -543,24 +529,32 @@ impl Function { | |||
543 | db.infer((*self).into()) | 529 | db.infer((*self).into()) |
544 | } | 530 | } |
545 | 531 | ||
546 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { | ||
547 | db.generic_params((*self).into()) | ||
548 | } | ||
549 | |||
550 | /// The containing impl block, if this is a method. | 532 | /// The containing impl block, if this is a method. |
551 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { | 533 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { |
552 | let module_impls = db.impls_in_module(self.module(db)); | 534 | let module_impls = db.impls_in_module(self.module(db)); |
553 | ImplBlock::containing(module_impls, (*self).into()) | 535 | ImplBlock::containing(module_impls, (*self).into()) |
554 | } | 536 | } |
555 | 537 | ||
538 | /// The containing trait, if this is a trait method definition. | ||
539 | pub fn parent_trait(&self, db: &impl DefDatabase) -> Option<Trait> { | ||
540 | db.trait_items_index(self.module(db)).get_parent_trait((*self).into()) | ||
541 | } | ||
542 | |||
543 | pub fn container(&self, db: &impl DefDatabase) -> Option<Container> { | ||
544 | if let Some(impl_block) = self.impl_block(db) { | ||
545 | Some(impl_block.into()) | ||
546 | } else if let Some(trait_) = self.parent_trait(db) { | ||
547 | Some(trait_.into()) | ||
548 | } else { | ||
549 | None | ||
550 | } | ||
551 | } | ||
552 | |||
556 | // FIXME: move to a more general type for 'body-having' items | 553 | // FIXME: move to a more general type for 'body-having' items |
557 | /// Builds a resolver for code inside this item. | 554 | /// Builds a resolver for code inside this item. |
558 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 555 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
559 | // take the outer scope... | 556 | // take the outer scope... |
560 | let r = self | 557 | let r = self.container(db).map_or_else(|| self.module(db).resolver(db), |c| c.resolver(db)); |
561 | .impl_block(db) | ||
562 | .map(|ib| ib.resolver(db)) | ||
563 | .unwrap_or_else(|| self.module(db).resolver(db)); | ||
564 | // ...and add generic params, if present | 558 | // ...and add generic params, if present |
565 | let p = self.generic_params(db); | 559 | let p = self.generic_params(db); |
566 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | 560 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; |
@@ -600,10 +594,6 @@ impl Const { | |||
600 | db.infer((*self).into()) | 594 | db.infer((*self).into()) |
601 | } | 595 | } |
602 | 596 | ||
603 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
604 | db.body_with_source_map((*self).into()).1 | ||
605 | } | ||
606 | |||
607 | /// The containing impl block, if this is a method. | 597 | /// The containing impl block, if this is a method. |
608 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { | 598 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { |
609 | let module_impls = db.impls_in_module(self.module(db)); | 599 | let module_impls = db.impls_in_module(self.module(db)); |
@@ -612,7 +602,7 @@ impl Const { | |||
612 | 602 | ||
613 | // FIXME: move to a more general type for 'body-having' items | 603 | // FIXME: move to a more general type for 'body-having' items |
614 | /// Builds a resolver for code inside this item. | 604 | /// Builds a resolver for code inside this item. |
615 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 605 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
616 | // take the outer scope... | 606 | // take the outer scope... |
617 | let r = self | 607 | let r = self |
618 | .impl_block(db) | 608 | .impl_block(db) |
@@ -664,7 +654,7 @@ impl Static { | |||
664 | } | 654 | } |
665 | 655 | ||
666 | /// Builds a resolver for code inside this item. | 656 | /// Builds a resolver for code inside this item. |
667 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 657 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
668 | // take the outer scope... | 658 | // take the outer scope... |
669 | self.module(db).resolver(db) | 659 | self.module(db).resolver(db) |
670 | } | 660 | } |
@@ -672,10 +662,6 @@ impl Static { | |||
672 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | 662 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { |
673 | db.infer((*self).into()) | 663 | db.infer((*self).into()) |
674 | } | 664 | } |
675 | |||
676 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
677 | db.body_with_source_map((*self).into()).1 | ||
678 | } | ||
679 | } | 665 | } |
680 | 666 | ||
681 | impl Docs for Static { | 667 | impl Docs for Static { |
@@ -698,10 +684,6 @@ impl Trait { | |||
698 | self.id.module(db) | 684 | self.id.module(db) |
699 | } | 685 | } |
700 | 686 | ||
701 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { | ||
702 | db.generic_params((*self).into()) | ||
703 | } | ||
704 | |||
705 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { | 687 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { |
706 | self.trait_data(db).name().clone() | 688 | self.trait_data(db).name().clone() |
707 | } | 689 | } |
@@ -713,6 +695,14 @@ impl Trait { | |||
713 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { | 695 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { |
714 | db.trait_data(self) | 696 | db.trait_data(self) |
715 | } | 697 | } |
698 | |||
699 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { | ||
700 | let r = self.module(db).resolver(db); | ||
701 | // add generic params, if present | ||
702 | let p = self.generic_params(db); | ||
703 | let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; | ||
704 | r | ||
705 | } | ||
716 | } | 706 | } |
717 | 707 | ||
718 | impl Docs for Trait { | 708 | impl Docs for Trait { |
@@ -731,10 +721,6 @@ impl TypeAlias { | |||
731 | self.id.source(db) | 721 | self.id.source(db) |
732 | } | 722 | } |
733 | 723 | ||
734 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { | ||
735 | db.generic_params((*self).into()) | ||
736 | } | ||
737 | |||
738 | pub fn module(&self, db: &impl DefDatabase) -> Module { | 724 | pub fn module(&self, db: &impl DefDatabase) -> Module { |
739 | self.id.module(db) | 725 | self.id.module(db) |
740 | } | 726 | } |
@@ -745,12 +731,27 @@ impl TypeAlias { | |||
745 | ImplBlock::containing(module_impls, (*self).into()) | 731 | ImplBlock::containing(module_impls, (*self).into()) |
746 | } | 732 | } |
747 | 733 | ||
734 | /// The containing trait, if this is a trait method definition. | ||
735 | pub fn parent_trait(&self, db: &impl DefDatabase) -> Option<Trait> { | ||
736 | db.trait_items_index(self.module(db)).get_parent_trait((*self).into()) | ||
737 | } | ||
738 | |||
739 | pub fn container(&self, db: &impl DefDatabase) -> Option<Container> { | ||
740 | if let Some(impl_block) = self.impl_block(db) { | ||
741 | Some(impl_block.into()) | ||
742 | } else if let Some(trait_) = self.parent_trait(db) { | ||
743 | Some(trait_.into()) | ||
744 | } else { | ||
745 | None | ||
746 | } | ||
747 | } | ||
748 | |||
748 | pub fn type_ref(self, db: &impl DefDatabase) -> Arc<TypeRef> { | 749 | pub fn type_ref(self, db: &impl DefDatabase) -> Arc<TypeRef> { |
749 | db.type_alias_ref(self) | 750 | db.type_alias_ref(self) |
750 | } | 751 | } |
751 | 752 | ||
752 | /// Builds a resolver for the type references in this type alias. | 753 | /// Builds a resolver for the type references in this type alias. |
753 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 754 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
754 | // take the outer scope... | 755 | // take the outer scope... |
755 | let r = self | 756 | let r = self |
756 | .impl_block(db) | 757 | .impl_block(db) |
@@ -768,3 +769,18 @@ impl Docs for TypeAlias { | |||
768 | docs_from_ast(&*self.source(db).1) | 769 | docs_from_ast(&*self.source(db).1) |
769 | } | 770 | } |
770 | } | 771 | } |
772 | |||
773 | pub enum Container { | ||
774 | Trait(Trait), | ||
775 | ImplBlock(ImplBlock), | ||
776 | } | ||
777 | impl_froms!(Container: Trait, ImplBlock); | ||
778 | |||
779 | impl Container { | ||
780 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { | ||
781 | match self { | ||
782 | Container::Trait(trait_) => trait_.resolver(db), | ||
783 | Container::ImplBlock(impl_block) => impl_block.resolver(db), | ||
784 | } | ||
785 | } | ||
786 | } | ||
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index 88dee3a69..5c2ea73ce 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs | |||
@@ -3,9 +3,9 @@ use ra_syntax::{ast, TreeArc}; | |||
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | Module, ModuleSource, Name, AstId, | 5 | Module, ModuleSource, Name, AstId, |
6 | nameres::{CrateModuleId, ImportId}, | 6 | nameres::CrateModuleId, |
7 | HirDatabase, DefDatabase, | 7 | HirDatabase, DefDatabase, |
8 | HirFileId, ImportSource, | 8 | HirFileId, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | impl ModuleSource { | 11 | impl ModuleSource { |
@@ -68,16 +68,6 @@ impl Module { | |||
68 | Some((decl.file_id(), ast)) | 68 | Some((decl.file_id(), ast)) |
69 | } | 69 | } |
70 | 70 | ||
71 | pub(crate) fn import_source_impl( | ||
72 | &self, | ||
73 | db: &impl HirDatabase, | ||
74 | import: ImportId, | ||
75 | ) -> ImportSource { | ||
76 | let (file_id, source) = self.definition_source(db); | ||
77 | let (_, source_map) = db.raw_items_with_source_map(file_id); | ||
78 | source_map.get(&source, import) | ||
79 | } | ||
80 | |||
81 | pub(crate) fn crate_root_impl(&self, db: &impl DefDatabase) -> Module { | 71 | pub(crate) fn crate_root_impl(&self, db: &impl DefDatabase) -> Module { |
82 | let def_map = db.crate_def_map(self.krate); | 72 | let def_map = db.crate_def_map(self.krate); |
83 | self.with_module_id(def_map.root()) | 73 | self.with_module_id(def_map.root()) |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index be8a8c98b..18627bbc2 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; | 3 | use ra_syntax::{SyntaxNode, TreeArc, SourceFile, ast}; |
4 | use ra_db::{SourceDatabase, salsa}; | 4 | use ra_db::{SourceDatabase, salsa}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | HirFileId, MacroDefId, AstIdMap, ErasedFileAstId, Crate, Module, HirInterner, | 7 | HirFileId, MacroDefId, AstIdMap, ErasedFileAstId, Crate, Module, MacroCallLoc, |
8 | Function, FnSignature, ExprScopes, TypeAlias, | 8 | Function, FnSignature, ExprScopes, TypeAlias, |
9 | Struct, Enum, StructField, | 9 | Struct, Enum, StructField, |
10 | Const, ConstSignature, Static, | 10 | Const, ConstSignature, Static, |
@@ -15,11 +15,29 @@ use crate::{ | |||
15 | impl_block::{ModuleImplBlocks, ImplSourceMap}, | 15 | impl_block::{ModuleImplBlocks, ImplSourceMap}, |
16 | generics::{GenericParams, GenericDef}, | 16 | generics::{GenericParams, GenericDef}, |
17 | type_ref::TypeRef, | 17 | type_ref::TypeRef, |
18 | traits::TraitData, Trait, ty::TraitRef | 18 | traits::TraitData, Trait, ty::TraitRef, |
19 | ids | ||
19 | }; | 20 | }; |
20 | 21 | ||
21 | #[salsa::query_group(DefDatabaseStorage)] | 22 | #[salsa::query_group(DefDatabaseStorage)] |
22 | pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> { | 23 | pub trait DefDatabase: SourceDatabase { |
24 | #[salsa::interned] | ||
25 | fn intern_macro(&self, macro_call: MacroCallLoc) -> ids::MacroCallId; | ||
26 | #[salsa::interned] | ||
27 | fn intern_function(&self, loc: ids::ItemLoc<ast::FnDef>) -> ids::FunctionId; | ||
28 | #[salsa::interned] | ||
29 | fn intern_struct(&self, loc: ids::ItemLoc<ast::StructDef>) -> ids::StructId; | ||
30 | #[salsa::interned] | ||
31 | fn intern_enum(&self, loc: ids::ItemLoc<ast::EnumDef>) -> ids::EnumId; | ||
32 | #[salsa::interned] | ||
33 | fn intern_const(&self, loc: ids::ItemLoc<ast::ConstDef>) -> ids::ConstId; | ||
34 | #[salsa::interned] | ||
35 | fn intern_static(&self, loc: ids::ItemLoc<ast::StaticDef>) -> ids::StaticId; | ||
36 | #[salsa::interned] | ||
37 | fn intern_trait(&self, loc: ids::ItemLoc<ast::TraitDef>) -> ids::TraitId; | ||
38 | #[salsa::interned] | ||
39 | fn intern_type_alias(&self, loc: ids::ItemLoc<ast::TypeAliasDef>) -> ids::TypeAliasId; | ||
40 | |||
23 | #[salsa::invoke(crate::ids::macro_def_query)] | 41 | #[salsa::invoke(crate::ids::macro_def_query)] |
24 | fn macro_def(&self, macro_id: MacroDefId) -> Option<Arc<mbe::MacroRules>>; | 42 | fn macro_def(&self, macro_id: MacroDefId) -> Option<Arc<mbe::MacroRules>>; |
25 | 43 | ||
@@ -35,6 +53,9 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> { | |||
35 | #[salsa::invoke(crate::traits::TraitData::trait_data_query)] | 53 | #[salsa::invoke(crate::traits::TraitData::trait_data_query)] |
36 | fn trait_data(&self, t: Trait) -> Arc<TraitData>; | 54 | fn trait_data(&self, t: Trait) -> Arc<TraitData>; |
37 | 55 | ||
56 | #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] | ||
57 | fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; | ||
58 | |||
38 | #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)] | 59 | #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)] |
39 | fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>; | 60 | fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>; |
40 | 61 | ||
@@ -110,8 +131,8 @@ pub trait HirDatabase: DefDatabase { | |||
110 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] | 131 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] |
111 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; | 132 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; |
112 | 133 | ||
113 | #[salsa::invoke(crate::ty::method_resolution::implements)] | 134 | #[salsa::invoke(crate::ty::traits::implements)] |
114 | fn implements(&self, trait_ref: TraitRef) -> bool; | 135 | fn implements(&self, trait_ref: TraitRef) -> Option<crate::ty::traits::Solution>; |
115 | } | 136 | } |
116 | 137 | ||
117 | #[test] | 138 | #[test] |
diff --git a/crates/ra_hir/src/either.rs b/crates/ra_hir/src/either.rs new file mode 100644 index 000000000..4073cc82e --- /dev/null +++ b/crates/ra_hir/src/either.rs | |||
@@ -0,0 +1,28 @@ | |||
1 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
2 | pub enum Either<A, B> { | ||
3 | A(A), | ||
4 | B(B), | ||
5 | } | ||
6 | |||
7 | impl<A, B> Either<A, B> { | ||
8 | pub fn either<R, F1, F2>(self, f1: F1, f2: F2) -> R | ||
9 | where | ||
10 | F1: FnOnce(A) -> R, | ||
11 | F2: FnOnce(B) -> R, | ||
12 | { | ||
13 | match self { | ||
14 | Either::A(a) => f1(a), | ||
15 | Either::B(b) => f2(b), | ||
16 | } | ||
17 | } | ||
18 | pub fn map<U, V, F1, F2>(self, f1: F1, f2: F2) -> Either<U, V> | ||
19 | where | ||
20 | F1: FnOnce(A) -> U, | ||
21 | F2: FnOnce(B) -> V, | ||
22 | { | ||
23 | match self { | ||
24 | Either::A(a) => Either::A(f1(a)), | ||
25 | Either::B(b) => Either::B(f2(b)), | ||
26 | } | ||
27 | } | ||
28 | } | ||
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 589a9b2db..817e660f9 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -10,13 +10,13 @@ use ra_syntax::{ | |||
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Path, Name, HirDatabase, Resolver,DefWithBody, | 13 | Path, Name, HirDatabase, Resolver,DefWithBody, Either, |
14 | name::AsName, | 14 | name::AsName, |
15 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
16 | }; | 16 | }; |
17 | use crate::{ path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}}; | 17 | use crate::{path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}}; |
18 | 18 | ||
19 | pub use self::scope::{ExprScopes, ScopesWithSourceMap, ScopeEntryWithSyntax}; | 19 | pub use self::scope::ExprScopes; |
20 | 20 | ||
21 | pub(crate) mod scope; | 21 | pub(crate) mod scope; |
22 | 22 | ||
@@ -51,11 +51,13 @@ pub struct Body { | |||
51 | pub struct BodySourceMap { | 51 | pub struct BodySourceMap { |
52 | expr_map: FxHashMap<SyntaxNodePtr, ExprId>, | 52 | expr_map: FxHashMap<SyntaxNodePtr, ExprId>, |
53 | expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, | 53 | expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, |
54 | pat_map: FxHashMap<SyntaxNodePtr, PatId>, | 54 | pat_map: FxHashMap<PatPtr, PatId>, |
55 | pat_map_back: ArenaMap<PatId, SyntaxNodePtr>, | 55 | pat_map_back: ArenaMap<PatId, PatPtr>, |
56 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::NamedField>>, | 56 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::NamedField>>, |
57 | } | 57 | } |
58 | 58 | ||
59 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
60 | |||
59 | impl Body { | 61 | impl Body { |
60 | pub fn params(&self) -> &[PatId] { | 62 | pub fn params(&self) -> &[PatId] { |
61 | &self.params | 63 | &self.params |
@@ -79,19 +81,23 @@ impl Body { | |||
79 | } | 81 | } |
80 | 82 | ||
81 | // needs arbitrary_self_types to be a method... or maybe move to the def? | 83 | // needs arbitrary_self_types to be a method... or maybe move to the def? |
82 | pub fn resolver_for_expr(body: Arc<Body>, db: &impl HirDatabase, expr_id: ExprId) -> Resolver { | 84 | pub(crate) fn resolver_for_expr( |
85 | body: Arc<Body>, | ||
86 | db: &impl HirDatabase, | ||
87 | expr_id: ExprId, | ||
88 | ) -> Resolver { | ||
83 | let scopes = db.expr_scopes(body.owner); | 89 | let scopes = db.expr_scopes(body.owner); |
84 | resolver_for_scope(body, db, scopes.scope_for(expr_id)) | 90 | resolver_for_scope(body, db, scopes.scope_for(expr_id)) |
85 | } | 91 | } |
86 | 92 | ||
87 | pub fn resolver_for_scope( | 93 | pub(crate) fn resolver_for_scope( |
88 | body: Arc<Body>, | 94 | body: Arc<Body>, |
89 | db: &impl HirDatabase, | 95 | db: &impl HirDatabase, |
90 | scope_id: Option<scope::ScopeId>, | 96 | scope_id: Option<scope::ScopeId>, |
91 | ) -> Resolver { | 97 | ) -> Resolver { |
92 | let mut r = body.owner.resolver(db); | 98 | let mut r = body.owner.resolver(db); |
93 | let scopes = db.expr_scopes(body.owner); | 99 | let scopes = db.expr_scopes(body.owner); |
94 | let scope_chain = scopes.scope_chain_for(scope_id).collect::<Vec<_>>(); | 100 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); |
95 | for scope in scope_chain.into_iter().rev() { | 101 | for scope in scope_chain.into_iter().rev() { |
96 | r = r.push_expr_scope(Arc::clone(&scopes), scope); | 102 | r = r.push_expr_scope(Arc::clone(&scopes), scope); |
97 | } | 103 | } |
@@ -115,31 +121,27 @@ impl Index<PatId> for Body { | |||
115 | } | 121 | } |
116 | 122 | ||
117 | impl BodySourceMap { | 123 | impl BodySourceMap { |
118 | pub fn expr_syntax(&self, expr: ExprId) -> Option<SyntaxNodePtr> { | 124 | pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<SyntaxNodePtr> { |
119 | self.expr_map_back.get(expr).cloned() | 125 | self.expr_map_back.get(expr).cloned() |
120 | } | 126 | } |
121 | 127 | ||
122 | pub fn syntax_expr(&self, ptr: SyntaxNodePtr) -> Option<ExprId> { | 128 | pub(crate) fn syntax_expr(&self, ptr: SyntaxNodePtr) -> Option<ExprId> { |
123 | self.expr_map.get(&ptr).cloned() | 129 | self.expr_map.get(&ptr).cloned() |
124 | } | 130 | } |
125 | 131 | ||
126 | pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { | 132 | pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { |
127 | self.expr_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() | 133 | self.expr_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() |
128 | } | 134 | } |
129 | 135 | ||
130 | pub fn pat_syntax(&self, pat: PatId) -> Option<SyntaxNodePtr> { | 136 | pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatPtr> { |
131 | self.pat_map_back.get(pat).cloned() | 137 | self.pat_map_back.get(pat).cloned() |
132 | } | 138 | } |
133 | 139 | ||
134 | pub fn syntax_pat(&self, ptr: SyntaxNodePtr) -> Option<PatId> { | 140 | pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { |
135 | self.pat_map.get(&ptr).cloned() | 141 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() |
136 | } | ||
137 | |||
138 | pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | ||
139 | self.pat_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() | ||
140 | } | 142 | } |
141 | 143 | ||
142 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::NamedField> { | 144 | pub(crate) fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::NamedField> { |
143 | self.field_map[&(expr, field)].clone() | 145 | self.field_map[&(expr, field)].clone() |
144 | } | 146 | } |
145 | } | 147 | } |
@@ -504,10 +506,10 @@ impl ExprCollector { | |||
504 | id | 506 | id |
505 | } | 507 | } |
506 | 508 | ||
507 | fn alloc_pat(&mut self, pat: Pat, syntax_ptr: SyntaxNodePtr) -> PatId { | 509 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { |
508 | let id = self.pats.alloc(pat); | 510 | let id = self.pats.alloc(pat); |
509 | self.source_map.pat_map.insert(syntax_ptr, id); | 511 | self.source_map.pat_map.insert(ptr, id); |
510 | self.source_map.pat_map_back.insert(id, syntax_ptr); | 512 | self.source_map.pat_map_back.insert(id, ptr); |
511 | id | 513 | id |
512 | } | 514 | } |
513 | 515 | ||
@@ -886,8 +888,8 @@ impl ExprCollector { | |||
886 | ast::PatKind::LiteralPat(_) => Pat::Missing, | 888 | ast::PatKind::LiteralPat(_) => Pat::Missing, |
887 | ast::PatKind::SlicePat(_) | ast::PatKind::RangePat(_) => Pat::Missing, | 889 | ast::PatKind::SlicePat(_) | ast::PatKind::RangePat(_) => Pat::Missing, |
888 | }; | 890 | }; |
889 | let syntax_ptr = SyntaxNodePtr::new(pat.syntax()); | 891 | let ptr = AstPtr::new(pat); |
890 | self.alloc_pat(pattern, syntax_ptr) | 892 | self.alloc_pat(pattern, Either::A(ptr)) |
891 | } | 893 | } |
892 | 894 | ||
893 | fn collect_pat_opt(&mut self, pat: Option<&ast::Pat>) -> PatId { | 895 | fn collect_pat_opt(&mut self, pat: Option<&ast::Pat>) -> PatId { |
@@ -911,14 +913,14 @@ impl ExprCollector { | |||
911 | fn collect_fn_body(&mut self, node: &ast::FnDef) { | 913 | fn collect_fn_body(&mut self, node: &ast::FnDef) { |
912 | if let Some(param_list) = node.param_list() { | 914 | if let Some(param_list) = node.param_list() { |
913 | if let Some(self_param) = param_list.self_param() { | 915 | if let Some(self_param) = param_list.self_param() { |
914 | let self_param = SyntaxNodePtr::new(self_param.syntax()); | 916 | let ptr = AstPtr::new(self_param); |
915 | let param_pat = self.alloc_pat( | 917 | let param_pat = self.alloc_pat( |
916 | Pat::Bind { | 918 | Pat::Bind { |
917 | name: Name::self_param(), | 919 | name: Name::self_param(), |
918 | mode: BindingAnnotation::Unannotated, | 920 | mode: BindingAnnotation::Unannotated, |
919 | subpat: None, | 921 | subpat: None, |
920 | }, | 922 | }, |
921 | self_param, | 923 | Either::B(ptr), |
922 | ); | 924 | ); |
923 | self.params.push(param_pat); | 925 | self.params.push(param_pat); |
924 | } | 926 | } |
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index 48283907b..58f365128 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -1,17 +1,11 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use rustc_hash::{FxHashMap, FxHashSet}; | 3 | use rustc_hash::FxHashMap; |
4 | |||
5 | use ra_syntax::{ | ||
6 | AstNode, SyntaxNode, TextUnit, TextRange, SyntaxNodePtr, | ||
7 | algo::generate, | ||
8 | ast, | ||
9 | }; | ||
10 | use ra_arena::{Arena, RawId, impl_arena_id}; | 4 | use ra_arena::{Arena, RawId, impl_arena_id}; |
11 | 5 | ||
12 | use crate::{ | 6 | use crate::{ |
13 | Name, AsName,DefWithBody, | 7 | Name, DefWithBody, |
14 | expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap}, | 8 | expr::{PatId, ExprId, Pat, Expr, Body, Statement}, |
15 | HirDatabase, | 9 | HirDatabase, |
16 | }; | 10 | }; |
17 | 11 | ||
@@ -23,23 +17,32 @@ impl_arena_id!(ScopeId); | |||
23 | pub struct ExprScopes { | 17 | pub struct ExprScopes { |
24 | body: Arc<Body>, | 18 | body: Arc<Body>, |
25 | scopes: Arena<ScopeId, ScopeData>, | 19 | scopes: Arena<ScopeId, ScopeData>, |
26 | scope_for: FxHashMap<ExprId, ScopeId>, | 20 | scope_by_expr: FxHashMap<ExprId, ScopeId>, |
27 | } | 21 | } |
28 | 22 | ||
29 | #[derive(Debug, PartialEq, Eq)] | 23 | #[derive(Debug, PartialEq, Eq)] |
30 | pub struct ScopeEntry { | 24 | pub(crate) struct ScopeEntry { |
31 | name: Name, | 25 | name: Name, |
32 | pat: PatId, | 26 | pat: PatId, |
33 | } | 27 | } |
34 | 28 | ||
29 | impl ScopeEntry { | ||
30 | pub(crate) fn name(&self) -> &Name { | ||
31 | &self.name | ||
32 | } | ||
33 | |||
34 | pub(crate) fn pat(&self) -> PatId { | ||
35 | self.pat | ||
36 | } | ||
37 | } | ||
38 | |||
35 | #[derive(Debug, PartialEq, Eq)] | 39 | #[derive(Debug, PartialEq, Eq)] |
36 | pub struct ScopeData { | 40 | pub(crate) struct ScopeData { |
37 | parent: Option<ScopeId>, | 41 | parent: Option<ScopeId>, |
38 | entries: Vec<ScopeEntry>, | 42 | entries: Vec<ScopeEntry>, |
39 | } | 43 | } |
40 | 44 | ||
41 | impl ExprScopes { | 45 | impl ExprScopes { |
42 | // FIXME: This should take something more general than Function | ||
43 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> { | 46 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> { |
44 | let body = db.body_hir(def); | 47 | let body = db.body_hir(def); |
45 | let res = ExprScopes::new(body); | 48 | let res = ExprScopes::new(body); |
@@ -50,7 +53,7 @@ impl ExprScopes { | |||
50 | let mut scopes = ExprScopes { | 53 | let mut scopes = ExprScopes { |
51 | body: body.clone(), | 54 | body: body.clone(), |
52 | scopes: Arena::default(), | 55 | scopes: Arena::default(), |
53 | scope_for: FxHashMap::default(), | 56 | scope_by_expr: FxHashMap::default(), |
54 | }; | 57 | }; |
55 | let root = scopes.root_scope(); | 58 | let root = scopes.root_scope(); |
56 | scopes.add_params_bindings(root, body.params()); | 59 | scopes.add_params_bindings(root, body.params()); |
@@ -58,19 +61,23 @@ impl ExprScopes { | |||
58 | scopes | 61 | scopes |
59 | } | 62 | } |
60 | 63 | ||
61 | pub fn body(&self) -> Arc<Body> { | 64 | pub(crate) fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { |
62 | self.body.clone() | ||
63 | } | ||
64 | |||
65 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | ||
66 | &self.scopes[scope].entries | 65 | &self.scopes[scope].entries |
67 | } | 66 | } |
68 | 67 | ||
69 | pub fn scope_chain_for<'a>( | 68 | pub(crate) fn scope_chain<'a>( |
70 | &'a self, | 69 | &'a self, |
71 | scope: Option<ScopeId>, | 70 | scope: Option<ScopeId>, |
72 | ) -> impl Iterator<Item = ScopeId> + 'a { | 71 | ) -> impl Iterator<Item = ScopeId> + 'a { |
73 | generate(scope, move |&scope| self.scopes[scope].parent) | 72 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) |
73 | } | ||
74 | |||
75 | pub(crate) fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | ||
76 | self.scope_by_expr.get(&expr).map(|&scope| scope) | ||
77 | } | ||
78 | |||
79 | pub(crate) fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> { | ||
80 | &self.scope_by_expr | ||
74 | } | 81 | } |
75 | 82 | ||
76 | fn root_scope(&mut self) -> ScopeId { | 83 | fn root_scope(&mut self) -> ScopeId { |
@@ -99,130 +106,7 @@ impl ExprScopes { | |||
99 | } | 106 | } |
100 | 107 | ||
101 | fn set_scope(&mut self, node: ExprId, scope: ScopeId) { | 108 | fn set_scope(&mut self, node: ExprId, scope: ScopeId) { |
102 | self.scope_for.insert(node, scope); | 109 | self.scope_by_expr.insert(node, scope); |
103 | } | ||
104 | |||
105 | pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | ||
106 | self.scope_for.get(&expr).map(|&scope| scope) | ||
107 | } | ||
108 | } | ||
109 | |||
110 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
111 | pub struct ScopesWithSourceMap { | ||
112 | pub source_map: Arc<BodySourceMap>, | ||
113 | pub scopes: Arc<ExprScopes>, | ||
114 | } | ||
115 | |||
116 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
117 | pub struct ScopeEntryWithSyntax { | ||
118 | name: Name, | ||
119 | ptr: SyntaxNodePtr, | ||
120 | } | ||
121 | |||
122 | impl ScopeEntryWithSyntax { | ||
123 | pub fn name(&self) -> &Name { | ||
124 | &self.name | ||
125 | } | ||
126 | |||
127 | pub fn ptr(&self) -> SyntaxNodePtr { | ||
128 | self.ptr | ||
129 | } | ||
130 | } | ||
131 | |||
132 | impl ScopesWithSourceMap { | ||
133 | fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + 'a { | ||
134 | generate(self.scope_for(node), move |&scope| self.scopes.scopes[scope].parent) | ||
135 | } | ||
136 | |||
137 | pub fn scope_for_offset(&self, offset: TextUnit) -> Option<ScopeId> { | ||
138 | self.scopes | ||
139 | .scope_for | ||
140 | .iter() | ||
141 | .filter_map(|(id, scope)| Some((self.source_map.expr_syntax(*id)?, scope))) | ||
142 | // find containing scope | ||
143 | .min_by_key(|(ptr, _scope)| { | ||
144 | (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) | ||
145 | }) | ||
146 | .map(|(ptr, scope)| self.adjust(ptr, *scope, offset)) | ||
147 | } | ||
148 | |||
149 | // XXX: during completion, cursor might be outside of any particular | ||
150 | // expression. Try to figure out the correct scope... | ||
151 | // FIXME: move this to source binder? | ||
152 | fn adjust(&self, ptr: SyntaxNodePtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { | ||
153 | let r = ptr.range(); | ||
154 | let child_scopes = self | ||
155 | .scopes | ||
156 | .scope_for | ||
157 | .iter() | ||
158 | .filter_map(|(id, scope)| Some((self.source_map.expr_syntax(*id)?, scope))) | ||
159 | .map(|(ptr, scope)| (ptr.range(), scope)) | ||
160 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); | ||
161 | |||
162 | child_scopes | ||
163 | .max_by(|(r1, _), (r2, _)| { | ||
164 | if r2.is_subrange(&r1) { | ||
165 | std::cmp::Ordering::Greater | ||
166 | } else if r1.is_subrange(&r2) { | ||
167 | std::cmp::Ordering::Less | ||
168 | } else { | ||
169 | r1.start().cmp(&r2.start()) | ||
170 | } | ||
171 | }) | ||
172 | .map(|(_ptr, scope)| *scope) | ||
173 | .unwrap_or(original_scope) | ||
174 | } | ||
175 | |||
176 | pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { | ||
177 | let mut shadowed = FxHashSet::default(); | ||
178 | let name = name_ref.as_name(); | ||
179 | let ret = self | ||
180 | .scope_chain(name_ref.syntax()) | ||
181 | .flat_map(|scope| self.scopes.entries(scope).iter()) | ||
182 | .filter(|entry| shadowed.insert(entry.name())) | ||
183 | .filter(|entry| entry.name() == &name) | ||
184 | .nth(0); | ||
185 | ret.and_then(|entry| { | ||
186 | Some(ScopeEntryWithSyntax { | ||
187 | name: entry.name().clone(), | ||
188 | ptr: self.source_map.pat_syntax(entry.pat())?, | ||
189 | }) | ||
190 | }) | ||
191 | } | ||
192 | |||
193 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { | ||
194 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | ||
195 | let name_ptr = SyntaxNodePtr::new(pat.syntax()); | ||
196 | fn_def | ||
197 | .syntax() | ||
198 | .descendants() | ||
199 | .filter_map(ast::NameRef::cast) | ||
200 | .filter(|name_ref| match self.resolve_local_name(*name_ref) { | ||
201 | None => false, | ||
202 | Some(entry) => entry.ptr() == name_ptr, | ||
203 | }) | ||
204 | .map(|name_ref| ReferenceDescriptor { | ||
205 | name: name_ref.syntax().text().to_string(), | ||
206 | range: name_ref.syntax().range(), | ||
207 | }) | ||
208 | .collect() | ||
209 | } | ||
210 | |||
211 | pub fn scope_for(&self, node: &SyntaxNode) -> Option<ScopeId> { | ||
212 | node.ancestors() | ||
213 | .map(SyntaxNodePtr::new) | ||
214 | .filter_map(|ptr| self.source_map.syntax_expr(ptr)) | ||
215 | .find_map(|it| self.scopes.scope_for(it)) | ||
216 | } | ||
217 | } | ||
218 | |||
219 | impl ScopeEntry { | ||
220 | pub fn name(&self) -> &Name { | ||
221 | &self.name | ||
222 | } | ||
223 | |||
224 | pub fn pat(&self) -> PatId { | ||
225 | self.pat | ||
226 | } | 110 | } |
227 | } | 111 | } |
228 | 112 | ||
@@ -286,22 +170,13 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope | |||
286 | }; | 170 | }; |
287 | } | 171 | } |
288 | 172 | ||
289 | #[derive(Debug)] | ||
290 | pub struct ReferenceDescriptor { | ||
291 | pub range: TextRange, | ||
292 | pub name: String, | ||
293 | } | ||
294 | |||
295 | #[cfg(test)] | 173 | #[cfg(test)] |
296 | mod tests { | 174 | mod tests { |
297 | use ra_syntax::{SourceFile, algo::find_node_at_offset}; | 175 | use ra_db::SourceDatabase; |
176 | use ra_syntax::{algo::find_node_at_offset, AstNode, SyntaxNodePtr, ast}; | ||
298 | use test_utils::{extract_offset, assert_eq_text}; | 177 | use test_utils::{extract_offset, assert_eq_text}; |
299 | use ra_arena::ArenaId; | ||
300 | use crate::Function; | ||
301 | |||
302 | use crate::expr::{ExprCollector}; | ||
303 | 178 | ||
304 | use super::*; | 179 | use crate::{source_binder::SourceAnalyzer, mock::MockDatabase}; |
305 | 180 | ||
306 | fn do_check(code: &str, expected: &[&str]) { | 181 | fn do_check(code: &str, expected: &[&str]) { |
307 | let (off, code) = extract_offset(code); | 182 | let (off, code) = extract_offset(code); |
@@ -313,17 +188,20 @@ mod tests { | |||
313 | buf.push_str(&code[off..]); | 188 | buf.push_str(&code[off..]); |
314 | buf | 189 | buf |
315 | }; | 190 | }; |
316 | let file = SourceFile::parse(&code); | 191 | |
192 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&code); | ||
193 | let file = db.parse(file_id); | ||
317 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 194 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
318 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 195 | let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); |
319 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; | 196 | |
320 | let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def); | 197 | let scopes = analyzer.scopes(); |
321 | let scopes = ExprScopes::new(Arc::new(body)); | 198 | let expr_id = |
322 | let scopes = | 199 | analyzer.body_source_map().syntax_expr(SyntaxNodePtr::new(marker.syntax())).unwrap(); |
323 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; | 200 | let scope = scopes.scope_for(expr_id); |
201 | |||
324 | let actual = scopes | 202 | let actual = scopes |
325 | .scope_chain(marker.syntax()) | 203 | .scope_chain(scope) |
326 | .flat_map(|scope| scopes.scopes.entries(scope)) | 204 | .flat_map(|scope| scopes.entries(scope)) |
327 | .map(|it| it.name().to_string()) | 205 | .map(|it| it.name().to_string()) |
328 | .collect::<Vec<_>>() | 206 | .collect::<Vec<_>>() |
329 | .join("\n"); | 207 | .join("\n"); |
@@ -406,28 +284,19 @@ mod tests { | |||
406 | ); | 284 | ); |
407 | } | 285 | } |
408 | 286 | ||
409 | fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> (Body, BodySourceMap) { | ||
410 | let mut collector = ExprCollector::new(DefWithBody::Function(function)); | ||
411 | collector.collect_fn_body(node); | ||
412 | collector.finish() | ||
413 | } | ||
414 | |||
415 | fn do_check_local_name(code: &str, expected_offset: u32) { | 287 | fn do_check_local_name(code: &str, expected_offset: u32) { |
416 | let (off, code) = extract_offset(code); | 288 | let (off, code) = extract_offset(code); |
417 | let file = SourceFile::parse(&code); | 289 | |
290 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&code); | ||
291 | let file = db.parse(file_id); | ||
418 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | 292 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) |
419 | .expect("failed to find a name at the target offset"); | 293 | .expect("failed to find a name at the target offset"); |
420 | |||
421 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | ||
422 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | 294 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); |
295 | let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None); | ||
423 | 296 | ||
424 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; | 297 | let local_name_entry = analyzer.resolve_local_name(name_ref).unwrap(); |
425 | let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def); | 298 | let local_name = |
426 | let scopes = ExprScopes::new(Arc::new(body)); | 299 | local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); |
427 | let scopes = | ||
428 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; | ||
429 | let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); | ||
430 | let local_name = local_name_entry.ptr(); | ||
431 | assert_eq!(local_name.range(), expected_name.syntax().range()); | 300 | assert_eq!(local_name.range(), expected_name.syntax().range()); |
432 | } | 301 | } |
433 | 302 | ||
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 84fe94289..5625c2459 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::ast::{self, NameOwner, TypeParamsOwner}; | |||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::DefDatabase, | 11 | db::DefDatabase, |
12 | Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock | 12 | Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container |
13 | }; | 13 | }; |
14 | 14 | ||
15 | /// Data about a generic parameter (to a function, struct, impl, ...). | 15 | /// Data about a generic parameter (to a function, struct, impl, ...). |
@@ -27,6 +27,7 @@ pub struct GenericParams { | |||
27 | pub(crate) params: Vec<GenericParam>, | 27 | pub(crate) params: Vec<GenericParam>, |
28 | } | 28 | } |
29 | 29 | ||
30 | // FIXME: consts can have type parameters from their parents (i.e. associated consts of traits) | ||
30 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | 31 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] |
31 | pub enum GenericDef { | 32 | pub enum GenericDef { |
32 | Function(Function), | 33 | Function(Function), |
@@ -45,18 +46,22 @@ impl GenericParams { | |||
45 | ) -> Arc<GenericParams> { | 46 | ) -> Arc<GenericParams> { |
46 | let mut generics = GenericParams::default(); | 47 | let mut generics = GenericParams::default(); |
47 | let parent = match def { | 48 | let parent = match def { |
48 | GenericDef::Function(it) => it.impl_block(db), | 49 | GenericDef::Function(it) => it.container(db).map(GenericDef::from), |
49 | GenericDef::TypeAlias(it) => it.impl_block(db), | 50 | GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from), |
50 | GenericDef::Struct(_) | GenericDef::Enum(_) | GenericDef::Trait(_) => None, | 51 | GenericDef::Struct(_) | GenericDef::Enum(_) | GenericDef::Trait(_) => None, |
51 | GenericDef::ImplBlock(_) => None, | 52 | GenericDef::ImplBlock(_) => None, |
52 | }; | 53 | }; |
53 | generics.parent_params = parent.map(|p| p.generic_params(db)); | 54 | generics.parent_params = parent.map(|p| db.generic_params(p)); |
54 | let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32; | 55 | let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32; |
55 | match def { | 56 | match def { |
56 | GenericDef::Function(it) => generics.fill(&*it.source(db).1, start), | 57 | GenericDef::Function(it) => generics.fill(&*it.source(db).1, start), |
57 | GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start), | 58 | GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start), |
58 | GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start), | 59 | GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start), |
59 | GenericDef::Trait(it) => generics.fill(&*it.source(db).1, start), | 60 | GenericDef::Trait(it) => { |
61 | // traits get the Self type as an implicit first type parameter | ||
62 | generics.params.push(GenericParam { idx: start, name: Name::self_type() }); | ||
63 | generics.fill(&*it.source(db).1, start + 1); | ||
64 | } | ||
60 | GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start), | 65 | GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start), |
61 | GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start), | 66 | GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start), |
62 | } | 67 | } |
@@ -104,3 +109,25 @@ impl GenericParams { | |||
104 | vec | 109 | vec |
105 | } | 110 | } |
106 | } | 111 | } |
112 | |||
113 | impl From<Container> for GenericDef { | ||
114 | fn from(c: Container) -> Self { | ||
115 | match c { | ||
116 | Container::Trait(trait_) => trait_.into(), | ||
117 | Container::ImplBlock(impl_block) => impl_block.into(), | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | pub trait HasGenericParams { | ||
123 | fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams>; | ||
124 | } | ||
125 | |||
126 | impl<T> HasGenericParams for T | ||
127 | where | ||
128 | T: Into<GenericDef>, | ||
129 | { | ||
130 | fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams> { | ||
131 | db.generic_params(self.into()) | ||
132 | } | ||
133 | } | ||
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index eb9939df7..141c9072f 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -3,40 +3,14 @@ use std::{ | |||
3 | sync::Arc, | 3 | sync::Arc, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use ra_db::{LocationInterner, FileId}; | 6 | use ra_db::{FileId, salsa}; |
7 | use ra_syntax::{TreeArc, SourceFile, AstNode, ast}; | 7 | use ra_syntax::{TreeArc, SourceFile, AstNode, ast}; |
8 | use ra_arena::{RawId, ArenaId, impl_arena_id}; | ||
9 | use mbe::MacroRules; | 8 | use mbe::MacroRules; |
10 | 9 | ||
11 | use crate::{ | 10 | use crate::{ |
12 | Module, DefDatabase, AstId, FileAstId, | 11 | Module, DefDatabase, AstId, FileAstId, |
13 | }; | 12 | }; |
14 | 13 | ||
15 | #[derive(Debug, Default)] | ||
16 | pub struct HirInterner { | ||
17 | macros: LocationInterner<MacroCallLoc, MacroCallId>, | ||
18 | fns: LocationInterner<ItemLoc<ast::FnDef>, FunctionId>, | ||
19 | structs: LocationInterner<ItemLoc<ast::StructDef>, StructId>, | ||
20 | enums: LocationInterner<ItemLoc<ast::EnumDef>, EnumId>, | ||
21 | consts: LocationInterner<ItemLoc<ast::ConstDef>, ConstId>, | ||
22 | statics: LocationInterner<ItemLoc<ast::StaticDef>, StaticId>, | ||
23 | traits: LocationInterner<ItemLoc<ast::TraitDef>, TraitId>, | ||
24 | types: LocationInterner<ItemLoc<ast::TypeAliasDef>, TypeAliasId>, | ||
25 | } | ||
26 | |||
27 | impl HirInterner { | ||
28 | pub fn len(&self) -> usize { | ||
29 | self.macros.len() | ||
30 | + self.fns.len() | ||
31 | + self.structs.len() | ||
32 | + self.enums.len() | ||
33 | + self.consts.len() | ||
34 | + self.statics.len() | ||
35 | + self.traits.len() | ||
36 | + self.types.len() | ||
37 | } | ||
38 | } | ||
39 | |||
40 | /// hir makes heavy use of ids: integer (u32) handlers to various things. You | 14 | /// hir makes heavy use of ids: integer (u32) handlers to various things. You |
41 | /// can think of id as a pointer (but without a lifetime) or a file descriptor | 15 | /// can think of id as a pointer (but without a lifetime) or a file descriptor |
42 | /// (but for hir objects). | 16 | /// (but for hir objects). |
@@ -135,11 +109,24 @@ pub(crate) fn macro_def_query(db: &impl DefDatabase, id: MacroDefId) -> Option<A | |||
135 | Some(Arc::new(rules)) | 109 | Some(Arc::new(rules)) |
136 | } | 110 | } |
137 | 111 | ||
112 | macro_rules! impl_intern_key { | ||
113 | ($name:ident) => { | ||
114 | impl salsa::InternKey for $name { | ||
115 | fn from_intern_id(v: salsa::InternId) -> Self { | ||
116 | $name(v) | ||
117 | } | ||
118 | fn as_intern_id(&self) -> salsa::InternId { | ||
119 | self.0 | ||
120 | } | ||
121 | } | ||
122 | }; | ||
123 | } | ||
124 | |||
138 | /// `MacroCallId` identifies a particular macro invocation, like | 125 | /// `MacroCallId` identifies a particular macro invocation, like |
139 | /// `println!("Hello, {}", world)`. | 126 | /// `println!("Hello, {}", world)`. |
140 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 127 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
141 | pub struct MacroCallId(RawId); | 128 | pub struct MacroCallId(salsa::InternId); |
142 | impl_arena_id!(MacroCallId); | 129 | impl_intern_key!(MacroCallId); |
143 | 130 | ||
144 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 131 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
145 | pub struct MacroCallLoc { | 132 | pub struct MacroCallLoc { |
@@ -148,14 +135,14 @@ pub struct MacroCallLoc { | |||
148 | } | 135 | } |
149 | 136 | ||
150 | impl MacroCallId { | 137 | impl MacroCallId { |
151 | pub(crate) fn loc(self, db: &impl AsRef<HirInterner>) -> MacroCallLoc { | 138 | pub(crate) fn loc(self, db: &impl DefDatabase) -> MacroCallLoc { |
152 | db.as_ref().macros.id2loc(self) | 139 | db.lookup_intern_macro(self) |
153 | } | 140 | } |
154 | } | 141 | } |
155 | 142 | ||
156 | impl MacroCallLoc { | 143 | impl MacroCallLoc { |
157 | pub(crate) fn id(&self, db: &impl AsRef<HirInterner>) -> MacroCallId { | 144 | pub(crate) fn id(self, db: &impl DefDatabase) -> MacroCallId { |
158 | db.as_ref().macros.loc2id(&self) | 145 | db.intern_macro(self) |
159 | } | 146 | } |
160 | } | 147 | } |
161 | 148 | ||
@@ -204,8 +191,10 @@ impl<'a, DB: DefDatabase> LocationCtx<&'a DB> { | |||
204 | } | 191 | } |
205 | } | 192 | } |
206 | 193 | ||
207 | pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone { | 194 | pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone { |
208 | fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<N>, Self>; | 195 | fn intern(db: &impl DefDatabase, loc: ItemLoc<N>) -> Self; |
196 | fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<N>; | ||
197 | |||
209 | fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self { | 198 | fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self { |
210 | let items = ctx.db.ast_id_map(ctx.file_id); | 199 | let items = ctx.db.ast_id_map(ctx.file_id); |
211 | let item_id = items.ast_id(ast); | 200 | let item_id = items.ast_id(ast); |
@@ -213,80 +202,100 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone { | |||
213 | } | 202 | } |
214 | fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self { | 203 | fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self { |
215 | let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) }; | 204 | let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) }; |
216 | Self::interner(ctx.db.as_ref()).loc2id(&loc) | 205 | Self::intern(ctx.db, loc) |
217 | } | 206 | } |
218 | fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) { | 207 | fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) { |
219 | let int = Self::interner(db.as_ref()); | 208 | let loc = self.lookup_intern(db); |
220 | let loc = int.id2loc(self); | ||
221 | let ast = loc.ast_id.to_node(db); | 209 | let ast = loc.ast_id.to_node(db); |
222 | (loc.ast_id.file_id(), ast) | 210 | (loc.ast_id.file_id(), ast) |
223 | } | 211 | } |
224 | fn module(self, db: &impl DefDatabase) -> Module { | 212 | fn module(self, db: &impl DefDatabase) -> Module { |
225 | let int = Self::interner(db.as_ref()); | 213 | let loc = self.lookup_intern(db); |
226 | let loc = int.id2loc(self); | ||
227 | loc.module | 214 | loc.module |
228 | } | 215 | } |
229 | } | 216 | } |
230 | 217 | ||
231 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 218 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
232 | pub(crate) struct FunctionId(RawId); | 219 | pub struct FunctionId(salsa::InternId); |
233 | impl_arena_id!(FunctionId); | 220 | impl_intern_key!(FunctionId); |
221 | |||
234 | impl AstItemDef<ast::FnDef> for FunctionId { | 222 | impl AstItemDef<ast::FnDef> for FunctionId { |
235 | fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::FnDef>, Self> { | 223 | fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::FnDef>) -> Self { |
236 | &interner.fns | 224 | db.intern_function(loc) |
225 | } | ||
226 | fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::FnDef> { | ||
227 | db.lookup_intern_function(self) | ||
237 | } | 228 | } |
238 | } | 229 | } |
239 | 230 | ||
240 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 231 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
241 | pub(crate) struct StructId(RawId); | 232 | pub struct StructId(salsa::InternId); |
242 | impl_arena_id!(StructId); | 233 | impl_intern_key!(StructId); |
243 | impl AstItemDef<ast::StructDef> for StructId { | 234 | impl AstItemDef<ast::StructDef> for StructId { |
244 | fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StructDef>, Self> { | 235 | fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StructDef>) -> Self { |
245 | &interner.structs | 236 | db.intern_struct(loc) |
237 | } | ||
238 | fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StructDef> { | ||
239 | db.lookup_intern_struct(self) | ||
246 | } | 240 | } |
247 | } | 241 | } |
248 | 242 | ||
249 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 243 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
250 | pub(crate) struct EnumId(RawId); | 244 | pub struct EnumId(salsa::InternId); |
251 | impl_arena_id!(EnumId); | 245 | impl_intern_key!(EnumId); |
252 | impl AstItemDef<ast::EnumDef> for EnumId { | 246 | impl AstItemDef<ast::EnumDef> for EnumId { |
253 | fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::EnumDef>, Self> { | 247 | fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::EnumDef>) -> Self { |
254 | &interner.enums | 248 | db.intern_enum(loc) |
249 | } | ||
250 | fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::EnumDef> { | ||
251 | db.lookup_intern_enum(self) | ||
255 | } | 252 | } |
256 | } | 253 | } |
257 | 254 | ||
258 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 255 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
259 | pub(crate) struct ConstId(RawId); | 256 | pub struct ConstId(salsa::InternId); |
260 | impl_arena_id!(ConstId); | 257 | impl_intern_key!(ConstId); |
261 | impl AstItemDef<ast::ConstDef> for ConstId { | 258 | impl AstItemDef<ast::ConstDef> for ConstId { |
262 | fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::ConstDef>, Self> { | 259 | fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::ConstDef>) -> Self { |
263 | &interner.consts | 260 | db.intern_const(loc) |
261 | } | ||
262 | fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::ConstDef> { | ||
263 | db.lookup_intern_const(self) | ||
264 | } | 264 | } |
265 | } | 265 | } |
266 | 266 | ||
267 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 267 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
268 | pub(crate) struct StaticId(RawId); | 268 | pub struct StaticId(salsa::InternId); |
269 | impl_arena_id!(StaticId); | 269 | impl_intern_key!(StaticId); |
270 | impl AstItemDef<ast::StaticDef> for StaticId { | 270 | impl AstItemDef<ast::StaticDef> for StaticId { |
271 | fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StaticDef>, Self> { | 271 | fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StaticDef>) -> Self { |
272 | &interner.statics | 272 | db.intern_static(loc) |
273 | } | ||
274 | fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StaticDef> { | ||
275 | db.lookup_intern_static(self) | ||
273 | } | 276 | } |
274 | } | 277 | } |
275 | 278 | ||
276 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 279 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
277 | pub(crate) struct TraitId(RawId); | 280 | pub struct TraitId(salsa::InternId); |
278 | impl_arena_id!(TraitId); | 281 | impl_intern_key!(TraitId); |
279 | impl AstItemDef<ast::TraitDef> for TraitId { | 282 | impl AstItemDef<ast::TraitDef> for TraitId { |
280 | fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TraitDef>, Self> { | 283 | fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TraitDef>) -> Self { |
281 | &interner.traits | 284 | db.intern_trait(loc) |
285 | } | ||
286 | fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TraitDef> { | ||
287 | db.lookup_intern_trait(self) | ||
282 | } | 288 | } |
283 | } | 289 | } |
284 | 290 | ||
285 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 291 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
286 | pub(crate) struct TypeAliasId(RawId); | 292 | pub struct TypeAliasId(salsa::InternId); |
287 | impl_arena_id!(TypeAliasId); | 293 | impl_intern_key!(TypeAliasId); |
288 | impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { | 294 | impl AstItemDef<ast::TypeAliasDef> for TypeAliasId { |
289 | fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TypeAliasDef>, Self> { | 295 | fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self { |
290 | &interner.types | 296 | db.intern_type_alias(loc) |
297 | } | ||
298 | fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TypeAliasDef> { | ||
299 | db.lookup_intern_type_alias(self) | ||
291 | } | 300 | } |
292 | } | 301 | } |
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 40d368cd9..a8a466e43 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -9,16 +9,15 @@ use ra_syntax::{ | |||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | Const, TypeAlias, Function, HirFileId, | 11 | Const, TypeAlias, Function, HirFileId, |
12 | HirDatabase, DefDatabase, | 12 | HirDatabase, DefDatabase, TraitRef, |
13 | ModuleDef, Trait, Resolution, | ||
14 | type_ref::TypeRef, | 13 | type_ref::TypeRef, |
15 | ids::LocationCtx, | 14 | ids::LocationCtx, |
16 | resolve::Resolver, | 15 | resolve::Resolver, |
17 | ty::Ty, generics::GenericParams, | 16 | ty::Ty, |
17 | generics::HasGenericParams, | ||
18 | code_model_api::{Module, ModuleSource} | ||
18 | }; | 19 | }; |
19 | 20 | ||
20 | use crate::code_model_api::{Module, ModuleSource}; | ||
21 | |||
22 | #[derive(Debug, Default, PartialEq, Eq)] | 21 | #[derive(Debug, Default, PartialEq, Eq)] |
23 | pub struct ImplSourceMap { | 22 | pub struct ImplSourceMap { |
24 | map: ArenaMap<ImplId, AstPtr<ast::ImplBlock>>, | 23 | map: ArenaMap<ImplId, AstPtr<ast::ImplBlock>>, |
@@ -73,7 +72,7 @@ impl ImplBlock { | |||
73 | self.module | 72 | self.module |
74 | } | 73 | } |
75 | 74 | ||
76 | pub fn target_trait_ref(&self, db: &impl DefDatabase) -> Option<TypeRef> { | 75 | pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> { |
77 | db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned() | 76 | db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned() |
78 | } | 77 | } |
79 | 78 | ||
@@ -85,27 +84,16 @@ impl ImplBlock { | |||
85 | Ty::from_hir(db, &self.resolver(db), &self.target_type(db)) | 84 | Ty::from_hir(db, &self.resolver(db), &self.target_type(db)) |
86 | } | 85 | } |
87 | 86 | ||
88 | pub fn target_trait(&self, db: &impl HirDatabase) -> Option<Trait> { | 87 | pub fn target_trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> { |
89 | if let Some(TypeRef::Path(path)) = self.target_trait_ref(db) { | 88 | let target_ty = self.target_ty(db); |
90 | let resolver = self.resolver(db); | 89 | TraitRef::from_hir(db, &self.resolver(db), &self.target_trait(db)?, Some(target_ty)) |
91 | if let Some(Resolution::Def(ModuleDef::Trait(tr))) = | ||
92 | resolver.resolve_path(db, &path).take_types() | ||
93 | { | ||
94 | return Some(tr); | ||
95 | } | ||
96 | } | ||
97 | None | ||
98 | } | 90 | } |
99 | 91 | ||
100 | pub fn items(&self, db: &impl DefDatabase) -> Vec<ImplItem> { | 92 | pub fn items(&self, db: &impl DefDatabase) -> Vec<ImplItem> { |
101 | db.impls_in_module(self.module).impls[self.impl_id].items().to_vec() | 93 | db.impls_in_module(self.module).impls[self.impl_id].items().to_vec() |
102 | } | 94 | } |
103 | 95 | ||
104 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { | 96 | pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { |
105 | db.generic_params((*self).into()) | ||
106 | } | ||
107 | |||
108 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
109 | let r = self.module().resolver(db); | 97 | let r = self.module().resolver(db); |
110 | // add generic params, if present | 98 | // add generic params, if present |
111 | let p = self.generic_params(db); | 99 | let p = self.generic_params(db); |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index c19450f39..9292de1b5 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -17,6 +17,8 @@ macro_rules! impl_froms { | |||
17 | } | 17 | } |
18 | } | 18 | } |
19 | 19 | ||
20 | mod either; | ||
21 | |||
20 | pub mod db; | 22 | pub mod db; |
21 | #[macro_use] | 23 | #[macro_use] |
22 | pub mod mock; | 24 | pub mod mock; |
@@ -49,20 +51,24 @@ use crate::{ | |||
49 | db::{HirDatabase, DefDatabase}, | 51 | db::{HirDatabase, DefDatabase}, |
50 | name::{AsName, KnownName}, | 52 | name::{AsName, KnownName}, |
51 | source_id::{FileAstId, AstId}, | 53 | source_id::{FileAstId, AstId}, |
54 | resolve::Resolver, | ||
52 | }; | 55 | }; |
53 | 56 | ||
54 | pub use self::{ | 57 | pub use self::{ |
58 | either::Either, | ||
55 | path::{Path, PathKind}, | 59 | path::{Path, PathKind}, |
56 | name::Name, | 60 | name::Name, |
57 | source_id::{AstIdMap, ErasedFileAstId}, | 61 | source_id::{AstIdMap, ErasedFileAstId}, |
58 | ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner}, | 62 | ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc}, |
59 | nameres::{PerNs, Namespace, ImportId, ImportSource}, | 63 | nameres::{PerNs, Namespace, ImportId}, |
60 | ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, | 64 | ty::{Ty, ApplicationTy, TypeCtor, TraitRef, Substs, display::HirDisplay, CallableDef}, |
61 | impl_block::{ImplBlock, ImplItem}, | 65 | impl_block::{ImplBlock, ImplItem}, |
62 | docs::{Docs, Documentation}, | 66 | docs::{Docs, Documentation}, |
63 | adt::AdtDef, | 67 | adt::AdtDef, |
64 | expr::{ExprScopes, ScopesWithSourceMap, ScopeEntryWithSyntax}, | 68 | expr::ExprScopes, |
65 | resolve::{Resolver, Resolution}, | 69 | resolve::Resolution, |
70 | generics::{GenericParams, GenericParam, HasGenericParams}, | ||
71 | source_binder::{SourceAnalyzer, PathResolution, ScopeEntryWithSyntax}, | ||
66 | }; | 72 | }; |
67 | 73 | ||
68 | pub use self::code_model_api::{ | 74 | pub use self::code_model_api::{ |
@@ -73,5 +79,5 @@ pub use self::code_model_api::{ | |||
73 | Function, FnSignature, | 79 | Function, FnSignature, |
74 | StructField, FieldSource, | 80 | StructField, FieldSource, |
75 | Static, Const, ConstSignature, | 81 | Static, Const, ConstSignature, |
76 | Trait, TypeAlias, | 82 | Trait, TypeAlias, Container, |
77 | }; | 83 | }; |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index aeab6b180..fa5882dea 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -9,7 +9,7 @@ use relative_path::RelativePathBuf; | |||
9 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; | 9 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; |
10 | use rustc_hash::FxHashMap; | 10 | use rustc_hash::FxHashMap; |
11 | 11 | ||
12 | use crate::{db, HirInterner, diagnostics::DiagnosticSink}; | 12 | use crate::{db, diagnostics::DiagnosticSink}; |
13 | 13 | ||
14 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | 14 | pub const WORKSPACE: SourceRootId = SourceRootId(0); |
15 | 15 | ||
@@ -18,7 +18,6 @@ pub const WORKSPACE: SourceRootId = SourceRootId(0); | |||
18 | pub struct MockDatabase { | 18 | pub struct MockDatabase { |
19 | events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, | 19 | events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, |
20 | runtime: salsa::Runtime<MockDatabase>, | 20 | runtime: salsa::Runtime<MockDatabase>, |
21 | interner: Arc<HirInterner>, | ||
22 | files: FxHashMap<String, FileId>, | 21 | files: FxHashMap<String, FileId>, |
23 | } | 22 | } |
24 | 23 | ||
@@ -195,7 +194,6 @@ impl Default for MockDatabase { | |||
195 | let mut db = MockDatabase { | 194 | let mut db = MockDatabase { |
196 | events: Default::default(), | 195 | events: Default::default(), |
197 | runtime: salsa::Runtime::default(), | 196 | runtime: salsa::Runtime::default(), |
198 | interner: Default::default(), | ||
199 | files: FxHashMap::default(), | 197 | files: FxHashMap::default(), |
200 | }; | 198 | }; |
201 | db.set_crate_graph(Default::default()); | 199 | db.set_crate_graph(Default::default()); |
@@ -208,19 +206,12 @@ impl salsa::ParallelDatabase for MockDatabase { | |||
208 | salsa::Snapshot::new(MockDatabase { | 206 | salsa::Snapshot::new(MockDatabase { |
209 | events: Default::default(), | 207 | events: Default::default(), |
210 | runtime: self.runtime.snapshot(self), | 208 | runtime: self.runtime.snapshot(self), |
211 | interner: Arc::clone(&self.interner), | ||
212 | // only the root database can be used to get file_id by path. | 209 | // only the root database can be used to get file_id by path. |
213 | files: FxHashMap::default(), | 210 | files: FxHashMap::default(), |
214 | }) | 211 | }) |
215 | } | 212 | } |
216 | } | 213 | } |
217 | 214 | ||
218 | impl AsRef<HirInterner> for MockDatabase { | ||
219 | fn as_ref(&self) -> &HirInterner { | ||
220 | &self.interner | ||
221 | } | ||
222 | } | ||
223 | |||
224 | impl MockDatabase { | 215 | impl MockDatabase { |
225 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<MockDatabase>> { | 216 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<MockDatabase>> { |
226 | *self.events.lock() = Some(Vec::new()); | 217 | *self.events.lock() = Some(Vec::new()); |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 4ae04514a..0eddfab12 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -75,7 +75,7 @@ pub(crate) use self::raw::{RawItems, ImportSourceMap}; | |||
75 | 75 | ||
76 | pub use self::{ | 76 | pub use self::{ |
77 | per_ns::{PerNs, Namespace}, | 77 | per_ns::{PerNs, Namespace}, |
78 | raw::{ImportId, ImportSource}, | 78 | raw::ImportId, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | /// Contans all top-level defs from a macro-expanded crate | 81 | /// Contans all top-level defs from a macro-expanded crate |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index b7416ede6..43c97a0bf 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -12,7 +12,7 @@ use ra_syntax::{ | |||
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, | 14 | DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, |
15 | AstIdMap, FileAstId, | 15 | AstIdMap, FileAstId, Either, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | /// `RawItems` is a set of top-level items in a file (except for impls). | 18 | /// `RawItems` is a set of top-level items in a file (except for impls). |
@@ -34,28 +34,15 @@ pub struct ImportSourceMap { | |||
34 | map: ArenaMap<ImportId, ImportSourcePtr>, | 34 | map: ArenaMap<ImportId, ImportSourcePtr>, |
35 | } | 35 | } |
36 | 36 | ||
37 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 37 | type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>; |
38 | enum ImportSourcePtr { | 38 | type ImportSource = Either<TreeArc<ast::UseTree>, TreeArc<ast::ExternCrateItem>>; |
39 | UseTree(AstPtr<ast::UseTree>), | ||
40 | ExternCrate(AstPtr<ast::ExternCrateItem>), | ||
41 | } | ||
42 | 39 | ||
43 | impl ImportSourcePtr { | 40 | impl ImportSourcePtr { |
44 | fn to_node(self, file: &SourceFile) -> ImportSource { | 41 | fn to_node(self, file: &SourceFile) -> ImportSource { |
45 | match self { | 42 | self.map(|ptr| ptr.to_node(file).to_owned(), |ptr| ptr.to_node(file).to_owned()) |
46 | ImportSourcePtr::UseTree(ptr) => ImportSource::UseTree(ptr.to_node(file).to_owned()), | ||
47 | ImportSourcePtr::ExternCrate(ptr) => { | ||
48 | ImportSource::ExternCrate(ptr.to_node(file).to_owned()) | ||
49 | } | ||
50 | } | ||
51 | } | 43 | } |
52 | } | 44 | } |
53 | 45 | ||
54 | pub enum ImportSource { | ||
55 | UseTree(TreeArc<ast::UseTree>), | ||
56 | ExternCrate(TreeArc<ast::ExternCrateItem>), | ||
57 | } | ||
58 | |||
59 | impl ImportSourceMap { | 46 | impl ImportSourceMap { |
60 | fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) { | 47 | fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) { |
61 | self.map.insert(import, ptr) | 48 | self.map.insert(import, ptr) |
@@ -281,11 +268,7 @@ impl RawItemsCollector { | |||
281 | Path::expand_use_item(use_item, |path, use_tree, is_glob, alias| { | 268 | Path::expand_use_item(use_item, |path, use_tree, is_glob, alias| { |
282 | let import_data = | 269 | let import_data = |
283 | ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false }; | 270 | ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false }; |
284 | self.push_import( | 271 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); |
285 | current_module, | ||
286 | import_data, | ||
287 | ImportSourcePtr::UseTree(AstPtr::new(use_tree)), | ||
288 | ); | ||
289 | }) | 272 | }) |
290 | } | 273 | } |
291 | 274 | ||
@@ -304,11 +287,7 @@ impl RawItemsCollector { | |||
304 | is_prelude: false, | 287 | is_prelude: false, |
305 | is_extern_crate: true, | 288 | is_extern_crate: true, |
306 | }; | 289 | }; |
307 | self.push_import( | 290 | self.push_import(current_module, import_data, Either::B(AstPtr::new(extern_crate))); |
308 | current_module, | ||
309 | import_data, | ||
310 | ImportSourcePtr::ExternCrate(AstPtr::new(extern_crate)), | ||
311 | ); | ||
312 | } | 291 | } |
313 | } | 292 | } |
314 | 293 | ||
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 2609585b1..685f4b8b1 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -9,13 +9,13 @@ use crate::{ | |||
9 | name::{Name, KnownName}, | 9 | name::{Name, KnownName}, |
10 | nameres::{PerNs, CrateDefMap, CrateModuleId}, | 10 | nameres::{PerNs, CrateDefMap, CrateModuleId}, |
11 | generics::GenericParams, | 11 | generics::GenericParams, |
12 | expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, | 12 | expr::{scope::{ExprScopes, ScopeId}, PatId}, |
13 | impl_block::ImplBlock, | 13 | impl_block::ImplBlock, |
14 | path::Path, Trait | 14 | path::Path, Trait |
15 | }; | 15 | }; |
16 | 16 | ||
17 | #[derive(Debug, Clone, Default)] | 17 | #[derive(Debug, Clone, Default)] |
18 | pub struct Resolver { | 18 | pub(crate) struct Resolver { |
19 | scopes: Vec<Scope>, | 19 | scopes: Vec<Scope>, |
20 | } | 20 | } |
21 | 21 | ||
@@ -117,7 +117,7 @@ pub enum Resolution { | |||
117 | } | 117 | } |
118 | 118 | ||
119 | impl Resolver { | 119 | impl Resolver { |
120 | pub fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> { | 120 | pub(crate) fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> { |
121 | let mut resolution = PerNs::none(); | 121 | let mut resolution = PerNs::none(); |
122 | for scope in self.scopes.iter().rev() { | 122 | for scope in self.scopes.iter().rev() { |
123 | resolution = resolution.or(scope.resolve_name(db, name)); | 123 | resolution = resolution.or(scope.resolve_name(db, name)); |
@@ -154,12 +154,12 @@ impl Resolver { | |||
154 | 154 | ||
155 | /// Returns the fully resolved path if we were able to resolve it. | 155 | /// Returns the fully resolved path if we were able to resolve it. |
156 | /// otherwise returns `PerNs::none` | 156 | /// otherwise returns `PerNs::none` |
157 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { | 157 | pub(crate) fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { |
158 | // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise | 158 | // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise |
159 | self.resolve_path_segments(db, path).into_fully_resolved() | 159 | self.resolve_path_segments(db, path).into_fully_resolved() |
160 | } | 160 | } |
161 | 161 | ||
162 | pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> { | 162 | pub(crate) fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> { |
163 | let mut names = FxHashMap::default(); | 163 | let mut names = FxHashMap::default(); |
164 | for scope in self.scopes.iter().rev() { | 164 | for scope in self.scopes.iter().rev() { |
165 | scope.collect_names(db, &mut |name, res| { | 165 | scope.collect_names(db, &mut |name, res| { |
@@ -197,14 +197,6 @@ impl Resolver { | |||
197 | _ => None, | 197 | _ => None, |
198 | }) | 198 | }) |
199 | } | 199 | } |
200 | |||
201 | /// The body from which any `LocalBinding` resolutions in this resolver come. | ||
202 | pub fn body(&self) -> Option<Arc<Body>> { | ||
203 | self.scopes.iter().rev().find_map(|scope| match scope { | ||
204 | Scope::ExprScope(expr_scope) => Some(expr_scope.expr_scopes.body()), | ||
205 | _ => None, | ||
206 | }) | ||
207 | } | ||
208 | } | 200 | } |
209 | 201 | ||
210 | impl Resolver { | 202 | impl Resolver { |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 182ed4c91..bd035ced9 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -5,16 +5,21 @@ | |||
5 | /// | 5 | /// |
6 | /// So, this modules should not be used during hir construction, it exists | 6 | /// So, this modules should not be used during hir construction, it exists |
7 | /// purely for "IDE needs". | 7 | /// purely for "IDE needs". |
8 | use std::sync::Arc; | ||
9 | |||
10 | use rustc_hash::{FxHashSet, FxHashMap}; | ||
8 | use ra_db::{FileId, FilePosition}; | 11 | use ra_db::{FileId, FilePosition}; |
9 | use ra_syntax::{ | 12 | use ra_syntax::{ |
10 | SyntaxNode, | 13 | SyntaxNode, AstPtr, TextUnit, SyntaxNodePtr, TextRange, |
11 | ast::{self, AstNode, NameOwner}, | 14 | ast::{self, AstNode, NameOwner}, |
12 | algo::{find_node_at_offset, find_token_at_offset}, | 15 | algo::find_node_at_offset, |
16 | SyntaxKind::*, | ||
13 | }; | 17 | }; |
14 | 18 | ||
15 | use crate::{ | 19 | use crate::{ |
16 | HirDatabase, Function, Struct, Enum,Const,Static, | 20 | HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody, PerNs, Name, |
17 | AsName, Module, HirFileId, Crate, Trait, Resolver, | 21 | AsName, Module, HirFileId, Crate, Trait, Resolver, |
22 | expr::{BodySourceMap, scope::{ScopeId, ExprScopes}}, | ||
18 | ids::LocationCtx, | 23 | ids::LocationCtx, |
19 | expr, AstId | 24 | expr, AstId |
20 | }; | 25 | }; |
@@ -87,63 +92,6 @@ fn module_from_source( | |||
87 | ) | 92 | ) |
88 | } | 93 | } |
89 | 94 | ||
90 | pub fn const_from_source( | ||
91 | db: &impl HirDatabase, | ||
92 | file_id: FileId, | ||
93 | const_def: &ast::ConstDef, | ||
94 | ) -> Option<Const> { | ||
95 | let module = module_from_child_node(db, file_id, const_def.syntax())?; | ||
96 | let res = const_from_module(db, module, const_def); | ||
97 | Some(res) | ||
98 | } | ||
99 | |||
100 | pub fn const_from_module( | ||
101 | db: &impl HirDatabase, | ||
102 | module: Module, | ||
103 | const_def: &ast::ConstDef, | ||
104 | ) -> Const { | ||
105 | let (file_id, _) = module.definition_source(db); | ||
106 | let file_id = file_id.into(); | ||
107 | let ctx = LocationCtx::new(db, module, file_id); | ||
108 | Const { id: ctx.to_def(const_def) } | ||
109 | } | ||
110 | |||
111 | pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { | ||
112 | let file = db.parse(position.file_id); | ||
113 | let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?; | ||
114 | function_from_source(db, position.file_id, fn_def) | ||
115 | } | ||
116 | |||
117 | pub fn function_from_source( | ||
118 | db: &impl HirDatabase, | ||
119 | file_id: FileId, | ||
120 | fn_def: &ast::FnDef, | ||
121 | ) -> Option<Function> { | ||
122 | let module = module_from_child_node(db, file_id, fn_def.syntax())?; | ||
123 | let res = function_from_module(db, module, fn_def); | ||
124 | Some(res) | ||
125 | } | ||
126 | |||
127 | pub fn function_from_module( | ||
128 | db: &impl HirDatabase, | ||
129 | module: Module, | ||
130 | fn_def: &ast::FnDef, | ||
131 | ) -> Function { | ||
132 | let (file_id, _) = module.definition_source(db); | ||
133 | let file_id = file_id.into(); | ||
134 | let ctx = LocationCtx::new(db, module, file_id); | ||
135 | Function { id: ctx.to_def(fn_def) } | ||
136 | } | ||
137 | |||
138 | pub fn function_from_child_node( | ||
139 | db: &impl HirDatabase, | ||
140 | file_id: FileId, | ||
141 | node: &SyntaxNode, | ||
142 | ) -> Option<Function> { | ||
143 | let fn_def = node.ancestors().find_map(ast::FnDef::cast)?; | ||
144 | function_from_source(db, file_id, fn_def) | ||
145 | } | ||
146 | |||
147 | pub fn struct_from_module( | 95 | pub fn struct_from_module( |
148 | db: &impl HirDatabase, | 96 | db: &impl HirDatabase, |
149 | module: Module, | 97 | module: Module, |
@@ -155,27 +103,6 @@ pub fn struct_from_module( | |||
155 | Struct { id: ctx.to_def(struct_def) } | 103 | Struct { id: ctx.to_def(struct_def) } |
156 | } | 104 | } |
157 | 105 | ||
158 | pub fn static_from_source( | ||
159 | db: &impl HirDatabase, | ||
160 | file_id: FileId, | ||
161 | static_def: &ast::StaticDef, | ||
162 | ) -> Option<Static> { | ||
163 | let module = module_from_child_node(db, file_id, static_def.syntax())?; | ||
164 | let res = static_from_module(db, module, static_def); | ||
165 | Some(res) | ||
166 | } | ||
167 | |||
168 | pub fn static_from_module( | ||
169 | db: &impl HirDatabase, | ||
170 | module: Module, | ||
171 | static_def: &ast::StaticDef, | ||
172 | ) -> Static { | ||
173 | let (file_id, _) = module.definition_source(db); | ||
174 | let file_id = file_id.into(); | ||
175 | let ctx = LocationCtx::new(db, module, file_id); | ||
176 | Static { id: ctx.to_def(static_def) } | ||
177 | } | ||
178 | |||
179 | pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { | 106 | pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { |
180 | let (file_id, _) = module.definition_source(db); | 107 | let (file_id, _) = module.definition_source(db); |
181 | let file_id = file_id.into(); | 108 | let file_id = file_id.into(); |
@@ -194,48 +121,6 @@ pub fn trait_from_module( | |||
194 | Trait { id: ctx.to_def(trait_def) } | 121 | Trait { id: ctx.to_def(trait_def) } |
195 | } | 122 | } |
196 | 123 | ||
197 | pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { | ||
198 | let file_id = position.file_id; | ||
199 | let file = db.parse(file_id); | ||
200 | find_token_at_offset(file.syntax(), position.offset) | ||
201 | .find_map(|token| { | ||
202 | token.parent().ancestors().find_map(|node| { | ||
203 | if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { | ||
204 | if let Some(func) = function_from_child_node(db, file_id, node) { | ||
205 | let scopes = func.scopes(db); | ||
206 | let scope = scopes.scope_for_offset(position.offset); | ||
207 | Some(expr::resolver_for_scope(func.body(db), db, scope)) | ||
208 | } else { | ||
209 | // FIXME const/static/array length | ||
210 | None | ||
211 | } | ||
212 | } else { | ||
213 | try_get_resolver_for_node(db, file_id, node) | ||
214 | } | ||
215 | }) | ||
216 | }) | ||
217 | .unwrap_or_default() | ||
218 | } | ||
219 | |||
220 | pub fn resolver_for_node(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNode) -> Resolver { | ||
221 | node.ancestors() | ||
222 | .find_map(|node| { | ||
223 | if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { | ||
224 | if let Some(func) = function_from_child_node(db, file_id, node) { | ||
225 | let scopes = func.scopes(db); | ||
226 | let scope = scopes.scope_for(&node); | ||
227 | Some(expr::resolver_for_scope(func.body(db), db, scope)) | ||
228 | } else { | ||
229 | // FIXME const/static/array length | ||
230 | None | ||
231 | } | ||
232 | } else { | ||
233 | try_get_resolver_for_node(db, file_id, node) | ||
234 | } | ||
235 | }) | ||
236 | .unwrap_or_default() | ||
237 | } | ||
238 | |||
239 | fn try_get_resolver_for_node( | 124 | fn try_get_resolver_for_node( |
240 | db: &impl HirDatabase, | 125 | db: &impl HirDatabase, |
241 | file_id: FileId, | 126 | file_id: FileId, |
@@ -251,10 +136,281 @@ fn try_get_resolver_for_node( | |||
251 | } else if let Some(e) = ast::EnumDef::cast(node) { | 136 | } else if let Some(e) = ast::EnumDef::cast(node) { |
252 | let module = module_from_child_node(db, file_id, e.syntax())?; | 137 | let module = module_from_child_node(db, file_id, e.syntax())?; |
253 | Some(enum_from_module(db, module, e).resolver(db)) | 138 | Some(enum_from_module(db, module, e).resolver(db)) |
254 | } else if let Some(f) = ast::FnDef::cast(node) { | 139 | } else if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { |
255 | function_from_source(db, file_id, f).map(|f| f.resolver(db)) | 140 | Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) |
256 | } else { | 141 | } else { |
257 | // FIXME add missing cases | 142 | // FIXME add missing cases |
258 | None | 143 | None |
259 | } | 144 | } |
260 | } | 145 | } |
146 | |||
147 | fn def_with_body_from_child_node( | ||
148 | db: &impl HirDatabase, | ||
149 | file_id: FileId, | ||
150 | node: &SyntaxNode, | ||
151 | ) -> Option<DefWithBody> { | ||
152 | let module = module_from_child_node(db, file_id, node)?; | ||
153 | let ctx = LocationCtx::new(db, module, file_id.into()); | ||
154 | node.ancestors().find_map(|node| { | ||
155 | if let Some(def) = ast::FnDef::cast(node) { | ||
156 | return Some(Function { id: ctx.to_def(def) }.into()); | ||
157 | } | ||
158 | if let Some(def) = ast::ConstDef::cast(node) { | ||
159 | return Some(Const { id: ctx.to_def(def) }.into()); | ||
160 | } | ||
161 | if let Some(def) = ast::StaticDef::cast(node) { | ||
162 | return Some(Static { id: ctx.to_def(def) }.into()); | ||
163 | } | ||
164 | None | ||
165 | }) | ||
166 | } | ||
167 | |||
168 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of | ||
169 | /// original source files. It should not be used inside the HIR itself. | ||
170 | #[derive(Debug)] | ||
171 | pub struct SourceAnalyzer { | ||
172 | resolver: Resolver, | ||
173 | body_source_map: Option<Arc<BodySourceMap>>, | ||
174 | infer: Option<Arc<crate::ty::InferenceResult>>, | ||
175 | scopes: Option<Arc<crate::expr::ExprScopes>>, | ||
176 | } | ||
177 | |||
178 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
179 | pub enum PathResolution { | ||
180 | /// An item | ||
181 | Def(crate::ModuleDef), | ||
182 | /// A local binding (only value namespace) | ||
183 | LocalBinding(Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>), | ||
184 | /// A generic parameter | ||
185 | GenericParam(u32), | ||
186 | SelfType(crate::ImplBlock), | ||
187 | AssocItem(crate::ImplItem), | ||
188 | } | ||
189 | |||
190 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
191 | pub struct ScopeEntryWithSyntax { | ||
192 | pub(crate) name: Name, | ||
193 | pub(crate) ptr: Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>, | ||
194 | } | ||
195 | |||
196 | impl ScopeEntryWithSyntax { | ||
197 | pub fn name(&self) -> &Name { | ||
198 | &self.name | ||
199 | } | ||
200 | |||
201 | pub fn ptr(&self) -> Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>> { | ||
202 | self.ptr | ||
203 | } | ||
204 | } | ||
205 | |||
206 | #[derive(Debug)] | ||
207 | pub struct ReferenceDescriptor { | ||
208 | pub range: TextRange, | ||
209 | pub name: String, | ||
210 | } | ||
211 | |||
212 | impl SourceAnalyzer { | ||
213 | pub fn new( | ||
214 | db: &impl HirDatabase, | ||
215 | file_id: FileId, | ||
216 | node: &SyntaxNode, | ||
217 | offset: Option<TextUnit>, | ||
218 | ) -> SourceAnalyzer { | ||
219 | let def_with_body = def_with_body_from_child_node(db, file_id, node); | ||
220 | if let Some(def) = def_with_body { | ||
221 | let source_map = def.body_source_map(db); | ||
222 | let scopes = db.expr_scopes(def); | ||
223 | let scope = match offset { | ||
224 | None => scope_for(&scopes, &source_map, &node), | ||
225 | Some(offset) => scope_for_offset(&scopes, &source_map, offset), | ||
226 | }; | ||
227 | let resolver = expr::resolver_for_scope(def.body(db), db, scope); | ||
228 | SourceAnalyzer { | ||
229 | resolver, | ||
230 | body_source_map: Some(source_map), | ||
231 | infer: Some(def.infer(db)), | ||
232 | scopes: Some(scopes), | ||
233 | } | ||
234 | } else { | ||
235 | SourceAnalyzer { | ||
236 | resolver: node | ||
237 | .ancestors() | ||
238 | .find_map(|node| try_get_resolver_for_node(db, file_id, node)) | ||
239 | .unwrap_or_default(), | ||
240 | body_source_map: None, | ||
241 | infer: None, | ||
242 | scopes: None, | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { | ||
248 | let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?; | ||
249 | Some(self.infer.as_ref()?[expr_id].clone()) | ||
250 | } | ||
251 | |||
252 | pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { | ||
253 | let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?; | ||
254 | Some(self.infer.as_ref()?[pat_id].clone()) | ||
255 | } | ||
256 | |||
257 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | ||
258 | let expr_id = self.body_source_map.as_ref()?.node_expr(call.into())?; | ||
259 | self.infer.as_ref()?.method_resolution(expr_id) | ||
260 | } | ||
261 | |||
262 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { | ||
263 | let expr_id = self.body_source_map.as_ref()?.node_expr(field.into())?; | ||
264 | self.infer.as_ref()?.field_resolution(expr_id) | ||
265 | } | ||
266 | |||
267 | pub fn resolve_hir_path( | ||
268 | &self, | ||
269 | db: &impl HirDatabase, | ||
270 | path: &crate::Path, | ||
271 | ) -> PerNs<crate::Resolution> { | ||
272 | self.resolver.resolve_path(db, path) | ||
273 | } | ||
274 | |||
275 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { | ||
276 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { | ||
277 | let expr_id = self.body_source_map.as_ref()?.node_expr(path_expr.into())?; | ||
278 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | ||
279 | return Some(PathResolution::AssocItem(assoc)); | ||
280 | } | ||
281 | } | ||
282 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { | ||
283 | let pat_id = self.body_source_map.as_ref()?.node_pat(path_pat.into())?; | ||
284 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { | ||
285 | return Some(PathResolution::AssocItem(assoc)); | ||
286 | } | ||
287 | } | ||
288 | let hir_path = crate::Path::from_ast(path)?; | ||
289 | let res = self.resolver.resolve_path(db, &hir_path); | ||
290 | let res = res.clone().take_types().or_else(|| res.take_values())?; | ||
291 | let res = match res { | ||
292 | crate::Resolution::Def(it) => PathResolution::Def(it), | ||
293 | crate::Resolution::LocalBinding(it) => { | ||
294 | PathResolution::LocalBinding(self.body_source_map.as_ref()?.pat_syntax(it)?) | ||
295 | } | ||
296 | crate::Resolution::GenericParam(it) => PathResolution::GenericParam(it), | ||
297 | crate::Resolution::SelfType(it) => PathResolution::SelfType(it), | ||
298 | }; | ||
299 | Some(res) | ||
300 | } | ||
301 | |||
302 | pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { | ||
303 | let mut shadowed = FxHashSet::default(); | ||
304 | let name = name_ref.as_name(); | ||
305 | let source_map = self.body_source_map.as_ref()?; | ||
306 | let scopes = self.scopes.as_ref()?; | ||
307 | let scope = scope_for(scopes, source_map, name_ref.syntax()); | ||
308 | let ret = scopes | ||
309 | .scope_chain(scope) | ||
310 | .flat_map(|scope| scopes.entries(scope).iter()) | ||
311 | .filter(|entry| shadowed.insert(entry.name())) | ||
312 | .filter(|entry| entry.name() == &name) | ||
313 | .nth(0); | ||
314 | ret.and_then(|entry| { | ||
315 | Some(ScopeEntryWithSyntax { | ||
316 | name: entry.name().clone(), | ||
317 | ptr: source_map.pat_syntax(entry.pat())?, | ||
318 | }) | ||
319 | }) | ||
320 | } | ||
321 | |||
322 | pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<crate::Resolution>> { | ||
323 | self.resolver.all_names(db) | ||
324 | } | ||
325 | |||
326 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { | ||
327 | // FIXME: at least, this should work with any DefWithBody, but ideally | ||
328 | // this should be hir-based altogether | ||
329 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | ||
330 | let ptr = Either::A(AstPtr::new(pat.into())); | ||
331 | fn_def | ||
332 | .syntax() | ||
333 | .descendants() | ||
334 | .filter_map(ast::NameRef::cast) | ||
335 | .filter(|name_ref| match self.resolve_local_name(*name_ref) { | ||
336 | None => false, | ||
337 | Some(entry) => entry.ptr() == ptr, | ||
338 | }) | ||
339 | .map(|name_ref| ReferenceDescriptor { | ||
340 | name: name_ref.text().to_string(), | ||
341 | range: name_ref.syntax().range(), | ||
342 | }) | ||
343 | .collect() | ||
344 | } | ||
345 | |||
346 | #[cfg(test)] | ||
347 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { | ||
348 | self.body_source_map.clone().unwrap() | ||
349 | } | ||
350 | |||
351 | #[cfg(test)] | ||
352 | pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> { | ||
353 | self.infer.clone().unwrap() | ||
354 | } | ||
355 | |||
356 | #[cfg(test)] | ||
357 | pub(crate) fn scopes(&self) -> Arc<ExprScopes> { | ||
358 | self.scopes.clone().unwrap() | ||
359 | } | ||
360 | } | ||
361 | |||
362 | fn scope_for( | ||
363 | scopes: &ExprScopes, | ||
364 | source_map: &BodySourceMap, | ||
365 | node: &SyntaxNode, | ||
366 | ) -> Option<ScopeId> { | ||
367 | node.ancestors() | ||
368 | .map(SyntaxNodePtr::new) | ||
369 | .filter_map(|ptr| source_map.syntax_expr(ptr)) | ||
370 | .find_map(|it| scopes.scope_for(it)) | ||
371 | } | ||
372 | |||
373 | fn scope_for_offset( | ||
374 | scopes: &ExprScopes, | ||
375 | source_map: &BodySourceMap, | ||
376 | offset: TextUnit, | ||
377 | ) -> Option<ScopeId> { | ||
378 | scopes | ||
379 | .scope_by_expr() | ||
380 | .iter() | ||
381 | .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope))) | ||
382 | // find containing scope | ||
383 | .min_by_key(|(ptr, _scope)| { | ||
384 | (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) | ||
385 | }) | ||
386 | .map(|(ptr, scope)| adjust(scopes, source_map, ptr, offset).unwrap_or(*scope)) | ||
387 | } | ||
388 | |||
389 | // XXX: during completion, cursor might be outside of any particular | ||
390 | // expression. Try to figure out the correct scope... | ||
391 | fn adjust( | ||
392 | scopes: &ExprScopes, | ||
393 | source_map: &BodySourceMap, | ||
394 | ptr: SyntaxNodePtr, | ||
395 | offset: TextUnit, | ||
396 | ) -> Option<ScopeId> { | ||
397 | let r = ptr.range(); | ||
398 | let child_scopes = scopes | ||
399 | .scope_by_expr() | ||
400 | .iter() | ||
401 | .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope))) | ||
402 | .map(|(ptr, scope)| (ptr.range(), scope)) | ||
403 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); | ||
404 | |||
405 | child_scopes | ||
406 | .max_by(|(r1, _), (r2, _)| { | ||
407 | if r2.is_subrange(&r1) { | ||
408 | std::cmp::Ordering::Greater | ||
409 | } else if r1.is_subrange(&r2) { | ||
410 | std::cmp::Ordering::Less | ||
411 | } else { | ||
412 | r1.start().cmp(&r2.start()) | ||
413 | } | ||
414 | }) | ||
415 | .map(|(_ptr, scope)| *scope) | ||
416 | } | ||
diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs index 725bdd5cb..15f0977b7 100644 --- a/crates/ra_hir/src/traits.rs +++ b/crates/ra_hir/src/traits.rs | |||
@@ -1,10 +1,11 @@ | |||
1 | //! HIR for trait definitions. | 1 | //! HIR for trait definitions. |
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | use rustc_hash::FxHashMap; | ||
4 | 5 | ||
5 | use ra_syntax::ast::{self, NameOwner}; | 6 | use ra_syntax::ast::{self, NameOwner}; |
6 | 7 | ||
7 | use crate::{Function, Const, TypeAlias, Name, DefDatabase, Trait, ids::LocationCtx, name::AsName}; | 8 | use crate::{Function, Const, TypeAlias, Name, DefDatabase, Trait, ids::LocationCtx, name::AsName, Module}; |
8 | 9 | ||
9 | #[derive(Debug, Clone, PartialEq, Eq)] | 10 | #[derive(Debug, Clone, PartialEq, Eq)] |
10 | pub struct TraitData { | 11 | pub struct TraitData { |
@@ -49,4 +50,34 @@ pub enum TraitItem { | |||
49 | TypeAlias(TypeAlias), | 50 | TypeAlias(TypeAlias), |
50 | // Existential | 51 | // Existential |
51 | } | 52 | } |
53 | // FIXME: not every function, ... is actually a trait item. maybe we should make | ||
54 | // sure that you can only turn actual trait items into TraitItems. This would | ||
55 | // require not implementing From, and instead having some checked way of | ||
56 | // casting them. | ||
52 | impl_froms!(TraitItem: Function, Const, TypeAlias); | 57 | impl_froms!(TraitItem: Function, Const, TypeAlias); |
58 | |||
59 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
60 | pub struct TraitItemsIndex { | ||
61 | traits_by_def: FxHashMap<TraitItem, Trait>, | ||
62 | } | ||
63 | |||
64 | impl TraitItemsIndex { | ||
65 | pub(crate) fn trait_items_index(db: &impl DefDatabase, module: Module) -> TraitItemsIndex { | ||
66 | let mut index = TraitItemsIndex { traits_by_def: FxHashMap::default() }; | ||
67 | for decl in module.declarations(db) { | ||
68 | match decl { | ||
69 | crate::ModuleDef::Trait(tr) => { | ||
70 | for item in tr.trait_data(db).items() { | ||
71 | index.traits_by_def.insert(*item, tr); | ||
72 | } | ||
73 | } | ||
74 | _ => {} | ||
75 | } | ||
76 | } | ||
77 | index | ||
78 | } | ||
79 | |||
80 | pub(crate) fn get_parent_trait(&self, item: TraitItem) -> Option<Trait> { | ||
81 | self.traits_by_def.get(&item).cloned() | ||
82 | } | ||
83 | } | ||
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 20e55d92d..12e10c751 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -5,6 +5,7 @@ mod autoderef; | |||
5 | pub(crate) mod primitive; | 5 | pub(crate) mod primitive; |
6 | #[cfg(test)] | 6 | #[cfg(test)] |
7 | mod tests; | 7 | mod tests; |
8 | pub(crate) mod traits; | ||
8 | pub(crate) mod method_resolution; | 9 | pub(crate) mod method_resolution; |
9 | mod op; | 10 | mod op; |
10 | mod lower; | 11 | mod lower; |
@@ -15,10 +16,11 @@ use std::sync::Arc; | |||
15 | use std::{fmt, mem}; | 16 | use std::{fmt, mem}; |
16 | 17 | ||
17 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait}; | 18 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait}; |
19 | use display::{HirDisplay, HirFormatter}; | ||
18 | 20 | ||
19 | pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig}; | 21 | pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig}; |
20 | pub(crate) use infer::{infer, InferenceResult, InferTy}; | 22 | pub(crate) use infer::{infer, InferenceResult, InferTy}; |
21 | use display::{HirDisplay, HirFormatter}; | 23 | pub use lower::CallableDef; |
22 | 24 | ||
23 | /// A type constructor or type name: this might be something like the primitive | 25 | /// A type constructor or type name: this might be something like the primitive |
24 | /// type `bool`, a struct like `Vec`, or things like function pointers or | 26 | /// type `bool`, a struct like `Vec`, or things like function pointers or |
@@ -144,6 +146,10 @@ impl Substs { | |||
144 | Substs(Arc::new([ty])) | 146 | Substs(Arc::new([ty])) |
145 | } | 147 | } |
146 | 148 | ||
149 | pub fn prefix(&self, n: usize) -> Substs { | ||
150 | Substs(self.0.iter().cloned().take(n).collect::<Vec<_>>().into()) | ||
151 | } | ||
152 | |||
147 | pub fn iter(&self) -> impl Iterator<Item = &Ty> { | 153 | pub fn iter(&self) -> impl Iterator<Item = &Ty> { |
148 | self.0.iter() | 154 | self.0.iter() |
149 | } | 155 | } |
@@ -169,6 +175,12 @@ impl Substs { | |||
169 | } | 175 | } |
170 | } | 176 | } |
171 | 177 | ||
178 | impl From<Vec<Ty>> for Substs { | ||
179 | fn from(v: Vec<Ty>) -> Self { | ||
180 | Substs(v.into()) | ||
181 | } | ||
182 | } | ||
183 | |||
172 | /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. | 184 | /// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. |
173 | /// Name to be bikeshedded: TraitBound? TraitImplements? | 185 | /// Name to be bikeshedded: TraitBound? TraitImplements? |
174 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 186 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
@@ -209,6 +221,14 @@ impl FnSig { | |||
209 | &self.params_and_return[self.params_and_return.len() - 1] | 221 | &self.params_and_return[self.params_and_return.len() - 1] |
210 | } | 222 | } |
211 | 223 | ||
224 | /// Applies the given substitutions to all types in this signature and | ||
225 | /// returns the result. | ||
226 | pub fn subst(&self, substs: &Substs) -> FnSig { | ||
227 | let result: Vec<_> = | ||
228 | self.params_and_return.iter().map(|ty| ty.clone().subst(substs)).collect(); | ||
229 | FnSig { params_and_return: result.into() } | ||
230 | } | ||
231 | |||
212 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 232 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
213 | // Without an Arc::make_mut_slice, we can't avoid the clone here: | 233 | // Without an Arc::make_mut_slice, we can't avoid the clone here: |
214 | let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); | 234 | let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); |
@@ -288,6 +308,15 @@ impl Ty { | |||
288 | } | 308 | } |
289 | } | 309 | } |
290 | 310 | ||
311 | pub fn as_callable(&self) -> Option<(CallableDef, &Substs)> { | ||
312 | match self { | ||
313 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(callable_def), parameters }) => { | ||
314 | Some((*callable_def, parameters)) | ||
315 | } | ||
316 | _ => None, | ||
317 | } | ||
318 | } | ||
319 | |||
291 | fn builtin_deref(&self) -> Option<Ty> { | 320 | fn builtin_deref(&self) -> Option<Ty> { |
292 | match self { | 321 | match self { |
293 | Ty::Apply(a_ty) => match a_ty.ctor { | 322 | Ty::Apply(a_ty) => match a_ty.ctor { |
@@ -299,6 +328,20 @@ impl Ty { | |||
299 | } | 328 | } |
300 | } | 329 | } |
301 | 330 | ||
331 | fn callable_sig(&self, db: &impl HirDatabase) -> Option<FnSig> { | ||
332 | match self { | ||
333 | Ty::Apply(a_ty) => match a_ty.ctor { | ||
334 | TypeCtor::FnPtr => Some(FnSig::from_fn_ptr_substs(&a_ty.parameters)), | ||
335 | TypeCtor::FnDef(def) => { | ||
336 | let sig = db.callable_item_signature(def); | ||
337 | Some(sig.subst(&a_ty.parameters)) | ||
338 | } | ||
339 | _ => None, | ||
340 | }, | ||
341 | _ => None, | ||
342 | } | ||
343 | } | ||
344 | |||
302 | /// If this is a type with type parameters (an ADT or function), replaces | 345 | /// If this is a type with type parameters (an ADT or function), replaces |
303 | /// the `Substs` for these type parameters with the given ones. (So e.g. if | 346 | /// the `Substs` for these type parameters with the given ones. (So e.g. if |
304 | /// `self` is `Option<_>` and the substs contain `u32`, we'll have | 347 | /// `self` is `Option<_>` and the substs contain `u32`, we'll have |
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index ab5f008ef..a442a856c 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | //! reference to a type with the field `bar`. This is an approximation of the | 3 | //! reference to a type with the field `bar`. This is an approximation of the |
4 | //! logic in rustc (which lives in librustc_typeck/check/autoderef.rs). | 4 | //! logic in rustc (which lives in librustc_typeck/check/autoderef.rs). |
5 | 5 | ||
6 | use ra_syntax::algo::generate; | 6 | use std::iter::successors; |
7 | 7 | ||
8 | use crate::HirDatabase; | 8 | use crate::HirDatabase; |
9 | use super::Ty; | 9 | use super::Ty; |
@@ -11,7 +11,7 @@ use super::Ty; | |||
11 | impl Ty { | 11 | impl Ty { |
12 | /// Iterates over the possible derefs of `ty`. | 12 | /// Iterates over the possible derefs of `ty`. |
13 | pub fn autoderef<'a>(self, db: &'a impl HirDatabase) -> impl Iterator<Item = Ty> + 'a { | 13 | pub fn autoderef<'a>(self, db: &'a impl HirDatabase) -> impl Iterator<Item = Ty> + 'a { |
14 | generate(Some(self), move |ty| ty.autoderef_step(db)) | 14 | successors(Some(self), move |ty| ty.autoderef_step(db)) |
15 | } | 15 | } |
16 | 16 | ||
17 | fn autoderef_step(&self, _db: &impl HirDatabase) -> Option<Ty> { | 17 | fn autoderef_step(&self, _db: &impl HirDatabase) -> Option<Ty> { |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 28947be51..651a78fe5 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -20,9 +20,9 @@ use std::sync::Arc; | |||
20 | use std::mem; | 20 | use std::mem; |
21 | 21 | ||
22 | use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError}; | 22 | use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError}; |
23 | use ra_arena::map::ArenaMap; | ||
24 | use rustc_hash::FxHashMap; | 23 | use rustc_hash::FxHashMap; |
25 | 24 | ||
25 | use ra_arena::map::ArenaMap; | ||
26 | use test_utils::tested_by; | 26 | use test_utils::tested_by; |
27 | 27 | ||
28 | use crate::{ | 28 | use crate::{ |
@@ -33,15 +33,18 @@ use crate::{ | |||
33 | ImplItem, | 33 | ImplItem, |
34 | type_ref::{TypeRef, Mutability}, | 34 | type_ref::{TypeRef, Mutability}, |
35 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat,Array, self}, | 35 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat,Array, self}, |
36 | generics::GenericParams, | 36 | generics::{GenericParams, HasGenericParams}, |
37 | path::{GenericArgs, GenericArg}, | 37 | path::{GenericArgs, GenericArg}, |
38 | adt::VariantDef, | 38 | adt::VariantDef, |
39 | resolve::{Resolver, Resolution}, | 39 | resolve::{Resolver, Resolution}, |
40 | nameres::Namespace, | 40 | nameres::Namespace, |
41 | ty::infer::diagnostics::InferenceDiagnostic, | ||
42 | diagnostics::DiagnosticSink, | 41 | diagnostics::DiagnosticSink, |
43 | }; | 42 | }; |
44 | use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor}; | 43 | use super::{ |
44 | Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef, | ||
45 | traits::{ Solution, Obligation, Guidance}, | ||
46 | }; | ||
47 | use self::diagnostics::InferenceDiagnostic; | ||
45 | 48 | ||
46 | /// The entry point of type inference. | 49 | /// The entry point of type inference. |
47 | pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { | 50 | pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { |
@@ -153,6 +156,7 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
153 | body: Arc<Body>, | 156 | body: Arc<Body>, |
154 | resolver: Resolver, | 157 | resolver: Resolver, |
155 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 158 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
159 | obligations: Vec<Obligation>, | ||
156 | method_resolutions: FxHashMap<ExprId, Function>, | 160 | method_resolutions: FxHashMap<ExprId, Function>, |
157 | field_resolutions: FxHashMap<ExprId, StructField>, | 161 | field_resolutions: FxHashMap<ExprId, StructField>, |
158 | assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>, | 162 | assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>, |
@@ -173,6 +177,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
173 | type_of_pat: ArenaMap::default(), | 177 | type_of_pat: ArenaMap::default(), |
174 | diagnostics: Vec::default(), | 178 | diagnostics: Vec::default(), |
175 | var_unification_table: InPlaceUnificationTable::new(), | 179 | var_unification_table: InPlaceUnificationTable::new(), |
180 | obligations: Vec::default(), | ||
176 | return_ty: Ty::Unknown, // set in collect_fn_signature | 181 | return_ty: Ty::Unknown, // set in collect_fn_signature |
177 | db, | 182 | db, |
178 | body, | 183 | body, |
@@ -181,6 +186,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
181 | } | 186 | } |
182 | 187 | ||
183 | fn resolve_all(mut self) -> InferenceResult { | 188 | fn resolve_all(mut self) -> InferenceResult { |
189 | // FIXME resolve obligations as well (use Guidance if necessary) | ||
184 | let mut tv_stack = Vec::new(); | 190 | let mut tv_stack = Vec::new(); |
185 | let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default()); | 191 | let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default()); |
186 | for ty in expr_types.values_mut() { | 192 | for ty in expr_types.values_mut() { |
@@ -311,11 +317,49 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
311 | ty.fold(&mut |ty| self.insert_type_vars_shallow(ty)) | 317 | ty.fold(&mut |ty| self.insert_type_vars_shallow(ty)) |
312 | } | 318 | } |
313 | 319 | ||
320 | fn resolve_obligations_as_possible(&mut self) { | ||
321 | let obligations = mem::replace(&mut self.obligations, Vec::new()); | ||
322 | for obligation in obligations { | ||
323 | // FIXME resolve types in the obligation first | ||
324 | let (solution, var_mapping) = match &obligation { | ||
325 | Obligation::Trait(tr) => { | ||
326 | let (tr, var_mapping) = super::traits::canonicalize(tr.clone()); | ||
327 | (self.db.implements(tr), var_mapping) | ||
328 | } | ||
329 | }; | ||
330 | match solution { | ||
331 | Some(Solution::Unique(substs)) => { | ||
332 | for (i, subst) in substs.0.iter().enumerate() { | ||
333 | let uncanonical = var_mapping[i]; | ||
334 | // FIXME the subst may contain type variables, which would need to be mapped back as well | ||
335 | self.unify(&Ty::Infer(InferTy::TypeVar(uncanonical)), subst); | ||
336 | } | ||
337 | } | ||
338 | Some(Solution::Ambig(Guidance::Definite(substs))) => { | ||
339 | for (i, subst) in substs.0.iter().enumerate() { | ||
340 | let uncanonical = var_mapping[i]; | ||
341 | // FIXME the subst may contain type variables, which would need to be mapped back as well | ||
342 | self.unify(&Ty::Infer(InferTy::TypeVar(uncanonical)), subst); | ||
343 | } | ||
344 | self.obligations.push(obligation); | ||
345 | } | ||
346 | Some(_) => { | ||
347 | self.obligations.push(obligation); | ||
348 | } | ||
349 | None => { | ||
350 | // FIXME obligation cannot be fulfilled => diagnostic | ||
351 | } | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | |||
314 | /// Resolves the type as far as currently possible, replacing type variables | 356 | /// Resolves the type as far as currently possible, replacing type variables |
315 | /// by their known types. All types returned by the infer_* functions should | 357 | /// by their known types. All types returned by the infer_* functions should |
316 | /// be resolved as far as possible, i.e. contain no type variables with | 358 | /// be resolved as far as possible, i.e. contain no type variables with |
317 | /// known type. | 359 | /// known type. |
318 | fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { | 360 | fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { |
361 | self.resolve_obligations_as_possible(); | ||
362 | |||
319 | ty.fold(&mut |ty| match ty { | 363 | ty.fold(&mut |ty| match ty { |
320 | Ty::Infer(tv) => { | 364 | Ty::Infer(tv) => { |
321 | let inner = tv.to_inner(); | 365 | let inner = tv.to_inner(); |
@@ -420,6 +464,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
420 | for segment in &path.segments[remaining_index..] { | 464 | for segment in &path.segments[remaining_index..] { |
421 | let ty = match resolved { | 465 | let ty = match resolved { |
422 | Resolution::Def(def) => { | 466 | Resolution::Def(def) => { |
467 | // FIXME resolve associated items from traits as well | ||
423 | let typable: Option<TypableDef> = def.into(); | 468 | let typable: Option<TypableDef> = def.into(); |
424 | let typable = typable?; | 469 | let typable = typable?; |
425 | 470 | ||
@@ -709,13 +754,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
709 | fn substs_for_method_call( | 754 | fn substs_for_method_call( |
710 | &mut self, | 755 | &mut self, |
711 | def_generics: Option<Arc<GenericParams>>, | 756 | def_generics: Option<Arc<GenericParams>>, |
712 | generic_args: &Option<GenericArgs>, | 757 | generic_args: Option<&GenericArgs>, |
758 | receiver_ty: &Ty, | ||
713 | ) -> Substs { | 759 | ) -> Substs { |
714 | let (parent_param_count, param_count) = | 760 | let (parent_param_count, param_count) = |
715 | def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); | 761 | def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); |
716 | let mut substs = Vec::with_capacity(parent_param_count + param_count); | 762 | let mut substs = Vec::with_capacity(parent_param_count + param_count); |
717 | for _ in 0..parent_param_count { | 763 | // Parent arguments are unknown, except for the receiver type |
718 | substs.push(Ty::Unknown); | 764 | if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { |
765 | for param in &parent_generics.params { | ||
766 | if param.name.as_known_name() == Some(crate::KnownName::SelfType) { | ||
767 | substs.push(receiver_ty.clone()); | ||
768 | } else { | ||
769 | substs.push(Ty::Unknown); | ||
770 | } | ||
771 | } | ||
719 | } | 772 | } |
720 | // handle provided type arguments | 773 | // handle provided type arguments |
721 | if let Some(generic_args) = generic_args { | 774 | if let Some(generic_args) = generic_args { |
@@ -737,6 +790,83 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
737 | Substs(substs.into()) | 790 | Substs(substs.into()) |
738 | } | 791 | } |
739 | 792 | ||
793 | fn register_obligations_for_call(&mut self, callable_ty: &Ty) { | ||
794 | match callable_ty { | ||
795 | Ty::Apply(a_ty) => match a_ty.ctor { | ||
796 | TypeCtor::FnDef(def) => { | ||
797 | // add obligation for trait implementation, if this is a trait method | ||
798 | // FIXME also register obligations from where clauses from the trait or impl and method | ||
799 | match def { | ||
800 | CallableDef::Function(f) => { | ||
801 | if let Some(trait_) = f.parent_trait(self.db) { | ||
802 | // construct a TraitDef | ||
803 | let substs = a_ty.parameters.prefix( | ||
804 | trait_.generic_params(self.db).count_params_including_parent(), | ||
805 | ); | ||
806 | self.obligations | ||
807 | .push(Obligation::Trait(TraitRef { trait_, substs })); | ||
808 | } | ||
809 | } | ||
810 | CallableDef::Struct(_) | CallableDef::EnumVariant(_) => {} | ||
811 | } | ||
812 | } | ||
813 | _ => {} | ||
814 | }, | ||
815 | _ => {} | ||
816 | } | ||
817 | } | ||
818 | |||
819 | fn infer_method_call( | ||
820 | &mut self, | ||
821 | tgt_expr: ExprId, | ||
822 | receiver: ExprId, | ||
823 | args: &[ExprId], | ||
824 | method_name: &Name, | ||
825 | generic_args: Option<&GenericArgs>, | ||
826 | ) -> Ty { | ||
827 | let receiver_ty = self.infer_expr(receiver, &Expectation::none()); | ||
828 | let resolved = receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver); | ||
829 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { | ||
830 | Some((ty, func)) => { | ||
831 | self.write_method_resolution(tgt_expr, func); | ||
832 | ( | ||
833 | ty, | ||
834 | self.db.type_for_def(func.into(), Namespace::Values), | ||
835 | Some(func.generic_params(self.db)), | ||
836 | ) | ||
837 | } | ||
838 | None => (receiver_ty, Ty::Unknown, None), | ||
839 | }; | ||
840 | let substs = | ||
841 | self.substs_for_method_call(def_generics.clone(), generic_args, &derefed_receiver_ty); | ||
842 | let method_ty = method_ty.apply_substs(substs); | ||
843 | let method_ty = self.insert_type_vars(method_ty); | ||
844 | self.register_obligations_for_call(&method_ty); | ||
845 | let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { | ||
846 | Some(sig) => { | ||
847 | if !sig.params().is_empty() { | ||
848 | (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone()) | ||
849 | } else { | ||
850 | (Ty::Unknown, Vec::new(), sig.ret().clone()) | ||
851 | } | ||
852 | } | ||
853 | None => (Ty::Unknown, Vec::new(), Ty::Unknown), | ||
854 | }; | ||
855 | // Apply autoref so the below unification works correctly | ||
856 | // FIXME: return correct autorefs from lookup_method | ||
857 | let actual_receiver_ty = match expected_receiver_ty.as_reference() { | ||
858 | Some((_, mutability)) => Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty), | ||
859 | _ => derefed_receiver_ty, | ||
860 | }; | ||
861 | self.unify(&expected_receiver_ty, &actual_receiver_ty); | ||
862 | |||
863 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | ||
864 | for (arg, param) in args.iter().zip(param_iter) { | ||
865 | self.infer_expr(*arg, &Expectation::has_type(param)); | ||
866 | } | ||
867 | ret_ty | ||
868 | } | ||
869 | |||
740 | fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 870 | fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
741 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 871 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
742 | let ty = match &body[tgt_expr] { | 872 | let ty = match &body[tgt_expr] { |
@@ -793,102 +923,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
793 | } | 923 | } |
794 | Expr::Call { callee, args } => { | 924 | Expr::Call { callee, args } => { |
795 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); | 925 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); |
796 | let (param_tys, ret_ty) = match &callee_ty { | 926 | let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) { |
797 | Ty::Apply(a_ty) => match a_ty.ctor { | 927 | Some(sig) => (sig.params().to_vec(), sig.ret().clone()), |
798 | TypeCtor::FnPtr => { | 928 | None => { |
799 | let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters); | 929 | // Not callable |
800 | (sig.params().to_vec(), sig.ret().clone()) | 930 | // FIXME: report an error |
801 | } | ||
802 | TypeCtor::FnDef(def) => { | ||
803 | let sig = self.db.callable_item_signature(def); | ||
804 | let ret_ty = sig.ret().clone().subst(&a_ty.parameters); | ||
805 | let param_tys = sig | ||
806 | .params() | ||
807 | .iter() | ||
808 | .map(|ty| ty.clone().subst(&a_ty.parameters)) | ||
809 | .collect(); | ||
810 | (param_tys, ret_ty) | ||
811 | } | ||
812 | _ => (Vec::new(), Ty::Unknown), | ||
813 | }, | ||
814 | _ => { | ||
815 | // not callable | ||
816 | // FIXME report an error? | ||
817 | (Vec::new(), Ty::Unknown) | 931 | (Vec::new(), Ty::Unknown) |
818 | } | 932 | } |
819 | }; | 933 | }; |
934 | // FIXME register obligations from where clauses from the function | ||
820 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | 935 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); |
821 | for (arg, param) in args.iter().zip(param_iter) { | 936 | for (arg, param) in args.iter().zip(param_iter) { |
822 | self.infer_expr(*arg, &Expectation::has_type(param)); | 937 | self.infer_expr(*arg, &Expectation::has_type(param)); |
823 | } | 938 | } |
824 | ret_ty | 939 | ret_ty |
825 | } | 940 | } |
826 | Expr::MethodCall { receiver, args, method_name, generic_args } => { | 941 | Expr::MethodCall { receiver, args, method_name, generic_args } => self |
827 | let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); | 942 | .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), |
828 | let resolved = | ||
829 | receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver); | ||
830 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { | ||
831 | Some((ty, func)) => { | ||
832 | self.write_method_resolution(tgt_expr, func); | ||
833 | ( | ||
834 | ty, | ||
835 | self.db.type_for_def(func.into(), Namespace::Values), | ||
836 | Some(func.generic_params(self.db)), | ||
837 | ) | ||
838 | } | ||
839 | None => (receiver_ty, Ty::Unknown, None), | ||
840 | }; | ||
841 | let substs = self.substs_for_method_call(def_generics, generic_args); | ||
842 | let method_ty = method_ty.apply_substs(substs); | ||
843 | let method_ty = self.insert_type_vars(method_ty); | ||
844 | let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { | ||
845 | Ty::Apply(a_ty) => match a_ty.ctor { | ||
846 | TypeCtor::FnPtr => { | ||
847 | let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters); | ||
848 | if !sig.params().is_empty() { | ||
849 | ( | ||
850 | sig.params()[0].clone(), | ||
851 | sig.params()[1..].to_vec(), | ||
852 | sig.ret().clone(), | ||
853 | ) | ||
854 | } else { | ||
855 | (Ty::Unknown, Vec::new(), sig.ret().clone()) | ||
856 | } | ||
857 | } | ||
858 | TypeCtor::FnDef(def) => { | ||
859 | let sig = self.db.callable_item_signature(def); | ||
860 | let ret_ty = sig.ret().clone().subst(&a_ty.parameters); | ||
861 | |||
862 | if !sig.params().is_empty() { | ||
863 | let mut params_iter = sig | ||
864 | .params() | ||
865 | .iter() | ||
866 | .map(|ty| ty.clone().subst(&a_ty.parameters)); | ||
867 | let receiver_ty = params_iter.next().unwrap(); | ||
868 | (receiver_ty, params_iter.collect(), ret_ty) | ||
869 | } else { | ||
870 | (Ty::Unknown, Vec::new(), ret_ty) | ||
871 | } | ||
872 | } | ||
873 | _ => (Ty::Unknown, Vec::new(), Ty::Unknown), | ||
874 | }, | ||
875 | _ => (Ty::Unknown, Vec::new(), Ty::Unknown), | ||
876 | }; | ||
877 | // Apply autoref so the below unification works correctly | ||
878 | let actual_receiver_ty = match expected_receiver_ty.as_reference() { | ||
879 | Some((_, mutability)) => { | ||
880 | Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty) | ||
881 | } | ||
882 | _ => derefed_receiver_ty, | ||
883 | }; | ||
884 | self.unify(&expected_receiver_ty, &actual_receiver_ty); | ||
885 | |||
886 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | ||
887 | for (arg, param) in args.iter().zip(param_iter) { | ||
888 | self.infer_expr(*arg, &Expectation::has_type(param)); | ||
889 | } | ||
890 | ret_ty | ||
891 | } | ||
892 | Expr::Match { expr, arms } => { | 943 | Expr::Match { expr, arms } => { |
893 | let expected = if expected.ty == Ty::Unknown { | 944 | let expected = if expected.ty == Ty::Unknown { |
894 | Expectation::has_type(self.new_type_var()) | 945 | Expectation::has_type(self.new_type_var()) |
@@ -1180,7 +1231,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1180 | 1231 | ||
1181 | /// The ID of a type variable. | 1232 | /// The ID of a type variable. |
1182 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | 1233 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] |
1183 | pub struct TypeVarId(u32); | 1234 | pub struct TypeVarId(pub(super) u32); |
1184 | 1235 | ||
1185 | impl UnifyKey for TypeVarId { | 1236 | impl UnifyKey for TypeVarId { |
1186 | type Value = TypeVarValue; | 1237 | type Value = TypeVarValue; |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 003a89f0d..7fac084ce 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -5,6 +5,7 @@ | |||
5 | //! - Building the type for an item: This happens through the `type_for_def` query. | 5 | //! - Building the type for an item: This happens through the `type_for_def` query. |
6 | //! | 6 | //! |
7 | //! This usually involves resolving names, collecting generic arguments etc. | 7 | //! This usually involves resolving names, collecting generic arguments etc. |
8 | use std::iter; | ||
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | Function, Struct, StructField, Enum, EnumVariant, Path, | 11 | Function, Struct, StructField, Enum, EnumVariant, Path, |
@@ -15,11 +16,11 @@ use crate::{ | |||
15 | name::KnownName, | 16 | name::KnownName, |
16 | nameres::Namespace, | 17 | nameres::Namespace, |
17 | resolve::{Resolver, Resolution}, | 18 | resolve::{Resolver, Resolution}, |
18 | path::{ PathSegment, GenericArg}, | 19 | path::{PathSegment, GenericArg}, |
19 | generics::GenericParams, | 20 | generics::{GenericParams, HasGenericParams}, |
20 | adt::VariantDef, | 21 | adt::VariantDef, Trait |
21 | }; | 22 | }; |
22 | use super::{Ty, primitive, FnSig, Substs, TypeCtor}; | 23 | use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef}; |
23 | 24 | ||
24 | impl Ty { | 25 | impl Ty { |
25 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { | 26 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { |
@@ -115,7 +116,6 @@ impl Ty { | |||
115 | segment: &PathSegment, | 116 | segment: &PathSegment, |
116 | resolved: TypableDef, | 117 | resolved: TypableDef, |
117 | ) -> Substs { | 118 | ) -> Substs { |
118 | let mut substs = Vec::new(); | ||
119 | let def_generics = match resolved { | 119 | let def_generics = match resolved { |
120 | TypableDef::Function(func) => func.generic_params(db), | 120 | TypableDef::Function(func) => func.generic_params(db), |
121 | TypableDef::Struct(s) => s.generic_params(db), | 121 | TypableDef::Struct(s) => s.generic_params(db), |
@@ -124,28 +124,7 @@ impl Ty { | |||
124 | TypableDef::TypeAlias(t) => t.generic_params(db), | 124 | TypableDef::TypeAlias(t) => t.generic_params(db), |
125 | TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), | 125 | TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), |
126 | }; | 126 | }; |
127 | let parent_param_count = def_generics.count_parent_params(); | 127 | substs_from_path_segment(db, resolver, segment, &def_generics, false) |
128 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | ||
129 | if let Some(generic_args) = &segment.args_and_bindings { | ||
130 | // if args are provided, it should be all of them, but we can't rely on that | ||
131 | let param_count = def_generics.params.len(); | ||
132 | for arg in generic_args.args.iter().take(param_count) { | ||
133 | match arg { | ||
134 | GenericArg::Type(type_ref) => { | ||
135 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
136 | substs.push(ty); | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | // add placeholders for args that were not provided | ||
142 | // FIXME: handle defaults | ||
143 | let supplied_params = substs.len(); | ||
144 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
145 | substs.push(Ty::Unknown); | ||
146 | } | ||
147 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
148 | Substs(substs.into()) | ||
149 | } | 128 | } |
150 | 129 | ||
151 | /// Collect generic arguments from a path into a `Substs`. See also | 130 | /// Collect generic arguments from a path into a `Substs`. See also |
@@ -185,6 +164,82 @@ impl Ty { | |||
185 | } | 164 | } |
186 | } | 165 | } |
187 | 166 | ||
167 | pub(super) fn substs_from_path_segment( | ||
168 | db: &impl HirDatabase, | ||
169 | resolver: &Resolver, | ||
170 | segment: &PathSegment, | ||
171 | def_generics: &GenericParams, | ||
172 | add_self_param: bool, | ||
173 | ) -> Substs { | ||
174 | let mut substs = Vec::new(); | ||
175 | let parent_param_count = def_generics.count_parent_params(); | ||
176 | substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); | ||
177 | if add_self_param { | ||
178 | // FIXME this add_self_param argument is kind of a hack: Traits have the | ||
179 | // Self type as an implicit first type parameter, but it can't be | ||
180 | // actually provided in the type arguments | ||
181 | // (well, actually sometimes it can, in the form of type-relative paths: `<Foo as Default>::default()`) | ||
182 | substs.push(Ty::Unknown); | ||
183 | } | ||
184 | if let Some(generic_args) = &segment.args_and_bindings { | ||
185 | // if args are provided, it should be all of them, but we can't rely on that | ||
186 | let self_param_correction = if add_self_param { 1 } else { 0 }; | ||
187 | let param_count = def_generics.params.len() - self_param_correction; | ||
188 | for arg in generic_args.args.iter().take(param_count) { | ||
189 | match arg { | ||
190 | GenericArg::Type(type_ref) => { | ||
191 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
192 | substs.push(ty); | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | // add placeholders for args that were not provided | ||
198 | // FIXME: handle defaults | ||
199 | let supplied_params = substs.len(); | ||
200 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
201 | substs.push(Ty::Unknown); | ||
202 | } | ||
203 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
204 | Substs(substs.into()) | ||
205 | } | ||
206 | |||
207 | impl TraitRef { | ||
208 | pub(crate) fn from_hir( | ||
209 | db: &impl HirDatabase, | ||
210 | resolver: &Resolver, | ||
211 | type_ref: &TypeRef, | ||
212 | explicit_self_ty: Option<Ty>, | ||
213 | ) -> Option<Self> { | ||
214 | let path = match type_ref { | ||
215 | TypeRef::Path(path) => path, | ||
216 | _ => return None, | ||
217 | }; | ||
218 | let resolved = match resolver.resolve_path(db, &path).take_types()? { | ||
219 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | ||
220 | _ => return None, | ||
221 | }; | ||
222 | let mut substs = Self::substs_from_path(db, resolver, path, resolved); | ||
223 | if let Some(self_ty) = explicit_self_ty { | ||
224 | // FIXME this could be nicer | ||
225 | let mut substs_vec = substs.0.to_vec(); | ||
226 | substs_vec[0] = self_ty; | ||
227 | substs.0 = substs_vec.into(); | ||
228 | } | ||
229 | Some(TraitRef { trait_: resolved, substs }) | ||
230 | } | ||
231 | |||
232 | fn substs_from_path( | ||
233 | db: &impl HirDatabase, | ||
234 | resolver: &Resolver, | ||
235 | path: &Path, | ||
236 | resolved: Trait, | ||
237 | ) -> Substs { | ||
238 | let segment = path.segments.last().expect("path should have at least one segment"); | ||
239 | substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true) | ||
240 | } | ||
241 | } | ||
242 | |||
188 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 243 | /// Build the declared type of an item. This depends on the namespace; e.g. for |
189 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | 244 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and |
190 | /// the constructor function `(usize) -> Foo` which lives in the values | 245 | /// the constructor function `(usize) -> Foo` which lives in the values |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 3ac8dc46b..6b7918187 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -10,10 +10,12 @@ use crate::{ | |||
10 | HirDatabase, Module, Crate, Name, Function, Trait, | 10 | HirDatabase, Module, Crate, Name, Function, Trait, |
11 | impl_block::{ImplId, ImplBlock, ImplItem}, | 11 | impl_block::{ImplId, ImplBlock, ImplItem}, |
12 | ty::{Ty, TypeCtor}, | 12 | ty::{Ty, TypeCtor}, |
13 | nameres::CrateModuleId, resolve::Resolver, traits::TraitItem | 13 | nameres::CrateModuleId, |
14 | 14 | resolve::Resolver, | |
15 | traits::TraitItem, | ||
16 | generics::HasGenericParams, | ||
15 | }; | 17 | }; |
16 | use super::{ TraitRef, Substs}; | 18 | use super::{TraitRef, Substs}; |
17 | 19 | ||
18 | /// This is used as a key for indexing impls. | 20 | /// This is used as a key for indexing impls. |
19 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 21 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
@@ -72,9 +74,9 @@ impl CrateImplBlocks { | |||
72 | 74 | ||
73 | let target_ty = impl_block.target_ty(db); | 75 | let target_ty = impl_block.target_ty(db); |
74 | 76 | ||
75 | if let Some(tr) = impl_block.target_trait(db) { | 77 | if let Some(tr) = impl_block.target_trait_ref(db) { |
76 | self.impls_by_trait | 78 | self.impls_by_trait |
77 | .entry(tr) | 79 | .entry(tr.trait_) |
78 | .or_insert_with(Vec::new) | 80 | .or_insert_with(Vec::new) |
79 | .push((module.module_id, impl_id)); | 81 | .push((module.module_id, impl_id)); |
80 | } else { | 82 | } else { |
@@ -108,20 +110,6 @@ impl CrateImplBlocks { | |||
108 | } | 110 | } |
109 | } | 111 | } |
110 | 112 | ||
111 | /// Rudimentary check whether an impl exists for a given type and trait; this | ||
112 | /// will actually be done by chalk. | ||
113 | pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool { | ||
114 | // FIXME use all trait impls in the whole crate graph | ||
115 | let krate = trait_ref.trait_.module(db).krate(db); | ||
116 | let krate = match krate { | ||
117 | Some(krate) => krate, | ||
118 | None => return false, | ||
119 | }; | ||
120 | let crate_impl_blocks = db.impls_in_crate(krate); | ||
121 | let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_); | ||
122 | impl_blocks.any(|impl_block| &impl_block.target_ty(db) == trait_ref.self_ty()) | ||
123 | } | ||
124 | |||
125 | fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | 113 | fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { |
126 | match ty { | 114 | match ty { |
127 | Ty::Apply(a_ty) => match a_ty.ctor { | 115 | Ty::Apply(a_ty) => match a_ty.ctor { |
@@ -135,13 +123,14 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | |||
135 | impl Ty { | 123 | impl Ty { |
136 | /// Look up the method with the given name, returning the actual autoderefed | 124 | /// Look up the method with the given name, returning the actual autoderefed |
137 | /// receiver type (but without autoref applied yet). | 125 | /// receiver type (but without autoref applied yet). |
138 | pub fn lookup_method( | 126 | pub(crate) fn lookup_method( |
139 | self, | 127 | self, |
140 | db: &impl HirDatabase, | 128 | db: &impl HirDatabase, |
141 | name: &Name, | 129 | name: &Name, |
142 | resolver: &Resolver, | 130 | resolver: &Resolver, |
143 | ) -> Option<(Ty, Function)> { | 131 | ) -> Option<(Ty, Function)> { |
144 | // FIXME: trait methods should be used before autoderefs | 132 | // FIXME: trait methods should be used before autoderefs |
133 | // (and we need to do autoderefs for trait method calls as well) | ||
145 | let inherent_method = self.clone().iterate_methods(db, |ty, f| { | 134 | let inherent_method = self.clone().iterate_methods(db, |ty, f| { |
146 | let sig = f.signature(db); | 135 | let sig = f.signature(db); |
147 | if sig.name() == name && sig.has_self_param() { | 136 | if sig.name() == name && sig.has_self_param() { |
@@ -174,22 +163,15 @@ impl Ty { | |||
174 | } | 163 | } |
175 | } | 164 | } |
176 | } | 165 | } |
177 | // FIXME: | ||
178 | // - we might not actually be able to determine fully that the type | ||
179 | // implements the trait here; it's enough if we (well, Chalk) determine | ||
180 | // that it's possible. | ||
181 | // - when the trait method is picked, we need to register an | ||
182 | // 'obligation' somewhere so that we later check that it's really | ||
183 | // implemented | ||
184 | // - both points go for additional requirements from where clauses as | ||
185 | // well (in fact, the 'implements' condition could just be considered a | ||
186 | // 'where Self: Trait' clause) | ||
187 | candidates.retain(|(t, _m)| { | 166 | candidates.retain(|(t, _m)| { |
188 | let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; | 167 | let trait_ref = |
189 | db.implements(trait_ref) | 168 | TraitRef { trait_: *t, substs: fresh_substs_for_trait(db, *t, self.clone()) }; |
169 | let (trait_ref, _) = super::traits::canonicalize(trait_ref); | ||
170 | db.implements(trait_ref).is_some() | ||
190 | }); | 171 | }); |
191 | // FIXME if there's multiple candidates here, that's an ambiguity error | 172 | // FIXME if there's multiple candidates here, that's an ambiguity error |
192 | let (_chosen_trait, chosen_method) = candidates.first()?; | 173 | let (_chosen_trait, chosen_method) = candidates.first()?; |
174 | // FIXME return correct receiver type | ||
193 | Some((self.clone(), *chosen_method)) | 175 | Some((self.clone(), *chosen_method)) |
194 | } | 176 | } |
195 | 177 | ||
@@ -252,3 +234,17 @@ impl Ty { | |||
252 | None | 234 | None |
253 | } | 235 | } |
254 | } | 236 | } |
237 | |||
238 | /// This creates Substs for a trait with the given Self type and type variables | ||
239 | /// for all other parameters. This is kind of a hack since these aren't 'real' | ||
240 | /// type variables; the resulting trait reference is just used for the | ||
241 | /// preliminary method candidate check. | ||
242 | fn fresh_substs_for_trait(db: &impl HirDatabase, tr: Trait, self_ty: Ty) -> Substs { | ||
243 | let mut substs = Vec::new(); | ||
244 | let generics = tr.generic_params(db); | ||
245 | substs.push(self_ty); | ||
246 | substs.extend(generics.params_including_parent().into_iter().skip(1).enumerate().map( | ||
247 | |(i, _p)| Ty::Infer(super::infer::InferTy::TypeVar(super::infer::TypeVarId(i as u32))), | ||
248 | )); | ||
249 | substs.into() | ||
250 | } | ||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f6a325033..291bc9ae5 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -4,15 +4,15 @@ use std::fmt::Write; | |||
4 | use insta::assert_snapshot_matches; | 4 | use insta::assert_snapshot_matches; |
5 | 5 | ||
6 | use ra_db::{SourceDatabase, salsa::Database, FilePosition}; | 6 | use ra_db::{SourceDatabase, salsa::Database, FilePosition}; |
7 | use ra_syntax::{algo, ast::{self, AstNode}}; | 7 | use ra_syntax::{algo, ast::{self, AstNode}, SyntaxKind::*}; |
8 | use test_utils::covers; | 8 | use test_utils::covers; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | source_binder, | ||
12 | mock::MockDatabase, | 11 | mock::MockDatabase, |
13 | ty::display::HirDisplay, | 12 | ty::display::HirDisplay, |
14 | ty::InferenceResult, | 13 | ty::InferenceResult, |
15 | expr::BodySourceMap | 14 | expr::BodySourceMap, |
15 | SourceAnalyzer, | ||
16 | }; | 16 | }; |
17 | 17 | ||
18 | // These tests compare the inference results for all expressions in a file | 18 | // These tests compare the inference results for all expressions in a file |
@@ -1862,14 +1862,14 @@ fn test() { | |||
1862 | @r###" | 1862 | @r###" |
1863 | [49; 50) '0': u32 | 1863 | [49; 50) '0': u32 |
1864 | [80; 83) '101': u32 | 1864 | [80; 83) '101': u32 |
1865 | [126; 128) '99': u32 | ||
1866 | [95; 213) '{ ...NST; }': () | 1865 | [95; 213) '{ ...NST; }': () |
1867 | [138; 139) 'x': {unknown} | 1866 | [138; 139) 'x': {unknown} |
1868 | [142; 153) 'LOCAL_CONST': {unknown} | 1867 | [142; 153) 'LOCAL_CONST': {unknown} |
1869 | [163; 164) 'z': u32 | 1868 | [163; 164) 'z': u32 |
1870 | [167; 179) 'GLOBAL_CONST': u32 | 1869 | [167; 179) 'GLOBAL_CONST': u32 |
1871 | [189; 191) 'id': u32 | 1870 | [189; 191) 'id': u32 |
1872 | [194; 210) 'Foo::A..._CONST': u32"### | 1871 | [194; 210) 'Foo::A..._CONST': u32 |
1872 | [126; 128) '99': u32"### | ||
1873 | ); | 1873 | ); |
1874 | } | 1874 | } |
1875 | 1875 | ||
@@ -1891,8 +1891,6 @@ fn test() { | |||
1891 | @r###" | 1891 | @r###" |
1892 | [29; 32) '101': u32 | 1892 | [29; 32) '101': u32 |
1893 | [70; 73) '101': u32 | 1893 | [70; 73) '101': u32 |
1894 | [118; 120) '99': u32 | ||
1895 | [161; 163) '99': u32 | ||
1896 | [85; 280) '{ ...MUT; }': () | 1894 | [85; 280) '{ ...MUT; }': () |
1897 | [173; 174) 'x': {unknown} | 1895 | [173; 174) 'x': {unknown} |
1898 | [177; 189) 'LOCAL_STATIC': {unknown} | 1896 | [177; 189) 'LOCAL_STATIC': {unknown} |
@@ -1901,7 +1899,9 @@ fn test() { | |||
1901 | [229; 230) 'z': u32 | 1899 | [229; 230) 'z': u32 |
1902 | [233; 246) 'GLOBAL_STATIC': u32 | 1900 | [233; 246) 'GLOBAL_STATIC': u32 |
1903 | [256; 257) 'w': u32 | 1901 | [256; 257) 'w': u32 |
1904 | [260; 277) 'GLOBAL...IC_MUT': u32"### | 1902 | [260; 277) 'GLOBAL...IC_MUT': u32 |
1903 | [118; 120) '99': u32 | ||
1904 | [161; 163) '99': u32"### | ||
1905 | ); | 1905 | ); |
1906 | } | 1906 | } |
1907 | 1907 | ||
@@ -1926,8 +1926,8 @@ fn test() { | |||
1926 | } | 1926 | } |
1927 | "#), | 1927 | "#), |
1928 | @r###" | 1928 | @r###" |
1929 | [31; 35) 'self': &{unknown} | 1929 | [31; 35) 'self': &Self |
1930 | [110; 114) 'self': &{unknown} | 1930 | [110; 114) 'self': &Self |
1931 | [170; 228) '{ ...i128 }': () | 1931 | [170; 228) '{ ...i128 }': () |
1932 | [176; 178) 'S1': S1 | 1932 | [176; 178) 'S1': S1 |
1933 | [176; 187) 'S1.method()': u32 | 1933 | [176; 187) 'S1.method()': u32 |
@@ -1972,8 +1972,8 @@ mod bar_test { | |||
1972 | } | 1972 | } |
1973 | "#), | 1973 | "#), |
1974 | @r###" | 1974 | @r###" |
1975 | [63; 67) 'self': &{unknown} | 1975 | [63; 67) 'self': &Self |
1976 | [169; 173) 'self': &{unknown} | 1976 | [169; 173) 'self': &Self |
1977 | [300; 337) '{ ... }': () | 1977 | [300; 337) '{ ... }': () |
1978 | [310; 311) 'S': S | 1978 | [310; 311) 'S': S |
1979 | [310; 320) 'S.method()': u32 | 1979 | [310; 320) 'S.method()': u32 |
@@ -1998,10 +1998,45 @@ fn test() { | |||
1998 | } | 1998 | } |
1999 | "#), | 1999 | "#), |
2000 | @r###" | 2000 | @r###" |
2001 | [33; 37) 'self': &{unknown} | 2001 | [33; 37) 'self': &Self |
2002 | [92; 111) '{ ...d(); }': () | 2002 | [92; 111) '{ ...d(); }': () |
2003 | [98; 99) 'S': S | 2003 | [98; 99) 'S': S |
2004 | [98; 108) 'S.method()': {unknown}"### | 2004 | [98; 108) 'S.method()': u32"### |
2005 | ); | ||
2006 | } | ||
2007 | |||
2008 | #[test] | ||
2009 | fn infer_trait_method_generic_more_params() { | ||
2010 | // the trait implementation is intentionally incomplete -- it shouldn't matter | ||
2011 | assert_snapshot_matches!( | ||
2012 | infer(r#" | ||
2013 | trait Trait<T1, T2, T3> { | ||
2014 | fn method1(&self) -> (T1, T2, T3); | ||
2015 | fn method2(&self) -> (T3, T2, T1); | ||
2016 | } | ||
2017 | struct S1; | ||
2018 | impl Trait<u8, u16, u32> for S1 {} | ||
2019 | struct S2; | ||
2020 | impl<T> Trait<i8, i16, T> for S2 {} | ||
2021 | fn test() { | ||
2022 | S1.method1(); // u8, u16, u32 | ||
2023 | S1.method2(); // u32, u16, u8 | ||
2024 | S2.method1(); // i8, i16, {unknown} | ||
2025 | S2.method2(); // {unknown}, i16, i8 | ||
2026 | } | ||
2027 | "#), | ||
2028 | @r###" | ||
2029 | [43; 47) 'self': &Self | ||
2030 | [82; 86) 'self': &Self | ||
2031 | [210; 361) '{ ..., i8 }': () | ||
2032 | [216; 218) 'S1': S1 | ||
2033 | [216; 228) 'S1.method1()': (u8, u16, u32) | ||
2034 | [250; 252) 'S1': S1 | ||
2035 | [250; 262) 'S1.method2()': (u32, u16, u8) | ||
2036 | [284; 286) 'S2': S2 | ||
2037 | [284; 296) 'S2.method1()': (i8, i16, {unknown}) | ||
2038 | [324; 326) 'S2': S2 | ||
2039 | [324; 336) 'S2.method2()': ({unknown}, i16, i8)"### | ||
2005 | ); | 2040 | ); |
2006 | } | 2041 | } |
2007 | 2042 | ||
@@ -2020,7 +2055,7 @@ fn test() { | |||
2020 | } | 2055 | } |
2021 | "#), | 2056 | "#), |
2022 | @r###" | 2057 | @r###" |
2023 | [33; 37) 'self': &{unknown} | 2058 | [33; 37) 'self': &Self |
2024 | [102; 127) '{ ...d(); }': () | 2059 | [102; 127) '{ ...d(); }': () |
2025 | [108; 109) 'S': S<u32>(T) -> S<T> | 2060 | [108; 109) 'S': S<u32>(T) -> S<T> |
2026 | [108; 115) 'S(1u32)': S<u32> | 2061 | [108; 115) 'S(1u32)': S<u32> |
@@ -2168,7 +2203,7 @@ fn test() { | |||
2168 | } | 2203 | } |
2169 | "#), | 2204 | "#), |
2170 | @r###" | 2205 | @r###" |
2171 | [29; 33) 'self': {unknown} | 2206 | [29; 33) 'self': Self |
2172 | [107; 198) '{ ...(S); }': () | 2207 | [107; 198) '{ ...(S); }': () |
2173 | [117; 118) 'x': u32 | 2208 | [117; 118) 'x': u32 |
2174 | [126; 127) 'S': S | 2209 | [126; 127) 'S': S |
@@ -2302,13 +2337,10 @@ fn test() -> u64 { | |||
2302 | } | 2337 | } |
2303 | 2338 | ||
2304 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 2339 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
2305 | let func = source_binder::function_from_position(db, pos).unwrap(); | 2340 | let file = db.parse(pos.file_id); |
2306 | let body_source_map = func.body_source_map(db); | 2341 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
2307 | let inference_result = func.infer(db); | 2342 | let analyzer = SourceAnalyzer::new(db, pos.file_id, expr.syntax(), Some(pos.offset)); |
2308 | let (_, syntax) = func.source(db); | 2343 | let ty = analyzer.type_of(db, expr).unwrap(); |
2309 | let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap(); | ||
2310 | let expr = body_source_map.node_expr(node).unwrap(); | ||
2311 | let ty = &inference_result[expr]; | ||
2312 | ty.display(db).to_string() | 2344 | ty.display(db).to_string() |
2313 | } | 2345 | } |
2314 | 2346 | ||
@@ -2324,7 +2356,7 @@ fn infer(content: &str) -> String { | |||
2324 | 2356 | ||
2325 | for (pat, ty) in inference_result.type_of_pat.iter() { | 2357 | for (pat, ty) in inference_result.type_of_pat.iter() { |
2326 | let syntax_ptr = match body_source_map.pat_syntax(pat) { | 2358 | let syntax_ptr = match body_source_map.pat_syntax(pat) { |
2327 | Some(sp) => sp, | 2359 | Some(sp) => sp.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()), |
2328 | None => continue, | 2360 | None => continue, |
2329 | }; | 2361 | }; |
2330 | types.push((syntax_ptr, ty)); | 2362 | types.push((syntax_ptr, ty)); |
@@ -2350,25 +2382,11 @@ fn infer(content: &str) -> String { | |||
2350 | } | 2382 | } |
2351 | }; | 2383 | }; |
2352 | 2384 | ||
2353 | for const_def in source_file.syntax().descendants().filter_map(ast::ConstDef::cast) { | 2385 | for node in source_file.syntax().descendants() { |
2354 | let konst = source_binder::const_from_source(&db, file_id, const_def).unwrap(); | 2386 | if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { |
2355 | let inference_result = konst.infer(&db); | 2387 | let analyzer = SourceAnalyzer::new(&db, file_id, node, None); |
2356 | let body_source_map = konst.body_source_map(&db); | 2388 | infer_def(analyzer.inference_result(), analyzer.body_source_map()); |
2357 | infer_def(inference_result, body_source_map) | 2389 | } |
2358 | } | ||
2359 | |||
2360 | for static_def in source_file.syntax().descendants().filter_map(ast::StaticDef::cast) { | ||
2361 | let static_ = source_binder::static_from_source(&db, file_id, static_def).unwrap(); | ||
2362 | let inference_result = static_.infer(&db); | ||
2363 | let body_source_map = static_.body_source_map(&db); | ||
2364 | infer_def(inference_result, body_source_map) | ||
2365 | } | ||
2366 | |||
2367 | for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { | ||
2368 | let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap(); | ||
2369 | let inference_result = func.infer(&db); | ||
2370 | let body_source_map = func.body_source_map(&db); | ||
2371 | infer_def(inference_result, body_source_map) | ||
2372 | } | 2390 | } |
2373 | 2391 | ||
2374 | acc.truncate(acc.trim_end().len()); | 2392 | acc.truncate(acc.trim_end().len()); |
@@ -2403,10 +2421,12 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
2403 | } | 2421 | } |
2404 | ", | 2422 | ", |
2405 | ); | 2423 | ); |
2406 | let func = source_binder::function_from_position(&db, pos).unwrap(); | ||
2407 | { | 2424 | { |
2425 | let file = db.parse(pos.file_id); | ||
2426 | let node = | ||
2427 | algo::find_token_at_offset(file.syntax(), pos.offset).right_biased().unwrap().parent(); | ||
2408 | let events = db.log_executed(|| { | 2428 | let events = db.log_executed(|| { |
2409 | func.infer(&db); | 2429 | SourceAnalyzer::new(&db, pos.file_id, node, None); |
2410 | }); | 2430 | }); |
2411 | assert!(format!("{:?}", events).contains("infer")) | 2431 | assert!(format!("{:?}", events).contains("infer")) |
2412 | } | 2432 | } |
@@ -2423,8 +2443,11 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
2423 | db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text)); | 2443 | db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text)); |
2424 | 2444 | ||
2425 | { | 2445 | { |
2446 | let file = db.parse(pos.file_id); | ||
2447 | let node = | ||
2448 | algo::find_token_at_offset(file.syntax(), pos.offset).right_biased().unwrap().parent(); | ||
2426 | let events = db.log_executed(|| { | 2449 | let events = db.log_executed(|| { |
2427 | func.infer(&db); | 2450 | SourceAnalyzer::new(&db, pos.file_id, node, None); |
2428 | }); | 2451 | }); |
2429 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) | 2452 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) |
2430 | } | 2453 | } |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs new file mode 100644 index 000000000..f8c3958bd --- /dev/null +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -0,0 +1,112 @@ | |||
1 | //! Stuff that will probably mostly replaced by Chalk. | ||
2 | use std::collections::HashMap; | ||
3 | |||
4 | use crate::db::HirDatabase; | ||
5 | use super::{ TraitRef, Substs, infer::{ TypeVarId, InferTy}, Ty}; | ||
6 | |||
7 | // Copied (and simplified) from Chalk | ||
8 | |||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
10 | /// A (possible) solution for a proposed goal. Usually packaged in a `Result`, | ||
11 | /// where `Err` represents definite *failure* to prove a goal. | ||
12 | pub enum Solution { | ||
13 | /// The goal indeed holds, and there is a unique value for all existential | ||
14 | /// variables. | ||
15 | Unique(Substs), | ||
16 | |||
17 | /// The goal may be provable in multiple ways, but regardless we may have some guidance | ||
18 | /// for type inference. | ||
19 | Ambig(Guidance), | ||
20 | } | ||
21 | |||
22 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
23 | /// When a goal holds ambiguously (e.g., because there are multiple possible | ||
24 | /// solutions), we issue a set of *guidance* back to type inference. | ||
25 | pub enum Guidance { | ||
26 | /// The existential variables *must* have the given values if the goal is | ||
27 | /// ever to hold, but that alone isn't enough to guarantee the goal will | ||
28 | /// actually hold. | ||
29 | Definite(Substs), | ||
30 | |||
31 | /// There are multiple plausible values for the existentials, but the ones | ||
32 | /// here are suggested as the preferred choice heuristically. These should | ||
33 | /// be used for inference fallback only. | ||
34 | Suggested(Substs), | ||
35 | |||
36 | /// There's no useful information to feed back to type inference | ||
37 | Unknown, | ||
38 | } | ||
39 | |||
40 | /// Something that needs to be proven (by Chalk) during type checking, e.g. that | ||
41 | /// a certain type implements a certain trait. Proving the Obligation might | ||
42 | /// result in additional information about inference variables. | ||
43 | /// | ||
44 | /// This might be handled by Chalk when we integrate it? | ||
45 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
46 | pub enum Obligation { | ||
47 | /// Prove that a certain type implements a trait (the type is the `Self` type | ||
48 | /// parameter to the `TraitRef`). | ||
49 | Trait(TraitRef), | ||
50 | } | ||
51 | |||
52 | /// Rudimentary check whether an impl exists for a given type and trait; this | ||
53 | /// will actually be done by chalk. | ||
54 | pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> Option<Solution> { | ||
55 | // FIXME use all trait impls in the whole crate graph | ||
56 | let krate = trait_ref.trait_.module(db).krate(db); | ||
57 | let krate = match krate { | ||
58 | Some(krate) => krate, | ||
59 | None => return None, | ||
60 | }; | ||
61 | let crate_impl_blocks = db.impls_in_crate(krate); | ||
62 | let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_); | ||
63 | impl_blocks | ||
64 | .find_map(|impl_block| unify_trait_refs(&trait_ref, &impl_block.target_trait_ref(db)?)) | ||
65 | } | ||
66 | |||
67 | pub(super) fn canonicalize(trait_ref: TraitRef) -> (TraitRef, Vec<TypeVarId>) { | ||
68 | let mut canonical = HashMap::new(); // mapping uncanonical -> canonical | ||
69 | let mut uncanonical = Vec::new(); // mapping canonical -> uncanonical (which is dense) | ||
70 | let mut substs = trait_ref.substs.0.to_vec(); | ||
71 | for ty in &mut substs { | ||
72 | ty.walk_mut(&mut |ty| match ty { | ||
73 | Ty::Infer(InferTy::TypeVar(tv)) => { | ||
74 | let tv: &mut TypeVarId = tv; | ||
75 | *tv = *canonical.entry(*tv).or_insert_with(|| { | ||
76 | let i = uncanonical.len(); | ||
77 | uncanonical.push(*tv); | ||
78 | TypeVarId(i as u32) | ||
79 | }); | ||
80 | } | ||
81 | _ => {} | ||
82 | }); | ||
83 | } | ||
84 | (TraitRef { substs: substs.into(), ..trait_ref }, uncanonical) | ||
85 | } | ||
86 | |||
87 | fn unify_trait_refs(tr1: &TraitRef, tr2: &TraitRef) -> Option<Solution> { | ||
88 | if tr1.trait_ != tr2.trait_ { | ||
89 | return None; | ||
90 | } | ||
91 | let mut solution_substs = Vec::new(); | ||
92 | for (t1, t2) in tr1.substs.0.iter().zip(tr2.substs.0.iter()) { | ||
93 | // this is very bad / hacky 'unification' logic, just enough to make the simple tests pass | ||
94 | match (t1, t2) { | ||
95 | (_, Ty::Infer(InferTy::TypeVar(_))) | (_, Ty::Unknown) | (_, Ty::Param { .. }) => { | ||
96 | // type variable (or similar) in the impl, we just assume it works | ||
97 | } | ||
98 | (Ty::Infer(InferTy::TypeVar(v1)), _) => { | ||
99 | // type variable in the query and fixed type in the impl, record its value | ||
100 | solution_substs.resize_with(v1.0 as usize + 1, || Ty::Unknown); | ||
101 | solution_substs[v1.0 as usize] = t2.clone(); | ||
102 | } | ||
103 | _ => { | ||
104 | // check that they're equal (actually we'd have to recurse etc.) | ||
105 | if t1 != t2 { | ||
106 | return None; | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | Some(Solution::Unique(solution_substs.into())) | ||
112 | } | ||