mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Infer generated variable types
This commit is contained in:
parent
03ffecd9bd
commit
cac741ec8b
7 changed files with 162 additions and 19 deletions
125
src/gen/mod.rs
125
src/gen/mod.rs
|
@ -2,7 +2,7 @@ use inkwell::basic_block::BasicBlock;
|
|||
use inkwell::builder::Builder;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::module::Module;
|
||||
use inkwell::types::BasicTypeEnum;
|
||||
use inkwell::types::{BasicType, BasicTypeEnum};
|
||||
use inkwell::values::{BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue};
|
||||
use inkwell::{FloatPredicate, IntPredicate};
|
||||
|
||||
|
@ -19,13 +19,14 @@ use crate::types;
|
|||
pub struct Env<'ctx, 'env> {
|
||||
pub procedures: MutMap<Symbol, Procedure>,
|
||||
pub subs: Subs,
|
||||
pub resolved_vars: ImMap<Symbol, Variable>,
|
||||
|
||||
pub context: &'ctx Context,
|
||||
pub builder: &'env Builder<'ctx>,
|
||||
pub module: &'env Module<'ctx>,
|
||||
}
|
||||
|
||||
enum TypedVal<'ctx> {
|
||||
pub enum TypedVal<'ctx> {
|
||||
FloatConst(FloatValue<'ctx>),
|
||||
IntConst(IntValue<'ctx>),
|
||||
#[allow(unused)]
|
||||
|
@ -33,6 +34,39 @@ enum TypedVal<'ctx> {
|
|||
}
|
||||
|
||||
impl<'ctx> TypedVal<'ctx> {
|
||||
pub fn new(
|
||||
content: Content,
|
||||
bv_enum: BasicValueEnum<'ctx>,
|
||||
subs: &Subs,
|
||||
) -> Result<Self, String> {
|
||||
match content {
|
||||
Content::Structure(flat_type) => match flat_type {
|
||||
Apply {
|
||||
module_name,
|
||||
name,
|
||||
args,
|
||||
} => {
|
||||
let module_name = module_name.as_str();
|
||||
let name = name.as_str();
|
||||
|
||||
if module_name == types::MOD_NUM && name == types::TYPE_NUM {
|
||||
let arg = *args.iter().next().unwrap();
|
||||
let arg_content = subs.get_without_compacting(arg).content;
|
||||
|
||||
num_to_typed_val(arg_content, bv_enum)
|
||||
} else {
|
||||
panic!(
|
||||
"TODO handle content_to_basic_type for flat_type {}.{} with args {:?}",
|
||||
module_name, name, args
|
||||
);
|
||||
}
|
||||
}
|
||||
other => panic!("TODO handle content_to_basic_type for {:?}", other),
|
||||
},
|
||||
other => Err(format!("Cannot convert {:?} to BasicTypeEnum", other)),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_basic_value(self) -> BasicValueEnum<'ctx> {
|
||||
use self::TypedVal::*;
|
||||
|
||||
|
@ -116,6 +150,46 @@ pub fn num_to_basic_type(content: Content, context: &Context) -> Result<BasicTyp
|
|||
}
|
||||
}
|
||||
|
||||
pub fn num_to_typed_val<'ctx>(
|
||||
content: Content,
|
||||
bv_enum: BasicValueEnum<'ctx>,
|
||||
) -> Result<TypedVal<'ctx>, String> {
|
||||
use TypedVal::*;
|
||||
|
||||
match content {
|
||||
Content::Structure(flat_type) => match flat_type {
|
||||
Apply {
|
||||
module_name,
|
||||
name,
|
||||
args,
|
||||
} => {
|
||||
let module_name = module_name.as_str();
|
||||
let name = name.as_str();
|
||||
|
||||
if module_name == types::MOD_FLOAT && name == types::TYPE_FLOATINGPOINT && args.is_empty() {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(FloatConst(bv_enum.into_float_value()))
|
||||
} else if module_name == types::MOD_INT && name == types::TYPE_INTEGER && args.is_empty() {
|
||||
debug_assert!(args.is_empty());
|
||||
|
||||
Ok(IntConst(bv_enum.into_int_value()))
|
||||
} else {
|
||||
Err(format!("Unrecognized numeric type: {}.{} with args {:?}", module_name, name, args))
|
||||
}
|
||||
}
|
||||
other => panic!(
|
||||
"TODO handle content_to_basic_type (branch 0) for {:?} which is NESTED inside Num.Num",
|
||||
other
|
||||
),
|
||||
},
|
||||
|
||||
other => panic!(
|
||||
"TODO handle content_to_basic_type (branch 1) for {:?} which is NESTED inside Num.Num",
|
||||
other
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_standalone_expr<'ctx, 'env>(
|
||||
env: &Env<'ctx, 'env>,
|
||||
parent: &FunctionValue<'ctx>,
|
||||
|
@ -167,7 +241,21 @@ fn compile_expr<'ctx, 'env>(
|
|||
Pattern::Identifier(symbol) => {
|
||||
let var_name = symbol.as_str();
|
||||
let val = compile_expr(env, parent, &def.loc_expr.value, vars).into_basic_value();
|
||||
let alloca = create_entry_block_alloca(env, parent, var_name);
|
||||
let var = env.resolved_vars.get(symbol).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Could not find var for symbol {:?} in resolved_vars {:?}",
|
||||
symbol, env.resolved_vars
|
||||
)
|
||||
});
|
||||
let content = env.subs.get_without_compacting(*var).content;
|
||||
let basic_type = content_to_basic_type(content, &env.subs, env.context)
|
||||
.unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Error converting symbol {:?} to basic type: {:?}",
|
||||
symbol, err
|
||||
)
|
||||
});
|
||||
let alloca = create_entry_block_alloca(env, parent, basic_type, var_name);
|
||||
|
||||
env.builder.build_store(alloca, val);
|
||||
|
||||
|
@ -179,6 +267,27 @@ fn compile_expr<'ctx, 'env>(
|
|||
panic!("TODO code gen Def pattern {:?}", pat);
|
||||
}
|
||||
},
|
||||
Var {
|
||||
ref resolved_symbol,
|
||||
..
|
||||
} => match vars.get(resolved_symbol) {
|
||||
Some(ptr) => {
|
||||
let bv_enum = env.builder.build_load(*ptr, resolved_symbol.as_str());
|
||||
let var = env
|
||||
.resolved_vars
|
||||
.get(resolved_symbol)
|
||||
.unwrap_or_else(|| panic!("Somehow a Lookup did not get its copy_var set."));
|
||||
let content = env.subs.get_without_compacting(*var).content;
|
||||
|
||||
TypedVal::new(content, bv_enum, &env.subs).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"Error creating TypedVal for lookup on {:?}: {:?} - vars were: {:?}",
|
||||
resolved_symbol, err, vars
|
||||
)
|
||||
})
|
||||
}
|
||||
None => panic!("Could not find a var for {:?}", resolved_symbol),
|
||||
},
|
||||
_ => {
|
||||
panic!("I don't yet know how to compile {:?}", expr);
|
||||
}
|
||||
|
@ -186,11 +295,15 @@ fn compile_expr<'ctx, 'env>(
|
|||
}
|
||||
|
||||
/// Creates a new stack allocation instruction in the entry block of the function.
|
||||
fn create_entry_block_alloca<'ctx>(
|
||||
fn create_entry_block_alloca<'ctx, BT>(
|
||||
env: &Env<'ctx, '_>,
|
||||
parent: &FunctionValue<'_>,
|
||||
basic_type: BT,
|
||||
name: &str,
|
||||
) -> PointerValue<'ctx> {
|
||||
) -> PointerValue<'ctx>
|
||||
where
|
||||
BT: BasicType<'ctx>,
|
||||
{
|
||||
let builder = env.context.create_builder();
|
||||
let entry = parent.get_first_basic_block().unwrap();
|
||||
|
||||
|
@ -199,7 +312,7 @@ fn create_entry_block_alloca<'ctx>(
|
|||
None => builder.position_at_end(&entry),
|
||||
}
|
||||
|
||||
builder.build_alloca(env.context.f64_type(), name)
|
||||
builder.build_alloca(basic_type, name)
|
||||
}
|
||||
|
||||
fn compile_when_branch<'ctx, 'env>(
|
||||
|
|
13
src/infer.rs
13
src/infer.rs
|
@ -1,3 +1,4 @@
|
|||
use crate::can::symbol::Symbol;
|
||||
use crate::collections::ImMap;
|
||||
use crate::solve;
|
||||
use crate::subs::{Content, Subs, Variable};
|
||||
|
@ -8,8 +9,14 @@ pub fn infer_expr(
|
|||
problems: &mut Vec<Problem>,
|
||||
constraint: &Constraint,
|
||||
expr_var: Variable,
|
||||
) -> Content {
|
||||
solve::run(&ImMap::default(), problems, subs, constraint);
|
||||
) -> (Content, ImMap<Symbol, Variable>) {
|
||||
let resolved_vars = solve::run(
|
||||
&ImMap::default(),
|
||||
problems,
|
||||
subs,
|
||||
constraint,
|
||||
ImMap::default(),
|
||||
);
|
||||
|
||||
subs.get(expr_var).content
|
||||
(subs.get(expr_var).content, resolved_vars)
|
||||
}
|
||||
|
|
|
@ -365,7 +365,7 @@ pub fn solve_loaded(
|
|||
problems: &mut Vec<Problem>,
|
||||
subs: &mut Subs,
|
||||
loaded_deps: LoadedDeps,
|
||||
) {
|
||||
) -> ImMap<Symbol, Variable> {
|
||||
use Declaration::*;
|
||||
use LoadedModule::*;
|
||||
|
||||
|
@ -438,9 +438,23 @@ pub fn solve_loaded(
|
|||
}
|
||||
}
|
||||
|
||||
let mut resolved_vars = ImMap::default();
|
||||
|
||||
for dep_constraint in dep_constraints {
|
||||
solve::run(&vars_by_symbol, problems, subs, &dep_constraint);
|
||||
resolved_vars = solve::run(
|
||||
&vars_by_symbol,
|
||||
problems,
|
||||
subs,
|
||||
&dep_constraint,
|
||||
resolved_vars,
|
||||
);
|
||||
}
|
||||
|
||||
solve::run(&vars_by_symbol, problems, subs, &module.constraint);
|
||||
solve::run(
|
||||
&vars_by_symbol,
|
||||
problems,
|
||||
subs,
|
||||
&module.constraint,
|
||||
resolved_vars,
|
||||
)
|
||||
}
|
||||
|
|
13
src/solve.rs
13
src/solve.rs
|
@ -61,6 +61,7 @@ impl Pools {
|
|||
|
||||
struct State {
|
||||
vars_by_symbol: Env,
|
||||
resolved_vars: Env,
|
||||
mark: Mark,
|
||||
}
|
||||
|
||||
|
@ -69,11 +70,13 @@ pub fn run(
|
|||
problems: &mut Vec<Problem>,
|
||||
subs: &mut Subs,
|
||||
constraint: &Constraint,
|
||||
) {
|
||||
resolved_vars: Env,
|
||||
) -> Env {
|
||||
let mut pools = Pools::default();
|
||||
let state = State {
|
||||
vars_by_symbol: vars_by_symbol.clone(),
|
||||
mark: Mark::NONE.next(),
|
||||
resolved_vars,
|
||||
};
|
||||
let rank = Rank::toplevel();
|
||||
|
||||
|
@ -85,12 +88,13 @@ pub fn run(
|
|||
problems,
|
||||
subs,
|
||||
constraint,
|
||||
);
|
||||
)
|
||||
.resolved_vars
|
||||
}
|
||||
|
||||
fn solve(
|
||||
vars_by_symbol: &Env,
|
||||
state: State,
|
||||
mut state: State,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
problems: &mut Vec<Problem>,
|
||||
|
@ -146,6 +150,8 @@ fn solve(
|
|||
|
||||
introduce(subs, rank, pools, &vars);
|
||||
|
||||
state.resolved_vars.insert(symbol.clone(), actual);
|
||||
|
||||
state
|
||||
}
|
||||
And(sub_constraints) => {
|
||||
|
@ -320,6 +326,7 @@ fn solve(
|
|||
let temp_state = State {
|
||||
vars_by_symbol: new_state.vars_by_symbol,
|
||||
mark: final_mark,
|
||||
resolved_vars: new_state.resolved_vars,
|
||||
};
|
||||
|
||||
// Now solve the body, using the new vars_by_symbol which includes
|
||||
|
|
|
@ -26,7 +26,8 @@ mod test_gen {
|
|||
let (expr, _output, _problems, var_store, variable, constraint) = can_expr($src);
|
||||
let mut subs = Subs::new(var_store.into());
|
||||
let mut unify_problems = Vec::new();
|
||||
let content = infer_expr(&mut subs, &mut unify_problems, &constraint, variable);
|
||||
let (content, resolved_vars) =
|
||||
infer_expr(&mut subs, &mut unify_problems, &constraint, variable);
|
||||
|
||||
let context = Context::create();
|
||||
let builder = context.create_builder();
|
||||
|
@ -51,6 +52,7 @@ mod test_gen {
|
|||
builder: &builder,
|
||||
context: &context,
|
||||
module: &module,
|
||||
resolved_vars,
|
||||
};
|
||||
let ret = compile_standalone_expr(&env, &function, &expr);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ mod test_infer {
|
|||
}
|
||||
|
||||
let mut unify_problems = Vec::new();
|
||||
let content = infer_expr(&mut subs, &mut unify_problems, &constraint, variable);
|
||||
let (content, _) = infer_expr(&mut subs, &mut unify_problems, &constraint, variable);
|
||||
|
||||
name_all_type_vars(variable, &mut subs);
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ mod test_infer_uniq {
|
|||
) = uniq_expr(src);
|
||||
|
||||
let mut unify_problems = Vec::new();
|
||||
let content1 = infer_expr(&mut subs1, &mut unify_problems, &constraint1, variable1);
|
||||
let content2 = infer_expr(&mut subs2, &mut unify_problems, &constraint2, variable2);
|
||||
let (content1, _) = infer_expr(&mut subs1, &mut unify_problems, &constraint1, variable1);
|
||||
let (content2, _) = infer_expr(&mut subs2, &mut unify_problems, &constraint2, variable2);
|
||||
|
||||
name_all_type_vars(variable1, &mut subs1);
|
||||
name_all_type_vars(variable2, &mut subs2);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue