mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
wip
This commit is contained in:
parent
58aaf32475
commit
0d459cc84b
4 changed files with 728 additions and 0 deletions
|
@ -13,6 +13,8 @@ use roc_types::{
|
|||
types::{AliasKind, RecordField},
|
||||
};
|
||||
|
||||
mod mono_type;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Problem {
|
||||
// Compiler bugs; these should never happen!
|
||||
|
|
76
crates/compiler/specialize_types/src/mono_type.rs
Normal file
76
crates/compiler/specialize_types/src/mono_type.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
use core::fmt;
|
||||
|
||||
/// A slice into the Vec<T> of MonoTypes
|
||||
///
|
||||
/// The starting position is a u32 which should be plenty
|
||||
/// We limit slices to u16::MAX = 65535 elements
|
||||
pub struct MonoSlice<T> {
|
||||
pub start: u32,
|
||||
pub length: u16,
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Copy for MonoSlice<T> {}
|
||||
|
||||
impl<T> Clone for MonoSlice<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::fmt::Debug for MonoSlice<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"MonoSlice {{ start: {}, length: {} }}",
|
||||
self.start, self.length
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Symbol {
|
||||
inner: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct MonoTypeId {
|
||||
inner: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum MonoType {
|
||||
Apply(Symbol, MonoSlice<MonoTypeId>),
|
||||
Func {
|
||||
args: MonoSlice<MonoTypeId>,
|
||||
ret: MonoTypeId,
|
||||
},
|
||||
Record(RecordFields),
|
||||
Tuple(TupleElems),
|
||||
TagUnion(UnionTags),
|
||||
EmptyRecord,
|
||||
EmptyTuple,
|
||||
EmptyTagUnion,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct RecordFields {
|
||||
pub length: u16,
|
||||
pub field_names_start: u32,
|
||||
pub field_type_ids_start: u32,
|
||||
pub field_types_start: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct TupleElems {
|
||||
pub length: u16,
|
||||
pub elem_index_start: u32,
|
||||
pub type_ids_start: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UnionTags {
|
||||
pub length: u16,
|
||||
pub labels_start: u32,
|
||||
pub values_start: u32,
|
||||
}
|
310
crates/compiler/specialize_types/src/specialize_expr.rs
Normal file
310
crates/compiler/specialize_types/src/specialize_expr.rs
Normal file
|
@ -0,0 +1,310 @@
|
|||
use crate::expr::{self, Declarations, Expr, FunctionDef};
|
||||
use crate::specialize_type::{MonoCache, Problem};
|
||||
use crate::subs::{Subs, Variable};
|
||||
use crate::symbol::Symbol;
|
||||
use roc_collections::VecMap;
|
||||
|
||||
struct Context {
|
||||
symbols: Symbol,
|
||||
fresh_tvar: Box<dyn Fn() -> Variable>,
|
||||
specializations: Specializations,
|
||||
}
|
||||
|
||||
struct Specializations {
|
||||
symbols: Symbol,
|
||||
fenv: Vec<(Symbol, expr::FunctionDef)>,
|
||||
specializations: Vec<(SpecializationKey, NeededSpecialization)>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct SpecializationKey(Symbol, Variable);
|
||||
|
||||
struct NeededSpecialization {
|
||||
def: expr::FunctionDef,
|
||||
name_new: Symbol,
|
||||
t_new: Variable,
|
||||
specialized: Option<expr::Def>,
|
||||
}
|
||||
|
||||
impl Specializations {
|
||||
fn make(symbols: Symbol, program: &expr::Declarations) -> Self {
|
||||
let fenv = program
|
||||
.iter_top_down()
|
||||
.filter_map(|(_, tag)| match tag {
|
||||
expr::DeclarationTag::Function(idx)
|
||||
| expr::DeclarationTag::Recursive(idx)
|
||||
| expr::DeclarationTag::TailRecursive(idx) => {
|
||||
let func = &program.function_bodies[idx.index()];
|
||||
Some((func.value.name, func.value.clone()))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Specializations {
|
||||
symbols,
|
||||
fenv,
|
||||
specializations: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn specialize_fn(
|
||||
&mut self,
|
||||
mono_cache: &mut MonoCache,
|
||||
name: Symbol,
|
||||
t_new: Variable,
|
||||
) -> Option<Symbol> {
|
||||
let specialization = (name, t_new);
|
||||
|
||||
if let Some((_, needed)) = self
|
||||
.specializations
|
||||
.iter()
|
||||
.find(|(key, _)| *key == specialization)
|
||||
{
|
||||
Some(needed.name_new)
|
||||
} else {
|
||||
let def = self.fenv.iter().find(|(n, _)| *n == name)?.1.clone();
|
||||
let name_new = self.symbols.fresh_symbol_named(name);
|
||||
let needed_specialization = NeededSpecialization {
|
||||
def,
|
||||
name_new,
|
||||
t_new,
|
||||
specialized: None,
|
||||
};
|
||||
self.specializations
|
||||
.push((specialization, needed_specialization));
|
||||
Some(name_new)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_needed_specialization(&mut self) -> Option<&mut NeededSpecialization> {
|
||||
self.specializations.iter_mut().find_map(|(_, ns)| {
|
||||
if ns.specialized.is_none() {
|
||||
Some(ns)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn solved_specializations(&self) -> Vec<expr::Def> {
|
||||
self.specializations
|
||||
.iter()
|
||||
.filter_map(|(_, ns)| ns.specialized.clone())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn specialize_expr(
|
||||
ctx: &mut Context,
|
||||
ty_cache: &mut Subs,
|
||||
mono_cache: &mut MonoCache,
|
||||
expr: &Expr,
|
||||
) -> Expr {
|
||||
match expr {
|
||||
Expr::Var(x) => {
|
||||
if let Some(y) = ctx
|
||||
.specializations
|
||||
.specialize_fn(mono_cache, *x, expr.get_type())
|
||||
{
|
||||
Expr::Var(y)
|
||||
} else {
|
||||
expr.clone()
|
||||
}
|
||||
}
|
||||
Expr::Int(i) => Expr::Int(*i),
|
||||
Expr::Str(s) => Expr::Str(s.clone()),
|
||||
Expr::Tag(t, args) => {
|
||||
let new_args = args
|
||||
.iter()
|
||||
.map(|a| specialize_expr(ctx, ty_cache, mono_cache, a))
|
||||
.collect();
|
||||
Expr::Tag(*t, new_args)
|
||||
}
|
||||
Expr::Record(fields) => {
|
||||
let new_fields = fields
|
||||
.iter()
|
||||
.map(|(f, e)| (*f, specialize_expr(ctx, ty_cache, mono_cache, e)))
|
||||
.collect();
|
||||
Expr::Record(new_fields)
|
||||
}
|
||||
Expr::Access(e, f) => {
|
||||
Expr::Access(Box::new(specialize_expr(ctx, ty_cache, mono_cache, e)), *f)
|
||||
}
|
||||
Expr::Let(def, rest) => {
|
||||
let new_def = match def {
|
||||
expr::Def::Letfn(f) => expr::Def::Letfn(FunctionDef {
|
||||
recursive: f.recursive,
|
||||
bind: (
|
||||
mono_cache.monomorphize_var(ty_cache, &mut Vec::new(), f.bind.0),
|
||||
f.bind.1,
|
||||
),
|
||||
arg: (
|
||||
mono_cache.monomorphize_var(ty_cache, &mut Vec::new(), f.arg.0),
|
||||
f.arg.1,
|
||||
),
|
||||
body: Box::new(specialize_expr(ctx, ty_cache, mono_cache, &f.body)),
|
||||
}),
|
||||
expr::Def::Letval(v) => expr::Def::Letval(expr::Letval {
|
||||
bind: (
|
||||
mono_cache.monomorphize_var(ty_cache, &mut Vec::new(), v.bind.0),
|
||||
v.bind.1,
|
||||
),
|
||||
body: Box::new(specialize_expr(ctx, ty_cache, mono_cache, &v.body)),
|
||||
}),
|
||||
};
|
||||
let new_rest = Box::new(specialize_expr(ctx, ty_cache, mono_cache, rest));
|
||||
Expr::Let(Box::new(new_def), new_rest)
|
||||
}
|
||||
Expr::Clos { arg, body } => {
|
||||
let new_arg = (
|
||||
mono_cache.monomorphize_var(ty_cache, &mut Vec::new(), arg.0),
|
||||
arg.1,
|
||||
);
|
||||
let new_body = Box::new(specialize_expr(ctx, ty_cache, mono_cache, body));
|
||||
Expr::Clos {
|
||||
arg: new_arg,
|
||||
body: new_body,
|
||||
}
|
||||
}
|
||||
Expr::Call(f, a) => {
|
||||
let new_f = Box::new(specialize_expr(ctx, ty_cache, mono_cache, f));
|
||||
let new_a = Box::new(specialize_expr(ctx, ty_cache, mono_cache, a));
|
||||
Expr::Call(new_f, new_a)
|
||||
}
|
||||
Expr::KCall(kfn, args) => {
|
||||
let new_args = args
|
||||
.iter()
|
||||
.map(|a| specialize_expr(ctx, ty_cache, mono_cache, a))
|
||||
.collect();
|
||||
Expr::KCall(*kfn, new_args)
|
||||
}
|
||||
Expr::When(e, branches) => {
|
||||
let new_e = Box::new(specialize_expr(ctx, ty_cache, mono_cache, e));
|
||||
let new_branches = branches
|
||||
.iter()
|
||||
.map(|(p, e)| {
|
||||
let new_p = specialize_pattern(ctx, ty_cache, mono_cache, p);
|
||||
let new_e = specialize_expr(ctx, ty_cache, mono_cache, e);
|
||||
(new_p, new_e)
|
||||
})
|
||||
.collect();
|
||||
Expr::When(new_e, new_branches)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn specialize_pattern(
|
||||
ctx: &mut Context,
|
||||
ty_cache: &mut Subs,
|
||||
mono_cache: &mut MonoCache,
|
||||
pattern: &expr::Pattern,
|
||||
) -> expr::Pattern {
|
||||
match pattern {
|
||||
expr::Pattern::PVar(x) => expr::Pattern::PVar(*x),
|
||||
expr::Pattern::PTag(tag, args) => {
|
||||
let new_args = args
|
||||
.iter()
|
||||
.map(|a| specialize_pattern(ctx, ty_cache, mono_cache, a))
|
||||
.collect();
|
||||
expr::Pattern::PTag(*tag, new_args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn specialize_let_fn(
|
||||
ctx: &mut Context,
|
||||
ty_cache: &mut Subs,
|
||||
mono_cache: &mut MonoCache,
|
||||
t_new: Variable,
|
||||
name_new: Symbol,
|
||||
f: &expr::FunctionDef,
|
||||
) -> expr::Def {
|
||||
mono_cache.monomorphize_var(ty_cache, &mut Vec::new(), t_new);
|
||||
let t = mono_cache.monomorphize_var(ty_cache, &mut Vec::new(), f.bind.0);
|
||||
let t_arg = mono_cache.monomorphize_var(ty_cache, &mut Vec::new(), f.arg.0);
|
||||
let body = specialize_expr(ctx, ty_cache, mono_cache, &f.body);
|
||||
|
||||
expr::Def::Letfn(FunctionDef {
|
||||
recursive: f.recursive,
|
||||
bind: (t, name_new),
|
||||
arg: (t_arg, f.arg.1),
|
||||
body: Box::new(body),
|
||||
})
|
||||
}
|
||||
|
||||
fn specialize_let_val(ctx: &mut Context, v: &expr::Letval) -> expr::Def {
|
||||
let mut ty_cache = Subs::new();
|
||||
let mut mono_cache = MonoCache::from_subs(&ty_cache);
|
||||
let t = mono_cache.monomorphize_var(&mut ty_cache, &mut Vec::new(), v.bind.0);
|
||||
let body = specialize_expr(ctx, &mut ty_cache, &mut mono_cache, &v.body);
|
||||
expr::Def::Letval(expr::Letval {
|
||||
bind: (t, v.bind.1),
|
||||
body: Box::new(body),
|
||||
})
|
||||
}
|
||||
|
||||
fn specialize_run_def(ctx: &mut Context, run: &expr::Run) -> expr::Run {
|
||||
let mut ty_cache = Subs::new();
|
||||
let mut mono_cache = MonoCache::from_subs(&ty_cache);
|
||||
let t = mono_cache.monomorphize_var(&mut ty_cache, &mut Vec::new(), run.bind.0);
|
||||
let body = specialize_expr(ctx, &mut ty_cache, &mut mono_cache, &run.body);
|
||||
expr::Run {
|
||||
bind: (t, run.bind.1),
|
||||
body: Box::new(body),
|
||||
ty: run.ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_context(
|
||||
symbols: Symbol,
|
||||
fresh_tvar: Box<dyn Fn() -> Variable>,
|
||||
program: &expr::Declarations,
|
||||
) -> Context {
|
||||
Context {
|
||||
symbols,
|
||||
fresh_tvar,
|
||||
specializations: Specializations::make(symbols, program),
|
||||
}
|
||||
}
|
||||
|
||||
fn loop_specializations(ctx: &mut Context) {
|
||||
while let Some(needed) = ctx.specializations.next_needed_specialization() {
|
||||
let mut ty_cache = Subs::new();
|
||||
let mut mono_cache = MonoCache::from_subs(&ty_cache);
|
||||
let def = specialize_let_fn(
|
||||
ctx,
|
||||
&mut ty_cache,
|
||||
&mut mono_cache,
|
||||
needed.t_new,
|
||||
needed.name_new,
|
||||
&needed.def,
|
||||
);
|
||||
needed.specialized = Some(def);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower(ctx: &mut Context, program: &expr::Declarations) -> expr::Declarations {
|
||||
let mut new_program = expr::Declarations::new();
|
||||
|
||||
for (idx, tag) in program.iter_top_down() {
|
||||
match tag {
|
||||
expr::DeclarationTag::Value => {
|
||||
let def = specialize_let_val(ctx, &program.expressions[idx]);
|
||||
new_program.push_def(def);
|
||||
}
|
||||
expr::DeclarationTag::Run(run_idx) => {
|
||||
let run = specialize_run_def(ctx, &program.expressions[run_idx.index()]);
|
||||
new_program.push_run(run);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
loop_specializations(ctx);
|
||||
|
||||
let other_defs = ctx.specializations.solved_specializations();
|
||||
new_program.extend(other_defs);
|
||||
|
||||
new_program
|
||||
}
|
340
crates/compiler/specialize_types/src/specialize_type.rs
Normal file
340
crates/compiler/specialize_types/src/specialize_type.rs
Normal file
|
@ -0,0 +1,340 @@
|
|||
/// Given a Subs that's been populated from type inference, and a Variable,
|
||||
/// ensure that Variable is monomorphic by going through and creating
|
||||
/// specializations of that type wherever necessary.
|
||||
///
|
||||
/// This only operates at the type level. It does not create new function implementations (for example).
|
||||
use bitvec::vec::BitVec;
|
||||
use roc_module::ident::{Lowercase, TagName};
|
||||
use roc_types::{
|
||||
subs::{
|
||||
Content, FlatType, RecordFields, Subs, TagExt, TupleElems, UnionLabels, UnionTags,
|
||||
Variable, VariableSubsSlice,
|
||||
},
|
||||
types::RecordField,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Problem {
|
||||
// Compiler bugs; these should never happen!
|
||||
TagUnionExtWasNotTagUnion,
|
||||
RecordExtWasNotRecord,
|
||||
TupleExtWasNotTuple,
|
||||
}
|
||||
|
||||
/// Variables that have already been monomorphized.
|
||||
pub struct MonoCache {
|
||||
inner: BitVec,
|
||||
}
|
||||
|
||||
impl MonoCache {
|
||||
pub fn from_subs(subs: &Subs) -> Self {
|
||||
Self {
|
||||
inner: BitVec::repeat(false, subs.len()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true iff we know this Variable is monomorphic because
|
||||
/// we've visited it before in the monomorphization process
|
||||
/// (and either it was already monomorphic, or we made it so).
|
||||
pub fn is_known_monomorphic(&self, var: Variable) -> bool {
|
||||
match self.inner.get(var.index() as usize) {
|
||||
Some(initialized) => {
|
||||
// false if it has never been set, because we initialized all the bits to 0
|
||||
*initialized
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Records that the given variable is now known to be monomorphic.
|
||||
fn set_monomorphic(&mut self, var: Variable) {
|
||||
self.inner.set(var.index() as usize, true);
|
||||
}
|
||||
|
||||
pub fn monomorphize_var(
|
||||
&mut self,
|
||||
subs: &mut Subs,
|
||||
problems: &mut Vec<Problem>,
|
||||
var: Variable,
|
||||
) {
|
||||
lower_var(self, subs, problems, var);
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_var(
|
||||
cache: &mut MonoCache,
|
||||
subs: &mut Subs,
|
||||
problems: &mut Vec<Problem>,
|
||||
var: Variable,
|
||||
) -> Variable {
|
||||
let root_var = subs.get_root_key_without_compacting(var);
|
||||
|
||||
if !cache.is_known_monomorphic(root_var) {
|
||||
let content = match *subs.get_content_without_compacting(root_var) {
|
||||
Content::Structure(flat_type) => match flat_type {
|
||||
FlatType::Apply(symbol, args) => {
|
||||
let new_args = args
|
||||
.into_iter()
|
||||
.map(|var_index| lower_var(cache, subs, problems, subs[var_index]))
|
||||
.collect::<Vec<Variable>>();
|
||||
|
||||
Content::Structure(FlatType::Apply(
|
||||
*symbol,
|
||||
VariableSubsSlice::insert_into_subs(subs, new_args),
|
||||
))
|
||||
}
|
||||
FlatType::Func(args, closure, ret) => {
|
||||
let new_args = args
|
||||
.into_iter()
|
||||
.map(|var_index| lower_var(cache, subs, problems, subs[var_index]))
|
||||
.collect::<Vec<_>>();
|
||||
let new_closure = lower_var(cache, subs, problems, *closure);
|
||||
let new_ret = lower_var(cache, subs, problems, *ret);
|
||||
Content::Structure(FlatType::Func(
|
||||
VariableSubsSlice::insert_into_subs(subs, new_args),
|
||||
new_closure,
|
||||
new_ret,
|
||||
))
|
||||
}
|
||||
FlatType::Record(fields, ext) => {
|
||||
let mut fields = resolve_record_ext(subs, problems, *fields, *ext);
|
||||
|
||||
// Now lower all the fields we gathered. Do this in a separate pass to avoid borrow errors on Subs.
|
||||
for (_, field) in fields.iter_mut() {
|
||||
let var = match field {
|
||||
RecordField::Required(v) | RecordField::Optional(v) | RecordField::Demanded(v) => v,
|
||||
RecordField::RigidRequired(v) | RecordField::RigidOptional(v) => v,
|
||||
};
|
||||
|
||||
*var = lower_var(cache, subs, problems, *var);
|
||||
}
|
||||
|
||||
Content::Structure(FlatType::Record(
|
||||
RecordFields::insert_into_subs(subs, fields),
|
||||
Variable::EMPTY_RECORD,
|
||||
))
|
||||
}
|
||||
FlatType::Tuple(elems, ext) => {
|
||||
let mut elems = resolve_tuple_ext(subs, problems, *elems, *ext);
|
||||
|
||||
// Now lower all the elems we gathered. Do this in a separate pass to avoid borrow errors on Subs.
|
||||
lower_vars(elems.iter_mut().map(|(_, var)| var), cache, subs, problems);
|
||||
|
||||
Content::Structure(FlatType::Tuple(
|
||||
TupleElems::insert_into_subs(subs, elems),
|
||||
Variable::EMPTY_TUPLE,
|
||||
))
|
||||
}
|
||||
FlatType::TagUnion(tags, ext) => {
|
||||
let mut tags = resolve_tag_ext(subs, problems, *tags, *ext);
|
||||
|
||||
// Now lower all the tags we gathered. Do this in a separate pass to avoid borrow errors on Subs.
|
||||
lower_vars(tags.iter_mut().flat_map(|(_, vars)| vars.iter_mut()), cache, subs, problems);
|
||||
|
||||
Content::Structure(FlatType::TagUnion(
|
||||
UnionTags::insert_into_subs(subs, tags),
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
))
|
||||
}
|
||||
FlatType::FunctionOrTagUnion(tag_names, _symbols, ext) => {
|
||||
// If this is still a FunctionOrTagUnion, turn it into a TagUnion.
|
||||
|
||||
// First, resolve the ext var.
|
||||
let mut tags = resolve_tag_ext(subs, problems, UnionTags::default(), *ext);
|
||||
|
||||
// Now lower all the tags we gathered from the ext var.
|
||||
// (Do this in a separate pass to avoid borrow errors on Subs.)
|
||||
lower_vars(tags.iter_mut().flat_map(|(_, vars)| vars.iter_mut()), cache, subs, problems);
|
||||
|
||||
// Then, add the tag names with no payloads. (There are no variables to lower here.)
|
||||
for index in tag_names.into_iter() {
|
||||
tags.push(((subs[index]).clone(), Vec::new()));
|
||||
}
|
||||
|
||||
Content::Structure(FlatType::TagUnion(
|
||||
UnionTags::insert_into_subs(subs, tags),
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
))
|
||||
}
|
||||
FlatType::RecursiveTagUnion(rec, tags, ext) => {
|
||||
let mut tags = resolve_tag_ext(subs, problems, *tags, *ext);
|
||||
|
||||
// Now lower all the tags we gathered. Do this in a separate pass to avoid borrow errors on Subs.
|
||||
lower_vars(tags.iter_mut().flat_map(|(_, vars)| vars.iter_mut()), cache, subs, problems);
|
||||
|
||||
Content::Structure(FlatType::RecursiveTagUnion(
|
||||
lower_var(cache, subs, problems, *rec),
|
||||
UnionTags::insert_into_subs(subs, tags),
|
||||
TagExt::Any(Variable::EMPTY_TAG_UNION),
|
||||
))
|
||||
}
|
||||
FlatType::EmptyRecord => Content::Structure(FlatType::EmptyRecord),
|
||||
FlatType::EmptyTuple => Content::Structure(FlatType::EmptyTuple),
|
||||
FlatType::EmptyTagUnion => Content::Structure(FlatType::EmptyTagUnion),
|
||||
},
|
||||
Content::RangedNumber(_) // RangedNumber goes in Num's type parameter slot, so monomorphize it to []
|
||||
| Content::FlexVar(_)
|
||||
| Content::RigidVar(_)
|
||||
| Content::FlexAbleVar(_, _)
|
||||
| Content::RigidAbleVar(_, _)
|
||||
| Content::RecursionVar { .. } => Content::Structure(FlatType::EmptyTagUnion),
|
||||
Content::LambdaSet(lambda_set) => Content::LambdaSet(*lambda_set),
|
||||
Content::ErasedLambda => Content::ErasedLambda,
|
||||
Content::Alias(symbol, args, real, kind) => {
|
||||
let todo = (); // TODO we should unwrap this, but doing that probably means changing this from root_var to other stuff.
|
||||
let new_real = lower_var(cache, subs, problems, *real);
|
||||
Content::Alias(*symbol, *args, new_real, *kind)
|
||||
}
|
||||
Content::Error => Content::Error,
|
||||
};
|
||||
|
||||
// Update Subs so when we look up this var in the future, it's the monomorphized Content.
|
||||
subs.set_content(root_var, content);
|
||||
|
||||
// This var is now known to be monomorphic.
|
||||
cache.set_monomorphic(root_var);
|
||||
}
|
||||
|
||||
root_var
|
||||
}
|
||||
|
||||
fn resolve_tag_ext(
|
||||
subs: &mut Subs,
|
||||
problems: &mut Vec<Problem>,
|
||||
mut tags: UnionTags,
|
||||
mut ext: TagExt,
|
||||
) -> Vec<(TagName, Vec<Variable>)> {
|
||||
let mut all_tags = Vec::new();
|
||||
|
||||
// Collapse (recursively) all the tags in ext_var into a flat list of tags.
|
||||
loop {
|
||||
for (tag, vars) in tags.iter_from_subs(subs) {
|
||||
all_tags.push((tag.clone(), vars.to_vec()));
|
||||
}
|
||||
|
||||
match subs.get_content_without_compacting(ext.var()) {
|
||||
Content::Structure(FlatType::TagUnion(new_tags, new_ext)) => {
|
||||
// Update tags and ext and loop back again to process them.
|
||||
tags = *new_tags;
|
||||
ext = *new_ext;
|
||||
}
|
||||
Content::Structure(FlatType::FunctionOrTagUnion(tag_names, _symbols, new_ext)) => {
|
||||
for index in tag_names.into_iter() {
|
||||
all_tags.push((subs[index].clone(), Vec::new()));
|
||||
}
|
||||
ext = *new_ext;
|
||||
}
|
||||
Content::Structure(FlatType::EmptyTagUnion) => break,
|
||||
Content::FlexVar(_) | Content::FlexAbleVar(_, _) => break,
|
||||
Content::Alias(_, _, real, _) => {
|
||||
// Follow the alias and process it on the next iteration of the loop.
|
||||
ext = TagExt::Any(*real);
|
||||
|
||||
// We just processed these tags, so don't process them again!
|
||||
tags = UnionLabels::default();
|
||||
}
|
||||
_ => {
|
||||
// This should never happen! If it does, record a Problem and break.
|
||||
problems.push(Problem::TagUnionExtWasNotTagUnion);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
all_tags
|
||||
}
|
||||
|
||||
fn resolve_record_ext(
|
||||
subs: &mut Subs,
|
||||
problems: &mut Vec<Problem>,
|
||||
mut fields: RecordFields,
|
||||
mut ext: Variable,
|
||||
) -> Vec<(Lowercase, RecordField<Variable>)> {
|
||||
let mut all_fields = Vec::new();
|
||||
|
||||
// Collapse (recursively) all the fields in ext into a flat list of fields.
|
||||
loop {
|
||||
for (label, field) in fields.sorted_iterator(subs, ext) {
|
||||
all_fields.push((label.clone(), field));
|
||||
}
|
||||
|
||||
match subs.get_content_without_compacting(ext) {
|
||||
Content::Structure(FlatType::Record(new_fields, new_ext)) => {
|
||||
// Update fields and ext and loop back again to process them.
|
||||
fields = *new_fields;
|
||||
ext = *new_ext;
|
||||
}
|
||||
Content::Structure(FlatType::EmptyRecord) => break,
|
||||
Content::FlexVar(_) | Content::FlexAbleVar(_, _) => break,
|
||||
Content::Alias(_, _, real, _) => {
|
||||
// Follow the alias and process it on the next iteration of the loop.
|
||||
ext = *real;
|
||||
|
||||
// We just processed these fields, so don't process them again!
|
||||
fields = RecordFields::empty();
|
||||
}
|
||||
_ => {
|
||||
// This should never happen! If it does, record a Problem and break.
|
||||
problems.push(Problem::RecordExtWasNotRecord);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
all_fields
|
||||
}
|
||||
|
||||
fn resolve_tuple_ext(
|
||||
subs: &mut Subs,
|
||||
problems: &mut Vec<Problem>,
|
||||
mut elems: TupleElems,
|
||||
mut ext: Variable,
|
||||
) -> Vec<(usize, Variable)> {
|
||||
let mut all_elems = Vec::new();
|
||||
|
||||
// Collapse (recursively) all the elements in ext into a flat list of elements.
|
||||
loop {
|
||||
for (idx, var_index) in elems.iter_all() {
|
||||
all_elems.push((idx.index as usize, subs[var_index]));
|
||||
}
|
||||
|
||||
match subs.get_content_without_compacting(ext) {
|
||||
Content::Structure(FlatType::Tuple(new_elems, new_ext)) => {
|
||||
// Update elems and ext and loop back again to process them.
|
||||
elems = *new_elems;
|
||||
ext = *new_ext;
|
||||
}
|
||||
Content::Structure(FlatType::EmptyTuple) => break,
|
||||
Content::FlexVar(_) | Content::FlexAbleVar(_, _) => break,
|
||||
Content::Alias(_, _, real, _) => {
|
||||
// Follow the alias and process it on the next iteration of the loop.
|
||||
ext = *real;
|
||||
|
||||
// We just processed these elements, so don't process them again!
|
||||
elems = TupleElems::empty();
|
||||
}
|
||||
_ => {
|
||||
// This should never happen! If it does, record a Problem and break.
|
||||
problems.push(Problem::TupleExtWasNotTuple);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
all_elems
|
||||
}
|
||||
|
||||
/// Lower the given vars in-place.
|
||||
fn lower_vars<'a>(
|
||||
vars: impl Iterator<Item = &'a mut Variable>,
|
||||
cache: &mut MonoCache,
|
||||
subs: &mut Subs,
|
||||
problems: &mut Vec<Problem>,
|
||||
) {
|
||||
for var in vars {
|
||||
*var = lower_var(cache, subs, problems, *var);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue