mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +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_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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
};
|
};
|
||||||
|
|
|
@ -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)
|
||||||
};
|
};
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue