Skip to content

Commit 67e7684

Browse files
bors[bot]flodiebold
andcommitted
Merge #327
327: Beginnings of type inference r=flodiebold a=flodiebold I was a bit bored, so I thought I'd try to start implementing the type system and see how far I come 😉 This is obviously still extremely WIP, only very basic stuff working, but I thought I'd post this now to get some feedback as to whether this approach makes sense at all. There's no user-visible effect yet, but the type inference has tests similar to the ones for the parser. My next step will probably be to implement struct types, after which this could probably be used to complete fields. I realize this may all get thrown away when/if the compiler query system gets usable, but I feel like there are lots of IDE features that could be implemented with somewhat working type inference in the meantime 😄 Co-authored-by: Florian Diebold <flodiebold@gmail.com>
2 parents abe09eb + 4befde1 commit 67e7684

22 files changed

Lines changed: 1189 additions & 148 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_analysis/src/db.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ salsa::database_storage! {
9393
fn item_map() for hir::db::ItemMapQuery;
9494
fn fn_syntax() for hir::db::FnSyntaxQuery;
9595
fn submodules() for hir::db::SubmodulesQuery;
96+
fn infer() for hir::db::InferQuery;
97+
fn type_for_def() for hir::db::TypeForDefQuery;
9698
}
9799
}
98100
}

crates/ra_analysis/src/imp.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use std::{
55

66
use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit};
77
use ra_syntax::{
8-
ast::{self, ArgListOwner, Expr, NameOwner},
8+
ast::{self, ArgListOwner, Expr, NameOwner, FnDef},
9+
algo::find_covering_node,
910
AstNode, SourceFileNode,
1011
SyntaxKind::*,
1112
SyntaxNodeRef, TextRange, TextUnit,
@@ -510,6 +511,23 @@ impl AnalysisImpl {
510511
Ok(None)
511512
}
512513

514+
pub fn type_of(&self, file_id: FileId, range: TextRange) -> Cancelable<Option<String>> {
515+
let file = self.db.source_file(file_id);
516+
let syntax = file.syntax();
517+
let node = find_covering_node(syntax, range);
518+
let parent_fn = node.ancestors().filter_map(FnDef::cast).next();
519+
let parent_fn = if let Some(p) = parent_fn {
520+
p
521+
} else {
522+
return Ok(None);
523+
};
524+
let function = ctry!(source_binder::function_from_source(
525+
&*self.db, file_id, parent_fn
526+
)?);
527+
let infer = function.infer(&*self.db)?;
528+
Ok(infer.type_of_node(node).map(|t| t.to_string()))
529+
}
530+
513531
fn index_resolve(&self, name_ref: ast::NameRef) -> Cancelable<Vec<(FileId, FileSymbol)>> {
514532
let name = name_ref.text();
515533
let mut query = Query::new(name.to_string());

crates/ra_analysis/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ impl Analysis {
366366
) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
367367
self.imp.resolve_callable(position)
368368
}
369+
pub fn type_of(&self, file_id: FileId, range: TextRange) -> Cancelable<Option<String>> {
370+
self.imp.type_of(file_id, range)
371+
}
369372
}
370373

371374
pub struct LibraryData {

crates/ra_hir/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ ra_syntax = { path = "../ra_syntax" }
1616
ra_editor = { path = "../ra_editor" }
1717
ra_db = { path = "../ra_db" }
1818
test_utils = { path = "../test_utils" }
19+
20+
[dev-dependencies]
21+
flexi_logger = "0.10.0"

crates/ra_hir/src/db.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{
1414
function::FnId,
1515
module::{ModuleId, ModuleTree, ModuleSource,
1616
nameres::{ItemMap, InputModuleItems}},
17+
ty::{InferenceResult, Ty},
1718
};
1819

1920
salsa::query_group! {
@@ -30,6 +31,16 @@ pub trait HirDatabase: SyntaxDatabase
3031
use fn query_definitions::fn_syntax;
3132
}
3233

34+
fn infer(fn_id: FnId) -> Cancelable<Arc<InferenceResult>> {
35+
type InferQuery;
36+
use fn query_definitions::infer;
37+
}
38+
39+
fn type_for_def(def_id: DefId) -> Cancelable<Ty> {
40+
type TypeForDefQuery;
41+
use fn query_definitions::type_for_def;
42+
}
43+
3344
fn file_items(file_id: FileId) -> Arc<SourceFileItems> {
3445
type SourceFileItemsQuery;
3546
use fn query_definitions::file_items;

crates/ra_hir/src/function.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,21 @@ use std::{
55
sync::Arc,
66
};
77

8+
use ra_db::Cancelable;
89
use ra_syntax::{
910
TextRange, TextUnit,
1011
ast::{self, AstNode, DocCommentsOwner, NameOwner},
1112
};
1213

13-
use crate::{ DefId, HirDatabase };
14+
use crate::{ DefId, HirDatabase, ty::InferenceResult, Module };
1415

1516
pub use self::scope::FnScopes;
1617

1718
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1819
pub struct FnId(pub(crate) DefId);
1920

2021
pub struct Function {
21-
fn_id: FnId,
22+
pub(crate) fn_id: FnId,
2223
}
2324

2425
impl Function {
@@ -27,6 +28,10 @@ impl Function {
2728
Function { fn_id }
2829
}
2930

31+
pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode {
32+
db.fn_syntax(self.fn_id)
33+
}
34+
3035
pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
3136
db.fn_scopes(self.fn_id)
3237
}
@@ -35,6 +40,15 @@ impl Function {
3540
let syntax = db.fn_syntax(self.fn_id);
3641
FnSignatureInfo::new(syntax.borrowed())
3742
}
43+
44+
pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> {
45+
db.infer(self.fn_id)
46+
}
47+
48+
pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> {
49+
let loc = self.fn_id.0.loc(db);
50+
Module::new(db, loc.source_root_id, loc.module_id)
51+
}
3852
}
3953

4054
#[derive(Debug, Clone)]

crates/ra_hir/src/lib.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ pub mod source_binder;
2525
mod krate;
2626
mod module;
2727
mod function;
28+
mod ty;
2829

2930
use std::ops::Index;
3031

31-
use ra_syntax::{SyntaxNodeRef, SyntaxNode};
32+
use ra_syntax::{SyntaxNodeRef, SyntaxNode, SyntaxKind};
3233
use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable};
3334

3435
use crate::{
@@ -66,6 +67,23 @@ pub struct DefLoc {
6667
source_item_id: SourceItemId,
6768
}
6869

70+
impl DefKind {
71+
pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> Option<DefKind> {
72+
match kind {
73+
SyntaxKind::FN_DEF => Some(DefKind::Function),
74+
SyntaxKind::MODULE => Some(DefKind::Module),
75+
// These define items, but don't have their own DefKinds yet:
76+
SyntaxKind::STRUCT_DEF => Some(DefKind::Item),
77+
SyntaxKind::ENUM_DEF => Some(DefKind::Item),
78+
SyntaxKind::TRAIT_DEF => Some(DefKind::Item),
79+
SyntaxKind::TYPE_DEF => Some(DefKind::Item),
80+
SyntaxKind::CONST_DEF => Some(DefKind::Item),
81+
SyntaxKind::STATIC_DEF => Some(DefKind::Item),
82+
_ => None,
83+
}
84+
}
85+
}
86+
6987
impl DefId {
7088
pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc {
7189
db.as_ref().id2loc(self)

crates/ra_hir/src/mock.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
88

99
use crate::{db, DefId, DefLoc};
1010

11-
const WORKSPACE: SourceRootId = SourceRootId(0);
11+
pub const WORKSPACE: SourceRootId = SourceRootId(0);
1212

1313
#[derive(Debug)]
1414
pub(crate) struct MockDatabase {
@@ -24,6 +24,15 @@ impl MockDatabase {
2424
(db, source_root)
2525
}
2626

27+
pub(crate) fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) {
28+
let mut db = MockDatabase::default();
29+
let mut source_root = SourceRoot::default();
30+
let file_id = db.add_file(&mut source_root, "/main.rs", text);
31+
db.query_mut(ra_db::SourceRootQuery)
32+
.set(WORKSPACE, Arc::new(source_root.clone()));
33+
(db, source_root, file_id)
34+
}
35+
2736
pub(crate) fn with_position(fixture: &str) -> (MockDatabase, FilePosition) {
2837
let (db, _, position) = MockDatabase::from_fixture(fixture);
2938
let position = position.expect("expected a marker ( <|> )");
@@ -182,6 +191,8 @@ salsa::database_storage! {
182191
fn item_map() for db::ItemMapQuery;
183192
fn fn_syntax() for db::FnSyntaxQuery;
184193
fn submodules() for db::SubmodulesQuery;
194+
fn infer() for db::InferQuery;
195+
fn type_for_def() for db::TypeForDefQuery;
185196
}
186197
}
187198
}

crates/ra_hir/src/module.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub(super) mod imp;
22
pub(super) mod nameres;
33

44
use std::sync::Arc;
5+
use log;
56

67
use ra_syntax::{
78
algo::generate,

0 commit comments

Comments
 (0)