mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
Merge branch 'glue-getters-rtfeldman' into pluggable-glue
This commit is contained in:
commit
5573ab2275
42 changed files with 4821 additions and 1011 deletions
|
@ -1,5 +1,5 @@
|
|||
use crate::roc_type;
|
||||
use crate::types::{Env, Types};
|
||||
use crate::types::Types;
|
||||
use bumpalo::Bump;
|
||||
use libloading::Library;
|
||||
use roc_build::{
|
||||
|
@ -9,12 +9,14 @@ use roc_build::{
|
|||
BuildFileError, BuildOrdering, BuiltFile, CodeGenBackend, CodeGenOptions,
|
||||
},
|
||||
};
|
||||
use roc_collections::MutMap;
|
||||
use roc_load::{ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_mono::layout::GlobalLayoutInterner;
|
||||
use roc_mono::ir::{generate_glue_procs, GlueProc, OptLevel};
|
||||
use roc_mono::layout::{GlobalLayoutInterner, LayoutCache, LayoutInterner};
|
||||
use roc_packaging::cache::{self, RocCacheDir};
|
||||
use roc_reporting::report::{RenderTarget, DEFAULT_PALETTE};
|
||||
use roc_target::{Architecture, OperatingSystem, TargetInfo};
|
||||
use roc_target::{Architecture, TargetInfo};
|
||||
use roc_types::subs::{Subs, Variable};
|
||||
use std::fs::File;
|
||||
use std::io::{self, ErrorKind, Write};
|
||||
use std::mem::ManuallyDrop;
|
||||
|
@ -209,6 +211,120 @@ pub fn generate(input_path: &Path, output_path: &Path, spec_path: &Path) -> io::
|
|||
}
|
||||
}
|
||||
|
||||
fn number_lambda_sets(subs: &Subs, initial: Variable) -> Vec<Variable> {
|
||||
let mut lambda_sets = vec![];
|
||||
let mut stack = vec![initial];
|
||||
|
||||
macro_rules! var_slice {
|
||||
($variable_subs_slice:expr) => {{
|
||||
let slice = $variable_subs_slice;
|
||||
subs.variables[slice.indices()].iter().rev()
|
||||
}};
|
||||
}
|
||||
|
||||
while let Some(var) = stack.pop() {
|
||||
use roc_types::subs::Content::*;
|
||||
use roc_types::subs::FlatType::*;
|
||||
|
||||
use roc_types::subs::GetSubsSlice;
|
||||
use roc_types::types::Uls;
|
||||
|
||||
match subs.get_content_without_compacting(var) {
|
||||
RigidVar(_) | RigidAbleVar(_, _) | FlexVar(_) | FlexAbleVar(_, _) | Error => (),
|
||||
|
||||
RecursionVar { .. } => {
|
||||
// we got here, so we've treated this type already
|
||||
}
|
||||
|
||||
Structure(flat_type) => match flat_type {
|
||||
Apply(_, args) => {
|
||||
stack.extend(var_slice!(*args));
|
||||
}
|
||||
|
||||
Func(arg_vars, closure_var, ret_var) => {
|
||||
lambda_sets.push(subs.get_root_key_without_compacting(*closure_var));
|
||||
|
||||
stack.push(*ret_var);
|
||||
stack.push(*closure_var);
|
||||
stack.extend(var_slice!(arg_vars));
|
||||
}
|
||||
|
||||
EmptyRecord => (),
|
||||
EmptyTagUnion => (),
|
||||
EmptyTuple => (),
|
||||
|
||||
Record(fields, ext) => {
|
||||
let fields = *fields;
|
||||
let ext = *ext;
|
||||
|
||||
stack.push(ext);
|
||||
stack.extend(var_slice!(fields.variables()));
|
||||
}
|
||||
Tuple(_, _) => todo!(),
|
||||
TagUnion(tags, ext) => {
|
||||
let tags = *tags;
|
||||
let ext = *ext;
|
||||
|
||||
stack.push(ext.var());
|
||||
|
||||
for slice_index in tags.variables() {
|
||||
let slice = subs.variable_slices[slice_index.index as usize];
|
||||
stack.extend(var_slice!(slice));
|
||||
}
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
stack.push(ext.var());
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
let tags = *tags;
|
||||
let ext = *ext;
|
||||
let rec_var = *rec_var;
|
||||
|
||||
stack.push(ext.var());
|
||||
|
||||
for slice_index in tags.variables() {
|
||||
let slice = subs.variable_slices[slice_index.index as usize];
|
||||
stack.extend(var_slice!(slice));
|
||||
}
|
||||
|
||||
stack.push(rec_var);
|
||||
}
|
||||
},
|
||||
Alias(_, args, var, _) => {
|
||||
let var = *var;
|
||||
let args = *args;
|
||||
|
||||
stack.extend(var_slice!(args.all_variables()));
|
||||
|
||||
stack.push(var);
|
||||
}
|
||||
LambdaSet(roc_types::subs::LambdaSet {
|
||||
solved,
|
||||
recursion_var,
|
||||
unspecialized,
|
||||
ambient_function: _,
|
||||
}) => {
|
||||
for slice_index in solved.variables() {
|
||||
let slice = subs.variable_slices[slice_index.index as usize];
|
||||
stack.extend(var_slice!(slice));
|
||||
}
|
||||
|
||||
if let Some(rec_var) = recursion_var.into_variable() {
|
||||
stack.push(rec_var);
|
||||
}
|
||||
|
||||
for Uls(var, _, _) in subs.get_subs_slice(*unspecialized) {
|
||||
stack.push(*var);
|
||||
}
|
||||
}
|
||||
&RangedNumber(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
lambda_sets
|
||||
}
|
||||
|
||||
pub fn load_types(
|
||||
full_file_path: PathBuf,
|
||||
threading: Threading,
|
||||
|
@ -223,6 +339,7 @@ pub fn load_types(
|
|||
mut declarations_by_id,
|
||||
mut solved,
|
||||
interns,
|
||||
exposed_to_host,
|
||||
..
|
||||
} = roc_load::load_and_typecheck(
|
||||
arena,
|
||||
|
@ -261,42 +378,90 @@ pub fn load_types(
|
|||
);
|
||||
}
|
||||
|
||||
// Get the variables for all the exposed_to_host symbols
|
||||
let variables = (0..decls.len()).filter_map(|index| {
|
||||
use roc_can::expr::DeclarationTag::*;
|
||||
|
||||
match decls.declarations[index] {
|
||||
Value | Function(_) | Recursive(_) | TailRecursive(_) => Some(decls.variables[index]),
|
||||
Destructure(_) => {
|
||||
// figure out if we need to export non-identifier defs - when would that
|
||||
// happen?
|
||||
None
|
||||
}
|
||||
MutualRecursion { .. } => {
|
||||
// handled by future iterations
|
||||
None
|
||||
}
|
||||
Expectation | ExpectationFx => {
|
||||
// not publicly visible
|
||||
None
|
||||
}
|
||||
if exposed_to_host.contains_key(&decls.symbols[index].value) {
|
||||
Some(decls.variables[index])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let layout_interner = GlobalLayoutInterner::with_capacity(128, target_info);
|
||||
|
||||
let operating_system = target_info.operating_system;
|
||||
let architectures = Architecture::iter();
|
||||
let mut arch_types = Vec::with_capacity(architectures.len());
|
||||
for arch in architectures {
|
||||
|
||||
let layout_interner = GlobalLayoutInterner::with_capacity(128, target_info);
|
||||
|
||||
for architecture in architectures {
|
||||
let mut interns = interns.clone(); // TODO there may be a way to avoid this.
|
||||
let target_info = TargetInfo {
|
||||
architecture: arch,
|
||||
operating_system: OperatingSystem::Unix,
|
||||
architecture,
|
||||
operating_system,
|
||||
};
|
||||
let mut layout_cache = LayoutCache::new(layout_interner.fork(), target_info);
|
||||
let mut glue_procs_by_layout = MutMap::default();
|
||||
|
||||
let types = {
|
||||
let mut env = Env::new(arena, subs, &interns, layout_interner.fork(), target_info);
|
||||
let mut extern_names = MutMap::default();
|
||||
|
||||
env.vars_to_types(variables.clone())
|
||||
};
|
||||
// Populate glue getters/setters for all relevant variables
|
||||
for var in variables.clone() {
|
||||
for (i, v) in number_lambda_sets(subs, var).iter().enumerate() {
|
||||
extern_names.insert(*v, i.to_string());
|
||||
}
|
||||
|
||||
let in_layout = layout_cache
|
||||
.from_var(arena, var, subs)
|
||||
.expect("Something weird ended up in the content");
|
||||
|
||||
let layout = layout_cache.interner.get(in_layout);
|
||||
|
||||
// dbg!(layout);
|
||||
|
||||
if layout.has_varying_stack_size(&layout_cache.interner, arena) {
|
||||
let ident_ids = interns.all_ident_ids.get_mut(&home).unwrap();
|
||||
let answer = generate_glue_procs(
|
||||
home,
|
||||
ident_ids,
|
||||
arena,
|
||||
&mut layout_interner.fork(),
|
||||
arena.alloc(layout),
|
||||
);
|
||||
|
||||
// Even though generate_glue_procs does more work than we need it to,
|
||||
// it's important that we use it in order to make sure we get exactly
|
||||
// the same names that mono::ir did for code gen!
|
||||
for (layout, glue_procs) in answer.getters {
|
||||
let mut names =
|
||||
bumpalo::collections::Vec::with_capacity_in(glue_procs.len(), arena);
|
||||
|
||||
// Record all the getter/setter names associated with this layout
|
||||
for GlueProc { name, .. } in glue_procs {
|
||||
// Given a struct layout (including lambda sets!) the offsets - and therefore
|
||||
// getters/setters - are deterministic, so we can use layout as the hash key
|
||||
// for these getters/setters. We also only need to store the name because
|
||||
// since they are getters and setters, we can know their types (from a
|
||||
// TypeId perspective) deterministically based on knowing the types of
|
||||
// the structs and fields.
|
||||
//
|
||||
// Store them as strings, because symbols won't be useful to glue generators!
|
||||
names.push(name.as_str(&interns).to_string());
|
||||
}
|
||||
|
||||
glue_procs_by_layout.insert(layout, names.into_bump_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let types = Types::new(
|
||||
arena,
|
||||
subs,
|
||||
variables.clone(),
|
||||
arena.alloc(interns),
|
||||
glue_procs_by_layout,
|
||||
layout_cache,
|
||||
target_info,
|
||||
);
|
||||
|
||||
arch_types.push(types);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue