mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-22 04:44:06 +00:00
Parse "as" aliases into tag/args rather than arbitrary annotations
This commit is contained in:
parent
4ddb8e10fb
commit
2cd5bf8c03
8 changed files with 276 additions and 253 deletions
|
@ -450,127 +450,110 @@ pub fn to_type2<'a>(
|
||||||
|
|
||||||
Type2::TagUnion(tag_types, ext_type)
|
Type2::TagUnion(tag_types, ext_type)
|
||||||
}
|
}
|
||||||
As(loc_inner, _spaces, loc_as) => {
|
As(loc_inner, _spaces, (ident, loc_vars)) => {
|
||||||
// e.g. `{ x : Int, y : Int } as Point }`
|
// e.g. `{ x : Int, y : Int } as Point`
|
||||||
match loc_as.value {
|
let symbol = match scope.introduce(
|
||||||
Apply(module_name, ident, loc_vars) if module_name.is_empty() => {
|
(*ident).into(),
|
||||||
let symbol = match scope.introduce(
|
&env.exposed_ident_ids,
|
||||||
ident.into(),
|
&mut env.ident_ids,
|
||||||
&env.exposed_ident_ids,
|
region,
|
||||||
&mut env.ident_ids,
|
) {
|
||||||
region,
|
Ok(symbol) => symbol,
|
||||||
) {
|
|
||||||
Ok(symbol) => symbol,
|
|
||||||
|
|
||||||
Err((_original_region, _shadow)) => {
|
Err((_original_region, _shadow)) => {
|
||||||
// let problem = Problem2::Shadowed(original_region, shadow.clone());
|
// let problem = Problem2::Shadowed(original_region, shadow.clone());
|
||||||
|
|
||||||
// env.problem(roc_problem::can::Problem::ShadowingInAnnotation {
|
// env.problem(roc_problem::can::Problem::ShadowingInAnnotation {
|
||||||
// original_region,
|
// original_region,
|
||||||
// shadow,
|
// shadow,
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// return Type2::Erroneous(problem);
|
// return Type2::Erroneous(problem);
|
||||||
todo!();
|
todo!();
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let inner_type = to_type2(env, scope, references, &loc_inner.value, region);
|
|
||||||
let vars = PoolVec::with_capacity(loc_vars.len() as u32, env.pool);
|
|
||||||
|
|
||||||
let lowercase_vars = PoolVec::with_capacity(loc_vars.len() as u32, env.pool);
|
|
||||||
|
|
||||||
for ((loc_var, named_id), var_id) in loc_vars
|
|
||||||
.iter()
|
|
||||||
.zip(lowercase_vars.iter_node_ids())
|
|
||||||
.zip(vars.iter_node_ids())
|
|
||||||
{
|
|
||||||
match loc_var.value {
|
|
||||||
BoundVariable(ident) => {
|
|
||||||
let var_name = Lowercase::from(ident);
|
|
||||||
|
|
||||||
if let Some(var) = references.named.get(&var_name) {
|
|
||||||
let poolstr = PoolStr::new(var_name.as_str(), env.pool);
|
|
||||||
|
|
||||||
let type_id = env.pool.add(Type2::Variable(*var));
|
|
||||||
env.pool[var_id] = (poolstr.shallow_clone(), type_id);
|
|
||||||
|
|
||||||
env.pool[named_id] = (poolstr, *var);
|
|
||||||
env.set_region(named_id, loc_var.region);
|
|
||||||
} else {
|
|
||||||
let var = env.var_store.fresh();
|
|
||||||
|
|
||||||
references.named.insert(var_name.clone(), var);
|
|
||||||
let poolstr = PoolStr::new(var_name.as_str(), env.pool);
|
|
||||||
|
|
||||||
let type_id = env.pool.add(Type2::Variable(var));
|
|
||||||
env.pool[var_id] = (poolstr.shallow_clone(), type_id);
|
|
||||||
|
|
||||||
env.pool[named_id] = (poolstr, var);
|
|
||||||
env.set_region(named_id, loc_var.region);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// If anything other than a lowercase identifier
|
|
||||||
// appears here, the whole annotation is invalid.
|
|
||||||
return Type2::Erroneous(Problem2::CanonicalizationProblem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let alias_actual = inner_type;
|
|
||||||
// TODO instantiate recursive tag union
|
|
||||||
// let alias_actual = if let Type2::TagUnion(tags, ext) = inner_type {
|
|
||||||
// let rec_var = env.var_store.fresh();
|
|
||||||
//
|
|
||||||
// let mut new_tags = Vec::with_capacity(tags.len());
|
|
||||||
// for (tag_name, args) in tags {
|
|
||||||
// let mut new_args = Vec::with_capacity(args.len());
|
|
||||||
// for arg in args {
|
|
||||||
// let mut new_arg = arg.clone();
|
|
||||||
// new_arg.substitute_alias(symbol, &Type2::Variable(rec_var));
|
|
||||||
// new_args.push(new_arg);
|
|
||||||
// }
|
|
||||||
// new_tags.push((tag_name.clone(), new_args));
|
|
||||||
// }
|
|
||||||
// Type2::RecursiveTagUnion(rec_var, new_tags, ext)
|
|
||||||
// } else {
|
|
||||||
// inner_type
|
|
||||||
// };
|
|
||||||
|
|
||||||
let mut hidden_variables = MutSet::default();
|
|
||||||
hidden_variables.extend(alias_actual.variables(env.pool));
|
|
||||||
|
|
||||||
for (_, var) in lowercase_vars.iter(env.pool) {
|
|
||||||
hidden_variables.remove(var);
|
|
||||||
}
|
|
||||||
|
|
||||||
let alias_actual_id = env.pool.add(alias_actual);
|
|
||||||
scope.add_alias(env.pool, symbol, lowercase_vars, alias_actual_id);
|
|
||||||
|
|
||||||
let alias = scope.lookup_alias(symbol).unwrap();
|
|
||||||
// local_aliases.insert(symbol, alias.clone());
|
|
||||||
|
|
||||||
// TODO host-exposed
|
|
||||||
// if vars.is_empty() && env.home == symbol.module_id() {
|
|
||||||
// let actual_var = env.var_store.fresh();
|
|
||||||
// rigids.host_exposed.insert(symbol, actual_var);
|
|
||||||
// Type::HostExposedAlias {
|
|
||||||
// name: symbol,
|
|
||||||
// arguments: vars,
|
|
||||||
// actual: Box::new(alias.typ.clone()),
|
|
||||||
// actual_var,
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// Type::Alias(symbol, vars, Box::new(alias.typ.clone()))
|
|
||||||
// }
|
|
||||||
Type2::AsAlias(symbol, vars, alias.actual)
|
|
||||||
}
|
}
|
||||||
_ => {
|
};
|
||||||
// This is a syntactically invalid type alias.
|
|
||||||
Type2::Erroneous(Problem2::CanonicalizationProblem)
|
let inner_type = to_type2(env, scope, references, &loc_inner.value, region);
|
||||||
|
let vars = PoolVec::with_capacity(loc_vars.len() as u32, env.pool);
|
||||||
|
|
||||||
|
let lowercase_vars = PoolVec::with_capacity(loc_vars.len() as u32, env.pool);
|
||||||
|
|
||||||
|
for ((loc_var, named_id), var_id) in loc_vars
|
||||||
|
.iter()
|
||||||
|
.zip(lowercase_vars.iter_node_ids())
|
||||||
|
.zip(vars.iter_node_ids())
|
||||||
|
{
|
||||||
|
let var_name = Lowercase::from(loc_var.value);
|
||||||
|
|
||||||
|
if let Some(var) = references.named.get(&var_name) {
|
||||||
|
let poolstr = PoolStr::new(var_name.as_str(), env.pool);
|
||||||
|
|
||||||
|
let type_id = env.pool.add(Type2::Variable(*var));
|
||||||
|
env.pool[var_id] = (poolstr.shallow_clone(), type_id);
|
||||||
|
|
||||||
|
env.pool[named_id] = (poolstr, *var);
|
||||||
|
env.set_region(named_id, loc_var.region);
|
||||||
|
} else {
|
||||||
|
let var = env.var_store.fresh();
|
||||||
|
|
||||||
|
references.named.insert(var_name.clone(), var);
|
||||||
|
let poolstr = PoolStr::new(var_name.as_str(), env.pool);
|
||||||
|
|
||||||
|
let type_id = env.pool.add(Type2::Variable(var));
|
||||||
|
env.pool[var_id] = (poolstr.shallow_clone(), type_id);
|
||||||
|
|
||||||
|
env.pool[named_id] = (poolstr, var);
|
||||||
|
env.set_region(named_id, loc_var.region);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let alias_actual = inner_type;
|
||||||
|
// TODO instantiate recursive tag union
|
||||||
|
// let alias_actual = if let Type2::TagUnion(tags, ext) = inner_type {
|
||||||
|
// let rec_var = env.var_store.fresh();
|
||||||
|
//
|
||||||
|
// let mut new_tags = Vec::with_capacity(tags.len());
|
||||||
|
// for (tag_name, args) in tags {
|
||||||
|
// let mut new_args = Vec::with_capacity(args.len());
|
||||||
|
// for arg in args {
|
||||||
|
// let mut new_arg = arg.clone();
|
||||||
|
// new_arg.substitute_alias(symbol, &Type2::Variable(rec_var));
|
||||||
|
// new_args.push(new_arg);
|
||||||
|
// }
|
||||||
|
// new_tags.push((tag_name.clone(), new_args));
|
||||||
|
// }
|
||||||
|
// Type2::RecursiveTagUnion(rec_var, new_tags, ext)
|
||||||
|
// } else {
|
||||||
|
// inner_type
|
||||||
|
// };
|
||||||
|
|
||||||
|
let mut hidden_variables = MutSet::default();
|
||||||
|
hidden_variables.extend(alias_actual.variables(env.pool));
|
||||||
|
|
||||||
|
for (_, var) in lowercase_vars.iter(env.pool) {
|
||||||
|
hidden_variables.remove(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
let alias_actual_id = env.pool.add(alias_actual);
|
||||||
|
scope.add_alias(env.pool, symbol, lowercase_vars, alias_actual_id);
|
||||||
|
|
||||||
|
let alias = scope.lookup_alias(symbol).unwrap();
|
||||||
|
// local_aliases.insert(symbol, alias.clone());
|
||||||
|
|
||||||
|
// TODO host-exposed
|
||||||
|
// if vars.is_empty() && env.home == symbol.module_id() {
|
||||||
|
// let actual_var = env.var_store.fresh();
|
||||||
|
// rigids.host_exposed.insert(symbol, actual_var);
|
||||||
|
// Type::HostExposedAlias {
|
||||||
|
// name: symbol,
|
||||||
|
// arguments: vars,
|
||||||
|
// actual: Box::new(alias.typ.clone()),
|
||||||
|
// actual_var,
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// Type::Alias(symbol, vars, Box::new(alias.typ.clone()))
|
||||||
|
// }
|
||||||
|
Type2::AsAlias(symbol, vars, alias.actual)
|
||||||
}
|
}
|
||||||
SpaceBefore(nested, _) | SpaceAfter(nested, _) => {
|
SpaceBefore(nested, _) | SpaceAfter(nested, _) => {
|
||||||
to_type2(env, scope, references, nested, region)
|
to_type2(env, scope, references, nested, region)
|
||||||
|
|
|
@ -576,11 +576,9 @@ impl<'a> RemoveSpaces<'a> for TypeAnnotation<'a> {
|
||||||
),
|
),
|
||||||
TypeAnnotation::Apply(a, b, c) => TypeAnnotation::Apply(a, b, c.remove_spaces(arena)),
|
TypeAnnotation::Apply(a, b, c) => TypeAnnotation::Apply(a, b, c.remove_spaces(arena)),
|
||||||
TypeAnnotation::BoundVariable(a) => TypeAnnotation::BoundVariable(a),
|
TypeAnnotation::BoundVariable(a) => TypeAnnotation::BoundVariable(a),
|
||||||
TypeAnnotation::As(a, _, c) => TypeAnnotation::As(
|
TypeAnnotation::As(a, _, c) => {
|
||||||
arena.alloc(a.remove_spaces(arena)),
|
TypeAnnotation::As(arena.alloc(a.remove_spaces(arena)), &[], c)
|
||||||
&[],
|
}
|
||||||
arena.alloc(c.remove_spaces(arena)),
|
|
||||||
),
|
|
||||||
TypeAnnotation::Record { fields, ext } => TypeAnnotation::Record {
|
TypeAnnotation::Record { fields, ext } => TypeAnnotation::Record {
|
||||||
fields: fields.remove_spaces(arena),
|
fields: fields.remove_spaces(arena),
|
||||||
ext: ext.remove_spaces(arena),
|
ext: ext.remove_spaces(arena),
|
||||||
|
|
|
@ -374,124 +374,109 @@ fn can_annotation_help(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
As(loc_inner, _spaces, loc_as) => match loc_as.value {
|
As(loc_inner, _spaces, (ident, loc_vars)) => {
|
||||||
TypeAnnotation::Apply(module_name, ident, loc_vars) if module_name.is_empty() => {
|
let symbol = match scope.introduce(
|
||||||
let symbol = match scope.introduce(
|
(*ident).into(),
|
||||||
ident.into(),
|
&env.exposed_ident_ids,
|
||||||
&env.exposed_ident_ids,
|
&mut env.ident_ids,
|
||||||
&mut env.ident_ids,
|
region,
|
||||||
region,
|
) {
|
||||||
) {
|
Ok(symbol) => symbol,
|
||||||
Ok(symbol) => symbol,
|
|
||||||
|
|
||||||
Err((original_region, shadow)) => {
|
Err((original_region, shadow)) => {
|
||||||
let problem = Problem::Shadowed(original_region, shadow.clone());
|
let problem = Problem::Shadowed(original_region, shadow.clone());
|
||||||
|
|
||||||
env.problem(roc_problem::can::Problem::ShadowingInAnnotation {
|
env.problem(roc_problem::can::Problem::ShadowingInAnnotation {
|
||||||
original_region,
|
original_region,
|
||||||
shadow,
|
shadow,
|
||||||
});
|
});
|
||||||
|
|
||||||
return Type::Erroneous(problem);
|
return Type::Erroneous(problem);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let inner_type = can_annotation_help(
|
|
||||||
env,
|
|
||||||
&loc_inner.value,
|
|
||||||
region,
|
|
||||||
scope,
|
|
||||||
var_store,
|
|
||||||
introduced_variables,
|
|
||||||
local_aliases,
|
|
||||||
references,
|
|
||||||
);
|
|
||||||
let mut vars = Vec::with_capacity(loc_vars.len());
|
|
||||||
let mut lowercase_vars = Vec::with_capacity(loc_vars.len());
|
|
||||||
|
|
||||||
references.insert(symbol);
|
|
||||||
|
|
||||||
for loc_var in loc_vars {
|
|
||||||
match loc_var.value {
|
|
||||||
BoundVariable(ident) => {
|
|
||||||
let var_name = Lowercase::from(ident);
|
|
||||||
|
|
||||||
if let Some(var) = introduced_variables.var_by_name(&var_name) {
|
|
||||||
vars.push((var_name.clone(), Type::Variable(*var)));
|
|
||||||
lowercase_vars.push(Loc::at(loc_var.region, (var_name, *var)));
|
|
||||||
} else {
|
|
||||||
let var = var_store.fresh();
|
|
||||||
|
|
||||||
introduced_variables.insert_named(var_name.clone(), var);
|
|
||||||
vars.push((var_name.clone(), Type::Variable(var)));
|
|
||||||
|
|
||||||
lowercase_vars.push(Loc::at(loc_var.region, (var_name, var)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// If anything other than a lowercase identifier
|
|
||||||
// appears here, the whole annotation is invalid.
|
|
||||||
return Type::Erroneous(Problem::CanonicalizationProblem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let alias_actual = if let Type::TagUnion(tags, ext) = inner_type {
|
let inner_type = can_annotation_help(
|
||||||
let rec_var = var_store.fresh();
|
env,
|
||||||
|
&loc_inner.value,
|
||||||
|
region,
|
||||||
|
scope,
|
||||||
|
var_store,
|
||||||
|
introduced_variables,
|
||||||
|
local_aliases,
|
||||||
|
references,
|
||||||
|
);
|
||||||
|
let mut vars = Vec::with_capacity(loc_vars.len());
|
||||||
|
let mut lowercase_vars = Vec::with_capacity(loc_vars.len());
|
||||||
|
|
||||||
let mut new_tags = Vec::with_capacity(tags.len());
|
references.insert(symbol);
|
||||||
for (tag_name, args) in tags {
|
|
||||||
let mut new_args = Vec::with_capacity(args.len());
|
for loc_var in *loc_vars {
|
||||||
for arg in args {
|
let var_name = Lowercase::from(loc_var.value);
|
||||||
let mut new_arg = arg.clone();
|
|
||||||
new_arg.substitute_alias(symbol, &Type::Variable(rec_var));
|
if let Some(var) = introduced_variables.var_by_name(&var_name) {
|
||||||
new_args.push(new_arg);
|
vars.push((var_name.clone(), Type::Variable(*var)));
|
||||||
}
|
lowercase_vars.push(Loc::at(loc_var.region, (var_name, *var)));
|
||||||
new_tags.push((tag_name.clone(), new_args));
|
|
||||||
}
|
|
||||||
Type::RecursiveTagUnion(rec_var, new_tags, ext)
|
|
||||||
} else {
|
} else {
|
||||||
inner_type
|
let var = var_store.fresh();
|
||||||
};
|
|
||||||
|
|
||||||
let mut hidden_variables = MutSet::default();
|
introduced_variables.insert_named(var_name.clone(), var);
|
||||||
hidden_variables.extend(alias_actual.variables());
|
vars.push((var_name.clone(), Type::Variable(var)));
|
||||||
|
|
||||||
for loc_var in lowercase_vars.iter() {
|
lowercase_vars.push(Loc::at(loc_var.region, (var_name, var)));
|
||||||
hidden_variables.remove(&loc_var.value.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.add_alias(symbol, region, lowercase_vars, alias_actual);
|
|
||||||
|
|
||||||
let alias = scope.lookup_alias(symbol).unwrap();
|
|
||||||
local_aliases.insert(symbol, alias.clone());
|
|
||||||
|
|
||||||
// Type::Alias(symbol, vars, Box::new(alias.typ.clone()))
|
|
||||||
|
|
||||||
if vars.is_empty() && env.home == symbol.module_id() {
|
|
||||||
let actual_var = var_store.fresh();
|
|
||||||
introduced_variables.insert_host_exposed_alias(symbol, actual_var);
|
|
||||||
Type::HostExposedAlias {
|
|
||||||
name: symbol,
|
|
||||||
type_arguments: vars,
|
|
||||||
lambda_set_variables: alias.lambda_set_variables.clone(),
|
|
||||||
actual: Box::new(alias.typ.clone()),
|
|
||||||
actual_var,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Type::Alias {
|
|
||||||
symbol,
|
|
||||||
type_arguments: vars,
|
|
||||||
lambda_set_variables: alias.lambda_set_variables.clone(),
|
|
||||||
actual: Box::new(alias.typ.clone()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
// This is a syntactically invalid type alias.
|
let alias_actual = if let Type::TagUnion(tags, ext) = inner_type {
|
||||||
Type::Erroneous(Problem::CanonicalizationProblem)
|
let rec_var = var_store.fresh();
|
||||||
|
|
||||||
|
let mut new_tags = Vec::with_capacity(tags.len());
|
||||||
|
for (tag_name, args) in tags {
|
||||||
|
let mut new_args = Vec::with_capacity(args.len());
|
||||||
|
for arg in args {
|
||||||
|
let mut new_arg = arg.clone();
|
||||||
|
new_arg.substitute_alias(symbol, &Type::Variable(rec_var));
|
||||||
|
new_args.push(new_arg);
|
||||||
|
}
|
||||||
|
new_tags.push((tag_name.clone(), new_args));
|
||||||
|
}
|
||||||
|
Type::RecursiveTagUnion(rec_var, new_tags, ext)
|
||||||
|
} else {
|
||||||
|
inner_type
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut hidden_variables = MutSet::default();
|
||||||
|
hidden_variables.extend(alias_actual.variables());
|
||||||
|
|
||||||
|
for loc_var in lowercase_vars.iter() {
|
||||||
|
hidden_variables.remove(&loc_var.value.1);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
scope.add_alias(symbol, region, lowercase_vars, alias_actual);
|
||||||
|
|
||||||
|
let alias = scope.lookup_alias(symbol).unwrap();
|
||||||
|
local_aliases.insert(symbol, alias.clone());
|
||||||
|
|
||||||
|
// Type::Alias(symbol, vars, Box::new(alias.typ.clone()))
|
||||||
|
|
||||||
|
if vars.is_empty() && env.home == symbol.module_id() {
|
||||||
|
let actual_var = var_store.fresh();
|
||||||
|
introduced_variables.insert_host_exposed_alias(symbol, actual_var);
|
||||||
|
Type::HostExposedAlias {
|
||||||
|
name: symbol,
|
||||||
|
type_arguments: vars,
|
||||||
|
lambda_set_variables: alias.lambda_set_variables.clone(),
|
||||||
|
actual: Box::new(alias.typ.clone()),
|
||||||
|
actual_var,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Type::Alias {
|
||||||
|
symbol,
|
||||||
|
type_arguments: vars,
|
||||||
|
lambda_set_variables: alias.lambda_set_variables.clone(),
|
||||||
|
actual: Box::new(alias.typ.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Record { fields, ext } => {
|
Record { fields, ext } => {
|
||||||
let ext_type = match ext {
|
let ext_type = match ext {
|
||||||
|
|
|
@ -126,7 +126,7 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
||||||
|| args.iter().any(|loc_arg| (&loc_arg.value).is_multiline())
|
|| args.iter().any(|loc_arg| (&loc_arg.value).is_multiline())
|
||||||
}
|
}
|
||||||
Apply(_, _, args) => args.iter().any(|loc_arg| loc_arg.value.is_multiline()),
|
Apply(_, _, args) => args.iter().any(|loc_arg| loc_arg.value.is_multiline()),
|
||||||
As(lhs, _, rhs) => lhs.value.is_multiline() || rhs.value.is_multiline(),
|
As(lhs, _, _) => lhs.value.is_multiline(),
|
||||||
|
|
||||||
Record { fields, ext } => {
|
Record { fields, ext } => {
|
||||||
match ext {
|
match ext {
|
||||||
|
@ -245,12 +245,17 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
As(lhs, _spaces, rhs) => {
|
As(lhs, _spaces, (name, args)) => {
|
||||||
// TODO use spaces?
|
// TODO use spaces?
|
||||||
lhs.value.format(buf, indent);
|
lhs.value.format(buf, indent);
|
||||||
buf.push_str(" as");
|
|
||||||
buf.spaces(1);
|
buf.spaces(1);
|
||||||
rhs.value.format(buf, indent);
|
buf.push_str("as");
|
||||||
|
buf.spaces(1);
|
||||||
|
buf.push_str(name);
|
||||||
|
for arg in *args {
|
||||||
|
buf.spaces(1);
|
||||||
|
buf.push_str(arg.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceBefore(ann, spaces) => {
|
SpaceBefore(ann, spaces) => {
|
||||||
|
|
|
@ -280,7 +280,7 @@ pub enum TypeAnnotation<'a> {
|
||||||
As(
|
As(
|
||||||
&'a Loc<TypeAnnotation<'a>>,
|
&'a Loc<TypeAnnotation<'a>>,
|
||||||
&'a [CommentOrNewline<'a>],
|
&'a [CommentOrNewline<'a>],
|
||||||
&'a Loc<TypeAnnotation<'a>>,
|
(&'a str, &'a [Loc<&'a str>]),
|
||||||
),
|
),
|
||||||
|
|
||||||
Record {
|
Record {
|
||||||
|
|
|
@ -482,6 +482,7 @@ pub enum EType<'a> {
|
||||||
TTagUnion(ETypeTagUnion<'a>, Position),
|
TTagUnion(ETypeTagUnion<'a>, Position),
|
||||||
TInParens(ETypeInParens<'a>, Position),
|
TInParens(ETypeInParens<'a>, Position),
|
||||||
TApply(ETypeApply, Position),
|
TApply(ETypeApply, Position),
|
||||||
|
TInlineAlias(ETypeInlineAlias, Position),
|
||||||
TBadTypeVariable(Position),
|
TBadTypeVariable(Position),
|
||||||
TWildcard(Position),
|
TWildcard(Position),
|
||||||
TInferred(Position),
|
TInferred(Position),
|
||||||
|
@ -553,6 +554,13 @@ pub enum ETypeApply {
|
||||||
StartIsNumber(Position),
|
StartIsNumber(Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum ETypeInlineAlias {
|
||||||
|
NotAnAlias(Position),
|
||||||
|
Qualified(Position),
|
||||||
|
ArgumentNotLowercase(Position),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParseProblem<'a, T> {
|
pub struct ParseProblem<'a, T> {
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
|
|
|
@ -3,13 +3,13 @@ use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||||
use crate::keyword;
|
use crate::keyword;
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
allocated, backtrackable, optional, specialize, specialize_ref, word1, word2, EType,
|
allocated, backtrackable, optional, specialize, specialize_ref, word1, word2, EType,
|
||||||
ETypeApply, ETypeInParens, ETypeRecord, ETypeTagUnion, ParseResult, Parser,
|
ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, ParseResult, Parser,
|
||||||
Progress::{self, *},
|
Progress::{self, *},
|
||||||
};
|
};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use bumpalo::collections::vec::Vec;
|
use bumpalo::collections::vec::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_region::all::{Loc, Position, Region};
|
use roc_region::all::{Loc, Position};
|
||||||
|
|
||||||
pub fn located_help<'a>(
|
pub fn located_help<'a>(
|
||||||
min_indent: u16,
|
min_indent: u16,
|
||||||
|
@ -47,6 +47,56 @@ fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, ET
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type_alias<'a>(
|
||||||
|
p: Progress,
|
||||||
|
annot: Loc<TypeAnnotation<'a>>,
|
||||||
|
) -> impl Parser<'a, Loc<(&'a str, &'a [Loc<&'a str>])>, ETypeInlineAlias> {
|
||||||
|
move |arena, state| match annot.value {
|
||||||
|
TypeAnnotation::Apply("", tag_name, args) => {
|
||||||
|
let mut arg_names = Vec::new_in(arena);
|
||||||
|
arg_names.reserve(args.len());
|
||||||
|
for arg in args {
|
||||||
|
if let TypeAnnotation::BoundVariable(v) = arg.value {
|
||||||
|
arg_names.push(Loc::at(arg.region, v));
|
||||||
|
} else {
|
||||||
|
return Err((
|
||||||
|
p,
|
||||||
|
ETypeInlineAlias::ArgumentNotLowercase(arg.region.start()),
|
||||||
|
state,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
p,
|
||||||
|
Loc::at(annot.region, (tag_name, arg_names.into_bump_slice())),
|
||||||
|
state,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
TypeAnnotation::Apply(_, _, _) => {
|
||||||
|
Err((p, ETypeInlineAlias::Qualified(annot.region.start()), state))
|
||||||
|
}
|
||||||
|
_ => Err((p, ETypeInlineAlias::NotAnAlias(annot.region.start()), state)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_type_alias_after_as<'a>(
|
||||||
|
min_indent: u16,
|
||||||
|
) -> impl Parser<'a, Loc<(&'a str, &'a [Loc<&'a str>])>, EType<'a>> {
|
||||||
|
move |arena, state| {
|
||||||
|
space0_before_e(
|
||||||
|
term(min_indent),
|
||||||
|
min_indent,
|
||||||
|
EType::TSpace,
|
||||||
|
EType::TAsIndentStart,
|
||||||
|
)
|
||||||
|
.parse(arena, state)
|
||||||
|
.and_then(|(p, annot, state)| {
|
||||||
|
specialize(EType::TInlineAlias, check_type_alias(p, annot)).parse(arena, state)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, EType<'a>> {
|
fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, EType<'a>> {
|
||||||
|_arena, state: State<'a>| Err((NoProgress, EType::TStart(state.pos), state))
|
|_arena, state: State<'a>| Err((NoProgress, EType::TStart(state.pos), state))
|
||||||
}
|
}
|
||||||
|
@ -72,12 +122,7 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'
|
||||||
backtrackable(space0_e(min_indent, EType::TSpace, EType::TIndentEnd)),
|
backtrackable(space0_e(min_indent, EType::TSpace, EType::TIndentEnd)),
|
||||||
crate::parser::keyword_e(keyword::AS, EType::TEnd)
|
crate::parser::keyword_e(keyword::AS, EType::TEnd)
|
||||||
),
|
),
|
||||||
space0_before_e(
|
parse_type_alias_after_as(min_indent)
|
||||||
term(min_indent),
|
|
||||||
min_indent,
|
|
||||||
EType::TSpace,
|
|
||||||
EType::TAsIndentStart
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
Some
|
Some
|
||||||
),
|
),
|
||||||
|
@ -87,13 +132,17 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'
|
||||||
|arena: &'a Bump,
|
|arena: &'a Bump,
|
||||||
(loc_ann, opt_as): (
|
(loc_ann, opt_as): (
|
||||||
Loc<TypeAnnotation<'a>>,
|
Loc<TypeAnnotation<'a>>,
|
||||||
Option<(&'a [_], Loc<TypeAnnotation<'a>>)>
|
Option<(&'a [_], Loc<(&'a str, &'a [Loc<&'a str>])>)>
|
||||||
)| {
|
)| {
|
||||||
match opt_as {
|
match opt_as {
|
||||||
Some((spaces, loc_as)) => {
|
Some((
|
||||||
let region = Region::span_across(&loc_ann.region, &loc_as.region);
|
spaces,
|
||||||
let value =
|
Loc {
|
||||||
TypeAnnotation::As(arena.alloc(loc_ann), spaces, arena.alloc(loc_as));
|
region,
|
||||||
|
value: alias,
|
||||||
|
},
|
||||||
|
)) => {
|
||||||
|
let value = TypeAnnotation::As(arena.alloc(loc_ann), spaces, alias);
|
||||||
|
|
||||||
Loc { region, value }
|
Loc { region, value }
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ Defs(
|
||||||
|L 0-0, C 0-3| Identifier(
|
|L 0-0, C 0-3| Identifier(
|
||||||
"foo",
|
"foo",
|
||||||
),
|
),
|
||||||
|L 0-0, C 6-33| As(
|
|L 0-0, C 25-33| As(
|
||||||
|L 0-0, C 6-21| Apply(
|
|L 0-0, C 6-21| Apply(
|
||||||
"Foo.Bar",
|
"Foo.Bar",
|
||||||
"Baz",
|
"Baz",
|
||||||
|
@ -18,16 +18,11 @@ Defs(
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
[],
|
[],
|
||||||
|L 0-0, C 25-33| Apply(
|
(
|
||||||
"",
|
|
||||||
"Blah",
|
"Blah",
|
||||||
[
|
[
|
||||||
|L 0-0, C 30-31| BoundVariable(
|
|L 0-0, C 30-31| "a",
|
||||||
"a",
|
|L 0-0, C 32-33| "b",
|
||||||
),
|
|
||||||
|L 0-0, C 32-33| BoundVariable(
|
|
||||||
"b",
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue