mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
Merge pull request #2838 from rtfeldman/abilities-typechecking
Inference and checking for abilities
This commit is contained in:
commit
4ea4aa4708
46 changed files with 2432 additions and 530 deletions
|
@ -116,7 +116,7 @@ fn find_names_needed(
|
|||
}
|
||||
|
||||
match &subs.get_content_without_compacting(variable).clone() {
|
||||
RecursionVar { opt_name: None, .. } | FlexVar(None) => {
|
||||
RecursionVar { opt_name: None, .. } | FlexVar(None) | FlexAbleVar(None, _) => {
|
||||
let root = subs.get_root_key_without_compacting(variable);
|
||||
|
||||
// If this var is *not* its own root, then the
|
||||
|
@ -139,7 +139,8 @@ fn find_names_needed(
|
|||
opt_name: Some(name_index),
|
||||
..
|
||||
}
|
||||
| FlexVar(Some(name_index)) => {
|
||||
| FlexVar(Some(name_index))
|
||||
| FlexAbleVar(Some(name_index), _) => {
|
||||
// This root already has a name. Nothing more to do here!
|
||||
|
||||
// User-defined names are already taken.
|
||||
|
@ -147,7 +148,7 @@ fn find_names_needed(
|
|||
let name = subs.field_names[name_index.index as usize].clone();
|
||||
names_taken.insert(name);
|
||||
}
|
||||
RigidVar(name_index) => {
|
||||
RigidVar(name_index) | RigidAbleVar(name_index, _) => {
|
||||
// User-defined names are already taken.
|
||||
// We must not accidentally generate names that collide with them!
|
||||
let name = subs.field_names[name_index.index as usize].clone();
|
||||
|
@ -289,6 +290,11 @@ fn set_root_name(root: Variable, name: Lowercase, subs: &mut Subs) {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Context<'a> {
|
||||
able_variables: Vec<(&'a str, Symbol)>,
|
||||
}
|
||||
|
||||
pub fn content_to_string(
|
||||
content: &Content,
|
||||
subs: &Subs,
|
||||
|
@ -297,8 +303,16 @@ pub fn content_to_string(
|
|||
) -> String {
|
||||
let mut buf = String::new();
|
||||
let env = Env { home, interns };
|
||||
let mut ctx = Context::default();
|
||||
|
||||
write_content(&env, content, subs, &mut buf, Parens::Unnecessary);
|
||||
write_content(&env, &mut ctx, content, subs, &mut buf, Parens::Unnecessary);
|
||||
|
||||
for (i, (var, ability)) in ctx.able_variables.into_iter().enumerate() {
|
||||
buf.push_str(if i == 0 { " | " } else { ", " });
|
||||
buf.push_str(var);
|
||||
buf.push_str(" has ");
|
||||
write_symbol(&env, ability, &mut buf);
|
||||
}
|
||||
|
||||
buf
|
||||
}
|
||||
|
@ -314,7 +328,14 @@ pub fn get_single_arg<'a>(subs: &'a Subs, args: &'a AliasVariables) -> &'a Conte
|
|||
subs.get_content_without_compacting(arg_var)
|
||||
}
|
||||
|
||||
fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, parens: Parens) {
|
||||
fn write_content<'a>(
|
||||
env: &Env,
|
||||
ctx: &mut Context<'a>,
|
||||
content: &Content,
|
||||
subs: &'a Subs,
|
||||
buf: &mut String,
|
||||
parens: Parens,
|
||||
) {
|
||||
use crate::subs::Content::*;
|
||||
|
||||
match content {
|
||||
|
@ -327,6 +348,18 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
let name = &subs.field_names[name_index.index as usize];
|
||||
buf.push_str(name.as_str())
|
||||
}
|
||||
FlexAbleVar(opt_name_index, ability) => {
|
||||
let name = opt_name_index
|
||||
.map(|name_index| subs.field_names[name_index.index as usize].as_str())
|
||||
.unwrap_or(WILDCARD);
|
||||
ctx.able_variables.push((name, *ability));
|
||||
buf.push_str(name);
|
||||
}
|
||||
RigidAbleVar(name_index, ability) => {
|
||||
let name = subs.field_names[name_index.index as usize].as_str();
|
||||
ctx.able_variables.push((name, *ability));
|
||||
buf.push_str(name);
|
||||
}
|
||||
RecursionVar { opt_name, .. } => match opt_name {
|
||||
Some(name_index) => {
|
||||
let name = &subs.field_names[name_index.index as usize];
|
||||
|
@ -334,7 +367,7 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
}
|
||||
None => buf.push_str(WILDCARD),
|
||||
},
|
||||
Structure(flat_type) => write_flat_type(env, flat_type, subs, buf, parens),
|
||||
Structure(flat_type) => write_flat_type(env, ctx, flat_type, subs, buf, parens),
|
||||
Alias(symbol, args, _actual, _kind) => {
|
||||
let write_parens = parens == Parens::InTypeParam && !args.is_empty();
|
||||
|
||||
|
@ -346,6 +379,7 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
Symbol::NUM_INTEGER => {
|
||||
write_integer(
|
||||
env,
|
||||
ctx,
|
||||
get_single_arg(subs, &args),
|
||||
subs,
|
||||
buf,
|
||||
|
@ -357,13 +391,13 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
|
||||
_ => write_parens!(write_parens, buf, {
|
||||
buf.push_str("Num ");
|
||||
write_content(env, content, subs, buf, parens);
|
||||
write_content(env, ctx, content, subs, buf, parens);
|
||||
}),
|
||||
},
|
||||
|
||||
_ => write_parens!(write_parens, buf, {
|
||||
buf.push_str("Num ");
|
||||
write_content(env, content, subs, buf, parens);
|
||||
write_content(env, ctx, content, subs, buf, parens);
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -371,7 +405,7 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
Symbol::NUM_INT => {
|
||||
let content = get_single_arg(subs, args);
|
||||
|
||||
write_integer(env, content, subs, buf, parens, write_parens)
|
||||
write_integer(env, ctx, content, subs, buf, parens, write_parens)
|
||||
}
|
||||
|
||||
Symbol::NUM_FLOAT => {
|
||||
|
@ -390,7 +424,7 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
Alias(Symbol::NUM_DECIMAL, _, _, _) => buf.push_str("Dec"),
|
||||
_ => write_parens!(write_parens, buf, {
|
||||
buf.push_str("Float ");
|
||||
write_content(env, content, subs, buf, parens);
|
||||
write_content(env, ctx, content, subs, buf, parens);
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -403,6 +437,7 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
buf.push(' ');
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(var),
|
||||
subs,
|
||||
buf,
|
||||
|
@ -414,7 +449,7 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
if false {
|
||||
buf.push_str("[[ but really ");
|
||||
let content = subs.get_content_without_compacting(*_actual);
|
||||
write_content(env, content, subs, buf, parens);
|
||||
write_content(env, ctx, content, subs, buf, parens);
|
||||
buf.push_str("]]");
|
||||
}
|
||||
}),
|
||||
|
@ -422,6 +457,7 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
}
|
||||
RangedNumber(typ, _range_vars) => write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(*typ),
|
||||
subs,
|
||||
buf,
|
||||
|
@ -431,10 +467,11 @@ fn write_content(env: &Env, content: &Content, subs: &Subs, buf: &mut String, pa
|
|||
}
|
||||
}
|
||||
|
||||
fn write_integer(
|
||||
fn write_integer<'a>(
|
||||
env: &Env,
|
||||
ctx: &mut Context<'a>,
|
||||
content: &Content,
|
||||
subs: &Subs,
|
||||
subs: &'a Subs,
|
||||
buf: &mut String,
|
||||
parens: Parens,
|
||||
write_parens: bool,
|
||||
|
@ -454,7 +491,7 @@ fn write_integer(
|
|||
)*
|
||||
actual => {
|
||||
buf.push_str("Int ");
|
||||
write_content(env, actual, subs, buf, parens);
|
||||
write_content(env, ctx, actual, subs, buf, parens);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -497,6 +534,7 @@ impl<'a> ExtContent<'a> {
|
|||
|
||||
fn write_ext_content<'a>(
|
||||
env: &Env,
|
||||
ctx: &mut Context<'a>,
|
||||
subs: &'a Subs,
|
||||
buf: &mut String,
|
||||
ext_content: ExtContent<'a>,
|
||||
|
@ -508,12 +546,13 @@ fn write_ext_content<'a>(
|
|||
//
|
||||
// e.g. the "*" at the end of `{ x: I64 }*`
|
||||
// or the "r" at the end of `{ x: I64 }r`
|
||||
write_content(env, content, subs, buf, parens)
|
||||
write_content(env, ctx, content, subs, buf, parens)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_sorted_tags2<'a>(
|
||||
env: &Env,
|
||||
ctx: &mut Context<'a>,
|
||||
subs: &'a Subs,
|
||||
buf: &mut String,
|
||||
tags: &UnionTags,
|
||||
|
@ -546,6 +585,7 @@ fn write_sorted_tags2<'a>(
|
|||
buf.push(' ');
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(*var),
|
||||
subs,
|
||||
buf,
|
||||
|
@ -559,6 +599,7 @@ fn write_sorted_tags2<'a>(
|
|||
|
||||
fn write_sorted_tags<'a>(
|
||||
env: &Env,
|
||||
ctx: &mut Context<'a>,
|
||||
subs: &'a Subs,
|
||||
buf: &mut String,
|
||||
tags: &MutMap<TagName, Vec<Variable>>,
|
||||
|
@ -603,6 +644,7 @@ fn write_sorted_tags<'a>(
|
|||
buf.push(' ');
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(*var),
|
||||
subs,
|
||||
buf,
|
||||
|
@ -614,18 +656,37 @@ fn write_sorted_tags<'a>(
|
|||
ExtContent::from_var(subs, ext_var)
|
||||
}
|
||||
|
||||
fn write_flat_type(env: &Env, flat_type: &FlatType, subs: &Subs, buf: &mut String, parens: Parens) {
|
||||
fn write_flat_type<'a>(
|
||||
env: &Env,
|
||||
ctx: &mut Context<'a>,
|
||||
flat_type: &FlatType,
|
||||
subs: &'a Subs,
|
||||
buf: &mut String,
|
||||
parens: Parens,
|
||||
) {
|
||||
use crate::subs::FlatType::*;
|
||||
|
||||
match flat_type {
|
||||
Apply(symbol, args) => {
|
||||
write_apply(env, *symbol, subs.get_subs_slice(*args), subs, buf, parens)
|
||||
}
|
||||
Apply(symbol, args) => write_apply(
|
||||
env,
|
||||
ctx,
|
||||
*symbol,
|
||||
subs.get_subs_slice(*args),
|
||||
subs,
|
||||
buf,
|
||||
parens,
|
||||
),
|
||||
EmptyRecord => buf.push_str(EMPTY_RECORD),
|
||||
EmptyTagUnion => buf.push_str(EMPTY_TAG_UNION),
|
||||
Func(args, _closure, ret) => {
|
||||
write_fn(env, subs.get_subs_slice(*args), *ret, subs, buf, parens)
|
||||
}
|
||||
Func(args, _closure, ret) => write_fn(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_subs_slice(*args),
|
||||
*ret,
|
||||
subs,
|
||||
buf,
|
||||
parens,
|
||||
),
|
||||
Record(fields, ext_var) => {
|
||||
use crate::types::{gather_fields, RecordStructure};
|
||||
|
||||
|
@ -664,6 +725,7 @@ fn write_flat_type(env: &Env, flat_type: &FlatType, subs: &Subs, buf: &mut Strin
|
|||
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(var),
|
||||
subs,
|
||||
buf,
|
||||
|
@ -684,18 +746,18 @@ fn write_flat_type(env: &Env, flat_type: &FlatType, subs: &Subs, buf: &mut Strin
|
|||
//
|
||||
// e.g. the "*" at the end of `{ x: I64 }*`
|
||||
// or the "r" at the end of `{ x: I64 }r`
|
||||
write_content(env, content, subs, buf, parens)
|
||||
write_content(env, ctx, content, subs, buf, parens)
|
||||
}
|
||||
}
|
||||
}
|
||||
TagUnion(tags, ext_var) => {
|
||||
buf.push_str("[ ");
|
||||
|
||||
let ext_content = write_sorted_tags2(env, subs, buf, tags, *ext_var);
|
||||
let ext_content = write_sorted_tags2(env, ctx, subs, buf, tags, *ext_var);
|
||||
|
||||
buf.push_str(" ]");
|
||||
|
||||
write_ext_content(env, subs, buf, ext_content, parens)
|
||||
write_ext_content(env, ctx, subs, buf, ext_content, parens)
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
||||
|
@ -703,25 +765,26 @@ fn write_flat_type(env: &Env, flat_type: &FlatType, subs: &Subs, buf: &mut Strin
|
|||
|
||||
let mut tags: MutMap<TagName, _> = MutMap::default();
|
||||
tags.insert(subs[*tag_name].clone(), vec![]);
|
||||
let ext_content = write_sorted_tags(env, subs, buf, &tags, *ext_var);
|
||||
let ext_content = write_sorted_tags(env, ctx, subs, buf, &tags, *ext_var);
|
||||
|
||||
buf.push_str(" ]");
|
||||
|
||||
write_ext_content(env, subs, buf, ext_content, parens)
|
||||
write_ext_content(env, ctx, subs, buf, ext_content, parens)
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
buf.push_str("[ ");
|
||||
|
||||
let ext_content = write_sorted_tags2(env, subs, buf, tags, *ext_var);
|
||||
let ext_content = write_sorted_tags2(env, ctx, subs, buf, tags, *ext_var);
|
||||
|
||||
buf.push_str(" ]");
|
||||
|
||||
write_ext_content(env, subs, buf, ext_content, parens);
|
||||
write_ext_content(env, ctx, subs, buf, ext_content, parens);
|
||||
|
||||
buf.push_str(" as ");
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(*rec_var),
|
||||
subs,
|
||||
buf,
|
||||
|
@ -777,11 +840,12 @@ pub fn chase_ext_tag_union<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn write_apply(
|
||||
fn write_apply<'a>(
|
||||
env: &Env,
|
||||
ctx: &mut Context<'a>,
|
||||
symbol: Symbol,
|
||||
args: &[Variable],
|
||||
subs: &Subs,
|
||||
subs: &'a Subs,
|
||||
buf: &mut String,
|
||||
parens: Parens,
|
||||
) {
|
||||
|
@ -805,7 +869,7 @@ fn write_apply(
|
|||
buf.push('(');
|
||||
}
|
||||
|
||||
write_content(env, content, subs, &mut arg_param, Parens::InTypeParam);
|
||||
write_content(env, ctx, content, subs, &mut arg_param, Parens::InTypeParam);
|
||||
buf.push_str("Num ");
|
||||
buf.push_str(&arg_param);
|
||||
|
||||
|
@ -838,6 +902,7 @@ fn write_apply(
|
|||
buf.push(' ');
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(*arg),
|
||||
subs,
|
||||
buf,
|
||||
|
@ -852,11 +917,12 @@ fn write_apply(
|
|||
}
|
||||
}
|
||||
|
||||
fn write_fn(
|
||||
fn write_fn<'a>(
|
||||
env: &Env,
|
||||
ctx: &mut Context<'a>,
|
||||
args: &[Variable],
|
||||
ret: Variable,
|
||||
subs: &Subs,
|
||||
subs: &'a Subs,
|
||||
buf: &mut String,
|
||||
parens: Parens,
|
||||
) {
|
||||
|
@ -876,6 +942,7 @@ fn write_fn(
|
|||
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(*arg),
|
||||
subs,
|
||||
buf,
|
||||
|
@ -886,6 +953,7 @@ fn write_fn(
|
|||
buf.push_str(" -> ");
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(ret),
|
||||
subs,
|
||||
buf,
|
||||
|
|
|
@ -756,7 +756,9 @@ impl<'a> fmt::Debug for SubsFmtContent<'a> {
|
|||
fn subs_fmt_content(this: &Content, subs: &Subs, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match this {
|
||||
Content::FlexVar(name) => write!(f, "Flex({:?})", name),
|
||||
Content::FlexAbleVar(name, symbol) => write!(f, "FlexAble({:?}, {:?})", name, symbol),
|
||||
Content::RigidVar(name) => write!(f, "Rigid({:?})", name),
|
||||
Content::RigidAbleVar(name, symbol) => write!(f, "RigidAble({:?}, {:?})", name, symbol),
|
||||
Content::RecursionVar {
|
||||
structure,
|
||||
opt_name,
|
||||
|
@ -796,7 +798,19 @@ fn subs_fmt_flat_type(this: &FlatType, subs: &Subs, f: &mut fmt::Formatter) -> f
|
|||
}
|
||||
FlatType::Func(arguments, lambda_set, result) => {
|
||||
let slice = subs.get_subs_slice(*arguments);
|
||||
write!(f, "Func({:?}, {:?}, {:?})", slice, lambda_set, result)
|
||||
write!(f, "Func([")?;
|
||||
for var in slice {
|
||||
let content = subs.get_content_without_compacting(*var);
|
||||
write!(f, "<{:?}>{:?},", *var, SubsFmtContent(content, subs))?;
|
||||
}
|
||||
let result_content = subs.get_content_without_compacting(*result);
|
||||
write!(
|
||||
f,
|
||||
"], {:?}, <{:?}>{:?})",
|
||||
lambda_set,
|
||||
*result,
|
||||
SubsFmtContent(result_content, subs)
|
||||
)
|
||||
}
|
||||
FlatType::Record(fields, ext) => {
|
||||
write!(f, "{{ ")?;
|
||||
|
@ -1739,6 +1753,14 @@ impl Subs {
|
|||
self.set(var, desc);
|
||||
}
|
||||
|
||||
pub fn rigid_able_var(&mut self, var: Variable, name: Lowercase, ability: Symbol) {
|
||||
let name_index = SubsIndex::push_new(&mut self.field_names, name);
|
||||
let content = Content::RigidAbleVar(name_index, ability);
|
||||
let desc = Descriptor::from(content);
|
||||
|
||||
self.set(var, desc);
|
||||
}
|
||||
|
||||
/// Unions two keys without the possibility of failure.
|
||||
pub fn union(&mut self, left: Variable, right: Variable, desc: Descriptor) {
|
||||
let l_root = self.utable.inlined_get_root_key(left);
|
||||
|
@ -2120,6 +2142,12 @@ pub enum Content {
|
|||
FlexVar(Option<SubsIndex<Lowercase>>),
|
||||
/// name given in a user-written annotation
|
||||
RigidVar(SubsIndex<Lowercase>),
|
||||
/// Like a [Self::FlexVar], but is also bound to an ability.
|
||||
/// This can only happen when unified with a [Self::RigidAbleVar].
|
||||
FlexAbleVar(Option<SubsIndex<Lowercase>>, Symbol),
|
||||
/// Like a [Self::RigidVar], but is also bound to an ability.
|
||||
/// For example, "a has Hash".
|
||||
RigidAbleVar(SubsIndex<Lowercase>, Symbol),
|
||||
/// name given to a recursion variable
|
||||
RecursionVar {
|
||||
structure: Variable,
|
||||
|
@ -2840,7 +2868,12 @@ fn occurs(
|
|||
Err((root_var, vec![]))
|
||||
} else {
|
||||
match subs.get_content_without_compacting(root_var) {
|
||||
FlexVar(_) | RigidVar(_) | RecursionVar { .. } | Error => Ok(()),
|
||||
FlexVar(_)
|
||||
| RigidVar(_)
|
||||
| FlexAbleVar(_, _)
|
||||
| RigidAbleVar(_, _)
|
||||
| RecursionVar { .. }
|
||||
| Error => Ok(()),
|
||||
|
||||
Structure(flat_type) => {
|
||||
let mut new_seen = seen.to_owned();
|
||||
|
@ -2968,7 +3001,12 @@ fn explicit_substitute(
|
|||
to
|
||||
} else {
|
||||
match subs.get(in_var).content {
|
||||
FlexVar(_) | RigidVar(_) | RecursionVar { .. } | Error => in_var,
|
||||
FlexVar(_)
|
||||
| RigidVar(_)
|
||||
| FlexAbleVar(_, _)
|
||||
| RigidAbleVar(_, _)
|
||||
| RecursionVar { .. }
|
||||
| Error => in_var,
|
||||
|
||||
Structure(flat_type) => {
|
||||
match flat_type {
|
||||
|
@ -3136,9 +3174,9 @@ fn get_var_names(
|
|||
subs.set_mark(var, Mark::GET_VAR_NAMES);
|
||||
|
||||
match desc.content {
|
||||
Error | FlexVar(None) => taken_names,
|
||||
Error | FlexVar(None) | FlexAbleVar(None, _) => taken_names,
|
||||
|
||||
FlexVar(Some(name_index)) => add_name(
|
||||
FlexVar(Some(name_index)) | FlexAbleVar(Some(name_index), _) => add_name(
|
||||
subs,
|
||||
0,
|
||||
name_index,
|
||||
|
@ -3165,7 +3203,9 @@ fn get_var_names(
|
|||
None => taken_names,
|
||||
},
|
||||
|
||||
RigidVar(name_index) => add_name(subs, 0, name_index, var, RigidVar, taken_names),
|
||||
RigidVar(name_index) | RigidAbleVar(name_index, _) => {
|
||||
add_name(subs, 0, name_index, var, RigidVar, taken_names)
|
||||
}
|
||||
|
||||
Alias(_, args, _, _) => args.into_iter().fold(taken_names, |answer, arg_var| {
|
||||
get_var_names(subs, subs[arg_var], answer)
|
||||
|
@ -3331,11 +3371,6 @@ fn content_to_err_type(
|
|||
match content {
|
||||
Structure(flat_type) => flat_type_to_err_type(subs, state, flat_type),
|
||||
|
||||
FlexVar(Some(name_index)) => {
|
||||
let name = subs.field_names[name_index.index as usize].clone();
|
||||
ErrorType::FlexVar(name)
|
||||
}
|
||||
|
||||
FlexVar(opt_name) => {
|
||||
let name = match opt_name {
|
||||
Some(name_index) => subs.field_names[name_index.index as usize].clone(),
|
||||
|
@ -3358,6 +3393,28 @@ fn content_to_err_type(
|
|||
ErrorType::RigidVar(name)
|
||||
}
|
||||
|
||||
FlexAbleVar(opt_name, ability) => {
|
||||
let name = match opt_name {
|
||||
Some(name_index) => subs.field_names[name_index.index as usize].clone(),
|
||||
None => {
|
||||
// set the name so when this variable occurs elsewhere in the type it gets the same name
|
||||
let name = get_fresh_var_name(state);
|
||||
let name_index = SubsIndex::push_new(&mut subs.field_names, name.clone());
|
||||
|
||||
subs.set_content(var, FlexVar(Some(name_index)));
|
||||
|
||||
name
|
||||
}
|
||||
};
|
||||
|
||||
ErrorType::FlexAbleVar(name, ability)
|
||||
}
|
||||
|
||||
RigidAbleVar(name_index, ability) => {
|
||||
let name = subs.field_names[name_index.index as usize].clone();
|
||||
ErrorType::RigidAbleVar(name, ability)
|
||||
}
|
||||
|
||||
RecursionVar { opt_name, .. } => {
|
||||
let name = match opt_name {
|
||||
Some(name_index) => subs.field_names[name_index.index as usize].clone(),
|
||||
|
@ -3630,7 +3687,7 @@ fn restore_help(subs: &mut Subs, initial: Variable) {
|
|||
use FlatType::*;
|
||||
|
||||
match &desc.content {
|
||||
FlexVar(_) | RigidVar(_) | Error => (),
|
||||
FlexVar(_) | RigidVar(_) | FlexAbleVar(_, _) | RigidAbleVar(_, _) | Error => (),
|
||||
|
||||
RecursionVar { structure, .. } => {
|
||||
stack.push(*structure);
|
||||
|
@ -3859,6 +3916,8 @@ impl StorageSubs {
|
|||
match content {
|
||||
FlexVar(opt_name) => FlexVar(*opt_name),
|
||||
RigidVar(name) => RigidVar(*name),
|
||||
FlexAbleVar(opt_name, ability) => FlexAbleVar(*opt_name, *ability),
|
||||
RigidAbleVar(name, ability) => RigidAbleVar(*name, *ability),
|
||||
RecursionVar {
|
||||
structure,
|
||||
opt_name,
|
||||
|
@ -4255,6 +4314,29 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
|||
copy
|
||||
}
|
||||
|
||||
FlexAbleVar(opt_name_index, ability) => {
|
||||
let new_name_index = opt_name_index.map(|name_index| {
|
||||
let name = env.source.field_names[name_index.index as usize].clone();
|
||||
SubsIndex::push_new(&mut env.target.field_names, name)
|
||||
});
|
||||
|
||||
let content = FlexAbleVar(new_name_index, ability);
|
||||
env.target.set_content(copy, content);
|
||||
|
||||
copy
|
||||
}
|
||||
|
||||
RigidAbleVar(name_index, ability) => {
|
||||
let name = env.source.field_names[name_index.index as usize].clone();
|
||||
let new_name_index = SubsIndex::push_new(&mut env.target.field_names, name);
|
||||
env.target.set(
|
||||
copy,
|
||||
make_descriptor(FlexAbleVar(Some(new_name_index), ability)),
|
||||
);
|
||||
|
||||
copy
|
||||
}
|
||||
|
||||
Alias(symbol, arguments, real_type_var, kind) => {
|
||||
let new_variables =
|
||||
SubsSlice::reserve_into_subs(env.target, arguments.all_variables_len as _);
|
||||
|
@ -4314,6 +4396,8 @@ pub struct CopiedImport {
|
|||
pub variable: Variable,
|
||||
pub flex: Vec<Variable>,
|
||||
pub rigid: Vec<Variable>,
|
||||
pub flex_able: Vec<Variable>,
|
||||
pub rigid_able: Vec<Variable>,
|
||||
pub translations: Vec<(Variable, Variable)>,
|
||||
pub registered: Vec<Variable>,
|
||||
}
|
||||
|
@ -4324,6 +4408,8 @@ struct CopyImportEnv<'a> {
|
|||
target: &'a mut Subs,
|
||||
flex: Vec<Variable>,
|
||||
rigid: Vec<Variable>,
|
||||
flex_able: Vec<Variable>,
|
||||
rigid_able: Vec<Variable>,
|
||||
translations: Vec<(Variable, Variable)>,
|
||||
registered: Vec<Variable>,
|
||||
}
|
||||
|
@ -4345,6 +4431,8 @@ pub fn copy_import_to(
|
|||
target,
|
||||
flex: Vec::new(),
|
||||
rigid: Vec::new(),
|
||||
flex_able: Vec::new(),
|
||||
rigid_able: Vec::new(),
|
||||
translations: Vec::new(),
|
||||
registered: Vec::new(),
|
||||
};
|
||||
|
@ -4356,6 +4444,8 @@ pub fn copy_import_to(
|
|||
source,
|
||||
flex,
|
||||
rigid,
|
||||
flex_able,
|
||||
rigid_able,
|
||||
translations,
|
||||
registered,
|
||||
target: _,
|
||||
|
@ -4378,6 +4468,8 @@ pub fn copy_import_to(
|
|||
variable: copy,
|
||||
flex,
|
||||
rigid,
|
||||
flex_able,
|
||||
rigid_able,
|
||||
translations,
|
||||
registered,
|
||||
}
|
||||
|
@ -4395,7 +4487,10 @@ pub fn copy_import_to(
|
|||
/// standard variables
|
||||
fn is_registered(content: &Content) -> bool {
|
||||
match content {
|
||||
Content::FlexVar(_) | Content::RigidVar(_) => false,
|
||||
Content::FlexVar(_)
|
||||
| Content::RigidVar(_)
|
||||
| Content::FlexAbleVar(..)
|
||||
| Content::RigidAbleVar(..) => false,
|
||||
Content::Structure(FlatType::EmptyRecord | FlatType::EmptyTagUnion) => false,
|
||||
|
||||
Content::Structure(_)
|
||||
|
@ -4633,6 +4728,20 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
|||
copy
|
||||
}
|
||||
|
||||
FlexAbleVar(opt_name_index, ability) => {
|
||||
if let Some(name_index) = opt_name_index {
|
||||
let name = env.source.field_names[name_index.index as usize].clone();
|
||||
let new_name_index = SubsIndex::push_new(&mut env.target.field_names, name);
|
||||
|
||||
let content = FlexAbleVar(Some(new_name_index), ability);
|
||||
env.target.set_content(copy, content);
|
||||
}
|
||||
|
||||
env.flex_able.push(copy);
|
||||
|
||||
copy
|
||||
}
|
||||
|
||||
Error => {
|
||||
// Open question: should this return Error, or a Flex var?
|
||||
|
||||
|
@ -4655,6 +4764,20 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
|||
copy
|
||||
}
|
||||
|
||||
RigidAbleVar(name_index, ability) => {
|
||||
let name = env.source.field_names[name_index.index as usize].clone();
|
||||
let new_name_index = SubsIndex::push_new(&mut env.target.field_names, name);
|
||||
|
||||
env.target
|
||||
.set(copy, make_descriptor(RigidAbleVar(new_name_index, ability)));
|
||||
|
||||
env.rigid_able.push(copy);
|
||||
|
||||
env.translations.push((var, copy));
|
||||
|
||||
copy
|
||||
}
|
||||
|
||||
RecursionVar {
|
||||
opt_name,
|
||||
structure,
|
||||
|
@ -4748,7 +4871,7 @@ where
|
|||
use Content::*;
|
||||
use FlatType::*;
|
||||
match content {
|
||||
FlexVar(_) | RigidVar(_) => {}
|
||||
FlexVar(_) | RigidVar(_) | FlexAbleVar(_, _) | RigidAbleVar(_, _) => {}
|
||||
RecursionVar {
|
||||
structure,
|
||||
opt_name: _,
|
||||
|
|
|
@ -1744,6 +1744,15 @@ pub enum Reason {
|
|||
RecordUpdateKeys(Symbol, SendMap<Lowercase, Region>),
|
||||
RecordDefaultField(Lowercase),
|
||||
NumericLiteralSuffix,
|
||||
InvalidAbilityMemberSpecialization {
|
||||
member_name: Symbol,
|
||||
def_region: Region,
|
||||
unimplemented_abilities: DoesNotImplementAbility,
|
||||
},
|
||||
GeneralizedAbilityMemberSpecialization {
|
||||
member_name: Symbol,
|
||||
def_region: Region,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
|
@ -1783,6 +1792,8 @@ pub enum Category {
|
|||
Accessor(Lowercase),
|
||||
Access(Lowercase),
|
||||
DefaultValue(Lowercase), // for setting optional fields
|
||||
|
||||
AbilityMemberSpecialization(Symbol),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -1867,14 +1878,19 @@ pub enum Mismatch {
|
|||
InconsistentWhenBranches,
|
||||
CanonicalizationProblem,
|
||||
TypeNotInRange,
|
||||
DoesNotImplementAbiity(Variable, Symbol),
|
||||
}
|
||||
|
||||
pub type DoesNotImplementAbility = Vec<(ErrorType, Symbol)>;
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Hash)]
|
||||
pub enum ErrorType {
|
||||
Infinite,
|
||||
Type(Symbol, Vec<ErrorType>),
|
||||
FlexVar(Lowercase),
|
||||
RigidVar(Lowercase),
|
||||
FlexAbleVar(Lowercase, Symbol),
|
||||
RigidAbleVar(Lowercase, Symbol),
|
||||
Record(SendMap<Lowercase, RecordField<ErrorType>>, TypeExt),
|
||||
TagUnion(SendMap<TagName, Vec<ErrorType>>, TypeExt),
|
||||
RecursiveTagUnion(Box<ErrorType>, SendMap<TagName, Vec<ErrorType>>, TypeExt),
|
||||
|
@ -1905,10 +1921,7 @@ impl ErrorType {
|
|||
match self {
|
||||
Infinite => {}
|
||||
Type(_, ts) => ts.iter().for_each(|t| t.add_names(taken)),
|
||||
FlexVar(v) => {
|
||||
taken.insert(v.clone());
|
||||
}
|
||||
RigidVar(v) => {
|
||||
FlexVar(v) | RigidVar(v) | FlexAbleVar(v, _) | RigidAbleVar(v, _) => {
|
||||
taken.insert(v.clone());
|
||||
}
|
||||
Record(fields, ext) => {
|
||||
|
@ -2087,8 +2100,18 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
|
|||
match error_type {
|
||||
Infinite => buf.push('∞'),
|
||||
Error => buf.push('?'),
|
||||
FlexVar(name) => buf.push_str(name.as_str()),
|
||||
RigidVar(name) => buf.push_str(name.as_str()),
|
||||
FlexVar(name) | RigidVar(name) => buf.push_str(name.as_str()),
|
||||
FlexAbleVar(name, symbol) | RigidAbleVar(name, symbol) => {
|
||||
let write_parens = parens == Parens::InTypeParam;
|
||||
if write_parens {
|
||||
buf.push('(');
|
||||
}
|
||||
buf.push_str(name.as_str());
|
||||
buf.push_str(&format!(" has {:?}", symbol));
|
||||
if write_parens {
|
||||
buf.push(')');
|
||||
}
|
||||
}
|
||||
Type(symbol, arguments) => {
|
||||
let write_parens = parens == Parens::InTypeParam && !arguments.is_empty();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue