Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adds data structures #64

Merged
merged 21 commits into from
Jan 11, 2020
Merged
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c84a7bf
feat: parsing of data structures
Wodann Nov 23, 2019
9a86797
feat(hir): resolve struct names
Wodann Nov 23, 2019
e241e86
improvement(struct): allow trailing semicolon
Wodann Nov 29, 2019
0b10bb1
feat(tuple): add parsing and HIR lowering for tuples
baszalmstra Nov 30, 2019
0ecdd6b
feat(structs): generate type ir for structs
baszalmstra Nov 30, 2019
7976f07
feat(struct): parsing of record literals
baszalmstra Dec 1, 2019
76e9188
feat(struct): type inference of record literals
Wodann Dec 4, 2019
b2aea8b
feat(struct): type inference of tuple literals
Wodann Dec 4, 2019
a6303a1
feat(struct): add lexing of indices, and parsing and type inferencing…
Wodann Dec 5, 2019
9c9758e
feat(struct): add IR generation for record, tuple, and unit struct li…
Wodann Dec 12, 2019
5d34607
feat(struct): add struct to ABI and runtime dispatch table
Wodann Dec 16, 2019
1069b9e
feat(struct): add IR generation for fields
Wodann Dec 17, 2019
d6dda23
misc(mun_hir): expression validator
baszalmstra Jan 10, 2020
afe18e1
feat: diagnostics for uninitialized variable access
baszalmstra Jan 10, 2020
d53ee2c
feat: struct memory type specifiers
baszalmstra Jan 10, 2020
a288b1f
feat: visibility can now include specifiers
baszalmstra Jan 10, 2020
0d41201
refactor: Renamed Source to InFile and added to diagnostics
baszalmstra Jan 10, 2020
e5f1fe8
misc: better diagnostic for uninitialized access
baszalmstra Jan 10, 2020
0e75842
feat(struct): add validity checks and diagnostics for struct literals
Wodann Jan 11, 2020
26621df
feat: initial very leaky implementation of heap allocation
baszalmstra Jan 11, 2020
a2c7ce7
misc: suggestions from review
baszalmstra Jan 11, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(structs): generate type ir for structs
baszalmstra committed Jan 11, 2020
commit 0ecdd6b52283e923830329e3297aa744abf7f7de
2 changes: 1 addition & 1 deletion crates/mun_codegen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
description = "LLVM IR code generation for Mun"

[dependencies]
mun_hir = { path = "../mun_hir" }
hir = { path = "../mun_hir", package = "mun_hir" }
mun_target = { path = "../mun_target" }
mun_lld = { path = "../mun_lld" }
failure = "0.1.5"
2 changes: 1 addition & 1 deletion crates/mun_codegen/src/code_gen.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::code_gen::linker::LinkerError;
use crate::IrDatabase;
use failure::Fail;
use hir::FileId;
use inkwell::module::Module;
use inkwell::passes::{PassManager, PassManagerBuilder};
use inkwell::targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target};
use inkwell::OptimizationLevel;
use mun_hir::FileId;
use std::io::{self, Write};
use std::path::Path;

6 changes: 3 additions & 3 deletions crates/mun_codegen/src/code_gen/symbols.rs
Original file line number Diff line number Diff line change
@@ -3,14 +3,14 @@ use crate::ir::dispatch_table::DispatchTable;
use crate::ir::function;
use crate::values::{BasicValue, GlobalValue};
use crate::IrDatabase;
use hir::{Ty, TypeCtor};
use inkwell::attributes::Attribute;
use inkwell::values::{IntValue, PointerValue, UnnamedAddress};
use inkwell::{
module::{Linkage, Module},
values::{FunctionValue, StructValue},
AddressSpace,
};
use mun_hir::{self as hir, Ty, TypeCtor};
use std::collections::HashMap;
use std::hash::{Hash, Hasher};

@@ -161,7 +161,7 @@ fn gen_function_info_array<'a, D: IrDatabase>(
db: &D,
types: &AbiTypes,
module: &Module,
functions: impl Iterator<Item = (&'a mun_hir::Function, &'a FunctionValue)>,
functions: impl Iterator<Item = (&'a hir::Function, &'a FunctionValue)>,
) -> GlobalValue {
let function_infos: Vec<StructValue> = functions
.map(|(f, value)| {
@@ -254,7 +254,7 @@ fn gen_dispatch_table<D: IrDatabase>(
/// for the ABI that `get_info` exposes.
pub(super) fn gen_reflection_ir(
db: &impl IrDatabase,
function_map: &HashMap<mun_hir::Function, FunctionValue>,
function_map: &HashMap<hir::Function, FunctionValue>,
dispatch_table: &DispatchTable,
module: &Module,
) {
2 changes: 1 addition & 1 deletion crates/mun_codegen/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(clippy::type_repetition_in_bounds)]

use mun_hir as hir;


use crate::{code_gen::symbols::TypeInfo, ir::module::ModuleIR, Context};
use inkwell::{types::AnyTypeEnum, OptimizationLevel};
1 change: 1 addition & 0 deletions crates/mun_codegen/src/ir.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use inkwell::types::{AnyTypeEnum, BasicTypeEnum};

pub mod adt;
pub mod body;
pub(crate) mod dispatch_table;
pub mod function;
24 changes: 24 additions & 0 deletions crates/mun_codegen/src/ir/adt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//use crate::ir::module::Types;
use crate::ir::try_convert_any_to_basic;
use crate::IrDatabase;
use inkwell::types::{AnyTypeEnum, BasicTypeEnum};

pub(super) fn gen_struct_decl(db: &impl IrDatabase, s: hir::Struct) {
if let AnyTypeEnum::StructType(struct_type) = db.type_ir(s.ty(db)) {
if struct_type.is_opaque() {
let field_types: Vec<BasicTypeEnum> = s
.fields(db)
.iter()
.map(|field| {
let field_type = field.ty(db);
try_convert_any_to_basic(db.type_ir(field_type))
.expect("could not convert field type")
})
.collect();

struct_type.set_body(&field_types, false);
}
} else {
unreachable!()
}
}
16 changes: 8 additions & 8 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use crate::{ir::dispatch_table::DispatchTable, ir::try_convert_any_to_basic, IrDatabase};
use hir::{
ArithOp, BinaryOp, Body, CmpOp, Expr, ExprId, HirDisplay, InferenceResult, Literal, Ordering,
Pat, PatId, Path, Resolution, Resolver, Statement, TypeCtor,
};
use inkwell::{
builder::Builder,
module::Module,
values::{BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue},
FloatPredicate, IntPredicate,
};
use mun_hir::{
self as hir, ArithOp, BinaryOp, Body, CmpOp, Expr, ExprId, HirDisplay, InferenceResult,
Literal, Ordering, Pat, PatId, Path, Resolution, Resolver, Statement, TypeCtor,
};
use std::{collections::HashMap, mem, sync::Arc};

use inkwell::basic_block::BasicBlock;
@@ -32,7 +32,7 @@ pub(crate) struct BodyIrGenerator<'a, 'b, D: IrDatabase> {
pat_to_param: HashMap<PatId, inkwell::values::BasicValueEnum>,
pat_to_local: HashMap<PatId, inkwell::values::PointerValue>,
pat_to_name: HashMap<PatId, String>,
function_map: &'a HashMap<mun_hir::Function, FunctionValue>,
function_map: &'a HashMap<hir::Function, FunctionValue>,
dispatch_table: &'b DispatchTable,
active_loop: Option<LoopInfo>,
hir_function: hir::Function,
@@ -44,7 +44,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
module: &'a Module,
hir_function: hir::Function,
ir_function: FunctionValue,
function_map: &'a HashMap<mun_hir::Function, FunctionValue>,
function_map: &'a HashMap<hir::Function, FunctionValue>,
dispatch_table: &'b DispatchTable,
) -> Self {
// Get the type information from the `hir::Function`
@@ -136,7 +136,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
tail,
} => self.gen_block(expr, statements, *tail),
Expr::Path(ref p) => {
let resolver = mun_hir::resolver_for_expr(self.body.clone(), self.db, expr);
let resolver = hir::resolver_for_expr(self.body.clone(), self.db, expr);
Some(self.gen_path_expr(p, expr, &resolver))
}
Expr::Literal(lit) => Some(self.gen_literal(lit)),
@@ -471,7 +471,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
let body = self.body.clone();
match &body[expr] {
Expr::Path(ref p) => {
let resolver = mun_hir::resolver_for_expr(self.body.clone(), self.db, expr);
let resolver = hir::resolver_for_expr(self.body.clone(), self.db, expr);
self.gen_path_place_expr(p, expr, &resolver)
}
_ => unreachable!("invalid place expression"),
6 changes: 3 additions & 3 deletions crates/mun_codegen/src/ir/dispatch_table.rs
Original file line number Diff line number Diff line change
@@ -3,8 +3,8 @@ use crate::IrDatabase;
use inkwell::module::Module;
use inkwell::types::BasicTypeEnum;
use inkwell::values::{BasicValueEnum, PointerValue};
use mun_hir as hir;
use mun_hir::{Body, Expr, ExprId, InferenceResult};

use hir::{Body, Expr, ExprId, InferenceResult};
use std::collections::HashMap;

/// A dispatch table in IR is a struct that contains pointers to all functions that are called from
@@ -147,7 +147,7 @@ impl<'a, D: IrDatabase> DispatchTableBuilder<'a, D> {
/// This creates the final DispatchTable with all *called* functions from within the module
/// # Parameters
/// * **functions**: Mapping of *defined* Mun functions to their respective IR values.
pub fn finalize(self, functions: &HashMap<mun_hir::Function, FunctionValue>) -> DispatchTable {
pub fn finalize(self, functions: &HashMap<hir::Function, FunctionValue>) -> DispatchTable {
// Construct the table body from all the entries in the dispatch table
let table_body: Vec<BasicTypeEnum> = self
.entries
4 changes: 2 additions & 2 deletions crates/mun_codegen/src/ir/function.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ use crate::values::FunctionValue;
use crate::{IrDatabase, Module, OptimizationLevel};
use inkwell::passes::{PassManager, PassManagerBuilder};
use inkwell::types::AnyTypeEnum;
use mun_hir as hir;

use std::collections::HashMap;

/// Constructs a PassManager to optimize functions for the given optimization level.
@@ -45,7 +45,7 @@ pub(crate) fn gen_body<'a, 'b, D: IrDatabase>(
hir_function: hir::Function,
llvm_function: FunctionValue,
module: &'a Module,
llvm_functions: &'a HashMap<mun_hir::Function, FunctionValue>,
llvm_functions: &'a HashMap<hir::Function, FunctionValue>,
dispatch_table: &'b DispatchTable,
) -> FunctionValue {
let mut code_gen = BodyIrGenerator::new(
14 changes: 11 additions & 3 deletions crates/mun_codegen/src/ir/module.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::ir::dispatch_table::{DispatchTable, DispatchTableBuilder};
use crate::ir::function;
use crate::ir::{adt, function};
use crate::IrDatabase;
use hir::{FileId, ModuleDef};
use inkwell::{module::Module, values::FunctionValue};
use mun_hir::{FileId, ModuleDef};
use std::collections::HashMap;
use std::sync::Arc;

@@ -15,7 +15,7 @@ pub struct ModuleIR {
pub llvm_module: Module,

/// A mapping from HIR functions to LLVM IR values
pub functions: HashMap<mun_hir::Function, FunctionValue>,
pub functions: HashMap<hir::Function, FunctionValue>,

/// The dispatch table
pub dispatch_table: DispatchTable,
@@ -27,6 +27,14 @@ pub(crate) fn ir_query(db: &impl IrDatabase, file_id: FileId) -> Arc<ModuleIR> {
.context()
.create_module(db.file_relative_path(file_id).as_str());

// Generate all type definitions
for def in db.module_data(file_id).definitions() {
match def {
ModuleDef::Struct(s) => adt::gen_struct_decl(db, *s),
ModuleDef::BuiltinType(_) | ModuleDef::Function(_) => (),
}
}

// Generate all the function signatures
let mut functions = HashMap::new();
let mut dispatch_table_builder = DispatchTableBuilder::new(db, &llvm_module);
6 changes: 5 additions & 1 deletion crates/mun_codegen/src/ir/ty.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::try_convert_any_to_basic;
use crate::IrDatabase;
use hir::{ApplicationTy, Ty, TypeCtor};
use inkwell::types::{AnyTypeEnum, BasicType, BasicTypeEnum};
use mun_hir::{ApplicationTy, Ty, TypeCtor};

/// Given a mun type, construct an LLVM IR type
pub(crate) fn ir_query(db: &impl IrDatabase, ty: Ty) -> AnyTypeEnum {
@@ -29,6 +29,10 @@ pub(crate) fn ir_query(db: &impl IrDatabase, ty: Ty) -> AnyTypeEnum {

AnyTypeEnum::FunctionType(fn_type)
}
TypeCtor::Struct(s) => {
let name = s.name(db).to_string();
context.opaque_struct_type(&name).into()
}
_ => unreachable!(),
},
_ => unreachable!("unknown type can not be converted"),
11 changes: 5 additions & 6 deletions crates/mun_codegen/src/mock.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use crate::{IrDatabase, OptimizationLevel};
use mun_hir::{FileId, RelativePathBuf};
use mun_hir::{SourceDatabase, SourceRoot, SourceRootId};
use hir::{FileId, RelativePathBuf, SourceDatabase, SourceRoot, SourceRootId};
use std::sync::Arc;

/// A mock implementation of the IR database. It can be used to set up a simple test case.
#[salsa::database(
mun_hir::SourceDatabaseStorage,
mun_hir::DefDatabaseStorage,
mun_hir::HirDatabaseStorage,
hir::SourceDatabaseStorage,
hir::DefDatabaseStorage,
hir::HirDatabaseStorage,
crate::IrDatabaseStorage
)]
#[derive(Default, Debug)]
@@ -38,7 +37,7 @@ impl MockDatabase {
source_root.insert_file(rel_path, file_id);

db.set_source_root(source_root_id, Arc::new(source_root));
db.set_optimization_lvl(OptimizationLevel::Default);
db.set_optimization_lvl(OptimizationLevel::None);

let context = crate::Context::create();
db.set_context(Arc::new(context));
19 changes: 19 additions & 0 deletions crates/mun_codegen/src/snapshots/test__struct_test.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
source: crates/mun_codegen/src/test.rs
expression: "struct Bar(float, int, bool, Foo);\nstruct Foo { a: int };\nstruct Baz;\nfn foo() {\n let a: Foo;\n let b: Bar;\n let c: Baz;\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"

%Baz = type {}
%Bar = type { double, i64, i1, %Foo }
%Foo = type { i64 }

define void @foo() {
body:
%c = alloca %Baz
%b = alloca %Bar
%a = alloca %Foo
ret void
}

33 changes: 28 additions & 5 deletions crates/mun_codegen/src/test.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use crate::{mock::MockDatabase, IrDatabase};
use mun_hir::diagnostics::DiagnosticSink;
use mun_hir::line_index::LineIndex;
use mun_hir::Module;
use mun_hir::SourceDatabase;
use hir::{diagnostics::DiagnosticSink, line_index::LineIndex, Module, SourceDatabase};
use inkwell::OptimizationLevel;
use std::cell::RefCell;
use std::sync::Arc;

@@ -359,15 +357,40 @@ fn while_expr() {
while n<4 {
break;
};
}
"#,
)
}

#[test]
fn struct_test() {
test_snapshot_unoptimized(
r#"
struct Bar(float, int, bool, Foo);
struct Foo { a: int };
struct Baz;
fn foo() {
let a: Foo;
let b: Bar;
let c: Baz;
}
"#,
)
}

fn test_snapshot(text: &str) {
test_snapshot_with_optimization(text, OptimizationLevel::Default);
}

fn test_snapshot_unoptimized(text: &str) {
test_snapshot_with_optimization(text, OptimizationLevel::None);
}

fn test_snapshot_with_optimization(text: &str, opt: OptimizationLevel) {
let text = text.trim().replace("\n ", "\n");

let (db, file_id) = MockDatabase::with_single_file(&text);
let (mut db, file_id) = MockDatabase::with_single_file(&text);
db.set_optimization_lvl(opt);

let line_index: Arc<LineIndex> = db.line_index(file_id);
let messages = RefCell::new(Vec::new());
31 changes: 25 additions & 6 deletions crates/mun_hir/src/adt.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::sync::Arc;

use crate::type_ref::{TypeRefBuilder, TypeRefId, TypeRefMap, TypeRefSourceMap};
use crate::{
arena::{Arena, RawId},
ids::{AstItemDef, StructId},
type_ref::TypeRef,
AsName, DefDatabase, Name,
};
use mun_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
@@ -23,7 +23,7 @@ use mun_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructFieldData {
pub name: Name,
pub type_ref: TypeRef,
pub type_ref: TypeRefId,
}

/// An identifier for a struct's or tuple's field
@@ -39,11 +39,13 @@ pub enum StructKind {
Unit,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq)]
pub struct StructData {
pub name: Name,
pub fields: Arena<StructFieldId, StructFieldData>,
pub kind: StructKind,
type_ref_map: TypeRefMap,
type_ref_source_map: TypeRefSourceMap,
}

impl StructData {
@@ -55,13 +57,14 @@ impl StructData {
.map(|n| n.as_name())
.unwrap_or_else(Name::missing);

let mut type_ref_builder = TypeRefBuilder::default();
let (fields, kind) = match src.ast.kind() {
ast::StructKind::Record(r) => {
let fields = r
.fields()
.map(|fd| StructFieldData {
name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
type_ref: type_ref_builder.alloc_from_node_opt(fd.ascribed_type().as_ref()),
})
.collect();
(fields, StructKind::Record)
@@ -72,13 +75,29 @@ impl StructData {
.enumerate()
.map(|(index, fd)| StructFieldData {
name: Name::new_tuple_field(index),
type_ref: TypeRef::from_ast_opt(fd.type_ref()),
type_ref: type_ref_builder.alloc_from_node_opt(fd.type_ref().as_ref()),
})
.collect();
(fields, StructKind::Tuple)
}
ast::StructKind::Unit => (Arena::default(), StructKind::Unit),
};
Arc::new(StructData { name, fields, kind })

let (type_ref_map, type_ref_source_map) = type_ref_builder.finish();
Arc::new(StructData {
name,
fields,
kind,
type_ref_map,
type_ref_source_map,
})
}

pub fn type_ref_source_map(&self) -> &TypeRefSourceMap {
&self.type_ref_source_map
}

pub fn type_ref_map(&self) -> &TypeRefMap {
&self.type_ref_map
}
}
40 changes: 39 additions & 1 deletion crates/mun_hir/src/code_model.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ use crate::ids::LocationCtx;
use crate::name_resolution::Namespace;
use crate::raw::{DefKind, RawFileItem};
use crate::resolve::{Resolution, Resolver};
use crate::ty::InferenceResult;
use crate::ty::{lower::LowerBatchResult, InferenceResult};
use crate::type_ref::{TypeRefBuilder, TypeRefId, TypeRefMap, TypeRefSourceMap};
use crate::{
ids::{FunctionId, StructId},
@@ -52,6 +52,7 @@ impl Module {
#[allow(clippy::single_match)]
match decl {
ModuleDef::Function(f) => f.diagnostics(db, sink),
ModuleDef::Struct(s) => s.diagnostics(db, sink),
_ => (),
}
}
@@ -336,6 +337,19 @@ pub struct StructField {
pub(crate) id: StructFieldId,
}

impl StructField {
pub fn ty(self, db: &impl HirDatabase) -> Ty {
let data = self.parent.data(db);
let type_ref_id = data.fields[self.id].type_ref;
let lower = self.parent.lower(db);
lower[type_ref_id].clone()
}

pub fn name(self, db: &impl HirDatabase) -> Name {
self.parent.data(db).fields[self.id].name.clone()
}
}

impl Struct {
pub fn module(self, db: &impl DefDatabase) -> Module {
Module {
@@ -358,6 +372,30 @@ impl Struct {
.map(|(id, _)| StructField { parent: self, id })
.collect()
}

pub fn ty(self, db: &impl HirDatabase) -> Ty {
db.type_for_def(self.into(), Namespace::Types)
}

pub fn lower(self, db: &impl HirDatabase) -> Arc<LowerBatchResult> {
db.lower_struct(self)
}

pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver {
// take the outer scope...
self.module(db).resolver(db)
}

pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
let data = self.data(db);
let lower = self.lower(db);
lower.add_diagnostics(
db,
self.module(db).file_id,
data.type_ref_source_map(),
sink,
);
}
}

mod diagnostics {
6 changes: 5 additions & 1 deletion crates/mun_hir/src/db.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

use crate::input::{SourceRoot, SourceRootId};
use crate::name_resolution::Namespace;
use crate::ty::lower::LowerBatchResult;
use crate::ty::{FnSig, Ty, TypableDef};
use crate::{
adt::StructData,
@@ -11,7 +12,7 @@ use crate::{
name_resolution::ModuleScope,
source_id::ErasedFileAstId,
ty::InferenceResult,
AstIdMap, ExprScopes, FileId, RawItems,
AstIdMap, ExprScopes, FileId, RawItems, Struct,
};
use mun_syntax::{ast, Parse, SourceFile, SyntaxNode};
pub use relative_path::RelativePathBuf;
@@ -83,6 +84,9 @@ pub trait HirDatabase: DefDatabase {
#[salsa::invoke(crate::ty::infer_query)]
fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>;

#[salsa::invoke(crate::ty::lower::lower_struct_query)]
fn lower_struct(&self, def: Struct) -> Arc<LowerBatchResult>;

#[salsa::invoke(crate::FnData::fn_data_query)]
fn fn_data(&self, func: Function) -> Arc<FnData>;

5 changes: 2 additions & 3 deletions crates/mun_hir/src/ty.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod infer;
mod lower;
pub(super) mod lower;
mod op;

use crate::display::{HirDisplay, HirFormatter};
use crate::ty::infer::TypeVarId;
@@ -10,8 +11,6 @@ pub(crate) use lower::{fn_sig_for_fn, type_for_def, TypableDef};
use std::fmt;
use std::sync::Arc;

mod op;

#[cfg(test)]
mod tests;

82 changes: 79 additions & 3 deletions crates/mun_hir/src/ty/lower.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,50 @@
pub(crate) use self::diagnostics::LowerDiagnostic;
use crate::adt::StructKind;
use crate::arena::map::ArenaMap;
use crate::code_model::BuiltinType;
use crate::diagnostics::DiagnosticSink;
use crate::name_resolution::Namespace;
use crate::resolve::{Resolution, Resolver};
use crate::ty::{FnSig, Ty, TypeCtor};
use crate::type_ref::{TypeRef, TypeRefId, TypeRefMap};
use crate::{Function, HirDatabase, ModuleDef, Path, Struct};
use crate::type_ref::{TypeRef, TypeRefId, TypeRefMap, TypeRefSourceMap};
use crate::{FileId, Function, HirDatabase, ModuleDef, Path, Struct};
use std::ops::Index;
use std::sync::Arc;

#[derive(Clone, PartialEq, Eq, Debug)]
pub(crate) struct LowerResult {
pub(crate) ty: Ty,
pub(crate) diagnostics: Vec<LowerDiagnostic>,
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct LowerBatchResult {
pub(crate) type_ref_to_type: ArenaMap<TypeRefId, Ty>,
pub(crate) diagnostics: Vec<LowerDiagnostic>,
}

impl Index<TypeRefId> for LowerBatchResult {
type Output = Ty;
fn index(&self, expr: TypeRefId) -> &Ty {
self.type_ref_to_type.get(expr).unwrap_or(&Ty::Unknown)
}
}

impl LowerBatchResult {
/// Adds all the `LowerDiagnostic`s of the result to the `DiagnosticSink`.
pub(crate) fn add_diagnostics(
&self,
db: &impl HirDatabase,
file_id: FileId,
source_map: &TypeRefSourceMap,
sink: &mut DiagnosticSink,
) {
self.diagnostics
.iter()
.for_each(|it| it.add_to(db, file_id, source_map, sink))
}
}

impl Ty {
pub(crate) fn from_hir(
db: &impl HirDatabase,
@@ -75,6 +107,28 @@ impl Ty {
}
}

pub fn types_from_hir(
db: &impl HirDatabase,
resolver: &Resolver,
type_ref_map: &TypeRefMap,
) -> Arc<LowerBatchResult> {
let mut result = LowerBatchResult::default();
for (id, _) in type_ref_map.iter() {
let LowerResult { ty, diagnostics } = Ty::from_hir(db, resolver, type_ref_map, id);
for diagnostic in diagnostics {
result.diagnostics.push(diagnostic);
}
// TODO: Add detection of cyclic types
result.type_ref_to_type.insert(id, ty);
}
Arc::new(result)
}

pub fn lower_struct_query(db: &impl HirDatabase, s: Struct) -> Arc<LowerBatchResult> {
let data = s.data(db);
types_from_hir(db, &s.resolver(db), data.type_ref_map())
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum TypableDef {
Function(Function),
@@ -175,10 +229,32 @@ fn type_for_struct(_db: &impl HirDatabase, def: Struct) -> Ty {
}

pub mod diagnostics {
use crate::type_ref::TypeRefId;
use crate::diagnostics::UnresolvedType;
use crate::{
diagnostics::DiagnosticSink,
type_ref::{TypeRefId, TypeRefSourceMap},
FileId, HirDatabase,
};

#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) enum LowerDiagnostic {
UnresolvedType { id: TypeRefId },
}

impl LowerDiagnostic {
pub(crate) fn add_to(
&self,
_db: &impl HirDatabase,
file_id: FileId,
source_map: &TypeRefSourceMap,
sink: &mut DiagnosticSink,
) {
match self {
LowerDiagnostic::UnresolvedType { id } => sink.push(UnresolvedType {
file: file_id,
type_ref: source_map.type_ref_syntax(*id).unwrap(),
}),
}
}
}
}
7 changes: 7 additions & 0 deletions crates/mun_hir/src/type_ref.rs
Original file line number Diff line number Diff line change
@@ -67,6 +67,13 @@ pub struct TypeRefMap {
type_refs: Arena<TypeRefId, TypeRef>,
}

impl TypeRefMap {
/// Iterate over the elements in the map
pub fn iter(&self) -> impl Iterator<Item = (TypeRefId, &TypeRef)> {
self.type_refs.iter()
}
}

impl Index<TypeRefId> for TypeRefMap {
type Output = TypeRef;

4 changes: 2 additions & 2 deletions crates/mun_syntax/src/tests/parser.rs
Original file line number Diff line number Diff line change
@@ -210,7 +210,7 @@ fn loop_expr() {

#[test]
fn break_expr() {
ok_snapshot_test(
snapshot_test(
r#"
fn foo() {
break;
@@ -223,7 +223,7 @@ fn break_expr() {

#[test]
fn while_expr() {
ok_snapshot_test(
snapshot_test(
r#"
fn foo() {
while true {};