mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
Parse opaque types
This commit is contained in:
parent
ab6019d402
commit
fa24e51593
13 changed files with 201 additions and 113 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -3304,6 +3304,7 @@ dependencies = [
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_parse",
|
"roc_parse",
|
||||||
"roc_problem",
|
"roc_problem",
|
||||||
|
@ -3572,6 +3573,7 @@ dependencies = [
|
||||||
"roc_can",
|
"roc_can",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
"roc_constrain",
|
"roc_constrain",
|
||||||
|
"roc_error_macros",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
"roc_mono",
|
"roc_mono",
|
||||||
"roc_parse",
|
"roc_parse",
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// use crate::pattern::{bindings_from_patterns, canonicalize_pattern, Pattern};
|
// use crate::pattern::{bindings_from_patterns, canonicalize_pattern, Pattern};
|
||||||
// use crate::procedure::References;
|
// use crate::procedure::References;
|
||||||
use roc_collections::all::{default_hasher, ImMap, MutMap, MutSet, SendMap};
|
use roc_collections::all::{default_hasher, ImMap, MutMap, MutSet, SendMap};
|
||||||
|
use roc_error_macros::todo_opaques;
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_parse::ast::{self, TypeHeader};
|
use roc_parse::ast::{self, TypeHeader};
|
||||||
|
@ -260,6 +261,8 @@ fn to_pending_def<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opaque { .. } => todo_opaques!(),
|
||||||
|
|
||||||
Expect(_) => todo!(),
|
Expect(_) => todo!(),
|
||||||
|
|
||||||
SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) => {
|
SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) => {
|
||||||
|
|
|
@ -9,8 +9,8 @@ use roc_fmt::module::fmt_module;
|
||||||
use roc_fmt::Buf;
|
use roc_fmt::Buf;
|
||||||
use roc_module::called_via::{BinOp, UnaryOp};
|
use roc_module::called_via::{BinOp, UnaryOp};
|
||||||
use roc_parse::ast::{
|
use roc_parse::ast::{
|
||||||
TypeHeader, AssignedField, Collection, Expr, Pattern, Spaced, StrLiteral, StrSegment, Tag,
|
AssignedField, Collection, Expr, Pattern, Spaced, StrLiteral, StrSegment, Tag, TypeAnnotation,
|
||||||
TypeAnnotation, WhenBranch,
|
TypeHeader, WhenBranch,
|
||||||
};
|
};
|
||||||
use roc_parse::header::{
|
use roc_parse::header::{
|
||||||
AppHeader, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
|
AppHeader, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
|
||||||
|
@ -411,6 +411,16 @@ impl<'a> RemoveSpaces<'a> for Def<'a> {
|
||||||
},
|
},
|
||||||
ann: ann.remove_spaces(arena),
|
ann: ann.remove_spaces(arena),
|
||||||
},
|
},
|
||||||
|
Def::Opaque {
|
||||||
|
header: TypeHeader { name, vars },
|
||||||
|
typ,
|
||||||
|
} => Def::Opaque {
|
||||||
|
header: TypeHeader {
|
||||||
|
name: name.remove_spaces(arena),
|
||||||
|
vars: vars.remove_spaces(arena),
|
||||||
|
},
|
||||||
|
typ: typ.remove_spaces(arena),
|
||||||
|
},
|
||||||
Def::Body(a, b) => Def::Body(
|
Def::Body(a, b) => Def::Body(
|
||||||
arena.alloc(a.remove_spaces(arena)),
|
arena.alloc(a.remove_spaces(arena)),
|
||||||
arena.alloc(b.remove_spaces(arena)),
|
arena.alloc(b.remove_spaces(arena)),
|
||||||
|
|
|
@ -7,6 +7,7 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
roc_collections = { path = "../collections" }
|
roc_collections = { path = "../collections" }
|
||||||
|
roc_error_macros = { path = "../../error_macros" }
|
||||||
roc_region = { path = "../region" }
|
roc_region = { path = "../region" }
|
||||||
roc_module = { path = "../module" }
|
roc_module = { path = "../module" }
|
||||||
roc_parse = { path = "../parse" }
|
roc_parse = { path = "../parse" }
|
||||||
|
|
|
@ -12,6 +12,7 @@ use crate::procedure::References;
|
||||||
use crate::scope::create_alias;
|
use crate::scope::create_alias;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_collections::all::{default_hasher, ImMap, ImSet, MutMap, MutSet, SendMap};
|
use roc_collections::all::{default_hasher, ImMap, ImSet, MutMap, MutSet, SendMap};
|
||||||
|
use roc_error_macros::todo_opaques;
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_parse::ast;
|
use roc_parse::ast;
|
||||||
|
@ -1504,6 +1505,8 @@ fn to_pending_def<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opaque { .. } => todo_opaques!(),
|
||||||
|
|
||||||
Expect(_condition) => todo!(),
|
Expect(_condition) => todo!(),
|
||||||
|
|
||||||
SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) => {
|
SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) => {
|
||||||
|
|
|
@ -95,6 +95,7 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> {
|
||||||
Body(loc_pattern, loc_expr) => Body(loc_pattern, desugar_expr(arena, loc_expr)),
|
Body(loc_pattern, loc_expr) => Body(loc_pattern, desugar_expr(arena, loc_expr)),
|
||||||
SpaceBefore(def, _) | SpaceAfter(def, _) => desugar_def(arena, def),
|
SpaceBefore(def, _) | SpaceAfter(def, _) => desugar_def(arena, def),
|
||||||
alias @ Alias { .. } => *alias,
|
alias @ Alias { .. } => *alias,
|
||||||
|
opaque @ Opaque { .. } => *opaque,
|
||||||
ann @ Annotation(_, _) => *ann,
|
ann @ Annotation(_, _) => *ann,
|
||||||
AnnotatedBody {
|
AnnotatedBody {
|
||||||
ann_pattern,
|
ann_pattern,
|
||||||
|
@ -415,7 +416,8 @@ fn binop_to_function(binop: BinOp) -> (&'static str, &'static str) {
|
||||||
Or => (ModuleName::BOOL, "or"),
|
Or => (ModuleName::BOOL, "or"),
|
||||||
Pizza => unreachable!("Cannot desugar the |> operator"),
|
Pizza => unreachable!("Cannot desugar the |> operator"),
|
||||||
Assignment => unreachable!("Cannot desugar the = operator"),
|
Assignment => unreachable!("Cannot desugar the = operator"),
|
||||||
HasType => unreachable!("Cannot desugar the : operator"),
|
IsAliasType => unreachable!("Cannot desugar the : operator"),
|
||||||
|
IsOpaqueType => unreachable!("Cannot desugar the := operator"),
|
||||||
Backpassing => unreachable!("Cannot desugar the <- operator"),
|
Backpassing => unreachable!("Cannot desugar the <- operator"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::annotation::{Formattable, Newlines, Parens};
|
||||||
use crate::pattern::fmt_pattern;
|
use crate::pattern::fmt_pattern;
|
||||||
use crate::spaces::{fmt_spaces, INDENT};
|
use crate::spaces::{fmt_spaces, INDENT};
|
||||||
use crate::Buf;
|
use crate::Buf;
|
||||||
use roc_parse::ast::{TypeHeader, Def, Expr, Pattern};
|
use roc_parse::ast::{Def, Expr, Pattern, TypeHeader};
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
||||||
/// A Located formattable value is also formattable
|
/// A Located formattable value is also formattable
|
||||||
|
@ -12,6 +12,7 @@ impl<'a> Formattable for Def<'a> {
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Alias { ann, .. } => ann.is_multiline(),
|
Alias { ann, .. } => ann.is_multiline(),
|
||||||
|
Opaque { typ, .. } => typ.is_multiline(),
|
||||||
Annotation(loc_pattern, loc_annotation) => {
|
Annotation(loc_pattern, loc_annotation) => {
|
||||||
loc_pattern.is_multiline() || loc_annotation.is_multiline()
|
loc_pattern.is_multiline() || loc_annotation.is_multiline()
|
||||||
}
|
}
|
||||||
|
@ -60,6 +61,10 @@ impl<'a> Formattable for Def<'a> {
|
||||||
Alias {
|
Alias {
|
||||||
header: TypeHeader { name, vars },
|
header: TypeHeader { name, vars },
|
||||||
ann,
|
ann,
|
||||||
|
}
|
||||||
|
| Opaque {
|
||||||
|
header: TypeHeader { name, vars },
|
||||||
|
typ: ann,
|
||||||
} => {
|
} => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str(name.value);
|
buf.push_str(name.value);
|
||||||
|
@ -69,7 +74,11 @@ impl<'a> Formattable for Def<'a> {
|
||||||
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push_str(" :");
|
buf.push_str(match self {
|
||||||
|
Alias { .. } => " :",
|
||||||
|
Opaque { .. } => " :=",
|
||||||
|
_ => unreachable!(),
|
||||||
|
});
|
||||||
buf.spaces(1);
|
buf.spaces(1);
|
||||||
|
|
||||||
ann.format(buf, indent + INDENT)
|
ann.format(buf, indent + INDENT)
|
||||||
|
|
|
@ -347,7 +347,8 @@ fn push_op(buf: &mut Buf, op: BinOp) {
|
||||||
called_via::BinOp::Or => buf.push_str("||"),
|
called_via::BinOp::Or => buf.push_str("||"),
|
||||||
called_via::BinOp::Pizza => buf.push_str("|>"),
|
called_via::BinOp::Pizza => buf.push_str("|>"),
|
||||||
called_via::BinOp::Assignment => unreachable!(),
|
called_via::BinOp::Assignment => unreachable!(),
|
||||||
called_via::BinOp::HasType => unreachable!(),
|
called_via::BinOp::IsAliasType => unreachable!(),
|
||||||
|
called_via::BinOp::IsOpaqueType => unreachable!(),
|
||||||
called_via::BinOp::Backpassing => unreachable!(),
|
called_via::BinOp::Backpassing => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1067,7 +1068,11 @@ fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool {
|
||||||
| BinOp::GreaterThanOrEq
|
| BinOp::GreaterThanOrEq
|
||||||
| BinOp::And
|
| BinOp::And
|
||||||
| BinOp::Or => true,
|
| BinOp::Or => true,
|
||||||
BinOp::Pizza | BinOp::Assignment | BinOp::HasType | BinOp::Backpassing => false,
|
BinOp::Pizza
|
||||||
|
| BinOp::Assignment
|
||||||
|
| BinOp::IsAliasType
|
||||||
|
| BinOp::IsOpaqueType
|
||||||
|
| BinOp::Backpassing => false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Expr::If(_, _) => true,
|
Expr::If(_, _) => true,
|
||||||
|
|
|
@ -7,6 +7,7 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
roc_collections = { path = "../collections" }
|
roc_collections = { path = "../collections" }
|
||||||
|
roc_error_macros = { path = "../../error_macros" }
|
||||||
roc_region = { path = "../region" }
|
roc_region = { path = "../region" }
|
||||||
roc_module = { path = "../module" }
|
roc_module = { path = "../module" }
|
||||||
roc_types = { path = "../types" }
|
roc_types = { path = "../types" }
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::docs::TypeAnnotation::{
|
||||||
};
|
};
|
||||||
use crate::file::LoadedModule;
|
use crate::file::LoadedModule;
|
||||||
use roc_can::scope::Scope;
|
use roc_can::scope::Scope;
|
||||||
|
use roc_error_macros::todo_opaques;
|
||||||
use roc_module::ident::ModuleName;
|
use roc_module::ident::ModuleName;
|
||||||
use roc_module::symbol::IdentIds;
|
use roc_module::symbol::IdentIds;
|
||||||
use roc_parse::ast::CommentOrNewline;
|
use roc_parse::ast::CommentOrNewline;
|
||||||
|
@ -228,6 +229,8 @@ fn generate_entry_doc<'a>(
|
||||||
(acc, None)
|
(acc, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Def::Opaque { .. } => todo_opaques!("figure out documentation for opaques"),
|
||||||
|
|
||||||
Def::Body(_, _) => (acc, None),
|
Def::Body(_, _) => (acc, None),
|
||||||
|
|
||||||
Def::Expect(c) => todo!("documentation for tests {:?}", c),
|
Def::Expect(c) => todo!("documentation for tests {:?}", c),
|
||||||
|
|
|
@ -47,7 +47,8 @@ pub enum BinOp {
|
||||||
Or,
|
Or,
|
||||||
Pizza,
|
Pizza,
|
||||||
Assignment,
|
Assignment,
|
||||||
HasType,
|
IsAliasType,
|
||||||
|
IsOpaqueType,
|
||||||
Backpassing,
|
Backpassing,
|
||||||
// lowest precedence
|
// lowest precedence
|
||||||
}
|
}
|
||||||
|
@ -59,7 +60,7 @@ impl BinOp {
|
||||||
Caret | Star | Slash | Percent | Plus | Minus | LessThan | GreaterThan => 1,
|
Caret | Star | Slash | Percent | Plus | Minus | LessThan | GreaterThan => 1,
|
||||||
DoubleSlash | DoublePercent | Equals | NotEquals | LessThanOrEq | GreaterThanOrEq
|
DoubleSlash | DoublePercent | Equals | NotEquals | LessThanOrEq | GreaterThanOrEq
|
||||||
| And | Or | Pizza => 2,
|
| And | Or | Pizza => 2,
|
||||||
Assignment | HasType | Backpassing => unreachable!(),
|
Assignment | IsAliasType | IsOpaqueType | Backpassing => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +104,7 @@ impl BinOp {
|
||||||
Equals | NotEquals | LessThan | GreaterThan | LessThanOrEq | GreaterThanOrEq => {
|
Equals | NotEquals | LessThan | GreaterThan | LessThanOrEq | GreaterThanOrEq => {
|
||||||
NonAssociative
|
NonAssociative
|
||||||
}
|
}
|
||||||
Assignment | HasType | Backpassing => unreachable!(),
|
Assignment | IsAliasType | IsOpaqueType | Backpassing => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +117,7 @@ impl BinOp {
|
||||||
And => 3,
|
And => 3,
|
||||||
Or => 2,
|
Or => 2,
|
||||||
Pizza => 1,
|
Pizza => 1,
|
||||||
Assignment | HasType | Backpassing => unreachable!(),
|
Assignment | IsAliasType | IsOpaqueType | Backpassing => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +155,8 @@ impl std::fmt::Display for BinOp {
|
||||||
Or => "||",
|
Or => "||",
|
||||||
Pizza => "|>",
|
Pizza => "|>",
|
||||||
Assignment => "=",
|
Assignment => "=",
|
||||||
HasType => ":",
|
IsAliasType => ":",
|
||||||
|
IsOpaqueType => ":=",
|
||||||
Backpassing => "<-",
|
Backpassing => "<-",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -257,6 +257,12 @@ pub enum Def<'a> {
|
||||||
ann: Loc<TypeAnnotation<'a>>,
|
ann: Loc<TypeAnnotation<'a>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// An opaque type, wrapping its inner type. E.g. Age := U64.
|
||||||
|
Opaque {
|
||||||
|
header: TypeHeader<'a>,
|
||||||
|
typ: Loc<TypeAnnotation<'a>>,
|
||||||
|
},
|
||||||
|
|
||||||
// TODO in canonicalization, check to see if there are any newlines after the
|
// TODO in canonicalization, check to see if there are any newlines after the
|
||||||
// annotation; if not, and if it's followed by a Body, then the annotation
|
// annotation; if not, and if it's followed by a Body, then the annotation
|
||||||
// applies to that expr! (TODO: verify that the pattern for both annotation and body match.)
|
// applies to that expr! (TODO: verify that the pattern for both annotation and body match.)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
TypeHeader, AssignedField, Collection, CommentOrNewline, Def, Expr, ExtractSpaces, Pattern,
|
AssignedField, Collection, CommentOrNewline, Def, Expr, ExtractSpaces, Pattern, Spaceable,
|
||||||
Spaceable, TypeAnnotation,
|
TypeAnnotation, TypeHeader,
|
||||||
};
|
};
|
||||||
use crate::blankspace::{space0_after_e, space0_around_ee, space0_before_e, space0_e};
|
use crate::blankspace::{space0_after_e, space0_around_ee, space0_before_e, space0_e};
|
||||||
use crate::ident::{lowercase_ident, parse_ident, Ident};
|
use crate::ident::{lowercase_ident, parse_ident, Ident};
|
||||||
|
@ -422,7 +422,7 @@ impl<'a> ExprState<'a> {
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
loc_op: Loc<BinOp>,
|
loc_op: Loc<BinOp>,
|
||||||
) -> Result<(Loc<Expr<'a>>, Vec<'a, &'a Loc<Expr<'a>>>), EExpr<'a>> {
|
) -> Result<(Loc<Expr<'a>>, Vec<'a, &'a Loc<Expr<'a>>>), EExpr<'a>> {
|
||||||
debug_assert_eq!(loc_op.value, BinOp::HasType);
|
debug_assert_eq!(loc_op.value, BinOp::IsAliasType);
|
||||||
|
|
||||||
if !self.operators.is_empty() {
|
if !self.operators.is_empty() {
|
||||||
// this `:` likely occurred inline; treat it as an invalid operator
|
// this `:` likely occurred inline; treat it as an invalid operator
|
||||||
|
@ -853,7 +853,7 @@ fn parse_defs_end<'a>(
|
||||||
|
|
||||||
parse_defs_end(options, column, def_state, arena, state)
|
parse_defs_end(options, column, def_state, arena, state)
|
||||||
}
|
}
|
||||||
Ok((_, BinOp::HasType, state)) => {
|
Ok((_, BinOp::IsAliasType, state)) => {
|
||||||
let (_, ann_type, state) = specialize(
|
let (_, ann_type, state) = specialize(
|
||||||
EExpr::Type,
|
EExpr::Type,
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
|
@ -919,6 +919,127 @@ fn parse_defs_expr<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
enum TypeKind {
|
||||||
|
Alias,
|
||||||
|
Opaque,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish_parsing_alias_or_opaque<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
options: ExprParseOptions,
|
||||||
|
start_column: u32,
|
||||||
|
expr_state: ExprState<'a>,
|
||||||
|
loc_op: Loc<BinOp>,
|
||||||
|
arena: &'a Bump,
|
||||||
|
state: State<'a>,
|
||||||
|
spaces_after_operator: &'a [CommentOrNewline<'a>],
|
||||||
|
kind: TypeKind,
|
||||||
|
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
||||||
|
let expr_region = expr_state.expr.region;
|
||||||
|
let indented_more = start_column + 1;
|
||||||
|
|
||||||
|
let (expr, arguments) = expr_state
|
||||||
|
.validate_has_type(arena, loc_op)
|
||||||
|
.map_err(|fail| (MadeProgress, fail, state.clone()))?;
|
||||||
|
|
||||||
|
let (loc_def, state) = match &expr.value {
|
||||||
|
Expr::GlobalTag(name) => {
|
||||||
|
let mut type_arguments = Vec::with_capacity_in(arguments.len(), arena);
|
||||||
|
|
||||||
|
for argument in arguments {
|
||||||
|
match expr_to_pattern_help(arena, &argument.value) {
|
||||||
|
Ok(good) => {
|
||||||
|
type_arguments.push(Loc::at(argument.region, good));
|
||||||
|
}
|
||||||
|
Err(_) => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (_, ann_type, state) = specialize(
|
||||||
|
EExpr::Type,
|
||||||
|
space0_before_e(
|
||||||
|
type_annotation::located_help(indented_more, true),
|
||||||
|
min_indent,
|
||||||
|
EType::TIndentStart,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
let def_region = Region::span_across(&expr.region, &ann_type.region);
|
||||||
|
|
||||||
|
let header = TypeHeader {
|
||||||
|
name: Loc::at(expr.region, name),
|
||||||
|
vars: type_arguments.into_bump_slice(),
|
||||||
|
};
|
||||||
|
let type_def = match kind {
|
||||||
|
TypeKind::Alias => Def::Alias {
|
||||||
|
header,
|
||||||
|
ann: ann_type,
|
||||||
|
},
|
||||||
|
TypeKind::Opaque => Def::Opaque {
|
||||||
|
header,
|
||||||
|
typ: ann_type,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(&*arena.alloc(Loc::at(def_region, type_def)), state)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
let call = to_call(arena, arguments, expr);
|
||||||
|
|
||||||
|
match expr_to_pattern_help(arena, &call.value) {
|
||||||
|
Ok(good) => {
|
||||||
|
let parser = specialize(
|
||||||
|
EExpr::Type,
|
||||||
|
space0_before_e(
|
||||||
|
type_annotation::located_help(indented_more, false),
|
||||||
|
min_indent,
|
||||||
|
EType::TIndentStart,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
match parser.parse(arena, state) {
|
||||||
|
Err((_, fail, state)) => return Err((MadeProgress, fail, state)),
|
||||||
|
Ok((_, mut ann_type, state)) => {
|
||||||
|
// put the spaces from after the operator in front of the call
|
||||||
|
if !spaces_after_operator.is_empty() {
|
||||||
|
ann_type = arena
|
||||||
|
.alloc(ann_type.value)
|
||||||
|
.with_spaces_before(spaces_after_operator, ann_type.region);
|
||||||
|
}
|
||||||
|
|
||||||
|
let def_region = Region::span_across(&call.region, &ann_type.region);
|
||||||
|
|
||||||
|
let alias = Def::Annotation(Loc::at(expr_region, good), ann_type);
|
||||||
|
|
||||||
|
(&*arena.alloc(Loc::at(def_region, alias)), state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
// this `:`/`:=` likely occurred inline; treat it as an invalid operator
|
||||||
|
let op = match kind {
|
||||||
|
TypeKind::Alias => ":",
|
||||||
|
TypeKind::Opaque => ":=",
|
||||||
|
};
|
||||||
|
let fail = EExpr::BadOperator(op, loc_op.region.start());
|
||||||
|
|
||||||
|
return Err((MadeProgress, fail, state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let def_state = DefState {
|
||||||
|
defs: bumpalo::vec![in arena; loc_def],
|
||||||
|
spaces_after: &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
parse_defs_expr(options, start_column, def_state, arena, state)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_expr_operator<'a>(
|
fn parse_expr_operator<'a>(
|
||||||
min_indent: u32,
|
min_indent: u32,
|
||||||
options: ExprParseOptions,
|
options: ExprParseOptions,
|
||||||
|
@ -1059,102 +1180,21 @@ fn parse_expr_operator<'a>(
|
||||||
|
|
||||||
Ok((MadeProgress, ret, state))
|
Ok((MadeProgress, ret, state))
|
||||||
}
|
}
|
||||||
BinOp::HasType => {
|
BinOp::IsAliasType | BinOp::IsOpaqueType => finish_parsing_alias_or_opaque(
|
||||||
let expr_region = expr_state.expr.region;
|
|
||||||
let indented_more = start_column + 1;
|
|
||||||
|
|
||||||
let (expr, arguments) = expr_state
|
|
||||||
.validate_has_type(arena, loc_op)
|
|
||||||
.map_err(|fail| (MadeProgress, fail, state.clone()))?;
|
|
||||||
|
|
||||||
let (loc_def, state) = match &expr.value {
|
|
||||||
Expr::GlobalTag(name) => {
|
|
||||||
let mut type_arguments = Vec::with_capacity_in(arguments.len(), arena);
|
|
||||||
|
|
||||||
for argument in arguments {
|
|
||||||
match expr_to_pattern_help(arena, &argument.value) {
|
|
||||||
Ok(good) => {
|
|
||||||
type_arguments.push(Loc::at(argument.region, good));
|
|
||||||
}
|
|
||||||
Err(_) => panic!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (_, ann_type, state) = specialize(
|
|
||||||
EExpr::Type,
|
|
||||||
space0_before_e(
|
|
||||||
type_annotation::located_help(indented_more, true),
|
|
||||||
min_indent,
|
min_indent,
|
||||||
EType::TIndentStart,
|
options,
|
||||||
),
|
start_column,
|
||||||
)
|
expr_state,
|
||||||
.parse(arena, state)?;
|
loc_op,
|
||||||
|
arena,
|
||||||
let alias_region = Region::span_across(&expr.region, &ann_type.region);
|
state,
|
||||||
|
|
||||||
let alias = Def::Alias {
|
|
||||||
header: TypeHeader {
|
|
||||||
name: Loc::at(expr.region, name),
|
|
||||||
vars: type_arguments.into_bump_slice(),
|
|
||||||
},
|
|
||||||
ann: ann_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
(&*arena.alloc(Loc::at(alias_region, alias)), state)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
let call = to_call(arena, arguments, expr);
|
|
||||||
|
|
||||||
match expr_to_pattern_help(arena, &call.value) {
|
|
||||||
Ok(good) => {
|
|
||||||
let parser = specialize(
|
|
||||||
EExpr::Type,
|
|
||||||
space0_before_e(
|
|
||||||
type_annotation::located_help(indented_more, false),
|
|
||||||
min_indent,
|
|
||||||
EType::TIndentStart,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
match parser.parse(arena, state) {
|
|
||||||
Err((_, fail, state)) => return Err((MadeProgress, fail, state)),
|
|
||||||
Ok((_, mut ann_type, state)) => {
|
|
||||||
// put the spaces from after the operator in front of the call
|
|
||||||
if !spaces_after_operator.is_empty() {
|
|
||||||
ann_type = arena.alloc(ann_type.value).with_spaces_before(
|
|
||||||
spaces_after_operator,
|
spaces_after_operator,
|
||||||
ann_type.region,
|
match op {
|
||||||
);
|
BinOp::IsAliasType => TypeKind::Alias,
|
||||||
}
|
BinOp::IsOpaqueType => TypeKind::Opaque,
|
||||||
|
_ => unreachable!(),
|
||||||
let alias_region =
|
},
|
||||||
Region::span_across(&call.region, &ann_type.region);
|
),
|
||||||
|
|
||||||
let alias =
|
|
||||||
Def::Annotation(Loc::at(expr_region, good), ann_type);
|
|
||||||
|
|
||||||
(&*arena.alloc(Loc::at(alias_region, alias)), state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
// this `:` likely occurred inline; treat it as an invalid operator
|
|
||||||
let fail = EExpr::BadOperator(":", loc_op.region.start());
|
|
||||||
|
|
||||||
return Err((MadeProgress, fail, state));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let def_state = DefState {
|
|
||||||
defs: bumpalo::vec![in arena; loc_def],
|
|
||||||
spaces_after: &[],
|
|
||||||
};
|
|
||||||
|
|
||||||
parse_defs_expr(options, start_column, def_state, arena, state)
|
|
||||||
}
|
|
||||||
_ => match loc_possibly_negative_or_negated_term(min_indent, options).parse(arena, state) {
|
_ => match loc_possibly_negative_or_negated_term(min_indent, options).parse(arena, state) {
|
||||||
Err((MadeProgress, f, s)) => Err((MadeProgress, f, s)),
|
Err((MadeProgress, f, s)) => Err((MadeProgress, f, s)),
|
||||||
Ok((_, mut new_expr, state)) => {
|
Ok((_, mut new_expr, state)) => {
|
||||||
|
@ -2372,7 +2412,8 @@ where
|
||||||
Err((NoProgress, to_error(".", state.pos()), state))
|
Err((NoProgress, to_error(".", state.pos()), state))
|
||||||
}
|
}
|
||||||
"=" => good!(BinOp::Assignment, 1),
|
"=" => good!(BinOp::Assignment, 1),
|
||||||
":" => good!(BinOp::HasType, 1),
|
":=" => good!(BinOp::IsOpaqueType, 2),
|
||||||
|
":" => good!(BinOp::IsAliasType, 1),
|
||||||
"|>" => good!(BinOp::Pizza, 2),
|
"|>" => good!(BinOp::Pizza, 2),
|
||||||
"==" => good!(BinOp::Equals, 2),
|
"==" => good!(BinOp::Equals, 2),
|
||||||
"!=" => good!(BinOp::NotEquals, 2),
|
"!=" => good!(BinOp::NotEquals, 2),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue