mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
Parse has-derived clauses
This commit is contained in:
parent
a6ec43af5e
commit
fcf464e9da
9 changed files with 421 additions and 105 deletions
|
@ -297,6 +297,7 @@ pub enum TypeDef<'a> {
|
||||||
Opaque {
|
Opaque {
|
||||||
header: TypeHeader<'a>,
|
header: TypeHeader<'a>,
|
||||||
typ: Loc<TypeAnnotation<'a>>,
|
typ: Loc<TypeAnnotation<'a>>,
|
||||||
|
derived: Option<Loc<Derived<'a>>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// An ability definition. E.g.
|
/// An ability definition. E.g.
|
||||||
|
@ -380,11 +381,23 @@ impl<'a> From<ValueDef<'a>> for Def<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Should always be a zero-argument `Apply`; we'll check this in canonicalization
|
||||||
|
pub type AbilityName<'a> = Loc<TypeAnnotation<'a>>;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct HasClause<'a> {
|
pub struct HasClause<'a> {
|
||||||
pub var: Loc<Spaced<'a, &'a str>>,
|
pub var: Loc<Spaced<'a, &'a str>>,
|
||||||
// Should always be a zero-argument `Apply`; we'll check this in canonicalization
|
pub ability: AbilityName<'a>,
|
||||||
pub ability: Loc<TypeAnnotation<'a>>,
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum Derived<'a> {
|
||||||
|
/// `has [ Eq, Hash ]`
|
||||||
|
Has(Collection<'a, AbilityName<'a>>),
|
||||||
|
|
||||||
|
// We preserve this for the formatter; canonicalization ignores it.
|
||||||
|
SpaceBefore(&'a Derived<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
|
SpaceAfter(&'a Derived<'a>, &'a [CommentOrNewline<'a>]),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
@ -901,6 +914,15 @@ impl<'a> Spaceable<'a> for Has<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Spaceable<'a> for Derived<'a> {
|
||||||
|
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||||
|
Derived::SpaceBefore(self, spaces)
|
||||||
|
}
|
||||||
|
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||||
|
Derived::SpaceAfter(self, spaces)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Expr<'a> {
|
impl<'a> Expr<'a> {
|
||||||
pub fn loc_ref(&'a self, region: Region) -> Loc<&'a Self> {
|
pub fn loc_ref(&'a self, region: Region) -> Loc<&'a Self> {
|
||||||
Loc {
|
Loc {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
AssignedField, Collection, CommentOrNewline, Def, Expr, ExtractSpaces, Has, Pattern, Spaceable,
|
AssignedField, Collection, CommentOrNewline, Def, Derived, Expr, ExtractSpaces, Has, Pattern,
|
||||||
TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
Spaceable, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||||
};
|
};
|
||||||
use crate::blankspace::{
|
use crate::blankspace::{
|
||||||
space0_after_e, space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
space0_after_e, space0_around_ee, space0_before_e, space0_before_optional_after, space0_e,
|
||||||
|
@ -426,21 +426,21 @@ impl<'a> ExprState<'a> {
|
||||||
mut self,
|
mut self,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
loc_op: Loc<BinOp>,
|
loc_op: Loc<BinOp>,
|
||||||
kind: TypeKind,
|
kind: AliasOrOpaque,
|
||||||
) -> 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!(
|
debug_assert_eq!(
|
||||||
loc_op.value,
|
loc_op.value,
|
||||||
match kind {
|
match kind {
|
||||||
TypeKind::Alias => BinOp::IsAliasType,
|
AliasOrOpaque::Alias => BinOp::IsAliasType,
|
||||||
TypeKind::Opaque => BinOp::IsOpaqueType,
|
AliasOrOpaque::Opaque => BinOp::IsOpaqueType,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
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
|
||||||
let op = match kind {
|
let op = match kind {
|
||||||
TypeKind::Alias => ":",
|
AliasOrOpaque::Alias => ":",
|
||||||
TypeKind::Opaque => ":=",
|
AliasOrOpaque::Opaque => ":=",
|
||||||
};
|
};
|
||||||
let fail = EExpr::BadOperator(op, loc_op.region.start());
|
let fail = EExpr::BadOperator(op, loc_op.region.start());
|
||||||
|
|
||||||
|
@ -690,7 +690,10 @@ fn append_annotation_definition<'a>(
|
||||||
spaces: &'a [CommentOrNewline<'a>],
|
spaces: &'a [CommentOrNewline<'a>],
|
||||||
loc_pattern: Loc<Pattern<'a>>,
|
loc_pattern: Loc<Pattern<'a>>,
|
||||||
loc_ann: Loc<TypeAnnotation<'a>>,
|
loc_ann: Loc<TypeAnnotation<'a>>,
|
||||||
kind: TypeKind,
|
|
||||||
|
// If this turns out to be an alias
|
||||||
|
kind: AliasOrOpaque,
|
||||||
|
opt_derived: Option<Loc<Derived<'a>>>,
|
||||||
) {
|
) {
|
||||||
let region = Region::span_across(&loc_pattern.region, &loc_ann.region);
|
let region = Region::span_across(&loc_pattern.region, &loc_ann.region);
|
||||||
|
|
||||||
|
@ -702,7 +705,7 @@ fn append_annotation_definition<'a>(
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
alias_arguments,
|
alias_arguments,
|
||||||
) => append_type_definition(
|
) => append_alias_or_opaque_definition(
|
||||||
arena,
|
arena,
|
||||||
defs,
|
defs,
|
||||||
region,
|
region,
|
||||||
|
@ -711,8 +714,9 @@ fn append_annotation_definition<'a>(
|
||||||
alias_arguments,
|
alias_arguments,
|
||||||
loc_ann,
|
loc_ann,
|
||||||
kind,
|
kind,
|
||||||
|
opt_derived,
|
||||||
),
|
),
|
||||||
Pattern::Tag(name) => append_type_definition(
|
Pattern::Tag(name) => append_alias_or_opaque_definition(
|
||||||
arena,
|
arena,
|
||||||
defs,
|
defs,
|
||||||
region,
|
region,
|
||||||
|
@ -721,6 +725,7 @@ fn append_annotation_definition<'a>(
|
||||||
&[],
|
&[],
|
||||||
loc_ann,
|
loc_ann,
|
||||||
kind,
|
kind,
|
||||||
|
opt_derived,
|
||||||
),
|
),
|
||||||
_ => {
|
_ => {
|
||||||
let mut loc_def = Loc::at(
|
let mut loc_def = Loc::at(
|
||||||
|
@ -762,7 +767,7 @@ fn append_expect_definition<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn append_type_definition<'a>(
|
fn append_alias_or_opaque_definition<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
defs: &mut Vec<'a, &'a Loc<Def<'a>>>,
|
defs: &mut Vec<'a, &'a Loc<Def<'a>>>,
|
||||||
region: Region,
|
region: Region,
|
||||||
|
@ -770,23 +775,26 @@ fn append_type_definition<'a>(
|
||||||
name: Loc<&'a str>,
|
name: Loc<&'a str>,
|
||||||
pattern_arguments: &'a [Loc<Pattern<'a>>],
|
pattern_arguments: &'a [Loc<Pattern<'a>>],
|
||||||
loc_ann: Loc<TypeAnnotation<'a>>,
|
loc_ann: Loc<TypeAnnotation<'a>>,
|
||||||
kind: TypeKind,
|
kind: AliasOrOpaque,
|
||||||
|
opt_derived: Option<Loc<Derived<'a>>>,
|
||||||
) {
|
) {
|
||||||
let header = TypeHeader {
|
let header = TypeHeader {
|
||||||
name,
|
name,
|
||||||
vars: pattern_arguments,
|
vars: pattern_arguments,
|
||||||
};
|
};
|
||||||
let def = match kind {
|
|
||||||
TypeKind::Alias => TypeDef::Alias {
|
let type_def = match kind {
|
||||||
|
AliasOrOpaque::Alias => TypeDef::Alias {
|
||||||
header,
|
header,
|
||||||
ann: loc_ann,
|
ann: loc_ann,
|
||||||
},
|
},
|
||||||
TypeKind::Opaque => TypeDef::Opaque {
|
AliasOrOpaque::Opaque => TypeDef::Opaque {
|
||||||
header,
|
header,
|
||||||
typ: loc_ann,
|
typ: loc_ann,
|
||||||
|
derived: opt_derived,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut loc_def = Loc::at(region, Def::Type(def));
|
let mut loc_def = Loc::at(region, Def::Type(type_def));
|
||||||
|
|
||||||
if !spaces.is_empty() {
|
if !spaces.is_empty() {
|
||||||
loc_def = arena
|
loc_def = arena
|
||||||
|
@ -922,16 +930,9 @@ fn parse_defs_end<'a>(
|
||||||
|
|
||||||
parse_defs_end(options, column, def_state, arena, state)
|
parse_defs_end(options, column, def_state, arena, state)
|
||||||
}
|
}
|
||||||
Ok((_, op @ (BinOp::IsAliasType | BinOp::IsOpaqueType), state)) => {
|
Ok((_, BinOp::IsAliasType, state)) => {
|
||||||
let (_, ann_type, state) = specialize(
|
let (_, ann_type, state) =
|
||||||
EExpr::Type,
|
alias_signature_with_space_before(min_indent + 1).parse(arena, state)?;
|
||||||
space0_before_e(
|
|
||||||
type_annotation::located_help(min_indent + 1, false),
|
|
||||||
min_indent + 1,
|
|
||||||
EType::TIndentStart,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.parse(arena, state)?;
|
|
||||||
|
|
||||||
append_annotation_definition(
|
append_annotation_definition(
|
||||||
arena,
|
arena,
|
||||||
|
@ -939,11 +940,24 @@ fn parse_defs_end<'a>(
|
||||||
def_state.spaces_after,
|
def_state.spaces_after,
|
||||||
loc_pattern,
|
loc_pattern,
|
||||||
ann_type,
|
ann_type,
|
||||||
match op {
|
AliasOrOpaque::Alias,
|
||||||
BinOp::IsAliasType => TypeKind::Alias,
|
None,
|
||||||
BinOp::IsOpaqueType => TypeKind::Opaque,
|
);
|
||||||
_ => unreachable!(),
|
|
||||||
},
|
parse_defs_end(options, column, def_state, arena, state)
|
||||||
|
}
|
||||||
|
Ok((_, BinOp::IsOpaqueType, state)) => {
|
||||||
|
let (_, (signature, derived), state) =
|
||||||
|
opaque_signature_with_space_before(min_indent + 1).parse(arena, state)?;
|
||||||
|
|
||||||
|
append_annotation_definition(
|
||||||
|
arena,
|
||||||
|
&mut def_state.defs,
|
||||||
|
def_state.spaces_after,
|
||||||
|
loc_pattern,
|
||||||
|
signature,
|
||||||
|
AliasOrOpaque::Opaque,
|
||||||
|
derived,
|
||||||
);
|
);
|
||||||
|
|
||||||
parse_defs_end(options, column, def_state, arena, state)
|
parse_defs_end(options, column, def_state, arena, state)
|
||||||
|
@ -994,8 +1008,44 @@ fn parse_defs_expr<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn alias_signature_with_space_before<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EExpr<'a>> {
|
||||||
|
specialize(
|
||||||
|
EExpr::Type,
|
||||||
|
space0_before_e(
|
||||||
|
type_annotation::located(min_indent + 1, false),
|
||||||
|
min_indent + 1,
|
||||||
|
EType::TIndentStart,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opaque_signature_with_space_before<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
) -> impl Parser<'a, (Loc<TypeAnnotation<'a>>, Option<Loc<Derived<'a>>>), EExpr<'a>> {
|
||||||
|
and!(
|
||||||
|
specialize(
|
||||||
|
EExpr::Type,
|
||||||
|
space0_before_e(
|
||||||
|
type_annotation::located_opaque_signature(min_indent, true),
|
||||||
|
min_indent,
|
||||||
|
EType::TIndentStart,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
optional(specialize(
|
||||||
|
EExpr::Type,
|
||||||
|
space0_before_e(
|
||||||
|
type_annotation::has_derived(min_indent),
|
||||||
|
min_indent,
|
||||||
|
EType::TIndentStart,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
enum TypeKind {
|
enum AliasOrOpaque {
|
||||||
Alias,
|
Alias,
|
||||||
Opaque,
|
Opaque,
|
||||||
}
|
}
|
||||||
|
@ -1010,7 +1060,7 @@ fn finish_parsing_alias_or_opaque<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
state: State<'a>,
|
state: State<'a>,
|
||||||
spaces_after_operator: &'a [CommentOrNewline<'a>],
|
spaces_after_operator: &'a [CommentOrNewline<'a>],
|
||||||
kind: TypeKind,
|
kind: AliasOrOpaque,
|
||||||
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
||||||
let expr_region = expr_state.expr.region;
|
let expr_region = expr_state.expr.region;
|
||||||
let indented_more = start_column + 1;
|
let indented_more = start_column + 1;
|
||||||
|
@ -1032,34 +1082,48 @@ fn finish_parsing_alias_or_opaque<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_, ann_type, state) = specialize(
|
let (loc_def, state) = match kind {
|
||||||
EExpr::Type,
|
AliasOrOpaque::Alias => {
|
||||||
space0_before_e(
|
let (_, signature, state) =
|
||||||
type_annotation::located_help(indented_more, true),
|
alias_signature_with_space_before(indented_more).parse(arena, state)?;
|
||||||
min_indent,
|
|
||||||
EType::TIndentStart,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.parse(arena, state)?;
|
|
||||||
|
|
||||||
let def_region = Region::span_across(&expr.region, &ann_type.region);
|
let def_region = Region::span_across(&expr.region, &signature.region);
|
||||||
|
|
||||||
let header = TypeHeader {
|
let header = TypeHeader {
|
||||||
name: Loc::at(expr.region, name),
|
name: Loc::at(expr.region, name),
|
||||||
vars: type_arguments.into_bump_slice(),
|
vars: type_arguments.into_bump_slice(),
|
||||||
};
|
};
|
||||||
let type_def = match kind {
|
|
||||||
TypeKind::Alias => TypeDef::Alias {
|
let def = TypeDef::Alias {
|
||||||
header,
|
header,
|
||||||
ann: ann_type,
|
ann: signature,
|
||||||
},
|
};
|
||||||
TypeKind::Opaque => TypeDef::Opaque {
|
|
||||||
header,
|
(Loc::at(def_region, Def::Type(def)), state)
|
||||||
typ: ann_type,
|
}
|
||||||
},
|
|
||||||
|
AliasOrOpaque::Opaque => {
|
||||||
|
let (_, (signature, derived), state) =
|
||||||
|
opaque_signature_with_space_before(indented_more).parse(arena, state)?;
|
||||||
|
|
||||||
|
let def_region = Region::span_across(&expr.region, &signature.region);
|
||||||
|
|
||||||
|
let header = TypeHeader {
|
||||||
|
name: Loc::at(expr.region, name),
|
||||||
|
vars: type_arguments.into_bump_slice(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let def = TypeDef::Opaque {
|
||||||
|
header,
|
||||||
|
typ: signature,
|
||||||
|
derived,
|
||||||
|
};
|
||||||
|
|
||||||
|
(Loc::at(def_region, Def::Type(def)), state)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(&*arena.alloc(Loc::at(def_region, type_def.into())), state)
|
(&*arena.alloc(loc_def), state)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1070,7 +1134,7 @@ fn finish_parsing_alias_or_opaque<'a>(
|
||||||
let parser = specialize(
|
let parser = specialize(
|
||||||
EExpr::Type,
|
EExpr::Type,
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
type_annotation::located_help(indented_more, false),
|
type_annotation::located(indented_more, false),
|
||||||
min_indent,
|
min_indent,
|
||||||
EType::TIndentStart,
|
EType::TIndentStart,
|
||||||
),
|
),
|
||||||
|
@ -1097,8 +1161,8 @@ fn finish_parsing_alias_or_opaque<'a>(
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// this `:`/`:=` likely occurred inline; treat it as an invalid operator
|
// this `:`/`:=` likely occurred inline; treat it as an invalid operator
|
||||||
let op = match kind {
|
let op = match kind {
|
||||||
TypeKind::Alias => ":",
|
AliasOrOpaque::Alias => ":",
|
||||||
TypeKind::Opaque => ":=",
|
AliasOrOpaque::Opaque => ":=",
|
||||||
};
|
};
|
||||||
let fail = EExpr::BadOperator(op, loc_op.region.start());
|
let fail = EExpr::BadOperator(op, loc_op.region.start());
|
||||||
|
|
||||||
|
@ -1139,7 +1203,7 @@ mod ability {
|
||||||
specialize(
|
specialize(
|
||||||
EAbility::Type,
|
EAbility::Type,
|
||||||
// Require the type to be more indented than the name
|
// Require the type to be more indented than the name
|
||||||
type_annotation::located_help(start_column + 1, true)
|
type_annotation::located(start_column + 1, true)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -1463,8 +1527,8 @@ fn parse_expr_operator<'a>(
|
||||||
state,
|
state,
|
||||||
spaces_after_operator,
|
spaces_after_operator,
|
||||||
match op {
|
match op {
|
||||||
BinOp::IsAliasType => TypeKind::Alias,
|
BinOp::IsAliasType => AliasOrOpaque::Alias,
|
||||||
BinOp::IsOpaqueType => TypeKind::Opaque,
|
BinOp::IsOpaqueType => AliasOrOpaque::Opaque,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -816,7 +816,7 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
specialize(
|
specialize(
|
||||||
ETypedIdent::Type,
|
ETypedIdent::Type,
|
||||||
type_annotation::located_help(min_indent, true)
|
type_annotation::located(min_indent, true)
|
||||||
),
|
),
|
||||||
min_indent,
|
min_indent,
|
||||||
ETypedIdent::IndentType,
|
ETypedIdent::IndentType,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
AssignedField, CommentOrNewline, HasClause, Pattern, Spaced, Tag, TypeAnnotation, TypeHeader,
|
AssignedField, CommentOrNewline, Derived, HasClause, Pattern, Spaced, Tag, TypeAnnotation,
|
||||||
|
TypeHeader,
|
||||||
};
|
};
|
||||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||||
use crate::ident::lowercase_ident;
|
use crate::ident::lowercase_ident;
|
||||||
|
@ -15,19 +16,29 @@ use bumpalo::collections::vec::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_region::all::{Loc, Position, Region};
|
use roc_region::all::{Loc, Position, Region};
|
||||||
|
|
||||||
pub fn located_help<'a>(
|
pub fn located<'a>(
|
||||||
min_indent: u32,
|
min_indent: u32,
|
||||||
is_trailing_comma_valid: bool,
|
is_trailing_comma_valid: bool,
|
||||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||||
expression(min_indent, is_trailing_comma_valid)
|
expression(min_indent, is_trailing_comma_valid, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn located_opaque_signature<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
is_trailing_comma_valid: bool,
|
||||||
|
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||||
|
expression(min_indent, is_trailing_comma_valid, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn tag_union_type<'a>(min_indent: u32) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> {
|
fn tag_union_type<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
stop_at_surface_has: bool,
|
||||||
|
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> {
|
||||||
move |arena, state| {
|
move |arena, state| {
|
||||||
let (_, tags, state) = collection_trailing_sep_e!(
|
let (_, tags, state) = collection_trailing_sep_e!(
|
||||||
word1(b'[', ETypeTagUnion::Open),
|
word1(b'[', ETypeTagUnion::Open),
|
||||||
loc!(tag_type(min_indent)),
|
loc!(tag_type(min_indent, false)),
|
||||||
word1(b',', ETypeTagUnion::End),
|
word1(b',', ETypeTagUnion::End),
|
||||||
word1(b']', ETypeTagUnion::End),
|
word1(b']', ETypeTagUnion::End),
|
||||||
min_indent,
|
min_indent,
|
||||||
|
@ -40,7 +51,7 @@ fn tag_union_type<'a>(min_indent: u32) -> impl Parser<'a, TypeAnnotation<'a>, ET
|
||||||
// This could be an open tag union, e.g. `[ Foo, Bar ]a`
|
// This could be an open tag union, e.g. `[ Foo, Bar ]a`
|
||||||
let (_, ext, state) = optional(allocated(specialize_ref(
|
let (_, ext, state) = optional(allocated(specialize_ref(
|
||||||
ETypeTagUnion::Type,
|
ETypeTagUnion::Type,
|
||||||
term(min_indent),
|
term(min_indent, stop_at_surface_has),
|
||||||
)))
|
)))
|
||||||
.parse(arena, state)?;
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
@ -90,7 +101,7 @@ fn check_type_alias(
|
||||||
|
|
||||||
fn parse_type_alias_after_as<'a>(min_indent: u32) -> impl Parser<'a, TypeHeader<'a>, EType<'a>> {
|
fn parse_type_alias_after_as<'a>(min_indent: u32) -> impl Parser<'a, TypeHeader<'a>, EType<'a>> {
|
||||||
move |arena, state| {
|
move |arena, state| {
|
||||||
space0_before_e(term(min_indent), min_indent, EType::TAsIndentStart)
|
space0_before_e(term(min_indent, false), min_indent, EType::TAsIndentStart)
|
||||||
.parse(arena, state)
|
.parse(arena, state)
|
||||||
.and_then(|(p, annot, state)| {
|
.and_then(|(p, annot, state)| {
|
||||||
specialize(EType::TInlineAlias, check_type_alias(p, annot)).parse(arena, state)
|
specialize(EType::TInlineAlias, check_type_alias(p, annot)).parse(arena, state)
|
||||||
|
@ -102,17 +113,26 @@ 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))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn term<'a>(min_indent: u32) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
fn term<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
stop_at_surface_has: bool,
|
||||||
|
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||||
map_with_arena!(
|
map_with_arena!(
|
||||||
and!(
|
and!(
|
||||||
one_of!(
|
one_of!(
|
||||||
loc_wildcard(),
|
loc_wildcard(),
|
||||||
loc_inferred(),
|
loc_inferred(),
|
||||||
specialize(EType::TInParens, loc_type_in_parens(min_indent)),
|
specialize(EType::TInParens, loc_type_in_parens(min_indent)),
|
||||||
loc!(specialize(EType::TRecord, record_type(min_indent))),
|
loc!(specialize(
|
||||||
loc!(specialize(EType::TTagUnion, tag_union_type(min_indent))),
|
EType::TRecord,
|
||||||
loc!(applied_type(min_indent)),
|
record_type(min_indent, stop_at_surface_has)
|
||||||
loc!(parse_type_variable),
|
)),
|
||||||
|
loc!(specialize(
|
||||||
|
EType::TTagUnion,
|
||||||
|
tag_union_type(min_indent, stop_at_surface_has)
|
||||||
|
)),
|
||||||
|
loc!(applied_type(min_indent, stop_at_surface_has)),
|
||||||
|
loc!(parse_type_variable(stop_at_surface_has)),
|
||||||
fail_type_start(),
|
fail_type_start(),
|
||||||
),
|
),
|
||||||
// Inline alias notation, e.g. [ Nil, Cons a (List a) ] as List a
|
// Inline alias notation, e.g. [ Nil, Cons a (List a) ] as List a
|
||||||
|
@ -163,7 +183,10 @@ fn loc_inferred<'a>() -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loc_applied_arg<'a>(min_indent: u32) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
fn loc_applied_arg<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
stop_at_surface_has: bool,
|
||||||
|
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||||
use crate::ast::Spaceable;
|
use crate::ast::Spaceable;
|
||||||
|
|
||||||
map_with_arena!(
|
map_with_arena!(
|
||||||
|
@ -173,10 +196,16 @@ fn loc_applied_arg<'a>(min_indent: u32) -> impl Parser<'a, Loc<TypeAnnotation<'a
|
||||||
loc_wildcard(),
|
loc_wildcard(),
|
||||||
loc_inferred(),
|
loc_inferred(),
|
||||||
specialize(EType::TInParens, loc_type_in_parens(min_indent)),
|
specialize(EType::TInParens, loc_type_in_parens(min_indent)),
|
||||||
loc!(specialize(EType::TRecord, record_type(min_indent))),
|
loc!(specialize(
|
||||||
loc!(specialize(EType::TTagUnion, tag_union_type(min_indent))),
|
EType::TRecord,
|
||||||
|
record_type(min_indent, stop_at_surface_has)
|
||||||
|
)),
|
||||||
|
loc!(specialize(
|
||||||
|
EType::TTagUnion,
|
||||||
|
tag_union_type(min_indent, stop_at_surface_has)
|
||||||
|
)),
|
||||||
loc!(specialize(EType::TApply, parse_concrete_type)),
|
loc!(specialize(EType::TApply, parse_concrete_type)),
|
||||||
loc!(parse_type_variable)
|
loc!(parse_type_variable(stop_at_surface_has))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|arena: &'a Bump, (spaces, argument): (&'a [_], Loc<TypeAnnotation<'a>>)| {
|
|arena: &'a Bump, (spaces, argument): (&'a [_], Loc<TypeAnnotation<'a>>)| {
|
||||||
|
@ -196,8 +225,11 @@ fn loc_type_in_parens<'a>(
|
||||||
between!(
|
between!(
|
||||||
word1(b'(', ETypeInParens::Open),
|
word1(b'(', ETypeInParens::Open),
|
||||||
space0_around_ee(
|
space0_around_ee(
|
||||||
move |arena, state| specialize_ref(ETypeInParens::Type, expression(min_indent, true))
|
move |arena, state| specialize_ref(
|
||||||
.parse(arena, state),
|
ETypeInParens::Type,
|
||||||
|
expression(min_indent, true, false)
|
||||||
|
)
|
||||||
|
.parse(arena, state),
|
||||||
min_indent,
|
min_indent,
|
||||||
ETypeInParens::IndentOpen,
|
ETypeInParens::IndentOpen,
|
||||||
ETypeInParens::IndentEnd,
|
ETypeInParens::IndentEnd,
|
||||||
|
@ -207,12 +239,18 @@ fn loc_type_in_parens<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn tag_type<'a>(min_indent: u32) -> impl Parser<'a, Tag<'a>, ETypeTagUnion<'a>> {
|
fn tag_type<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
stop_at_surface_has: bool,
|
||||||
|
) -> impl Parser<'a, Tag<'a>, ETypeTagUnion<'a>> {
|
||||||
move |arena, state: State<'a>| {
|
move |arena, state: State<'a>| {
|
||||||
let (_, name, state) = loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state)?;
|
let (_, name, state) = loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state)?;
|
||||||
|
|
||||||
let (_, args, state) = specialize_ref(ETypeTagUnion::Type, loc_applied_args_e(min_indent))
|
let (_, args, state) = specialize_ref(
|
||||||
.parse(arena, state)?;
|
ETypeTagUnion::Type,
|
||||||
|
loc_applied_args_e(min_indent, stop_at_surface_has),
|
||||||
|
)
|
||||||
|
.parse(arena, state)?;
|
||||||
|
|
||||||
let result = Tag::Apply {
|
let result = Tag::Apply {
|
||||||
name,
|
name,
|
||||||
|
@ -262,7 +300,7 @@ fn record_type_field<'a>(
|
||||||
))
|
))
|
||||||
.parse(arena, state)?;
|
.parse(arena, state)?;
|
||||||
|
|
||||||
let val_parser = specialize_ref(ETypeRecord::Type, expression(min_indent, true));
|
let val_parser = specialize_ref(ETypeRecord::Type, expression(min_indent, true, false));
|
||||||
|
|
||||||
match opt_loc_val {
|
match opt_loc_val {
|
||||||
Some(First(_)) => {
|
Some(First(_)) => {
|
||||||
|
@ -304,7 +342,10 @@ fn record_type_field<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn record_type<'a>(min_indent: u32) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> {
|
fn record_type<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
stop_at_surface_has: bool,
|
||||||
|
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> {
|
||||||
use crate::type_annotation::TypeAnnotation::*;
|
use crate::type_annotation::TypeAnnotation::*;
|
||||||
|
|
||||||
(move |arena, state| {
|
(move |arena, state| {
|
||||||
|
@ -322,7 +363,7 @@ fn record_type<'a>(min_indent: u32) -> impl Parser<'a, TypeAnnotation<'a>, EType
|
||||||
)
|
)
|
||||||
.parse(arena, state)?;
|
.parse(arena, state)?;
|
||||||
|
|
||||||
let field_term = specialize_ref(ETypeRecord::Type, term(min_indent));
|
let field_term = specialize_ref(ETypeRecord::Type, term(min_indent, stop_at_surface_has));
|
||||||
let (_, ext, state) = optional(allocated(field_term)).parse(arena, state)?;
|
let (_, ext, state) = optional(allocated(field_term)).parse(arena, state)?;
|
||||||
|
|
||||||
let result = Record { fields, ext };
|
let result = Record { fields, ext };
|
||||||
|
@ -332,13 +373,16 @@ fn record_type<'a>(min_indent: u32) -> impl Parser<'a, TypeAnnotation<'a>, EType
|
||||||
.trace("type_annotation:record_type")
|
.trace("type_annotation:record_type")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn applied_type<'a>(min_indent: u32) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
|
fn applied_type<'a>(
|
||||||
|
min_indent: u32,
|
||||||
|
stop_at_surface_has: bool,
|
||||||
|
) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
|
||||||
map!(
|
map!(
|
||||||
and!(
|
and!(
|
||||||
specialize(EType::TApply, parse_concrete_type),
|
specialize(EType::TApply, parse_concrete_type),
|
||||||
// Optionally parse space-separated arguments for the constructor,
|
// Optionally parse space-separated arguments for the constructor,
|
||||||
// e.g. `Str Float` in `Map Str Float`
|
// e.g. `Str Float` in `Map Str Float`
|
||||||
loc_applied_args_e(min_indent)
|
loc_applied_args_e(min_indent, stop_at_surface_has)
|
||||||
),
|
),
|
||||||
|(ctor, args): (TypeAnnotation<'a>, Vec<'a, Loc<TypeAnnotation<'a>>>)| {
|
|(ctor, args): (TypeAnnotation<'a>, Vec<'a, Loc<TypeAnnotation<'a>>>)| {
|
||||||
match &ctor {
|
match &ctor {
|
||||||
|
@ -360,8 +404,9 @@ fn applied_type<'a>(min_indent: u32) -> impl Parser<'a, TypeAnnotation<'a>, ETyp
|
||||||
|
|
||||||
fn loc_applied_args_e<'a>(
|
fn loc_applied_args_e<'a>(
|
||||||
min_indent: u32,
|
min_indent: u32,
|
||||||
|
stop_at_surface_has: bool,
|
||||||
) -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, EType<'a>> {
|
) -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, EType<'a>> {
|
||||||
zero_or_more!(loc_applied_arg(min_indent))
|
zero_or_more!(loc_applied_arg(min_indent, stop_at_surface_has))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_clause<'a>(min_indent: u32) -> impl Parser<'a, Loc<HasClause<'a>>, EType<'a>> {
|
fn has_clause<'a>(min_indent: u32) -> impl Parser<'a, Loc<HasClause<'a>>, EType<'a>> {
|
||||||
|
@ -433,20 +478,51 @@ fn has_clause_chain<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a has-derived clause, e.g. `has [ Eq, Hash ]`.
|
||||||
|
pub fn has_derived<'a>(min_indent: u32) -> impl Parser<'a, Loc<Derived<'a>>, EType<'a>> {
|
||||||
|
skip_first!(
|
||||||
|
// Parse "has"; we don't care about this keyword
|
||||||
|
word3(b'h', b'a', b's', EType::THasClause),
|
||||||
|
// Parse "Hash"; this may be qualified from another module like "Hash.Hash"
|
||||||
|
space0_before_e(
|
||||||
|
loc!(map!(
|
||||||
|
collection_trailing_sep_e!(
|
||||||
|
word1(b'[', EType::TStart),
|
||||||
|
specialize(EType::TApply, loc!(parse_concrete_type)),
|
||||||
|
word1(b',', EType::TEnd),
|
||||||
|
word1(b']', EType::TEnd),
|
||||||
|
min_indent + 1,
|
||||||
|
EType::TStart,
|
||||||
|
EType::TIndentEnd,
|
||||||
|
TypeAnnotation::SpaceBefore
|
||||||
|
),
|
||||||
|
Derived::Has
|
||||||
|
)),
|
||||||
|
min_indent + 1,
|
||||||
|
EType::TIndentEnd
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn expression<'a>(
|
fn expression<'a>(
|
||||||
min_indent: u32,
|
min_indent: u32,
|
||||||
is_trailing_comma_valid: bool,
|
is_trailing_comma_valid: bool,
|
||||||
|
stop_at_surface_has: bool,
|
||||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||||
(move |arena, state: State<'a>| {
|
(move |arena, state: State<'a>| {
|
||||||
let (p1, first, state) = space0_before_e(term(min_indent), min_indent, EType::TIndentStart)
|
let (p1, first, state) = space0_before_e(
|
||||||
.parse(arena, state)?;
|
term(min_indent, stop_at_surface_has),
|
||||||
|
min_indent,
|
||||||
|
EType::TIndentStart,
|
||||||
|
)
|
||||||
|
.parse(arena, state)?;
|
||||||
|
|
||||||
let result = and![
|
let result = and![
|
||||||
zero_or_more!(skip_first!(
|
zero_or_more!(skip_first!(
|
||||||
word1(b',', EType::TFunctionArgument),
|
word1(b',', EType::TFunctionArgument),
|
||||||
one_of![
|
one_of![
|
||||||
space0_around_ee(
|
space0_around_ee(
|
||||||
term(min_indent),
|
term(min_indent, stop_at_surface_has),
|
||||||
min_indent,
|
min_indent,
|
||||||
EType::TIndentStart,
|
EType::TIndentStart,
|
||||||
EType::TIndentEnd
|
EType::TIndentEnd
|
||||||
|
@ -471,9 +547,12 @@ fn expression<'a>(
|
||||||
|
|
||||||
let (progress, annot, state) = match result {
|
let (progress, annot, state) = match result {
|
||||||
Ok((p2, (rest, _dropped_spaces), state)) => {
|
Ok((p2, (rest, _dropped_spaces), state)) => {
|
||||||
let (p3, return_type, state) =
|
let (p3, return_type, state) = space0_before_e(
|
||||||
space0_before_e(term(min_indent), min_indent, EType::TIndentStart)
|
term(min_indent, stop_at_surface_has),
|
||||||
.parse(arena, state)?;
|
min_indent,
|
||||||
|
EType::TIndentStart,
|
||||||
|
)
|
||||||
|
.parse(arena, state)?;
|
||||||
|
|
||||||
let region = Region::span_across(&first.region, &return_type.region);
|
let region = Region::span_across(&first.region, &return_type.region);
|
||||||
|
|
||||||
|
@ -590,14 +669,17 @@ fn parse_concrete_type<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_type_variable<'a>(
|
fn parse_type_variable<'a>(
|
||||||
arena: &'a Bump,
|
stop_at_surface_has: bool,
|
||||||
state: State<'a>,
|
) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
|
||||||
) -> ParseResult<'a, TypeAnnotation<'a>, EType<'a>> {
|
move |arena, state: State<'a>| match crate::ident::lowercase_ident().parse(arena, state) {
|
||||||
match crate::ident::lowercase_ident().parse(arena, state) {
|
|
||||||
Ok((_, name, state)) => {
|
Ok((_, name, state)) => {
|
||||||
let answer = TypeAnnotation::BoundVariable(name);
|
if name == "has" && stop_at_surface_has {
|
||||||
|
Err((NoProgress, EType::TEnd(state.pos()), state))
|
||||||
|
} else {
|
||||||
|
let answer = TypeAnnotation::BoundVariable(name);
|
||||||
|
|
||||||
Ok((MadeProgress, answer, state))
|
Ok((MadeProgress, answer, state))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err((progress, _, state)) => Err((progress, EType::TBadTypeVariable(state.pos()), state)),
|
Err((progress, _, state)) => Err((progress, EType::TBadTypeVariable(state.pos()), state)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
Defs(
|
||||||
|
[
|
||||||
|
@0-7 Type(
|
||||||
|
Opaque {
|
||||||
|
header: TypeHeader {
|
||||||
|
name: @0-1 "A",
|
||||||
|
vars: [],
|
||||||
|
},
|
||||||
|
typ: @5-7 Apply(
|
||||||
|
"",
|
||||||
|
"U8",
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
derived: Some(
|
||||||
|
@12-22 Has(
|
||||||
|
[
|
||||||
|
@13-15 Apply(
|
||||||
|
"",
|
||||||
|
"Eq",
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
@17-21 Apply(
|
||||||
|
"",
|
||||||
|
"Hash",
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
@24-44 SpaceBefore(
|
||||||
|
Type(
|
||||||
|
Opaque {
|
||||||
|
header: TypeHeader {
|
||||||
|
name: @24-25 "A",
|
||||||
|
vars: [],
|
||||||
|
},
|
||||||
|
typ: @29-44 Where(
|
||||||
|
@29-30 BoundVariable(
|
||||||
|
"a",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
@33-44 HasClause {
|
||||||
|
var: @33-34 "a",
|
||||||
|
ability: @39-44 Apply(
|
||||||
|
"",
|
||||||
|
"Other",
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
derived: Some(
|
||||||
|
@49-59 Has(
|
||||||
|
[
|
||||||
|
@50-52 Apply(
|
||||||
|
"",
|
||||||
|
"Eq",
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
@54-58 Apply(
|
||||||
|
"",
|
||||||
|
"Hash",
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
@61-81 SpaceBefore(
|
||||||
|
Type(
|
||||||
|
Opaque {
|
||||||
|
header: TypeHeader {
|
||||||
|
name: @61-62 "A",
|
||||||
|
vars: [],
|
||||||
|
},
|
||||||
|
typ: @66-81 Where(
|
||||||
|
@66-67 BoundVariable(
|
||||||
|
"a",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
@70-81 HasClause {
|
||||||
|
var: @70-71 "a",
|
||||||
|
ability: @76-81 Apply(
|
||||||
|
"",
|
||||||
|
"Other",
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
derived: Some(
|
||||||
|
@91-101 SpaceBefore(
|
||||||
|
Has(
|
||||||
|
[
|
||||||
|
@92-94 Apply(
|
||||||
|
"",
|
||||||
|
"Eq",
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
@96-100 Apply(
|
||||||
|
"",
|
||||||
|
"Hash",
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
@103-104 SpaceBefore(
|
||||||
|
Num(
|
||||||
|
"0",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
A := U8 has [Eq, Hash]
|
||||||
|
|
||||||
|
A := a | a has Other has [Eq, Hash]
|
||||||
|
|
||||||
|
A := a | a has Other
|
||||||
|
has [Eq, Hash]
|
||||||
|
|
||||||
|
0
|
|
@ -12,6 +12,7 @@
|
||||||
"U8",
|
"U8",
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
|
derived: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[],
|
[],
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
],
|
],
|
||||||
ext: None,
|
ext: None,
|
||||||
},
|
},
|
||||||
|
derived: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[],
|
[],
|
||||||
|
|
|
@ -211,6 +211,7 @@ mod test_parse {
|
||||||
pass/one_minus_two.expr,
|
pass/one_minus_two.expr,
|
||||||
pass/one_plus_two.expr,
|
pass/one_plus_two.expr,
|
||||||
pass/one_spaced_def.expr,
|
pass/one_spaced_def.expr,
|
||||||
|
pass/opaque_has_abilities.expr,
|
||||||
pass/opaque_simple.module,
|
pass/opaque_simple.module,
|
||||||
pass/opaque_with_type_arguments.module,
|
pass/opaque_with_type_arguments.module,
|
||||||
pass/opaque_reference_expr.expr,
|
pass/opaque_reference_expr.expr,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue