mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
commit
2cc8e95198
22 changed files with 569 additions and 437 deletions
|
@ -75,7 +75,7 @@ use crate::mem_pool::shallow_clone::ShallowClone;
|
||||||
// Ranks are used to limit the number of type variables considered for generalization. Only those inside
|
// Ranks are used to limit the number of type variables considered for generalization. Only those inside
|
||||||
// of the let (so those used in inferring the type of `\x -> x`) are considered.
|
// of the let (so those used in inferring the type of `\x -> x`) are considered.
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TypeError {
|
pub enum TypeError {
|
||||||
BadExpr(Region, Category, ErrorType, Expected<ErrorType>),
|
BadExpr(Region, Category, ErrorType, Expected<ErrorType>),
|
||||||
BadPattern(Region, PatternCategory, ErrorType, PExpected<ErrorType>),
|
BadPattern(Region, PatternCategory, ErrorType, PExpected<ErrorType>),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_collections::all::{ImMap, MutMap, MutSet, SendMap, VecSet};
|
use roc_collections::{ImMap, MutSet, SendMap, VecMap, VecSet};
|
||||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||||
use roc_parse::ast::{AssignedField, ExtractSpaces, Pattern, Tag, TypeAnnotation, TypeHeader};
|
use roc_parse::ast::{AssignedField, ExtractSpaces, Pattern, Tag, TypeAnnotation, TypeHeader};
|
||||||
|
@ -12,7 +12,7 @@ use roc_types::types::{
|
||||||
TypeExtension,
|
TypeExtension,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Annotation {
|
pub struct Annotation {
|
||||||
pub typ: Type,
|
pub typ: Type,
|
||||||
pub introduced_variables: IntroducedVariables,
|
pub introduced_variables: IntroducedVariables,
|
||||||
|
@ -68,14 +68,14 @@ pub struct AbleVariable {
|
||||||
pub first_seen: Region,
|
pub first_seen: Region,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct IntroducedVariables {
|
pub struct IntroducedVariables {
|
||||||
pub wildcards: Vec<Loc<Variable>>,
|
pub wildcards: Vec<Loc<Variable>>,
|
||||||
pub lambda_sets: Vec<Variable>,
|
pub lambda_sets: Vec<Variable>,
|
||||||
pub inferred: Vec<Loc<Variable>>,
|
pub inferred: Vec<Loc<Variable>>,
|
||||||
pub named: VecSet<NamedVariable>,
|
pub named: VecSet<NamedVariable>,
|
||||||
pub able: VecSet<AbleVariable>,
|
pub able: VecSet<AbleVariable>,
|
||||||
pub host_exposed_aliases: MutMap<Symbol, Variable>,
|
pub host_exposed_aliases: VecMap<Symbol, Variable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntroducedVariables {
|
impl IntroducedVariables {
|
||||||
|
@ -140,7 +140,7 @@ impl IntroducedVariables {
|
||||||
self.lambda_sets.extend(other.lambda_sets.iter().copied());
|
self.lambda_sets.extend(other.lambda_sets.iter().copied());
|
||||||
self.inferred.extend(other.inferred.iter().copied());
|
self.inferred.extend(other.inferred.iter().copied());
|
||||||
self.host_exposed_aliases
|
self.host_exposed_aliases
|
||||||
.extend(other.host_exposed_aliases.clone());
|
.extend(other.host_exposed_aliases.iter().map(|(k, v)| (*k, *v)));
|
||||||
|
|
||||||
self.named.extend(other.named.iter().cloned());
|
self.named.extend(other.named.iter().cloned());
|
||||||
self.able.extend(other.able.iter().cloned());
|
self.able.extend(other.able.iter().cloned());
|
||||||
|
|
|
@ -601,7 +601,7 @@ impl Constraints {
|
||||||
|
|
||||||
roc_error_macros::assert_sizeof_default!(Constraint, 3 * 8);
|
roc_error_macros::assert_sizeof_default!(Constraint, 3 * 8);
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone)]
|
||||||
pub enum Constraint {
|
pub enum Constraint {
|
||||||
Eq(
|
Eq(
|
||||||
EitherIndex<Type, Variable>,
|
EitherIndex<Type, Variable>,
|
||||||
|
@ -643,13 +643,13 @@ pub enum Constraint {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct DefTypes {
|
pub struct DefTypes {
|
||||||
pub types: Slice<Type>,
|
pub types: Slice<Type>,
|
||||||
pub loc_symbols: Slice<(Symbol, Region)>,
|
pub loc_symbols: Slice<(Symbol, Region)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LetConstraint {
|
pub struct LetConstraint {
|
||||||
pub rigid_vars: Slice<Variable>,
|
pub rigid_vars: Slice<Variable>,
|
||||||
pub flex_vars: Slice<Variable>,
|
pub flex_vars: Slice<Variable>,
|
||||||
|
@ -657,7 +657,7 @@ pub struct LetConstraint {
|
||||||
pub defs_and_ret_constraint: Index<(Constraint, Constraint)>,
|
pub defs_and_ret_constraint: Index<(Constraint, Constraint)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IncludesTag {
|
pub struct IncludesTag {
|
||||||
pub type_index: Index<Type>,
|
pub type_index: Index<Type>,
|
||||||
pub tag_name: TagName,
|
pub tag_name: TagName,
|
||||||
|
|
|
@ -9,8 +9,7 @@ use crate::pattern::{bindings_from_patterns, canonicalize_def_header_pattern, Pa
|
||||||
use crate::procedure::References;
|
use crate::procedure::References;
|
||||||
use crate::scope::create_alias;
|
use crate::scope::create_alias;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_collections::all::ImSet;
|
use roc_collections::{default_hasher, ImEntry, ImMap, ImSet, MutMap, MutSet, SendMap};
|
||||||
use roc_collections::all::{default_hasher, ImEntry, ImMap, MutMap, MutSet, SendMap};
|
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_parse::ast;
|
use roc_parse::ast;
|
||||||
|
@ -29,7 +28,7 @@ use std::collections::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use ven_graph::{strongly_connected_components, topological_sort};
|
use ven_graph::{strongly_connected_components, topological_sort};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Def {
|
pub struct Def {
|
||||||
pub loc_pattern: Loc<Pattern>,
|
pub loc_pattern: Loc<Pattern>,
|
||||||
pub loc_expr: Loc<Expr>,
|
pub loc_expr: Loc<Expr>,
|
||||||
|
@ -38,7 +37,7 @@ pub struct Def {
|
||||||
pub annotation: Option<Annotation>,
|
pub annotation: Option<Annotation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Annotation {
|
pub struct Annotation {
|
||||||
pub signature: Type,
|
pub signature: Type,
|
||||||
pub introduced_variables: IntroducedVariables,
|
pub introduced_variables: IntroducedVariables,
|
||||||
|
@ -56,7 +55,7 @@ pub struct CanDefs {
|
||||||
/// A Def that has had patterns and type annnotations canonicalized,
|
/// A Def that has had patterns and type annnotations canonicalized,
|
||||||
/// but no Expr canonicalization has happened yet. Also, it has had spaces
|
/// but no Expr canonicalization has happened yet. Also, it has had spaces
|
||||||
/// and nesting resolved, and knows whether annotations are standalone or not.
|
/// and nesting resolved, and knows whether annotations are standalone or not.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
enum PendingValueDef<'a> {
|
enum PendingValueDef<'a> {
|
||||||
/// A standalone annotation with no body
|
/// A standalone annotation with no body
|
||||||
AnnotationOnly(
|
AnnotationOnly(
|
||||||
|
@ -79,7 +78,7 @@ enum PendingValueDef<'a> {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
enum PendingTypeDef<'a> {
|
enum PendingTypeDef<'a> {
|
||||||
/// A structural or opaque type alias, e.g. `Ints : List Int` or `Age := U32` respectively.
|
/// A structural or opaque type alias, e.g. `Ints : List Int` or `Age := U32` respectively.
|
||||||
Alias {
|
Alias {
|
||||||
|
@ -97,6 +96,7 @@ enum PendingTypeDef<'a> {
|
||||||
/// An invalid alias, that is ignored in the rest of the pipeline
|
/// An invalid alias, that is ignored in the rest of the pipeline
|
||||||
/// e.g. a shadowed alias, or a definition like `MyAlias 1 : Int`
|
/// e.g. a shadowed alias, or a definition like `MyAlias 1 : Int`
|
||||||
/// with an incorrect pattern
|
/// with an incorrect pattern
|
||||||
|
#[allow(dead_code)]
|
||||||
InvalidAlias { kind: AliasKind },
|
InvalidAlias { kind: AliasKind },
|
||||||
|
|
||||||
/// An invalid ability, that is ignored in the rest of the pipeline.
|
/// An invalid ability, that is ignored in the rest of the pipeline.
|
||||||
|
@ -105,7 +105,7 @@ enum PendingTypeDef<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
pub enum Declaration {
|
pub enum Declaration {
|
||||||
Declare(Def),
|
Declare(Def),
|
||||||
|
@ -342,8 +342,7 @@ pub fn canonicalize_defs<'a>(
|
||||||
|
|
||||||
// Record all the annotation's references in output.references.lookups
|
// Record all the annotation's references in output.references.lookups
|
||||||
for symbol in can_ann.references {
|
for symbol in can_ann.references {
|
||||||
output.references.type_lookups.insert(symbol);
|
output.references.insert_type_lookup(symbol);
|
||||||
output.references.referenced_type_defs.insert(symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut can_vars: Vec<Loc<(Lowercase, Variable)>> = Vec::with_capacity(vars.len());
|
let mut can_vars: Vec<Loc<(Lowercase, Variable)>> = Vec::with_capacity(vars.len());
|
||||||
|
@ -453,8 +452,7 @@ pub fn canonicalize_defs<'a>(
|
||||||
|
|
||||||
// Record all the annotation's references in output.references.lookups
|
// Record all the annotation's references in output.references.lookups
|
||||||
for symbol in member_annot.references {
|
for symbol in member_annot.references {
|
||||||
output.references.type_lookups.insert(symbol);
|
output.references.insert_type_lookup(symbol);
|
||||||
output.references.referenced_type_defs.insert(symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let name_region = member.name.region;
|
let name_region = member.name.region;
|
||||||
|
@ -577,9 +575,17 @@ pub fn canonicalize_defs<'a>(
|
||||||
// once we've finished assembling the entire scope.
|
// once we've finished assembling the entire scope.
|
||||||
let mut pending_value_defs = Vec::with_capacity(value_defs.len());
|
let mut pending_value_defs = Vec::with_capacity(value_defs.len());
|
||||||
for loc_def in value_defs.into_iter() {
|
for loc_def in value_defs.into_iter() {
|
||||||
match to_pending_value_def(env, var_store, loc_def.value, &mut scope, pattern_type) {
|
let mut new_output = Output::default();
|
||||||
|
match to_pending_value_def(
|
||||||
|
env,
|
||||||
|
var_store,
|
||||||
|
loc_def.value,
|
||||||
|
&mut scope,
|
||||||
|
&mut new_output,
|
||||||
|
pattern_type,
|
||||||
|
) {
|
||||||
None => { /* skip */ }
|
None => { /* skip */ }
|
||||||
Some((new_output, pending_def)) => {
|
Some(pending_def) => {
|
||||||
// store the top-level defs, used to ensure that closures won't capture them
|
// store the top-level defs, used to ensure that closures won't capture them
|
||||||
if let PatternType::TopLevelDef = pattern_type {
|
if let PatternType::TopLevelDef = pattern_type {
|
||||||
match &pending_def {
|
match &pending_def {
|
||||||
|
@ -706,10 +712,10 @@ pub fn sort_can_defs(
|
||||||
let mut loc_succ = local_successors_with_duplicates(references, &env.closures);
|
let mut loc_succ = local_successors_with_duplicates(references, &env.closures);
|
||||||
|
|
||||||
// if the current symbol is a closure, peek into its body
|
// if the current symbol is a closure, peek into its body
|
||||||
if let Some(References { value_lookups, .. }) = env.closures.get(symbol) {
|
if let Some(references) = env.closures.get(symbol) {
|
||||||
let home = env.home;
|
let home = env.home;
|
||||||
|
|
||||||
for lookup in value_lookups.iter() {
|
for lookup in references.value_lookups() {
|
||||||
if lookup != symbol && lookup.module_id() == home {
|
if lookup != symbol && lookup.module_id() == home {
|
||||||
// DO NOT register a self-call behind a lambda!
|
// DO NOT register a self-call behind a lambda!
|
||||||
//
|
//
|
||||||
|
@ -759,8 +765,8 @@ pub fn sort_can_defs(
|
||||||
let mut loc_succ = local_successors_with_duplicates(references, &env.closures);
|
let mut loc_succ = local_successors_with_duplicates(references, &env.closures);
|
||||||
|
|
||||||
// if the current symbol is a closure, peek into its body
|
// if the current symbol is a closure, peek into its body
|
||||||
if let Some(References { value_lookups, .. }) = env.closures.get(symbol) {
|
if let Some(references) = env.closures.get(symbol) {
|
||||||
for lookup in value_lookups.iter() {
|
for lookup in references.value_lookups() {
|
||||||
loc_succ.push(*lookup);
|
loc_succ.push(*lookup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1182,8 +1188,7 @@ fn canonicalize_pending_value_def<'a>(
|
||||||
// Record all the annotation's references in output.references.lookups
|
// Record all the annotation's references in output.references.lookups
|
||||||
|
|
||||||
for symbol in type_annotation.references.iter() {
|
for symbol in type_annotation.references.iter() {
|
||||||
output.references.type_lookups.insert(*symbol);
|
output.references.insert_type_lookup(*symbol);
|
||||||
output.references.referenced_type_defs.insert(*symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_annotation_aliases(&type_annotation, aliases);
|
add_annotation_aliases(&type_annotation, aliases);
|
||||||
|
@ -1308,8 +1313,7 @@ fn canonicalize_pending_value_def<'a>(
|
||||||
|
|
||||||
// Record all the annotation's references in output.references.lookups
|
// Record all the annotation's references in output.references.lookups
|
||||||
for symbol in type_annotation.references.iter() {
|
for symbol in type_annotation.references.iter() {
|
||||||
output.references.type_lookups.insert(*symbol);
|
output.references.insert_type_lookup(*symbol);
|
||||||
output.references.referenced_type_defs.insert(*symbol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_annotation_aliases(&type_annotation, aliases);
|
add_annotation_aliases(&type_annotation, aliases);
|
||||||
|
@ -1388,7 +1392,7 @@ fn canonicalize_pending_value_def<'a>(
|
||||||
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
||||||
// would result in circular def errors!)
|
// would result in circular def errors!)
|
||||||
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
||||||
refs.value_lookups.remove(&symbol);
|
refs.remove_value_lookup(&symbol);
|
||||||
});
|
});
|
||||||
|
|
||||||
// renamed_closure_def = Some(&symbol);
|
// renamed_closure_def = Some(&symbol);
|
||||||
|
@ -1528,7 +1532,7 @@ fn canonicalize_pending_value_def<'a>(
|
||||||
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
||||||
// would result in circular def errors!)
|
// would result in circular def errors!)
|
||||||
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
||||||
refs.value_lookups.remove(&symbol);
|
refs.remove_value_lookup(&symbol);
|
||||||
});
|
});
|
||||||
|
|
||||||
loc_can_expr.value = Closure(ClosureData {
|
loc_can_expr.value = Closure(ClosureData {
|
||||||
|
@ -1623,8 +1627,7 @@ pub fn can_defs_with_return<'a>(
|
||||||
// Now that we've collected all the references, check to see if any of the new idents
|
// 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.
|
// we defined went unused by the return expression. If any were unused, report it.
|
||||||
for (symbol, region) in symbols_introduced {
|
for (symbol, region) in symbols_introduced {
|
||||||
if !output.references.has_value_lookup(symbol)
|
if !output.references.has_type_or_value_lookup(symbol)
|
||||||
&& !output.references.has_type_lookup(symbol)
|
|
||||||
&& !scope.abilities_store.is_specialization_name(symbol)
|
&& !scope.abilities_store.is_specialization_name(symbol)
|
||||||
{
|
{
|
||||||
env.problem(Problem::UnusedDef(symbol, region));
|
env.problem(Problem::UnusedDef(symbol, region));
|
||||||
|
@ -1672,7 +1675,7 @@ fn closure_recursivity(symbol: Symbol, closures: &MutMap<Symbol, References>) ->
|
||||||
let mut stack = Vec::new();
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
if let Some(references) = closures.get(&symbol) {
|
if let Some(references) = closures.get(&symbol) {
|
||||||
for v in references.calls.iter() {
|
for v in references.calls() {
|
||||||
stack.push(*v);
|
stack.push(*v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1688,7 +1691,7 @@ fn closure_recursivity(symbol: Symbol, closures: &MutMap<Symbol, References>) ->
|
||||||
// if it calls any functions
|
// if it calls any functions
|
||||||
if let Some(nested_references) = closures.get(&nested_symbol) {
|
if let Some(nested_references) = closures.get(&nested_symbol) {
|
||||||
// add its called to the stack
|
// add its called to the stack
|
||||||
for v in nested_references.calls.iter() {
|
for v in nested_references.calls() {
|
||||||
stack.push(*v);
|
stack.push(*v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1850,41 +1853,46 @@ fn to_pending_value_def<'a>(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
def: &'a ast::ValueDef<'a>,
|
def: &'a ast::ValueDef<'a>,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
output: &mut Output,
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
) -> Option<(Output, PendingValueDef<'a>)> {
|
) -> Option<PendingValueDef<'a>> {
|
||||||
use ast::ValueDef::*;
|
use ast::ValueDef::*;
|
||||||
|
|
||||||
match def {
|
match def {
|
||||||
Annotation(loc_pattern, loc_ann) => {
|
Annotation(loc_pattern, loc_ann) => {
|
||||||
// This takes care of checking for shadowing and adding idents to scope.
|
// This takes care of checking for shadowing and adding idents to scope.
|
||||||
let (output, loc_can_pattern) = canonicalize_def_header_pattern(
|
let loc_can_pattern = canonicalize_def_header_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
Some((
|
Some(PendingValueDef::AnnotationOnly(
|
||||||
output,
|
loc_pattern,
|
||||||
PendingValueDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann),
|
loc_can_pattern,
|
||||||
|
loc_ann,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Body(loc_pattern, loc_expr) => {
|
Body(loc_pattern, loc_expr) => {
|
||||||
// This takes care of checking for shadowing and adding idents to scope.
|
// This takes care of checking for shadowing and adding idents to scope.
|
||||||
let (output, loc_can_pattern) = canonicalize_def_header_pattern(
|
let loc_can_pattern = canonicalize_def_header_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
Some((
|
Some(PendingValueDef::Body(
|
||||||
output,
|
loc_pattern,
|
||||||
PendingValueDef::Body(loc_pattern, loc_can_pattern, loc_expr),
|
loc_can_pattern,
|
||||||
|
loc_expr,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1903,18 +1911,21 @@ fn to_pending_value_def<'a>(
|
||||||
// { x, y ? False } = rec
|
// { x, y ? False } = rec
|
||||||
//
|
//
|
||||||
// This takes care of checking for shadowing and adding idents to scope.
|
// This takes care of checking for shadowing and adding idents to scope.
|
||||||
let (output, loc_can_pattern) = canonicalize_def_header_pattern(
|
let loc_can_pattern = canonicalize_def_header_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&body_pattern.value,
|
&body_pattern.value,
|
||||||
body_pattern.region,
|
body_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
Some((
|
Some(PendingValueDef::TypedBody(
|
||||||
output,
|
body_pattern,
|
||||||
PendingValueDef::TypedBody(body_pattern, loc_can_pattern, ann_type, body_expr),
|
loc_can_pattern,
|
||||||
|
ann_type,
|
||||||
|
body_expr,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
// the pattern of the annotation does not match the pattern of the body direc
|
// the pattern of the annotation does not match the pattern of the body direc
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::env::Env;
|
||||||
use crate::expr::{ClosureData, Expr, Recursive};
|
use crate::expr::{ClosureData, Expr, Recursive};
|
||||||
use crate::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_collections::all::{SendMap, VecSet};
|
use roc_collections::{SendMap, VecSet};
|
||||||
use roc_module::called_via::CalledVia;
|
use roc_module::called_via::CalledVia;
|
||||||
use roc_module::ident::TagName;
|
use roc_module::ident::TagName;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::procedure::References;
|
use crate::procedure::References;
|
||||||
use roc_collections::all::{MutMap, VecSet};
|
use roc_collections::{MutMap, VecSet};
|
||||||
use roc_module::ident::{Ident, Lowercase, ModuleName};
|
use roc_module::ident::{Ident, Lowercase, ModuleName};
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||||
use roc_problem::can::{Problem, RuntimeError};
|
use roc_problem::can::{Problem, RuntimeError};
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::pattern::Pattern;
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::types::{AnnotationSource, PReason, Reason};
|
use roc_types::types::{AnnotationSource, PReason, Reason};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expected<T> {
|
pub enum Expected<T> {
|
||||||
NoExpectation(T),
|
NoExpectation(T),
|
||||||
FromAnnotation(Loc<Pattern>, usize, AnnotationSource, T),
|
FromAnnotation(Loc<Pattern>, usize, AnnotationSource, T),
|
||||||
|
@ -10,7 +10,7 @@ pub enum Expected<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like Expected, but for Patterns.
|
/// Like Expected, but for Patterns.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PExpected<T> {
|
pub enum PExpected<T> {
|
||||||
NoExpectation(T),
|
NoExpectation(T),
|
||||||
ForReason(PReason, T, Region),
|
ForReason(PReason, T, Region),
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::num::{
|
||||||
use crate::pattern::{canonicalize_pattern, Pattern};
|
use crate::pattern::{canonicalize_pattern, Pattern};
|
||||||
use crate::procedure::References;
|
use crate::procedure::References;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_collections::all::{MutMap, MutSet, SendMap, VecSet};
|
use roc_collections::{MutMap, MutSet, SendMap, VecMap, VecSet};
|
||||||
use roc_module::called_via::CalledVia;
|
use roc_module::called_via::CalledVia;
|
||||||
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
|
@ -23,12 +23,12 @@ use roc_types::types::{Alias, LambdaSet, Type};
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
use std::{char, u32};
|
use std::{char, u32};
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug, PartialEq)]
|
#[derive(Clone, Default, Debug)]
|
||||||
pub struct Output {
|
pub struct Output {
|
||||||
pub references: References,
|
pub references: References,
|
||||||
pub tail_call: Option<Symbol>,
|
pub tail_call: Option<Symbol>,
|
||||||
pub introduced_variables: IntroducedVariables,
|
pub introduced_variables: IntroducedVariables,
|
||||||
pub aliases: SendMap<Symbol, Alias>,
|
pub aliases: VecMap<Symbol, Alias>,
|
||||||
pub non_closures: VecSet<Symbol>,
|
pub non_closures: VecSet<Symbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ impl Display for IntValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
// Literals
|
// Literals
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ pub enum Expr {
|
||||||
// Compiles, but will crash if reached
|
// Compiles, but will crash if reached
|
||||||
RuntimeError(RuntimeError),
|
RuntimeError(RuntimeError),
|
||||||
}
|
}
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ClosureData {
|
pub struct ClosureData {
|
||||||
pub function_type: Variable,
|
pub function_type: Variable,
|
||||||
pub closure_type: Variable,
|
pub closure_type: Variable,
|
||||||
|
@ -271,7 +271,7 @@ impl AccessorData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
pub var: Variable,
|
pub var: Variable,
|
||||||
// The region of the full `foo: f bar`, rather than just `f bar`
|
// The region of the full `foo: f bar`, rather than just `f bar`
|
||||||
|
@ -286,7 +286,7 @@ pub enum Recursive {
|
||||||
TailRecursive = 2,
|
TailRecursive = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct WhenBranch {
|
pub struct WhenBranch {
|
||||||
pub patterns: Vec<Loc<Pattern>>,
|
pub patterns: Vec<Loc<Pattern>>,
|
||||||
pub value: Loc<Expr>,
|
pub value: Loc<Expr>,
|
||||||
|
@ -487,8 +487,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
}
|
}
|
||||||
Ok((name, opaque_def)) => {
|
Ok((name, opaque_def)) => {
|
||||||
let argument = Box::new(args.pop().unwrap());
|
let argument = Box::new(args.pop().unwrap());
|
||||||
output.references.referenced_type_defs.insert(name);
|
output.references.insert_type_lookup(name);
|
||||||
output.references.type_lookups.insert(name);
|
|
||||||
|
|
||||||
let (type_arguments, lambda_set_variables, specialized_def_type) =
|
let (type_arguments, lambda_set_variables, specialized_def_type) =
|
||||||
freshen_opaque_def(var_store, opaque_def);
|
freshen_opaque_def(var_store, opaque_def);
|
||||||
|
@ -518,7 +517,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
|
|
||||||
let expr = match fn_expr.value {
|
let expr = match fn_expr.value {
|
||||||
Var(symbol) => {
|
Var(symbol) => {
|
||||||
output.references.calls.insert(symbol);
|
output.references.insert_call(symbol);
|
||||||
|
|
||||||
// we're tail-calling a symbol by name, check if it's the tail-callable symbol
|
// we're tail-calling a symbol by name, check if it's the tail-callable symbol
|
||||||
output.tail_call = match &env.tailcallable_symbol {
|
output.tail_call = match &env.tailcallable_symbol {
|
||||||
|
@ -628,26 +627,23 @@ pub fn canonicalize_expr<'a>(
|
||||||
let mut can_args = Vec::with_capacity(loc_arg_patterns.len());
|
let mut can_args = Vec::with_capacity(loc_arg_patterns.len());
|
||||||
let mut output = Output::default();
|
let mut output = Output::default();
|
||||||
|
|
||||||
let mut bound_by_argument_patterns = MutSet::default();
|
|
||||||
|
|
||||||
for loc_pattern in loc_arg_patterns.iter() {
|
for loc_pattern in loc_arg_patterns.iter() {
|
||||||
let (new_output, can_arg) = canonicalize_pattern(
|
let can_argument_pattern = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
|
&mut output,
|
||||||
FunctionArg,
|
FunctionArg,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
bound_by_argument_patterns
|
can_args.push((var_store.fresh(), can_argument_pattern));
|
||||||
.extend(new_output.references.bound_symbols.iter().copied());
|
|
||||||
|
|
||||||
output.union(new_output);
|
|
||||||
|
|
||||||
can_args.push((var_store.fresh(), can_arg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let bound_by_argument_patterns: Vec<_> =
|
||||||
|
output.references.bound_symbols().copied().collect();
|
||||||
|
|
||||||
let (loc_body_expr, new_output) = canonicalize_expr(
|
let (loc_body_expr, new_output) = canonicalize_expr(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
|
@ -656,18 +652,14 @@ pub fn canonicalize_expr<'a>(
|
||||||
&loc_body_expr.value,
|
&loc_body_expr.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut captured_symbols: MutSet<Symbol> = new_output
|
let mut captured_symbols: MutSet<Symbol> =
|
||||||
.references
|
new_output.references.value_lookups().copied().collect();
|
||||||
.value_lookups
|
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// filter out the closure's name itself
|
// filter out the closure's name itself
|
||||||
captured_symbols.remove(&symbol);
|
captured_symbols.remove(&symbol);
|
||||||
|
|
||||||
// symbols bound either in this pattern or deeper down are not captured!
|
// symbols bound either in this pattern or deeper down are not captured!
|
||||||
captured_symbols.retain(|s| !new_output.references.bound_symbols.contains(s));
|
captured_symbols.retain(|s| !new_output.references.bound_symbols().any(|x| x == s));
|
||||||
captured_symbols.retain(|s| !bound_by_argument_patterns.contains(s));
|
captured_symbols.retain(|s| !bound_by_argument_patterns.contains(s));
|
||||||
|
|
||||||
// filter out top-level symbols
|
// filter out top-level symbols
|
||||||
|
@ -685,7 +677,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
// filter out aliases
|
// filter out aliases
|
||||||
debug_assert!(captured_symbols
|
debug_assert!(captured_symbols
|
||||||
.iter()
|
.iter()
|
||||||
.all(|s| !output.references.referenced_type_defs.contains(s)));
|
.all(|s| !output.references.references_type_def(*s)));
|
||||||
// captured_symbols.retain(|s| !output.references.referenced_type_defs.contains(s));
|
// captured_symbols.retain(|s| !output.references.referenced_type_defs.contains(s));
|
||||||
|
|
||||||
// filter out functions that don't close over anything
|
// filter out functions that don't close over anything
|
||||||
|
@ -703,7 +695,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
// We shouldn't ultimately count arguments as referenced locals. Otherwise,
|
// We shouldn't ultimately count arguments as referenced locals. Otherwise,
|
||||||
// we end up with weird conclusions like the expression (\x -> x + 1)
|
// we end up with weird conclusions like the expression (\x -> x + 1)
|
||||||
// references the (nonexistent) local variable x!
|
// references the (nonexistent) local variable x!
|
||||||
output.references.value_lookups.remove(sub_symbol);
|
output.references.remove_value_lookup(sub_symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1040,17 +1032,16 @@ fn canonicalize_when_branch<'a>(
|
||||||
|
|
||||||
// TODO report symbols not bound in all patterns
|
// TODO report symbols not bound in all patterns
|
||||||
for loc_pattern in branch.patterns.iter() {
|
for loc_pattern in branch.patterns.iter() {
|
||||||
let (new_output, can_pattern) = canonicalize_pattern(
|
let can_pattern = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
|
output,
|
||||||
WhenBranch,
|
WhenBranch,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
output.union(new_output);
|
|
||||||
|
|
||||||
patterns.push(can_pattern);
|
patterns.push(can_pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1078,10 +1069,8 @@ fn canonicalize_when_branch<'a>(
|
||||||
for (symbol, region) in scope.symbols() {
|
for (symbol, region) in scope.symbols() {
|
||||||
let symbol = *symbol;
|
let symbol = *symbol;
|
||||||
|
|
||||||
if !output.references.has_value_lookup(symbol)
|
if !output.references.has_type_or_value_lookup(symbol)
|
||||||
&& !output.references.has_type_lookup(symbol)
|
&& !branch_output.references.has_type_or_value_lookup(symbol)
|
||||||
&& !branch_output.references.has_value_lookup(symbol)
|
|
||||||
&& !branch_output.references.has_type_lookup(symbol)
|
|
||||||
&& !original_scope.contains_symbol(symbol)
|
&& !original_scope.contains_symbol(symbol)
|
||||||
&& !scope.abilities_store.is_specialization_name(symbol)
|
&& !scope.abilities_store.is_specialization_name(symbol)
|
||||||
{
|
{
|
||||||
|
@ -1106,9 +1095,9 @@ pub fn local_successors_with_duplicates<'a>(
|
||||||
references: &'a References,
|
references: &'a References,
|
||||||
closures: &'a MutMap<Symbol, References>,
|
closures: &'a MutMap<Symbol, References>,
|
||||||
) -> Vec<Symbol> {
|
) -> Vec<Symbol> {
|
||||||
let mut answer: Vec<_> = references.value_lookups.iter().copied().collect();
|
let mut answer: Vec<_> = references.value_lookups().copied().collect();
|
||||||
|
|
||||||
let mut stack: Vec<_> = references.calls.iter().copied().collect();
|
let mut stack: Vec<_> = references.calls().copied().collect();
|
||||||
let mut seen = Vec::new();
|
let mut seen = Vec::new();
|
||||||
|
|
||||||
while let Some(symbol) = stack.pop() {
|
while let Some(symbol) = stack.pop() {
|
||||||
|
@ -1117,8 +1106,8 @@ pub fn local_successors_with_duplicates<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(references) = closures.get(&symbol) {
|
if let Some(references) = closures.get(&symbol) {
|
||||||
answer.extend(references.value_lookups.iter().copied());
|
answer.extend(references.value_lookups().copied());
|
||||||
stack.extend(references.calls.iter().copied());
|
stack.extend(references.calls().copied());
|
||||||
|
|
||||||
seen.push(symbol);
|
seen.push(symbol);
|
||||||
}
|
}
|
||||||
|
@ -1255,7 +1244,7 @@ fn canonicalize_var_lookup(
|
||||||
// Look it up in scope!
|
// Look it up in scope!
|
||||||
match scope.lookup(&(*ident).into(), region) {
|
match scope.lookup(&(*ident).into(), region) {
|
||||||
Ok(symbol) => {
|
Ok(symbol) => {
|
||||||
output.references.value_lookups.insert(symbol);
|
output.references.insert_value_lookup(symbol);
|
||||||
|
|
||||||
Var(symbol)
|
Var(symbol)
|
||||||
}
|
}
|
||||||
|
@ -1270,7 +1259,7 @@ fn canonicalize_var_lookup(
|
||||||
// Look it up in the env!
|
// Look it up in the env!
|
||||||
match env.qualified_lookup(module_name, ident, region) {
|
match env.qualified_lookup(module_name, ident, region) {
|
||||||
Ok(symbol) => {
|
Ok(symbol) => {
|
||||||
output.references.value_lookups.insert(symbol);
|
output.references.insert_value_lookup(symbol);
|
||||||
|
|
||||||
Var(symbol)
|
Var(symbol)
|
||||||
}
|
}
|
||||||
|
@ -1726,7 +1715,7 @@ fn flatten_str_lines<'a>(
|
||||||
Interpolated(loc_expr) => {
|
Interpolated(loc_expr) => {
|
||||||
if is_valid_interpolation(loc_expr.value) {
|
if is_valid_interpolation(loc_expr.value) {
|
||||||
// Interpolations desugar to Str.concat calls
|
// Interpolations desugar to Str.concat calls
|
||||||
output.references.calls.insert(Symbol::STR_CONCAT);
|
output.references.insert_call(Symbol::STR_CONCAT);
|
||||||
|
|
||||||
if !buf.is_empty() {
|
if !buf.is_empty() {
|
||||||
segments.push(StrSegment::Plaintext(buf.into()));
|
segments.push(StrSegment::Plaintext(buf.into()));
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::operator::desugar_def;
|
||||||
use crate::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_collections::all::{MutMap, SendMap, VecSet};
|
use roc_collections::{MutMap, SendMap, VecSet};
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_module::ident::{Ident, TagName};
|
use roc_module::ident::{Ident, TagName};
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||||
|
@ -302,8 +302,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
// See if any of the new idents we defined went unused.
|
// See if any of the new idents we defined went unused.
|
||||||
// If any were unused and also not exposed, report it.
|
// If any were unused and also not exposed, report it.
|
||||||
for (symbol, region) in symbols_introduced {
|
for (symbol, region) in symbols_introduced {
|
||||||
if !output.references.has_value_lookup(symbol)
|
if !output.references.has_type_or_value_lookup(symbol)
|
||||||
&& !output.references.has_type_lookup(symbol)
|
|
||||||
&& !exposed_symbols.contains(&symbol)
|
&& !exposed_symbols.contains(&symbol)
|
||||||
&& !scope.abilities_store.is_specialization_name(symbol)
|
&& !scope.abilities_store.is_specialization_name(symbol)
|
||||||
{
|
{
|
||||||
|
@ -329,11 +328,11 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
let mut referenced_types = VecSet::default();
|
let mut referenced_types = VecSet::default();
|
||||||
|
|
||||||
// Gather up all the symbols that were referenced across all the defs' lookups.
|
// Gather up all the symbols that were referenced across all the defs' lookups.
|
||||||
referenced_values.extend(output.references.value_lookups);
|
referenced_values.extend(output.references.value_lookups().copied());
|
||||||
referenced_types.extend(output.references.type_lookups);
|
referenced_types.extend(output.references.type_lookups().copied());
|
||||||
|
|
||||||
// Gather up all the symbols that were referenced across all the defs' calls.
|
// Gather up all the symbols that were referenced across all the defs' calls.
|
||||||
referenced_values.extend(output.references.calls);
|
referenced_values.extend(output.references.calls().copied());
|
||||||
|
|
||||||
// Gather up all the symbols that were referenced from other modules.
|
// Gather up all the symbols that were referenced from other modules.
|
||||||
referenced_values.extend(env.qualified_value_lookups.iter().copied());
|
referenced_values.extend(env.qualified_value_lookups.iter().copied());
|
||||||
|
@ -528,11 +527,11 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Incorporate any remaining output.lookups entries into references.
|
// Incorporate any remaining output.lookups entries into references.
|
||||||
referenced_values.extend(output.references.value_lookups);
|
referenced_values.extend(output.references.value_lookups().copied());
|
||||||
referenced_types.extend(output.references.type_lookups);
|
referenced_types.extend(output.references.type_lookups().copied());
|
||||||
|
|
||||||
// Incorporate any remaining output.calls entries into references.
|
// Incorporate any remaining output.calls entries into references.
|
||||||
referenced_values.extend(output.references.calls);
|
referenced_values.extend(output.references.calls().copied());
|
||||||
|
|
||||||
// Gather up all the symbols that were referenced from other modules.
|
// Gather up all the symbols that were referenced from other modules.
|
||||||
referenced_values.extend(env.qualified_value_lookups.iter().copied());
|
referenced_values.extend(env.qualified_value_lookups.iter().copied());
|
||||||
|
|
|
@ -17,7 +17,7 @@ use roc_types::types::{LambdaSet, Type};
|
||||||
|
|
||||||
/// A pattern, including possible problems (e.g. shadowing) so that
|
/// A pattern, including possible problems (e.g. shadowing) so that
|
||||||
/// codegen can generate a runtime error if this pattern is reached.
|
/// codegen can generate a runtime error if this pattern is reached.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Identifier(Symbol),
|
Identifier(Symbol),
|
||||||
AppliedTag {
|
AppliedTag {
|
||||||
|
@ -82,7 +82,7 @@ pub enum Pattern {
|
||||||
MalformedPattern(MalformedPatternProblem, Region),
|
MalformedPattern(MalformedPatternProblem, Region),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RecordDestruct {
|
pub struct RecordDestruct {
|
||||||
pub var: Variable,
|
pub var: Variable,
|
||||||
pub label: Lowercase,
|
pub label: Lowercase,
|
||||||
|
@ -90,7 +90,7 @@ pub struct RecordDestruct {
|
||||||
pub typ: DestructType,
|
pub typ: DestructType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum DestructType {
|
pub enum DestructType {
|
||||||
Required,
|
Required,
|
||||||
Optional(Variable, Loc<Expr>),
|
Optional(Variable, Loc<Expr>),
|
||||||
|
@ -156,13 +156,13 @@ pub fn canonicalize_def_header_pattern<'a>(
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
output: &mut Output,
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
pattern: &ast::Pattern<'a>,
|
pattern: &ast::Pattern<'a>,
|
||||||
region: Region,
|
region: Region,
|
||||||
) -> (Output, Loc<Pattern>) {
|
) -> Loc<Pattern> {
|
||||||
use roc_parse::ast::Pattern::*;
|
use roc_parse::ast::Pattern::*;
|
||||||
|
|
||||||
let mut output = Output::default();
|
|
||||||
match pattern {
|
match pattern {
|
||||||
// Identifiers that shadow ability members may appear (and may only appear) at the header of a def.
|
// Identifiers that shadow ability members may appear (and may only appear) at the header of a def.
|
||||||
Identifier(name) => match scope.introduce_or_shadow_ability_member(
|
Identifier(name) => match scope.introduce_or_shadow_ability_member(
|
||||||
|
@ -172,7 +172,7 @@ pub fn canonicalize_def_header_pattern<'a>(
|
||||||
region,
|
region,
|
||||||
) {
|
) {
|
||||||
Ok((symbol, shadowing_ability_member)) => {
|
Ok((symbol, shadowing_ability_member)) => {
|
||||||
output.references.bound_symbols.insert(symbol);
|
output.references.insert_bound(symbol);
|
||||||
let can_pattern = match shadowing_ability_member {
|
let can_pattern = match shadowing_ability_member {
|
||||||
// A fresh identifier.
|
// A fresh identifier.
|
||||||
None => Pattern::Identifier(symbol),
|
None => Pattern::Identifier(symbol),
|
||||||
|
@ -182,7 +182,7 @@ pub fn canonicalize_def_header_pattern<'a>(
|
||||||
specializes: ability_member_name,
|
specializes: ability_member_name,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
(output, Loc::at(region, can_pattern))
|
Loc::at(region, can_pattern)
|
||||||
}
|
}
|
||||||
Err((original_region, shadow, new_symbol)) => {
|
Err((original_region, shadow, new_symbol)) => {
|
||||||
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
env.problem(Problem::RuntimeError(RuntimeError::Shadowing {
|
||||||
|
@ -190,13 +190,13 @@ pub fn canonicalize_def_header_pattern<'a>(
|
||||||
shadow: shadow.clone(),
|
shadow: shadow.clone(),
|
||||||
kind: ShadowKind::Variable,
|
kind: ShadowKind::Variable,
|
||||||
}));
|
}));
|
||||||
output.references.bound_symbols.insert(new_symbol);
|
output.references.insert_bound(new_symbol);
|
||||||
|
|
||||||
let can_pattern = Pattern::Shadowed(original_region, shadow, new_symbol);
|
let can_pattern = Pattern::Shadowed(original_region, shadow, new_symbol);
|
||||||
(output, Loc::at(region, can_pattern))
|
Loc::at(region, can_pattern)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => canonicalize_pattern(env, var_store, scope, pattern_type, pattern, region),
|
_ => canonicalize_pattern(env, var_store, scope, output, pattern_type, pattern, region),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,14 +204,14 @@ pub fn canonicalize_pattern<'a>(
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
output: &mut Output,
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
pattern: &ast::Pattern<'a>,
|
pattern: &ast::Pattern<'a>,
|
||||||
region: Region,
|
region: Region,
|
||||||
) -> (Output, Loc<Pattern>) {
|
) -> Loc<Pattern> {
|
||||||
use roc_parse::ast::Pattern::*;
|
use roc_parse::ast::Pattern::*;
|
||||||
use PatternType::*;
|
use PatternType::*;
|
||||||
|
|
||||||
let mut output = Output::default();
|
|
||||||
let can_pattern = match pattern {
|
let can_pattern = match pattern {
|
||||||
Identifier(name) => match scope.introduce(
|
Identifier(name) => match scope.introduce(
|
||||||
(*name).into(),
|
(*name).into(),
|
||||||
|
@ -220,7 +220,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
region,
|
region,
|
||||||
) {
|
) {
|
||||||
Ok(symbol) => {
|
Ok(symbol) => {
|
||||||
output.references.bound_symbols.insert(symbol);
|
output.references.insert_bound(symbol);
|
||||||
|
|
||||||
Pattern::Identifier(symbol)
|
Pattern::Identifier(symbol)
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
shadow: shadow.clone(),
|
shadow: shadow.clone(),
|
||||||
kind: ShadowKind::Variable,
|
kind: ShadowKind::Variable,
|
||||||
}));
|
}));
|
||||||
output.references.bound_symbols.insert(new_symbol);
|
output.references.insert_bound(new_symbol);
|
||||||
|
|
||||||
Pattern::Shadowed(original_region, shadow, new_symbol)
|
Pattern::Shadowed(original_region, shadow, new_symbol)
|
||||||
}
|
}
|
||||||
|
@ -266,17 +266,16 @@ pub fn canonicalize_pattern<'a>(
|
||||||
Apply(tag, patterns) => {
|
Apply(tag, patterns) => {
|
||||||
let mut can_patterns = Vec::with_capacity(patterns.len());
|
let mut can_patterns = Vec::with_capacity(patterns.len());
|
||||||
for loc_pattern in *patterns {
|
for loc_pattern in *patterns {
|
||||||
let (new_output, can_pattern) = canonicalize_pattern(
|
let can_pattern = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
output.union(new_output);
|
|
||||||
|
|
||||||
can_patterns.push((var_store.fresh(), can_pattern));
|
can_patterns.push((var_store.fresh(), can_pattern));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,8 +317,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
let (type_arguments, lambda_set_variables, specialized_def_type) =
|
let (type_arguments, lambda_set_variables, specialized_def_type) =
|
||||||
freshen_opaque_def(var_store, opaque_def);
|
freshen_opaque_def(var_store, opaque_def);
|
||||||
|
|
||||||
output.references.referenced_type_defs.insert(opaque);
|
output.references.insert_type_lookup(opaque);
|
||||||
output.references.type_lookups.insert(opaque);
|
|
||||||
|
|
||||||
Pattern::UnwrappedOpaque {
|
Pattern::UnwrappedOpaque {
|
||||||
whole_var: var_store.fresh(),
|
whole_var: var_store.fresh(),
|
||||||
|
@ -443,7 +441,15 @@ pub fn canonicalize_pattern<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
SpaceBefore(sub_pattern, _) | SpaceAfter(sub_pattern, _) => {
|
SpaceBefore(sub_pattern, _) | SpaceAfter(sub_pattern, _) => {
|
||||||
return canonicalize_pattern(env, var_store, scope, pattern_type, sub_pattern, region)
|
return canonicalize_pattern(
|
||||||
|
env,
|
||||||
|
var_store,
|
||||||
|
scope,
|
||||||
|
output,
|
||||||
|
pattern_type,
|
||||||
|
sub_pattern,
|
||||||
|
region,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
RecordDestructure(patterns) => {
|
RecordDestructure(patterns) => {
|
||||||
let ext_var = var_store.fresh();
|
let ext_var = var_store.fresh();
|
||||||
|
@ -461,7 +467,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
region,
|
region,
|
||||||
) {
|
) {
|
||||||
Ok(symbol) => {
|
Ok(symbol) => {
|
||||||
output.references.bound_symbols.insert(symbol);
|
output.references.insert_bound(symbol);
|
||||||
|
|
||||||
destructs.push(Loc {
|
destructs.push(Loc {
|
||||||
region: loc_pattern.region,
|
region: loc_pattern.region,
|
||||||
|
@ -493,17 +499,16 @@ pub fn canonicalize_pattern<'a>(
|
||||||
RequiredField(label, loc_guard) => {
|
RequiredField(label, loc_guard) => {
|
||||||
// a guard does not introduce the label into scope!
|
// a guard does not introduce the label into scope!
|
||||||
let symbol = scope.ignore(label.into(), &mut env.ident_ids);
|
let symbol = scope.ignore(label.into(), &mut env.ident_ids);
|
||||||
let (new_output, can_guard) = canonicalize_pattern(
|
let can_guard = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
|
output,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
&loc_guard.value,
|
&loc_guard.value,
|
||||||
loc_guard.region,
|
loc_guard.region,
|
||||||
);
|
);
|
||||||
|
|
||||||
output.union(new_output);
|
|
||||||
|
|
||||||
destructs.push(Loc {
|
destructs.push(Loc {
|
||||||
region: loc_pattern.region,
|
region: loc_pattern.region,
|
||||||
value: RecordDestruct {
|
value: RecordDestruct {
|
||||||
|
@ -532,7 +537,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
// an optional field binds the symbol!
|
// an optional field binds the symbol!
|
||||||
output.references.bound_symbols.insert(symbol);
|
output.references.insert_bound(symbol);
|
||||||
|
|
||||||
output.union(expr_output);
|
output.union(expr_output);
|
||||||
|
|
||||||
|
@ -598,13 +603,10 @@ pub fn canonicalize_pattern<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
Loc {
|
||||||
output,
|
region,
|
||||||
Loc {
|
value: can_pattern,
|
||||||
region,
|
}
|
||||||
value: can_pattern,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
|
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::expr::Expr;
|
use crate::expr::Expr;
|
||||||
use crate::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use roc_collections::all::VecSet;
|
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::Variable;
|
use roc_types::subs::Variable;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Procedure {
|
pub struct Procedure {
|
||||||
pub name: Option<Box<str>>,
|
pub name: Option<Box<str>>,
|
||||||
pub is_self_tail_recursive: bool,
|
pub is_self_tail_recursive: bool,
|
||||||
|
@ -39,40 +38,147 @@ impl Procedure {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// These are all ordered sets because they end up getting traversed in a graph search
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
/// to determine how defs should be ordered. We want builds to be reproducible,
|
struct ReferencesBitflags(u8);
|
||||||
/// so it's important that building the same code gives the same order every time!
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
impl ReferencesBitflags {
|
||||||
|
const VALUE_LOOKUP: Self = ReferencesBitflags(1);
|
||||||
|
const TYPE_LOOKUP: Self = ReferencesBitflags(2);
|
||||||
|
const CALL: Self = ReferencesBitflags(4);
|
||||||
|
const BOUND: Self = ReferencesBitflags(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct References {
|
pub struct References {
|
||||||
pub bound_symbols: VecSet<Symbol>,
|
symbols: Vec<Symbol>,
|
||||||
pub type_lookups: VecSet<Symbol>,
|
bitflags: Vec<ReferencesBitflags>,
|
||||||
pub value_lookups: VecSet<Symbol>,
|
|
||||||
/// Aliases or opaque types referenced
|
|
||||||
pub referenced_type_defs: VecSet<Symbol>,
|
|
||||||
pub calls: VecSet<Symbol>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl References {
|
impl References {
|
||||||
pub fn new() -> References {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn union_mut(&mut self, other: &References) {
|
pub fn union_mut(&mut self, other: &Self) {
|
||||||
self.value_lookups
|
for (k, v) in other.symbols.iter().zip(other.bitflags.iter()) {
|
||||||
.extend(other.value_lookups.iter().copied());
|
self.insert(*k, *v);
|
||||||
self.type_lookups.extend(other.type_lookups.iter().copied());
|
}
|
||||||
self.calls.extend(other.calls.iter().copied());
|
|
||||||
self.bound_symbols
|
|
||||||
.extend(other.bound_symbols.iter().copied());
|
|
||||||
self.referenced_type_defs
|
|
||||||
.extend(other.referenced_type_defs.iter().copied());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// iterators
|
||||||
|
|
||||||
|
fn retain<'a, P: Fn(&'a ReferencesBitflags) -> bool>(
|
||||||
|
&'a self,
|
||||||
|
pred: P,
|
||||||
|
) -> impl Iterator<Item = &'a Symbol> {
|
||||||
|
self.symbols
|
||||||
|
.iter()
|
||||||
|
.zip(self.bitflags.iter())
|
||||||
|
.filter_map(move |(a, b)| if pred(b) { Some(a) } else { None })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_lookups(&self) -> impl Iterator<Item = &Symbol> {
|
||||||
|
self.retain(|b| b.0 & ReferencesBitflags::VALUE_LOOKUP.0 > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_lookups(&self) -> impl Iterator<Item = &Symbol> {
|
||||||
|
self.retain(|b| b.0 & ReferencesBitflags::TYPE_LOOKUP.0 > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bound_symbols(&self) -> impl Iterator<Item = &Symbol> {
|
||||||
|
self.retain(|b| b.0 & ReferencesBitflags::BOUND.0 > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calls(&self) -> impl Iterator<Item = &Symbol> {
|
||||||
|
self.retain(|b| b.0 & ReferencesBitflags::CALL.0 > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert
|
||||||
|
|
||||||
|
fn insert(&mut self, symbol: Symbol, flags: ReferencesBitflags) {
|
||||||
|
match self.symbols.iter().position(|x| *x == symbol) {
|
||||||
|
None => {
|
||||||
|
self.symbols.push(symbol);
|
||||||
|
self.bitflags.push(flags);
|
||||||
|
}
|
||||||
|
Some(index) => {
|
||||||
|
// idea: put some debug_asserts in here?
|
||||||
|
self.bitflags[index].0 |= flags.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_value_lookup(&mut self, symbol: Symbol) {
|
||||||
|
self.insert(symbol, ReferencesBitflags::VALUE_LOOKUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_type_lookup(&mut self, symbol: Symbol) {
|
||||||
|
self.insert(symbol, ReferencesBitflags::TYPE_LOOKUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_bound(&mut self, symbol: Symbol) {
|
||||||
|
self.insert(symbol, ReferencesBitflags::BOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_call(&mut self, symbol: Symbol) {
|
||||||
|
self.insert(symbol, ReferencesBitflags::CALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove
|
||||||
|
|
||||||
|
pub fn remove_value_lookup(&mut self, symbol: &Symbol) {
|
||||||
|
match self.symbols.iter().position(|x| x == symbol) {
|
||||||
|
None => {
|
||||||
|
// it's not in there; do nothing
|
||||||
|
}
|
||||||
|
Some(index) => {
|
||||||
|
// idea: put some debug_asserts in here?
|
||||||
|
self.bitflags[index].0 ^= ReferencesBitflags::VALUE_LOOKUP.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// contains
|
||||||
|
|
||||||
pub fn has_value_lookup(&self, symbol: Symbol) -> bool {
|
pub fn has_value_lookup(&self, symbol: Symbol) -> bool {
|
||||||
self.value_lookups.contains(&symbol)
|
// println!("has a value lookup? {} {:?}", self.symbols.len(), symbol);
|
||||||
|
let it = self.symbols.iter().zip(self.bitflags.iter());
|
||||||
|
|
||||||
|
for (a, b) in it {
|
||||||
|
if *a == symbol && b.0 & ReferencesBitflags::VALUE_LOOKUP.0 > 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_type_lookup(&self, symbol: Symbol) -> bool {
|
fn has_type_lookup(&self, symbol: Symbol) -> bool {
|
||||||
self.type_lookups.contains(&symbol)
|
let it = self.symbols.iter().zip(self.bitflags.iter());
|
||||||
|
|
||||||
|
for (a, b) in it {
|
||||||
|
if *a == symbol && b.0 & ReferencesBitflags::TYPE_LOOKUP.0 > 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_type_or_value_lookup(&self, symbol: Symbol) -> bool {
|
||||||
|
let mask = ReferencesBitflags::VALUE_LOOKUP.0 | ReferencesBitflags::TYPE_LOOKUP.0;
|
||||||
|
let it = self.symbols.iter().zip(self.bitflags.iter());
|
||||||
|
|
||||||
|
for (a, b) in it {
|
||||||
|
if *a == symbol && b.0 & mask > 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn references_type_def(&self, symbol: Symbol) -> bool {
|
||||||
|
self.has_type_lookup(symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
#[macro_use]
|
|
||||||
extern crate pretty_assertions;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate indoc;
|
|
||||||
|
|
||||||
extern crate bumpalo;
|
|
||||||
extern crate roc_can;
|
|
||||||
extern crate roc_parse;
|
|
||||||
extern crate roc_region;
|
|
||||||
|
|
||||||
mod helpers;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod can_inline {
|
|
||||||
use crate::helpers::{can_expr_with, test_home};
|
|
||||||
use bumpalo::Bump;
|
|
||||||
use roc_can::expr::inline_calls;
|
|
||||||
use roc_can::expr::Expr::{self, *};
|
|
||||||
use roc_can::scope::Scope;
|
|
||||||
use roc_types::subs::VarStore;
|
|
||||||
|
|
||||||
fn assert_inlines_to(input: &str, expected: Expr, var_store: &mut VarStore) {
|
|
||||||
let arena = Bump::new();
|
|
||||||
let scope = &mut Scope::new(test_home(), var_store);
|
|
||||||
let actual_out = can_expr_with(&arena, test_home(), input);
|
|
||||||
let actual = inline_calls(var_store, scope, actual_out.loc_expr.value);
|
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn inline_empty_record() {
|
|
||||||
// fn inline_list_len() {
|
|
||||||
let var_store = &mut VarStore::default();
|
|
||||||
|
|
||||||
assert_inlines_to(
|
|
||||||
indoc!(
|
|
||||||
r#"
|
|
||||||
{}
|
|
||||||
"#
|
|
||||||
),
|
|
||||||
EmptyRecord,
|
|
||||||
var_store,
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO testing with hardcoded variables is very brittle.
|
|
||||||
// Should find a better way to test this!
|
|
||||||
// (One idea would be to traverse both Exprs and zero out all the Variables,
|
|
||||||
// so they always pass equality.)
|
|
||||||
// let aliases = SendMap::default();
|
|
||||||
// assert_inlines_to(
|
|
||||||
// indoc!(
|
|
||||||
// r#"
|
|
||||||
// Int.isZero 5
|
|
||||||
// "#
|
|
||||||
// ),
|
|
||||||
// LetNonRec(
|
|
||||||
// Box::new(Def {
|
|
||||||
// loc_pattern: Located {
|
|
||||||
// region: Region::zero(),
|
|
||||||
// value: Pattern::Identifier(Symbol::ARG_1),
|
|
||||||
// },
|
|
||||||
// pattern_vars: SendMap::default(),
|
|
||||||
// loc_expr: Located {
|
|
||||||
// region: Region::new(0, 0, 11, 12),
|
|
||||||
// value: Num(unsafe { Variable::unsafe_test_debug_variable(7) }, 5),
|
|
||||||
// },
|
|
||||||
// expr_var: unsafe { Variable::unsafe_test_debug_variable(8) },
|
|
||||||
// annotation: None,
|
|
||||||
// }),
|
|
||||||
// Box::new(Located {
|
|
||||||
// region: Region::zero(),
|
|
||||||
// value: Expr::Call(
|
|
||||||
// Box::new((
|
|
||||||
// unsafe { Variable::unsafe_test_debug_variable(138) },
|
|
||||||
// Located {
|
|
||||||
// region: Region::zero(),
|
|
||||||
// value: Expr::Var(Symbol::BOOL_EQ),
|
|
||||||
// },
|
|
||||||
// unsafe { Variable::unsafe_test_debug_variable(139) },
|
|
||||||
// )),
|
|
||||||
// vec![
|
|
||||||
// (
|
|
||||||
// unsafe { Variable::unsafe_test_debug_variable(140) },
|
|
||||||
// Located {
|
|
||||||
// region: Region::zero(),
|
|
||||||
// value: Var(Symbol::ARG_1),
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// (
|
|
||||||
// unsafe { Variable::unsafe_test_debug_variable(141) },
|
|
||||||
// Located {
|
|
||||||
// region: Region::zero(),
|
|
||||||
// value: Int(
|
|
||||||
// unsafe { Variable::unsafe_test_debug_variable(137) },
|
|
||||||
// 0,
|
|
||||||
// ),
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// CalledVia::Space,
|
|
||||||
// ),
|
|
||||||
// }),
|
|
||||||
// unsafe { Variable::unsafe_test_debug_variable(198) },
|
|
||||||
// aliases,
|
|
||||||
// ),
|
|
||||||
// var_store,
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -20,11 +20,32 @@ mod test_can {
|
||||||
use roc_region::all::{Position, Region};
|
use roc_region::all::{Position, Region};
|
||||||
use std::{f64, i64};
|
use std::{f64, i64};
|
||||||
|
|
||||||
fn assert_can(input: &str, expected: Expr) {
|
fn assert_can_runtime_error(input: &str, expected: RuntimeError) {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
let actual_out = can_expr_with(&arena, test_home(), input);
|
let actual_out = can_expr_with(&arena, test_home(), input);
|
||||||
|
|
||||||
assert_eq!(actual_out.loc_expr.value, expected);
|
match actual_out.loc_expr.value {
|
||||||
|
Expr::RuntimeError(actual) => {
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
}
|
||||||
|
actual => {
|
||||||
|
panic!("Expected a Float, but got: {:?}", actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_can_string(input: &str, expected: &str) {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let actual_out = can_expr_with(&arena, test_home(), input);
|
||||||
|
|
||||||
|
match actual_out.loc_expr.value {
|
||||||
|
Expr::Str(actual) => {
|
||||||
|
assert_eq!(expected, &*actual);
|
||||||
|
}
|
||||||
|
actual => {
|
||||||
|
panic!("Expected a Float, but got: {:?}", actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_can_float(input: &str, expected: f64) {
|
fn assert_can_float(input: &str, expected: f64) {
|
||||||
|
@ -69,10 +90,6 @@ mod test_can {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_str(contents: &str) -> Expr {
|
|
||||||
Expr::Str(contents.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
// NUMBER LITERALS
|
// NUMBER LITERALS
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -81,14 +98,14 @@ mod test_can {
|
||||||
|
|
||||||
let string = "340_282_366_920_938_463_463_374_607_431_768_211_456".to_string();
|
let string = "340_282_366_920_938_463_463_374_607_431_768_211_456".to_string();
|
||||||
|
|
||||||
assert_can(
|
assert_can_runtime_error(
|
||||||
&string.clone(),
|
&string.clone(),
|
||||||
RuntimeError(RuntimeError::InvalidInt(
|
RuntimeError::InvalidInt(
|
||||||
IntErrorKind::Overflow,
|
IntErrorKind::Overflow,
|
||||||
Base::Decimal,
|
Base::Decimal,
|
||||||
Region::zero(),
|
Region::zero(),
|
||||||
string.into_boxed_str(),
|
string.into_boxed_str(),
|
||||||
)),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,14 +115,14 @@ mod test_can {
|
||||||
|
|
||||||
let string = "-170_141_183_460_469_231_731_687_303_715_884_105_729".to_string();
|
let string = "-170_141_183_460_469_231_731_687_303_715_884_105_729".to_string();
|
||||||
|
|
||||||
assert_can(
|
assert_can_runtime_error(
|
||||||
&string.clone(),
|
&string.clone(),
|
||||||
RuntimeError(RuntimeError::InvalidInt(
|
RuntimeError::InvalidInt(
|
||||||
IntErrorKind::Underflow,
|
IntErrorKind::Underflow,
|
||||||
Base::Decimal,
|
Base::Decimal,
|
||||||
Region::zero(),
|
Region::zero(),
|
||||||
string.into(),
|
string.into(),
|
||||||
)),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,13 +131,9 @@ mod test_can {
|
||||||
let string = format!("{}1.0", f64::MAX);
|
let string = format!("{}1.0", f64::MAX);
|
||||||
let region = Region::zero();
|
let region = Region::zero();
|
||||||
|
|
||||||
assert_can(
|
assert_can_runtime_error(
|
||||||
&string.clone(),
|
&string.clone(),
|
||||||
RuntimeError(RuntimeError::InvalidFloat(
|
RuntimeError::InvalidFloat(FloatErrorKind::PositiveInfinity, region, string.into()),
|
||||||
FloatErrorKind::PositiveInfinity,
|
|
||||||
region,
|
|
||||||
string.into(),
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,13 +142,9 @@ mod test_can {
|
||||||
let string = format!("{}1.0", f64::MIN);
|
let string = format!("{}1.0", f64::MIN);
|
||||||
let region = Region::zero();
|
let region = Region::zero();
|
||||||
|
|
||||||
assert_can(
|
assert_can_runtime_error(
|
||||||
&string.clone(),
|
&string.clone(),
|
||||||
RuntimeError(RuntimeError::InvalidFloat(
|
RuntimeError::InvalidFloat(FloatErrorKind::NegativeInfinity, region, string.into()),
|
||||||
FloatErrorKind::NegativeInfinity,
|
|
||||||
region,
|
|
||||||
string.into(),
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,13 +153,9 @@ mod test_can {
|
||||||
let string = "1.1.1";
|
let string = "1.1.1";
|
||||||
let region = Region::zero();
|
let region = Region::zero();
|
||||||
|
|
||||||
assert_can(
|
assert_can_runtime_error(
|
||||||
string.clone(),
|
string.clone(),
|
||||||
RuntimeError(RuntimeError::InvalidFloat(
|
RuntimeError::InvalidFloat(FloatErrorKind::Error, region, string.into()),
|
||||||
FloatErrorKind::Error,
|
|
||||||
region,
|
|
||||||
string.into(),
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1582,27 +1587,27 @@ mod test_can {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_with_valid_unicode_escapes() {
|
fn string_with_valid_unicode_escapes() {
|
||||||
assert_can(r#""x\u(00A0)x""#, expr_str("x\u{00A0}x"));
|
assert_can_string(r#""x\u(00A0)x""#, "x\u{00A0}x");
|
||||||
assert_can(r#""x\u(101010)x""#, expr_str("x\u{101010}x"));
|
assert_can_string(r#""x\u(101010)x""#, "x\u{101010}x");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn block_string() {
|
fn block_string() {
|
||||||
assert_can(
|
assert_can_string(
|
||||||
r#"
|
r#"
|
||||||
"""foobar"""
|
"""foobar"""
|
||||||
"#,
|
"#,
|
||||||
expr_str("foobar"),
|
"foobar",
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_can(
|
assert_can_string(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
"""foo
|
"""foo
|
||||||
bar"""
|
bar"""
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
expr_str("foo\nbar"),
|
"foo\nbar",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,99 +220,3 @@ macro_rules! mut_map {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct VecSet<T> {
|
|
||||||
elements: Vec<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for VecSet<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
elements: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PartialEq> VecSet<T> {
|
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
elements: Vec::with_capacity(capacity),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.elements.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.elements.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn swap_remove(&mut self, index: usize) -> T {
|
|
||||||
self.elements.swap_remove(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, value: T) -> bool {
|
|
||||||
if self.elements.contains(&value) {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
self.elements.push(value);
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn contains(&self, value: &T) -> bool {
|
|
||||||
self.elements.contains(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove(&mut self, value: &T) {
|
|
||||||
match self.elements.iter().position(|x| x == value) {
|
|
||||||
None => {
|
|
||||||
// just do nothing
|
|
||||||
}
|
|
||||||
Some(index) => {
|
|
||||||
self.elements.swap_remove(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
|
||||||
self.elements.iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Ord> Extend<A> for VecSet<A> {
|
|
||||||
fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
|
|
||||||
let it = iter.into_iter();
|
|
||||||
let hint = it.size_hint();
|
|
||||||
|
|
||||||
match hint {
|
|
||||||
(0, Some(0)) => {
|
|
||||||
// done, do nothing
|
|
||||||
}
|
|
||||||
(1, Some(1)) | (2, Some(2)) => {
|
|
||||||
for value in it {
|
|
||||||
self.insert(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.elements.extend(it);
|
|
||||||
|
|
||||||
self.elements.sort();
|
|
||||||
self.elements.dedup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> IntoIterator for VecSet<T> {
|
|
||||||
type Item = T;
|
|
||||||
|
|
||||||
type IntoIter = std::vec::IntoIter<T>;
|
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
self.elements.into_iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,3 +4,9 @@
|
||||||
|
|
||||||
pub mod all;
|
pub mod all;
|
||||||
pub mod soa;
|
pub mod soa;
|
||||||
|
mod vec_map;
|
||||||
|
mod vec_set;
|
||||||
|
|
||||||
|
pub use all::{default_hasher, BumpMap, ImEntry, ImMap, ImSet, MutMap, MutSet, SendMap};
|
||||||
|
pub use vec_map::VecMap;
|
||||||
|
pub use vec_set::VecSet;
|
||||||
|
|
133
compiler/collections/src/vec_map.rs
Normal file
133
compiler/collections/src/vec_map.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct VecMap<K, V> {
|
||||||
|
keys: Vec<K>,
|
||||||
|
values: Vec<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> Default for VecMap<K, V> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
keys: Vec::new(),
|
||||||
|
values: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: PartialEq, V> VecMap<K, V> {
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
keys: Vec::with_capacity(capacity),
|
||||||
|
values: Vec::with_capacity(capacity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
debug_assert_eq!(self.keys.len(), self.values.len());
|
||||||
|
self.keys.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
debug_assert_eq!(self.keys.len(), self.values.len());
|
||||||
|
self.keys.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn swap_remove(&mut self, index: usize) -> (K, V) {
|
||||||
|
let k = self.keys.swap_remove(index);
|
||||||
|
let v = self.values.swap_remove(index);
|
||||||
|
|
||||||
|
(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, key: K, mut value: V) -> Option<V> {
|
||||||
|
match self.keys.iter().position(|x| x == &key) {
|
||||||
|
Some(index) => {
|
||||||
|
std::mem::swap(&mut value, &mut self.values[index]);
|
||||||
|
|
||||||
|
Some(value)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.keys.push(key);
|
||||||
|
self.values.push(value);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, key: &K) -> bool {
|
||||||
|
self.keys.contains(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, key: &K) {
|
||||||
|
match self.keys.iter().position(|x| x == key) {
|
||||||
|
None => {
|
||||||
|
// just do nothing
|
||||||
|
}
|
||||||
|
Some(index) => {
|
||||||
|
self.swap_remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
|
||||||
|
self.keys.iter().zip(self.values.iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn values(&self) -> impl Iterator<Item = &V> {
|
||||||
|
self.values.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Ord, V> Extend<(K, V)> for VecMap<K, V> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
|
||||||
|
let it = iter.into_iter();
|
||||||
|
let hint = it.size_hint();
|
||||||
|
|
||||||
|
match hint {
|
||||||
|
(0, Some(0)) => {
|
||||||
|
// done, do nothing
|
||||||
|
}
|
||||||
|
(1, Some(1)) | (2, Some(2)) => {
|
||||||
|
for (k, v) in it {
|
||||||
|
self.insert(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(_min, _opt_max) => {
|
||||||
|
// TODO do this with sorting and dedup?
|
||||||
|
for (k, v) in it {
|
||||||
|
self.insert(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> IntoIterator for VecMap<K, V> {
|
||||||
|
type Item = (K, V);
|
||||||
|
|
||||||
|
type IntoIter = IntoIter<K, V>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
IntoIter {
|
||||||
|
keys: self.keys.into_iter(),
|
||||||
|
values: self.values.into_iter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IntoIter<K, V> {
|
||||||
|
keys: std::vec::IntoIter<K>,
|
||||||
|
values: std::vec::IntoIter<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> Iterator for IntoIter<K, V> {
|
||||||
|
type Item = (K, V);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match (self.keys.next(), self.values.next()) {
|
||||||
|
(Some(k), Some(v)) => Some((k, v)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
compiler/collections/src/vec_set.rs
Normal file
95
compiler/collections/src/vec_set.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct VecSet<T> {
|
||||||
|
elements: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for VecSet<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
elements: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq> VecSet<T> {
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
elements: Vec::with_capacity(capacity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.elements.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.elements.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn swap_remove(&mut self, index: usize) -> T {
|
||||||
|
self.elements.swap_remove(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, value: T) -> bool {
|
||||||
|
if self.elements.contains(&value) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.elements.push(value);
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, value: &T) -> bool {
|
||||||
|
self.elements.contains(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, value: &T) {
|
||||||
|
match self.elements.iter().position(|x| x == value) {
|
||||||
|
None => {
|
||||||
|
// just do nothing
|
||||||
|
}
|
||||||
|
Some(index) => {
|
||||||
|
self.elements.swap_remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||||
|
self.elements.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord> Extend<A> for VecSet<A> {
|
||||||
|
fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
|
||||||
|
let it = iter.into_iter();
|
||||||
|
let hint = it.size_hint();
|
||||||
|
|
||||||
|
match hint {
|
||||||
|
(0, Some(0)) => {
|
||||||
|
// done, do nothing
|
||||||
|
}
|
||||||
|
(1, Some(1)) | (2, Some(2)) => {
|
||||||
|
for value in it {
|
||||||
|
self.insert(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.elements.extend(it);
|
||||||
|
|
||||||
|
self.elements.sort();
|
||||||
|
self.elements.dedup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoIterator for VecSet<T> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
type IntoIter = std::vec::IntoIter<T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.elements.into_iter()
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ use roc_can::abilities::AbilitiesStore;
|
||||||
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
|
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
|
||||||
use roc_can::def::Declaration;
|
use roc_can::def::Declaration;
|
||||||
use roc_can::module::{canonicalize_module_defs, Module};
|
use roc_can::module::{canonicalize_module_defs, Module};
|
||||||
use roc_collections::all::{default_hasher, BumpMap, MutMap, MutSet, VecSet};
|
use roc_collections::{default_hasher, BumpMap, MutMap, MutSet, VecSet};
|
||||||
use roc_constrain::module::{
|
use roc_constrain::module::{
|
||||||
constrain_builtin_imports, constrain_module, ExposedByModule, ExposedForModule,
|
constrain_builtin_imports, constrain_module, ExposedByModule, ExposedForModule,
|
||||||
ExposedModuleTypes,
|
ExposedModuleTypes,
|
||||||
|
|
|
@ -112,13 +112,11 @@ mod test_load {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert!(loaded_module
|
||||||
loaded_module
|
.type_problems
|
||||||
.type_problems
|
.remove(&home)
|
||||||
.remove(&home)
|
.unwrap_or_default()
|
||||||
.unwrap_or_default(),
|
.is_empty(),);
|
||||||
Vec::new()
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(loaded_module)
|
Ok(loaded_module)
|
||||||
}
|
}
|
||||||
|
@ -208,13 +206,11 @@ mod test_load {
|
||||||
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
||||||
Vec::new()
|
Vec::new()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert!(loaded_module
|
||||||
loaded_module
|
.type_problems
|
||||||
.type_problems
|
.remove(&home)
|
||||||
.remove(&home)
|
.unwrap_or_default()
|
||||||
.unwrap_or_default(),
|
.is_empty());
|
||||||
Vec::new()
|
|
||||||
);
|
|
||||||
|
|
||||||
let expected_name = loaded_module
|
let expected_name = loaded_module
|
||||||
.interns
|
.interns
|
||||||
|
@ -261,13 +257,11 @@ mod test_load {
|
||||||
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
||||||
Vec::new()
|
Vec::new()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert!(loaded_module
|
||||||
loaded_module
|
.type_problems
|
||||||
.type_problems
|
.remove(&home)
|
||||||
.remove(&home)
|
.unwrap_or_default()
|
||||||
.unwrap_or_default(),
|
.is_empty());
|
||||||
Vec::new()
|
|
||||||
);
|
|
||||||
|
|
||||||
for decl in loaded_module.declarations_by_id.remove(&home).unwrap() {
|
for decl in loaded_module.declarations_by_id.remove(&home).unwrap() {
|
||||||
match decl {
|
match decl {
|
||||||
|
@ -365,13 +359,11 @@ mod test_load {
|
||||||
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
loaded_module.can_problems.remove(&home).unwrap_or_default(),
|
||||||
Vec::new()
|
Vec::new()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert!(loaded_module
|
||||||
loaded_module
|
.type_problems
|
||||||
.type_problems
|
.remove(&home)
|
||||||
.remove(&home)
|
.unwrap_or_default()
|
||||||
.unwrap_or_default(),
|
.is_empty(),);
|
||||||
Vec::new()
|
|
||||||
);
|
|
||||||
|
|
||||||
let def_count: usize = loaded_module
|
let def_count: usize = loaded_module
|
||||||
.declarations_by_id
|
.declarations_by_id
|
||||||
|
|
|
@ -108,7 +108,7 @@ pub struct EntryPoint<'a> {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct PartialProcId(usize);
|
pub struct PartialProcId(usize);
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PartialProcs<'a> {
|
pub struct PartialProcs<'a> {
|
||||||
/// maps a function name (symbol) to an index
|
/// maps a function name (symbol) to an index
|
||||||
symbols: Vec<'a, Symbol>,
|
symbols: Vec<'a, Symbol>,
|
||||||
|
@ -190,7 +190,7 @@ impl<'a> PartialProcs<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PartialProc<'a> {
|
pub struct PartialProc<'a> {
|
||||||
pub annotation: Variable,
|
pub annotation: Variable,
|
||||||
pub pattern_symbols: &'a [Symbol],
|
pub pattern_symbols: &'a [Symbol],
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub struct IncompleteAbilityImplementation {
|
||||||
pub missing_members: Vec<Loc<Symbol>>,
|
pub missing_members: Vec<Loc<Symbol>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TypeError {
|
pub enum TypeError {
|
||||||
BadExpr(Region, Category, ErrorType, Expected<ErrorType>),
|
BadExpr(Region, Category, ErrorType, Expected<ErrorType>),
|
||||||
BadPattern(Region, PatternCategory, ErrorType, PExpected<ErrorType>),
|
BadPattern(Region, PatternCategory, ErrorType, PExpected<ErrorType>),
|
||||||
|
|
|
@ -129,7 +129,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
||||||
println!("Ignoring {} canonicalization problems", can_problems.len());
|
println!("Ignoring {} canonicalization problems", can_problems.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(type_problems, Vec::new());
|
assert!(type_problems.is_empty());
|
||||||
assert_eq!(mono_problems, Vec::new());
|
assert_eq!(mono_problems, Vec::new());
|
||||||
|
|
||||||
debug_assert_eq!(exposed_to_host.values.len(), 1);
|
debug_assert_eq!(exposed_to_host.values.len(), 1);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue