diff --git a/ast/src/lang/core/def/def.rs b/ast/src/lang/core/def/def.rs index 3f5b38a1e4..46dc57f072 100644 --- a/ast/src/lang/core/def/def.rs +++ b/ast/src/lang/core/def/def.rs @@ -16,7 +16,7 @@ use roc_collections::all::{default_hasher, ImMap, MutMap, MutSet, SendMap}; use roc_error_macros::{todo_abilities, todo_opaques}; use roc_module::ident::Lowercase; use roc_module::symbol::Symbol; -use roc_parse::ast::{self, TypeHeader}; +use roc_parse::ast::{self, TypeDef, TypeHeader, ValueDef as AstValueDef}; use roc_parse::pattern::PatternType; use roc_problem::can::{Problem, RuntimeError}; use roc_region::all::{Loc, Region}; @@ -133,7 +133,7 @@ fn to_pending_def<'a>( use roc_parse::ast::Def::*; match def { - Annotation(loc_pattern, loc_ann) => { + Value(AstValueDef::Annotation(loc_pattern, loc_ann)) => { // This takes care of checking for shadowing and adding idents to scope. let (output, loc_can_pattern) = pattern::to_pattern_id( env, @@ -148,7 +148,7 @@ fn to_pending_def<'a>( PendingDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann), )) } - Body(loc_pattern, loc_expr) => { + Value(AstValueDef::Body(loc_pattern, loc_expr)) => { // This takes care of checking for shadowing and adding idents to scope. let (output, loc_can_pattern) = pattern::to_pattern_id( env, @@ -164,13 +164,13 @@ fn to_pending_def<'a>( )) } - AnnotatedBody { + Value(AstValueDef::AnnotatedBody { ann_pattern, ann_type, comment: _, body_pattern, body_expr, - } => { + }) => { if ann_pattern.value.equivalent(&body_pattern.value) { // NOTE: Pick the body pattern, picking the annotation one is // incorrect in the presence of optional record fields! @@ -199,10 +199,10 @@ fn to_pending_def<'a>( } } - roc_parse::ast::Def::Alias { + Type(TypeDef::Alias { header: TypeHeader { name, vars }, ann, - } => { + }) => { let region = Region::span_across(&name.region, &ann.region); match scope.introduce( @@ -261,10 +261,10 @@ fn to_pending_def<'a>( } } - Opaque { .. } => todo_opaques!(), - Ability { .. } => todo_abilities!(), + Type(TypeDef::Opaque { .. }) => todo_opaques!(), + Type(TypeDef::Ability { .. }) => todo_abilities!(), - Expect(_) => todo!(), + Value(AstValueDef::Expect(_)) => todo!(), SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) => { to_pending_def(env, sub_def, scope, pattern_type) @@ -608,7 +608,7 @@ fn canonicalize_pending_def<'a>( pattern_id: loc_can_pattern, expr_id: env.pool.add(loc_can_expr), type_id: annotation, - rigids: rigids, + rigids, expr_var: env.var_store.fresh(), }; diff --git a/ast/src/lang/core/def/def_to_def2.rs b/ast/src/lang/core/def/def_to_def2.rs index 96e974550a..d628e5c64d 100644 --- a/ast/src/lang/core/def/def_to_def2.rs +++ b/ast/src/lang/core/def/def_to_def2.rs @@ -72,7 +72,7 @@ pub fn def_to_def2<'a>( def_to_def2(arena, env, scope, inner_def, region) } } - Body(&loc_pattern, &loc_expr) => { + Value(roc_parse::ast::ValueDef::Body(&loc_pattern, &loc_expr)) => { let expr2 = loc_expr_to_expr2(arena, loc_expr, env, scope, region).0; let expr_id = env.pool.add(expr2); diff --git a/cli/src/format.rs b/cli/src/format.rs index b8d2340412..ea77c5f1dc 100644 --- a/cli/src/format.rs +++ b/cli/src/format.rs @@ -11,7 +11,7 @@ use roc_fmt::Buf; use roc_module::called_via::{BinOp, UnaryOp}; use roc_parse::ast::{ AbilityMember, AssignedField, Collection, Expr, Has, HasClause, Pattern, Spaced, StrLiteral, - StrSegment, Tag, TypeAnnotation, TypeHeader, WhenBranch, + StrSegment, Tag, TypeAnnotation, TypeDef, TypeHeader, ValueDef, WhenBranch, }; use roc_parse::header::{ AppHeader, ExposedName, HostedHeader, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry, @@ -445,54 +445,36 @@ impl<'a, T: RemoveSpaces<'a>> RemoveSpaces<'a> for &'a T { } } -impl<'a> RemoveSpaces<'a> for Def<'a> { +impl<'a> RemoveSpaces<'a> for TypeDef<'a> { fn remove_spaces(&self, arena: &'a Bump) -> Self { + use TypeDef::*; + match *self { - Def::Annotation(a, b) => { - Def::Annotation(a.remove_spaces(arena), b.remove_spaces(arena)) - } - Def::Alias { + Alias { header: TypeHeader { name, vars }, ann, - } => Def::Alias { + } => Alias { header: TypeHeader { name: name.remove_spaces(arena), vars: vars.remove_spaces(arena), }, ann: ann.remove_spaces(arena), }, - Def::Opaque { + Opaque { header: TypeHeader { name, vars }, typ, - } => Def::Opaque { + } => Opaque { header: TypeHeader { name: name.remove_spaces(arena), vars: vars.remove_spaces(arena), }, typ: typ.remove_spaces(arena), }, - Def::Body(a, b) => Def::Body( - arena.alloc(a.remove_spaces(arena)), - arena.alloc(b.remove_spaces(arena)), - ), - Def::AnnotatedBody { - ann_pattern, - ann_type, - comment: _, - body_pattern, - body_expr, - } => Def::AnnotatedBody { - ann_pattern: arena.alloc(ann_pattern.remove_spaces(arena)), - ann_type: arena.alloc(ann_type.remove_spaces(arena)), - comment: None, - body_pattern: arena.alloc(body_pattern.remove_spaces(arena)), - body_expr: arena.alloc(body_expr.remove_spaces(arena)), - }, - Def::Ability { + Ability { header: TypeHeader { name, vars }, loc_has, members, - } => Def::Ability { + } => Ability { header: TypeHeader { name: name.remove_spaces(arena), vars: vars.remove_spaces(arena), @@ -500,7 +482,43 @@ impl<'a> RemoveSpaces<'a> for Def<'a> { loc_has: loc_has.remove_spaces(arena), members: members.remove_spaces(arena), }, - Def::Expect(a) => Def::Expect(arena.alloc(a.remove_spaces(arena))), + } + } +} + +impl<'a> RemoveSpaces<'a> for ValueDef<'a> { + fn remove_spaces(&self, arena: &'a Bump) -> Self { + use ValueDef::*; + + match *self { + Annotation(a, b) => Annotation(a.remove_spaces(arena), b.remove_spaces(arena)), + Body(a, b) => Body( + arena.alloc(a.remove_spaces(arena)), + arena.alloc(b.remove_spaces(arena)), + ), + AnnotatedBody { + ann_pattern, + ann_type, + comment: _, + body_pattern, + body_expr, + } => AnnotatedBody { + ann_pattern: arena.alloc(ann_pattern.remove_spaces(arena)), + ann_type: arena.alloc(ann_type.remove_spaces(arena)), + comment: None, + body_pattern: arena.alloc(body_pattern.remove_spaces(arena)), + body_expr: arena.alloc(body_expr.remove_spaces(arena)), + }, + Expect(a) => Expect(arena.alloc(a.remove_spaces(arena))), + } + } +} + +impl<'a> RemoveSpaces<'a> for Def<'a> { + fn remove_spaces(&self, arena: &'a Bump) -> Self { + match *self { + Def::Type(def) => Def::Type(def.remove_spaces(arena)), + Def::Value(def) => Def::Value(def.remove_spaces(arena)), Def::NotYetImplemented(a) => Def::NotYetImplemented(a), Def::SpaceBefore(a, _) | Def::SpaceAfter(a, _) => a.remove_spaces(arena), } diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index 23321bf361..6815fca412 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -49,11 +49,12 @@ pub struct CanDefs { pub can_defs_by_symbol: MutMap, pub aliases: SendMap, } + /// A Def that has had patterns and type annnotations canonicalized, /// but no Expr canonicalization has happened yet. Also, it has had spaces /// and nesting resolved, and knows whether annotations are standalone or not. #[derive(Debug, Clone, PartialEq)] -enum PendingDef<'a> { +enum PendingValueDef<'a> { /// A standalone annotation with no body AnnotationOnly( &'a Loc>, @@ -73,7 +74,10 @@ enum PendingDef<'a> { &'a Loc>, &'a Loc>, ), +} +#[derive(Debug, Clone, PartialEq)] +enum PendingTypeDef<'a> { /// A structural or opaque type alias, e.g. `Ints : List Int` or `Age := U32` respectively. Alias { name: Loc, @@ -206,56 +210,40 @@ pub fn canonicalize_defs<'a>( let num_defs = loc_defs.len(); let mut refs_by_symbol = MutMap::default(); let mut can_defs_by_symbol = HashMap::with_capacity_and_hasher(num_defs, default_hasher()); - let mut pending = Vec::with_capacity(num_defs); // TODO bump allocate this! - // Canonicalize all the patterns, record shadowing problems, and store - // the ast::Expr values in pending_exprs for further canonicalization - // once we've finished assembling the entire scope. + let mut type_defs = Vec::with_capacity(num_defs); + let mut value_defs = Vec::with_capacity(num_defs); + for loc_def in loc_defs { - match to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type) { - None => (), - Some((new_output, pending_def)) => { - // store the top-level defs, used to ensure that closures won't capture them - if let PatternType::TopLevelDef = pattern_type { - match &pending_def { - PendingDef::AnnotationOnly(_, loc_can_pattern, _) - | PendingDef::Body(_, loc_can_pattern, _) - | PendingDef::TypedBody(_, loc_can_pattern, _, _) => { - env.top_level_symbols.extend( - bindings_from_patterns(std::iter::once(loc_can_pattern)) - .iter() - .map(|t| t.0), - ) - } - - // Type definitions aren't value definitions, so we don't need to do - // anything for them here. - PendingDef::Alias { .. } | PendingDef::InvalidAlias { .. } => {} - } - } - // Record the ast::Expr for later. We'll do another pass through these - // once we have the entire scope assembled. If we were to canonicalize - // the exprs right now, they wouldn't have symbols in scope from defs - // that get would have gotten added later in the defs list! - pending.push(pending_def); - output.union(new_output); - } + match loc_def.value.unroll_def() { + Ok(type_def) => type_defs.push(Loc::at(loc_def.region, type_def)), + Err(value_def) => value_defs.push(Loc::at(loc_def.region, value_def)), } } + // We need to canonicalize all the type defs first. + let pending_type_defs = type_defs + .into_iter() + .filter_map(|loc_def| { + to_pending_type_def(env, &loc_def.value, &mut scope).map(|(new_output, pending_def)| { + output.union(new_output); + pending_def + }) + }) + .collect::>(); + if cfg!(debug_assertions) { env.home.register_debug_idents(&env.ident_ids); } let mut aliases = SendMap::default(); - let mut value_defs = Vec::new(); let mut alias_defs = MutMap::default(); let mut referenced_type_symbols = MutMap::default(); - for pending_def in pending.into_iter() { + for pending_def in pending_type_defs.into_iter() { match pending_def { - PendingDef::Alias { + PendingTypeDef::Alias { name, vars, ann, @@ -271,7 +259,7 @@ pub fn canonicalize_defs<'a>( alias_defs.insert(name.value, (name, vars, ann, kind)); } - other => value_defs.push(other), + PendingTypeDef::InvalidAlias { .. } => { /* ignore */ } } } @@ -373,8 +361,41 @@ pub fn canonicalize_defs<'a>( // Now that we have the scope completely assembled, and shadowing resolved, // we're ready to canonicalize any body exprs. - for pending_def in value_defs.into_iter() { - output = canonicalize_pending_def( + + // Canonicalize all the patterns, record shadowing problems, and store + // the ast::Expr values in pending_exprs for further canonicalization + // once we've finished assembling the entire scope. + let mut pending_value_defs = Vec::with_capacity(value_defs.len()); + for loc_def in value_defs.into_iter() { + match to_pending_value_def(env, var_store, &loc_def.value, &mut scope, pattern_type) { + None => { /* skip */ } + Some((new_output, pending_def)) => { + // store the top-level defs, used to ensure that closures won't capture them + if let PatternType::TopLevelDef = pattern_type { + match &pending_def { + PendingValueDef::AnnotationOnly(_, loc_can_pattern, _) + | PendingValueDef::Body(_, loc_can_pattern, _) + | PendingValueDef::TypedBody(_, loc_can_pattern, _, _) => { + env.top_level_symbols.extend( + bindings_from_patterns(std::iter::once(loc_can_pattern)) + .iter() + .map(|t| t.0), + ) + } + } + } + // Record the ast::Expr for later. We'll do another pass through these + // once we have the entire scope assembled. If we were to canonicalize + // the exprs right now, they wouldn't have symbols in scope from defs + // that get would have gotten added later in the defs list! + pending_value_defs.push(pending_def); + output.union(new_output); + } + } + } + + for pending_def in pending_value_defs.into_iter() { + output = canonicalize_pending_value_def( env, pending_def, output, @@ -910,9 +931,9 @@ fn add_annotation_aliases( // TODO trim down these arguments! #[allow(clippy::too_many_arguments)] #[allow(clippy::cognitive_complexity)] -fn canonicalize_pending_def<'a>( +fn canonicalize_pending_value_def<'a>( env: &mut Env<'a>, - pending_def: PendingDef<'a>, + pending_def: PendingValueDef<'a>, mut output: Output, scope: &mut Scope, can_defs_by_symbol: &mut MutMap, @@ -920,7 +941,7 @@ fn canonicalize_pending_def<'a>( refs_by_symbol: &mut MutMap, aliases: &mut ImMap, ) -> Output { - use PendingDef::*; + use PendingValueDef::*; // Make types for the body expr, even if we won't end up having a body. let expr_var = var_store.fresh(); @@ -1047,11 +1068,6 @@ fn canonicalize_pending_def<'a>( } } - Alias { .. } => unreachable!("Aliases are handled in a separate pass"), - - InvalidAlias { .. } => { - // invalid aliases and opaques (shadowed, incorrect patterns) get ignored - } TypedBody(_loc_pattern, loc_can_pattern, loc_ann, loc_expr) => { let type_annotation = canonicalize_annotation(env, scope, &loc_ann.value, loc_ann.region, var_store); @@ -1446,85 +1462,14 @@ fn closure_recursivity(symbol: Symbol, closures: &MutMap) -> Recursive::NotRecursive } -fn to_pending_def<'a>( +fn to_pending_type_def<'a>( env: &mut Env<'a>, - var_store: &mut VarStore, - def: &'a ast::Def<'a>, + def: &'a ast::TypeDef<'a>, scope: &mut Scope, - pattern_type: PatternType, -) -> Option<(Output, PendingDef<'a>)> { - use roc_parse::ast::Def::*; +) -> Option<(Output, PendingTypeDef<'a>)> { + use ast::TypeDef::*; match def { - Annotation(loc_pattern, loc_ann) => { - // This takes care of checking for shadowing and adding idents to scope. - let (output, loc_can_pattern) = canonicalize_pattern( - env, - var_store, - scope, - pattern_type, - &loc_pattern.value, - loc_pattern.region, - ); - - Some(( - output, - PendingDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann), - )) - } - Body(loc_pattern, loc_expr) => { - // This takes care of checking for shadowing and adding idents to scope. - let (output, loc_can_pattern) = canonicalize_pattern( - env, - var_store, - scope, - pattern_type, - &loc_pattern.value, - loc_pattern.region, - ); - - Some(( - output, - PendingDef::Body(loc_pattern, loc_can_pattern, loc_expr), - )) - } - - AnnotatedBody { - ann_pattern, - ann_type, - comment: _, - body_pattern, - body_expr, - } => { - if ann_pattern.value.equivalent(&body_pattern.value) { - // NOTE: Pick the body pattern, picking the annotation one is - // incorrect in the presence of optional record fields! - // - // { x, y } : { x : Int, y ? Bool }* - // { x, y ? False } = rec - Some(pending_typed_body( - env, - body_pattern, - ann_type, - body_expr, - var_store, - scope, - pattern_type, - )) - } else { - // the pattern of the annotation does not match the pattern of the body direc - env.problems.push(Problem::SignatureDefMismatch { - annotation_pattern: ann_pattern.region, - def_pattern: body_pattern.region, - }); - - // TODO: Should we instead build some PendingDef::InvalidAnnotatedBody ? This would - // remove the `Option` on this function (and be probably more reliable for further - // problem/error reporting) - None - } - } - Alias { header: TypeHeader { name, vars }, ann, @@ -1571,7 +1516,7 @@ fn to_pending_def<'a>( return Some(( Output::default(), - PendingDef::InvalidAlias { kind }, + PendingTypeDef::InvalidAlias { kind }, )); } } @@ -1582,7 +1527,7 @@ fn to_pending_def<'a>( value: symbol, }; - let pending_def = PendingDef::Alias { + let pending_def = PendingTypeDef::Alias { name, vars: can_rigids, ann, @@ -1598,20 +1543,12 @@ fn to_pending_def<'a>( shadow: loc_shadowed_symbol, }); - Some((Output::default(), PendingDef::InvalidAlias { kind })) + Some((Output::default(), PendingTypeDef::InvalidAlias { kind })) } } } Ability { .. } => todo_abilities!(), - - Expect(_condition) => todo!(), - - SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) => { - to_pending_def(env, var_store, sub_def, scope, pattern_type) - } - - NotYetImplemented(s) => todo!("{}", s), } } @@ -1623,7 +1560,7 @@ fn pending_typed_body<'a>( var_store: &mut VarStore, scope: &mut Scope, pattern_type: PatternType, -) -> (Output, PendingDef<'a>) { +) -> (Output, PendingValueDef<'a>) { // This takes care of checking for shadowing and adding idents to scope. let (output, loc_can_pattern) = canonicalize_pattern( env, @@ -1636,10 +1573,93 @@ fn pending_typed_body<'a>( ( output, - PendingDef::TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr), + PendingValueDef::TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr), ) } +fn to_pending_value_def<'a>( + env: &mut Env<'a>, + var_store: &mut VarStore, + def: &'a ast::ValueDef<'a>, + scope: &mut Scope, + pattern_type: PatternType, +) -> Option<(Output, PendingValueDef<'a>)> { + use ast::ValueDef::*; + + match def { + Annotation(loc_pattern, loc_ann) => { + // This takes care of checking for shadowing and adding idents to scope. + let (output, loc_can_pattern) = canonicalize_pattern( + env, + var_store, + scope, + pattern_type, + &loc_pattern.value, + loc_pattern.region, + ); + + Some(( + output, + PendingValueDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann), + )) + } + Body(loc_pattern, loc_expr) => { + // This takes care of checking for shadowing and adding idents to scope. + let (output, loc_can_pattern) = canonicalize_pattern( + env, + var_store, + scope, + pattern_type, + &loc_pattern.value, + loc_pattern.region, + ); + + Some(( + output, + PendingValueDef::Body(loc_pattern, loc_can_pattern, loc_expr), + )) + } + + AnnotatedBody { + ann_pattern, + ann_type, + comment: _, + body_pattern, + body_expr, + } => { + if ann_pattern.value.equivalent(&body_pattern.value) { + // NOTE: Pick the body pattern, picking the annotation one is + // incorrect in the presence of optional record fields! + // + // { x, y } : { x : Int, y ? Bool }* + // { x, y ? False } = rec + Some(pending_typed_body( + env, + body_pattern, + ann_type, + body_expr, + var_store, + scope, + pattern_type, + )) + } else { + // the pattern of the annotation does not match the pattern of the body direc + env.problems.push(Problem::SignatureDefMismatch { + annotation_pattern: ann_pattern.region, + def_pattern: body_pattern.region, + }); + + // TODO: Should we instead build some PendingValueDef::InvalidAnnotatedBody ? This would + // remove the `Option` on this function (and be probably more reliable for further + // problem/error reporting) + None + } + } + + Expect(_condition) => todo!(), + } +} + /// Make aliases recursive fn correct_mutual_recursive_type_alias<'a>( env: &mut Env<'a>, diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index bfd8e5725d..6bbb3d23b9 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -6,7 +6,7 @@ use roc_module::called_via::BinOp::Pizza; use roc_module::called_via::{BinOp, CalledVia}; use roc_module::ident::ModuleName; use roc_parse::ast::Expr::{self, *}; -use roc_parse::ast::{AssignedField, Def, WhenBranch}; +use roc_parse::ast::{AssignedField, Def, TypeDef, ValueDef, WhenBranch}; use roc_region::all::{Loc, Region}; // BinOp precedence logic adapted from Gluon by Markus Westerlind @@ -88,15 +88,21 @@ fn desugar_def_helps<'a>( }) } -pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> { - use roc_parse::ast::Def::*; +fn desugar_type_def<'a>(def: &'a TypeDef<'a>) -> TypeDef<'a> { + use TypeDef::*; match def { - Body(loc_pattern, loc_expr) => Body(loc_pattern, desugar_expr(arena, loc_expr)), - SpaceBefore(def, _) | SpaceAfter(def, _) => desugar_def(arena, def), alias @ Alias { .. } => *alias, opaque @ Opaque { .. } => *opaque, ability @ Ability { .. } => *ability, + } +} + +fn desugar_value_def<'a>(arena: &'a Bump, def: &'a ValueDef<'a>) -> ValueDef<'a> { + use ValueDef::*; + + match def { + Body(loc_pattern, loc_expr) => Body(loc_pattern, desugar_expr(arena, loc_expr)), ann @ Annotation(_, _) => *ann, AnnotatedBody { ann_pattern, @@ -115,6 +121,16 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> { let desugared_condition = &*arena.alloc(desugar_expr(arena, condition)); Expect(desugared_condition) } + } +} + +pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> { + use roc_parse::ast::Def::*; + + match def { + Type(type_def) => Type(desugar_type_def(type_def)), + Value(value_def) => Value(desugar_value_def(arena, value_def)), + SpaceBefore(def, _) | SpaceAfter(def, _) => desugar_def(arena, def), NotYetImplemented(s) => todo!("{}", s), } } diff --git a/compiler/fmt/src/def.rs b/compiler/fmt/src/def.rs index 4cf729a451..ca99d19110 100644 --- a/compiler/fmt/src/def.rs +++ b/compiler/fmt/src/def.rs @@ -9,20 +9,28 @@ use roc_region::all::Loc; impl<'a> Formattable for Def<'a> { fn is_multiline(&self) -> bool { use roc_parse::ast::Def::*; + use roc_parse::ast::TypeDef::*; + use roc_parse::ast::ValueDef::*; match self { - Alias { ann, .. } => ann.is_multiline(), - Opaque { typ, .. } => typ.is_multiline(), - Annotation(loc_pattern, loc_annotation) => { - loc_pattern.is_multiline() || loc_annotation.is_multiline() - } - Body(loc_pattern, loc_expr) => loc_pattern.is_multiline() || loc_expr.is_multiline(), - AnnotatedBody { .. } => true, - Expect(loc_expr) => loc_expr.is_multiline(), + Type(def) => match def { + Alias { ann, .. } => ann.is_multiline(), + Opaque { typ, .. } => typ.is_multiline(), + Ability { members, .. } => members.iter().any(|d| d.is_multiline()), + }, + Value(def) => match def { + Annotation(loc_pattern, loc_annotation) => { + loc_pattern.is_multiline() || loc_annotation.is_multiline() + } + Body(loc_pattern, loc_expr) => { + loc_pattern.is_multiline() || loc_expr.is_multiline() + } + AnnotatedBody { .. } => true, + Expect(loc_expr) => loc_expr.is_multiline(), + }, SpaceBefore(sub_def, spaces) | SpaceAfter(sub_def, spaces) => { spaces.iter().any(|s| s.is_comment()) || sub_def.is_multiline() } - Ability { members, .. } => members.iter().any(|d| d.is_multiline()), NotYetImplemented(s) => todo!("{}", s), } } @@ -35,104 +43,110 @@ impl<'a> Formattable for Def<'a> { indent: u16, ) { use roc_parse::ast::Def::*; + use roc_parse::ast::TypeDef::*; + use roc_parse::ast::ValueDef::*; match self { - Annotation(loc_pattern, loc_annotation) => { - loc_pattern.format(buf, indent); - if loc_annotation.is_multiline() { - buf.push_str(" :"); - loc_annotation.format_with_options( - buf, - Parens::NotNeeded, - Newlines::Yes, - indent + INDENT, - ); - } else { - buf.spaces(1); - buf.push_str(":"); - buf.spaces(1); - loc_annotation.format_with_options( - buf, - Parens::NotNeeded, - Newlines::No, - indent, - ); + Type(def) => match def { + Alias { + header: TypeHeader { name, vars }, + ann, } - } - Alias { - header: TypeHeader { name, vars }, - ann, - } - | Opaque { - header: TypeHeader { name, vars }, - typ: ann, - } => { - buf.indent(indent); - buf.push_str(name.value); + | Opaque { + header: TypeHeader { name, vars }, + typ: ann, + } => { + buf.indent(indent); + buf.push_str(name.value); - for var in *vars { + for var in *vars { + buf.spaces(1); + fmt_pattern(buf, &var.value, indent, Parens::NotNeeded); + } + + buf.push_str(match def { + Alias { .. } => " :", + Opaque { .. } => " :=", + _ => unreachable!(), + }); buf.spaces(1); - fmt_pattern(buf, &var.value, indent, Parens::NotNeeded); + + ann.format(buf, indent + INDENT) } + Ability { + header: TypeHeader { name, vars }, + loc_has: _, + members, + } => { + buf.indent(indent); + buf.push_str(name.value); + for var in *vars { + buf.spaces(1); + fmt_pattern(buf, &var.value, indent, Parens::NotNeeded); + } - buf.push_str(match self { - Alias { .. } => " :", - Opaque { .. } => " :=", - _ => unreachable!(), - }); - buf.spaces(1); + buf.push_str(" has"); - ann.format(buf, indent + INDENT) - } - Ability { - header: TypeHeader { name, vars }, - loc_has: _, - members, - } => { - buf.indent(indent); - buf.push_str(name.value); - for var in *vars { - buf.spaces(1); - fmt_pattern(buf, &var.value, indent, Parens::NotNeeded); - } - - buf.push_str(" has"); - - if !self.is_multiline() { - debug_assert_eq!(members.len(), 1); - buf.push_str(" "); - members[0].format(buf, indent + INDENT); - } else { - for demand in members.iter() { - buf.newline(); - buf.indent(indent + INDENT); - demand.format(buf, indent + INDENT); + if !self.is_multiline() { + debug_assert_eq!(members.len(), 1); + buf.push_str(" "); + members[0].format(buf, indent + INDENT); + } else { + for demand in members.iter() { + buf.newline(); + buf.indent(indent + INDENT); + demand.format(buf, indent + INDENT); + } } } - } - Body(loc_pattern, loc_expr) => { - fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent); - } - Expect(condition) => fmt_expect(buf, condition, self.is_multiline(), indent), - AnnotatedBody { - ann_pattern, - ann_type, - comment, - body_pattern, - body_expr, - } => { - ann_pattern.format(buf, indent); - buf.push_str(" :"); - buf.spaces(1); - ann_type.format(buf, indent); - if let Some(comment_str) = comment { - buf.push_str(" #"); - buf.spaces(1); - buf.push_str(comment_str.trim()); + }, + Value(def) => match def { + Annotation(loc_pattern, loc_annotation) => { + loc_pattern.format(buf, indent); + if loc_annotation.is_multiline() { + buf.push_str(" :"); + loc_annotation.format_with_options( + buf, + Parens::NotNeeded, + Newlines::Yes, + indent + INDENT, + ); + } else { + buf.spaces(1); + buf.push_str(":"); + buf.spaces(1); + loc_annotation.format_with_options( + buf, + Parens::NotNeeded, + Newlines::No, + indent, + ); + } } - buf.newline(); - fmt_body(buf, &body_pattern.value, &body_expr.value, indent); - } + Body(loc_pattern, loc_expr) => { + fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent); + } + Expect(condition) => fmt_expect(buf, condition, self.is_multiline(), indent), + AnnotatedBody { + ann_pattern, + ann_type, + comment, + body_pattern, + body_expr, + } => { + ann_pattern.format(buf, indent); + buf.push_str(" :"); + buf.spaces(1); + ann_type.format(buf, indent); + if let Some(comment_str) = comment { + buf.push_str(" #"); + buf.spaces(1); + buf.push_str(comment_str.trim()); + } + buf.newline(); + fmt_body(buf, &body_pattern.value, &body_expr.value, indent); + } + }, SpaceBefore(sub_def, spaces) => { fmt_spaces(buf, spaces.iter(), indent); diff --git a/compiler/load_internal/src/docs.rs b/compiler/load_internal/src/docs.rs index dd34893c43..0400a53533 100644 --- a/compiler/load_internal/src/docs.rs +++ b/compiler/load_internal/src/docs.rs @@ -7,9 +7,9 @@ use roc_can::scope::Scope; use roc_error_macros::todo_abilities; use roc_module::ident::ModuleName; use roc_module::symbol::IdentIds; -use roc_parse::ast::CommentOrNewline; use roc_parse::ast::{self, TypeHeader}; use roc_parse::ast::{AssignedField, Def}; +use roc_parse::ast::{CommentOrNewline, TypeDef, ValueDef}; use roc_region::all::Loc; // Documentation generation requirements @@ -166,98 +166,105 @@ fn generate_entry_doc<'a>( (new_acc, Some(comments_or_new_lines)) } - Def::Annotation(loc_pattern, loc_ann) => match loc_pattern.value { - Pattern::Identifier(identifier) => { - // Check if the definition is exposed - if ident_ids.get_id(&identifier.into()).is_some() { - let name = identifier.to_string(); - let doc_def = DocDef { - name, - type_annotation: type_to_docs(false, loc_ann.value), - type_vars: Vec::new(), - docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), - }; - acc.push(DocEntry::DocDef(doc_def)); + Def::Value(def) => match def { + ValueDef::Annotation(loc_pattern, loc_ann) => match loc_pattern.value { + Pattern::Identifier(identifier) => { + // Check if the definition is exposed + if ident_ids.get_id(&identifier.into()).is_some() { + let name = identifier.to_string(); + let doc_def = DocDef { + name, + type_annotation: type_to_docs(false, loc_ann.value), + type_vars: Vec::new(), + docs: before_comments_or_new_lines + .and_then(comments_or_new_lines_to_docs), + }; + acc.push(DocEntry::DocDef(doc_def)); + } + (acc, None) } + + _ => (acc, None), + }, + + ValueDef::AnnotatedBody { + ann_pattern, + ann_type, + .. + } => match ann_pattern.value { + Pattern::Identifier(identifier) => { + // Check if the definition is exposed + if ident_ids.get_id(&identifier.into()).is_some() { + let doc_def = DocDef { + name: identifier.to_string(), + type_annotation: type_to_docs(false, ann_type.value), + type_vars: Vec::new(), + docs: before_comments_or_new_lines + .and_then(comments_or_new_lines_to_docs), + }; + acc.push(DocEntry::DocDef(doc_def)); + } + (acc, None) + } + + _ => (acc, None), + }, + + ValueDef::Body(_, _) => (acc, None), + + ValueDef::Expect(c) => todo!("documentation for tests {:?}", c), + }, + + Def::Type(def) => match def { + TypeDef::Alias { + header: TypeHeader { name, vars }, + ann, + } => { + let mut type_vars = Vec::new(); + + for var in vars.iter() { + if let Pattern::Identifier(ident_name) = var.value { + type_vars.push(ident_name.to_string()); + } + } + + let doc_def = DocDef { + name: name.value.to_string(), + type_annotation: type_to_docs(false, ann.value), + type_vars, + docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), + }; + acc.push(DocEntry::DocDef(doc_def)); + (acc, None) } - _ => (acc, None), - }, - Def::AnnotatedBody { - ann_pattern, - ann_type, - .. - } => match ann_pattern.value { - Pattern::Identifier(identifier) => { - // Check if the definition is exposed - if ident_ids.get_id(&identifier.into()).is_some() { - let doc_def = DocDef { - name: identifier.to_string(), - type_annotation: type_to_docs(false, ann_type.value), - type_vars: Vec::new(), - docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), - }; - acc.push(DocEntry::DocDef(doc_def)); + TypeDef::Opaque { + header: TypeHeader { name, vars }, + .. + } => { + let mut type_vars = Vec::new(); + + for var in vars.iter() { + if let Pattern::Identifier(ident_name) = var.value { + type_vars.push(ident_name.to_string()); + } } + + let doc_def = DocDef { + name: name.value.to_string(), + type_annotation: TypeAnnotation::NoTypeAnn, + type_vars, + docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), + }; + acc.push(DocEntry::DocDef(doc_def)); + (acc, None) } - _ => (acc, None), + TypeDef::Ability { .. } => todo_abilities!(), }, - Def::Alias { - header: TypeHeader { name, vars }, - ann, - } => { - let mut type_vars = Vec::new(); - - for var in vars.iter() { - if let Pattern::Identifier(ident_name) = var.value { - type_vars.push(ident_name.to_string()); - } - } - - let doc_def = DocDef { - name: name.value.to_string(), - type_annotation: type_to_docs(false, ann.value), - type_vars, - docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), - }; - acc.push(DocEntry::DocDef(doc_def)); - - (acc, None) - } - - Def::Opaque { - header: TypeHeader { name, vars }, - .. - } => { - let mut type_vars = Vec::new(); - - for var in vars.iter() { - if let Pattern::Identifier(ident_name) = var.value { - type_vars.push(ident_name.to_string()); - } - } - - let doc_def = DocDef { - name: name.value.to_string(), - type_annotation: TypeAnnotation::NoTypeAnn, - type_vars, - docs: before_comments_or_new_lines.and_then(comments_or_new_lines_to_docs), - }; - acc.push(DocEntry::DocDef(doc_def)); - - (acc, None) - } - - Def::Ability { .. } => todo_abilities!(), - - Def::Body(_, _) => (acc, None), - - Def::Expect(c) => todo!("documentation for tests {:?}", c), - Def::NotYetImplemented(s) => todo!("{}", s), } } diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 936842fc4a..f616f07d7f 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -279,11 +279,7 @@ pub struct AbilityMember<'a> { } #[derive(Debug, Clone, Copy, PartialEq)] -pub enum Def<'a> { - // TODO in canonicalization, validate the pattern; only certain patterns - // are allowed in annotations. - Annotation(Loc>, Loc>), - +pub enum TypeDef<'a> { /// A type alias. This is like a standalone annotation, except the pattern /// must be a capitalized Identifier, e.g. /// @@ -307,6 +303,13 @@ pub enum Def<'a> { loc_has: Loc>, members: &'a [AbilityMember<'a>], }, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ValueDef<'a> { + // TODO in canonicalization, validate the pattern; only certain patterns + // are allowed in annotations. + Annotation(Loc>, Loc>), // 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 @@ -323,6 +326,12 @@ pub enum Def<'a> { }, Expect(&'a Loc>), +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Def<'a> { + Type(TypeDef<'a>), + Value(ValueDef<'a>), // Blank Space (e.g. comments, spaces, newlines) before or after a def. // We preserve this for the formatter; canonicalization ignores it. @@ -341,6 +350,30 @@ impl<'a> Def<'a> { debug_assert!(!matches!(def, Def::SpaceBefore(_, _))); (spaces, def) } + + pub fn unroll_def(&self) -> Result<&TypeDef<'a>, &ValueDef<'a>> { + let mut def = self; + loop { + match def { + Def::Type(type_def) => return Ok(type_def), + Def::Value(value_def) => return Err(value_def), + Def::SpaceBefore(def1, _) | Def::SpaceAfter(def1, _) => def = def1, + Def::NotYetImplemented(s) => todo!("{}", s), + } + } + } +} + +impl<'a> From> for Def<'a> { + fn from(def: TypeDef<'a>) -> Self { + Self::Type(def) + } +} + +impl<'a> From> for Def<'a> { + fn from(def: ValueDef<'a>) -> Self { + Self::Value(def) + } } #[derive(Debug, Copy, Clone, PartialEq)] diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index 655eba99c8..97f81ed416 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -1,6 +1,6 @@ use crate::ast::{ AssignedField, Collection, CommentOrNewline, Def, Expr, ExtractSpaces, Has, Pattern, Spaceable, - TypeAnnotation, TypeHeader, + TypeAnnotation, TypeDef, TypeHeader, ValueDef, }; use crate::blankspace::{space0_after_e, space0_around_ee, space0_before_e, space0_e}; use crate::ident::{lowercase_ident, parse_ident, Ident}; @@ -576,7 +576,7 @@ fn append_body_definition<'a>( if spaces.len() <= 1 { let last = defs.pop(); match last.map(|d| d.value.unroll_spaces_before()) { - Some((before_ann_spaces, Def::Annotation(ann_pattern, ann_type))) => { + Some((before_ann_spaces, Def::Value(ValueDef::Annotation(ann_pattern, ann_type)))) => { return append_body_definition_help( arena, defs, @@ -591,10 +591,10 @@ fn append_body_definition<'a>( } Some(( before_ann_spaces, - Def::Alias { + Def::Type(TypeDef::Alias { header, ann: ann_type, - }, + }), )) => { // This is a case like // UserId x : [ UserId Int ] @@ -628,7 +628,10 @@ fn append_body_definition<'a>( // the previous and current def can't be joined up let mut loc_def = Loc::at( region, - Def::Body(arena.alloc(loc_pattern), &*arena.alloc(loc_def_body)), + Def::Value(ValueDef::Body( + arena.alloc(loc_pattern), + &*arena.alloc(loc_def_body), + )), ); if !spaces.is_empty() { @@ -660,13 +663,13 @@ fn append_body_definition_help<'a>( let mut loc_def = Loc::at( region, - Def::AnnotatedBody { + Def::Value(ValueDef::AnnotatedBody { ann_pattern: loc_pattern_ann, ann_type: loc_ann, comment, body_pattern: arena.alloc(loc_pattern_body), body_expr: &*arena.alloc(loc_def_body), - }, + }), ); if !before_ann_spaces.is_empty() { @@ -717,7 +720,10 @@ fn append_annotation_definition<'a>( kind, ), _ => { - let mut loc_def = Loc::at(region, Def::Annotation(loc_pattern, loc_ann)); + let mut loc_def = Loc::at( + region, + Def::Value(ValueDef::Annotation(loc_pattern, loc_ann)), + ); if !spaces.is_empty() { loc_def = arena .alloc(loc_def.value) @@ -736,7 +742,7 @@ fn append_expect_definition<'a>( spaces: &'a [CommentOrNewline<'a>], loc_expect_body: Loc>, ) { - let def = Def::Expect(arena.alloc(loc_expect_body)); + let def: Def = ValueDef::Expect(arena.alloc(loc_expect_body)).into(); let end = loc_expect_body.region.end(); let region = Region::new(start, end); @@ -768,16 +774,16 @@ fn append_type_definition<'a>( vars: pattern_arguments, }; let def = match kind { - TypeKind::Alias => Def::Alias { + TypeKind::Alias => TypeDef::Alias { header, ann: loc_ann, }, - TypeKind::Opaque => Def::Opaque { + TypeKind::Opaque => TypeDef::Opaque { header, typ: loc_ann, }, }; - let mut loc_def = Loc::at(region, def); + let mut loc_def = Loc::at(region, Def::Type(def)); if !spaces.is_empty() { loc_def = arena @@ -1038,17 +1044,17 @@ fn finish_parsing_alias_or_opaque<'a>( vars: type_arguments.into_bump_slice(), }; let type_def = match kind { - TypeKind::Alias => Def::Alias { + TypeKind::Alias => TypeDef::Alias { header, ann: ann_type, }, - TypeKind::Opaque => Def::Opaque { + TypeKind::Opaque => TypeDef::Opaque { header, typ: ann_type, }, }; - (&*arena.alloc(Loc::at(def_region, type_def)), state) + (&*arena.alloc(Loc::at(def_region, type_def.into())), state) } _ => { @@ -1077,9 +1083,9 @@ fn finish_parsing_alias_or_opaque<'a>( let def_region = Region::span_across(&call.region, &ann_type.region); - let alias = Def::Annotation(Loc::at(expr_region, good), ann_type); + let alias = ValueDef::Annotation(Loc::at(expr_region, good), ann_type); - (&*arena.alloc(Loc::at(def_region, alias)), state) + (&*arena.alloc(Loc::at(def_region, alias.into())), state) } } } @@ -1270,11 +1276,12 @@ fn finish_parsing_ability_def<'a>( } let def_region = Region::span_across(&name.region, &demands.last().unwrap().typ.region); - let def = Def::Ability { + let def = TypeDef::Ability { header: TypeHeader { name, vars: args }, loc_has, members: demands.into_bump_slice(), - }; + } + .into(); let loc_def = &*(arena.alloc(Loc::at(def_region, def))); Ok((MadeProgress, loc_def, state)) @@ -1357,23 +1364,24 @@ fn parse_expr_operator<'a>( let (loc_def, state) = { match expr_to_pattern_help(arena, &call.value) { Ok(good) => { - let (_, mut ann_type, state) = parse_loc_expr(indented_more, arena, state)?; + let (_, mut body, state) = parse_loc_expr(indented_more, arena, 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); + body = arena + .alloc(body.value) + .with_spaces_before(spaces_after_operator, body.region); } - let alias_region = Region::span_across(&call.region, &ann_type.region); + let body_region = Region::span_across(&call.region, &body.region); - let alias = Def::Body( + let alias = ValueDef::Body( arena.alloc(Loc::at(expr_region, good)), - arena.alloc(ann_type), - ); + arena.alloc(body), + ) + .into(); - (&*arena.alloc(Loc::at(alias_region, alias)), state) + (&*arena.alloc(Loc::at(body_region, alias)), state) } Err(_) => { // this `=` likely occurred inline; treat it as an invalid operator diff --git a/compiler/parse/tests/snapshots/pass/ability_demand_signature_is_multiline.expr.result-ast b/compiler/parse/tests/snapshots/pass/ability_demand_signature_is_multiline.expr.result-ast index c5a2217c99..103b1338b6 100644 --- a/compiler/parse/tests/snapshots/pass/ability_demand_signature_is_multiline.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/ability_demand_signature_is_multiline.expr.result-ast @@ -1,34 +1,36 @@ Defs( [ - @0-36 Ability { - header: TypeHeader { - name: @0-4 "Hash", - vars: [], - }, - loc_has: @5-8 Has, - members: [ - AbilityMember { - name: @11-15 SpaceBefore( - "hash", - [ - Newline, - ], - ), - typ: @33-36 Function( - [ - @18-19 BoundVariable( - "a", - ), - ], - @33-36 Apply( - "", - "U64", - [], - ), - ), + @0-36 Type( + Ability { + header: TypeHeader { + name: @0-4 "Hash", + vars: [], }, - ], - }, + loc_has: @5-8 Has, + members: [ + AbilityMember { + name: @11-15 SpaceBefore( + "hash", + [ + Newline, + ], + ), + typ: @33-36 Function( + [ + @18-19 BoundVariable( + "a", + ), + ], + @33-36 Apply( + "", + "U64", + [], + ), + ), + }, + ], + }, + ), ], @38-39 SpaceBefore( Num( diff --git a/compiler/parse/tests/snapshots/pass/ability_multi_line.expr.result-ast b/compiler/parse/tests/snapshots/pass/ability_multi_line.expr.result-ast index 01dd4bbed5..1d7fd2505b 100644 --- a/compiler/parse/tests/snapshots/pass/ability_multi_line.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/ability_multi_line.expr.result-ast @@ -1,54 +1,56 @@ Defs( [ - @0-45 Ability { - header: TypeHeader { - name: @0-4 "Hash", - vars: [], + @0-45 Type( + Ability { + header: TypeHeader { + name: @0-4 "Hash", + vars: [], + }, + loc_has: @5-8 Has, + members: [ + AbilityMember { + name: @11-15 SpaceBefore( + "hash", + [ + Newline, + ], + ), + typ: @23-26 Function( + [ + @18-19 BoundVariable( + "a", + ), + ], + @23-26 Apply( + "", + "U64", + [], + ), + ), + }, + AbilityMember { + name: @29-34 SpaceBefore( + "hash2", + [ + Newline, + ], + ), + typ: @42-45 Function( + [ + @37-38 BoundVariable( + "a", + ), + ], + @42-45 Apply( + "", + "U64", + [], + ), + ), + }, + ], }, - loc_has: @5-8 Has, - members: [ - AbilityMember { - name: @11-15 SpaceBefore( - "hash", - [ - Newline, - ], - ), - typ: @23-26 Function( - [ - @18-19 BoundVariable( - "a", - ), - ], - @23-26 Apply( - "", - "U64", - [], - ), - ), - }, - AbilityMember { - name: @29-34 SpaceBefore( - "hash2", - [ - Newline, - ], - ), - typ: @42-45 Function( - [ - @37-38 BoundVariable( - "a", - ), - ], - @42-45 Apply( - "", - "U64", - [], - ), - ), - }, - ], - }, + ), ], @47-48 SpaceBefore( Num( diff --git a/compiler/parse/tests/snapshots/pass/ability_single_line.expr.result-ast b/compiler/parse/tests/snapshots/pass/ability_single_line.expr.result-ast index f7c3f923a1..4ce7c5f245 100644 --- a/compiler/parse/tests/snapshots/pass/ability_single_line.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/ability_single_line.expr.result-ast @@ -1,41 +1,43 @@ Defs( [ - @0-37 Ability { - header: TypeHeader { - name: @0-4 "Hash", - vars: [], - }, - loc_has: @5-8 Has, - members: [ - AbilityMember { - name: @9-13 "hash", - typ: @21-37 Where( - @21-24 Function( - [ - @16-17 BoundVariable( - "a", - ), - ], - @21-24 Apply( - "", - "U64", - [], - ), - ), - [ - @27-37 HasClause { - var: @27-28 "a", - ability: @33-37 Apply( + @0-37 Type( + Ability { + header: TypeHeader { + name: @0-4 "Hash", + vars: [], + }, + loc_has: @5-8 Has, + members: [ + AbilityMember { + name: @9-13 "hash", + typ: @21-37 Where( + @21-24 Function( + [ + @16-17 BoundVariable( + "a", + ), + ], + @21-24 Apply( "", - "Hash", + "U64", [], ), - }, - ], - ), - }, - ], - }, + ), + [ + @27-37 HasClause { + var: @27-28 "a", + ability: @33-37 Apply( + "", + "Hash", + [], + ), + }, + ], + ), + }, + ], + }, + ), ], @39-40 SpaceBefore( Num( diff --git a/compiler/parse/tests/snapshots/pass/ability_two_in_a_row.expr.result-ast b/compiler/parse/tests/snapshots/pass/ability_two_in_a_row.expr.result-ast index 46e16466f6..4bd0831c5c 100644 --- a/compiler/parse/tests/snapshots/pass/ability_two_in_a_row.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/ability_two_in_a_row.expr.result-ast @@ -1,79 +1,83 @@ Defs( [ - @0-33 Ability { - header: TypeHeader { - name: @0-3 "Ab1", - vars: [], - }, - loc_has: @4-7 Has, - members: [ - AbilityMember { - name: @8-11 "ab1", - typ: @19-33 Where( - @19-21 Function( - [ - @14-15 BoundVariable( - "a", - ), - ], - @19-21 Record { - fields: [], - ext: None, - }, - ), - [ - @24-33 HasClause { - var: @24-25 "a", - ability: @30-33 Apply( - "", - "Ab1", - [], - ), - }, - ], - ), + @0-33 Type( + Ability { + header: TypeHeader { + name: @0-3 "Ab1", + vars: [], }, - ], - }, + loc_has: @4-7 Has, + members: [ + AbilityMember { + name: @8-11 "ab1", + typ: @19-33 Where( + @19-21 Function( + [ + @14-15 BoundVariable( + "a", + ), + ], + @19-21 Record { + fields: [], + ext: None, + }, + ), + [ + @24-33 HasClause { + var: @24-25 "a", + ability: @30-33 Apply( + "", + "Ab1", + [], + ), + }, + ], + ), + }, + ], + }, + ), ], @35-71 SpaceBefore( Defs( [ - @35-68 Ability { - header: TypeHeader { - name: @35-38 "Ab2", - vars: [], - }, - loc_has: @39-42 Has, - members: [ - AbilityMember { - name: @43-46 "ab2", - typ: @54-68 Where( - @54-56 Function( - [ - @49-50 BoundVariable( - "a", - ), - ], - @54-56 Record { - fields: [], - ext: None, - }, - ), - [ - @59-68 HasClause { - var: @59-60 "a", - ability: @65-68 Apply( - "", - "Ab2", - [], - ), - }, - ], - ), + @35-68 Type( + Ability { + header: TypeHeader { + name: @35-38 "Ab2", + vars: [], }, - ], - }, + loc_has: @39-42 Has, + members: [ + AbilityMember { + name: @43-46 "ab2", + typ: @54-68 Where( + @54-56 Function( + [ + @49-50 BoundVariable( + "a", + ), + ], + @54-56 Record { + fields: [], + ext: None, + }, + ), + [ + @59-68 HasClause { + var: @59-60 "a", + ability: @65-68 Apply( + "", + "Ab2", + [], + ), + }, + ], + ), + }, + ], + }, + ), ], @70-71 SpaceBefore( Num( diff --git a/compiler/parse/tests/snapshots/pass/annotated_record_destructure.expr.result-ast b/compiler/parse/tests/snapshots/pass/annotated_record_destructure.expr.result-ast index 3b4a561069..3b87b36828 100644 --- a/compiler/parse/tests/snapshots/pass/annotated_record_destructure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/annotated_record_destructure.expr.result-ast @@ -1,53 +1,55 @@ Defs( [ - @15-49 AnnotatedBody { - ann_pattern: @0-8 RecordDestructure( - [ - @2-3 Identifier( - "x", - ), - @5-7 Identifier( - "y", - ), - ], - ), - ann_type: @11-14 Apply( - "", - "Foo", - [], - ), - comment: None, - body_pattern: @15-23 RecordDestructure( - [ - @17-18 Identifier( - "x", - ), - @20-21 Identifier( - "y", - ), - ], - ), - body_expr: @26-49 Record( - [ - @28-37 RequiredValue( - @28-29 "x", - [], - @32-37 Str( - PlainLine( - "foo", + @15-49 Value( + AnnotatedBody { + ann_pattern: @0-8 RecordDestructure( + [ + @2-3 Identifier( + "x", + ), + @5-7 Identifier( + "y", + ), + ], + ), + ann_type: @11-14 Apply( + "", + "Foo", + [], + ), + comment: None, + body_pattern: @15-23 RecordDestructure( + [ + @17-18 Identifier( + "x", + ), + @20-21 Identifier( + "y", + ), + ], + ), + body_expr: @26-49 Record( + [ + @28-37 RequiredValue( + @28-29 "x", + [], + @32-37 Str( + PlainLine( + "foo", + ), ), ), - ), - @39-47 RequiredValue( - @39-40 "y", - [], - @43-47 Float( - "3.14", + @39-47 RequiredValue( + @39-40 "y", + [], + @43-47 Float( + "3.14", + ), ), - ), - ], - ), - }, + ], + ), + }, + ), ], @51-52 SpaceBefore( Var { diff --git a/compiler/parse/tests/snapshots/pass/annotated_tag_destructure.expr.result-ast b/compiler/parse/tests/snapshots/pass/annotated_tag_destructure.expr.result-ast index 178aca2667..54d3d56502 100644 --- a/compiler/parse/tests/snapshots/pass/annotated_tag_destructure.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/annotated_tag_destructure.expr.result-ast @@ -1,54 +1,56 @@ Defs( [ - @26-46 AnnotatedBody { - ann_pattern: @0-8 Apply( - @0-6 GlobalTag( - "UserId", - ), - [ - @7-8 Identifier( - "x", + @26-46 Value( + AnnotatedBody { + ann_pattern: @0-8 Apply( + @0-6 GlobalTag( + "UserId", ), - ], - ), - ann_type: @11-25 TagUnion { - ext: None, - tags: [ - @13-23 Global { - name: @13-19 "UserId", - args: [ - @20-23 Apply( - "", - "I64", - [], - ), - ], - }, - ], + [ + @7-8 Identifier( + "x", + ), + ], + ), + ann_type: @11-25 TagUnion { + ext: None, + tags: [ + @13-23 Global { + name: @13-19 "UserId", + args: [ + @20-23 Apply( + "", + "I64", + [], + ), + ], + }, + ], + }, + comment: None, + body_pattern: @26-34 Apply( + @26-32 GlobalTag( + "UserId", + ), + [ + @33-34 Identifier( + "x", + ), + ], + ), + body_expr: @37-46 Apply( + @37-43 GlobalTag( + "UserId", + ), + [ + @44-46 Num( + "42", + ), + ], + Space, + ), }, - comment: None, - body_pattern: @26-34 Apply( - @26-32 GlobalTag( - "UserId", - ), - [ - @33-34 Identifier( - "x", - ), - ], - ), - body_expr: @37-46 Apply( - @37-43 GlobalTag( - "UserId", - ), - [ - @44-46 Num( - "42", - ), - ], - Space, - ), - }, + ), ], @48-49 SpaceBefore( Var { diff --git a/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast index 8f016cf433..e457bb7705 100644 --- a/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/basic_docs.expr.result-ast @@ -1,12 +1,14 @@ SpaceBefore( Defs( [ - @107-112 Body( - @107-108 Identifier( - "x", - ), - @111-112 Num( - "5", + @107-112 Value( + Body( + @107-108 Identifier( + "x", + ), + @111-112 Num( + "5", + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/comment_after_def.module.result-ast b/compiler/parse/tests/snapshots/pass/comment_after_def.module.result-ast index 0579437258..6b15b031b6 100644 --- a/compiler/parse/tests/snapshots/pass/comment_after_def.module.result-ast +++ b/compiler/parse/tests/snapshots/pass/comment_after_def.module.result-ast @@ -1,12 +1,14 @@ [ @0-7 SpaceAfter( SpaceBefore( - Body( - @0-3 Identifier( - "foo", - ), - @6-7 Num( - "1", + Value( + Body( + @0-3 Identifier( + "foo", + ), + @6-7 Num( + "1", + ), ), ), [], diff --git a/compiler/parse/tests/snapshots/pass/destructure_tag_assignment.expr.result-ast b/compiler/parse/tests/snapshots/pass/destructure_tag_assignment.expr.result-ast index be7a2a54bf..4cdfd0b739 100644 --- a/compiler/parse/tests/snapshots/pass/destructure_tag_assignment.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/destructure_tag_assignment.expr.result-ast @@ -1,28 +1,30 @@ Defs( [ - @0-36 Body( - @0-5 Apply( - @0-5 GlobalTag( - "Email", - ), - [ - @6-9 Identifier( - "str", + @0-36 Value( + Body( + @0-5 Apply( + @0-5 GlobalTag( + "Email", ), - ], - ), - @12-36 Apply( - @12-17 GlobalTag( - "Email", - ), - [ - @18-36 Str( - PlainLine( - "blah@example.com", + [ + @6-9 Identifier( + "str", ), + ], + ), + @12-36 Apply( + @12-17 GlobalTag( + "Email", ), - ], - Space, + [ + @18-36 Str( + PlainLine( + "blah@example.com", + ), + ), + ], + Space, + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast index 08284e3121..61962aa8bc 100644 --- a/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/if_def.expr.result-ast @@ -1,11 +1,13 @@ Defs( [ - @0-6 Body( - @0-4 Identifier( - "iffy", - ), - @5-6 Num( - "5", + @0-6 Value( + Body( + @0-4 Identifier( + "iffy", + ), + @5-6 Num( + "5", + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/list_closing_indent_not_enough.expr.result-ast b/compiler/parse/tests/snapshots/pass/list_closing_indent_not_enough.expr.result-ast index 74ccc748aa..d51238a4c5 100644 --- a/compiler/parse/tests/snapshots/pass/list_closing_indent_not_enough.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/list_closing_indent_not_enough.expr.result-ast @@ -1,65 +1,67 @@ Defs( [ - @0-58 Body( - @0-7 Malformed( - "my_list", - ), - @10-58 List( - Collection { - items: [ - @16-17 SpaceBefore( - Num( - "0", + @0-58 Value( + Body( + @0-7 Malformed( + "my_list", + ), + @10-58 List( + Collection { + items: [ + @16-17 SpaceBefore( + Num( + "0", + ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - @23-48 SpaceBefore( - List( - Collection { - items: [ - @33-34 SpaceBefore( - Var { - module_name: "", - ident: "a", - }, - [ - Newline, - ], - ), - @44-45 SpaceBefore( - Var { - module_name: "", - ident: "b", - }, - [ - Newline, - ], - ), - ], - final_comments: [ - Newline, - ], - }, + @23-48 SpaceBefore( + List( + Collection { + items: [ + @33-34 SpaceBefore( + Var { + module_name: "", + ident: "a", + }, + [ + Newline, + ], + ), + @44-45 SpaceBefore( + Var { + module_name: "", + ident: "b", + }, + [ + Newline, + ], + ), + ], + final_comments: [ + Newline, + ], + }, + ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - @54-55 SpaceBefore( - Num( - "1", + @54-55 SpaceBefore( + Num( + "1", + ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - ], - final_comments: [ - Newline, - ], - }, + ], + final_comments: [ + Newline, + ], + }, + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/list_closing_same_indent_no_trailing_comma.expr.result-ast b/compiler/parse/tests/snapshots/pass/list_closing_same_indent_no_trailing_comma.expr.result-ast index 5af6f4259c..ffe535c03f 100644 --- a/compiler/parse/tests/snapshots/pass/list_closing_same_indent_no_trailing_comma.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/list_closing_same_indent_no_trailing_comma.expr.result-ast @@ -1,33 +1,35 @@ Defs( [ - @0-26 Body( - @0-7 Malformed( - "my_list", - ), - @10-26 List( - Collection { - items: [ - @16-17 SpaceBefore( - Num( - "0", + @0-26 Value( + Body( + @0-7 Malformed( + "my_list", + ), + @10-26 List( + Collection { + items: [ + @16-17 SpaceBefore( + Num( + "0", + ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - @23-24 SpaceBefore( - Num( - "1", + @23-24 SpaceBefore( + Num( + "1", + ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - ], - final_comments: [ - Newline, - ], - }, + ], + final_comments: [ + Newline, + ], + }, + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/list_closing_same_indent_with_trailing_comma.expr.result-ast b/compiler/parse/tests/snapshots/pass/list_closing_same_indent_with_trailing_comma.expr.result-ast index 99d1bf828f..e526c773d2 100644 --- a/compiler/parse/tests/snapshots/pass/list_closing_same_indent_with_trailing_comma.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/list_closing_same_indent_with_trailing_comma.expr.result-ast @@ -1,33 +1,35 @@ Defs( [ - @0-27 Body( - @0-7 Malformed( - "my_list", - ), - @10-27 List( - Collection { - items: [ - @16-17 SpaceBefore( - Num( - "0", + @0-27 Value( + Body( + @0-7 Malformed( + "my_list", + ), + @10-27 List( + Collection { + items: [ + @16-17 SpaceBefore( + Num( + "0", + ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - @23-24 SpaceBefore( - Num( - "1", + @23-24 SpaceBefore( + Num( + "1", + ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - ], - final_comments: [ - Newline, - ], - }, + ], + final_comments: [ + Newline, + ], + }, + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast index 190e21ca40..9b61bffafa 100644 --- a/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/mixed_docs.expr.result-ast @@ -1,12 +1,14 @@ SpaceBefore( Defs( [ - @113-118 Body( - @113-114 Identifier( - "x", - ), - @117-118 Num( - "5", + @113-118 Value( + Body( + @113-114 Identifier( + "x", + ), + @117-118 Num( + "5", + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast b/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast index 11a0ded5c2..8b3f051c8d 100644 --- a/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast +++ b/compiler/parse/tests/snapshots/pass/module_def_newline.module.result-ast @@ -1,36 +1,40 @@ [ @0-24 SpaceAfter( SpaceBefore( - Body( - @0-4 Identifier( - "main", - ), - @11-24 SpaceBefore( - Defs( - [ - @11-17 Body( - @11-12 Identifier( - "i", - ), - @15-17 Num( - "64", - ), - ), - ], - @23-24 SpaceBefore( - Var { - module_name: "", - ident: "i", - }, - [ - Newline, - Newline, - ], - ), + Value( + Body( + @0-4 Identifier( + "main", + ), + @11-24 SpaceBefore( + Defs( + [ + @11-17 Value( + Body( + @11-12 Identifier( + "i", + ), + @15-17 Num( + "64", + ), + ), + ), + ], + @23-24 SpaceBefore( + Var { + module_name: "", + ident: "i", + }, + [ + Newline, + Newline, + ], + ), + ), + [ + Newline, + ], ), - [ - Newline, - ], ), ), [], diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast index 8946c66262..d3519069ff 100644 --- a/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature.expr.result-ast @@ -1,17 +1,19 @@ Defs( [ - @0-10 Annotation( - @0-1 Identifier( - "f", - ), - @8-10 SpaceBefore( - Record { - fields: [], - ext: None, - }, - [ - Newline, - ], + @0-10 Value( + Annotation( + @0-1 Identifier( + "f", + ), + @8-10 SpaceBefore( + Record { + fields: [], + ext: None, + }, + [ + Newline, + ], + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast index 8c30fd95c0..d989a361e4 100644 --- a/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/multiline_type_signature_with_comment.expr.result-ast @@ -1,19 +1,21 @@ Defs( [ - @0-19 Annotation( - @0-1 Identifier( - "f", - ), - @17-19 SpaceBefore( - Record { - fields: [], - ext: None, - }, - [ - LineComment( - " comment", - ), - ], + @0-19 Value( + Annotation( + @0-1 Identifier( + "f", + ), + @17-19 SpaceBefore( + Record { + fields: [], + ext: None, + }, + [ + LineComment( + " comment", + ), + ], + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast b/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast index 33722ca531..adec062681 100644 --- a/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast +++ b/compiler/parse/tests/snapshots/pass/nested_def_annotation.module.result-ast @@ -1,93 +1,97 @@ [ @0-115 SpaceAfter( SpaceBefore( - Body( - @0-4 Identifier( - "main", - ), - @11-115 SpaceBefore( - Defs( - [ - @43-93 AnnotatedBody { - ann_pattern: @11-23 Identifier( - "wrappedNotEq", - ), - ann_type: @34-38 Function( - [ - @26-27 BoundVariable( - "a", + Value( + Body( + @0-4 Identifier( + "main", + ), + @11-115 SpaceBefore( + Defs( + [ + @43-93 Value( + AnnotatedBody { + ann_pattern: @11-23 Identifier( + "wrappedNotEq", ), - @29-30 BoundVariable( - "a", - ), - ], - @34-38 Apply( - "", - "Bool", - [], - ), - ), - comment: None, - body_pattern: @43-55 Identifier( - "wrappedNotEq", - ), - body_expr: @58-93 Closure( - [ - @59-63 Identifier( - "num1", - ), - @65-69 Identifier( - "num2", - ), - ], - @81-93 SpaceBefore( - BinOps( + ann_type: @34-38 Function( [ - ( - @81-85 Var { - module_name: "", - ident: "num1", - }, - @86-88 NotEquals, + @26-27 BoundVariable( + "a", + ), + @29-30 BoundVariable( + "a", ), ], - @89-93 Var { - module_name: "", - ident: "num2", - }, + @34-38 Apply( + "", + "Bool", + [], + ), ), - [ - Newline, - ], - ), + comment: None, + body_pattern: @43-55 Identifier( + "wrappedNotEq", + ), + body_expr: @58-93 Closure( + [ + @59-63 Identifier( + "num1", + ), + @65-69 Identifier( + "num2", + ), + ], + @81-93 SpaceBefore( + BinOps( + [ + ( + @81-85 Var { + module_name: "", + ident: "num1", + }, + @86-88 NotEquals, + ), + ], + @89-93 Var { + module_name: "", + ident: "num2", + }, + ), + [ + Newline, + ], + ), + ), + }, ), - }, - ], - @99-115 SpaceBefore( - Apply( - @99-111 Var { - module_name: "", - ident: "wrappedNotEq", - }, - [ - @112-113 Num( - "2", - ), - @114-115 Num( - "3", - ), - ], - Space, - ), - [ - Newline, - Newline, ], + @99-115 SpaceBefore( + Apply( + @99-111 Var { + module_name: "", + ident: "wrappedNotEq", + }, + [ + @112-113 Num( + "2", + ), + @114-115 Num( + "3", + ), + ], + Space, + ), + [ + Newline, + Newline, + ], + ), ), + [ + Newline, + ], ), - [ - Newline, - ], ), ), [], diff --git a/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast index 3cdf6755b6..a62f3cc138 100644 --- a/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_after_equals.expr.result-ast @@ -1,16 +1,18 @@ Defs( [ - @0-9 Body( - @0-1 Identifier( - "x", - ), - @8-9 SpaceBefore( - Num( - "5", + @0-9 Value( + Body( + @0-1 Identifier( + "x", + ), + @8-9 SpaceBefore( + Num( + "5", + ), + [ + Newline, + ], ), - [ - Newline, - ], ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast index cbc30d8ba0..2fd5007e3d 100644 --- a/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/newline_and_spaces_before_less_than.expr.result-ast @@ -1,25 +1,27 @@ Defs( [ - @0-13 Body( - @0-1 Identifier( - "x", - ), - @4-13 BinOps( - [ - ( - @4-5 SpaceAfter( - Num( - "1", + @0-13 Value( + Body( + @0-1 Identifier( + "x", + ), + @4-13 BinOps( + [ + ( + @4-5 SpaceAfter( + Num( + "1", + ), + [ + Newline, + ], ), - [ - Newline, - ], + @10-11 LessThan, ), - @10-11 LessThan, + ], + @12-13 Num( + "2", ), - ], - @12-13 Num( - "2", ), ), ), diff --git a/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast b/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast index e9a5247b17..0df9d829d3 100644 --- a/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/not_docs.expr.result-ast @@ -1,12 +1,14 @@ SpaceBefore( Defs( [ - @46-51 Body( - @46-47 Identifier( - "x", - ), - @50-51 Num( - "5", + @46-51 Value( + Body( + @46-47 Identifier( + "x", + ), + @50-51 Num( + "5", + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast index 7caa61c752..a8af60df37 100644 --- a/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_def.expr.result-ast @@ -1,12 +1,14 @@ SpaceBefore( Defs( [ - @18-21 Body( - @18-19 Identifier( - "x", - ), - @20-21 Num( - "5", + @18-21 Value( + Body( + @18-19 Identifier( + "x", + ), + @20-21 Num( + "5", + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast index a1fab8b814..7e47e88173 100644 --- a/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/one_spaced_def.expr.result-ast @@ -1,12 +1,14 @@ SpaceBefore( Defs( [ - @18-23 Body( - @18-19 Identifier( - "x", - ), - @22-23 Num( - "5", + @18-23 Value( + Body( + @18-19 Identifier( + "x", + ), + @22-23 Num( + "5", + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/opaque_simple.module.result-ast b/compiler/parse/tests/snapshots/pass/opaque_simple.module.result-ast index d90ca292eb..297911616f 100644 --- a/compiler/parse/tests/snapshots/pass/opaque_simple.module.result-ast +++ b/compiler/parse/tests/snapshots/pass/opaque_simple.module.result-ast @@ -1,17 +1,19 @@ [ @0-9 SpaceAfter( SpaceBefore( - Opaque { - header: TypeHeader { - name: @0-3 "Age", - vars: [], + Type( + Opaque { + header: TypeHeader { + name: @0-3 "Age", + vars: [], + }, + typ: @7-9 Apply( + "", + "U8", + [], + ), }, - typ: @7-9 Apply( - "", - "U8", - [], - ), - }, + ), [], ), [ diff --git a/compiler/parse/tests/snapshots/pass/opaque_with_type_arguments.module.result-ast b/compiler/parse/tests/snapshots/pass/opaque_with_type_arguments.module.result-ast index 8c2e2d44f5..c541386e23 100644 --- a/compiler/parse/tests/snapshots/pass/opaque_with_type_arguments.module.result-ast +++ b/compiler/parse/tests/snapshots/pass/opaque_with_type_arguments.module.result-ast @@ -1,46 +1,48 @@ [ @0-53 SpaceAfter( SpaceBefore( - Opaque { - header: TypeHeader { - name: @0-10 "Bookmark", - vars: [ - @9-10 Identifier( - "a", - ), - ], - }, - typ: @14-53 Record { - fields: [ - @16-28 RequiredValue( - @16-23 "chapter", - [], - @25-28 Apply( - "", - "Str", - [], - ), - ), - @30-41 RequiredValue( - @30-36 "stanza", - [], - @38-41 Apply( - "", - "Str", - [], - ), - ), - @43-51 RequiredValue( - @43-48 "notes", - [], - @50-51 BoundVariable( + Type( + Opaque { + header: TypeHeader { + name: @0-10 "Bookmark", + vars: [ + @9-10 Identifier( "a", ), - ), - ], - ext: None, + ], + }, + typ: @14-53 Record { + fields: [ + @16-28 RequiredValue( + @16-23 "chapter", + [], + @25-28 Apply( + "", + "Str", + [], + ), + ), + @30-41 RequiredValue( + @30-36 "stanza", + [], + @38-41 Apply( + "", + "Str", + [], + ), + ), + @43-51 RequiredValue( + @43-48 "notes", + [], + @50-51 BoundVariable( + "a", + ), + ), + ], + ext: None, + }, }, - }, + ), [], ), [ diff --git a/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast b/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast index 9beffce00a..7db0abac4a 100644 --- a/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parse_alias.expr.result-ast @@ -1,30 +1,32 @@ Defs( [ - @0-26 Alias { - header: TypeHeader { - name: @0-4 "Blah", - vars: [ - @5-6 Identifier( - "a", - ), - @7-8 Identifier( - "b", - ), - ], + @0-26 Type( + Alias { + header: TypeHeader { + name: @0-4 "Blah", + vars: [ + @5-6 Identifier( + "a", + ), + @7-8 Identifier( + "b", + ), + ], + }, + ann: @11-26 Apply( + "Foo.Bar", + "Baz", + [ + @23-24 BoundVariable( + "x", + ), + @25-26 BoundVariable( + "y", + ), + ], + ), }, - ann: @11-26 Apply( - "Foo.Bar", - "Baz", - [ - @23-24 BoundVariable( - "x", - ), - @25-26 BoundVariable( - "y", - ), - ], - ), - }, + ), ], @28-30 SpaceBefore( Num( diff --git a/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast index 5e6b069d15..b6faae0f69 100644 --- a/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/parse_as_ann.expr.result-ast @@ -1,34 +1,36 @@ Defs( [ - @0-33 Annotation( - @0-3 Identifier( - "foo", - ), - @6-33 As( - @6-21 Apply( - "Foo.Bar", - "Baz", - [ - @18-19 BoundVariable( - "x", - ), - @20-21 BoundVariable( - "y", - ), - ], + @0-33 Value( + Annotation( + @0-3 Identifier( + "foo", + ), + @6-33 As( + @6-21 Apply( + "Foo.Bar", + "Baz", + [ + @18-19 BoundVariable( + "x", + ), + @20-21 BoundVariable( + "y", + ), + ], + ), + [], + TypeHeader { + name: @25-29 "Blah", + vars: [ + @30-31 Identifier( + "a", + ), + @32-33 Identifier( + "b", + ), + ], + }, ), - [], - TypeHeader { - name: @25-29 "Blah", - vars: [ - @30-31 Identifier( - "a", - ), - @32-33 Identifier( - "b", - ), - ], - }, ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast index 498e786bb0..b2cbb9bbca 100644 --- a/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/record_destructure_def.expr.result-ast @@ -1,28 +1,32 @@ SpaceBefore( Defs( [ - @18-30 Body( - @18-26 RecordDestructure( - [ - @20-21 Identifier( - "x", - ), - @23-25 Identifier( - "y", - ), - ], - ), - @29-30 Num( - "5", + @18-30 Value( + Body( + @18-26 RecordDestructure( + [ + @20-21 Identifier( + "x", + ), + @23-25 Identifier( + "y", + ), + ], + ), + @29-30 Num( + "5", + ), ), ), @31-36 SpaceBefore( - Body( - @31-32 Identifier( - "y", - ), - @35-36 Num( - "6", + Value( + Body( + @31-32 Identifier( + "y", + ), + @35-36 Num( + "6", + ), ), ), [ diff --git a/compiler/parse/tests/snapshots/pass/record_func_type_decl.expr.result-ast b/compiler/parse/tests/snapshots/pass/record_func_type_decl.expr.result-ast index 6ae895c6e0..289456aed3 100644 --- a/compiler/parse/tests/snapshots/pass/record_func_type_decl.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/record_func_type_decl.expr.result-ast @@ -1,102 +1,104 @@ Defs( [ - @0-122 Annotation( - @0-1 Identifier( - "f", - ), - @8-122 SpaceBefore( - Record { - fields: [ - @18-38 SpaceBefore( - RequiredValue( - @18-25 "getLine", - [], - @28-38 Apply( - "", - "Effect", - [ - @35-38 Apply( - "", - "Str", - [], - ), - ], - ), - ), - [ - Newline, - ], - ), - @48-75 SpaceBefore( - RequiredValue( - @48-55 "putLine", - [], - @65-75 Function( - [ - @58-61 Apply( - "", - "Str", - [], - ), - ], - @65-75 Apply( + @0-122 Value( + Annotation( + @0-1 Identifier( + "f", + ), + @8-122 SpaceBefore( + Record { + fields: [ + @18-38 SpaceBefore( + RequiredValue( + @18-25 "getLine", + [], + @28-38 Apply( "", "Effect", [ - @72-75 Apply( + @35-38 Apply( "", - "Int", + "Str", [], ), ], ), ), - ), - [ - Newline, - ], - ), - @85-94 SpaceBefore( - RequiredValue( - @85-89 "text", - [], - @91-94 Apply( - "", - "Str", - [], - ), - ), - [ - Newline, - ], - ), - @104-116 SpaceBefore( - SpaceAfter( - RequiredValue( - @104-109 "value", - [], - @111-116 Apply( - "", - "Int", - [ - @115-116 Wildcard, - ], - ), - ), [ Newline, ], ), - [ - Newline, - ], - ), + @48-75 SpaceBefore( + RequiredValue( + @48-55 "putLine", + [], + @65-75 Function( + [ + @58-61 Apply( + "", + "Str", + [], + ), + ], + @65-75 Apply( + "", + "Effect", + [ + @72-75 Apply( + "", + "Int", + [], + ), + ], + ), + ), + ), + [ + Newline, + ], + ), + @85-94 SpaceBefore( + RequiredValue( + @85-89 "text", + [], + @91-94 Apply( + "", + "Str", + [], + ), + ), + [ + Newline, + ], + ), + @104-116 SpaceBefore( + SpaceAfter( + RequiredValue( + @104-109 "value", + [], + @111-116 Apply( + "", + "Int", + [ + @115-116 Wildcard, + ], + ), + ), + [ + Newline, + ], + ), + [ + Newline, + ], + ), + ], + ext: None, + }, + [ + Newline, ], - ext: None, - }, - [ - Newline, - ], + ), ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast b/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast index e03334f801..3833ec65ea 100644 --- a/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast +++ b/compiler/parse/tests/snapshots/pass/standalone_module_defs.module.result-ast @@ -1,11 +1,13 @@ [ @12-19 SpaceBefore( - Body( - @12-15 Identifier( - "foo", - ), - @18-19 Num( - "1", + Value( + Body( + @12-15 Identifier( + "foo", + ), + @18-19 Num( + "1", + ), ), ), [ @@ -15,13 +17,15 @@ ], ), @33-43 SpaceBefore( - Body( - @33-36 Identifier( - "bar", - ), - @39-43 Str( - PlainLine( - "hi", + Value( + Body( + @33-36 Identifier( + "bar", + ), + @39-43 Str( + PlainLine( + "hi", + ), ), ), ), @@ -35,13 +39,15 @@ ), @44-57 SpaceAfter( SpaceBefore( - Body( - @44-47 Identifier( - "baz", - ), - @50-57 Str( - PlainLine( - "stuff", + Value( + Body( + @44-47 Identifier( + "baz", + ), + @50-57 Str( + PlainLine( + "stuff", + ), ), ), ), diff --git a/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast index 7ae7c0abd2..27cab84f39 100644 --- a/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/two_spaced_def.expr.result-ast @@ -1,21 +1,25 @@ SpaceBefore( Defs( [ - @18-23 Body( - @18-19 Identifier( - "x", - ), - @22-23 Num( - "5", + @18-23 Value( + Body( + @18-19 Identifier( + "x", + ), + @22-23 Num( + "5", + ), ), ), @24-29 SpaceBefore( - Body( - @24-25 Identifier( - "y", - ), - @28-29 Num( - "6", + Value( + Body( + @24-25 Identifier( + "y", + ), + @28-29 Num( + "6", + ), ), ), [ diff --git a/compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.result-ast b/compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.result-ast index ca8a45f681..bd43d845a3 100644 --- a/compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/type_decl_with_underscore.expr.result-ast @@ -1,28 +1,30 @@ Defs( [ - @0-30 Annotation( - @0-7 Identifier( - "doStuff", - ), - @20-30 Function( - [ - @10-16 Apply( - "", - "UserId", - [], - ), - ], - @20-30 Apply( - "", - "Task", + @0-30 Value( + Annotation( + @0-7 Identifier( + "doStuff", + ), + @20-30 Function( [ - @25-28 Apply( + @10-16 Apply( "", - "Str", + "UserId", [], ), - @29-30 Inferred, ], + @20-30 Apply( + "", + "Task", + [ + @25-28 Apply( + "", + "Str", + [], + ), + @29-30 Inferred, + ], + ), ), ), ), diff --git a/compiler/parse/tests/snapshots/pass/where_clause_function.expr.result-ast b/compiler/parse/tests/snapshots/pass/where_clause_function.expr.result-ast index 89f39700a8..9f9d62c54f 100644 --- a/compiler/parse/tests/snapshots/pass/where_clause_function.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/where_clause_function.expr.result-ast @@ -1,37 +1,39 @@ Defs( [ - @0-27 Annotation( - @0-1 Identifier( - "f", - ), - @15-27 Where( - @15-16 Function( - [ - @4-5 BoundVariable( - "a", - ), - ], + @0-27 Value( + Annotation( + @0-1 Identifier( + "f", + ), + @15-27 Where( @15-16 Function( [ - @10-11 BoundVariable( - "b", + @4-5 BoundVariable( + "a", ), ], - @15-16 BoundVariable( - "c", + @15-16 Function( + [ + @10-11 BoundVariable( + "b", + ), + ], + @15-16 BoundVariable( + "c", + ), ), ), + [ + @20-27 HasClause { + var: @20-21 "a", + ability: @26-27 Apply( + "", + "A", + [], + ), + }, + ], ), - [ - @20-27 HasClause { - var: @20-21 "a", - ability: @26-27 Apply( - "", - "A", - [], - ), - }, - ], ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/where_clause_multiple_has.expr.result-ast b/compiler/parse/tests/snapshots/pass/where_clause_multiple_has.expr.result-ast index 223beca196..b823357d7e 100644 --- a/compiler/parse/tests/snapshots/pass/where_clause_multiple_has.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/where_clause_multiple_has.expr.result-ast @@ -1,53 +1,55 @@ Defs( [ - @0-48 Annotation( - @0-1 Identifier( - "f", - ), - @15-48 Where( - @15-16 Function( - [ - @4-5 BoundVariable( - "a", - ), - ], + @0-48 Value( + Annotation( + @0-1 Identifier( + "f", + ), + @15-48 Where( @15-16 Function( [ - @10-11 BoundVariable( - "b", + @4-5 BoundVariable( + "a", ), ], - @15-16 BoundVariable( - "c", + @15-16 Function( + [ + @10-11 BoundVariable( + "b", + ), + ], + @15-16 BoundVariable( + "c", + ), ), ), + [ + @20-27 HasClause { + var: @20-21 "a", + ability: @26-27 Apply( + "", + "A", + [], + ), + }, + @29-37 HasClause { + var: @29-30 "b", + ability: @35-37 Apply( + "", + "Eq", + [], + ), + }, + @39-48 HasClause { + var: @39-40 "c", + ability: @45-48 Apply( + "", + "Ord", + [], + ), + }, + ], ), - [ - @20-27 HasClause { - var: @20-21 "a", - ability: @26-27 Apply( - "", - "A", - [], - ), - }, - @29-37 HasClause { - var: @29-30 "b", - ability: @35-37 Apply( - "", - "Eq", - [], - ), - }, - @39-48 HasClause { - var: @39-40 "c", - ability: @45-48 Apply( - "", - "Ord", - [], - ), - }, - ], ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.result-ast b/compiler/parse/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.result-ast index 36428ce1b4..226a3edb57 100644 --- a/compiler/parse/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.result-ast @@ -1,68 +1,70 @@ Defs( [ - @0-67 Annotation( - @0-1 Identifier( - "f", - ), - @15-67 Where( - @15-16 SpaceBefore( - Function( - [ - @4-5 BoundVariable( - "a", - ), - ], - @15-16 Function( + @0-67 Value( + Annotation( + @0-1 Identifier( + "f", + ), + @15-67 Where( + @15-16 SpaceBefore( + Function( [ - @10-11 BoundVariable( - "b", + @4-5 BoundVariable( + "a", ), ], - @15-16 BoundVariable( - "c", + @15-16 Function( + [ + @10-11 BoundVariable( + "b", + ), + ], + @15-16 BoundVariable( + "c", + ), ), ), + [ + Newline, + ], ), [ - Newline, + @24-34 HasClause { + var: @24-25 "a", + ability: @30-34 Apply( + "", + "Hash", + [], + ), + }, + @42-50 HasClause { + var: @42-43 SpaceBefore( + "b", + [ + Newline, + ], + ), + ability: @48-50 Apply( + "", + "Eq", + [], + ), + }, + @58-67 HasClause { + var: @58-59 SpaceBefore( + "c", + [ + Newline, + ], + ), + ability: @64-67 Apply( + "", + "Ord", + [], + ), + }, ], ), - [ - @24-34 HasClause { - var: @24-25 "a", - ability: @30-34 Apply( - "", - "Hash", - [], - ), - }, - @42-50 HasClause { - var: @42-43 SpaceBefore( - "b", - [ - Newline, - ], - ), - ability: @48-50 Apply( - "", - "Eq", - [], - ), - }, - @58-67 HasClause { - var: @58-59 SpaceBefore( - "c", - [ - Newline, - ], - ), - ability: @64-67 Apply( - "", - "Ord", - [], - ), - }, - ], ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/where_clause_non_function.expr.result-ast b/compiler/parse/tests/snapshots/pass/where_clause_non_function.expr.result-ast index ae9ce97671..841d963271 100644 --- a/compiler/parse/tests/snapshots/pass/where_clause_non_function.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/where_clause_non_function.expr.result-ast @@ -1,23 +1,25 @@ Defs( [ - @0-15 Annotation( - @0-1 Identifier( - "f", - ), - @4-15 Where( - @4-5 BoundVariable( - "a", + @0-15 Value( + Annotation( + @0-1 Identifier( + "f", + ), + @4-15 Where( + @4-5 BoundVariable( + "a", + ), + [ + @8-15 HasClause { + var: @8-9 "a", + ability: @14-15 Apply( + "", + "A", + [], + ), + }, + ], ), - [ - @8-15 HasClause { - var: @8-9 "a", - ability: @14-15 Apply( - "", - "A", - [], - ), - }, - ], ), ), ], diff --git a/compiler/parse/tests/snapshots/pass/where_clause_on_newline.expr.result-ast b/compiler/parse/tests/snapshots/pass/where_clause_on_newline.expr.result-ast index 81df078444..29ac20747f 100644 --- a/compiler/parse/tests/snapshots/pass/where_clause_on_newline.expr.result-ast +++ b/compiler/parse/tests/snapshots/pass/where_clause_on_newline.expr.result-ast @@ -1,37 +1,39 @@ Defs( [ - @0-29 Annotation( - @0-1 Identifier( - "f", - ), - @9-29 Where( - @9-12 SpaceBefore( - Function( - [ - @4-5 BoundVariable( - "a", + @0-29 Value( + Annotation( + @0-1 Identifier( + "f", + ), + @9-29 Where( + @9-12 SpaceBefore( + Function( + [ + @4-5 BoundVariable( + "a", + ), + ], + @9-12 Apply( + "", + "U64", + [], ), - ], - @9-12 Apply( - "", - "U64", - [], ), + [ + Newline, + ], ), [ - Newline, + @19-29 HasClause { + var: @19-20 "a", + ability: @25-29 Apply( + "", + "Hash", + [], + ), + }, ], ), - [ - @19-29 HasClause { - var: @19-20 "a", - ability: @25-29 Apply( - "", - "Hash", - [], - ), - }, - ], ), ), ],