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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: adds modules and visibility #283

Merged
merged 1 commit into from Nov 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/mun/src/ops/init.rs
Expand Up @@ -41,7 +41,7 @@ version="0.1.0"
let src_path = create_in.join("src");
create_dir(&src_path)?;

let main_file_path = src_path.join("main.mun");
let main_file_path = src_path.join("mod.mun");

write(
&main_file_path,
Expand Down
2 changes: 1 addition & 1 deletion crates/mun/tests/integration.rs
Expand Up @@ -48,7 +48,7 @@ fn build_and_run(project: impl AsRef<Path>) {
];
assert_eq!(run_with_args(args).unwrap(), mun::ExitStatus::Success);

let library_path = project.as_ref().join("target/main.munlib");
let library_path = project.as_ref().join("target/mod.munlib");
assert!(library_path.is_file());

let runtime = RuntimeBuilder::new(&library_path).spawn().unwrap();
Expand Down
4 changes: 2 additions & 2 deletions crates/mun_codegen/src/assembly.rs
Expand Up @@ -34,7 +34,7 @@ impl Assembly {
}

/// Builds an assembly for the specified file
pub(crate) fn build_assembly(db: &dyn CodeGenDatabase, file_id: hir::FileId) -> Arc<Assembly> {
pub(crate) fn build_assembly(db: &dyn CodeGenDatabase, module: hir::Module) -> Arc<Assembly> {
// Construct a temporary file for the assembly
let file = NamedTempFile::new().expect("could not create temp file for shared object");

Expand All @@ -44,7 +44,7 @@ pub(crate) fn build_assembly(db: &dyn CodeGenDatabase, file_id: hir::FileId) ->

// Construct the module
let module_builder =
ModuleBuilder::new(&code_gen_context, file_id).expect("could not create ModuleBuilder");
ModuleBuilder::new(&code_gen_context, module).expect("could not create ModuleBuilder");
let obj_file = module_builder
.build()
.expect("unable to create object file");
Expand Down
14 changes: 8 additions & 6 deletions crates/mun_codegen/src/code_gen/module_builder.rs
Expand Up @@ -3,37 +3,39 @@ use crate::code_gen::{optimize_module, symbols, CodeGenContext, CodeGenerationEr
use crate::ir::file::gen_file_ir;
use crate::ir::file_group::gen_file_group_ir;
use crate::value::{IrTypeContext, IrValueContext};
use hir::FileId;
use inkwell::module::{Linkage, Module};

/// A struct that can be used to build an LLVM `Module`.
pub struct ModuleBuilder<'db, 'ink, 'ctx> {
code_gen: &'ctx CodeGenContext<'db, 'ink>,
file_id: FileId,
module: hir::Module,
assembly_module: Module<'ink>,
}

impl<'db, 'ink, 'ctx> ModuleBuilder<'db, 'ink, 'ctx> {
/// Constructs a module for the given `hir::FileId` using the provided `CodeGenContext`.
pub fn new(
code_gen: &'ctx CodeGenContext<'db, 'ink>,
file_id: FileId,
module: hir::Module,
) -> Result<Self, anyhow::Error> {
// Construct a module for the assembly
let file_id = module
.file_id(code_gen.db)
.expect("module must have a file");
let assembly_name = code_gen.db.file_relative_path(file_id);
let assembly_module = code_gen.create_module(assembly_name);

Ok(Self {
code_gen,
file_id,
module,
assembly_module,
})
}

/// Constructs an object file.
pub fn build(self) -> Result<ObjectFile, anyhow::Error> {
let group_ir = gen_file_group_ir(self.code_gen, self.file_id);
let file = gen_file_ir(self.code_gen, &group_ir, self.file_id);
let group_ir = gen_file_group_ir(self.code_gen, self.module);
let file = gen_file_ir(self.code_gen, &group_ir, self.module);

// Clone the LLVM modules so that we can modify it without modifying the cached value.
self.assembly_module
Expand Down
2 changes: 1 addition & 1 deletion crates/mun_codegen/src/db.rs
Expand Up @@ -22,7 +22,7 @@ pub trait CodeGenDatabase: hir::HirDatabase + hir::Upcast<dyn hir::HirDatabase>
/// Returns a fully linked shared object for the specified group of files.
/// TODO: Current, a group always consists of a single file. Need to add support for multiple.
#[salsa::invoke(crate::assembly::build_assembly)]
fn assembly(&self, file: hir::FileId) -> Arc<Assembly>;
fn assembly(&self, module: hir::Module) -> Arc<Assembly>;
}

/// Constructs the primary interface to the complete machine description for the target machine. All
Expand Down
50 changes: 25 additions & 25 deletions crates/mun_codegen/src/ir/body.rs
Expand Up @@ -7,8 +7,8 @@ use crate::{
};
use hir::{
ArithOp, BinaryOp, Body, CmpOp, Expr, ExprId, HirDatabase, HirDisplay, InferenceResult,
Literal, LogicOp, Name, Ordering, Pat, PatId, Path, Resolution, ResolveBitness, Resolver,
Statement, TypeCtor, UnaryOp,
Literal, LogicOp, Name, Ordering, Pat, PatId, Path, ResolveBitness, Resolver, Statement,
TypeCtor, UnaryOp, ValueNs,
};
use inkwell::{
basic_block::BasicBlock,
Expand Down Expand Up @@ -209,7 +209,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
tail,
} => self.gen_block(expr, statements, *tail),
Expr::Path(ref p) => {
let resolver = hir::resolver_for_expr(self.body.clone(), self.db, expr);
let resolver = hir::resolver_for_expr(self.db.upcast(), self.body.owner(), expr);
Some(self.gen_path_expr(p, expr, &resolver))
}
Expr::Literal(lit) => Some(self.gen_literal(lit, expr)),
Expand Down Expand Up @@ -412,7 +412,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
struct_ir_ty
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::Generic),
&format!("{}_ptr_ptr", hir_struct.name(self.db.upcast()).to_string()),
&format!("{}_ptr_ptr", hir_struct.name(self.db).to_string()),
)
.into_pointer_value();

Expand All @@ -421,7 +421,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
.builder
.build_load(
struct_ptr_ptr,
&format!("{}_mem_ptr", hir_struct.name(self.db.upcast()).to_string()),
&format!("{}_mem_ptr", hir_struct.name(self.db).to_string()),
)
.into_pointer_value();

Expand Down Expand Up @@ -557,13 +557,12 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
expr: ExprId,
resolver: &Resolver,
) -> inkwell::values::BasicValueEnum<'ink> {
let resolution = resolver
.resolve_path_without_assoc_items(self.db, path)
.take_values()
.expect("unknown path");

match resolution {
Resolution::LocalBinding(pat) => {
match resolver
.resolve_path_as_value_fully(self.db.upcast(), path)
.expect("unknown path")
.0
{
ValueNs::LocalBinding(pat) => {
if let Some(param) = self.pat_to_param.get(&pat) {
*param
} else if let Some(ptr) = self.pat_to_local.get(&pat) {
Expand All @@ -573,8 +572,8 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
unreachable!("could not find the pattern..");
}
}
Resolution::Def(hir::ModuleDef::Struct(_)) => self.gen_unit_struct_lit(expr),
Resolution::Def(_) => panic!("no support for module definitions"),
ValueNs::StructId(_) => self.gen_unit_struct_lit(expr),
ValueNs::FunctionId(_) => panic!("unable to generate path expression from a function"),
}
}

Expand Down Expand Up @@ -605,17 +604,18 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
_expr: ExprId,
resolver: &Resolver,
) -> inkwell::values::PointerValue<'ink> {
let resolution = resolver
.resolve_path_without_assoc_items(self.db, path)
.take_values()
.expect("unknown path");

match resolution {
Resolution::LocalBinding(pat) => *self
match resolver
.resolve_path_as_value_fully(self.db.upcast(), path)
.expect("unknown path")
.0
{
ValueNs::LocalBinding(pat) => *self
.pat_to_local
.get(&pat)
.expect("unresolved local binding"),
Resolution::Def(_) => panic!("no support for module definitions"),
ValueNs::FunctionId(_) | ValueNs::StructId(_) => {
panic!("no support for module definitions")
}
}
}

Expand Down Expand Up @@ -1043,7 +1043,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
let body = self.body.clone();
match &body[expr] {
Expr::Path(ref p) => {
let resolver = hir::resolver_for_expr(self.body.clone(), self.db, expr);
let resolver = hir::resolver_for_expr(self.db.upcast(), self.body.owner(), expr);
self.gen_path_place_expr(p, expr, &resolver)
}
Expr::Field {
Expand Down Expand Up @@ -1325,7 +1325,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
.as_struct()
.expect("expected a struct");

let hir_struct_name = hir_struct.name(self.db.upcast());
let hir_struct_name = hir_struct.name(self.db);

let field_idx = hir_struct
.field(self.db, name)
Expand Down Expand Up @@ -1376,7 +1376,7 @@ impl<'db, 'ink, 't> BodyIrGenerator<'db, 'ink, 't> {
.as_struct()
.expect("expected a struct");

let hir_struct_name = hir_struct.name(self.db.upcast());
let hir_struct_name = hir_struct.name(self.db);

let field_idx = hir_struct
.field(self.db, name)
Expand Down
33 changes: 19 additions & 14 deletions crates/mun_codegen/src/ir/file.rs
@@ -1,10 +1,12 @@
use super::body::ExternalGlobals;
use crate::code_gen::CodeGenContext;
use crate::ir::body::BodyIrGenerator;
use crate::ir::file_group::FileGroupIR;
use crate::ir::{function, type_table::TypeTable};
use crate::value::Global;
use hir::{FileId, ModuleDef};
use crate::{
code_gen::CodeGenContext,
ir::body::BodyIrGenerator,
ir::file_group::FileGroupIR,
ir::{function, type_table::TypeTable},
value::Global,
};
use hir::{FileId, HasVisibility, ModuleDef};
use inkwell::module::Module;
use std::collections::{BTreeMap, HashMap, HashSet};

Expand All @@ -23,8 +25,11 @@ pub struct FileIR<'ink> {
pub(crate) fn gen_file_ir<'db, 'ink>(
code_gen: &CodeGenContext<'db, 'ink>,
group_ir: &FileGroupIR<'ink>,
file_id: FileId,
module: hir::Module,
) -> FileIR<'ink> {
let file_id = module
.file_id(code_gen.db)
.expect("module must have an associated file");
let llvm_module = code_gen
.context
.create_module(code_gen.db.file_relative_path(file_id).as_str());
Expand All @@ -35,23 +40,23 @@ pub(crate) fn gen_file_ir<'db, 'ink>(
// Use a `BTreeMap` to guarantee deterministically ordered output.ures
let mut functions = HashMap::new();
let mut wrapper_functions = BTreeMap::new();
for def in code_gen.db.module_data(file_id).definitions() {
for def in module.declarations(code_gen.db) {
if let ModuleDef::Function(f) = def {
if !f.is_extern(code_gen.db) {
let fun = function::gen_prototype(code_gen.db, hir_types, *f, &llvm_module);
functions.insert(*f, fun);
let fun = function::gen_prototype(code_gen.db, hir_types, f, &llvm_module);
functions.insert(f, fun);

let fn_sig = f.ty(code_gen.db).callable_sig(code_gen.db).unwrap();
if !f.data(code_gen.db).visibility().is_private()
if f.visibility(code_gen.db).is_externally_visible()
&& !fn_sig.marshallable(code_gen.db)
{
let wrapper_fun = function::gen_public_prototype(
code_gen.db,
&code_gen.hir_types,
*f,
f,
&llvm_module,
);
wrapper_functions.insert(*f, wrapper_fun);
wrapper_functions.insert(f, wrapper_fun);
}
}
}
Expand Down Expand Up @@ -116,7 +121,7 @@ pub(crate) fn gen_file_ir<'db, 'ink>(
// Filter private methods
let api: HashSet<hir::Function> = functions
.keys()
.filter(|f| f.visibility(code_gen.db) != hir::Visibility::Private)
.filter(|f| f.visibility(code_gen.db).is_externally_visible())
.cloned()
.collect();

Expand Down
29 changes: 16 additions & 13 deletions crates/mun_codegen/src/ir/file_group.rs
Expand Up @@ -3,9 +3,11 @@ use super::{
intrinsics,
type_table::{TypeTable, TypeTableBuilder},
};
use crate::code_gen::CodeGenContext;
use crate::value::{IrTypeContext, IrValueContext};
use hir::ModuleDef;
use crate::{
code_gen::CodeGenContext,
value::{IrTypeContext, IrValueContext},
};
use hir::{HasVisibility, ModuleDef};
use inkwell::{module::Module, types::PointerType, values::UnnamedAddress, AddressSpace};
use std::collections::BTreeMap;

Expand All @@ -28,7 +30,7 @@ pub struct FileGroupIR<'ink> {
/// files using something like `FileGroupId`.
pub(crate) fn gen_file_group_ir<'db, 'ink>(
code_gen: &CodeGenContext<'db, 'ink>,
file_id: hir::FileId,
module: hir::Module,
) -> FileGroupIR<'ink> {
let llvm_module = code_gen.context.create_module("group_name");

Expand All @@ -37,7 +39,7 @@ pub(crate) fn gen_file_group_ir<'db, 'ink>(
let mut needs_alloc = false;

// Collect all intrinsic functions, wrapper function, and generate struct declarations.
for def in code_gen.db.module_data(file_id).definitions() {
for def in module.declarations(code_gen.db) {
match def {
ModuleDef::Function(f) if !f.is_extern(code_gen.db) => {
intrinsics::collect_fn_body(
Expand All @@ -51,7 +53,7 @@ pub(crate) fn gen_file_group_ir<'db, 'ink>(
);

let fn_sig = f.ty(code_gen.db).callable_sig(code_gen.db).unwrap();
if !f.data(code_gen.db).visibility().is_private()
if f.visibility(code_gen.db).is_externally_visible()
&& !fn_sig.marshallable(code_gen.db)
{
intrinsics::collect_wrapper_body(
Expand All @@ -62,9 +64,10 @@ pub(crate) fn gen_file_group_ir<'db, 'ink>(
);
}
}
ModuleDef::Module(_) => (),
ModuleDef::Function(_) => (), // TODO: Extern types?
ModuleDef::Struct(_) => (),
ModuleDef::BuiltinType(_) => (),
ModuleDef::PrimitiveType(_) => (),
ModuleDef::TypeAlias(_) => (),
}
}
Expand All @@ -78,9 +81,9 @@ pub(crate) fn gen_file_group_ir<'db, 'ink>(
&intrinsics_map,
&code_gen.hir_types,
);
for def in code_gen.db.module_data(file_id).definitions() {
for def in module.declarations(code_gen.db) {
if let ModuleDef::Function(f) = def {
if !f.data(code_gen.db).visibility().is_private() && !f.is_extern(code_gen.db) {
if f.visibility(code_gen.db).is_externally_visible() && !f.is_extern(code_gen.db) {
let body = f.body(code_gen.db);
let infer = f.infer(code_gen.db);
dispatch_table_builder.collect_body(&body, &infer);
Expand Down Expand Up @@ -111,15 +114,15 @@ pub(crate) fn gen_file_group_ir<'db, 'ink>(
);

// Collect all used types
for def in code_gen.db.module_data(file_id).definitions() {
for def in module.declarations(code_gen.db) {
match def {
ModuleDef::Struct(s) => {
type_table_builder.collect_struct(*s);
type_table_builder.collect_struct(s);
}
ModuleDef::Function(f) => {
type_table_builder.collect_fn(*f);
type_table_builder.collect_fn(f);
}
ModuleDef::BuiltinType(_) | ModuleDef::TypeAlias(_) => (),
ModuleDef::PrimitiveType(_) | ModuleDef::TypeAlias(_) | ModuleDef::Module(_) => (),
}
}

Expand Down
13 changes: 5 additions & 8 deletions crates/mun_codegen/src/ir/intrinsics.rs
Expand Up @@ -2,7 +2,7 @@ use crate::{
intrinsics::{self, Intrinsic},
ir::dispatch_table::FunctionPrototype,
};
use hir::{Body, Expr, ExprId, HirDatabase, InferenceResult};
use hir::{Body, Expr, ExprId, HirDatabase, InferenceResult, ValueNs};
use inkwell::{context::Context, targets::TargetData, types::FunctionType};
use std::{collections::BTreeMap, sync::Arc};

Expand Down Expand Up @@ -56,13 +56,10 @@ fn collect_expr<'db, 'ink>(
}

if let Expr::Path(path) = expr {
let resolver = hir::resolver_for_expr(body.clone(), db, expr_id);
let resolution = resolver
.resolve_path_without_assoc_items(db, path)
.take_values()
.expect("unknown path");

if let hir::Resolution::Def(hir::ModuleDef::Struct(_)) = resolution {
let resolver = hir::resolver_for_expr(db.upcast(), body.owner(), expr_id);
if let Some((ValueNs::StructId(_), _)) =
resolver.resolve_path_as_value_fully(db.upcast(), path)
{
collect_intrinsic(context, &target, &intrinsics::new, intrinsics);
// self.collect_intrinsic( module, entries, &intrinsics::drop);
*needs_alloc = true;
Expand Down