From 6a34c080497b953a5ea00c9a9ad0a1057a70208c Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 20 Mar 2021 01:05:05 +0100 Subject: [PATCH 01/84] cleanup --- compiler/mono/src/ir.rs | 64 +++-------------------------------------- 1 file changed, 4 insertions(+), 60 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 00ff4b499d..160e64bf4d 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -4049,9 +4049,8 @@ pub fn with_hole<'a>( let arg_symbols = arg_symbols.into_bump_slice(); // layout of the return type - let layout = layout_cache - .from_var(env.arena, ret_var, env.subs) - .unwrap_or_else(|err| todo!("TODO turn fn_var into a RuntimeError {:?}", err)); + let layout = + return_on_layout_error!(env, layout_cache.from_var(env.arena, ret_var, env.subs)); let call = self::Call { call_type: CallType::Foreign { @@ -4072,8 +4071,6 @@ pub fn with_hole<'a>( } RunLowLevel { op, args, ret_var } => { - let op = optimize_low_level(env.subs, op, &args); - let mut arg_symbols = Vec::with_capacity_in(args.len(), env.arena); for (_, arg_expr) in args.iter() { @@ -4082,23 +4079,8 @@ pub fn with_hole<'a>( let arg_symbols = arg_symbols.into_bump_slice(); // layout of the return type - let layout = match layout_cache.from_var(env.arena, ret_var, env.subs) { - Ok(cached) => cached, - Err(LayoutProblem::UnresolvedTypeVar(_)) => { - return Stmt::RuntimeError(env.arena.alloc(format!( - "UnresolvedTypeVar {} line {}", - file!(), - line!() - ))); - } - Err(LayoutProblem::Erroneous) => { - return Stmt::RuntimeError(env.arena.alloc(format!( - "Erroneous {} line {}", - file!(), - line!() - ))); - } - }; + let layout = + return_on_layout_error!(env, layout_cache.from_var(env.arena, ret_var, env.subs)); let call = self::Call { call_type: CallType::LowLevel { op }, @@ -7034,44 +7016,6 @@ fn from_can_record_destruct<'a>( }) } -/// Potentially translate LowLevel operations into more efficient ones based on -/// uniqueness type info. -/// -/// For example, turning LowLevel::ListSet to LowLevel::ListSetInPlace if the -/// list is Unique. -fn optimize_low_level( - subs: &Subs, - op: LowLevel, - args: &[(Variable, roc_can::expr::Expr)], -) -> LowLevel { - match op { - LowLevel::ListSet => { - // The first arg is the one with the List in it. - // List.set : List elem, Int, elem -> List elem - let list_arg_var = args[0].0; - let content = subs.get_without_compacting(list_arg_var).content; - - match content { - Content::Structure(FlatType::Apply(Symbol::ATTR_ATTR, attr_args)) => { - debug_assert_eq!(attr_args.len(), 2); - - // If the first argument (the List) is unique, - // then we can safely upgrade to List.set_in_place - let attr_arg_content = subs.get_without_compacting(attr_args[0]).content; - - if attr_arg_content.is_unique(subs) { - LowLevel::ListSetInPlace - } else { - LowLevel::ListSet - } - } - _ => op, - } - } - _ => op, - } -} - pub enum IntPrecision { I128, I64, From 19f05c9db8f0bcb7ccaf9149c16f010e1554a949 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 20:55:07 +0100 Subject: [PATCH 02/84] remove old code --- compiler/can/src/expr.rs | 41 +--------------------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index 3eaffe6e55..ea52661f72 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -408,46 +408,7 @@ pub fn canonicalize_expr<'a>( } ast::Expr::Var { module_name, ident } => { canonicalize_lookup(env, scope, module_name, ident, region) - } //ast::Expr::InterpolatedStr(pairs, suffix) => { - // let mut output = Output::new(); - // let can_pairs: Vec<(String, Located)> = pairs - // .into_iter() - // .map(|(string, loc_ident)| { - // // From a language design perspective, we only permit idents in interpolation. - // // However, in a canonical Expr we store it as a full Expr, not a Symbol. - // // This is so that we can resolve it to either Var or Unrecognized; if we - // // stored it as a Symbol, we couldn't record runtime errors here. - // let can_expr = match resolve_ident( - // &env, - // &scope, - // loc_ident.value, - // &mut output.references, - // ) { - // Ok(symbol) => Var(symbol), - // Err(ident) => { - // let loc_ident = Located { - // region: loc_ident.region, - // value: ident, - // }; - - // env.problem(Problem::LookupNotInScope(loc_ident.clone())); - - // RuntimeError(LookupNotInScope(loc_ident)) - // } - // }; - - // ( - // string, - // Located { - // region: loc_ident.region, - // value: can_expr, - // }, - // ) - // }) - // .collect(); - - // (InterpolatedStr(can_pairs, suffix), output) - //} + } ast::Expr::Defs(loc_defs, loc_ret) => { can_defs_with_return( env, From 197835b6edb9a0f6a8391e2d76be18460951fd9a Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 20:56:18 +0100 Subject: [PATCH 03/84] remove nested in expr --- compiler/can/src/expr.rs | 5 --- compiler/can/src/operator.rs | 85 ++++++++++-------------------------- compiler/fmt/src/expr.rs | 7 +-- compiler/parse/src/ast.rs | 4 -- compiler/parse/src/expr.rs | 4 +- editor/src/lang/expr.rs | 1 - 6 files changed, 26 insertions(+), 80 deletions(-) diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index ea52661f72..78cdb8038c 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -728,11 +728,6 @@ pub fn canonicalize_expr<'a>( (RuntimeError(problem), Output::default()) } - ast::Expr::Nested(sub_expr) => { - let (answer, output) = canonicalize_expr(env, var_store, scope, region, sub_expr); - - (answer.value, output) - } ast::Expr::NonBase10Int { string, base, diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index 520e67e2f1..78731de045 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -59,7 +59,7 @@ fn new_op_call_expr<'a>( Located { value, region } } -fn desugar_defs<'a>( +fn desugar_def_helps<'a>( arena: &'a Bump, region: Region, defs: &'a [&'a Located>], @@ -69,7 +69,7 @@ fn desugar_defs<'a>( for loc_def in defs.iter() { let loc_def = Located { - value: desugar_def(arena, &loc_def.value), + value: desugar_def_help(arena, &loc_def.value), region: loc_def.region, }; @@ -94,8 +94,8 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> { SpaceBefore(def, _) | SpaceAfter(def, _) | Nested(SpaceBefore(def, _)) - | Nested(SpaceAfter(def, _)) => desugar_def(arena, def), - Nested(Nested(def)) => desugar_def(arena, def), + | Nested(SpaceAfter(def, _)) => desugar_def_help(arena, def), + Nested(Nested(def)) => desugar_def_help(arena, def), alias @ Alias { .. } => Nested(alias), Nested(alias @ Alias { .. }) => Nested(alias), ann @ Annotation(_, _) => Nested(ann), @@ -130,33 +130,22 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> { pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a Located> { match &loc_expr.value { Float(_) - | Nested(Float(_)) | Num(_) - | Nested(Num(_)) | NonBase10Int { .. } - | Nested(NonBase10Int { .. }) | Str(_) - | Nested(Str(_)) | AccessorFunction(_) - | Nested(AccessorFunction(_)) | Var { .. } - | Nested(Var { .. }) | MalformedIdent(_, _) - | Nested(MalformedIdent(_, _)) | MalformedClosure - | Nested(MalformedClosure) | PrecedenceConflict { .. } - | Nested(PrecedenceConflict { .. }) | GlobalTag(_) - | Nested(GlobalTag(_)) - | PrivateTag(_) - | Nested(PrivateTag(_)) => loc_expr, + | PrivateTag(_) => loc_expr, - Access(sub_expr, paths) | Nested(Access(sub_expr, paths)) => { + Access(sub_expr, paths) => { let region = loc_expr.region; let loc_sub_expr = Located { region, - value: Nested(sub_expr), + value: (*sub_expr).clone(), }; let value = Access(&desugar_expr(arena, arena.alloc(loc_sub_expr)).value, paths); @@ -165,11 +154,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a List { items, final_comments, - } - | Nested(List { - items, - final_comments, - }) => { + } => { let mut new_items = Vec::with_capacity_in(items.len(), arena); for item in items.iter() { @@ -189,11 +174,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a Record { fields, final_comments, - } - | Nested(Record { - fields, - final_comments, - }) => { + } => { let mut new_fields = Vec::with_capacity_in(fields.len(), arena); for field in fields.iter() { @@ -220,12 +201,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a fields, update, final_comments, - } - | Nested(RecordUpdate { - fields, - update, - final_comments, - }) => { + } => { // NOTE the `update` field is always a `Var { .. }` and does not need to be desugared let mut new_fields = Vec::with_capacity_in(fields.len(), arena); @@ -249,14 +225,11 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a }, }) } - Closure(loc_patterns, loc_ret) | Nested(Closure(loc_patterns, loc_ret)) => { - arena.alloc(Located { - region: loc_expr.region, - value: Closure(loc_patterns, desugar_expr(arena, loc_ret)), - }) - } - Backpassing(loc_patterns, loc_body, loc_ret) - | Nested(Backpassing(loc_patterns, loc_body, loc_ret)) => { + Closure(loc_patterns, loc_ret) => arena.alloc(Located { + region: loc_expr.region, + value: Closure(loc_patterns, desugar_expr(arena, loc_ret)), + }), + Backpassing(loc_patterns, loc_body, loc_ret) => { // loc_patterns <- loc_body // // loc_ret @@ -293,13 +266,9 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a } } } - BinOps(lefts, right) | Nested(BinOps(lefts, right)) => { - desugar_bin_ops(arena, loc_expr.region, lefts, right) - } - Defs(defs, loc_ret) | Nested(Defs(defs, loc_ret)) => { - desugar_defs(arena, loc_expr.region, *defs, loc_ret) - } - Apply(loc_fn, loc_args, called_via) | Nested(Apply(loc_fn, loc_args, called_via)) => { + BinOps(lefts, right) => desugar_bin_ops(arena, loc_expr.region, lefts, right), + Defs(defs, loc_ret) => desugar_def_helps(arena, loc_expr.region, *defs, loc_ret), + Apply(loc_fn, loc_args, called_via) => { let mut desugared_args = Vec::with_capacity_in(loc_args.len(), arena); for loc_arg in loc_args.iter() { @@ -313,7 +282,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a region: loc_expr.region, }) } - When(loc_cond_expr, branches) | Nested(When(loc_cond_expr, branches)) => { + When(loc_cond_expr, branches) => { let loc_desugared_cond = &*arena.alloc(desugar_expr(arena, &loc_cond_expr)); let mut desugared_branches = Vec::with_capacity_in(branches.len(), arena); @@ -340,7 +309,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a patterns: alternatives, value: Located { region: desugared.region, - value: Nested(&desugared.value), + value: desugared.value.clone(), }, guard: desugared_guard, })); @@ -353,7 +322,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a region: loc_expr.region, }) } - UnaryOp(loc_arg, loc_op) | Nested(UnaryOp(loc_arg, loc_op)) => { + UnaryOp(loc_arg, loc_op) => { use roc_module::operator::UnaryOp::*; let region = loc_op.region; @@ -379,24 +348,18 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a region: loc_expr.region, }) } - SpaceBefore(expr, _) - | Nested(SpaceBefore(expr, _)) - | SpaceAfter(expr, _) - | Nested(SpaceAfter(expr, _)) - | ParensAround(expr) - | Nested(ParensAround(expr)) - | Nested(Nested(expr)) => { + SpaceBefore(expr, _) | SpaceAfter(expr, _) | ParensAround(expr) => { // Since we've already begun canonicalization, spaces and parens // are no longer needed and should be dropped. desugar_expr( arena, arena.alloc(Located { - value: Nested(expr), + value: (*expr).clone(), region: loc_expr.region, }), ) } - If(if_thens, final_else_branch) | Nested(If(if_thens, final_else_branch)) => { + If(if_thens, final_else_branch) => { // If does not get desugared into `when` so we can give more targetted error messages during type checking. let desugared_final_else = &*arena.alloc(desugar_expr(arena, &final_else_branch)); diff --git a/compiler/fmt/src/expr.rs b/compiler/fmt/src/expr.rs index f04cfdbe35..41fc6592d0 100644 --- a/compiler/fmt/src/expr.rs +++ b/compiler/fmt/src/expr.rs @@ -75,7 +75,7 @@ impl<'a> Formattable<'a> for Expr<'a> { expr: loc_subexpr, .. }) => loc_subexpr.is_multiline(), - ParensAround(subexpr) | Nested(subexpr) => subexpr.is_multiline(), + ParensAround(subexpr) => subexpr.is_multiline(), Closure(loc_patterns, loc_body) => { // check the body first because it's more likely to be multiline @@ -298,9 +298,6 @@ impl<'a> Formattable<'a> for Expr<'a> { sub_expr.format_with_options(buf, parens, newlines, indent); } - Nested(nested_expr) => { - nested_expr.format_with_options(buf, parens, newlines, indent); - } AccessorFunction(key) => { buf.push('.'); buf.push_str(key); @@ -508,8 +505,6 @@ fn empty_line_before_expr<'a>(expr: &'a Expr<'a>) -> bool { false } - Nested(nested_expr) => empty_line_before_expr(nested_expr), - _ => false, } } diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index b92e3debc3..895491d6a0 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -151,10 +151,6 @@ pub enum Expr<'a> { SpaceAfter(&'a Expr<'a>, &'a [CommentOrNewline<'a>]), ParensAround(&'a Expr<'a>), - /// This is used only to avoid cloning when reordering expressions (e.g. in desugar()). - /// It lets us take an (&Expr) and create a plain (Expr) from it. - Nested(&'a Expr<'a>), - // Problems MalformedIdent(&'a str, crate::ident::BadIdent), MalformedClosure, diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index bc9075eced..2866809b51 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -1335,9 +1335,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result { - expr_to_pattern_help(arena, sub_expr) - } + Expr::ParensAround(sub_expr) => expr_to_pattern_help(arena, sub_expr), Expr::Record { fields, diff --git a/editor/src/lang/expr.rs b/editor/src/lang/expr.rs index 70cb52f6e8..10bdacb515 100644 --- a/editor/src/lang/expr.rs +++ b/editor/src/lang/expr.rs @@ -809,7 +809,6 @@ pub fn to_expr2<'a>( // (RuntimeError(problem), Output::default()) todo!() } - Nested(sub_expr) => to_expr2(env, scope, sub_expr, region), Var { module_name, ident } => canonicalize_lookup(env, scope, module_name, ident, region), // Below this point, we shouln't see any of these nodes anymore because From 2827af7e59aba409554595ee48df19c591b7493d Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 21:03:37 +0100 Subject: [PATCH 04/84] remove Nested from pattern --- compiler/can/src/operator.rs | 9 ++------- compiler/can/src/pattern.rs | 2 +- compiler/fmt/src/pattern.rs | 6 ------ compiler/parse/src/ast.rs | 10 ++-------- editor/src/lang/pattern.rs | 2 +- 5 files changed, 6 insertions(+), 23 deletions(-) diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index 78731de045..d1de3bf4f2 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -4,7 +4,7 @@ use roc_module::ident::ModuleName; use roc_module::operator::BinOp::Pizza; use roc_module::operator::{BinOp, CalledVia}; use roc_parse::ast::Expr::{self, *}; -use roc_parse::ast::{AssignedField, Def, Pattern, WhenBranch}; +use roc_parse::ast::{AssignedField, Def, WhenBranch}; use roc_region::all::{Located, Region}; // BinOp precedence logic adapted from Gluon by Markus Westerlind, MIT licensed @@ -290,12 +290,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a let desugared = desugar_expr(arena, &branch.value); let mut alternatives = Vec::with_capacity_in(branch.patterns.len(), arena); - for loc_pattern in branch.patterns.iter() { - alternatives.push(Located { - region: loc_pattern.region, - value: Pattern::Nested(&loc_pattern.value), - }) - } + alternatives.extend(branch.patterns.iter().copied()); let desugared_guard = if let Some(guard) = &branch.guard { Some(desugar_expr(arena, guard).clone()) diff --git a/compiler/can/src/pattern.rs b/compiler/can/src/pattern.rs index d95965da52..a150befc24 100644 --- a/compiler/can/src/pattern.rs +++ b/compiler/can/src/pattern.rs @@ -238,7 +238,7 @@ pub fn canonicalize_pattern<'a>( ptype => unsupported_pattern(env, ptype, region), }, - SpaceBefore(sub_pattern, _) | SpaceAfter(sub_pattern, _) | Nested(sub_pattern) => { + SpaceBefore(sub_pattern, _) | SpaceAfter(sub_pattern, _) => { return canonicalize_pattern(env, var_store, scope, pattern_type, sub_pattern, region) } RecordDestructure(patterns) => { diff --git a/compiler/fmt/src/pattern.rs b/compiler/fmt/src/pattern.rs index f768b26813..30f0d96125 100644 --- a/compiler/fmt/src/pattern.rs +++ b/compiler/fmt/src/pattern.rs @@ -22,8 +22,6 @@ impl<'a> Formattable<'a> for Pattern<'a> { spaces.iter().any(|s| s.is_comment()) } - Pattern::Nested(nested_pat) => nested_pat.is_multiline(), - Pattern::RecordDestructure(fields) => fields.iter().any(|f| f.is_multiline()), Pattern::RequiredField(_, subpattern) => subpattern.is_multiline(), @@ -153,10 +151,6 @@ impl<'a> Formattable<'a> for Pattern<'a> { } } - Nested(sub_pattern) => { - sub_pattern.format_with_options(buf, parens, newlines, indent); - } - // Malformed Malformed(string) | MalformedIdent(string, _) => buf.push_str(string), QualifiedIdentifier { module_name, ident } => { diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 895491d6a0..5e39738711 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -57,7 +57,7 @@ impl EscapedChar { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum StrLiteral<'a> { /// The most common case: a plain string with no escapes or interpolations PlainLine(&'a str), @@ -326,7 +326,7 @@ impl<'a> CommentOrNewline<'a> { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum Pattern<'a> { // Identifier Identifier(&'a str), @@ -347,10 +347,6 @@ pub enum Pattern<'a> { /// Can only occur inside of a RecordDestructure OptionalField(&'a str, &'a Loc>), - /// This is used only to avoid cloning when reordering expressions (e.g. in desugar()). - /// It lets us take an (&Expr) and create a plain (Expr) from it. - Nested(&'a Pattern<'a>), - // Literal NumLiteral(&'a str), NonBase10Literal { @@ -460,8 +456,6 @@ impl<'a> Pattern<'a> { // { x, y ? False } = rec x == y } - (Nested(x), Nested(y)) => x.equivalent(y), - // Literal (NumLiteral(x), NumLiteral(y)) => x == y, ( diff --git a/editor/src/lang/pattern.rs b/editor/src/lang/pattern.rs index 317c871622..dab08d384e 100644 --- a/editor/src/lang/pattern.rs +++ b/editor/src/lang/pattern.rs @@ -414,7 +414,7 @@ pub fn to_pattern2<'a>( malformed_pattern(env, problem, region) } - SpaceBefore(sub_pattern, _) | SpaceAfter(sub_pattern, _) | Nested(sub_pattern) => { + SpaceBefore(sub_pattern, _) | SpaceAfter(sub_pattern, _) => { return to_pattern2(env, scope, pattern_type, sub_pattern, region) } }; From f3fc9f450fd1b603bb5b3c07e098b51cc8a8d2a9 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 21:05:36 +0100 Subject: [PATCH 05/84] make ast::Expr Copy --- compiler/parse/src/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 5e39738711..181c7e0915 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -74,7 +74,7 @@ pub enum StrLiteral<'a> { /// we move on to canonicalization, which often needs to allocate more because /// it's doing things like turning local variables into fully qualified symbols. /// Once canonicalization is done, the arena and the input string get dropped. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum Expr<'a> { // Number Literals Float(&'a str), From 52854a6f57b9af1010b05314340134cb29ea0d7a Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 21:08:16 +0100 Subject: [PATCH 06/84] make Def and TypeAnnotation Copy --- compiler/parse/src/ast.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 181c7e0915..32847879c2 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -159,7 +159,7 @@ pub enum Expr<'a> { PrecedenceConflict(&'a PrecedenceConflict<'a>), } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct PrecedenceConflict<'a> { pub whole_region: Region, pub binop1_position: Position, @@ -169,7 +169,7 @@ pub struct PrecedenceConflict<'a> { pub expr: &'a Loc>, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum Def<'a> { // TODO in canonicalization, validate the pattern; only certain patterns // are allowed in annotations. @@ -211,7 +211,7 @@ pub enum Def<'a> { NotYetImplemented(&'static str), } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] pub enum TypeAnnotation<'a> { /// A function. The types of its arguments, then the type of its return value. Function(&'a [Loc>], &'a Loc>), From ce98da9d0474e2ad04488a5b0666b5f5f5a3b3a0 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 21:14:32 +0100 Subject: [PATCH 07/84] remove Nested from Def --- compiler/can/src/def.rs | 2 +- compiler/can/src/operator.rs | 28 ++++++---------------------- compiler/fmt/src/def.rs | 2 -- compiler/load/src/docs.rs | 2 +- compiler/parse/src/ast.rs | 4 ---- editor/src/lang/def.rs | 2 +- 6 files changed, 9 insertions(+), 31 deletions(-) diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index 82c9fb71c8..54d361b46d 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -1481,7 +1481,7 @@ fn to_pending_def<'a>( } } - SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) | Nested(sub_def) => { + SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) => { to_pending_def(env, var_store, sub_def, scope, pattern_type) } diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index d1de3bf4f2..428cddbb67 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -69,7 +69,7 @@ fn desugar_def_helps<'a>( for loc_def in defs.iter() { let loc_def = Located { - value: desugar_def_help(arena, &loc_def.value), + value: desugar_def(arena, &loc_def.value), region: loc_def.region, }; @@ -88,39 +88,23 @@ pub fn desugar_def<'a>(arena: &'a Bump, def: &'a Def<'a>) -> Def<'a> { use roc_parse::ast::Def::*; match def { - Body(loc_pattern, loc_expr) | Nested(Body(loc_pattern, loc_expr)) => { - Body(loc_pattern, desugar_expr(arena, loc_expr)) - } - SpaceBefore(def, _) - | SpaceAfter(def, _) - | Nested(SpaceBefore(def, _)) - | Nested(SpaceAfter(def, _)) => desugar_def_help(arena, def), - Nested(Nested(def)) => desugar_def_help(arena, def), - alias @ Alias { .. } => Nested(alias), - Nested(alias @ Alias { .. }) => Nested(alias), - ann @ Annotation(_, _) => Nested(ann), - Nested(ann @ Annotation(_, _)) => Nested(ann), + Body(loc_pattern, loc_expr) => Body(loc_pattern, desugar_expr(arena, loc_expr)), + SpaceBefore(def, _) | SpaceAfter(def, _) => desugar_def(arena, def), + alias @ Alias { .. } => *alias, + ann @ Annotation(_, _) => *ann, AnnotatedBody { ann_pattern, ann_type, comment, body_pattern, body_expr, - } - | Nested(AnnotatedBody { - ann_pattern, - ann_type, - comment, - body_pattern, - body_expr, - }) => AnnotatedBody { + } => AnnotatedBody { ann_pattern, ann_type, comment: *comment, body_pattern: *body_pattern, body_expr: desugar_expr(arena, body_expr), }, - Nested(NotYetImplemented(s)) => todo!("{}", s), NotYetImplemented(s) => todo!("{}", s), } } diff --git a/compiler/fmt/src/def.rs b/compiler/fmt/src/def.rs index f6d9558ede..92de3da1ce 100644 --- a/compiler/fmt/src/def.rs +++ b/compiler/fmt/src/def.rs @@ -19,7 +19,6 @@ impl<'a> Formattable<'a> for Def<'a> { SpaceBefore(sub_def, spaces) | SpaceAfter(sub_def, spaces) => { spaces.iter().any(|s| s.is_comment()) || sub_def.is_multiline() } - Nested(def) => def.is_multiline(), NotYetImplemented(s) => todo!("{}", s), } } @@ -99,7 +98,6 @@ impl<'a> Formattable<'a> for Def<'a> { sub_def.format(buf, indent); fmt_spaces(buf, spaces.iter(), indent); } - Nested(def) => def.format(buf, indent), NotYetImplemented(s) => todo!("{}", s), } } diff --git a/compiler/load/src/docs.rs b/compiler/load/src/docs.rs index b52d655cf4..f5c8bfc6ad 100644 --- a/compiler/load/src/docs.rs +++ b/compiler/load/src/docs.rs @@ -120,7 +120,7 @@ fn generate_module_doc<'a>( (acc, None) } - Body(_, _) | Nested(_) => (acc, None), + Body(_, _) => (acc, None), NotYetImplemented(s) => todo!("{}", s), } diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 32847879c2..074061b680 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -204,10 +204,6 @@ pub enum Def<'a> { SpaceBefore(&'a Def<'a>, &'a [CommentOrNewline<'a>]), SpaceAfter(&'a Def<'a>, &'a [CommentOrNewline<'a>]), - /// This is used only to avoid cloning when reordering expressions (e.g. in desugar()). - /// It lets us take a (&Def) and create a plain (Def) from it. - Nested(&'a Def<'a>), - NotYetImplemented(&'static str), } diff --git a/editor/src/lang/def.rs b/editor/src/lang/def.rs index 0dc6420db6..6cc88b8f6d 100644 --- a/editor/src/lang/def.rs +++ b/editor/src/lang/def.rs @@ -247,7 +247,7 @@ fn to_pending_def<'a>( } } - SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) | Nested(sub_def) => { + SpaceBefore(sub_def, _) | SpaceAfter(sub_def, _) => { to_pending_def(env, sub_def, scope, pattern_type) } From f3318fbc2fdcbb384692a107c108159a8d164d9d Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 21:38:11 +0100 Subject: [PATCH 08/84] more Copy --- compiler/parse/src/ast.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/parse/src/ast.rs b/compiler/parse/src/ast.rs index 074061b680..0118ff379c 100644 --- a/compiler/parse/src/ast.rs +++ b/compiler/parse/src/ast.rs @@ -12,20 +12,20 @@ pub enum Module<'a> { Platform { header: PlatformHeader<'a> }, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct WhenBranch<'a> { pub patterns: &'a [Loc>], pub value: Loc>, pub guard: Option>>, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct WhenPattern<'a> { pub pattern: Loc>, pub guard: Option>>, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum StrSegment<'a> { Plaintext(&'a str), // e.g. "foo" Unicode(Loc<&'a str>), // e.g. "00A0" in "\u(00A0)" @@ -33,7 +33,7 @@ pub enum StrSegment<'a> { Interpolated(Loc<&'a Expr<'a>>), // e.g. (name) in "Hi, \(name)!" } -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum EscapedChar { Newline, // \n Tab, // \t @@ -253,7 +253,7 @@ pub enum TypeAnnotation<'a> { Malformed(&'a str), } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum Tag<'a> { Global { name: Loc<&'a str>, @@ -273,7 +273,7 @@ pub enum Tag<'a> { Malformed(&'a str), } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum AssignedField<'a, Val> { // A required field with a label, e.g. `{ name: "blah" }` or `{ name : Str }` RequiredValue(Loc<&'a str>, &'a [CommentOrNewline<'a>], &'a Loc), @@ -295,7 +295,7 @@ pub enum AssignedField<'a, Val> { Malformed(&'a str), } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum CommentOrNewline<'a> { Newline, LineComment(&'a str), From ef211ce49a9108bd672b52f1a09c8c8c98065d04 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 22:13:57 +0100 Subject: [PATCH 09/84] clippy --- compiler/can/src/operator.rs | 15 ++++++--------- compiler/parse/src/expr.rs | 6 +++--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/compiler/can/src/operator.rs b/compiler/can/src/operator.rs index 428cddbb67..53e082407e 100644 --- a/compiler/can/src/operator.rs +++ b/compiler/can/src/operator.rs @@ -129,7 +129,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a let region = loc_expr.region; let loc_sub_expr = Located { region, - value: (*sub_expr).clone(), + value: **sub_expr, }; let value = Access(&desugar_expr(arena, arena.alloc(loc_sub_expr)).value, paths); @@ -277,7 +277,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a alternatives.extend(branch.patterns.iter().copied()); let desugared_guard = if let Some(guard) = &branch.guard { - Some(desugar_expr(arena, guard).clone()) + Some(*desugar_expr(arena, guard)) } else { None }; @@ -286,10 +286,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a desugared_branches.push(&*arena.alloc(WhenBranch { patterns: alternatives, - value: Located { - region: desugared.region, - value: desugared.value.clone(), - }, + value: *desugared, guard: desugared_guard, })); } @@ -333,7 +330,7 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a desugar_expr( arena, arena.alloc(Located { - value: (*expr).clone(), + value: **expr, region: loc_expr.region, }), ) @@ -346,8 +343,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located>) -> &'a for (condition, then_branch) in if_thens.iter() { desugared_if_thens.push(( - desugar_expr(arena, condition).clone(), - desugar_expr(arena, then_branch).clone(), + *desugar_expr(arena, condition), + *desugar_expr(arena, then_branch), )); } diff --git a/compiler/parse/src/expr.rs b/compiler/parse/src/expr.rs index 2866809b51..0b163b5057 100644 --- a/compiler/parse/src/expr.rs +++ b/compiler/parse/src/expr.rs @@ -1379,7 +1379,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result Err(()), - Expr::Str(string) => Ok(Pattern::StrLiteral(string.clone())), + Expr::Str(string) => Ok(Pattern::StrLiteral(*string)), Expr::MalformedIdent(string, _problem) => Ok(Pattern::Malformed(string)), } } @@ -1408,7 +1408,7 @@ fn assigned_expr_field_to_pattern_help<'a>( AssignedField::OptionalValue(name, spaces, value) => { let result = arena.alloc(Located { region: value.region, - value: value.value.clone(), + value: value.value, }); if spaces.is_empty() { Pattern::OptionalField(name.value, result) @@ -1456,7 +1456,7 @@ pub fn defs<'a>(min_indent: u16) -> impl Parser<'a, Vec<'a, Located>>, E let last = def_state.defs.len() - 1; for (i, ref_def) in def_state.defs.into_iter().enumerate() { - let mut def = ref_def.clone(); + let mut def = *ref_def; if i == first { def = arena From b68192327081e1b61dbc77f538248f42b5c07231 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 22:52:23 +0100 Subject: [PATCH 10/84] report malformed type names in annotations --- compiler/can/src/annotation.rs | 28 +++- compiler/problem/src/can.rs | 1 + compiler/reporting/src/error/canonicalize.rs | 16 ++- compiler/reporting/tests/test_reporting.rs | 134 +++++++++++++------ 4 files changed, 129 insertions(+), 50 deletions(-) diff --git a/compiler/can/src/annotation.rs b/compiler/can/src/annotation.rs index f9db76ab05..f7ec5dd547 100644 --- a/compiler/can/src/annotation.rs +++ b/compiler/can/src/annotation.rs @@ -65,6 +65,13 @@ impl IntroducedVariables { } } +fn malformed(env: &mut Env, region: Region, name: &str) { + use roc_problem::can::RuntimeError::*; + + let problem = MalformedTypeName((*name).into(), region); + env.problem(roc_problem::can::Problem::RuntimeError(problem.clone())); +} + pub fn canonicalize_annotation( env: &mut Env, scope: &mut Scope, @@ -446,7 +453,16 @@ fn can_annotation_help( local_aliases, references, ), - Wildcard | Malformed(_) => { + Wildcard => { + let var = var_store.fresh(); + + introduced_variables.insert_wildcard(var); + + Type::Variable(var) + } + Malformed(string) => { + malformed(env, region, string); + let var = var_store.fresh(); introduced_variables.insert_wildcard(var); @@ -542,8 +558,9 @@ fn can_assigned_fields<'a>( field = nested; continue 'inner; } - Malformed(_) => { - // TODO report this? + Malformed(string) => { + malformed(env, region, string); + // completely skip this element, advance to the next tag continue 'outer; } @@ -645,8 +662,9 @@ fn can_tags<'a>( tag = nested; continue 'inner; } - Tag::Malformed(_) => { - // TODO report this? + Tag::Malformed(string) => { + malformed(env, region, string); + // completely skip this element, advance to the next tag continue 'outer; } diff --git a/compiler/problem/src/can.rs b/compiler/problem/src/can.rs index f28d3b1c5e..6fc5c086aa 100644 --- a/compiler/problem/src/can.rs +++ b/compiler/problem/src/can.rs @@ -134,6 +134,7 @@ pub enum RuntimeError { }, InvalidPrecedence(PrecedenceProblem, Region), MalformedIdentifier(Box, roc_parse::ident::BadIdent, Region), + MalformedTypeName(Box, Region), MalformedClosure(Region), InvalidRecordUpdate { region: Region, diff --git a/compiler/reporting/src/error/canonicalize.rs b/compiler/reporting/src/error/canonicalize.rs index 9ccd46c4c0..452b60e46c 100644 --- a/compiler/reporting/src/error/canonicalize.rs +++ b/compiler/reporting/src/error/canonicalize.rs @@ -776,8 +776,20 @@ fn pretty_runtime_error<'b>( } RuntimeError::MalformedIdentifier(_box_str, bad_ident, surroundings) => { to_bad_ident_expr_report(alloc, bad_ident, surroundings) - - + } + RuntimeError::MalformedTypeName(_box_str, surroundings) => { + alloc.stack(vec![ + alloc.reflow(r"I am confused by this type name:"), + alloc.region(surroundings), + alloc.concat(vec![ + alloc.reflow("Type names start with an uppercase letter, "), + alloc.reflow("and can optionally be qualified by a module name, like "), + alloc.parser_suggestion("Bool"), + alloc.reflow(" or "), + alloc.parser_suggestion("Http.Request.Request"), + alloc.reflow("."), + ]), + ]) } RuntimeError::MalformedClosure(_) => todo!(""), RuntimeError::InvalidFloat(sign @ FloatErrorKind::PositiveInfinity, region, _raw_str) diff --git a/compiler/reporting/tests/test_reporting.rs b/compiler/reporting/tests/test_reporting.rs index f86d7909d4..d6430cab2f 100644 --- a/compiler/reporting/tests/test_reporting.rs +++ b/compiler/reporting/tests/test_reporting.rs @@ -3265,20 +3265,20 @@ mod test_reporting { indoc!( r#" ── TYPE MISMATCH ─────────────────────────────────────────────────────────────── - + Something is off with the body of the `x` definition: - + 4│ x : AList I64 I64 5│ x = ACons 0 (BCons 1 (ACons "foo" BNil )) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - + This `ACons` global tag application has the type: - + [ ACons Num (Integer Signed64) [ BCons (Num a) [ ACons Str [ BNil ]b ]c ]d, ANil ] - + But the type annotation on `x` says it should be: - + [ ACons I64 BList I64 I64, ANil ] "# ), @@ -4155,12 +4155,12 @@ mod test_reporting { indoc!( r#" ── UNKNOWN OPERATOR ──────────────────────────────────────────────────────────── - + This looks like an operator, but it's not one I recognize! - + 1│ f :: I64 ^^ - + I have no specific suggestion for this operator, see TODO for the full list of operators in Roc. "# @@ -4188,12 +4188,12 @@ mod test_reporting { indoc!( r#" ── TOO MANY ARGS ─────────────────────────────────────────────────────────────── - + This value is not a function, but it was given 3 arguments: - + 3│ x == 5 ^ - + Are there any missing commas? Or missing parentheses? "# ), @@ -4476,12 +4476,12 @@ mod test_reporting { indoc!( r#" ── TAB CHARACTER ─────────────────────────────────────────────────────────────── - + I encountered a tab character - - 1│ # comment with a + + 1│ # comment with a ^ - + Tab characters are not allowed. "# ), @@ -4500,9 +4500,9 @@ mod test_reporting { indoc!( r#" ── BAD TYPE VARIABLE ─────────────────────────────────────────────────────────── - + I am expecting a type variable, but I got stuck here: - + 1│ f : ( ^ "# @@ -4545,7 +4545,19 @@ mod test_reporting { f "# ), - indoc!(r#""#), + indoc!( + r#" + ── SYNTAX PROBLEM ────────────────────────────────────────────────────────────── + + I am confused by this type name: + + 1│ f : Foo..Bar + ^^^^^^^^ + + Type names start with an uppercase letter, and can optionally be + qualified by a module name, like Bool or Http.Request.Request. + "# + ), ) // ── DOUBLE DOT ────────────────────────────────────────────────────────────────── @@ -4568,7 +4580,19 @@ mod test_reporting { f "# ), - indoc!(r#""#), + indoc!( + r#" + ── SYNTAX PROBLEM ────────────────────────────────────────────────────────────── + + I am confused by this type name: + + 1│ f : Foo.Bar. + ^^^^^^^^ + + Type names start with an uppercase letter, and can optionally be + qualified by a module name, like Bool or Http.Request.Request. + "# + ), ) // ── TRAILING DOT ──────────────────────────────────────────────────────────────── @@ -4619,7 +4643,19 @@ mod test_reporting { f "# ), - indoc!(r#""#), + indoc!( + r#" + ── SYNTAX PROBLEM ────────────────────────────────────────────────────────────── + + I am confused by this type name: + + 1│ f : Foo.1 + ^^^^^ + + Type names start with an uppercase letter, and can optionally be + qualified by a module name, like Bool or Http.Request.Request. + "# + ), ) // ── WEIRD QUALIFIED NAME ──────────────────────────────────────────────────────── @@ -4643,7 +4679,19 @@ mod test_reporting { f "# ), - indoc!(r#""#), + indoc!( + r#" + ── SYNTAX PROBLEM ────────────────────────────────────────────────────────────── + + I am confused by this type name: + + 1│ f : Foo.foo + ^^^^^^^ + + Type names start with an uppercase letter, and can optionally be + qualified by a module name, like Bool or Http.Request.Request. + "# + ), ) } @@ -4658,19 +4706,19 @@ mod test_reporting { indoc!( r#" ── MISSING FINAL EXPRESSION ──────────────────────────────────────────────────── - + I am partway through parsing a definition's final expression, but I got stuck here: - + 1│ f : Foo.foo ^ - + This definition is missing a final expression. A nested definition must be followed by either another definition, or an expression - + x = 4 y = 2 - + x + y "# ), @@ -4973,13 +5021,13 @@ mod test_reporting { indoc!( r#" ── MISSING EXPRESSION ────────────────────────────────────────────────────────── - + I am partway through parsing a definition, but I got stuck here: - + 1│ when Just 4 is 2│ Just when -> ^ - + I was expecting to see an expression like 42 or "hello". "# ), @@ -5646,14 +5694,14 @@ mod test_reporting { indoc!( r#" ── SYNTAX PROBLEM ────────────────────────────────────────────────────────────── - + I cannot find a `bar` value - + 1│ [ "foo", bar("") ] ^^^ - + these names seem close though: - + Nat Str U8 @@ -5729,16 +5777,16 @@ mod test_reporting { indoc!( r#" ── UNKNOWN OPERATOR ──────────────────────────────────────────────────────────── - + This looks like an operator, but it's not one I recognize! - + 1│ main = 2│ (\x -> x) : I64 ^ - + The has-type operator : can only occur in a definition's type signature, like - + increment : I64 -> I64 increment = \x -> x + 1 "# @@ -5759,19 +5807,19 @@ mod test_reporting { indoc!( r#" ── MISSING FINAL EXPRESSION ──────────────────────────────────────────────────── - + I am partway through parsing a definition's final expression, but I got stuck here: - + 1│ main = 5 -> 3 ^ - + This definition is missing a final expression. A nested definition must be followed by either another definition, or an expression - + x = 4 y = 2 - + x + y "# ), From 03a90faa37a399a60bfec710a827ef64e115bb1c Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 22:53:05 +0100 Subject: [PATCH 11/84] clippy --- compiler/can/src/annotation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/can/src/annotation.rs b/compiler/can/src/annotation.rs index f7ec5dd547..1dae84e6c9 100644 --- a/compiler/can/src/annotation.rs +++ b/compiler/can/src/annotation.rs @@ -69,7 +69,7 @@ fn malformed(env: &mut Env, region: Region, name: &str) { use roc_problem::can::RuntimeError::*; let problem = MalformedTypeName((*name).into(), region); - env.problem(roc_problem::can::Problem::RuntimeError(problem.clone())); + env.problem(roc_problem::can::Problem::RuntimeError(problem)); } pub fn canonicalize_annotation( From 5bbea3510f0e6b158a26722a4b5e60d7c4270bcd Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 21 Mar 2021 23:42:34 +0100 Subject: [PATCH 12/84] fix tab case --- compiler/reporting/tests/test_reporting.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/reporting/tests/test_reporting.rs b/compiler/reporting/tests/test_reporting.rs index d6430cab2f..ee2af9e6bf 100644 --- a/compiler/reporting/tests/test_reporting.rs +++ b/compiler/reporting/tests/test_reporting.rs @@ -4474,16 +4474,16 @@ mod test_reporting { report_problem_as( "# comment with a \t\n4", indoc!( - r#" + " ── TAB CHARACTER ─────────────────────────────────────────────────────────────── I encountered a tab character - 1│ # comment with a + 1│ # comment with a \t ^ Tab characters are not allowed. - "# + " ), ) } From 41e61ba38a062c36e747d110a13962514c5467aa Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 22 Mar 2021 02:04:59 +0100 Subject: [PATCH 13/84] Subs efficiency --- compiler/solve/src/solve.rs | 71 ++++++++++++++----------------------- compiler/types/src/subs.rs | 12 +++++++ vendor/ena/src/unify/mod.rs | 11 ++++++ 3 files changed, 50 insertions(+), 44 deletions(-) diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index 669333e638..bd19e9ffab 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -880,7 +880,7 @@ fn check_for_infinite_type( let var = loc_var.value; let is_uniq_infer = matches!( - subs.get(var).content, + subs.get_ref(var).content, Content::Alias(Symbol::ATTR_ATTR, _, _) ); @@ -1088,7 +1088,7 @@ fn generalize( for vars in all_but_last_pool { for &var in vars { if !subs.redundant(var) { - let rank = subs.get(var).rank; + let rank = subs.get_rank(var); pools.get_mut(rank).push(var); } @@ -1099,13 +1099,12 @@ fn generalize( // otherwise generalize for &var in last_pool { if !subs.redundant(var) { - let mut desc = subs.get(var); + let desc_rank = subs.get_rank(var); - if desc.rank < young_rank { - pools.get_mut(desc.rank).push(var); + if desc_rank < young_rank { + pools.get_mut(desc_rank).push(var); } else { - desc.rank = Rank::NONE; - subs.set(var, desc); + subs.set_rank(var, Rank::NONE); } } } @@ -1121,18 +1120,8 @@ fn pool_to_rank_table( // Sort the variables into buckets by rank. for &var in young_vars.iter() { - let desc = subs.get(var); - let rank = desc.rank; - - subs.set( - var, - Descriptor { - rank, - mark: young_mark, - content: desc.content, - copy: desc.copy, - }, - ); + let rank = subs.get_rank(var); + subs.set_mark(var, young_mark); debug_assert!(rank.into_usize() < young_rank.into_usize() + 1); pools.get_mut(rank).push(var); @@ -1155,24 +1144,15 @@ fn adjust_rank( if desc.mark == young_mark { let Descriptor { content, - rank, + rank: _, mark: _, copy, } = desc; // Mark the variable as visited before adjusting content, as it may be cyclic. - subs.set( - var, - Descriptor { - content: content.clone(), - rank, - mark: visit_mark, - copy, - }, - ); + subs.set_mark(var, visit_mark); - let max_rank = - adjust_rank_content(subs, young_mark, visit_mark, group_rank, content.clone()); + let max_rank = adjust_rank_content(subs, young_mark, visit_mark, group_rank, &content); subs.set( var, @@ -1208,7 +1188,7 @@ fn adjust_rank_content( young_mark: Mark, visit_mark: Mark, group_rank: Rank, - content: Content, + content: &Content, ) -> Rank { use roc_types::subs::Content::*; use roc_types::subs::FlatType::*; @@ -1224,14 +1204,15 @@ fn adjust_rank_content( let mut rank = Rank::toplevel(); for var in args { - rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); + rank = + rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var)); } rank } Func(arg_vars, closure_var, ret_var) => { - let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, ret_var); + let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ret_var); // TODO investigate further. // @@ -1244,12 +1225,13 @@ fn adjust_rank_content( young_mark, visit_mark, group_rank, - closure_var, + *closure_var, )); } for var in arg_vars { - rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); + rank = + rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var)); } rank @@ -1263,7 +1245,7 @@ fn adjust_rank_content( EmptyTagUnion => Rank::toplevel(), Record(fields, ext_var) => { - let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var); + let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var); for (_, var) in fields { rank = rank.max(adjust_rank( @@ -1279,7 +1261,7 @@ fn adjust_rank_content( } TagUnion(tags, ext_var) => { - let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var); + let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var); for var in tags.values().flatten() { rank = @@ -1290,9 +1272,9 @@ fn adjust_rank_content( } RecursiveTagUnion(rec_var, tags, ext_var) => { - let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, rec_var); + let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *rec_var); rank = rank.max(adjust_rank( - subs, young_mark, visit_mark, group_rank, ext_var, + subs, young_mark, visit_mark, group_rank, *ext_var, )); for var in tags.values().flatten() { @@ -1305,10 +1287,11 @@ fn adjust_rank_content( Boolean(Bool::Shared) => Rank::toplevel(), Boolean(Bool::Container(cvar, mvars)) => { - let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, cvar); + let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *cvar); for var in mvars { - rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); + rank = + rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var)); } rank @@ -1322,13 +1305,13 @@ fn adjust_rank_content( let mut rank = Rank::toplevel(); for (_, var) in args { - rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); + rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var)); } // from elm-compiler: THEORY: anything in the real_var would be Rank::toplevel() // this theory is not true in Roc! aliases of function types capture the closure var rank = rank.max(adjust_rank( - subs, young_mark, visit_mark, group_rank, real_var, + subs, young_mark, visit_mark, group_rank, *real_var, )); rank diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 1156fdde1b..27f2e10c49 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -306,6 +306,18 @@ impl Subs { self.utable.probe_value(key) } + pub fn get_ref(&self, key: Variable) -> &Descriptor { + &self.utable.probe_value_ref(key).value + } + + pub fn get_rank(&mut self, key: Variable) -> Rank { + self.utable.probe_value_ref(key).value.rank + } + + pub fn get_mark(&mut self, key: Variable) -> Mark { + self.utable.probe_value_ref(key).value.mark + } + pub fn get_without_compacting(&self, key: Variable) -> Descriptor { self.utable.probe_value_without_compacting(key) } diff --git a/vendor/ena/src/unify/mod.rs b/vendor/ena/src/unify/mod.rs index de12c36a00..2210266f02 100644 --- a/vendor/ena/src/unify/mod.rs +++ b/vendor/ena/src/unify/mod.rs @@ -433,6 +433,17 @@ where self.value(id).value.clone() } + /// Returns the current value for the given key. If the key has + /// been union'd, this will give the value from the current root. + pub fn probe_value_ref(&self, id: K1) -> &VarValue + where + K1: Into, + { + let id = id.into(); + let id = self.get_root_key_without_compacting(id); + self.value(id) + } + /// This is for a debug_assert! in solve() only. Do not use it elsewhere! pub fn probe_value_without_compacting(&self, id: K1) -> V where From 807250f3e395795660819c148a50df43f6ad0219 Mon Sep 17 00:00:00 2001 From: Chadtech Date: Sun, 21 Mar 2021 22:37:39 -0400 Subject: [PATCH 14/84] Moved docs/src/main.rs to docs/src/lib.rs and imported it into the repl. Commented out doc code to avoid it deleting my entire roc project (which happened) --- Cargo.lock | 39 ++++--- cli/Cargo.toml | 1 + cli/src/lib.rs | 33 +++++- cli/src/main.rs | 19 ++- docs/Cargo.toml | 2 +- docs/src/lib.rs | 253 ++++++++++++++++++++++++++++++++++++++++ docs/src/main.rs | 298 ----------------------------------------------- 7 files changed, 324 insertions(+), 321 deletions(-) create mode 100644 docs/src/lib.rs delete mode 100644 docs/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 2d40ce558c..a4621269a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -889,25 +889,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" -[[package]] -name = "docs" -version = "0.1.0" -dependencies = [ - "bumpalo", - "fs_extra", - "handlebars", - "maplit", - "pretty_assertions 0.5.1", - "pulldown-cmark", - "roc_builtins", - "roc_can", - "roc_collections", - "roc_load", - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "downcast-rs" version = "1.2.0" @@ -2961,6 +2942,7 @@ dependencies = [ "roc_can", "roc_collections", "roc_constrain", + "roc_docs", "roc_editor", "roc_fmt", "roc_gen", @@ -3012,6 +2994,25 @@ dependencies = [ "roc_types", ] +[[package]] +name = "roc_docs" +version = "0.1.0" +dependencies = [ + "bumpalo", + "fs_extra", + "handlebars", + "maplit", + "pretty_assertions 0.5.1", + "pulldown-cmark", + "roc_builtins", + "roc_can", + "roc_collections", + "roc_load", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "roc_editor" version = "0.1.0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 6c4b3ba494..bd542b0f43 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -33,6 +33,7 @@ target-all = [ [dependencies] roc_collections = { path = "../compiler/collections" } roc_can = { path = "../compiler/can" } +roc_docs = { path = "../docs" } roc_parse = { path = "../compiler/parse" } roc_region = { path = "../compiler/region" } roc_module = { path = "../compiler/module" } diff --git a/cli/src/lib.rs b/cli/src/lib.rs index dfec81975e..bd5032c50f 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -8,11 +8,12 @@ use roc_build::link::LinkType; use roc_gen::llvm::build::OptLevel; use roc_load::file::LoadingProblem; use std::io; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process; use std::process::Command; use target_lexicon::Triple; + pub mod build; pub mod repl; @@ -76,6 +77,36 @@ pub fn build_app<'a>() -> App<'a> { .help("(optional) The directory or files to open on launch.") ) ) + .subcommand( + App::new("docs") + .about("Generate documentation for Roc modules") + .arg(Arg::with_name(DIRECTORY_OR_FILES) + .index(1) + .multiple(true) + .required(true) + .help("The directory or files to build documentation for") + + ) + ) +} + +pub fn docs(files: Vec) { + roc_docs::generate( + files, + // vec![ + // PathBuf::from(r"./compiler/builtins/docs/Bool.roc"), + // // PathBuf::from(r"../compiler/builtins/docs/Dict.roc"), + // // Not working + // // PathBuf::from(r"../compiler/builtins/docs/List.roc"), + // // Not working + // // PathBuf::from(r"../compiler/builtins/docs/Num.roc"), + // // PathBuf::from(r"../compiler/builtins/docs/Set.roc"), + // // PathBuf::from(r"../compiler/builtins/docs/Str.roc"), + // ], + roc_builtins::std::standard_stdlib(), + Path::new("./"), + // Path::new("./build"), + ) } pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io::Result<()> { diff --git a/cli/src/main.rs b/cli/src/main.rs index 3a07efd95a..d806f3a57b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,6 +1,6 @@ -use roc_cli::{build, build_app, repl, DIRECTORY_OR_FILES}; +use roc_cli::{build, docs, build_app, repl, DIRECTORY_OR_FILES}; use std::io; -use std::path::Path; +use std::path::{Path, PathBuf}; use target_lexicon::Triple; fn main() -> io::Result<()> { @@ -35,6 +35,21 @@ fn main() -> io::Result<()> { } } } + Some("docs") => { + let values = matches + .subcommand_matches("docs") + .unwrap() + .values_of_os(DIRECTORY_OR_FILES) + .unwrap(); + + let paths = values + .map(|os_str| Path::new(os_str).to_path_buf()) + .collect::>(); + + docs(paths); + + Ok(()) + } _ => unreachable!(), } } diff --git a/docs/Cargo.toml b/docs/Cargo.toml index f8438af1b7..60a1225ce7 100644 --- a/docs/Cargo.toml +++ b/docs/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "docs" +name = "roc_docs" version = "0.1.0" authors = ["Pablo Hirafuji "] edition = "2018" diff --git a/docs/src/lib.rs b/docs/src/lib.rs new file mode 100644 index 0000000000..d1887614ab --- /dev/null +++ b/docs/src/lib.rs @@ -0,0 +1,253 @@ +extern crate fs_extra; +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate pulldown_cmark; +extern crate serde_json; +use roc_builtins::std::StdLib; +use roc_can::builtins::builtin_defs_map; +use roc_load::docs::Documentation; +use roc_load::docs::ModuleDocumentation; +use roc_load::file::LoadingProblem; + +use std::fs; +extern crate roc_load; +use bumpalo::Bump; +use roc_collections::all::MutMap; +use std::path::{Path, PathBuf}; + +#[derive(Serialize)] +pub struct Template { + pub package_name: String, + pub package_version: String, + pub module_name: String, + pub module_docs: String, + pub module_entries: Vec, + pub module_links: Vec, +} + +#[derive(Serialize, Clone, Debug, PartialEq)] +pub struct ModuleEntry { + pub name: String, + pub docs: String, +} + +#[derive(Serialize)] +pub struct TemplateLink { + pub name: String, + pub href: String, + pub classes: String, + pub entries: Vec, +} + +#[derive(Serialize)] +pub struct TemplateLinkEntry { + name: String, +} + +// fn main() { +// generate( +// vec![ +// PathBuf::from(r"../compiler/builtins/docs/Bool.roc"), +// // PathBuf::from(r"../compiler/builtins/docs/Dict.roc"), +// // Not working +// // PathBuf::from(r"../compiler/builtins/docs/List.roc"), +// // Not working +// // PathBuf::from(r"../compiler/builtins/docs/Num.roc"), +// // PathBuf::from(r"../compiler/builtins/docs/Set.roc"), +// // PathBuf::from(r"../compiler/builtins/docs/Str.roc"), +// ], +// roc_builtins::std::standard_stdlib(), +// Path::new("../compiler/builtins/docs"), +// // Path::new("./build"), +// ) +// } + +pub fn generate(filenames: Vec, std_lib: StdLib, build_dir: &Path) { + // let files_docs = files_to_documentations(filenames, std_lib); + // + // // TODO: get info from a file like "elm.json" + // let package = roc_load::docs::Documentation { + // name: "roc/builtins".to_string(), + // version: "1.0.0".to_string(), + // docs: "Package introduction or README.".to_string(), + // modules: files_docs, + // }; + // + // let version_folder = build_dir + // .join(package.name.clone()) + // .join(package.version.clone()); + // + // println!("{}", version_folder.display()); + + // // Make sure the output directories exists + // fs::create_dir_all(&version_folder) + // .expect("TODO gracefully handle creating directories failing"); + // + // // Register handlebars template + // let mut handlebars = handlebars::Handlebars::new(); + // handlebars + // .register_template_file("page", "./docs/src/templates/page.hbs") + // .expect("TODO gracefully handle registering template failing"); + // + // // Write each package's module docs html file + // for module in &package.modules { + // let template = documentation_to_template_data(&package, module); + // + // let handlebars_data = handlebars::to_json(&template); + // let filepath = version_folder.join(format!("{}.html", module.name)); + // let mut output_file = + // fs::File::create(filepath).expect("TODO gracefully handle creating file failing"); + // handlebars + // .render_to_write("page", &handlebars_data, &mut output_file) + // .expect("TODO gracefully handle writing file failing"); + // } + // + // // Copy /static folder content to /build + // let copy_options = fs_extra::dir::CopyOptions { + // overwrite: true, + // skip_exist: false, + // buffer_size: 64000, //64kb + // copy_inside: false, + // content_only: true, + // depth: 0, + // }; + // fs_extra::dir::copy("./docs/src/static/", &build_dir, ©_options) + // .expect("TODO gracefully handle copying static content failing"); + // println!("Docs generated at {}", build_dir.display()); +} + +pub fn files_to_documentations( + filenames: Vec, + std_lib: StdLib, +) -> Vec { + let arena = Bump::new(); + let mut files_docs = vec![]; + + for filename in filenames { + let mut src_dir = filename.clone(); + src_dir.pop(); + + match roc_load::file::load_and_typecheck( + &arena, + filename, + &std_lib, + src_dir.as_path(), + MutMap::default(), + 8, // TODO: Is it okay to hardcode ptr_bytes here? I think it should be fine since we'er only type checking (also, 8 => 32bit system) + builtin_defs_map, + ) { + Ok(mut loaded) => files_docs.extend(loaded.documentation.drain().map(|x| x.1)), + Err(LoadingProblem::ParsingFailedReport(report)) => { + println!("{}", report); + panic!(); + } + Err(e) => panic!("{:?}", e), + } + } + files_docs +} + +pub fn documentation_to_template_data( + doc: &Documentation, + module: &ModuleDocumentation, +) -> Template { + Template { + package_name: doc.name.clone(), + package_version: doc.version.clone(), + module_name: module.name.clone(), + module_docs: markdown_to_html(module.docs.clone()), + module_entries: module + .entries + .clone() + .into_iter() + .map(|entry| ModuleEntry { + name: entry.name.clone(), + docs: match entry.docs { + Some(docs) => markdown_to_html(docs), + None => String::new(), + }, + }) + .collect(), + module_links: doc + .modules + .clone() + .into_iter() + .map(|module_link| TemplateLink { + name: module_link.name.clone(), + href: format!("./{}.html", module_link.name), + classes: "".to_string(), + entries: module_link + .entries + .into_iter() + .map(|entry| TemplateLinkEntry { name: entry.name }) + .collect(), + }) + .collect(), + } +} + +fn markdown_to_html(markdown: String) -> String { + use pulldown_cmark::CodeBlockKind::*; + use pulldown_cmark::CowStr::*; + use pulldown_cmark::Event::*; + use pulldown_cmark::Tag::*; + + let markdown_options = pulldown_cmark::Options::all(); + let mut docs_parser = vec![]; + let (_, _) = pulldown_cmark::Parser::new_ext(&markdown, markdown_options).fold( + (0, 0), + |(start_quote_count, end_quote_count), event| match event { + // Replace this sequence (`>>>` syntax): + // Start(BlockQuote) + // Start(BlockQuote) + // Start(BlockQuote) + // Start(Paragraph) + // For `Start(CodeBlock(Fenced(Borrowed("roc"))))` + Start(BlockQuote) => { + docs_parser.push(event); + (start_quote_count + 1, 0) + } + Start(Paragraph) => { + if start_quote_count == 3 { + docs_parser.pop(); + docs_parser.pop(); + docs_parser.pop(); + docs_parser.push(Start(CodeBlock(Fenced(Borrowed("roc"))))); + } else { + docs_parser.push(event); + } + (0, 0) + } + // Replace this sequence (`>>>` syntax): + // End(Paragraph) + // End(BlockQuote) + // End(BlockQuote) + // End(BlockQuote) + // For `End(CodeBlock(Fenced(Borrowed("roc"))))` + End(Paragraph) => { + docs_parser.push(event); + (0, 1) + } + End(BlockQuote) => { + if end_quote_count == 3 { + docs_parser.pop(); + docs_parser.pop(); + docs_parser.pop(); + docs_parser.push(End(CodeBlock(Fenced(Borrowed("roc"))))); + (0, 0) + } else { + docs_parser.push(event); + (0, end_quote_count + 1) + } + } + _ => { + docs_parser.push(event); + (0, 0) + } + }, + ); + let mut docs_html = String::new(); + pulldown_cmark::html::push_html(&mut docs_html, docs_parser.into_iter()); + docs_html +} diff --git a/docs/src/main.rs b/docs/src/main.rs deleted file mode 100644 index 2e5a741a5b..0000000000 --- a/docs/src/main.rs +++ /dev/null @@ -1,298 +0,0 @@ -extern crate fs_extra; -extern crate handlebars; -extern crate serde; -#[macro_use] -extern crate serde_derive; -extern crate pulldown_cmark; -extern crate serde_json; -use roc_builtins::std::StdLib; -use roc_can::builtins::builtin_defs_map; -use roc_load::docs::Documentation; -use roc_load::docs::ModuleDocumentation; -use roc_load::file::LoadingProblem; - -use std::fs; -extern crate roc_load; -use bumpalo::Bump; -use roc_collections::all::MutMap; -use std::path::{Path, PathBuf}; - -#[derive(Serialize)] -pub struct Template { - package_name: String, - package_version: String, - module_name: String, - module_docs: String, - module_entries: Vec, - module_links: Vec, -} - -#[derive(Serialize, Clone, Debug, PartialEq)] -pub struct ModuleEntry { - name: String, - docs: String, -} - -#[derive(Serialize)] -pub struct TemplateLink { - name: String, - href: String, - classes: String, - entries: Vec, -} - -#[derive(Serialize)] -pub struct TemplateLinkEntry { - name: String, -} - -fn main() { - generate( - vec![ - PathBuf::from(r"../compiler/builtins/docs/Bool.roc"), - PathBuf::from(r"../compiler/builtins/docs/Dict.roc"), - // Not working - // PathBuf::from(r"../compiler/builtins/docs/List.roc"), - // Not working - // PathBuf::from(r"../compiler/builtins/docs/Num.roc"), - PathBuf::from(r"../compiler/builtins/docs/Set.roc"), - PathBuf::from(r"../compiler/builtins/docs/Str.roc"), - ], - roc_builtins::std::standard_stdlib(), - Path::new("../compiler/builtins/docs"), - Path::new("./build"), - ) -} - -pub fn generate(filenames: Vec, std_lib: StdLib, src_dir: &Path, build_dir: &Path) { - let files_docs = files_to_documentations(filenames, std_lib, src_dir); - - // TODO: get info from a file like "elm.json" - let package = roc_load::docs::Documentation { - name: "roc/builtins".to_string(), - version: "1.0.0".to_string(), - docs: "Package introduction or README.".to_string(), - modules: files_docs, - }; - - // Remove old build folder, if exists - let _ = fs::remove_dir_all(build_dir); - - let version_folder = build_dir - .join(package.name.clone()) - .join(package.version.clone()); - - // Make sure the output directories exists - fs::create_dir_all(&version_folder) - .expect("TODO gracefully handle creating directories failing"); - - // Register handlebars template - let mut handlebars = handlebars::Handlebars::new(); - handlebars - .register_template_file("page", "./src/templates/page.hbs") - .expect("TODO gracefully handle registering template failing"); - - // Write each package's module docs html file - for module in &package.modules { - let template = documentation_to_template_data(&package, module); - - let handlebars_data = handlebars::to_json(&template); - let filepath = version_folder.join(format!("{}.html", module.name)); - let mut output_file = - fs::File::create(filepath).expect("TODO gracefully handle creating file failing"); - handlebars - .render_to_write("page", &handlebars_data, &mut output_file) - .expect("TODO gracefully handle writing file failing"); - } - - // Copy /static folder content to /build - let copy_options = fs_extra::dir::CopyOptions { - overwrite: true, - skip_exist: false, - buffer_size: 64000, //64kb - copy_inside: false, - content_only: true, - depth: 0, - }; - fs_extra::dir::copy("./src/static/", &build_dir, ©_options) - .expect("TODO gracefully handle copying static content failing"); - println!("Docs generated at {}", build_dir.display()); -} - -fn files_to_documentations( - filenames: Vec, - std_lib: StdLib, - src_dir: &Path, -) -> Vec { - let arena = Bump::new(); - let mut files_docs = vec![]; - - for filename in filenames { - match roc_load::file::load_and_typecheck( - &arena, - filename, - &std_lib, - src_dir, - MutMap::default(), - 8, // TODO: Is it okay to hardcode ptr_bytes here? I think it should be fine since we'er only type checking (also, 8 => 32bit system) - builtin_defs_map, - ) { - Ok(mut loaded) => files_docs.extend(loaded.documentation.drain().map(|x| x.1)), - Err(LoadingProblem::ParsingFailedReport(report)) => { - println!("{}", report); - panic!(); - } - Err(e) => panic!("{:?}", e), - } - } - files_docs -} - -fn documentation_to_template_data(doc: &Documentation, module: &ModuleDocumentation) -> Template { - Template { - package_name: doc.name.clone(), - package_version: doc.version.clone(), - module_name: module.name.clone(), - module_docs: markdown_to_html(module.docs.clone()), - module_entries: module - .entries - .clone() - .into_iter() - .map(|entry| ModuleEntry { - name: entry.name.clone(), - docs: match entry.docs { - Some(docs) => markdown_to_html(docs), - None => String::new(), - }, - }) - .collect(), - module_links: doc - .modules - .clone() - .into_iter() - .map(|module_link| TemplateLink { - name: module_link.name.clone(), - href: format!("./{}.html", module_link.name), - classes: "".to_string(), - entries: module_link - .entries - .into_iter() - .map(|entry| TemplateLinkEntry { name: entry.name }) - .collect(), - }) - .collect(), - } -} - -fn markdown_to_html(markdown: String) -> String { - use pulldown_cmark::CodeBlockKind::*; - use pulldown_cmark::CowStr::*; - use pulldown_cmark::Event::*; - use pulldown_cmark::Tag::*; - - let markdown_options = pulldown_cmark::Options::all(); - let mut docs_parser = vec![]; - let (_, _) = pulldown_cmark::Parser::new_ext(&markdown, markdown_options).fold( - (0, 0), - |(start_quote_count, end_quote_count), event| match event { - // Replace this sequence (`>>>` syntax): - // Start(BlockQuote) - // Start(BlockQuote) - // Start(BlockQuote) - // Start(Paragraph) - // For `Start(CodeBlock(Fenced(Borrowed("roc"))))` - Start(BlockQuote) => { - docs_parser.push(event); - (start_quote_count + 1, 0) - } - Start(Paragraph) => { - if start_quote_count == 3 { - docs_parser.pop(); - docs_parser.pop(); - docs_parser.pop(); - docs_parser.push(Start(CodeBlock(Fenced(Borrowed("roc"))))); - } else { - docs_parser.push(event); - } - (0, 0) - } - // Replace this sequence (`>>>` syntax): - // End(Paragraph) - // End(BlockQuote) - // End(BlockQuote) - // End(BlockQuote) - // For `End(CodeBlock(Fenced(Borrowed("roc"))))` - End(Paragraph) => { - docs_parser.push(event); - (0, 1) - } - End(BlockQuote) => { - if end_quote_count == 3 { - docs_parser.pop(); - docs_parser.pop(); - docs_parser.pop(); - docs_parser.push(End(CodeBlock(Fenced(Borrowed("roc"))))); - (0, 0) - } else { - docs_parser.push(event); - (0, end_quote_count + 1) - } - } - _ => { - docs_parser.push(event); - (0, 0) - } - }, - ); - let mut docs_html = String::new(); - pulldown_cmark::html::push_html(&mut docs_html, docs_parser.into_iter()); - docs_html -} - -#[cfg(test)] -mod test_docs { - use super::*; - - #[test] - fn internal() { - let files_docs = files_to_documentations( - vec![PathBuf::from(r"tests/fixtures/Interface.roc")], - roc_builtins::std::standard_stdlib(), - Path::new("tests/fixtures"), - ); - - let package = roc_load::docs::Documentation { - name: "roc/builtins".to_string(), - version: "1.0.0".to_string(), - docs: "Package introduction or README.".to_string(), - modules: files_docs, - }; - - let expected_entries = vec![ - ModuleEntry { - name: "singleline".to_string(), - docs: "

Single line documentation.

\n".to_string(), - }, - ModuleEntry { - name: "multiline".to_string(), - docs: "

Multiline documentation.\nWithout any complex syntax yet!

\n".to_string(), - }, ModuleEntry { - name: "multiparagraph".to_string(), - docs: "

Multiparagraph documentation.

\n

Without any complex syntax yet!

\n".to_string(), - }, ModuleEntry { - name: "codeblock".to_string(), - docs: "

Turns >>> into code block for now.

\n
codeblock
\n".to_string(), - }, - ]; - - for module in &package.modules { - let template = documentation_to_template_data(&package, module); - assert_eq!(template.module_name, "Test"); - template - .module_entries - .iter() - .zip(expected_entries.iter()) - .for_each(|(x, y)| assert_eq!(x, y)); - } - } -} From 547ec2756d1a81547e51aa62dbc19d8e30d44206 Mon Sep 17 00:00:00 2001 From: Chadtech Date: Sun, 21 Mar 2021 22:46:16 -0400 Subject: [PATCH 15/84] Docs test file --- docs/tests/test_docs.rs | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 docs/tests/test_docs.rs diff --git a/docs/tests/test_docs.rs b/docs/tests/test_docs.rs new file mode 100644 index 0000000000..da99e07b08 --- /dev/null +++ b/docs/tests/test_docs.rs @@ -0,0 +1,49 @@ +use roc_docs::{documentation_to_template_data, files_to_documentations, ModuleEntry}; +use std::path::{Path, PathBuf}; + +#[cfg(test)] +mod test_docs { + use super::*; + + #[test] + fn internal() { + let files_docs = files_to_documentations( + vec![PathBuf::from(r"tests/fixtures/Interface.roc")], + roc_builtins::std::standard_stdlib(), + ); + + let package = roc_load::docs::Documentation { + name: "roc/builtins".to_string(), + version: "1.0.0".to_string(), + docs: "Package introduction or README.".to_string(), + modules: files_docs, + }; + + let expected_entries = vec![ + ModuleEntry { + name: "singleline".to_string(), + docs: "

Single line documentation.

\n".to_string(), + }, + ModuleEntry { + name: "multiline".to_string(), + docs: "

Multiline documentation.\nWithout any complex syntax yet!

\n".to_string(), + }, ModuleEntry { + name: "multiparagraph".to_string(), + docs: "

Multiparagraph documentation.

\n

Without any complex syntax yet!

\n".to_string(), + }, ModuleEntry { + name: "codeblock".to_string(), + docs: "

Turns >>> into code block for now.

\n
codeblock
\n".to_string(), + }, + ]; + + for module in &package.modules { + let template = documentation_to_template_data(&package, module); + assert_eq!(template.module_name, "Test"); + template + .module_entries + .iter() + .zip(expected_entries.iter()) + .for_each(|(x, y)| assert_eq!(x, y)); + } + } +} From e38823b52a8b9ef58435b496131ea995261b26e2 Mon Sep 17 00:00:00 2001 From: Chadtech Date: Mon, 22 Mar 2021 00:54:07 -0400 Subject: [PATCH 16/84] Delete commented out docs code --- cli/src/lib.rs | 17 +-------- docs/src/lib.rs | 95 +++++++++++++++---------------------------------- 2 files changed, 29 insertions(+), 83 deletions(-) diff --git a/cli/src/lib.rs b/cli/src/lib.rs index bd5032c50f..b1ecd343e6 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -91,22 +91,7 @@ pub fn build_app<'a>() -> App<'a> { } pub fn docs(files: Vec) { - roc_docs::generate( - files, - // vec![ - // PathBuf::from(r"./compiler/builtins/docs/Bool.roc"), - // // PathBuf::from(r"../compiler/builtins/docs/Dict.roc"), - // // Not working - // // PathBuf::from(r"../compiler/builtins/docs/List.roc"), - // // Not working - // // PathBuf::from(r"../compiler/builtins/docs/Num.roc"), - // // PathBuf::from(r"../compiler/builtins/docs/Set.roc"), - // // PathBuf::from(r"../compiler/builtins/docs/Str.roc"), - // ], - roc_builtins::std::standard_stdlib(), - Path::new("./"), - // Path::new("./build"), - ) + roc_docs::generate(files, roc_builtins::std::standard_stdlib(), Path::new("./")) } pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io::Result<()> { diff --git a/docs/src/lib.rs b/docs/src/lib.rs index d1887614ab..d18ecaa759 100644 --- a/docs/src/lib.rs +++ b/docs/src/lib.rs @@ -45,76 +45,37 @@ pub struct TemplateLinkEntry { name: String, } -// fn main() { -// generate( -// vec![ -// PathBuf::from(r"../compiler/builtins/docs/Bool.roc"), -// // PathBuf::from(r"../compiler/builtins/docs/Dict.roc"), -// // Not working -// // PathBuf::from(r"../compiler/builtins/docs/List.roc"), -// // Not working -// // PathBuf::from(r"../compiler/builtins/docs/Num.roc"), -// // PathBuf::from(r"../compiler/builtins/docs/Set.roc"), -// // PathBuf::from(r"../compiler/builtins/docs/Str.roc"), -// ], -// roc_builtins::std::standard_stdlib(), -// Path::new("../compiler/builtins/docs"), -// // Path::new("./build"), -// ) -// } - pub fn generate(filenames: Vec, std_lib: StdLib, build_dir: &Path) { - // let files_docs = files_to_documentations(filenames, std_lib); + let files_docs = files_to_documentations(filenames, std_lib); // - // // TODO: get info from a file like "elm.json" - // let package = roc_load::docs::Documentation { - // name: "roc/builtins".to_string(), - // version: "1.0.0".to_string(), - // docs: "Package introduction or README.".to_string(), - // modules: files_docs, - // }; - // - // let version_folder = build_dir - // .join(package.name.clone()) - // .join(package.version.clone()); - // - // println!("{}", version_folder.display()); + // TODO: get info from a file like "elm.json" + let package = roc_load::docs::Documentation { + name: "roc/builtins".to_string(), + version: "1.0.0".to_string(), + docs: "Package introduction or README.".to_string(), + modules: files_docs, + }; - // // Make sure the output directories exists - // fs::create_dir_all(&version_folder) - // .expect("TODO gracefully handle creating directories failing"); - // - // // Register handlebars template - // let mut handlebars = handlebars::Handlebars::new(); - // handlebars - // .register_template_file("page", "./docs/src/templates/page.hbs") - // .expect("TODO gracefully handle registering template failing"); - // - // // Write each package's module docs html file - // for module in &package.modules { - // let template = documentation_to_template_data(&package, module); - // - // let handlebars_data = handlebars::to_json(&template); - // let filepath = version_folder.join(format!("{}.html", module.name)); - // let mut output_file = - // fs::File::create(filepath).expect("TODO gracefully handle creating file failing"); - // handlebars - // .render_to_write("page", &handlebars_data, &mut output_file) - // .expect("TODO gracefully handle writing file failing"); - // } - // - // // Copy /static folder content to /build - // let copy_options = fs_extra::dir::CopyOptions { - // overwrite: true, - // skip_exist: false, - // buffer_size: 64000, //64kb - // copy_inside: false, - // content_only: true, - // depth: 0, - // }; - // fs_extra::dir::copy("./docs/src/static/", &build_dir, ©_options) - // .expect("TODO gracefully handle copying static content failing"); - // println!("Docs generated at {}", build_dir.display()); + // Register handlebars template + let mut handlebars = handlebars::Handlebars::new(); + handlebars + .register_template_file("page", "./docs/src/templates/page.hbs") + .expect("TODO gracefully handle registering template failing"); + + // Write each package's module docs html file + for module in &package.modules { + let template = documentation_to_template_data(&package, module); + + let handlebars_data = handlebars::to_json(&template); + let filepath = build_dir.join(format!("{}.html", module.name)); + let mut output_file = + fs::File::create(filepath).expect("TODO gracefully handle creating file failing"); + handlebars + .render_to_write("page", &handlebars_data, &mut output_file) + .expect("TODO gracefully handle writing file failing"); + } + + println!("Docs generated at {}", build_dir.display()); } pub fn files_to_documentations( From 35c7bb7a5ad96cabfd387db46443160a7edbabf5 Mon Sep 17 00:00:00 2001 From: Chadtech Date: Mon, 22 Mar 2021 00:54:42 -0400 Subject: [PATCH 17/84] Correct errors in List.roc --- compiler/builtins/docs/Dict.roc | 2 +- compiler/builtins/docs/List.roc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/builtins/docs/Dict.roc b/compiler/builtins/docs/Dict.roc index c3a78b00df..94d37dc0b1 100644 --- a/compiler/builtins/docs/Dict.roc +++ b/compiler/builtins/docs/Dict.roc @@ -17,6 +17,6 @@ isEmpty : Dict * * -> Bool ## See for example #Result.map, #List.map, and #Set.map. map : Dict beforeKey beforeValue, - (\{ key: beforeKey, value: beforeValue } -> + ({ key: beforeKey, value: beforeValue } -> { key: afterKey, value: afterValue } ) -> Dict afterKey afterValue diff --git a/compiler/builtins/docs/List.roc b/compiler/builtins/docs/List.roc index dda129e03d..1522afd0af 100644 --- a/compiler/builtins/docs/List.roc +++ b/compiler/builtins/docs/List.roc @@ -298,7 +298,7 @@ oks : List (Result elem *) -> List elem ## ## > For a generalized version that returns whatever you like, instead of a `Pair`, ## > see `zipMap`. -zip : List a, List b, -> List [ Pair a b ]* +zip : List a, List b -> List [ Pair a b ]* ## Like `zip` but you can specify what to do with each element. ## @@ -307,7 +307,7 @@ zip : List a, List b, -> List [ Pair a b ]* ## >>> List.zipMap [ 1, 2, 3 ] [ 0, 5, 4 ] [ 2, 1 ] \num1 num2 num3 -> num1 + num2 - num3 ## ## Accepts up to 8 lists. -zipMap : List a, List b, (a, b) -> List c +zipMap : List a, List b, (a, b -> c) -> List c ## Filter From e6d900b97873a6f30698c83dffc2cd1d5f86d851 Mon Sep 17 00:00:00 2001 From: Chadtech Date: Mon, 22 Mar 2021 00:55:05 -0400 Subject: [PATCH 18/84] Vertical List.roc exports --- compiler/builtins/docs/List.roc | 51 ++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/compiler/builtins/docs/List.roc b/compiler/builtins/docs/List.roc index 1522afd0af..fbc7a192d7 100644 --- a/compiler/builtins/docs/List.roc +++ b/compiler/builtins/docs/List.roc @@ -1,5 +1,54 @@ interface List2 - exposes [ List, single, empty, repeat, range, reverse, sort, map, mapWithIndex, mapOrCancel, mapOks, update, updater, allOks, append, prepend, concat, join, joinMap, oks, zip, zipMap, keepIf, dropIf, first, last, get, max, min, put, drop, append, prepend, dropLast, dropFirst, takeFirst, takeLast, split, sublist, walk, walkBackwards, walkUntil, walkBackwardsUntil, len, isEmpty, contains, all, any ] + exposes + [ List + , single + , empty + , repeat + , range + , reverse + , sort + , map + , mapWithIndex + , mapOrCancel + , mapOks + , update + , updater + , allOks + , append + , prepend + , concat + , join + , joinMap + , oks + , zip + , zipMap + , keepIf + , dropIf + , first + , last + , get + , max + , min + , put + , drop + , append + , prepend + , dropLast + , dropFirst + , takeFirst + , takeLast + , split + , sublist + , walk + , walkBackwards + , walkUntil + , walkBackwardsUntil + , len + , isEmpty + , contains + , all + , any + ] imports [] ## Types From 9f5ed5816bb1ffa95c5442a7177a9c5dfa43089f Mon Sep 17 00:00:00 2001 From: Chadtech Date: Mon, 22 Mar 2021 01:31:23 -0400 Subject: [PATCH 19/84] Cargo fmt --- cli/src/lib.rs | 1 - cli/src/main.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/src/lib.rs b/cli/src/lib.rs index b1ecd343e6..c99068408f 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -13,7 +13,6 @@ use std::process; use std::process::Command; use target_lexicon::Triple; - pub mod build; pub mod repl; diff --git a/cli/src/main.rs b/cli/src/main.rs index d806f3a57b..fca8e3924b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,4 +1,4 @@ -use roc_cli::{build, docs, build_app, repl, DIRECTORY_OR_FILES}; +use roc_cli::{build, build_app, docs, repl, DIRECTORY_OR_FILES}; use std::io; use std::path::{Path, PathBuf}; use target_lexicon::Triple; From fdebfa6b3feda0fb736791f7a01275cabdba19e1 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 22 Mar 2021 11:58:13 +0100 Subject: [PATCH 20/84] cloning --- compiler/mono/src/decision_tree.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index 729b27422e..5dec912230 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -172,13 +172,13 @@ fn to_decision_tree(raw_branches: Vec) -> DecisionTree { decision_tree.clone() } (_, None) => DecisionTree::Decision { - path, + path: path.clone(), edges: decision_edges, default: None, }, (None, Some(_)) => to_decision_tree(fallback), _ => DecisionTree::Decision { - path, + path: path.clone(), edges: decision_edges, default: Some(Box::new(to_decision_tree(fallback))), }, @@ -879,7 +879,6 @@ fn small_defaults(branches: &[Branch], path: &Path) -> usize { } fn small_branching_factor(branches: &[Branch], path: &Path) -> usize { - // TODO remove clone let (edges, fallback) = gather_edges(branches.to_vec(), path); edges.len() + (if fallback.is_empty() { 0 } else { 1 }) @@ -1033,7 +1032,6 @@ fn path_to_expr_help<'a>( debug_assert_eq!(field_layouts.len(), 1); - let inner_layout = field_layouts[*index as usize].clone(); let inner_expr = Expr::AccessAtIndex { index: *index, field_layouts: env.arena.alloc(field_layouts), @@ -1042,7 +1040,8 @@ fn path_to_expr_help<'a>( }; symbol = env.unique_symbol(); - stores.push((symbol, inner_layout.clone(), inner_expr)); + let inner_layout = layout.clone(); + stores.push((symbol, inner_layout, inner_expr)); break; } From addf130be5965b14de76a6bbfde2271b525bcd90 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 22 Mar 2021 13:09:56 +0100 Subject: [PATCH 21/84] optimize Path --- compiler/mono/src/decision_tree.rs | 159 +++++++++++++++-------------- 1 file changed, 83 insertions(+), 76 deletions(-) diff --git a/compiler/mono/src/decision_tree.rs b/compiler/mono/src/decision_tree.rs index 5dec912230..e4fb09c041 100644 --- a/compiler/mono/src/decision_tree.rs +++ b/compiler/mono/src/decision_tree.rs @@ -22,7 +22,7 @@ pub fn compile<'a>(raw_branches: Vec<(Guard<'a>, Pattern<'a>, u64)>) -> Decision .into_iter() .map(|(guard, pattern, index)| Branch { goal: index, - patterns: vec![(Path::Empty, guard, pattern)], + patterns: vec![(Vec::new(), guard, pattern)], }) .collect(); @@ -52,7 +52,7 @@ impl<'a> Guard<'a> { pub enum DecisionTree<'a> { Match(Label), Decision { - path: Path, + path: Vec, edges: Vec<(Test<'a>, DecisionTree<'a>)>, default: Option>>, }, @@ -148,7 +148,7 @@ pub enum Path { #[derive(Clone, Debug, PartialEq)] struct Branch<'a> { goal: Label, - patterns: Vec<(Path, Guard<'a>, Pattern<'a>)>, + patterns: Vec<(Vec, Guard<'a>, Pattern<'a>)>, } fn to_decision_tree(raw_branches: Vec) -> DecisionTree { @@ -218,8 +218,8 @@ fn flatten_patterns(branch: Branch) -> Branch { } fn flatten<'a>( - path_pattern: (Path, Guard<'a>, Pattern<'a>), - path_patterns: &mut Vec<(Path, Guard<'a>, Pattern<'a>)>, + path_pattern: (Vec, Guard<'a>, Pattern<'a>), + path_patterns: &mut Vec<(Vec, Guard<'a>, Pattern<'a>)>, ) { match path_pattern.2 { Pattern::AppliedTag { @@ -237,12 +237,13 @@ fn flatten<'a>( { // TODO ^ do we need to check that guard.is_none() here? - let path = path_pattern.0; + let mut path = path_pattern.0; // Theory: unbox doesn't have any value for us, because one-element tag unions // don't store the tag anyway. if arguments.len() == 1 { + // NOTE here elm will unbox, but we don't use that path_patterns.push(( - Path::Unbox(Box::new(path)), + path, path_pattern.1.clone(), Pattern::AppliedTag { union, @@ -254,13 +255,15 @@ fn flatten<'a>( )); } else { for (index, (arg_pattern, _)) in arguments.iter().enumerate() { + let mut new_path = path.clone(); + new_path.push(PathInstruction { + index: index as u64, + tag_id, + }); + flatten( ( - Path::Index { - index: index as u64, - tag_id, - path: Box::new(path.clone()), - }, + new_path, // same guard here? path_pattern.1.clone(), arg_pattern.clone(), @@ -300,7 +303,7 @@ fn check_for_match(branches: &Vec) -> Option