mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 04:08:19 +00:00
Push implicit openness vars through
This commit is contained in:
parent
96b2b7a0c5
commit
5fceb9ceb7
5 changed files with 190 additions and 95 deletions
|
@ -9,8 +9,8 @@ use roc_problem::can::ShadowKind;
|
|||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
use roc_types::types::{
|
||||
name_type_var, AbilitySet, Alias, AliasCommon, AliasKind, AliasVar, LambdaSet, OptAbleType,
|
||||
OptAbleVar, RecordField, Type, TypeExtension,
|
||||
name_type_var, AbilitySet, Alias, AliasCommon, AliasKind, AliasVar, IsImplicitOpennessVar,
|
||||
LambdaSet, OptAbleType, OptAbleVar, RecordField, Type, TypeExtension,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -876,7 +876,7 @@ fn can_annotation_help(
|
|||
todo!("tuple");
|
||||
}
|
||||
Record { fields, ext } => {
|
||||
let ext_type = can_extension_type(
|
||||
let (ext_type, is_implicit_openness) = can_extension_type(
|
||||
env,
|
||||
pol,
|
||||
scope,
|
||||
|
@ -888,13 +888,21 @@ fn can_annotation_help(
|
|||
roc_problem::can::ExtensionTypeKind::Record,
|
||||
);
|
||||
|
||||
debug_assert!(
|
||||
!is_implicit_openness.0,
|
||||
"records should never be implicitly inferred open"
|
||||
);
|
||||
|
||||
if fields.is_empty() {
|
||||
match ext {
|
||||
Some(_) => {
|
||||
// just `a` does not mean the same as `{}a`, so even
|
||||
// if there are no fields, still make this a `Record`,
|
||||
// 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,
|
||||
|
@ -912,11 +920,14 @@ fn can_annotation_help(
|
|||
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, .. } => {
|
||||
let ext_type = can_extension_type(
|
||||
let (ext_type, is_implicit_openness) = can_extension_type(
|
||||
env,
|
||||
pol,
|
||||
scope,
|
||||
|
@ -934,7 +945,10 @@ fn can_annotation_help(
|
|||
// just `a` does not mean the same as `[]`, so even
|
||||
// if there are no fields, still make this a `TagUnion`,
|
||||
// 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,
|
||||
|
@ -957,7 +971,10 @@ fn can_annotation_help(
|
|||
// 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));
|
||||
|
||||
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(
|
||||
|
@ -1094,7 +1111,7 @@ fn can_extension_type<'a>(
|
|||
references: &mut VecSet<Symbol>,
|
||||
opt_ext: &Option<&Loc<TypeAnnotation<'a>>>,
|
||||
ext_problem_kind: roc_problem::can::ExtensionTypeKind,
|
||||
) -> Type {
|
||||
) -> (Type, IsImplicitOpennessVar) {
|
||||
fn valid_record_ext_type(typ: &Type) -> bool {
|
||||
// Include erroneous types so that we don't overreport errors.
|
||||
matches!(
|
||||
|
@ -1141,7 +1158,7 @@ fn can_extension_type<'a>(
|
|||
})
|
||||
}
|
||||
|
||||
ext_type
|
||||
(ext_type, IsImplicitOpennessVar::NO)
|
||||
} else {
|
||||
// Report an error but mark the extension variable to be inferred
|
||||
// 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));
|
||||
|
||||
Type::Variable(var)
|
||||
(
|
||||
Type::Variable(var),
|
||||
// Since this is an error anyway, just be permissive
|
||||
IsImplicitOpennessVar::NO,
|
||||
)
|
||||
}
|
||||
}
|
||||
None => match ext_problem_kind {
|
||||
ExtensionTypeKind::Record => Type::EmptyRec,
|
||||
ExtensionTypeKind::Record => (Type::EmptyRec, IsImplicitOpennessVar::NO),
|
||||
ExtensionTypeKind::TagUnion => {
|
||||
// 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.
|
||||
match pol {
|
||||
CanPolarity::Neg | CanPolarity::InOpaque => Type::EmptyTagUnion,
|
||||
CanPolarity::Neg | CanPolarity::InOpaque => {
|
||||
(Type::EmptyTagUnion, IsImplicitOpennessVar::NO)
|
||||
}
|
||||
CanPolarity::Pos | CanPolarity::InAlias => {
|
||||
let var = var_store.fresh();
|
||||
introduced_variables.insert_infer_ext_in_output(var);
|
||||
|
||||
Type::Variable(var)
|
||||
(Type::Variable(var), IsImplicitOpennessVar::YES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -279,7 +279,7 @@ pub fn constrain_expr(
|
|||
let fields_type = {
|
||||
let typ = types.from_old_type(&Type::Record(
|
||||
fields,
|
||||
TypeExtension::from_type(Type::Variable(*ext_var)),
|
||||
TypeExtension::from_non_annotation_type(Type::Variable(*ext_var)),
|
||||
));
|
||||
constraints.push_type(types, typ)
|
||||
};
|
||||
|
@ -1090,7 +1090,7 @@ pub fn constrain_expr(
|
|||
let record_type = {
|
||||
let typ = types.from_old_type(&Type::Record(
|
||||
rec_field_types,
|
||||
TypeExtension::from_type(ext_type),
|
||||
TypeExtension::from_non_annotation_type(ext_type),
|
||||
));
|
||||
constraints.push_type(types, typ)
|
||||
};
|
||||
|
@ -1134,7 +1134,10 @@ pub fn constrain_expr(
|
|||
let mut field_types = SendMap::default();
|
||||
let label = field.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 typ = types.from_old_type(&record_type);
|
||||
constraints.push_type(types, typ)
|
||||
|
@ -1267,7 +1270,7 @@ pub fn constrain_expr(
|
|||
let tag_union_type = {
|
||||
let typ = types.from_old_type(&Type::TagUnion(
|
||||
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)
|
||||
};
|
||||
|
@ -1299,7 +1302,7 @@ pub fn constrain_expr(
|
|||
let typ = types.from_old_type(&Type::FunctionOrTagUnion(
|
||||
name.clone(),
|
||||
*closure_name,
|
||||
TypeExtension::from_type(Type::Variable(*ext_var)),
|
||||
TypeExtension::from_non_annotation_type(Type::Variable(*ext_var)),
|
||||
));
|
||||
constraints.push_type(types, typ)
|
||||
};
|
||||
|
|
|
@ -578,7 +578,7 @@ pub fn constrain_pattern(
|
|||
let record_type = {
|
||||
let typ = types.from_old_type(&Type::Record(
|
||||
field_types,
|
||||
TypeExtension::from_type(ext_type),
|
||||
TypeExtension::from_non_annotation_type(ext_type),
|
||||
));
|
||||
constraints.push_type(types, typ)
|
||||
};
|
||||
|
|
|
@ -33,8 +33,8 @@ use roc_types::subs::{
|
|||
UnionTags, Variable, VariableSubsSlice,
|
||||
};
|
||||
use roc_types::types::{
|
||||
gather_fields_unsorted_iter, AliasKind, AliasShared, Category, OptAbleVar, Polarity, Reason,
|
||||
RecordField, Type, TypeExtension, TypeTag, Types, Uls,
|
||||
gather_fields_unsorted_iter, AliasKind, AliasShared, Category, IsImplicitOpennessVar,
|
||||
OptAbleVar, Polarity, Reason, RecordField, Type, TypeExtension, TypeTag, Types, Uls,
|
||||
};
|
||||
use roc_unify::unify::{
|
||||
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)
|
||||
}
|
||||
|
||||
TagUnion(tags) => {
|
||||
TagUnion(tags, ext_openness) => {
|
||||
let ext_slice = types.get_type_arguments(typ_index);
|
||||
|
||||
// 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());
|
||||
|
||||
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));
|
||||
|
||||
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 tag_name = types.get_tag_name(&typ_index).clone();
|
||||
|
||||
debug_assert!(ext_slice.len() <= 1);
|
||||
let temp_ext_var = match ext_slice.into_iter().next() {
|
||||
Some(ext) => helper!(ext),
|
||||
None => roc_types::subs::Variable::EMPTY_TAG_UNION,
|
||||
let temp_ext = match ext_slice.into_iter().next() {
|
||||
Some(ext) => {
|
||||
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(
|
||||
subs,
|
||||
UnionTags::default(),
|
||||
TagExt::Any(temp_ext_var),
|
||||
temp_ext,
|
||||
)
|
||||
.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)
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags) => {
|
||||
RecursiveTagUnion(rec_var, tags, ext_openness) => {
|
||||
let ext_slice = types.get_type_arguments(typ_index);
|
||||
|
||||
// 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());
|
||||
|
||||
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::RecursiveTagUnion(rec_var, union_tags, ext));
|
||||
|
@ -3076,7 +3099,7 @@ fn roc_result_to_var(
|
|||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> Variable {
|
||||
match types[result_type] {
|
||||
TypeTag::TagUnion(tags) => {
|
||||
TypeTag::TagUnion(tags, _ext_openness) => {
|
||||
let ext_slice = types.get_type_arguments(result_type);
|
||||
|
||||
debug_assert!(ext_slice.is_empty());
|
||||
|
@ -3385,6 +3408,7 @@ fn type_to_union_tags(
|
|||
types: &mut Types,
|
||||
union_tags: UnionTags,
|
||||
opt_ext_slice: Slice<TypeTag>,
|
||||
ext_openness: IsImplicitOpennessVar,
|
||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||
) -> (UnionTags, TagExt) {
|
||||
use bumpalo::collections::Vec;
|
||||
|
@ -3411,14 +3435,18 @@ fn type_to_union_tags(
|
|||
Some(ext) => {
|
||||
let mut tag_vars = Vec::with_capacity_in(tags.len(), arena);
|
||||
|
||||
let temp_ext_var =
|
||||
RegisterVariable::with_stack(subs, rank, pools, arena, types, ext, stack);
|
||||
let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
|
||||
subs,
|
||||
UnionTags::default(),
|
||||
TagExt::Any(temp_ext_var),
|
||||
)
|
||||
.expect("extension var could not be seen as tag union");
|
||||
let temp_ext = {
|
||||
let temp_ext_var =
|
||||
RegisterVariable::with_stack(subs, rank, pools, arena, types, ext, stack);
|
||||
if ext_openness.0 {
|
||||
TagExt::Openness(temp_ext_var)
|
||||
} else {
|
||||
TagExt::Any(temp_ext_var)
|
||||
}
|
||||
};
|
||||
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)));
|
||||
|
||||
|
|
|
@ -397,7 +397,7 @@ pub enum TypeTag {
|
|||
},
|
||||
// type extension is implicit
|
||||
// tag name is in the `single_tag_union_tag_names` map
|
||||
FunctionOrTagUnion(Symbol),
|
||||
FunctionOrTagUnion(Symbol, IsImplicitOpennessVar),
|
||||
UnspecializedLambdaSet {
|
||||
unspecialized: Uls,
|
||||
},
|
||||
|
@ -431,9 +431,10 @@ pub enum TypeTag {
|
|||
Error,
|
||||
|
||||
// TypeExtension is implicit in the type slice
|
||||
// it is length zero for closed, length 1 for open
|
||||
TagUnion(UnionTags),
|
||||
RecursiveTagUnion(Variable, UnionTags),
|
||||
// it is length zero for closed, length 1 for existing
|
||||
// if not closed, IsImplicitOpennessVar is whether the extension is an Openness variable
|
||||
TagUnion(UnionTags, IsImplicitOpennessVar),
|
||||
RecursiveTagUnion(Variable, UnionTags, IsImplicitOpennessVar),
|
||||
Record(RecordFields),
|
||||
}
|
||||
|
||||
|
@ -664,7 +665,7 @@ impl Types {
|
|||
};
|
||||
|
||||
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(),
|
||||
};
|
||||
|
||||
|
@ -784,24 +785,32 @@ impl Types {
|
|||
Type::TagUnion(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) => {
|
||||
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)
|
||||
}
|
||||
Type::FunctionOrTagUnion(tag_name, symbol, 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(),
|
||||
};
|
||||
|
||||
self.single_tag_union_tag_names
|
||||
.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)
|
||||
}
|
||||
Type::UnspecializedLambdaSet { unspecialized } => {
|
||||
|
@ -812,7 +821,7 @@ impl Types {
|
|||
}
|
||||
Type::Record(fields, 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(),
|
||||
};
|
||||
|
||||
|
@ -1116,14 +1125,14 @@ impl Types {
|
|||
new_captures,
|
||||
)
|
||||
}
|
||||
FunctionOrTagUnion(symbol) => {
|
||||
FunctionOrTagUnion(symbol, ext_openness) => {
|
||||
let ext = self.get_type_arguments(typ);
|
||||
|
||||
let new_ext = defer_slice!(ext);
|
||||
self.single_tag_union_tag_names
|
||||
.insert(dest_index, self.get_tag_name(&typ).clone());
|
||||
|
||||
(FunctionOrTagUnion(symbol), new_ext)
|
||||
(FunctionOrTagUnion(symbol, ext_openness), new_ext)
|
||||
}
|
||||
UnspecializedLambdaSet {
|
||||
unspecialized: Uls(var, sym, region),
|
||||
|
@ -1214,15 +1223,15 @@ impl Types {
|
|||
new_type_arguments,
|
||||
)
|
||||
}
|
||||
TagUnion(union_tags) => {
|
||||
TagUnion(union_tags, ext_openness) => {
|
||||
let ext_slice = self.get_type_arguments(typ);
|
||||
|
||||
let new_ext_slice = defer_slice!(ext_slice);
|
||||
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 new_rec_var = subst!(rec_var);
|
||||
|
@ -1230,7 +1239,7 @@ impl Types {
|
|||
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,
|
||||
)
|
||||
}
|
||||
|
@ -1351,7 +1360,7 @@ mod debug_types {
|
|||
.append(f.text(format!(", ^{ambient_function:?}")))
|
||||
.append(f.text("]"))
|
||||
}
|
||||
TypeTag::FunctionOrTagUnion(_) => {
|
||||
TypeTag::FunctionOrTagUnion(_, _) => {
|
||||
let tag_name = types.get_tag_name(&tag);
|
||||
f.text(tag_name.0.as_str())
|
||||
}
|
||||
|
@ -1400,10 +1409,10 @@ mod debug_types {
|
|||
TypeTag::Variable(var) => f.text(format!("{var:?}")),
|
||||
TypeTag::RangedNumber(range) => ranged(f, range),
|
||||
TypeTag::Error => f.text("ERROR"),
|
||||
TypeTag::TagUnion(tags) => {
|
||||
TypeTag::TagUnion(tags, _) => {
|
||||
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,
|
||||
f,
|
||||
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)]
|
||||
pub enum TypeExtension {
|
||||
Open(Box<Type>),
|
||||
Open(Box<Type>, IsImplicitOpennessVar),
|
||||
Closed,
|
||||
}
|
||||
|
||||
impl TypeExtension {
|
||||
#[inline(always)]
|
||||
pub fn from_type(typ: Type) -> Self {
|
||||
pub fn from_type(typ: Type, is_implicit_openness: IsImplicitOpennessVar) -> Self {
|
||||
match typ {
|
||||
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)]
|
||||
pub fn is_closed(&self) -> bool {
|
||||
match self {
|
||||
TypeExtension::Open(_) => false,
|
||||
TypeExtension::Open(..) => false,
|
||||
TypeExtension::Closed => true,
|
||||
}
|
||||
}
|
||||
|
@ -1810,10 +1839,18 @@ impl TypeExtension {
|
|||
#[inline(always)]
|
||||
fn iter_mut(&mut self) -> impl Iterator<Item = &mut Type> {
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
|
@ -1823,7 +1860,7 @@ impl<'a> IntoIterator for &'a TypeExtension {
|
|||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
@ -1997,7 +2034,7 @@ impl fmt::Debug for Type {
|
|||
// This is a closed record. We're done!
|
||||
Ok(())
|
||||
}
|
||||
TypeExtension::Open(other) => {
|
||||
TypeExtension::Open(other, _) => {
|
||||
// This is an open record, so print the variable
|
||||
// right after the '}'
|
||||
//
|
||||
|
@ -2015,7 +2052,7 @@ impl fmt::Debug for Type {
|
|||
// This is a closed variant. We're done!
|
||||
Ok(())
|
||||
}
|
||||
TypeExtension::Open(other) => {
|
||||
TypeExtension::Open(other, _) => {
|
||||
// This is an open tag union, so print the variable
|
||||
// right after the ']'
|
||||
//
|
||||
|
@ -2035,7 +2072,7 @@ impl fmt::Debug for Type {
|
|||
// This is a closed variant. We're done!
|
||||
Ok(())
|
||||
}
|
||||
TypeExtension::Open(other) => {
|
||||
TypeExtension::Open(other, _) => {
|
||||
// This is an open tag union, so print the variable
|
||||
// right after the ']'
|
||||
//
|
||||
|
@ -2067,7 +2104,7 @@ impl fmt::Debug for Type {
|
|||
// This is a closed variant. We're done!
|
||||
Ok(())
|
||||
}
|
||||
TypeExtension::Open(other) => {
|
||||
TypeExtension::Open(other, _) => {
|
||||
// This is an open tag union, so print the variable
|
||||
// right after the ']'
|
||||
//
|
||||
|
@ -2150,12 +2187,12 @@ impl Type {
|
|||
stack.extend(args.iter_mut());
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
|
@ -2164,7 +2201,7 @@ impl Type {
|
|||
stack.extend(args.iter_mut());
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
|
@ -2173,7 +2210,7 @@ impl Type {
|
|||
stack.push(x.as_inner_mut());
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
|
@ -2279,12 +2316,12 @@ impl Type {
|
|||
stack.extend(args.iter_mut());
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
|
@ -2297,7 +2334,7 @@ impl Type {
|
|||
stack.extend(args.iter_mut());
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
|
@ -2305,7 +2342,7 @@ impl Type {
|
|||
for (_, x) in fields.iter_mut() {
|
||||
stack.push(x.as_inner_mut());
|
||||
}
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
stack.push(ext);
|
||||
}
|
||||
}
|
||||
|
@ -2399,7 +2436,7 @@ impl Type {
|
|||
ret.substitute_alias(rep_symbol, rep_args, actual)
|
||||
}
|
||||
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(()),
|
||||
},
|
||||
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
|
||||
|
@ -2410,7 +2447,9 @@ impl Type {
|
|||
}
|
||||
|
||||
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(()),
|
||||
}
|
||||
}
|
||||
|
@ -2420,7 +2459,9 @@ impl Type {
|
|||
}
|
||||
|
||||
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(()),
|
||||
}
|
||||
}
|
||||
|
@ -2484,7 +2525,7 @@ impl Type {
|
|||
|
||||
fn contains_symbol_ext(ext: &TypeExtension, rep_symbol: Symbol) -> bool {
|
||||
match ext {
|
||||
TypeExtension::Open(ext) => ext.contains_symbol(rep_symbol),
|
||||
TypeExtension::Open(ext, _) => ext.contains_symbol(rep_symbol),
|
||||
TypeExtension::Closed => false,
|
||||
}
|
||||
}
|
||||
|
@ -2546,7 +2587,7 @@ impl Type {
|
|||
|
||||
fn contains_variable_ext(ext: &TypeExtension, rep_variable: Variable) -> bool {
|
||||
match ext {
|
||||
TypeExtension::Open(ext) => ext.contains_variable(rep_variable),
|
||||
TypeExtension::Open(ext, _) => ext.contains_variable(rep_variable),
|
||||
TypeExtension::Closed => false,
|
||||
}
|
||||
}
|
||||
|
@ -2665,7 +2706,7 @@ impl Type {
|
|||
);
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
ext.instantiate_aliases(
|
||||
region,
|
||||
aliases,
|
||||
|
@ -2688,7 +2729,7 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
ext.instantiate_aliases(
|
||||
region,
|
||||
aliases,
|
||||
|
@ -2709,7 +2750,7 @@ impl Type {
|
|||
);
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
ext.instantiate_aliases(
|
||||
region,
|
||||
aliases,
|
||||
|
@ -2938,7 +2979,7 @@ impl Type {
|
|||
typ.substitute(&substitution);
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = &mut ext {
|
||||
if let TypeExtension::Open(ext, _) = &mut ext {
|
||||
ext.substitute(&substitution);
|
||||
}
|
||||
|
||||
|
@ -3020,7 +3061,7 @@ impl Type {
|
|||
tags.len() == 1 && tags[0].1.len() == 1 && tags[0].1[0].is_narrow()
|
||||
}
|
||||
Type::Record(fields, ext) => match ext {
|
||||
TypeExtension::Open(ext) => {
|
||||
TypeExtension::Open(ext, _) => {
|
||||
fields.values().all(|field| field.as_inner().is_narrow()) && ext.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);
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
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);
|
||||
}
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -3273,7 +3314,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
|
|||
variables_help_detailed(field.as_inner(), accum);
|
||||
}
|
||||
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
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);
|
||||
}
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
if let TypeExtension::Open(ext) = ext {
|
||||
if let TypeExtension::Open(ext, _) = ext {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue