From 1f467ec62be8b0ad6c49edaea019fa3d2bac6ac9 Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 21 Jun 2021 00:19:00 -0400 Subject: [PATCH 01/30] test: constrain update --- editor/tests/solve_expr2.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/editor/tests/solve_expr2.rs b/editor/tests/solve_expr2.rs index 374afd6590..465bb6511b 100644 --- a/editor/tests/solve_expr2.rs +++ b/editor/tests/solve_expr2.rs @@ -300,3 +300,17 @@ fn constrain_when() { "[ Blue, Purple ]*", ) } + +#[test] +fn constrain_update() { + infer_eq( + indoc!( + r#" + thing = { name: "roc" } + + { thing & name: "bird" } + "# + ), + "{ name : Str }*", + ) +} From 8b957ea712f21ea4f9c1a5f1b121cbcfd3e32d94 Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 21 Jun 2021 00:19:27 -0400 Subject: [PATCH 02/30] feat: more consistent field name --- editor/src/lang/ast.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index b1b75b0554..717428038c 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -135,9 +135,9 @@ pub enum Expr2 { body_id: NodeId, // 4B }, LetFunction { - def: NodeId, // 4B - body_var: Variable, // 8B - body_id: NodeId, // 4B + def_id: NodeId, // 4B + body_var: Variable, // 8B + body_id: NodeId, // 4B }, LetValue { def_id: NodeId, // 4B From 876687e0787ffd7d14cc6668de683751e177657a Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 21 Jun 2021 00:21:42 -0400 Subject: [PATCH 03/30] feat(Expr2): support Defs and add desugaring --- editor/src/lang/expr.rs | 179 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 4 deletions(-) diff --git a/editor/src/lang/expr.rs b/editor/src/lang/expr.rs index 2a9626bd5b..a383b6b00d 100644 --- a/editor/src/lang/expr.rs +++ b/editor/src/lang/expr.rs @@ -1,11 +1,16 @@ #![allow(clippy::all)] #![allow(dead_code)] #![allow(unused_imports)] +use std::collections::HashMap; + use crate::lang::ast::expr2_to_string; use crate::lang::ast::RecordField; use crate::lang::ast::{ClosureExtra, Expr2, ExprId, FloatVal, IntStyle, IntVal, WhenBranch}; -use crate::lang::def::References; -use crate::lang::pattern::to_pattern2; +use crate::lang::def::canonicalize_defs; +use crate::lang::def::sort_can_defs; +use crate::lang::def::Def; +use crate::lang::def::{CanDefs, PendingDef, References}; +use crate::lang::pattern::{to_pattern2, Pattern2}; use crate::lang::pool::{NodeId, Pool, PoolStr, PoolVec, ShallowClone}; use crate::lang::scope::Scope; use crate::lang::types::{Alias, Type2, TypeId}; @@ -13,7 +18,10 @@ use bumpalo::Bump; use inlinable_string::InlinableString; use roc_can::expr::Recursive; use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int}; +use roc_can::operator::desugar_expr; +use roc_collections::all::default_hasher; use roc_collections::all::{MutMap, MutSet}; +use roc_module::ident::Lowercase; use roc_module::ident::ModuleName; use roc_module::low_level::LowLevel; use roc_module::operator::CalledVia; @@ -21,14 +29,69 @@ use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol}; use roc_parse::ast; use roc_parse::ast::StrLiteral; use roc_parse::parser::{loc, Parser, State, SyntaxError}; +use roc_parse::pattern::PatternType; use roc_problem::can::{Problem, RuntimeError}; use roc_region::all::{Located, Region}; use roc_types::subs::{VarStore, Variable}; +use super::def::Declaration; +use super::pattern::PatternId; +use super::types::Annotation2; + +#[derive(Clone, Debug, PartialEq, Default)] +pub struct IntroducedVariables { + // NOTE on rigids + // + // Rigids must be unique within a type annoation. + // E.g. in `identity : a -> a`, there should only be one + // variable (a rigid one, with name "a"). + // Hence `rigids : ImMap` + // + // But then between annotations, the same name can occur multiple times, + // but a variable can only have one name. Therefore + // `ftv : SendMap`. + pub wildcards: Vec, + pub var_by_name: MutMap, + pub name_by_var: MutMap, + pub host_exposed_aliases: MutMap, +} + +impl IntroducedVariables { + pub fn insert_named(&mut self, name: Lowercase, var: Variable) { + self.var_by_name.insert(name.clone(), var); + self.name_by_var.insert(var, name); + } + + pub fn insert_wildcard(&mut self, var: Variable) { + self.wildcards.push(var); + } + + pub fn insert_host_exposed_alias(&mut self, symbol: Symbol, var: Variable) { + self.host_exposed_aliases.insert(symbol, var); + } + + pub fn union(&mut self, other: &Self) { + self.wildcards.extend(other.wildcards.iter().cloned()); + self.var_by_name.extend(other.var_by_name.clone()); + self.name_by_var.extend(other.name_by_var.clone()); + self.host_exposed_aliases + .extend(other.host_exposed_aliases.clone()); + } + + pub fn var_by_name(&self, name: &Lowercase) -> Option<&Variable> { + self.var_by_name.get(name) + } + + pub fn name_by_var(&self, var: Variable) -> Option<&Lowercase> { + self.name_by_var.get(&var) + } +} + #[derive(Clone, Default, Debug, PartialEq)] pub struct Output { pub references: References, pub tail_call: Option, + pub introduced_variables: IntroducedVariables, pub aliases: MutMap>, pub non_closures: MutSet, } @@ -236,7 +299,16 @@ pub fn str_to_expr2<'a>( region: Region, ) -> Result<(Expr2, self::Output), SyntaxError<'a>> { match roc_parse::test_helpers::parse_loc_with(arena, input.trim()) { - Ok(loc_expr) => Ok(to_expr2(env, scope, arena.alloc(loc_expr.value), region)), + Ok(loc_expr) => { + let desugared_loc_expr = desugar_expr(arena, arena.alloc(loc_expr)); + + Ok(to_expr2( + env, + scope, + arena.alloc(desugared_loc_expr.value), + region, + )) + } Err(fail) => Err(fail), } } @@ -780,7 +852,50 @@ pub fn to_expr2<'a>( } Defs(loc_defs, loc_ret) => { - todo!("{:?} {:?}", loc_defs, loc_ret) + let (unsorted, mut scope, defs_output, symbols_introduced) = canonicalize_defs( + env, + Output::default(), + &scope, + loc_defs, + PatternType::DefExpr, + ); + + // The def as a whole is a tail call iff its return expression is a tail call. + // Use its output as a starting point because its tail_call already has the right answer! + let (ret_expr, mut output) = to_expr2(env, &mut scope, &loc_ret.value, loc_ret.region); + + output + .introduced_variables + .union(&defs_output.introduced_variables); + + output.references.union_mut(defs_output.references); + + // Now that we've collected all the references, check to see if any of the new idents + // we defined went unused by the return expression. If any were unused, report it. + for (symbol, region) in symbols_introduced { + if !output.references.has_lookup(symbol) { + env.problem(Problem::UnusedDef(symbol, region)); + } + } + + let (can_defs, output) = sort_can_defs(env, unsorted, output); + + match can_defs { + Ok(decls) => { + let mut expr = ret_expr; + + for declaration in decls.into_iter().rev() { + expr = decl_to_let(env.pool, env.var_store, declaration, expr); + } + + (expr, output) + } + Err(_err) => { + // TODO: fix this to be something from Expr2 + // (RuntimeError(err), output) + todo!() + } + } } PrecedenceConflict { .. } => { @@ -1294,3 +1409,59 @@ fn canonicalize_lookup( (can_expr, output) } + +fn decl_to_let(pool: &mut Pool, var_store: &mut VarStore, decl: Declaration, ret: Expr2) -> Expr2 { + match decl { + Declaration::Declare(def) => match def { + Def::AnnotationOnly { .. } => todo!(), + Def::Value(value_def) => { + let def_id = pool.add(value_def); + let body_id = pool.add(ret); + + Expr2::LetValue { + def_id, + body_id, + body_var: var_store.fresh(), + } + } + Def::Function(function_def) => { + let def_id = pool.add(function_def); + let body_id = pool.add(ret); + + Expr2::LetFunction { + def_id, + body_id, + body_var: var_store.fresh(), + } + } + }, + Declaration::DeclareRec(defs) => { + let mut function_defs = vec![]; + + for def in defs { + match def { + Def::AnnotationOnly { .. } => todo!(), + Def::Function(function_def) => function_defs.push(function_def), + Def::Value(_) => unreachable!(), + } + } + + let body_id = pool.add(ret); + + Expr2::LetRec { + defs: PoolVec::new(function_defs.into_iter(), pool), + body_var: var_store.fresh(), + body_id, + } + } + Declaration::InvalidCycle(_entries, _) => { + // TODO: replace with something from Expr2 + // Expr::RuntimeError(RuntimeError::CircularDef(entries)) + todo!() + } + Declaration::Builtin(_) => { + // Builtins should only be added to top-level decls, not to let-exprs! + unreachable!() + } + } +} From e69b798857fd853048b77fcfd18c5df780f70ecf Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 21 Jun 2021 00:22:32 -0400 Subject: [PATCH 04/30] chore: pending def should be pub --- editor/src/lang/def.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/src/lang/def.rs b/editor/src/lang/def.rs index c56115eb03..8d60444847 100644 --- a/editor/src/lang/def.rs +++ b/editor/src/lang/def.rs @@ -79,7 +79,7 @@ impl ShallowClone for Def { /// 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)] -enum PendingDef<'a> { +pub enum PendingDef<'a> { /// A standalone annotation with no body AnnotationOnly( &'a Located>, From 477dee0ae6f81eab24705bde398a6845843905b5 Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 21 Jun 2021 00:23:05 -0400 Subject: [PATCH 05/30] feat(Expr2): constrain LetValue and Update --- editor/src/lang/constrain.rs | 157 ++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index 106eea2f1f..cdad0e3d3f 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -9,8 +9,11 @@ use crate::lang::{ }; use roc_can::expected::{Expected, PExpected}; -use roc_collections::all::{BumpMap, BumpMapDefault, Index}; -use roc_module::{ident::TagName, symbol::Symbol}; +use roc_collections::all::{BumpMap, BumpMapDefault, Index, SendMap}; +use roc_module::{ + ident::{Lowercase, TagName}, + symbol::Symbol, +}; use roc_region::all::Region; use roc_types::{ subs::Variable, @@ -754,6 +757,140 @@ pub fn constrain_expr<'a>( // exhautiveness checking happens when converting to mono::Expr exists(arena, flex_vars, And(constraints)) } + Expr2::LetValue { + def_id, + body_id, + body_var, + } => { + let value_def = env.pool.get(*def_id); + let body = env.pool.get(*body_id); + + let mut body_con = constrain_expr(arena, env, body, expected.shallow_clone(), region); + + if let Some((expr_type_id, _)) = value_def.expr_type { + let mut flex_vars = BumpVec::with_capacity_in(1, arena); + flex_vars.push(*body_var); + + // Constrain Def + let mut and_constraints = BumpVec::with_capacity_in(1, arena); + + let pattern = env.pool.get(value_def.pattern); + + let expr_type = env.pool.get(expr_type_id); + + let pattern_expected = PExpected::NoExpectation(expr_type.shallow_clone()); + + let mut state = PatternState2 { + headers: BumpMap::new_in(arena), + vars: BumpVec::with_capacity_in(1, arena), + constraints: BumpVec::with_capacity_in(1, arena), + }; + + constrain_pattern(arena, env, pattern, region, pattern_expected, &mut state); + + state.vars.push(value_def.expr_var); + + let constrained_def = Let(arena.alloc(LetConstraint { + rigid_vars: BumpVec::new_in(arena), + flex_vars: state.vars, + def_types: state.headers, + defs_constraint: And(state.constraints), + ret_constraint: body_con, + })); + + and_constraints.push(constrained_def); + and_constraints.push(Eq( + Type2::Variable(*body_var), + expected, + Category::Storage(std::file!(), std::line!()), + // TODO: needs to be ret region + region, + )); + + body_con = exists(arena, flex_vars, And(and_constraints)); + } + + body_con + } + Expr2::Update { + symbol, + updates, + ext_var, + record_var, + } => { + let field_types = PoolVec::with_capacity(updates.len() as u32, env.pool); + let mut flex_vars = BumpVec::with_capacity_in(updates.len() + 2, arena); + let mut cons = BumpVec::with_capacity_in(updates.len() + 1, arena); + let mut record_key_updates = SendMap::default(); + + for (record_field_id, field_type_node_id) in + updates.iter_node_ids().zip(field_types.iter_node_ids()) + { + let record_field = env.pool.get(record_field_id); + + match record_field { + RecordField::LabeledValue(pool_str, var, node_id) => { + let expr = env.pool.get(*node_id); + + let (field_type, field_con) = constrain_field_update( + arena, + env, + *var, + pool_str.as_str(env.pool).into(), + expr, + ); + + let field_type_id = env.pool.add(field_type); + + env.pool[field_type_node_id] = + (*pool_str, types::RecordField::Required(field_type_id)); + + record_key_updates.insert(pool_str.as_str(env.pool).into(), Region::zero()); + + flex_vars.push(*var); + cons.push(field_con); + } + e => todo!("{:?}", e), + } + } + + let fields_type = Type2::Record(field_types, env.pool.add(Type2::Variable(*ext_var))); + let record_type = Type2::Variable(*record_var); + + // NOTE from elm compiler: fields_type is separate so that Error propagates better + let fields_con = Eq( + record_type.shallow_clone(), + Expected::NoExpectation(fields_type), + Category::Record, + region, + ); + let record_con = Eq( + record_type.shallow_clone(), + expected, + Category::Record, + region, + ); + + flex_vars.push(*record_var); + flex_vars.push(*ext_var); + + let con = Lookup( + *symbol, + Expected::ForReason( + Reason::RecordUpdateKeys(*symbol, record_key_updates), + record_type, + region, + ), + region, + ); + + // ensure constraints are solved in this order, gives better errors + cons.insert(0, fields_con); + cons.insert(1, con); + cons.insert(2, record_con); + + exists(arena, flex_vars, And(cons)) + } _ => todo!("implement constraints for {:?}", expr), } } @@ -785,6 +922,22 @@ fn constrain_field<'a>( (field_type, constraint) } +#[inline(always)] +fn constrain_field_update<'a>( + arena: &'a Bump, + env: &mut Env, + field_var: Variable, + field: Lowercase, + expr: &Expr2, +) -> (Type2, Constraint<'a>) { + let field_type = Type2::Variable(field_var); + let reason = Reason::RecordUpdateValue(field); + let field_expected = Expected::ForReason(reason, field_type.shallow_clone(), Region::zero()); + let con = constrain_expr(arena, env, expr, field_expected, Region::zero()); + + (field_type, con) +} + fn constrain_empty_record<'a>(expected: Expected, region: Region) -> Constraint<'a> { Constraint::Eq(Type2::EmptyRec, expected, Category::Record, region) } From c4f9812ad8dd92fd883fb83396e9c92815a0cc7d Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 21 Jun 2021 17:26:55 -0400 Subject: [PATCH 06/30] test: split into two --- editor/tests/solve_expr2.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/editor/tests/solve_expr2.rs b/editor/tests/solve_expr2.rs index 465bb6511b..f2bcf0bdd9 100644 --- a/editor/tests/solve_expr2.rs +++ b/editor/tests/solve_expr2.rs @@ -301,16 +301,30 @@ fn constrain_when() { ) } +#[test] +fn constrain_let_value() { + infer_eq( + indoc!( + r#" + person = { name: "roc" } + + person + "# + ), + "{ name : Str }", + ) +} + #[test] fn constrain_update() { infer_eq( indoc!( r#" - thing = { name: "roc" } + person = { name: "roc" } - { thing & name: "bird" } + { person & name: "bird" } "# ), - "{ name : Str }*", + "{ name : Str }", ) } From 11a1111e3331b11123850a4547a467f16ecf67c5 Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 28 Jun 2021 00:12:37 -0400 Subject: [PATCH 07/30] feat(ValueDef): add expr and some hacks to get this to compile --- editor/src/lang/ast.rs | 10 ++++++---- editor/src/lang/def.rs | 5 ++++- editor/src/lang/module.rs | 38 +++++++++++++++++++------------------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index 717428038c..d8137aa2c4 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -218,17 +218,19 @@ pub enum Expr2 { #[derive(Debug)] pub struct ValueDef { - pub pattern: PatternId, // 4B - pub expr_type: Option<(TypeId, Rigids)>, // ? - pub expr_var: Variable, // 4B + pub pattern: PatternId, // 4B + pub expr: ExprId, // 4B + pub expr_type: Option, // ? + pub expr_var: Variable, // 4B } impl ShallowClone for ValueDef { fn shallow_clone(&self) -> Self { Self { pattern: self.pattern, + expr: self.expr, expr_type: match &self.expr_type { - Some((id, rigids)) => Some((*id, rigids.shallow_clone())), + Some(rigids) => Some(rigids.shallow_clone()), None => None, }, expr_var: self.expr_var, diff --git a/editor/src/lang/def.rs b/editor/src/lang/def.rs index 8d60444847..3baaadf06b 100644 --- a/editor/src/lang/def.rs +++ b/editor/src/lang/def.rs @@ -626,7 +626,9 @@ fn canonicalize_pending_def<'a>( let value_def = ValueDef { pattern: loc_can_pattern, - expr_type: Some((annotation, rigids)), + expr: env.pool.add(loc_can_expr), + // annotation + expr_type: Some(rigids), expr_var: env.var_store.fresh(), }; @@ -747,6 +749,7 @@ fn canonicalize_pending_def<'a>( _ => { let value_def = ValueDef { pattern: loc_can_pattern, + expr: env.pool.add(loc_can_expr), expr_type: None, expr_var: env.var_store.fresh(), }; diff --git a/editor/src/lang/module.rs b/editor/src/lang/module.rs index a8b33481df..7cd3e039aa 100644 --- a/editor/src/lang/module.rs +++ b/editor/src/lang/module.rs @@ -175,7 +175,7 @@ pub fn canonicalize_module_defs<'a>( // this is now done later, in file.rs. match sort_can_defs(&mut env, defs, Output::default()) { - (Ok(mut declarations), output) => { + (Ok(declarations), output) => { use Declaration::*; for decl in declarations.iter() { @@ -238,29 +238,29 @@ pub fn canonicalize_module_defs<'a>( // exposed_symbols and added to exposed_vars_by_symbol. If any were // not, that means they were declared as exposed but there was // no actual declaration with that name! - for symbol in exposed_symbols { - env.problem(Problem::ExposedButNotDefined(symbol)); + // for symbol in exposed_symbols { + // env.problem(Problem::ExposedButNotDefined(symbol)); - // In case this exposed value is referenced by other modules, - // create a decl for it whose implementation is a runtime error. - let mut pattern_vars = SendMap::default(); - pattern_vars.insert(symbol, env.var_store.fresh()); + // // In case this exposed value is referenced by other modules, + // // create a decl for it whose implementation is a runtime error. + // let mut pattern_vars = SendMap::default(); + // pattern_vars.insert(symbol, env.var_store.fresh()); - let runtime_error = RuntimeError::ExposedButNotDefined(symbol); + // let runtime_error = RuntimeError::ExposedButNotDefined(symbol); - let value_def = { - let pattern = env.pool.add(Pattern2::Identifier(symbol)); - ValueDef { - pattern, - expr_type: None, - expr_var: env.var_store.fresh(), - } - }; + // let value_def = { + // let pattern = env.pool.add(Pattern2::Identifier(symbol)); + // ValueDef { + // pattern, + // expr_type: None, + // expr_var: env.var_store.fresh(), + // } + // }; - let def = Def::Value(value_def); + // let def = Def::Value(value_def); - declarations.push(Declaration::Declare(def)); - } + // declarations.push(Declaration::Declare(def)); + // } // Incorporate any remaining output.lookups entries into references. for symbol in output.references.lookups { From 8ae8f50a0ad89d4b15451d7f4556d408f710dbda Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 28 Jun 2021 00:13:19 -0400 Subject: [PATCH 08/30] fix: LetValue constraint gen --- editor/src/lang/constrain.rs | 78 +++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index cdad0e3d3f..968eaabb8c 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -765,52 +765,58 @@ pub fn constrain_expr<'a>( let value_def = env.pool.get(*def_id); let body = env.pool.get(*body_id); - let mut body_con = constrain_expr(arena, env, body, expected.shallow_clone(), region); + let body_con = constrain_expr(arena, env, body, expected.shallow_clone(), region); + let pattern = env.pool.get(value_def.pattern); - if let Some((expr_type_id, _)) = value_def.expr_type { - let mut flex_vars = BumpVec::with_capacity_in(1, arena); - flex_vars.push(*body_var); + let mut flex_vars = BumpVec::with_capacity_in(1, arena); + flex_vars.push(*body_var); - // Constrain Def - let mut and_constraints = BumpVec::with_capacity_in(1, arena); + let expr_type = Type2::Variable(value_def.expr_var); - let pattern = env.pool.get(value_def.pattern); + let pattern_expected = PExpected::NoExpectation(expr_type.shallow_clone()); + let mut state = PatternState2 { + headers: BumpMap::new_in(arena), + vars: BumpVec::with_capacity_in(1, arena), + constraints: BumpVec::with_capacity_in(1, arena), + }; - let expr_type = env.pool.get(expr_type_id); + constrain_pattern(arena, env, pattern, region, pattern_expected, &mut state); + state.vars.push(value_def.expr_var); - let pattern_expected = PExpected::NoExpectation(expr_type.shallow_clone()); + let def_expr = env.pool.get(value_def.expr); - let mut state = PatternState2 { - headers: BumpMap::new_in(arena), - vars: BumpVec::with_capacity_in(1, arena), - constraints: BumpVec::with_capacity_in(1, arena), - }; - - constrain_pattern(arena, env, pattern, region, pattern_expected, &mut state); - - state.vars.push(value_def.expr_var); - - let constrained_def = Let(arena.alloc(LetConstraint { - rigid_vars: BumpVec::new_in(arena), - flex_vars: state.vars, - def_types: state.headers, + let constrained_def = Let(arena.alloc(LetConstraint { + rigid_vars: BumpVec::new_in(arena), + flex_vars: state.vars, + def_types: state.headers, + defs_constraint: Let(arena.alloc(LetConstraint { + rigid_vars: BumpVec::new_in(arena), // always empty + flex_vars: BumpVec::new_in(arena), // empty, because our functions have no arguments + def_types: BumpMap::new_in(arena), // empty, because our functions have no arguments! defs_constraint: And(state.constraints), - ret_constraint: body_con, - })); + ret_constraint: constrain_expr( + arena, + env, + def_expr, + Expected::NoExpectation(expr_type), + region, + ), + })), + ret_constraint: body_con, + })); - and_constraints.push(constrained_def); - and_constraints.push(Eq( - Type2::Variable(*body_var), - expected, - Category::Storage(std::file!(), std::line!()), - // TODO: needs to be ret region - region, - )); + let mut and_constraints = BumpVec::with_capacity_in(1, arena); - body_con = exists(arena, flex_vars, And(and_constraints)); - } + and_constraints.push(constrained_def); + and_constraints.push(Eq( + Type2::Variable(*body_var), + expected, + Category::Storage(std::file!(), std::line!()), + // TODO: needs to be ret region + region, + )); - body_con + exists(arena, flex_vars, And(and_constraints)) } Expr2::Update { symbol, From a00a8c8e97aed389256ab940047e136c8594059a Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 28 Jun 2021 11:52:51 -0400 Subject: [PATCH 09/30] fix: imports --- editor/src/lang/expr.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/editor/src/lang/expr.rs b/editor/src/lang/expr.rs index a383b6b00d..b98e98f453 100644 --- a/editor/src/lang/expr.rs +++ b/editor/src/lang/expr.rs @@ -1,21 +1,22 @@ #![allow(clippy::all)] #![allow(dead_code)] #![allow(unused_imports)] +use bumpalo::{collections::Vec as BumpVec, Bump}; +use inlinable_string::InlinableString; use std::collections::HashMap; -use crate::lang::ast::expr2_to_string; -use crate::lang::ast::RecordField; -use crate::lang::ast::{ClosureExtra, Expr2, ExprId, FloatVal, IntStyle, IntVal, WhenBranch}; -use crate::lang::def::canonicalize_defs; -use crate::lang::def::sort_can_defs; -use crate::lang::def::Def; -use crate::lang::def::{CanDefs, PendingDef, References}; -use crate::lang::pattern::{to_pattern2, Pattern2}; +use crate::lang::ast::{ + expr2_to_string, ClosureExtra, Expr2, ExprId, FloatVal, IntStyle, IntVal, RecordField, + WhenBranch, +}; +use crate::lang::def::{ + canonicalize_defs, sort_can_defs, CanDefs, Declaration, Def, PendingDef, References, +}; +use crate::lang::pattern::{to_pattern2, Pattern2, PatternId}; use crate::lang::pool::{NodeId, Pool, PoolStr, PoolVec, ShallowClone}; use crate::lang::scope::Scope; -use crate::lang::types::{Alias, Type2, TypeId}; -use bumpalo::Bump; -use inlinable_string::InlinableString; +use crate::lang::types::{Alias, Annotation2, Type2, TypeId}; + use roc_can::expr::Recursive; use roc_can::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int}; use roc_can::operator::desugar_expr; @@ -34,10 +35,6 @@ use roc_problem::can::{Problem, RuntimeError}; use roc_region::all::{Located, Region}; use roc_types::subs::{VarStore, Variable}; -use super::def::Declaration; -use super::pattern::PatternId; -use super::types::Annotation2; - #[derive(Clone, Debug, PartialEq, Default)] pub struct IntroducedVariables { // NOTE on rigids From 6b882b85de59096e7a92c98a7e28f0e0c4548b25 Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 28 Jun 2021 11:53:47 -0400 Subject: [PATCH 10/30] feat(Expr2): implement Env::problem --- editor/src/lang/expr.rs | 22 +++++++++++----------- editor/tests/solve_expr2.rs | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/editor/src/lang/expr.rs b/editor/src/lang/expr.rs index b98e98f453..ca216f35d2 100644 --- a/editor/src/lang/expr.rs +++ b/editor/src/lang/expr.rs @@ -113,6 +113,8 @@ pub struct Env<'a> { pub pool: &'a mut Pool, pub arena: &'a Bump, + pub problems: BumpVec<'a, Problem>, + pub dep_idents: MutMap, pub module_ids: &'a ModuleIds, pub ident_ids: IdentIds, @@ -142,6 +144,7 @@ impl<'a> Env<'a> { home, arena, pool, + problems: BumpVec::new_in(arena), var_store, dep_idents, module_ids, @@ -162,8 +165,8 @@ impl<'a> Env<'a> { id } - pub fn problem(&mut self, _problem: Problem) { - todo!(); + pub fn problem(&mut self, problem: Problem) { + self.problems.push(problem); } pub fn set_region(&mut self, _node_id: NodeId, _region: Region) { @@ -1374,11 +1377,10 @@ fn canonicalize_lookup( Var(symbol) } - Err(_problem) => { - // env.problem(Problem::RuntimeError(problem.clone())); + Err(problem) => { + env.problem(Problem::RuntimeError(problem.clone())); - // RuntimeError(problem) - todo!() + RuntimeError() } } } else { @@ -1390,14 +1392,12 @@ fn canonicalize_lookup( Var(symbol) } - Err(_problem) => { + Err(problem) => { // Either the module wasn't imported, or // it was imported but it doesn't expose this ident. - // env.problem(Problem::RuntimeError(problem.clone())); + env.problem(Problem::RuntimeError(problem.clone())); - // RuntimeError(problem) - - todo!() + RuntimeError() } } }; diff --git a/editor/tests/solve_expr2.rs b/editor/tests/solve_expr2.rs index f2bcf0bdd9..4f3bf8b254 100644 --- a/editor/tests/solve_expr2.rs +++ b/editor/tests/solve_expr2.rs @@ -118,7 +118,7 @@ fn infer_eq(actual: &str, expected_str: &str) { let content = subs.get(var).content; let interns = Interns { - module_ids, + module_ids: env.module_ids.clone(), all_ident_ids: dep_idents, }; let actual_str = content_to_string(content, &subs, mod_id, &interns); From d817ecb51d361ad84a079ef903f192d60669c570 Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 28 Jun 2021 11:54:19 -0400 Subject: [PATCH 11/30] feat(markup): add explicit case for RuntimeError --- editor/src/editor/markup/nodes.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editor/src/editor/markup/nodes.rs b/editor/src/editor/markup/nodes.rs index 2d09f21ed6..e40a38c714 100644 --- a/editor/src/editor/markup/nodes.rs +++ b/editor/src/editor/markup/nodes.rs @@ -347,6 +347,9 @@ pub fn expr2_to_markup<'a, 'b>( syn_high_style: HighlightStyle::Blank, parent_id_opt: None, }), + Expr2::RuntimeError() => { + todo!("Handle Expr2::RuntimeError") + } rest => todo!("implement expr2_to_markup for {:?}", rest), } } From f4b6bdd7582bb8d7d3fe8d9ed31688e0dde71bcb Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 28 Jun 2021 12:00:54 -0400 Subject: [PATCH 12/30] fix: capacity 2 --- editor/src/lang/constrain.rs | 2 +- editor/src/lang/expr.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index 968eaabb8c..a22ab39334 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -805,7 +805,7 @@ pub fn constrain_expr<'a>( ret_constraint: body_con, })); - let mut and_constraints = BumpVec::with_capacity_in(1, arena); + let mut and_constraints = BumpVec::with_capacity_in(2, arena); and_constraints.push(constrained_def); and_constraints.push(Eq( diff --git a/editor/src/lang/expr.rs b/editor/src/lang/expr.rs index ca216f35d2..936da9242d 100644 --- a/editor/src/lang/expr.rs +++ b/editor/src/lang/expr.rs @@ -37,16 +37,14 @@ use roc_types::subs::{VarStore, Variable}; #[derive(Clone, Debug, PartialEq, Default)] pub struct IntroducedVariables { - // NOTE on rigids - // // Rigids must be unique within a type annoation. // E.g. in `identity : a -> a`, there should only be one // variable (a rigid one, with name "a"). - // Hence `rigids : ImMap` + // Hence `rigids : Map` // // But then between annotations, the same name can occur multiple times, // but a variable can only have one name. Therefore - // `ftv : SendMap`. + // `ftv : Map`. pub wildcards: Vec, pub var_by_name: MutMap, pub name_by_var: MutMap, From 5afcbeed206eac311a57a4b88787e7178035fd1e Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 28 Jun 2021 18:54:21 -0400 Subject: [PATCH 13/30] fix: better RunTimeError case in nodes --- editor/src/editor/markup/nodes.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/editor/src/editor/markup/nodes.rs b/editor/src/editor/markup/nodes.rs index e40a38c714..f5bc37f95a 100644 --- a/editor/src/editor/markup/nodes.rs +++ b/editor/src/editor/markup/nodes.rs @@ -347,9 +347,12 @@ pub fn expr2_to_markup<'a, 'b>( syn_high_style: HighlightStyle::Blank, parent_id_opt: None, }), - Expr2::RuntimeError() => { - todo!("Handle Expr2::RuntimeError") - } + Expr2::RuntimeError() => new_markup_node( + "RunTimeError".to_string(), + expr2_node_id, + HighlightStyle::Blank, + markup_node_pool, + ), rest => todo!("implement expr2_to_markup for {:?}", rest), } } From 8f97637d1cb3e7a003b0787502a3c671ce94ab02 Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 28 Jun 2021 18:54:44 -0400 Subject: [PATCH 14/30] tests: deal with new changes for RunTimeError --- editor/src/editor/mvc/ed_update.rs | 168 ++++++++++++++++------------- 1 file changed, 96 insertions(+), 72 deletions(-) diff --git a/editor/src/editor/mvc/ed_update.rs b/editor/src/editor/mvc/ed_update.rs index 5562261a69..47ada05250 100644 --- a/editor/src/editor/mvc/ed_update.rs +++ b/editor/src/editor/mvc/ed_update.rs @@ -1016,27 +1016,27 @@ pub mod test_ed_update { fn test_record() -> Result<(), String> { assert_insert(&["┃"], &["{ ┃ }"], '{')?; assert_insert(&["{ ┃ }"], &["{ a┃ }"], 'a')?; - assert_insert(&["{ a┃ }"], &["{ ab┃ }"], 'b')?; - assert_insert(&["{ a┃ }"], &["{ a1┃ }"], '1')?; - assert_insert(&["{ a1┃ }"], &["{ a1z┃ }"], 'z')?; - assert_insert(&["{ a1┃ }"], &["{ a15┃ }"], '5')?; - assert_insert(&["{ ab┃ }"], &["{ abc┃ }"], 'c')?; - assert_insert(&["{ ┃abc }"], &["{ z┃abc }"], 'z')?; - assert_insert(&["{ a┃b }"], &["{ az┃b }"], 'z')?; - assert_insert(&["{ a┃b }"], &["{ a9┃b }"], '9')?; + assert_insert(&["{ a┃ }"], &["{ ab┃: RunTimeError }"], 'b')?; + assert_insert(&["{ a┃ }"], &["{ a1┃: RunTimeError }"], '1')?; + assert_insert(&["{ a1┃ }"], &["{ a1z┃: RunTimeError }"], 'z')?; + assert_insert(&["{ a1┃ }"], &["{ a15┃: RunTimeError }"], '5')?; + assert_insert(&["{ ab┃ }"], &["{ abc┃: RunTimeError }"], 'c')?; + assert_insert(&["{ ┃abc }"], &["{ z┃abc: RunTimeError }"], 'z')?; + assert_insert(&["{ a┃b }"], &["{ az┃b: RunTimeError }"], 'z')?; + assert_insert(&["{ a┃b }"], &["{ a9┃b: RunTimeError }"], '9')?; // extra space for Blank node - assert_insert(&["{ a┃ }"], &["{ a: ┃ }"], ':')?; - assert_insert(&["{ abc┃ }"], &["{ abc: ┃ }"], ':')?; - assert_insert(&["{ aBc┃ }"], &["{ aBc: ┃ }"], ':')?; + assert_insert(&["{ a┃ }"], &["{ a┃: RunTimeError }"], ':')?; + assert_insert(&["{ abc┃ }"], &["{ abc┃: RunTimeError }"], ':')?; + assert_insert(&["{ aBc┃ }"], &["{ aBc┃: RunTimeError }"], ':')?; - assert_insert_seq(&["{ a┃ }"], &["{ a: \"┃\" }"], ":\"")?; - assert_insert_seq(&["{ abc┃ }"], &["{ abc: \"┃\" }"], ":\"")?; + assert_insert_seq(&["{ a┃ }"], &["{ a┃: RunTimeError }"], ":\"")?; + assert_insert_seq(&["{ abc┃ }"], &["{ abc┃: RunTimeError }"], ":\"")?; - assert_insert_seq(&["{ a┃ }"], &["{ a: 0┃ }"], ":0")?; - assert_insert_seq(&["{ abc┃ }"], &["{ abc: 9┃ }"], ":9")?; - assert_insert_seq(&["{ a┃ }"], &["{ a: 1000┃ }"], ":1000")?; - assert_insert_seq(&["{ abc┃ }"], &["{ abc: 98761┃ }"], ":98761")?; + assert_insert_seq(&["{ a┃ }"], &["{ a0┃: RunTimeError }"], ":0")?; + assert_insert_seq(&["{ abc┃ }"], &["{ abc9┃: RunTimeError }"], ":9")?; + assert_insert_seq(&["{ a┃ }"], &["{ a1000┃: RunTimeError }"], ":1000")?; + assert_insert_seq(&["{ abc┃ }"], &["{ abc98761┃: RunTimeError }"], ":98761")?; assert_insert(&["{ a: \"┃\" }"], &["{ a: \"a┃\" }"], 'a')?; assert_insert(&["{ a: \"a┃\" }"], &["{ a: \"ab┃\" }"], 'b')?; @@ -1092,9 +1092,9 @@ pub mod test_ed_update { #[test] fn test_nested_record() -> Result<(), String> { - assert_insert_seq(&["{ a┃ }"], &["{ a: { ┃ } }"], ":{")?; - assert_insert_seq(&["{ abc┃ }"], &["{ abc: { ┃ } }"], ":{")?; - assert_insert_seq(&["{ camelCase┃ }"], &["{ camelCase: { ┃ } }"], ":{")?; + assert_insert_seq(&["{ a┃ }"], &["{ a┃: RunTimeError }"], ":{")?; + assert_insert_seq(&["{ abc┃ }"], &["{ abc┃: RunTimeError }"], ":{")?; + assert_insert_seq(&["{ camelCase┃ }"], &["{ camelCase┃: RunTimeError }"], ":{")?; assert_insert_seq(&["{ a: { ┃ } }"], &["{ a: { zulu┃ } }"], "zulu")?; assert_insert_seq( @@ -1104,35 +1104,51 @@ pub mod test_ed_update { )?; assert_insert_seq(&["{ camelCase: { ┃ } }"], &["{ camelCase: { z┃ } }"], "z")?; - assert_insert_seq(&["{ a: { zulu┃ } }"], &["{ a: { zulu: ┃ } }"], ":")?; + assert_insert_seq( + &["{ a: { zulu┃ } }"], + &["{ a: { zulu┃: RunTimeError } }"], + ":", + )?; assert_insert_seq( &["{ abc: { camelCase┃ } }"], - &["{ abc: { camelCase: ┃ } }"], + &["{ abc: { camelCase┃: RunTimeError } }"], ":", )?; assert_insert_seq( &["{ camelCase: { z┃ } }"], - &["{ camelCase: { z: ┃ } }"], + &["{ camelCase: { z┃: RunTimeError } }"], ":", )?; - assert_insert_seq(&["{ a┃: { zulu } }"], &["{ a0┃: { zulu } }"], "0")?; + assert_insert_seq( + &["{ a┃: { zulu } }"], + &["{ a0┃: { zulu: RunTimeError } }"], + "0", + )?; assert_insert_seq( &["{ ab┃c: { camelCase } }"], - &["{ abz┃c: { camelCase } }"], + &["{ abz┃c: { camelCase: RunTimeError } }"], "z", )?; - assert_insert_seq(&["{ ┃camelCase: { z } }"], &["{ x┃camelCase: { z } }"], "x")?; + assert_insert_seq( + &["{ ┃camelCase: { z } }"], + &["{ x┃camelCase: { z: RunTimeError } }"], + "x", + )?; - assert_insert_seq(&["{ a: { zulu┃ } }"], &["{ a: { zulu: \"┃\" } }"], ":\"")?; + assert_insert_seq( + &["{ a: { zulu┃ } }"], + &["{ a: { zulu┃: RunTimeError } }"], + ":\"", + )?; assert_insert_seq( &["{ abc: { camelCase┃ } }"], - &["{ abc: { camelCase: \"┃\" } }"], + &["{ abc: { camelCase┃: RunTimeError } }"], ":\"", )?; assert_insert_seq( &["{ camelCase: { z┃ } }"], - &["{ camelCase: { z: \"┃\" } }"], + &["{ camelCase: { z┃: RunTimeError } }"], ":\"", )?; @@ -1147,15 +1163,19 @@ pub mod test_ed_update { "ul", )?; - assert_insert_seq(&["{ a: { zulu┃ } }"], &["{ a: { zulu: 1┃ } }"], ":1")?; + assert_insert_seq( + &["{ a: { zulu┃ } }"], + &["{ a: { zulu1┃: RunTimeError } }"], + ":1", + )?; assert_insert_seq( &["{ abc: { camelCase┃ } }"], - &["{ abc: { camelCase: 0┃ } }"], + &["{ abc: { camelCase0┃: RunTimeError } }"], ":0", )?; assert_insert_seq( &["{ camelCase: { z┃ } }"], - &["{ camelCase: { z: 45┃ } }"], + &["{ camelCase: { z45┃: RunTimeError } }"], ":45", )?; @@ -1166,15 +1186,19 @@ pub mod test_ed_update { "77", )?; - assert_insert_seq(&["{ a: { zulu┃ } }"], &["{ a: { zulu: { ┃ } } }"], ":{")?; + assert_insert_seq( + &["{ a: { zulu┃ } }"], + &["{ a: { zulu┃: RunTimeError } }"], + ":{", + )?; assert_insert_seq( &["{ abc: { camelCase┃ } }"], - &["{ abc: { camelCase: { ┃ } } }"], + &["{ abc: { camelCase┃: RunTimeError } }"], ":{", )?; assert_insert_seq( &["{ camelCase: { z┃ } }"], - &["{ camelCase: { z: { ┃ } } }"], + &["{ camelCase: { z┃: RunTimeError } }"], ":{", )?; @@ -1201,17 +1225,17 @@ pub mod test_ed_update { assert_insert_seq( &["{ a┃: { bcD: { eFgHij: { k15 } } } }"], - &["{ a4┃: { bcD: { eFgHij: { k15 } } } }"], + &["{ a4┃: { bcD: { eFgHij: { k15: RunTimeError } } } }"], "4", )?; assert_insert_seq( &["{ ┃a: { bcD: { eFgHij: { k15 } } } }"], - &["{ y┃a: { bcD: { eFgHij: { k15 } } } }"], + &["{ y┃a: { bcD: { eFgHij: { k15: RunTimeError } } } }"], "y", )?; assert_insert_seq( &["{ a: { bcD: { eF┃gHij: { k15 } } } }"], - &["{ a: { bcD: { eFxyz┃gHij: { k15 } } } }"], + &["{ a: { bcD: { eFxyz┃gHij: { k15: RunTimeError } } } }"], "xyz", )?; @@ -1236,23 +1260,23 @@ pub mod test_ed_update { assert_insert_seq_ignore(&["{ ┃}"], IGNORE_CHARS)?; assert_insert_seq_ignore(&["{ ┃ }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{ ┃a }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{ ┃abc }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{ ┃a: RunTimeError }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{ ┃abc: RunTimeError }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["┃{ a }"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["{ a }┃"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["{┃ a }"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["{ a ┃}"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["┃{ a: RunTimeError }"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["{ a: ┃RunTimeError }"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["{┃ a: RunTimeError }"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["{ a:┃ RunTimeError }"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["┃{ a15 }"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["{ a15 }┃"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["{┃ a15 }"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["{ a15 ┃}"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["┃{ a15: RunTimeError }"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["{ a15: ┃RunTimeError }"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["{┃ a15: RunTimeError }"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["{ a15:┃ RunTimeError }"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["┃{ camelCase }"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["{ camelCase }┃"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["{┃ camelCase }"], IGNORE_CHARS)?; - assert_insert_seq_ignore(&["{ camelCase ┃}"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["┃{ camelCase: RunTimeError }"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["{ camelCase: ┃RunTimeError }"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["{┃ camelCase: RunTimeError }"], IGNORE_CHARS)?; + assert_insert_seq_ignore(&["{ camelCase:┃ RunTimeError }"], IGNORE_CHARS)?; assert_insert_seq_ignore(&["┃{ a: \"\" }"], IGNORE_CHARS)?; assert_insert_seq_ignore(&["{┃ a: \"\" }"], IGNORE_CHARS)?; @@ -1328,17 +1352,17 @@ pub mod test_ed_update { assert_insert_seq_ignore(&["┃{ a: { } }"], IGNORE_NO_LTR)?; assert_insert_seq_ignore(&["{ ┃a: { } }"], "1")?; - assert_insert_seq_ignore(&["{ camelCaseB1: { z15a ┃} }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{ camelCaseB1: {┃ z15a } }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{ camelCaseB1: ┃{ z15a } }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{ camelCaseB1: { z15a }┃ }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{ camelCaseB1: { z15a } ┃}"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{ camelCaseB1: { z15a } }┃"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{ camelCaseB1:┃ { z15a } }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{┃ camelCaseB1: { z15a } }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["┃{ camelCaseB1: { z15a } }"], IGNORE_NO_LTR)?; - assert_insert_seq_ignore(&["{ ┃camelCaseB1: { z15a } }"], "1")?; - assert_insert_seq_ignore(&["{ camelCaseB1: { ┃z15a } }"], "1")?; + assert_insert_seq_ignore(&["{ camelCaseB1: { z15a:┃ RunTimeError } }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{ camelCaseB1: {┃ z15a: RunTimeError } }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{ camelCaseB1: ┃{ z15a: RunTimeError } }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: ┃RunTimeError } }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: R┃unTimeError } }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: Ru┃nTimeError } }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{ camelCaseB1:┃ { z15a: RunTimeError } }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{┃ camelCaseB1: { z15a: RunTimeError } }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["┃{ camelCaseB1: { z15a: RunTimeError } }"], IGNORE_NO_LTR)?; + assert_insert_seq_ignore(&["{ ┃camelCaseB1: { z15a: RunTimeError } }"], "1")?; + assert_insert_seq_ignore(&["{ camelCaseB1: { ┃z15a: RunTimeError } }"], "1")?; assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: \"\"┃ } }"], IGNORE_NO_LTR)?; assert_insert_seq_ignore(&["{ camelCaseB1: { z15a: ┃\"\" } }"], IGNORE_NO_LTR)?; @@ -1428,39 +1452,39 @@ pub mod test_ed_update { )?; assert_insert_seq_ignore( - &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase ┃} } } } } } } }"], + &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase:┃ RunTimeError } } } } } } } }"], IGNORE_NO_LTR, )?; assert_insert_seq_ignore( - &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } ┃} } } } } } }"], + &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase: R┃unTimeError } } } } } } } }"], IGNORE_NO_LTR, )?; assert_insert_seq_ignore( - &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }┃"], + &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase: RunTimeError } } } } } } } }┃"], IGNORE_NO_LTR, )?; assert_insert_seq_ignore( - &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } ┃} } }"], + &["{ g: { oi: { ng: { d: { e: { e: { p: { camelCase: RunTimeEr┃ror } } } } } } } }"], IGNORE_NO_LTR, )?; assert_insert_seq_ignore( - &["{ g: { oi: { ng: { d: { e: {┃ e: { p: { camelCase } } } } } } } }"], + &["{ g: { oi: { ng: { d: { e: {┃ e: { p: { camelCase: RunTimeError } } } } } } } }"], IGNORE_NO_LTR, )?; assert_insert_seq_ignore( - &["{ g: { oi: { ng: { d: { e: { e:┃ { p: { camelCase } } } } } } } }"], + &["{ g: { oi: { ng: { d: { e: { e:┃ { p: { camelCase: RunTimeError } } } } } } } }"], IGNORE_NO_LTR, )?; assert_insert_seq_ignore( - &["{┃ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }"], + &["{┃ g: { oi: { ng: { d: { e: { e: { p: { camelCase: RunTimeError } } } } } } } }"], IGNORE_NO_LTR, )?; assert_insert_seq_ignore( - &["┃{ g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }"], + &["┃{ g: { oi: { ng: { d: { e: { e: { p: { camelCase: RunTimeError } } } } } } } }"], IGNORE_NO_LTR, )?; assert_insert_seq_ignore( - &["{ ┃g: { oi: { ng: { d: { e: { e: { p: { camelCase } } } } } } } }"], + &["{ ┃g: { oi: { ng: { d: { e: { e: { p: { camelCase: RunTimeError } } } } } } } }"], "2", )?; Ok(()) From 528e1f543b135c6be1a1a522a6e1fd3b6e3a3d84 Mon Sep 17 00:00:00 2001 From: rvcas Date: Fri, 2 Jul 2021 16:17:26 -0400 Subject: [PATCH 15/30] fix: value def adjustments --- editor/src/lang/ast.rs | 12 +++++------ editor/src/lang/def.rs | 4 ++-- editor/src/lang/module.rs | 42 ++++++++++++++++++++------------------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index d8137aa2c4..50e0d32891 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -218,10 +218,10 @@ pub enum Expr2 { #[derive(Debug)] pub struct ValueDef { - pub pattern: PatternId, // 4B - pub expr: ExprId, // 4B - pub expr_type: Option, // ? - pub expr_var: Variable, // 4B + pub pattern: PatternId, // 4B + pub expr: ExprId, // 4B + pub opt_expr_type: Option<(TypeId, Rigids)>, // ? + pub expr_var: Variable, // 4B } impl ShallowClone for ValueDef { @@ -229,8 +229,8 @@ impl ShallowClone for ValueDef { Self { pattern: self.pattern, expr: self.expr, - expr_type: match &self.expr_type { - Some(rigids) => Some(rigids.shallow_clone()), + opt_expr_type: match &self.opt_expr_type { + Some((annotation, rigids)) => Some((*annotation, rigids.shallow_clone())), None => None, }, expr_var: self.expr_var, diff --git a/editor/src/lang/def.rs b/editor/src/lang/def.rs index 3baaadf06b..afdef67359 100644 --- a/editor/src/lang/def.rs +++ b/editor/src/lang/def.rs @@ -628,7 +628,7 @@ fn canonicalize_pending_def<'a>( pattern: loc_can_pattern, expr: env.pool.add(loc_can_expr), // annotation - expr_type: Some(rigids), + opt_expr_type: Some((annotation, rigids)), expr_var: env.var_store.fresh(), }; @@ -750,7 +750,7 @@ fn canonicalize_pending_def<'a>( let value_def = ValueDef { pattern: loc_can_pattern, expr: env.pool.add(loc_can_expr), - expr_type: None, + opt_expr_type: None, expr_var: env.var_store.fresh(), }; diff --git a/editor/src/lang/module.rs b/editor/src/lang/module.rs index 7cd3e039aa..3fbc93228f 100644 --- a/editor/src/lang/module.rs +++ b/editor/src/lang/module.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] #![allow(unused_imports)] #![allow(unused_variables)] -use crate::lang::ast::{FunctionDef, ValueDef}; +use crate::lang::ast::{Expr2, FunctionDef, ValueDef}; use crate::lang::def::{canonicalize_defs, sort_can_defs, Declaration, Def}; use crate::lang::expr::Env; use crate::lang::expr::Output; @@ -175,7 +175,7 @@ pub fn canonicalize_module_defs<'a>( // this is now done later, in file.rs. match sort_can_defs(&mut env, defs, Output::default()) { - (Ok(declarations), output) => { + (Ok(mut declarations), output) => { use Declaration::*; for decl in declarations.iter() { @@ -238,29 +238,31 @@ pub fn canonicalize_module_defs<'a>( // exposed_symbols and added to exposed_vars_by_symbol. If any were // not, that means they were declared as exposed but there was // no actual declaration with that name! - // for symbol in exposed_symbols { - // env.problem(Problem::ExposedButNotDefined(symbol)); + for symbol in exposed_symbols { + env.problem(Problem::ExposedButNotDefined(symbol)); - // // In case this exposed value is referenced by other modules, - // // create a decl for it whose implementation is a runtime error. - // let mut pattern_vars = SendMap::default(); - // pattern_vars.insert(symbol, env.var_store.fresh()); + // In case this exposed value is referenced by other modules, + // create a decl for it whose implementation is a runtime error. + let mut pattern_vars = SendMap::default(); + pattern_vars.insert(symbol, env.var_store.fresh()); - // let runtime_error = RuntimeError::ExposedButNotDefined(symbol); + let runtime_error = RuntimeError::ExposedButNotDefined(symbol); - // let value_def = { - // let pattern = env.pool.add(Pattern2::Identifier(symbol)); - // ValueDef { - // pattern, - // expr_type: None, - // expr_var: env.var_store.fresh(), - // } - // }; + let value_def = { + let pattern = env.pool.add(Pattern2::Identifier(symbol)); + let expr = env.pool.add(Expr2::RuntimeError()); + ValueDef { + pattern, + expr, + opt_expr_type: None, + expr_var: env.var_store.fresh(), + } + }; - // let def = Def::Value(value_def); + let def = Def::Value(value_def); - // declarations.push(Declaration::Declare(def)); - // } + declarations.push(Declaration::Declare(def)); + } // Incorporate any remaining output.lookups entries into references. for symbol in output.references.lookups { From e4bc0adc598e4954489264d46e0289b8bdec0138 Mon Sep 17 00:00:00 2001 From: rvcas Date: Fri, 2 Jul 2021 20:53:37 -0400 Subject: [PATCH 16/30] feat: make ValueDef an enum --- editor/src/lang/ast.rs | 49 +++++++++++++----- editor/src/lang/constrain.rs | 98 ++++++++++++++++++++---------------- editor/src/lang/def.rs | 25 +++++---- editor/src/lang/module.rs | 11 ++-- 4 files changed, 110 insertions(+), 73 deletions(-) diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index 86a37e4ed4..9d8d413c88 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -217,23 +217,48 @@ pub enum Expr2 { } #[derive(Debug)] -pub struct ValueDef { - pub pattern: PatternId, // 4B - pub expr: ExprId, // 4B - pub opt_expr_type: Option<(TypeId, Rigids)>, // ? - pub expr_var: Variable, // 4B +pub enum ValueDef { + WithAnnotation { + pattern_id: PatternId, // 4B + expr_id: ExprId, // 4B + type_id: TypeId, + rigids: NodeId, + expr_var: Variable, // 4B + }, + NoAnnotation { + pattern_id: PatternId, // 4B + expr_id: ExprId, // 4B + expr_var: Variable, // 4B + }, } impl ShallowClone for ValueDef { fn shallow_clone(&self) -> Self { - Self { - pattern: self.pattern, - expr: self.expr, - opt_expr_type: match &self.opt_expr_type { - Some((annotation, rigids)) => Some((*annotation, rigids.shallow_clone())), - None => None, + match self { + Self::WithAnnotation { + pattern_id, + expr_id, + type_id, + rigids, + expr_var, + padding, + } => Self::WithAnnotation { + pattern_id: *pattern_id, + expr_id: *expr_id, + type_id: *type_id, + rigids: *rigids, + expr_var: *expr_var, + padding: *padding, + }, + Self::NoAnnotation { + pattern_id, + expr_id, + expr_var, + } => Self::NoAnnotation { + pattern_id: *pattern_id, + expr_id: *expr_id, + expr_var: *expr_var, }, - expr_var: self.expr_var, } } } diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index a22ab39334..b813d76153 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -1,7 +1,7 @@ use bumpalo::{collections::Vec as BumpVec, Bump}; use crate::lang::{ - ast::{Expr2, RecordField, WhenBranch}, + ast::{Expr2, RecordField, ValueDef, WhenBranch}, expr::Env, pattern::{DestructType, Pattern2, PatternState2, RecordDestruct}, pool::{Pool, PoolStr, PoolVec, ShallowClone}, @@ -766,57 +766,67 @@ pub fn constrain_expr<'a>( let body = env.pool.get(*body_id); let body_con = constrain_expr(arena, env, body, expected.shallow_clone(), region); - let pattern = env.pool.get(value_def.pattern); - let mut flex_vars = BumpVec::with_capacity_in(1, arena); - flex_vars.push(*body_var); + match value_def { + ValueDef::WithAnnotation { .. } => todo!("implement {:?}", value_def), + ValueDef::NoAnnotation { + pattern_id, + expr_id, + expr_var, + } => { + let pattern = env.pool.get(*pattern_id); - let expr_type = Type2::Variable(value_def.expr_var); + let mut flex_vars = BumpVec::with_capacity_in(1, arena); + flex_vars.push(*body_var); - let pattern_expected = PExpected::NoExpectation(expr_type.shallow_clone()); - let mut state = PatternState2 { - headers: BumpMap::new_in(arena), - vars: BumpVec::with_capacity_in(1, arena), - constraints: BumpVec::with_capacity_in(1, arena), - }; + let expr_type = Type2::Variable(*expr_var); - constrain_pattern(arena, env, pattern, region, pattern_expected, &mut state); - state.vars.push(value_def.expr_var); + let pattern_expected = PExpected::NoExpectation(expr_type.shallow_clone()); + let mut state = PatternState2 { + headers: BumpMap::new_in(arena), + vars: BumpVec::with_capacity_in(1, arena), + constraints: BumpVec::with_capacity_in(1, arena), + }; - let def_expr = env.pool.get(value_def.expr); + constrain_pattern(arena, env, pattern, region, pattern_expected, &mut state); + state.vars.push(*expr_var); - let constrained_def = Let(arena.alloc(LetConstraint { - rigid_vars: BumpVec::new_in(arena), - flex_vars: state.vars, - def_types: state.headers, - defs_constraint: Let(arena.alloc(LetConstraint { - rigid_vars: BumpVec::new_in(arena), // always empty - flex_vars: BumpVec::new_in(arena), // empty, because our functions have no arguments - def_types: BumpMap::new_in(arena), // empty, because our functions have no arguments! - defs_constraint: And(state.constraints), - ret_constraint: constrain_expr( - arena, - env, - def_expr, - Expected::NoExpectation(expr_type), + let def_expr = env.pool.get(*expr_id); + + let constrained_def = Let(arena.alloc(LetConstraint { + rigid_vars: BumpVec::new_in(arena), + flex_vars: state.vars, + def_types: state.headers, + defs_constraint: Let(arena.alloc(LetConstraint { + rigid_vars: BumpVec::new_in(arena), // always empty + flex_vars: BumpVec::new_in(arena), // empty, because our functions have no arguments + def_types: BumpMap::new_in(arena), // empty, because our functions have no arguments! + defs_constraint: And(state.constraints), + ret_constraint: constrain_expr( + arena, + env, + def_expr, + Expected::NoExpectation(expr_type), + region, + ), + })), + ret_constraint: body_con, + })); + + let mut and_constraints = BumpVec::with_capacity_in(2, arena); + + and_constraints.push(constrained_def); + and_constraints.push(Eq( + Type2::Variable(*body_var), + expected, + Category::Storage(std::file!(), std::line!()), + // TODO: needs to be ret region region, - ), - })), - ret_constraint: body_con, - })); + )); - let mut and_constraints = BumpVec::with_capacity_in(2, arena); - - and_constraints.push(constrained_def); - and_constraints.push(Eq( - Type2::Variable(*body_var), - expected, - Category::Storage(std::file!(), std::line!()), - // TODO: needs to be ret region - region, - )); - - exists(arena, flex_vars, And(and_constraints)) + exists(arena, flex_vars, And(and_constraints)) + } + } } Expr2::Update { symbol, diff --git a/editor/src/lang/def.rs b/editor/src/lang/def.rs index afdef67359..f7f4deaa52 100644 --- a/editor/src/lang/def.rs +++ b/editor/src/lang/def.rs @@ -46,8 +46,11 @@ impl Def { match self { Def::AnnotationOnly { .. } => todo!("lost pattern information here ... "), - Def::Value(ValueDef { pattern, .. }) => { - let pattern2 = &pool[*pattern]; + Def::Value( + ValueDef::WithAnnotation { pattern_id, .. } + | ValueDef::NoAnnotation { pattern_id, .. }, + ) => { + let pattern2 = &pool[*pattern_id]; output.extend(symbols_from_pattern(pool, pattern2)); } Def::Function(function_def) => match function_def { @@ -624,12 +627,13 @@ fn canonicalize_pending_def<'a>( }; let annotation = env.add(annotation, loc_ann.region); - let value_def = ValueDef { - pattern: loc_can_pattern, - expr: env.pool.add(loc_can_expr), - // annotation - opt_expr_type: Some((annotation, rigids)), + let value_def = ValueDef::WithAnnotation { + pattern_id: loc_can_pattern, + expr_id: env.pool.add(loc_can_expr), + type_id: annotation, + rigids: env.pool.add(rigids), expr_var: env.var_store.fresh(), + padding: Default::default(), }; let def = Def::Value(value_def); @@ -747,10 +751,9 @@ fn canonicalize_pending_def<'a>( } _ => { - let value_def = ValueDef { - pattern: loc_can_pattern, - expr: env.pool.add(loc_can_expr), - opt_expr_type: None, + let value_def = ValueDef::NoAnnotation { + pattern_id: loc_can_pattern, + expr_id: env.pool.add(loc_can_expr), expr_var: env.var_store.fresh(), }; diff --git a/editor/src/lang/module.rs b/editor/src/lang/module.rs index 3fbc93228f..c0494d3193 100644 --- a/editor/src/lang/module.rs +++ b/editor/src/lang/module.rs @@ -249,12 +249,11 @@ pub fn canonicalize_module_defs<'a>( let runtime_error = RuntimeError::ExposedButNotDefined(symbol); let value_def = { - let pattern = env.pool.add(Pattern2::Identifier(symbol)); - let expr = env.pool.add(Expr2::RuntimeError()); - ValueDef { - pattern, - expr, - opt_expr_type: None, + let pattern_id = env.pool.add(Pattern2::Identifier(symbol)); + let expr_id = env.pool.add(Expr2::RuntimeError()); + ValueDef::NoAnnotation { + pattern_id, + expr_id, expr_var: env.var_store.fresh(), } }; From a6c6760c2a20473cbc070abe6e24abb9cdff5521 Mon Sep 17 00:00:00 2001 From: rvcas Date: Fri, 2 Jul 2021 21:00:57 -0400 Subject: [PATCH 17/30] this compiles but has a lot of indirection --- editor/src/lang/ast.rs | 12 +++++------- editor/src/lang/def.rs | 8 +++++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index 9d8d413c88..f47fc68dda 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -219,9 +219,9 @@ pub enum Expr2 { #[derive(Debug)] pub enum ValueDef { WithAnnotation { - pattern_id: PatternId, // 4B - expr_id: ExprId, // 4B - type_id: TypeId, + pattern_id: PatternId, // 4B + expr_id: PoolVec, // 4B + type_id: PoolVec, rigids: NodeId, expr_var: Variable, // 4B }, @@ -241,14 +241,12 @@ impl ShallowClone for ValueDef { type_id, rigids, expr_var, - padding, } => Self::WithAnnotation { pattern_id: *pattern_id, - expr_id: *expr_id, - type_id: *type_id, + expr_id: expr_id.shallow_clone(), + type_id: type_id.shallow_clone(), rigids: *rigids, expr_var: *expr_var, - padding: *padding, }, Self::NoAnnotation { pattern_id, diff --git a/editor/src/lang/def.rs b/editor/src/lang/def.rs index f7f4deaa52..3b6d87b076 100644 --- a/editor/src/lang/def.rs +++ b/editor/src/lang/def.rs @@ -629,11 +629,13 @@ fn canonicalize_pending_def<'a>( let value_def = ValueDef::WithAnnotation { pattern_id: loc_can_pattern, - expr_id: env.pool.add(loc_can_expr), - type_id: annotation, + expr_id: PoolVec::new( + vec![env.pool.add(loc_can_expr)].into_iter(), + env.pool, + ), + type_id: PoolVec::new(vec![annotation].into_iter(), env.pool), rigids: env.pool.add(rigids), expr_var: env.var_store.fresh(), - padding: Default::default(), }; let def = Def::Value(value_def); From 197a34c41d3efc4c09e48015707629d0cb10b10c Mon Sep 17 00:00:00 2001 From: rvcas Date: Fri, 2 Jul 2021 21:24:34 -0400 Subject: [PATCH 18/30] fix: accidentally used experimental feature --- editor/src/lang/def.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/editor/src/lang/def.rs b/editor/src/lang/def.rs index 3b6d87b076..c9ae1bfc4a 100644 --- a/editor/src/lang/def.rs +++ b/editor/src/lang/def.rs @@ -46,13 +46,13 @@ impl Def { match self { Def::AnnotationOnly { .. } => todo!("lost pattern information here ... "), - Def::Value( + Def::Value(value_def) => match value_def { ValueDef::WithAnnotation { pattern_id, .. } - | ValueDef::NoAnnotation { pattern_id, .. }, - ) => { - let pattern2 = &pool[*pattern_id]; - output.extend(symbols_from_pattern(pool, pattern2)); - } + | ValueDef::NoAnnotation { pattern_id, .. } => { + let pattern2 = &pool[*pattern_id]; + output.extend(symbols_from_pattern(pool, pattern2)); + } + }, Def::Function(function_def) => match function_def { FunctionDef::NoAnnotation { name, .. } | FunctionDef::WithAnnotation { name, .. } => { From 8deb377d30128eebd96090725b3a63705b904aa0 Mon Sep 17 00:00:00 2001 From: Eric Correia Date: Sat, 3 Jul 2021 12:06:48 -0400 Subject: [PATCH 19/30] tag must be its own type fix --- compiler/mono/src/ir.rs | 21 +++++++++++---------- compiler/test_gen/src/gen_tags.rs | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 94877e4ad0..9729d7b27d 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -4126,17 +4126,18 @@ fn convert_tag_union<'a>( hole, ), ByteUnion(tag_names) => { - let tag_id = tag_names - .iter() - .position(|key| key == &tag_name) - .expect("tag must be in its own type"); + let opt_tag_id = tag_names.iter().position(|key| key == &tag_name); + // .expect("tag must be in its own type"); - Stmt::Let( - assigned, - Expr::Literal(Literal::Byte(tag_id as u8)), - Layout::Builtin(Builtin::Int8), - hole, - ) + match opt_tag_id { + Some(tag_id) => Stmt::Let( + assigned, + Expr::Literal(Literal::Byte(tag_id as u8)), + Layout::Builtin(Builtin::Int8), + hole, + ), + None => Stmt::RuntimeError("tag must be in its own type"), + } } Newtype { diff --git a/compiler/test_gen/src/gen_tags.rs b/compiler/test_gen/src/gen_tags.rs index 776c06ff07..cfd11b807f 100644 --- a/compiler/test_gen/src/gen_tags.rs +++ b/compiler/test_gen/src/gen_tags.rs @@ -1033,3 +1033,20 @@ fn applied_tag_function_linked_list() { i64 ); } + +#[test] +#[should_panic(expected = "")] +fn tag_must_be_its_own_type() { + assert_evals_to!( + indoc!( + r#" + z : [ A, B, C ] + z = Z + + z + "# + ), + 1, + i64 + ); +} From aa123635fa23c022f24f8b285ee04efc88df4e27 Mon Sep 17 00:00:00 2001 From: Eric Correia Date: Sat, 3 Jul 2021 12:08:42 -0400 Subject: [PATCH 20/30] remove comment --- compiler/mono/src/ir.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 9729d7b27d..87080476cb 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -4127,7 +4127,6 @@ fn convert_tag_union<'a>( ), ByteUnion(tag_names) => { let opt_tag_id = tag_names.iter().position(|key| key == &tag_name); - // .expect("tag must be in its own type"); match opt_tag_id { Some(tag_id) => Stmt::Let( From 16542f0e1e0a98a30ad296fcd15d466b6fee2608 Mon Sep 17 00:00:00 2001 From: rvcas Date: Sat, 3 Jul 2021 13:04:38 -0400 Subject: [PATCH 21/30] test: incompatible type params in if --- compiler/test_gen/src/gen_list.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index b6384a8ba5..9a964c3213 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -1939,3 +1939,23 @@ fn list_sort_with() { RocList ); } + +#[test] +#[should_panic(expected = r#"Roc failed with message: "invalid ret_layout""#)] +fn lists_with_incompatible_type_param_in_if() { + assert_evals_to!( + indoc!( + r#" + list1 = [ {} ] + + list2 = [ "" ] + + x = if True then list1 else list2 + + "" + "# + ), + RocStr::empty(), + RocStr + ); +} From 39d39c218f2c71886ecbd3c07449c463c0bc9467 Mon Sep 17 00:00:00 2001 From: rvcas Date: Sat, 3 Jul 2021 13:05:30 -0400 Subject: [PATCH 22/30] feat(mono): return Stmt::RuntimeError on bad layouts for If --- compiler/mono/src/ir.rs | 213 ++++++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 104 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 94877e4ad0..a1f595fcf0 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -3150,118 +3150,123 @@ pub fn with_hole<'a>( branches, final_else, } => { - let ret_layout = layout_cache - .from_var(env.arena, branch_var, env.subs) - .expect("invalid ret_layout"); - let cond_layout = layout_cache - .from_var(env.arena, cond_var, env.subs) - .expect("invalid cond_layout"); + match ( + layout_cache.from_var(env.arena, branch_var, env.subs), + layout_cache.from_var(env.arena, cond_var, env.subs), + ) { + (Ok(ret_layout), Ok(cond_layout)) => { + // if the hole is a return, then we don't need to merge the two + // branches together again, we can just immediately return + let is_terminated = matches!(hole, Stmt::Ret(_)); - // if the hole is a return, then we don't need to merge the two - // branches together again, we can just immediately return - let is_terminated = matches!(hole, Stmt::Ret(_)); + if is_terminated { + let terminator = hole; - if is_terminated { - let terminator = hole; + let mut stmt = with_hole( + env, + final_else.value, + branch_var, + procs, + layout_cache, + assigned, + terminator, + ); - let mut stmt = with_hole( - env, - final_else.value, - branch_var, - procs, - layout_cache, - assigned, - terminator, - ); + for (loc_cond, loc_then) in branches.into_iter().rev() { + let branching_symbol = env.unique_symbol(); - for (loc_cond, loc_then) in branches.into_iter().rev() { - let branching_symbol = env.unique_symbol(); + let then = with_hole( + env, + loc_then.value, + branch_var, + procs, + layout_cache, + assigned, + terminator, + ); - let then = with_hole( - env, - loc_then.value, - branch_var, - procs, - layout_cache, - assigned, - terminator, - ); + stmt = cond(env, branching_symbol, cond_layout, then, stmt, ret_layout); - stmt = cond(env, branching_symbol, cond_layout, then, stmt, ret_layout); + // add condition + stmt = with_hole( + env, + loc_cond.value, + cond_var, + procs, + layout_cache, + branching_symbol, + env.arena.alloc(stmt), + ); + } + stmt + } else { + let assigned_in_jump = env.unique_symbol(); + let id = JoinPointId(env.unique_symbol()); - // add condition - stmt = with_hole( - env, - loc_cond.value, - cond_var, - procs, - layout_cache, - branching_symbol, - env.arena.alloc(stmt), - ); - } - stmt - } else { - let assigned_in_jump = env.unique_symbol(); - let id = JoinPointId(env.unique_symbol()); - - let terminator = env - .arena - .alloc(Stmt::Jump(id, env.arena.alloc([assigned_in_jump]))); - - let mut stmt = with_hole( - env, - final_else.value, - branch_var, - procs, - layout_cache, - assigned_in_jump, - terminator, - ); - - for (loc_cond, loc_then) in branches.into_iter().rev() { - let branching_symbol = possible_reuse_symbol(env, procs, &loc_cond.value); - - let then = with_hole( - env, - loc_then.value, - branch_var, - procs, - layout_cache, - assigned_in_jump, - terminator, - ); - - stmt = cond(env, branching_symbol, cond_layout, then, stmt, ret_layout); - - // add condition - stmt = assign_to_symbol( - env, - procs, - layout_cache, - cond_var, - loc_cond, - branching_symbol, - stmt, - ); - } - - let layout = layout_cache - .from_var(env.arena, branch_var, env.subs) - .unwrap_or_else(|err| panic!("TODO turn fn_var into a RuntimeError {:?}", err)); - - let param = Param { - symbol: assigned, - layout, - borrow: false, - }; - - Stmt::Join { - id, - parameters: env.arena.alloc([param]), - remainder: env.arena.alloc(stmt), - body: hole, + let terminator = env + .arena + .alloc(Stmt::Jump(id, env.arena.alloc([assigned_in_jump]))); + + let mut stmt = with_hole( + env, + final_else.value, + branch_var, + procs, + layout_cache, + assigned_in_jump, + terminator, + ); + + for (loc_cond, loc_then) in branches.into_iter().rev() { + let branching_symbol = + possible_reuse_symbol(env, procs, &loc_cond.value); + + let then = with_hole( + env, + loc_then.value, + branch_var, + procs, + layout_cache, + assigned_in_jump, + terminator, + ); + + stmt = cond(env, branching_symbol, cond_layout, then, stmt, ret_layout); + + // add condition + stmt = assign_to_symbol( + env, + procs, + layout_cache, + cond_var, + loc_cond, + branching_symbol, + stmt, + ); + } + + let layout = layout_cache + .from_var(env.arena, branch_var, env.subs) + .unwrap_or_else(|err| { + panic!("TODO turn fn_var into a RuntimeError {:?}", err) + }); + + let param = Param { + symbol: assigned, + layout, + borrow: false, + }; + + Stmt::Join { + id, + parameters: env.arena.alloc([param]), + remainder: env.arena.alloc(stmt), + body: hole, + } + } } + (Err(_), _) => Stmt::RuntimeError("invalid ret_layout"), + (_, Err(_)) => Stmt::RuntimeError("invalid cond_layout"), } } From 3fa5b4363e8caecaf8818e37be9639e04ca66ea9 Mon Sep 17 00:00:00 2001 From: rvcas Date: Sat, 3 Jul 2021 14:23:21 -0400 Subject: [PATCH 23/30] feat(cli): do not run executable if build failed --- cli/src/build.rs | 9 ++++++--- cli/src/lib.rs | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cli/src/build.rs b/cli/src/build.rs index a1f3add2bc..26ddc1e37c 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -204,12 +204,15 @@ pub fn build_file<'a>( let total_time = compilation_start.elapsed().unwrap(); + // TODO change this to report whether there were errors or warnings! + let outcome = match &cmd_result { + Ok(exit_status) if exit_status.success() => BuildOutcome::NoProblems, + _ => BuildOutcome::Errors, + }; + // If the cmd errored out, return the Err. cmd_result?; - // TODO change this to report whether there were errors or warnings! - let outcome = BuildOutcome::NoProblems; - Ok(BuiltFile { binary_path, outcome, diff --git a/cli/src/lib.rs b/cli/src/lib.rs index a86c3ec56c..d5a80eb53f 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -231,7 +231,10 @@ pub fn build(target: &Triple, matches: &ArgMatches, config: BuildConfig) -> io:: } } - roc_run(cmd.current_dir(original_cwd)) + match outcome { + BuildOutcome::Errors => Ok(2), + _ => roc_run(cmd.current_dir(original_cwd)), + } } } } From a82b403aa41c3d100cf9bf2e9255704892afaac5 Mon Sep 17 00:00:00 2001 From: rvcas Date: Sat, 3 Jul 2021 14:41:58 -0400 Subject: [PATCH 24/30] feat(cli): impl BuildOutcome::status_code --- cli/src/build.rs | 10 ++++++++++ cli/src/lib.rs | 12 +++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cli/src/build.rs b/cli/src/build.rs index 26ddc1e37c..1682aff916 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -26,6 +26,16 @@ pub enum BuildOutcome { Errors, } +impl BuildOutcome { + pub fn status_code(&self) -> i32 { + match self { + Self::NoProblems => 0, + Self::OnlyWarnings => 1, + Self::Errors => 2, + } + } +} + pub struct BuiltFile { pub binary_path: PathBuf, pub outcome: BuildOutcome, diff --git a/cli/src/lib.rs b/cli/src/lib.rs index d5a80eb53f..1cd2ea0eab 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -196,13 +196,6 @@ pub fn build(target: &Triple, matches: &ArgMatches, config: BuildConfig) -> io:: .strip_prefix(env::current_dir().unwrap()) .unwrap_or(&binary_path); - // Return a nonzero exit code if there were problems - let status_code = match outcome { - BuildOutcome::NoProblems => 0, - BuildOutcome::OnlyWarnings => 1, - BuildOutcome::Errors => 2, - }; - // No need to waste time freeing this memory, // since the process is about to exit anyway. std::mem::forget(arena); @@ -213,7 +206,8 @@ pub fn build(target: &Triple, matches: &ArgMatches, config: BuildConfig) -> io:: total_time.as_millis() ); - Ok(status_code) + // Return a nonzero exit code if there were problems + Ok(outcome.status_code()) } BuildAndRun { roc_file_arg_index } => { let mut cmd = Command::new(binary_path); @@ -232,7 +226,7 @@ pub fn build(target: &Triple, matches: &ArgMatches, config: BuildConfig) -> io:: } match outcome { - BuildOutcome::Errors => Ok(2), + BuildOutcome::Errors => Ok(outcome.status_code()), _ => roc_run(cmd.current_dir(original_cwd)), } } From fe7e492572b61590209e91f2006fe76fd07ac8db Mon Sep 17 00:00:00 2001 From: rvcas Date: Sat, 3 Jul 2021 14:54:05 -0400 Subject: [PATCH 25/30] chore: cleaner way to check status code --- cli/src/build.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cli/src/build.rs b/cli/src/build.rs index 1682aff916..d75bf0361b 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -214,14 +214,15 @@ pub fn build_file<'a>( let total_time = compilation_start.elapsed().unwrap(); - // TODO change this to report whether there were errors or warnings! - let outcome = match &cmd_result { - Ok(exit_status) if exit_status.success() => BuildOutcome::NoProblems, - _ => BuildOutcome::Errors, - }; - // If the cmd errored out, return the Err. - cmd_result?; + let exit_status = cmd_result?; + + // TODO change this to report whether there were errors or warnings! + let outcome = if exit_status.success() { + BuildOutcome::NoProblems + } else { + BuildOutcome::Errors + }; Ok(BuiltFile { binary_path, From 40bb078882a76b7e43abd10d815e6b30f90e2e87 Mon Sep 17 00:00:00 2001 From: rvcas Date: Sun, 4 Jul 2021 15:32:48 -0400 Subject: [PATCH 26/30] feat: adjust rigids to let it fit better in ValueDef --- editor/src/lang/ast.rs | 81 ++++++++++++++++++++++++++++++++++++------ editor/src/lang/def.rs | 69 ++++++++--------------------------- 2 files changed, 84 insertions(+), 66 deletions(-) diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index f47fc68dda..b5fbd154cc 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -1,11 +1,15 @@ #![allow(clippy::manual_map)] +use std::collections::{HashMap, HashSet}; +use std::hash::BuildHasherDefault; + use crate::lang::pattern::{Pattern2, PatternId}; use crate::lang::pool::Pool; use crate::lang::pool::{NodeId, PoolStr, PoolVec, ShallowClone}; use crate::lang::types::{Type2, TypeId}; use arraystring::{typenum::U30, ArrayString}; use roc_can::expr::Recursive; +use roc_collections::all::WyHash; use roc_module::low_level::LowLevel; use roc_module::operator::CalledVia; use roc_module::symbol::Symbol; @@ -219,10 +223,10 @@ pub enum Expr2 { #[derive(Debug)] pub enum ValueDef { WithAnnotation { - pattern_id: PatternId, // 4B - expr_id: PoolVec, // 4B - type_id: PoolVec, - rigids: NodeId, + pattern_id: PatternId, // 4B + expr_id: ExprId, // 4B + type_id: TypeId, + rigids: Rigids, expr_var: Variable, // 4B }, NoAnnotation { @@ -243,9 +247,9 @@ impl ShallowClone for ValueDef { expr_var, } => Self::WithAnnotation { pattern_id: *pattern_id, - expr_id: expr_id.shallow_clone(), - type_id: type_id.shallow_clone(), - rigids: *rigids, + expr_id: *expr_id, + type_id: *type_id, + rigids: rigids.shallow_clone(), expr_var: *expr_var, }, Self::NoAnnotation { @@ -312,8 +316,63 @@ impl ShallowClone for FunctionDef { #[derive(Debug)] pub struct Rigids { - pub named: PoolVec<(PoolStr, Variable)>, // 8B - pub unnamed: PoolVec, // 8B + pub names: PoolVec<(Option, Variable)>, // 8B + padding: [u8; 1], +} + +impl Rigids { + pub fn new( + named: HashMap<&str, Variable, BuildHasherDefault>, + unnamed: HashSet>, + pool: &mut Pool, + ) -> Self { + let names = PoolVec::with_capacity((named.len() + unnamed.len()) as u32, pool); + + let mut temp_names = Vec::new(); + + temp_names.extend(named.iter().map(|(name, var)| (Some(*name), *var))); + + temp_names.extend(unnamed.iter().map(|var| (None, *var))); + + for (node_id, (opt_name, variable)) in names.iter_node_ids().zip(temp_names) { + let poolstr = opt_name.map(|name| PoolStr::new(name, pool)); + + pool[node_id] = (poolstr, variable); + } + + Self { + names, + padding: Default::default(), + } + } + + pub fn named(&self, pool: &Pool) -> Vec<(PoolStr, Variable)> { + let mut named = Vec::new(); + + for node_id in self.names.iter_node_ids() { + let (opt_pool_str, var) = pool.get(node_id); + + if let Some(pool_str) = opt_pool_str { + named.push((*pool_str, *var)); + } + } + + named + } + + pub fn unnamed(&self, pool: &Pool) -> Vec { + let mut unnamed = Vec::new(); + + for node_id in self.names.iter_node_ids() { + let (opt_pool_str, var) = pool.get(node_id); + + if opt_pool_str.is_none() { + unnamed.push(*var); + } + } + + unnamed + } } /// This is overflow data from a Closure variant, which needs to store @@ -499,8 +558,8 @@ fn size_of_expr() { impl ShallowClone for Rigids { fn shallow_clone(&self) -> Self { Self { - named: self.named.shallow_clone(), - unnamed: self.unnamed.shallow_clone(), + names: self.names.shallow_clone(), + padding: self.padding, } } } diff --git a/editor/src/lang/def.rs b/editor/src/lang/def.rs index c9ae1bfc4a..84dfbb9ba6 100644 --- a/editor/src/lang/def.rs +++ b/editor/src/lang/def.rs @@ -318,23 +318,7 @@ fn from_pending_alias<'a>( } } - let named = PoolVec::with_capacity(named_rigids.len() as u32, env.pool); - let unnamed = PoolVec::with_capacity(unnamed_rigids.len() as u32, env.pool); - - for (node_id, (name, variable)) in named.iter_node_ids().zip(named_rigids) { - let poolstr = PoolStr::new(name, env.pool); - - env.pool[node_id] = (poolstr, variable); - } - - for (node_id, rigid) in unnamed.iter_node_ids().zip(unnamed_rigids) { - env.pool[node_id] = rigid; - } - - let rigids = Rigids { - named: named.shallow_clone(), - unnamed, - }; + let rigids = Rigids::new(named_rigids, unnamed_rigids, env.pool); let annotation = match signature { Signature::Value { annotation } => annotation, @@ -358,14 +342,20 @@ fn from_pending_alias<'a>( rec_type_union.substitute_alias(env.pool, symbol, Type2::Variable(rec_var)); let annotation_id = env.add(rec_type_union, ann.region); - scope.add_alias(env.pool, symbol, named, annotation_id); + let named = rigids.named(env.pool); + let named_pool_vec = PoolVec::new(named.into_iter(), env.pool); + + scope.add_alias(env.pool, symbol, named_pool_vec, annotation_id); } else { env.problem(Problem::CyclicAlias(symbol, name.region, vec![])); return output; } } else { let annotation_id = env.add(annotation, ann.region); - scope.add_alias(env.pool, symbol, named, annotation_id); + let named = rigids.named(env.pool); + let named_pool_vec = PoolVec::new(named.into_iter(), env.pool); + + scope.add_alias(env.pool, symbol, named_pool_vec, annotation_id); } output @@ -410,21 +400,7 @@ fn canonicalize_pending_def<'a>( output.references.referenced_aliases.insert(symbol); } - let rigids = { - let named = PoolVec::with_capacity(named_rigids.len() as u32, env.pool); - let unnamed = PoolVec::with_capacity(unnamed_rigids.len() as u32, env.pool); - - for (node_id, (name, variable)) in named.iter_node_ids().zip(named_rigids) { - let poolstr = PoolStr::new(name, env.pool); - env.pool[node_id] = (poolstr, variable); - } - - for (node_id, rigid) in unnamed.iter_node_ids().zip(unnamed_rigids) { - env.pool[node_id] = rigid; - } - - Rigids { named, unnamed } - }; + let rigids = Rigids::new(named_rigids, unnamed_rigids, env.pool); let annotation = match signature { Signature::Value { annotation } => annotation, @@ -473,21 +449,7 @@ fn canonicalize_pending_def<'a>( output.references.referenced_aliases.insert(symbol); } - let rigids = { - let named = PoolVec::with_capacity(named_rigids.len() as u32, env.pool); - let unnamed = PoolVec::with_capacity(unnamed_rigids.len() as u32, env.pool); - - for (node_id, (name, variable)) in named.iter_node_ids().zip(named_rigids) { - let poolstr = PoolStr::new(name, env.pool); - env.pool[node_id] = (poolstr, variable); - } - - for (node_id, rigid) in unnamed.iter_node_ids().zip(unnamed_rigids) { - env.pool[node_id] = rigid; - } - - Rigids { named, unnamed } - }; + let rigids = Rigids::new(named_rigids, unnamed_rigids, env.pool); // bookkeeping for tail-call detection. If we're assigning to an // identifier (e.g. `f = \x -> ...`), then this symbol can be tail-called. @@ -629,12 +591,9 @@ fn canonicalize_pending_def<'a>( let value_def = ValueDef::WithAnnotation { pattern_id: loc_can_pattern, - expr_id: PoolVec::new( - vec![env.pool.add(loc_can_expr)].into_iter(), - env.pool, - ), - type_id: PoolVec::new(vec![annotation].into_iter(), env.pool), - rigids: env.pool.add(rigids), + expr_id: env.pool.add(loc_can_expr), + type_id: annotation, + rigids: rigids, expr_var: env.var_store.fresh(), }; From d4da68e1d470cc91e3d6eb90e01e83c33afbf446 Mon Sep 17 00:00:00 2001 From: rvcas Date: Sun, 4 Jul 2021 15:58:59 -0400 Subject: [PATCH 27/30] feat: use filter_map --- editor/src/lang/ast.rs | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index b5fbd154cc..c1f9ca9bf5 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -347,29 +347,33 @@ impl Rigids { } pub fn named(&self, pool: &Pool) -> Vec<(PoolStr, Variable)> { - let mut named = Vec::new(); - - for node_id in self.names.iter_node_ids() { - let (opt_pool_str, var) = pool.get(node_id); - - if let Some(pool_str) = opt_pool_str { - named.push((*pool_str, *var)); - } - } + let named = self + .names + .iter(pool) + .filter_map(|(opt_pool_str, var)| { + if let Some(pool_str) = opt_pool_str { + Some((*pool_str, *var)) + } else { + None + } + }) + .collect(); named } pub fn unnamed(&self, pool: &Pool) -> Vec { - let mut unnamed = Vec::new(); - - for node_id in self.names.iter_node_ids() { - let (opt_pool_str, var) = pool.get(node_id); - - if opt_pool_str.is_none() { - unnamed.push(*var); - } - } + let unnamed = self + .names + .iter(pool) + .filter_map(|(opt_pool_str, var)| { + if opt_pool_str.is_none() { + Some(*var) + } else { + None + } + }) + .collect(); unnamed } From 1349da3f39c2948e93c30b1d172bfae1bff57cc9 Mon Sep 17 00:00:00 2001 From: rvcas Date: Sun, 4 Jul 2021 16:08:48 -0400 Subject: [PATCH 28/30] feat: return PoolVec directly, duplication seems inevitable --- editor/src/lang/ast.rs | 12 ++++++------ editor/src/lang/def.rs | 6 ++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index c1f9ca9bf5..4585b04ff4 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -346,7 +346,7 @@ impl Rigids { } } - pub fn named(&self, pool: &Pool) -> Vec<(PoolStr, Variable)> { + pub fn named(&self, pool: &mut Pool) -> PoolVec<(PoolStr, Variable)> { let named = self .names .iter(pool) @@ -357,12 +357,12 @@ impl Rigids { None } }) - .collect(); + .collect::>(); - named + PoolVec::new(named.into_iter(), pool) } - pub fn unnamed(&self, pool: &Pool) -> Vec { + pub fn unnamed(&self, pool: &mut Pool) -> PoolVec { let unnamed = self .names .iter(pool) @@ -373,9 +373,9 @@ impl Rigids { None } }) - .collect(); + .collect::>(); - unnamed + PoolVec::new(unnamed.into_iter(), pool) } } diff --git a/editor/src/lang/def.rs b/editor/src/lang/def.rs index 84dfbb9ba6..0cd3b25ba0 100644 --- a/editor/src/lang/def.rs +++ b/editor/src/lang/def.rs @@ -343,9 +343,8 @@ fn from_pending_alias<'a>( let annotation_id = env.add(rec_type_union, ann.region); let named = rigids.named(env.pool); - let named_pool_vec = PoolVec::new(named.into_iter(), env.pool); - scope.add_alias(env.pool, symbol, named_pool_vec, annotation_id); + scope.add_alias(env.pool, symbol, named, annotation_id); } else { env.problem(Problem::CyclicAlias(symbol, name.region, vec![])); return output; @@ -353,9 +352,8 @@ fn from_pending_alias<'a>( } else { let annotation_id = env.add(annotation, ann.region); let named = rigids.named(env.pool); - let named_pool_vec = PoolVec::new(named.into_iter(), env.pool); - scope.add_alias(env.pool, symbol, named_pool_vec, annotation_id); + scope.add_alias(env.pool, symbol, named, annotation_id); } output From 879bea2339d597757db53f5413498588600142df Mon Sep 17 00:00:00 2001 From: rvcas Date: Sun, 4 Jul 2021 16:16:50 -0400 Subject: [PATCH 29/30] chore: clippy is wrong :p --- editor/src/lang/ast.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/src/lang/ast.rs b/editor/src/lang/ast.rs index 4585b04ff4..d0d42ad1b6 100644 --- a/editor/src/lang/ast.rs +++ b/editor/src/lang/ast.rs @@ -320,6 +320,7 @@ pub struct Rigids { padding: [u8; 1], } +#[allow(clippy::needless_collect)] impl Rigids { pub fn new( named: HashMap<&str, Variable, BuildHasherDefault>, From eef740b51aa6496677f7bc2a21f58fa40508315d Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 5 Jul 2021 15:52:02 +0200 Subject: [PATCH 30/30] Voice command ideas --- editor/editor-ideas.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/editor/editor-ideas.md b/editor/editor-ideas.md index 547d120f05..1356c919ab 100644 --- a/editor/editor-ideas.md +++ b/editor/editor-ideas.md @@ -88,7 +88,27 @@ e.g. you have a test `calculate_sum_test` that only uses the function `add`, whe * Show edit history for this function. * Adjusting settings: switch to light theme, increase font size... * Use (context specific) voice command state machine to assist Machine Learning voice recognition model. -* Nice special use case: using voice to code while on treadmill desk. +* Nice special use case: using voice to code while on treadmill desk. +* Use word embeddings to find most similar voice command to recorded input in vector space. + +#### Useful voice commands + +* clear all breakpoints +* increase/decrease font size +* switch to dark/light/high-contrast mode +* open/go to file "Main"(fuzzy matching) +* go to function "foo" +* go to definition +* show all references(uses) of this function/type/... +* show history timeline of this function/file +* show recent projects +* generate unit test for this function +* generate unit test for this function based on debug trace (input and output is recorded and used in test) +* who wrote this line (git blame integration) +* search documentation of library X for Foo +* show example of how to use library function Foo +* open google/github/duckduckgo search for error... +* show editor plugins for library X #### Inspiration