Merge remote-tracking branch 'origin/trunk' into low-level-ops

This commit is contained in:
Richard Feldman 2020-07-07 21:02:03 -04:00
commit 1cd49689c2
29 changed files with 1630 additions and 440 deletions

View file

@ -10,7 +10,7 @@ use crate::pattern::{bindings_from_patterns, canonicalize_pattern, Pattern};
use crate::procedure::References;
use crate::scope::Scope;
use roc_collections::all::{default_hasher, ImMap, ImSet, MutMap, MutSet, SendMap};
use roc_module::ident::{Ident, Lowercase};
use roc_module::ident::Lowercase;
use roc_module::symbol::Symbol;
use roc_parse::ast;
use roc_parse::pattern::PatternType;
@ -41,9 +41,7 @@ pub struct Annotation {
#[derive(Debug)]
pub struct CanDefs {
// TODO don't store the Ident in here (lots of cloning!) - instead,
// make refs_by_symbol be something like MutMap<Symbol, (Region, References)>
pub refs_by_symbol: MutMap<Symbol, (Located<Ident>, References)>,
pub refs_by_symbol: MutMap<Symbol, (Region, References)>,
pub can_defs_by_symbol: MutMap<Symbol, Def>,
pub aliases: SendMap<Symbol, Alias>,
}
@ -79,7 +77,10 @@ enum PendingDef<'a> {
ann: &'a Located<ast::TypeAnnotation<'a>>,
},
ShadowedAlias,
/// An invalid alias, that is ignored in the rest of the pipeline
/// e.g. a shadowed alias, or a definition like `MyAlias 1 : Int`
/// with an incorrect pattern
InvalidAlias,
}
#[derive(Clone, Debug, PartialEq)]
@ -87,11 +88,8 @@ enum PendingDef<'a> {
pub enum Declaration {
Declare(Def),
DeclareRec(Vec<Def>),
InvalidCycle(
Vec<Located<Ident>>,
Vec<(Region /* pattern */, Region /* expr */)>,
),
Builtin(Def),
InvalidCycle(Vec<Symbol>, Vec<(Region /* pattern */, Region /* expr */)>),
}
impl Declaration {
@ -155,7 +153,7 @@ pub fn canonicalize_defs<'a>(
match iter.peek() {
Some(Located {
value: Body(body_pattern, body_expr),
..
region: body_region,
}) => {
if pattern.value.equivalent(&body_pattern.value) {
iter.next();
@ -169,8 +167,20 @@ pub fn canonicalize_defs<'a>(
&mut scope,
pattern_type,
)
} else if loc_def.region.lines_between(body_region) > 1 {
// there is a line of whitespace between the annotation and the body
// treat annotation and body separately
to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type)
} else {
panic!("TODO gracefully handle the case where a type annotation appears immediately before a body def, but the patterns are different. This should be an error; put a newline or comment between them!");
// the pattern of the annotation does not match the pattern of the body directly below it
env.problems.push(Problem::SignatureDefMismatch {
annotation_pattern: pattern.region,
def_pattern: body_pattern.region,
});
// both the annotation and definition are skipped!
iter.next();
continue;
}
}
_ => to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type),
@ -551,17 +561,18 @@ pub fn sort_can_defs(
if is_invalid_cycle {
// We want to show the entire cycle in the error message, so expand it out.
let mut loc_idents_in_cycle: Vec<Located<Ident>> = Vec::new();
let mut loc_symbols = Vec::new();
for symbol in cycle {
let refs = refs_by_symbol.get(&symbol).unwrap_or_else(|| {
panic!(
"Symbol not found in refs_by_symbol: {:?} - refs_by_symbol was: {:?}",
symbol, refs_by_symbol
)
});
loc_idents_in_cycle.push(refs.0.clone());
match refs_by_symbol.get(&symbol) {
None => unreachable!(
r#"Symbol `{:?}` not found in refs_by_symbol! refs_by_symbol was: {:?}"#,
symbol, refs_by_symbol
),
Some((region, _)) => {
loc_symbols.push(Located::at(*region, symbol));
}
}
}
let mut regions = Vec::with_capacity(can_defs_by_symbol.len());
@ -569,16 +580,19 @@ pub fn sort_can_defs(
regions.push((def.loc_pattern.region, def.loc_expr.region));
}
// Sort them to make the report more helpful.
loc_idents_in_cycle.sort();
// Sort them by line number to make the report more helpful.
loc_symbols.sort();
regions.sort();
let symbols_in_cycle: Vec<Symbol> =
loc_symbols.into_iter().map(|s| s.value).collect();
problems.push(Problem::RuntimeError(RuntimeError::CircularDef(
loc_idents_in_cycle.clone(),
symbols_in_cycle.clone(),
regions.clone(),
)));
declarations.push(Declaration::InvalidCycle(loc_idents_in_cycle, regions));
declarations.push(Declaration::InvalidCycle(symbols_in_cycle, regions));
} else {
// slightly inefficient, because we know this becomes exactly one DeclareRec already
group_to_declaration(
@ -711,6 +725,7 @@ fn pattern_to_vars_by_symbol(
| FloatLiteral(_)
| StrLiteral(_)
| Underscore
| MalformedPattern(_, _)
| UnsupportedPattern(_) => {}
Shadowed(_, _) => {}
@ -727,7 +742,7 @@ fn canonicalize_pending_def<'a>(
scope: &mut Scope,
can_defs_by_symbol: &mut MutMap<Symbol, Def>,
var_store: &mut VarStore,
refs_by_symbol: &mut MutMap<Symbol, (Located<Ident>, References)>,
refs_by_symbol: &mut MutMap<Symbol, (Region, References)>,
aliases: &mut SendMap<Symbol, Alias>,
) -> Output {
use PendingDef::*;
@ -893,9 +908,8 @@ fn canonicalize_pending_def<'a>(
.union(&can_ann.introduced_variables);
}
ShadowedAlias => {
// Since this alias was shadowed, it gets ignored and has no
// effect on the output.
InvalidAlias => {
// invalid aliases (shadowed, incorrect patterns) get ignored
}
TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr) => {
let ann =
@ -995,7 +1009,7 @@ fn canonicalize_pending_def<'a>(
// Store the referenced locals in the refs_by_symbol map, so we can later figure out
// which defined names reference each other.
for (ident, (symbol, region)) in scope.idents() {
for (_, (symbol, region)) in scope.idents() {
if !vars_by_symbol.contains_key(&symbol) {
continue;
}
@ -1010,16 +1024,7 @@ fn canonicalize_pending_def<'a>(
can_output.references.clone()
};
refs_by_symbol.insert(
*symbol,
(
Located {
value: ident.clone(),
region: *region,
},
refs,
),
);
refs_by_symbol.insert(*symbol, (*region, refs));
can_defs_by_symbol.insert(
*symbol,
@ -1140,23 +1145,7 @@ fn canonicalize_pending_def<'a>(
can_output.references.clone()
};
let ident = env
.ident_ids
.get_name(symbol.ident_id())
.unwrap_or_else(|| {
panic!("Could not find {:?} in env.ident_ids", symbol);
});
refs_by_symbol.insert(
symbol,
(
Located {
value: ident.clone().into(),
region,
},
refs,
),
);
refs_by_symbol.insert(symbol, (region, refs));
can_defs_by_symbol.insert(
symbol,
@ -1363,7 +1352,13 @@ fn to_pending_def<'a>(
});
}
_ => {
panic!("TODO gracefully handle an invalid pattern appearing where a type alias rigid var should be.");
// any other pattern in this position is a syntax error.
env.problems.push(Problem::InvalidAliasRigid {
alias_name: symbol,
region: loc_var.region,
});
return PendingDef::InvalidAlias;
}
}
}
@ -1384,7 +1379,7 @@ fn to_pending_def<'a>(
shadow: loc_shadowed_symbol,
});
PendingDef::ShadowedAlias
PendingDef::InvalidAlias
}
}
}