Push implicit openness vars through

This commit is contained in:
Ayaz Hafiz 2023-01-13 11:13:00 -06:00
parent 96b2b7a0c5
commit 5fceb9ceb7
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
5 changed files with 190 additions and 95 deletions

View file

@ -9,8 +9,8 @@ use roc_problem::can::ShadowKind;
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
use roc_types::subs::{VarStore, Variable}; use roc_types::subs::{VarStore, Variable};
use roc_types::types::{ use roc_types::types::{
name_type_var, AbilitySet, Alias, AliasCommon, AliasKind, AliasVar, LambdaSet, OptAbleType, name_type_var, AbilitySet, Alias, AliasCommon, AliasKind, AliasVar, IsImplicitOpennessVar,
OptAbleVar, RecordField, Type, TypeExtension, LambdaSet, OptAbleType, OptAbleVar, RecordField, Type, TypeExtension,
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -876,7 +876,7 @@ fn can_annotation_help(
todo!("tuple"); todo!("tuple");
} }
Record { fields, ext } => { Record { fields, ext } => {
let ext_type = can_extension_type( let (ext_type, is_implicit_openness) = can_extension_type(
env, env,
pol, pol,
scope, scope,
@ -888,13 +888,21 @@ fn can_annotation_help(
roc_problem::can::ExtensionTypeKind::Record, roc_problem::can::ExtensionTypeKind::Record,
); );
debug_assert!(
!is_implicit_openness.0,
"records should never be implicitly inferred open"
);
if fields.is_empty() { if fields.is_empty() {
match ext { match ext {
Some(_) => { Some(_) => {
// just `a` does not mean the same as `{}a`, so even // just `a` does not mean the same as `{}a`, so even
// if there are no fields, still make this a `Record`, // if there are no fields, still make this a `Record`,
// not an EmptyRec // not an EmptyRec
Type::Record(Default::default(), TypeExtension::from_type(ext_type)) Type::Record(
Default::default(),
TypeExtension::from_type(ext_type, is_implicit_openness),
)
} }
None => Type::EmptyRec, None => Type::EmptyRec,
@ -912,11 +920,14 @@ fn can_annotation_help(
references, references,
); );
Type::Record(field_types, TypeExtension::from_type(ext_type)) Type::Record(
field_types,
TypeExtension::from_type(ext_type, is_implicit_openness),
)
} }
} }
TagUnion { tags, ext, .. } => { TagUnion { tags, ext, .. } => {
let ext_type = can_extension_type( let (ext_type, is_implicit_openness) = can_extension_type(
env, env,
pol, pol,
scope, scope,
@ -934,7 +945,10 @@ fn can_annotation_help(
// just `a` does not mean the same as `[]`, so even // just `a` does not mean the same as `[]`, so even
// if there are no fields, still make this a `TagUnion`, // if there are no fields, still make this a `TagUnion`,
// not an EmptyTagUnion // not an EmptyTagUnion
Type::TagUnion(Default::default(), TypeExtension::from_type(ext_type)) Type::TagUnion(
Default::default(),
TypeExtension::from_type(ext_type, is_implicit_openness),
)
} }
None => Type::EmptyTagUnion, None => Type::EmptyTagUnion,
@ -957,7 +971,10 @@ fn can_annotation_help(
// in theory we save a lot of time by sorting once here // in theory we save a lot of time by sorting once here
insertion_sort_by(&mut tag_types, |a, b| a.0.cmp(&b.0)); insertion_sort_by(&mut tag_types, |a, b| a.0.cmp(&b.0));
Type::TagUnion(tag_types, TypeExtension::from_type(ext_type)) Type::TagUnion(
tag_types,
TypeExtension::from_type(ext_type, is_implicit_openness),
)
} }
} }
SpaceBefore(nested, _) | SpaceAfter(nested, _) => can_annotation_help( SpaceBefore(nested, _) | SpaceAfter(nested, _) => can_annotation_help(
@ -1094,7 +1111,7 @@ fn can_extension_type<'a>(
references: &mut VecSet<Symbol>, references: &mut VecSet<Symbol>,
opt_ext: &Option<&Loc<TypeAnnotation<'a>>>, opt_ext: &Option<&Loc<TypeAnnotation<'a>>>,
ext_problem_kind: roc_problem::can::ExtensionTypeKind, ext_problem_kind: roc_problem::can::ExtensionTypeKind,
) -> Type { ) -> (Type, IsImplicitOpennessVar) {
fn valid_record_ext_type(typ: &Type) -> bool { fn valid_record_ext_type(typ: &Type) -> bool {
// Include erroneous types so that we don't overreport errors. // Include erroneous types so that we don't overreport errors.
matches!( matches!(
@ -1141,7 +1158,7 @@ fn can_extension_type<'a>(
}) })
} }
ext_type (ext_type, IsImplicitOpennessVar::NO)
} else { } else {
// Report an error but mark the extension variable to be inferred // Report an error but mark the extension variable to be inferred
// so that we're as permissive as possible. // so that we're as permissive as possible.
@ -1157,21 +1174,27 @@ fn can_extension_type<'a>(
introduced_variables.insert_inferred(Loc::at_zero(var)); introduced_variables.insert_inferred(Loc::at_zero(var));
Type::Variable(var) (
Type::Variable(var),
// Since this is an error anyway, just be permissive
IsImplicitOpennessVar::NO,
)
} }
} }
None => match ext_problem_kind { None => match ext_problem_kind {
ExtensionTypeKind::Record => Type::EmptyRec, ExtensionTypeKind::Record => (Type::EmptyRec, IsImplicitOpennessVar::NO),
ExtensionTypeKind::TagUnion => { ExtensionTypeKind::TagUnion => {
// In negative positions a missing extension variable forces a closed tag union; // In negative positions a missing extension variable forces a closed tag union;
// otherwise, open-in-output-position means we give the tag an inference variable. // otherwise, open-in-output-position means we give the tag an inference variable.
match pol { match pol {
CanPolarity::Neg | CanPolarity::InOpaque => Type::EmptyTagUnion, CanPolarity::Neg | CanPolarity::InOpaque => {
(Type::EmptyTagUnion, IsImplicitOpennessVar::NO)
}
CanPolarity::Pos | CanPolarity::InAlias => { CanPolarity::Pos | CanPolarity::InAlias => {
let var = var_store.fresh(); let var = var_store.fresh();
introduced_variables.insert_infer_ext_in_output(var); introduced_variables.insert_infer_ext_in_output(var);
Type::Variable(var) (Type::Variable(var), IsImplicitOpennessVar::YES)
} }
} }
} }

View file

@ -279,7 +279,7 @@ pub fn constrain_expr(
let fields_type = { let fields_type = {
let typ = types.from_old_type(&Type::Record( let typ = types.from_old_type(&Type::Record(
fields, fields,
TypeExtension::from_type(Type::Variable(*ext_var)), TypeExtension::from_non_annotation_type(Type::Variable(*ext_var)),
)); ));
constraints.push_type(types, typ) constraints.push_type(types, typ)
}; };
@ -1090,7 +1090,7 @@ pub fn constrain_expr(
let record_type = { let record_type = {
let typ = types.from_old_type(&Type::Record( let typ = types.from_old_type(&Type::Record(
rec_field_types, rec_field_types,
TypeExtension::from_type(ext_type), TypeExtension::from_non_annotation_type(ext_type),
)); ));
constraints.push_type(types, typ) constraints.push_type(types, typ)
}; };
@ -1134,7 +1134,10 @@ pub fn constrain_expr(
let mut field_types = SendMap::default(); let mut field_types = SendMap::default();
let label = field.clone(); let label = field.clone();
field_types.insert(label, RecordField::Demanded(field_type.clone())); field_types.insert(label, RecordField::Demanded(field_type.clone()));
let record_type = Type::Record(field_types, TypeExtension::from_type(ext_type)); let record_type = Type::Record(
field_types,
TypeExtension::from_non_annotation_type(ext_type),
);
let record_type_index = { let record_type_index = {
let typ = types.from_old_type(&record_type); let typ = types.from_old_type(&record_type);
constraints.push_type(types, typ) constraints.push_type(types, typ)
@ -1267,7 +1270,7 @@ pub fn constrain_expr(
let tag_union_type = { let tag_union_type = {
let typ = types.from_old_type(&Type::TagUnion( let typ = types.from_old_type(&Type::TagUnion(
vec![(name.clone(), payload_types)], vec![(name.clone(), payload_types)],
TypeExtension::from_type(Type::Variable(*ext_var)), TypeExtension::from_non_annotation_type(Type::Variable(*ext_var)),
)); ));
constraints.push_type(types, typ) constraints.push_type(types, typ)
}; };
@ -1299,7 +1302,7 @@ pub fn constrain_expr(
let typ = types.from_old_type(&Type::FunctionOrTagUnion( let typ = types.from_old_type(&Type::FunctionOrTagUnion(
name.clone(), name.clone(),
*closure_name, *closure_name,
TypeExtension::from_type(Type::Variable(*ext_var)), TypeExtension::from_non_annotation_type(Type::Variable(*ext_var)),
)); ));
constraints.push_type(types, typ) constraints.push_type(types, typ)
}; };

View file

@ -578,7 +578,7 @@ pub fn constrain_pattern(
let record_type = { let record_type = {
let typ = types.from_old_type(&Type::Record( let typ = types.from_old_type(&Type::Record(
field_types, field_types,
TypeExtension::from_type(ext_type), TypeExtension::from_non_annotation_type(ext_type),
)); ));
constraints.push_type(types, typ) constraints.push_type(types, typ)
}; };

View file

@ -33,8 +33,8 @@ use roc_types::subs::{
UnionTags, Variable, VariableSubsSlice, UnionTags, Variable, VariableSubsSlice,
}; };
use roc_types::types::{ use roc_types::types::{
gather_fields_unsorted_iter, AliasKind, AliasShared, Category, OptAbleVar, Polarity, Reason, gather_fields_unsorted_iter, AliasKind, AliasShared, Category, IsImplicitOpennessVar,
RecordField, Type, TypeExtension, TypeTag, Types, Uls, OptAbleVar, Polarity, Reason, RecordField, Type, TypeExtension, TypeTag, Types, Uls,
}; };
use roc_unify::unify::{ use roc_unify::unify::{
unify, unify_introduced_ability_specialization, Env as UEnv, Mode, Obligated, unify, unify_introduced_ability_specialization, Env as UEnv, Mode, Obligated,
@ -2658,7 +2658,7 @@ fn type_to_variable<'a>(
register_with_known_var(subs, destination, rank, pools, content) register_with_known_var(subs, destination, rank, pools, content)
} }
TagUnion(tags) => { TagUnion(tags, ext_openness) => {
let ext_slice = types.get_type_arguments(typ_index); let ext_slice = types.get_type_arguments(typ_index);
// An empty tags is inefficient (but would be correct) // An empty tags is inefficient (but would be correct)
@ -2666,26 +2666,41 @@ fn type_to_variable<'a>(
debug_assert!(!tags.is_empty() || !ext_slice.is_empty()); debug_assert!(!tags.is_empty() || !ext_slice.is_empty());
let (union_tags, ext) = type_to_union_tags( let (union_tags, ext) = type_to_union_tags(
subs, rank, pools, arena, types, tags, ext_slice, &mut stack, subs,
rank,
pools,
arena,
types,
tags,
ext_slice,
ext_openness,
&mut stack,
); );
let content = Content::Structure(FlatType::TagUnion(union_tags, ext)); let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
register_with_known_var(subs, destination, rank, pools, content) register_with_known_var(subs, destination, rank, pools, content)
} }
FunctionOrTagUnion(symbol) => { FunctionOrTagUnion(symbol, ext_openness) => {
let ext_slice = types.get_type_arguments(typ_index); let ext_slice = types.get_type_arguments(typ_index);
let tag_name = types.get_tag_name(&typ_index).clone(); let tag_name = types.get_tag_name(&typ_index).clone();
debug_assert!(ext_slice.len() <= 1); debug_assert!(ext_slice.len() <= 1);
let temp_ext_var = match ext_slice.into_iter().next() { let temp_ext = match ext_slice.into_iter().next() {
Some(ext) => helper!(ext), Some(ext) => {
None => roc_types::subs::Variable::EMPTY_TAG_UNION, let var = helper!(ext);
if ext_openness.0 {
TagExt::Openness(var)
} else {
TagExt::Any(var)
}
}
None => TagExt::Any(roc_types::subs::Variable::EMPTY_TAG_UNION),
}; };
let (it, ext) = roc_types::types::gather_tags_unsorted_iter( let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
subs, subs,
UnionTags::default(), UnionTags::default(),
TagExt::Any(temp_ext_var), temp_ext,
) )
.expect("extension var could not be seen as a tag union"); .expect("extension var could not be seen as a tag union");
@ -2701,7 +2716,7 @@ fn type_to_variable<'a>(
register_with_known_var(subs, destination, rank, pools, content) register_with_known_var(subs, destination, rank, pools, content)
} }
RecursiveTagUnion(rec_var, tags) => { RecursiveTagUnion(rec_var, tags, ext_openness) => {
let ext_slice = types.get_type_arguments(typ_index); let ext_slice = types.get_type_arguments(typ_index);
// An empty tags is inefficient (but would be correct) // An empty tags is inefficient (but would be correct)
@ -2709,7 +2724,15 @@ fn type_to_variable<'a>(
debug_assert!(!tags.is_empty() || !ext_slice.is_empty()); debug_assert!(!tags.is_empty() || !ext_slice.is_empty());
let (union_tags, ext) = type_to_union_tags( let (union_tags, ext) = type_to_union_tags(
subs, rank, pools, arena, types, tags, ext_slice, &mut stack, subs,
rank,
pools,
arena,
types,
tags,
ext_slice,
ext_openness,
&mut stack,
); );
let content = let content =
Content::Structure(FlatType::RecursiveTagUnion(rec_var, union_tags, ext)); Content::Structure(FlatType::RecursiveTagUnion(rec_var, union_tags, ext));
@ -3076,7 +3099,7 @@ fn roc_result_to_var(
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>, stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
) -> Variable { ) -> Variable {
match types[result_type] { match types[result_type] {
TypeTag::TagUnion(tags) => { TypeTag::TagUnion(tags, _ext_openness) => {
let ext_slice = types.get_type_arguments(result_type); let ext_slice = types.get_type_arguments(result_type);
debug_assert!(ext_slice.is_empty()); debug_assert!(ext_slice.is_empty());
@ -3385,6 +3408,7 @@ fn type_to_union_tags(
types: &mut Types, types: &mut Types,
union_tags: UnionTags, union_tags: UnionTags,
opt_ext_slice: Slice<TypeTag>, opt_ext_slice: Slice<TypeTag>,
ext_openness: IsImplicitOpennessVar,
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>, stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
) -> (UnionTags, TagExt) { ) -> (UnionTags, TagExt) {
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
@ -3411,14 +3435,18 @@ fn type_to_union_tags(
Some(ext) => { Some(ext) => {
let mut tag_vars = Vec::with_capacity_in(tags.len(), arena); let mut tag_vars = Vec::with_capacity_in(tags.len(), arena);
let temp_ext_var = let temp_ext = {
RegisterVariable::with_stack(subs, rank, pools, arena, types, ext, stack); let temp_ext_var =
let (it, ext) = roc_types::types::gather_tags_unsorted_iter( RegisterVariable::with_stack(subs, rank, pools, arena, types, ext, stack);
subs, if ext_openness.0 {
UnionTags::default(), TagExt::Openness(temp_ext_var)
TagExt::Any(temp_ext_var), } else {
) TagExt::Any(temp_ext_var)
.expect("extension var could not be seen as tag union"); }
};
let (it, ext) =
roc_types::types::gather_tags_unsorted_iter(subs, UnionTags::default(), temp_ext)
.expect("extension var could not be seen as tag union");
tag_vars.extend(it.map(|(n, v)| (n.clone(), v))); tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));

View file

@ -397,7 +397,7 @@ pub enum TypeTag {
}, },
// type extension is implicit // type extension is implicit
// tag name is in the `single_tag_union_tag_names` map // tag name is in the `single_tag_union_tag_names` map
FunctionOrTagUnion(Symbol), FunctionOrTagUnion(Symbol, IsImplicitOpennessVar),
UnspecializedLambdaSet { UnspecializedLambdaSet {
unspecialized: Uls, unspecialized: Uls,
}, },
@ -431,9 +431,10 @@ pub enum TypeTag {
Error, Error,
// TypeExtension is implicit in the type slice // TypeExtension is implicit in the type slice
// it is length zero for closed, length 1 for open // it is length zero for closed, length 1 for existing
TagUnion(UnionTags), // if not closed, IsImplicitOpennessVar is whether the extension is an Openness variable
RecursiveTagUnion(Variable, UnionTags), TagUnion(UnionTags, IsImplicitOpennessVar),
RecursiveTagUnion(Variable, UnionTags, IsImplicitOpennessVar),
Record(RecordFields), Record(RecordFields),
} }
@ -664,7 +665,7 @@ impl Types {
}; };
let type_slice = match extension { let type_slice = match extension {
TypeExtension::Open(ext) => self.from_old_type(ext).as_slice(), TypeExtension::Open(ext, _) => self.from_old_type(ext).as_slice(),
TypeExtension::Closed => Slice::default(), TypeExtension::Closed => Slice::default(),
}; };
@ -784,24 +785,32 @@ impl Types {
Type::TagUnion(tags, extension) => { Type::TagUnion(tags, extension) => {
let (union_tags, type_slice) = self.tag_union_help(tags, extension); let (union_tags, type_slice) = self.tag_union_help(tags, extension);
self.set_type_tag(index, TypeTag::TagUnion(union_tags), type_slice) self.set_type_tag(
index,
TypeTag::TagUnion(union_tags, extension.is_implicit_openness()),
type_slice,
)
} }
Type::RecursiveTagUnion(rec_var, tags, extension) => { Type::RecursiveTagUnion(rec_var, tags, extension) => {
let (union_tags, type_slice) = self.tag_union_help(tags, extension); let (union_tags, type_slice) = self.tag_union_help(tags, extension);
let tag = TypeTag::RecursiveTagUnion(*rec_var, union_tags); let tag = TypeTag::RecursiveTagUnion(
*rec_var,
union_tags,
extension.is_implicit_openness(),
);
self.set_type_tag(index, tag, type_slice) self.set_type_tag(index, tag, type_slice)
} }
Type::FunctionOrTagUnion(tag_name, symbol, extension) => { Type::FunctionOrTagUnion(tag_name, symbol, extension) => {
let type_slice = match extension { let type_slice = match extension {
TypeExtension::Open(ext) => self.from_old_type(ext).as_slice(), TypeExtension::Open(ext, _) => self.from_old_type(ext).as_slice(),
TypeExtension::Closed => Slice::default(), TypeExtension::Closed => Slice::default(),
}; };
self.single_tag_union_tag_names self.single_tag_union_tag_names
.insert(index, tag_name.clone()); .insert(index, tag_name.clone());
let tag = TypeTag::FunctionOrTagUnion(*symbol); let tag = TypeTag::FunctionOrTagUnion(*symbol, extension.is_implicit_openness());
self.set_type_tag(index, tag, type_slice) self.set_type_tag(index, tag, type_slice)
} }
Type::UnspecializedLambdaSet { unspecialized } => { Type::UnspecializedLambdaSet { unspecialized } => {
@ -812,7 +821,7 @@ impl Types {
} }
Type::Record(fields, extension) => { Type::Record(fields, extension) => {
let type_slice = match extension { let type_slice = match extension {
TypeExtension::Open(ext) => self.from_old_type(ext).as_slice(), TypeExtension::Open(ext, _) => self.from_old_type(ext).as_slice(),
TypeExtension::Closed => Slice::default(), TypeExtension::Closed => Slice::default(),
}; };
@ -1116,14 +1125,14 @@ impl Types {
new_captures, new_captures,
) )
} }
FunctionOrTagUnion(symbol) => { FunctionOrTagUnion(symbol, ext_openness) => {
let ext = self.get_type_arguments(typ); let ext = self.get_type_arguments(typ);
let new_ext = defer_slice!(ext); let new_ext = defer_slice!(ext);
self.single_tag_union_tag_names self.single_tag_union_tag_names
.insert(dest_index, self.get_tag_name(&typ).clone()); .insert(dest_index, self.get_tag_name(&typ).clone());
(FunctionOrTagUnion(symbol), new_ext) (FunctionOrTagUnion(symbol, ext_openness), new_ext)
} }
UnspecializedLambdaSet { UnspecializedLambdaSet {
unspecialized: Uls(var, sym, region), unspecialized: Uls(var, sym, region),
@ -1214,15 +1223,15 @@ impl Types {
new_type_arguments, new_type_arguments,
) )
} }
TagUnion(union_tags) => { TagUnion(union_tags, ext_openness) => {
let ext_slice = self.get_type_arguments(typ); let ext_slice = self.get_type_arguments(typ);
let new_ext_slice = defer_slice!(ext_slice); let new_ext_slice = defer_slice!(ext_slice);
let new_union_tags = do_union_tags!(union_tags); let new_union_tags = do_union_tags!(union_tags);
(TagUnion(new_union_tags), new_ext_slice) (TagUnion(new_union_tags, ext_openness), new_ext_slice)
} }
RecursiveTagUnion(rec_var, union_tags) => { RecursiveTagUnion(rec_var, union_tags, ext_openness) => {
let ext_slice = self.get_type_arguments(typ); let ext_slice = self.get_type_arguments(typ);
let new_rec_var = subst!(rec_var); let new_rec_var = subst!(rec_var);
@ -1230,7 +1239,7 @@ impl Types {
let new_union_tags = do_union_tags!(union_tags); let new_union_tags = do_union_tags!(union_tags);
( (
RecursiveTagUnion(new_rec_var, new_union_tags), RecursiveTagUnion(new_rec_var, new_union_tags, ext_openness),
new_ext_slice, new_ext_slice,
) )
} }
@ -1351,7 +1360,7 @@ mod debug_types {
.append(f.text(format!(", ^{ambient_function:?}"))) .append(f.text(format!(", ^{ambient_function:?}")))
.append(f.text("]")) .append(f.text("]"))
} }
TypeTag::FunctionOrTagUnion(_) => { TypeTag::FunctionOrTagUnion(_, _) => {
let tag_name = types.get_tag_name(&tag); let tag_name = types.get_tag_name(&tag);
f.text(tag_name.0.as_str()) f.text(tag_name.0.as_str())
} }
@ -1400,10 +1409,10 @@ mod debug_types {
TypeTag::Variable(var) => f.text(format!("{var:?}")), TypeTag::Variable(var) => f.text(format!("{var:?}")),
TypeTag::RangedNumber(range) => ranged(f, range), TypeTag::RangedNumber(range) => ranged(f, range),
TypeTag::Error => f.text("ERROR"), TypeTag::Error => f.text("ERROR"),
TypeTag::TagUnion(tags) => { TypeTag::TagUnion(tags, _) => {
tag_union(types, f, f.nil(), tags, types.get_type_arguments(tag)) tag_union(types, f, f.nil(), tags, types.get_type_arguments(tag))
} }
TypeTag::RecursiveTagUnion(rec, tags) => tag_union( TypeTag::RecursiveTagUnion(rec, tags, _) => tag_union(
types, types,
f, f,
f.text(format!("<rec {rec:?}>")), f.text(format!("<rec {rec:?}>")),
@ -1784,25 +1793,45 @@ impl Clone for OptAbleType {
} }
} }
/// `true` if an extension variable is inferred-open-in-output-position, and should be treated as a
/// marker of openness-polymorphism - it can only be inferred to be polymorphic in size, or closed,
/// but can't grow more monomorphic tags.
/// E.g. `[]_a` can unify with `[]` or `[]*` but not `[A, B]`.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct IsImplicitOpennessVar(pub bool);
impl IsImplicitOpennessVar {
pub const YES: Self = Self(true);
pub const NO: Self = Self(false);
}
#[derive(PartialEq, Eq, Clone)] #[derive(PartialEq, Eq, Clone)]
pub enum TypeExtension { pub enum TypeExtension {
Open(Box<Type>), Open(Box<Type>, IsImplicitOpennessVar),
Closed, Closed,
} }
impl TypeExtension { impl TypeExtension {
#[inline(always)] #[inline(always)]
pub fn from_type(typ: Type) -> Self { pub fn from_type(typ: Type, is_implicit_openness: IsImplicitOpennessVar) -> Self {
match typ { match typ {
Type::EmptyTagUnion | Type::EmptyRec => Self::Closed, Type::EmptyTagUnion | Type::EmptyRec => Self::Closed,
_ => Self::Open(Box::new(typ)), _ => Self::Open(Box::new(typ), is_implicit_openness),
}
}
#[inline(always)]
pub fn from_non_annotation_type(typ: Type) -> Self {
match typ {
Type::EmptyTagUnion | Type::EmptyRec => Self::Closed,
_ => Self::Open(Box::new(typ), IsImplicitOpennessVar::NO),
} }
} }
#[inline(always)] #[inline(always)]
pub fn is_closed(&self) -> bool { pub fn is_closed(&self) -> bool {
match self { match self {
TypeExtension::Open(_) => false, TypeExtension::Open(..) => false,
TypeExtension::Closed => true, TypeExtension::Closed => true,
} }
} }
@ -1810,10 +1839,18 @@ impl TypeExtension {
#[inline(always)] #[inline(always)]
fn iter_mut(&mut self) -> impl Iterator<Item = &mut Type> { fn iter_mut(&mut self) -> impl Iterator<Item = &mut Type> {
match self { match self {
TypeExtension::Open(ext) => Some(ext.as_mut()).into_iter(), TypeExtension::Open(ext, _) => Some(ext.as_mut()).into_iter(),
TypeExtension::Closed => None.into_iter(), TypeExtension::Closed => None.into_iter(),
} }
} }
#[inline(always)]
fn is_implicit_openness(&self) -> IsImplicitOpennessVar {
match self {
TypeExtension::Open(_, is_implicit_openness) => *is_implicit_openness,
TypeExtension::Closed => IsImplicitOpennessVar::NO,
}
}
} }
impl<'a> IntoIterator for &'a TypeExtension { impl<'a> IntoIterator for &'a TypeExtension {
@ -1823,7 +1860,7 @@ impl<'a> IntoIterator for &'a TypeExtension {
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
match self { match self {
TypeExtension::Open(ext) => Some(ext.as_ref()).into_iter(), TypeExtension::Open(ext, _) => Some(ext.as_ref()).into_iter(),
TypeExtension::Closed => None.into_iter(), TypeExtension::Closed => None.into_iter(),
} }
} }
@ -1997,7 +2034,7 @@ impl fmt::Debug for Type {
// This is a closed record. We're done! // This is a closed record. We're done!
Ok(()) Ok(())
} }
TypeExtension::Open(other) => { TypeExtension::Open(other, _) => {
// This is an open record, so print the variable // This is an open record, so print the variable
// right after the '}' // right after the '}'
// //
@ -2015,7 +2052,7 @@ impl fmt::Debug for Type {
// This is a closed variant. We're done! // This is a closed variant. We're done!
Ok(()) Ok(())
} }
TypeExtension::Open(other) => { TypeExtension::Open(other, _) => {
// This is an open tag union, so print the variable // This is an open tag union, so print the variable
// right after the ']' // right after the ']'
// //
@ -2035,7 +2072,7 @@ impl fmt::Debug for Type {
// This is a closed variant. We're done! // This is a closed variant. We're done!
Ok(()) Ok(())
} }
TypeExtension::Open(other) => { TypeExtension::Open(other, _) => {
// This is an open tag union, so print the variable // This is an open tag union, so print the variable
// right after the ']' // right after the ']'
// //
@ -2067,7 +2104,7 @@ impl fmt::Debug for Type {
// This is a closed variant. We're done! // This is a closed variant. We're done!
Ok(()) Ok(())
} }
TypeExtension::Open(other) => { TypeExtension::Open(other, _) => {
// This is an open tag union, so print the variable // This is an open tag union, so print the variable
// right after the ']' // right after the ']'
// //
@ -2150,12 +2187,12 @@ impl Type {
stack.extend(args.iter_mut()); stack.extend(args.iter_mut());
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
stack.push(ext); stack.push(ext);
} }
} }
FunctionOrTagUnion(_, _, ext) => { FunctionOrTagUnion(_, _, ext) => {
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
stack.push(ext); stack.push(ext);
} }
} }
@ -2164,7 +2201,7 @@ impl Type {
stack.extend(args.iter_mut()); stack.extend(args.iter_mut());
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
stack.push(ext); stack.push(ext);
} }
} }
@ -2173,7 +2210,7 @@ impl Type {
stack.push(x.as_inner_mut()); stack.push(x.as_inner_mut());
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
stack.push(ext); stack.push(ext);
} }
} }
@ -2279,12 +2316,12 @@ impl Type {
stack.extend(args.iter_mut()); stack.extend(args.iter_mut());
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
stack.push(ext); stack.push(ext);
} }
} }
FunctionOrTagUnion(_, _, ext) => { FunctionOrTagUnion(_, _, ext) => {
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
stack.push(ext); stack.push(ext);
} }
} }
@ -2297,7 +2334,7 @@ impl Type {
stack.extend(args.iter_mut()); stack.extend(args.iter_mut());
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
stack.push(ext); stack.push(ext);
} }
} }
@ -2305,7 +2342,7 @@ impl Type {
for (_, x) in fields.iter_mut() { for (_, x) in fields.iter_mut() {
stack.push(x.as_inner_mut()); stack.push(x.as_inner_mut());
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
stack.push(ext); stack.push(ext);
} }
} }
@ -2399,7 +2436,7 @@ impl Type {
ret.substitute_alias(rep_symbol, rep_args, actual) ret.substitute_alias(rep_symbol, rep_args, actual)
} }
FunctionOrTagUnion(_, _, ext) => match ext { FunctionOrTagUnion(_, _, ext) => match ext {
TypeExtension::Open(ext) => ext.substitute_alias(rep_symbol, rep_args, actual), TypeExtension::Open(ext, _) => ext.substitute_alias(rep_symbol, rep_args, actual),
TypeExtension::Closed => Ok(()), TypeExtension::Closed => Ok(()),
}, },
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => { RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
@ -2410,7 +2447,9 @@ impl Type {
} }
match ext { match ext {
TypeExtension::Open(ext) => ext.substitute_alias(rep_symbol, rep_args, actual), TypeExtension::Open(ext, _) => {
ext.substitute_alias(rep_symbol, rep_args, actual)
}
TypeExtension::Closed => Ok(()), TypeExtension::Closed => Ok(()),
} }
} }
@ -2420,7 +2459,9 @@ impl Type {
} }
match ext { match ext {
TypeExtension::Open(ext) => ext.substitute_alias(rep_symbol, rep_args, actual), TypeExtension::Open(ext, _) => {
ext.substitute_alias(rep_symbol, rep_args, actual)
}
TypeExtension::Closed => Ok(()), TypeExtension::Closed => Ok(()),
} }
} }
@ -2484,7 +2525,7 @@ impl Type {
fn contains_symbol_ext(ext: &TypeExtension, rep_symbol: Symbol) -> bool { fn contains_symbol_ext(ext: &TypeExtension, rep_symbol: Symbol) -> bool {
match ext { match ext {
TypeExtension::Open(ext) => ext.contains_symbol(rep_symbol), TypeExtension::Open(ext, _) => ext.contains_symbol(rep_symbol),
TypeExtension::Closed => false, TypeExtension::Closed => false,
} }
} }
@ -2546,7 +2587,7 @@ impl Type {
fn contains_variable_ext(ext: &TypeExtension, rep_variable: Variable) -> bool { fn contains_variable_ext(ext: &TypeExtension, rep_variable: Variable) -> bool {
match ext { match ext {
TypeExtension::Open(ext) => ext.contains_variable(rep_variable), TypeExtension::Open(ext, _) => ext.contains_variable(rep_variable),
TypeExtension::Closed => false, TypeExtension::Closed => false,
} }
} }
@ -2665,7 +2706,7 @@ impl Type {
); );
} }
FunctionOrTagUnion(_, _, ext) => { FunctionOrTagUnion(_, _, ext) => {
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
ext.instantiate_aliases( ext.instantiate_aliases(
region, region,
aliases, aliases,
@ -2688,7 +2729,7 @@ impl Type {
} }
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
ext.instantiate_aliases( ext.instantiate_aliases(
region, region,
aliases, aliases,
@ -2709,7 +2750,7 @@ impl Type {
); );
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
ext.instantiate_aliases( ext.instantiate_aliases(
region, region,
aliases, aliases,
@ -2938,7 +2979,7 @@ impl Type {
typ.substitute(&substitution); typ.substitute(&substitution);
} }
if let TypeExtension::Open(ext) = &mut ext { if let TypeExtension::Open(ext, _) = &mut ext {
ext.substitute(&substitution); ext.substitute(&substitution);
} }
@ -3020,7 +3061,7 @@ impl Type {
tags.len() == 1 && tags[0].1.len() == 1 && tags[0].1[0].is_narrow() tags.len() == 1 && tags[0].1.len() == 1 && tags[0].1[0].is_narrow()
} }
Type::Record(fields, ext) => match ext { Type::Record(fields, ext) => match ext {
TypeExtension::Open(ext) => { TypeExtension::Open(ext, _) => {
fields.values().all(|field| field.as_inner().is_narrow()) && ext.is_narrow() fields.values().all(|field| field.as_inner().is_narrow()) && ext.is_narrow()
} }
TypeExtension::Closed => fields.values().all(|field| field.as_inner().is_narrow()), TypeExtension::Closed => fields.values().all(|field| field.as_inner().is_narrow()),
@ -3138,7 +3179,7 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
variables_help(field.as_inner(), accum); variables_help(field.as_inner(), accum);
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
variables_help(ext, accum); variables_help(ext, accum);
} }
} }
@ -3163,12 +3204,12 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
} }
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
variables_help(ext, accum); variables_help(ext, accum);
} }
} }
FunctionOrTagUnion(_, _, ext) => { FunctionOrTagUnion(_, _, ext) => {
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
variables_help(ext, accum); variables_help(ext, accum);
} }
} }
@ -3179,7 +3220,7 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
} }
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
variables_help(ext, accum); variables_help(ext, accum);
} }
@ -3273,7 +3314,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
variables_help_detailed(field.as_inner(), accum); variables_help_detailed(field.as_inner(), accum);
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
variables_help_detailed(ext, accum); variables_help_detailed(ext, accum);
} }
} }
@ -3293,12 +3334,12 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
} }
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
variables_help_detailed(ext, accum); variables_help_detailed(ext, accum);
} }
} }
FunctionOrTagUnion(_, _, ext) => { FunctionOrTagUnion(_, _, ext) => {
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
variables_help_detailed(ext, accum); variables_help_detailed(ext, accum);
} }
} }
@ -3314,7 +3355,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
} }
} }
if let TypeExtension::Open(ext) = ext { if let TypeExtension::Open(ext, _) = ext {
variables_help_detailed(ext, accum); variables_help_detailed(ext, accum);
} }