mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-18 19:10:18 +00:00
Initial implementation of tuples in type checking
This leaves in place a bunch of TODOs and likely many bugs - notably, I haven't tested codegen/layout at all here.
This commit is contained in:
parent
d57cb50425
commit
de828416bf
32 changed files with 1785 additions and 112 deletions
|
@ -14,7 +14,7 @@ use roc_solve_problem::{
|
|||
use roc_types::num::NumericRange;
|
||||
use roc_types::subs::{
|
||||
instantiate_rigids, Content, FlatType, GetSubsSlice, Rank, RecordFields, Subs, SubsSlice,
|
||||
Variable,
|
||||
TupleElems, Variable,
|
||||
};
|
||||
use roc_types::types::{AliasKind, Category, MemberImpl, PatternCategory, Polarity, Types};
|
||||
use roc_unify::unify::{Env, MustImplementConstraints};
|
||||
|
@ -542,6 +542,18 @@ trait DerivableVisitor {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn visit_tuple(
|
||||
_subs: &Subs,
|
||||
var: Variable,
|
||||
_elems: TupleElems,
|
||||
) -> Result<Descend, NotDerivable> {
|
||||
Err(NotDerivable {
|
||||
var,
|
||||
context: NotDerivableContext::NoContext,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn visit_tag_union(var: Variable) -> Result<Descend, NotDerivable> {
|
||||
Err(NotDerivable {
|
||||
|
@ -574,6 +586,14 @@ trait DerivableVisitor {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn visit_empty_tuple(var: Variable) -> Result<(), NotDerivable> {
|
||||
Err(NotDerivable {
|
||||
var,
|
||||
context: NotDerivableContext::NoContext,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn visit_empty_tag_union(var: Variable) -> Result<(), NotDerivable> {
|
||||
Err(NotDerivable {
|
||||
|
@ -702,6 +722,18 @@ trait DerivableVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
Tuple(elems, ext) => {
|
||||
let descend = Self::visit_tuple(subs, var, elems)?;
|
||||
if descend.0 {
|
||||
push_var_slice!(elems.variables());
|
||||
if !matches!(
|
||||
subs.get_content_without_compacting(ext),
|
||||
Content::FlexVar(_) | Content::RigidVar(_)
|
||||
) {
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
TagUnion(tags, ext) => {
|
||||
let descend = Self::visit_tag_union(var)?;
|
||||
if descend.0 {
|
||||
|
@ -728,6 +760,7 @@ trait DerivableVisitor {
|
|||
}
|
||||
}
|
||||
EmptyRecord => Self::visit_empty_record(var)?,
|
||||
EmptyTuple => Self::visit_empty_tuple(var)?,
|
||||
EmptyTagUnion => Self::visit_empty_tag_union(var)?,
|
||||
},
|
||||
Alias(
|
||||
|
|
|
@ -29,12 +29,13 @@ use roc_region::all::Loc;
|
|||
use roc_solve_problem::TypeError;
|
||||
use roc_types::subs::{
|
||||
self, AliasVariables, Content, Descriptor, FlatType, GetSubsSlice, LambdaSet, Mark,
|
||||
OptVariable, Rank, RecordFields, Subs, SubsSlice, TagExt, UlsOfVar, UnionLabels, UnionLambdas,
|
||||
UnionTags, Variable, VariableSubsSlice,
|
||||
OptVariable, Rank, RecordFields, Subs, SubsSlice, TagExt, TupleElems, UlsOfVar, UnionLabels,
|
||||
UnionLambdas, UnionTags, Variable, VariableSubsSlice,
|
||||
};
|
||||
use roc_types::types::{
|
||||
gather_fields_unsorted_iter, AliasKind, AliasShared, Category, ExtImplicitOpenness, OptAbleVar,
|
||||
Polarity, Reason, RecordField, Type, TypeExtension, TypeTag, Types, Uls,
|
||||
gather_fields_unsorted_iter, gather_tuple_elems_unsorted_iter, AliasKind, AliasShared,
|
||||
Category, ExtImplicitOpenness, OptAbleVar, Polarity, Reason, RecordField, Type, TypeExtension,
|
||||
TypeTag, Types, Uls,
|
||||
};
|
||||
use roc_unify::unify::{
|
||||
unify, unify_introduced_ability_specialization, Env as UEnv, Mode, Obligated,
|
||||
|
@ -2658,6 +2659,39 @@ fn type_to_variable<'a>(
|
|||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
|
||||
Tuple(elems) => {
|
||||
let ext_slice = types.get_type_arguments(typ_index);
|
||||
|
||||
// Elems should never be empty; we don't support empty tuples
|
||||
debug_assert!(!elems.is_empty() || !ext_slice.is_empty());
|
||||
|
||||
let mut elem_vars = Vec::with_capacity_in(elems.len(), arena);
|
||||
|
||||
let (indices, elem_tys) = types.tuple_elems_slices(elems);
|
||||
|
||||
for (index, elem_type) in indices.into_iter().zip(elem_tys.into_iter()) {
|
||||
let elem_var = helper!(elem_type);
|
||||
elem_vars.push((types[index], elem_var));
|
||||
}
|
||||
|
||||
debug_assert!(ext_slice.len() <= 1);
|
||||
let temp_ext_var = match ext_slice.into_iter().next() {
|
||||
None => roc_types::subs::Variable::EMPTY_TUPLE,
|
||||
Some(ext) => helper!(ext),
|
||||
};
|
||||
|
||||
let (it, new_ext_var) =
|
||||
gather_tuple_elems_unsorted_iter(subs, TupleElems::empty(), temp_ext_var)
|
||||
.expect("Something ended up weird in this tuple type");
|
||||
|
||||
elem_vars.extend(it);
|
||||
let tuple_elems = TupleElems::insert_into_subs(subs, elem_vars);
|
||||
|
||||
let content = Content::Structure(FlatType::Tuple(tuple_elems, new_ext_var));
|
||||
|
||||
register_with_known_var(subs, destination, rank, pools, content)
|
||||
}
|
||||
|
||||
TagUnion(tags, ext_openness) => {
|
||||
let ext_slice = types.get_type_arguments(typ_index);
|
||||
|
||||
|
@ -3728,7 +3762,7 @@ fn adjust_rank_content(
|
|||
rank
|
||||
}
|
||||
|
||||
EmptyRecord => {
|
||||
EmptyRecord | EmptyTuple => {
|
||||
// from elm-compiler: THEORY: an empty record never needs to get generalized
|
||||
//
|
||||
// But for us, that theory does not hold, because there might be type variables hidden
|
||||
|
@ -3767,6 +3801,10 @@ fn adjust_rank_content(
|
|||
rank
|
||||
}
|
||||
|
||||
Tuple(_elems, _ext_var) => {
|
||||
todo!()
|
||||
}
|
||||
|
||||
TagUnion(tags, ext_var) => {
|
||||
let mut rank =
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var.var());
|
||||
|
@ -4125,7 +4163,7 @@ fn deep_copy_var_help(
|
|||
Func(new_arguments, new_closure_var, new_ret_var)
|
||||
}
|
||||
|
||||
same @ EmptyRecord | same @ EmptyTagUnion => same,
|
||||
same @ EmptyRecord | same @ EmptyTuple | same @ EmptyTagUnion => same,
|
||||
|
||||
Record(fields, ext_var) => {
|
||||
let record_fields = {
|
||||
|
@ -4168,6 +4206,20 @@ fn deep_copy_var_help(
|
|||
Record(record_fields, work!(ext_var))
|
||||
}
|
||||
|
||||
Tuple(elems, ext_var) => {
|
||||
let tuple_elems = {
|
||||
let new_variables = copy_sequence!(elems.len(), elems.iter_variables());
|
||||
|
||||
TupleElems {
|
||||
length: elems.length,
|
||||
variables_start: new_variables.start,
|
||||
elem_index_start: elems.elem_index_start,
|
||||
}
|
||||
};
|
||||
|
||||
Tuple(tuple_elems, work!(ext_var))
|
||||
}
|
||||
|
||||
TagUnion(tags, ext_var) => {
|
||||
let union_tags = copy_union!(tags);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue