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:
Joshua Warner 2022-12-25 19:26:32 -08:00
parent d57cb50425
commit de828416bf
No known key found for this signature in database
GPG key ID: 89AD497003F93FDD
32 changed files with 1785 additions and 112 deletions

View file

@ -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(

View file

@ -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);