mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 08:17:40 +03:00
Merge remote-tracking branch 'origin/trunk' into fix-module-constraints
This commit is contained in:
commit
8eb91807e4
@ -6,9 +6,10 @@ use crate::can::scope::Scope;
|
||||
use crate::collections::{default_hasher, ImMap, MutMap, MutSet, SendMap};
|
||||
use crate::module::symbol::Symbol;
|
||||
use crate::parse::ast::{AssignedField, Tag, TypeAnnotation};
|
||||
use crate::region::Located;
|
||||
use crate::region::Region;
|
||||
use crate::subs::{VarStore, Variable};
|
||||
use crate::types::{Problem, Type};
|
||||
use crate::types::{Alias, Problem, Type};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@ -17,6 +18,7 @@ pub struct Annotation {
|
||||
pub ftv: MutMap<Variable, Lowercase>,
|
||||
pub rigids: ImMap<Lowercase, Variable>,
|
||||
pub references: MutSet<Symbol>,
|
||||
pub aliases: SendMap<Symbol, Alias>,
|
||||
}
|
||||
|
||||
pub fn canonicalize_annotation(
|
||||
@ -37,21 +39,17 @@ pub fn canonicalize_annotation(
|
||||
// but a variable can only have one name. Therefore
|
||||
// `ftv : SendMap<Variable, Lowercase>`.
|
||||
let mut rigids = ImMap::default();
|
||||
let mut local_aliases = Vec::new();
|
||||
let (mut typ, references) = can_annotation_help(
|
||||
let mut aliases = SendMap::default();
|
||||
let (typ, references) = can_annotation_help(
|
||||
env,
|
||||
annotation,
|
||||
region,
|
||||
scope,
|
||||
var_store,
|
||||
&mut rigids,
|
||||
&mut local_aliases,
|
||||
&mut aliases,
|
||||
);
|
||||
|
||||
for (symbol, tipe) in local_aliases {
|
||||
typ.substitute_alias(symbol, &tipe);
|
||||
}
|
||||
|
||||
let mut ftv = MutMap::default();
|
||||
|
||||
for (k, v) in rigids.clone() {
|
||||
@ -63,6 +61,7 @@ pub fn canonicalize_annotation(
|
||||
ftv,
|
||||
references,
|
||||
rigids,
|
||||
aliases,
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,8 +72,8 @@ fn can_annotation_help(
|
||||
scope: &mut Scope,
|
||||
var_store: &VarStore,
|
||||
rigids: &mut ImMap<Lowercase, Variable>,
|
||||
local_aliases: &mut Vec<(Symbol, crate::types::Type)>,
|
||||
) -> (crate::types::Type, MutSet<Symbol>) {
|
||||
local_aliases: &mut SendMap<Symbol, Alias>,
|
||||
) -> (Type, MutSet<Symbol>) {
|
||||
use crate::parse::ast::TypeAnnotation::*;
|
||||
|
||||
match annotation {
|
||||
@ -166,41 +165,7 @@ fn can_annotation_help(
|
||||
args.push(arg_ann);
|
||||
}
|
||||
|
||||
if let Some(alias) = scope.lookup_alias(symbol) {
|
||||
let ftv = &alias.vars;
|
||||
let actual = &alias.typ;
|
||||
|
||||
if args.len() != ftv.len() {
|
||||
panic!("TODO alias applied to incorrect number of type arguments");
|
||||
}
|
||||
let mut zipped_args: Vec<(Lowercase, Type)> = Vec::with_capacity(args.len());
|
||||
let mut substitution = ImMap::default();
|
||||
|
||||
for (loc_var, arg) in ftv.iter().zip(args.iter()) {
|
||||
substitution.insert(loc_var.value.1, arg.clone());
|
||||
zipped_args.push((loc_var.value.0.clone(), arg.clone()));
|
||||
}
|
||||
|
||||
let mut instantiated = actual.clone();
|
||||
instantiated.substitute(&substitution);
|
||||
|
||||
if let Type::RecursiveTagUnion(rec, _, _) = &mut instantiated {
|
||||
let new_rec = var_store.fresh();
|
||||
let old = *rec;
|
||||
*rec = new_rec;
|
||||
|
||||
let mut rec_substitution = ImMap::default();
|
||||
rec_substitution.insert(old, Type::Variable(new_rec));
|
||||
instantiated.substitute(&rec_substitution);
|
||||
}
|
||||
|
||||
(
|
||||
Type::Alias(symbol, zipped_args, Box::new(instantiated)),
|
||||
references,
|
||||
)
|
||||
} else {
|
||||
(Type::Apply(symbol, args), references)
|
||||
}
|
||||
(Type::Apply(symbol, args), references)
|
||||
}
|
||||
BoundVariable(v) => {
|
||||
let name = Lowercase::from(*v);
|
||||
@ -245,6 +210,7 @@ fn can_annotation_help(
|
||||
local_aliases,
|
||||
);
|
||||
let mut vars = Vec::with_capacity(loc_vars.len());
|
||||
let mut lowercase_vars = Vec::with_capacity(loc_vars.len());
|
||||
|
||||
references.insert(symbol);
|
||||
|
||||
@ -259,7 +225,9 @@ fn can_annotation_help(
|
||||
let var = var_store.fresh();
|
||||
|
||||
rigids.insert(var_name.clone(), var);
|
||||
vars.push((var_name, Type::Variable(var)));
|
||||
vars.push((var_name.clone(), Type::Variable(var)));
|
||||
|
||||
lowercase_vars.push(Located::at(loc_var.region, (var_name, var)));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -273,7 +241,7 @@ fn can_annotation_help(
|
||||
}
|
||||
}
|
||||
|
||||
let alias = if let Type::TagUnion(tags, ext) = inner_type {
|
||||
let alias_actual = if let Type::TagUnion(tags, ext) = inner_type {
|
||||
let rec_var = var_store.fresh();
|
||||
|
||||
let mut new_tags = Vec::with_capacity(tags.len());
|
||||
@ -286,16 +254,20 @@ fn can_annotation_help(
|
||||
}
|
||||
new_tags.push((tag_name.clone(), new_args));
|
||||
}
|
||||
let rec_tag_union = Type::RecursiveTagUnion(rec_var, new_tags, ext);
|
||||
|
||||
Type::Alias(symbol, vars, Box::new(rec_tag_union))
|
||||
Type::RecursiveTagUnion(rec_var, new_tags, ext)
|
||||
} else {
|
||||
Type::Alias(symbol, vars, Box::new(inner_type))
|
||||
inner_type
|
||||
};
|
||||
|
||||
local_aliases.push((symbol, alias.clone()));
|
||||
let alias = Alias {
|
||||
region,
|
||||
vars: lowercase_vars,
|
||||
typ: alias_actual.clone(),
|
||||
};
|
||||
local_aliases.insert(symbol, alias);
|
||||
|
||||
(alias, references)
|
||||
let type_alias = Type::Alias(symbol, vars, Box::new(alias_actual));
|
||||
(type_alias, references)
|
||||
}
|
||||
_ => {
|
||||
// This is a syntactically invalid type alias.
|
||||
@ -398,7 +370,7 @@ fn can_assigned_field<'a>(
|
||||
scope: &mut Scope,
|
||||
var_store: &VarStore,
|
||||
rigids: &mut ImMap<Lowercase, Variable>,
|
||||
local_aliases: &mut Vec<(Symbol, Type)>,
|
||||
local_aliases: &mut SendMap<Symbol, Alias>,
|
||||
field_types: &mut SendMap<Lowercase, Type>,
|
||||
) -> MutSet<Symbol> {
|
||||
use crate::parse::ast::AssignedField::*;
|
||||
@ -460,7 +432,7 @@ fn can_tag<'a>(
|
||||
scope: &mut Scope,
|
||||
var_store: &VarStore,
|
||||
rigids: &mut ImMap<Lowercase, Variable>,
|
||||
local_aliases: &mut Vec<(Symbol, Type)>,
|
||||
local_aliases: &mut SendMap<Symbol, Alias>,
|
||||
tag_types: &mut Vec<(TagName, Vec<Type>)>,
|
||||
) -> MutSet<Symbol> {
|
||||
match tag {
|
||||
|
@ -18,18 +18,19 @@ use crate::module::symbol::Symbol;
|
||||
use crate::parse::ast;
|
||||
use crate::region::{Located, Region};
|
||||
use crate::subs::{VarStore, Variable};
|
||||
use crate::types::Type;
|
||||
use crate::types::{Alias, Type};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Def {
|
||||
pub loc_pattern: Located<Pattern>,
|
||||
pub loc_expr: Located<Expr>,
|
||||
pub expr_var: Variable,
|
||||
pub pattern_vars: SendMap<Symbol, Variable>,
|
||||
pub annotation: Option<(Type, SendMap<Variable, Lowercase>)>,
|
||||
pub annotation: Option<(Type, SendMap<Variable, Lowercase>, SendMap<Symbol, Alias>)>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -39,6 +40,7 @@ pub struct CanDefs {
|
||||
pub refs_by_symbol: MutMap<Symbol, (Located<Ident>, References)>,
|
||||
pub can_defs_by_symbol: MutMap<Symbol, Def>,
|
||||
pub symbols_introduced: MutMap<Symbol, Region>,
|
||||
pub aliases: SendMap<Symbol, Alias>,
|
||||
}
|
||||
/// A Def that has had patterns and type annnotations canonicalized,
|
||||
/// but no Expr canonicalization has happened yet. Also, it has had spaces
|
||||
@ -186,6 +188,8 @@ pub fn canonicalize_defs<'a>(
|
||||
|
||||
pending.sort_by(aliases_first);
|
||||
|
||||
let mut aliases = SendMap::default();
|
||||
|
||||
// Now that we have the scope completely assembled, and shadowing resolved,
|
||||
// we're ready to canonicalize any body exprs.
|
||||
for pending_def in pending.into_iter() {
|
||||
@ -197,6 +201,7 @@ pub fn canonicalize_defs<'a>(
|
||||
&mut can_defs_by_symbol,
|
||||
var_store,
|
||||
&mut refs_by_symbol,
|
||||
&mut aliases,
|
||||
);
|
||||
|
||||
// TODO we should do something with these references; they include
|
||||
@ -227,6 +232,7 @@ pub fn canonicalize_defs<'a>(
|
||||
refs_by_symbol,
|
||||
can_defs_by_symbol,
|
||||
symbols_introduced,
|
||||
aliases,
|
||||
},
|
||||
scope,
|
||||
output,
|
||||
@ -243,8 +249,13 @@ pub fn sort_can_defs(
|
||||
symbols_introduced,
|
||||
refs_by_symbol,
|
||||
can_defs_by_symbol,
|
||||
aliases,
|
||||
} = defs;
|
||||
|
||||
for (symbol, alias) in aliases.clone() {
|
||||
output.aliases.insert(symbol, alias);
|
||||
}
|
||||
|
||||
// Determine the full set of references by traversing the graph.
|
||||
let mut visited_symbols = MutSet::default();
|
||||
let returned_lookups = ImSet::clone(&output.references.lookups);
|
||||
@ -653,6 +664,7 @@ fn canonicalize_pending_def<'a>(
|
||||
can_defs_by_symbol: &mut MutMap<Symbol, Def>,
|
||||
var_store: &VarStore,
|
||||
refs_by_symbol: &mut MutMap<Symbol, (Located<Ident>, References)>,
|
||||
aliases: &mut SendMap<Symbol, Alias>,
|
||||
) -> Output {
|
||||
use PendingDef::*;
|
||||
|
||||
@ -667,6 +679,10 @@ fn canonicalize_pending_def<'a>(
|
||||
// use them. We discard them!
|
||||
let ann = loc_ann.value;
|
||||
|
||||
for (symbol, alias) in ann.aliases.clone() {
|
||||
aliases.insert(symbol, alias);
|
||||
}
|
||||
|
||||
// union seen rigids with already found ones
|
||||
for (k, v) in ann.ftv {
|
||||
output.rigids.insert(k, v);
|
||||
@ -740,15 +756,20 @@ fn canonicalize_pending_def<'a>(
|
||||
value: loc_can_expr.value.clone(),
|
||||
},
|
||||
pattern_vars: im::HashMap::clone(&vars_by_symbol),
|
||||
annotation: Some((typ.clone(), output.rigids.clone())),
|
||||
annotation: Some((typ.clone(), output.rigids.clone(), ann.aliases.clone())),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Alias { ann, .. } => {
|
||||
Alias { ann, name, .. } => {
|
||||
let can_ann = canonicalize_annotation(env, scope, &ann.value, ann.region, var_store);
|
||||
|
||||
// For now, use the alias from the scope (which already deals with (mutual) recursion)
|
||||
if let Some(alias) = scope.lookup_alias(name.value) {
|
||||
aliases.insert(name.value, alias.clone());
|
||||
}
|
||||
|
||||
// TODO should probably incorporate can_ann.references here - possibly by
|
||||
// inserting them into refs_by_symbol?
|
||||
|
||||
@ -759,13 +780,17 @@ fn canonicalize_pending_def<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
TypedBody(loc_pattern, loc_can_pattern, loc_annotation, loc_expr) => {
|
||||
TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr) => {
|
||||
// TODO we have ann.references here, which includes information about
|
||||
// which symbols were referenced in type annotations, but we never
|
||||
// use them. We discard them!
|
||||
let ann = loc_annotation.value;
|
||||
let ann = loc_ann.value;
|
||||
let typ = ann.typ;
|
||||
|
||||
for (symbol, alias) in ann.aliases.clone() {
|
||||
aliases.insert(symbol, alias);
|
||||
}
|
||||
|
||||
// union seen rigids with already found ones
|
||||
for (k, v) in ann.ftv {
|
||||
output.rigids.insert(k, v);
|
||||
@ -886,7 +911,7 @@ fn canonicalize_pending_def<'a>(
|
||||
value: loc_can_expr.value.clone(),
|
||||
},
|
||||
pattern_vars: im::HashMap::clone(&vars_by_symbol),
|
||||
annotation: Some((typ.clone(), output.rigids.clone())),
|
||||
annotation: Some((typ.clone(), output.rigids.clone(), ann.aliases.clone())),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -1063,7 +1088,7 @@ pub fn can_defs_with_return<'a>(
|
||||
for declaration in decls.into_iter().rev() {
|
||||
loc_expr = Located {
|
||||
region: Region::zero(),
|
||||
value: decl_to_let(var_store, declaration, loc_expr),
|
||||
value: decl_to_let(var_store, declaration, loc_expr, output.aliases.clone()),
|
||||
};
|
||||
}
|
||||
|
||||
@ -1073,12 +1098,19 @@ pub fn can_defs_with_return<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn decl_to_let(var_store: &VarStore, decl: Declaration, loc_ret: Located<Expr>) -> Expr {
|
||||
fn decl_to_let(
|
||||
var_store: &VarStore,
|
||||
decl: Declaration,
|
||||
loc_ret: Located<Expr>,
|
||||
aliases: SendMap<Symbol, Alias>,
|
||||
) -> Expr {
|
||||
match decl {
|
||||
Declaration::Declare(def) => {
|
||||
Expr::LetNonRec(Box::new(def), Box::new(loc_ret), var_store.fresh())
|
||||
Expr::LetNonRec(Box::new(def), Box::new(loc_ret), var_store.fresh(), aliases)
|
||||
}
|
||||
Declaration::DeclareRec(defs) => {
|
||||
Expr::LetRec(defs, Box::new(loc_ret), var_store.fresh(), aliases)
|
||||
}
|
||||
Declaration::DeclareRec(defs) => Expr::LetRec(defs, Box::new(loc_ret), var_store.fresh()),
|
||||
Declaration::InvalidCycle(symbols, regions) => {
|
||||
Expr::RuntimeError(RuntimeError::CircularDef(symbols, regions))
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ use crate::operator::CalledVia;
|
||||
use crate::parse::ast;
|
||||
use crate::region::{Located, Region};
|
||||
use crate::subs::{VarStore, Variable};
|
||||
use crate::types::Alias;
|
||||
use std::fmt::Debug;
|
||||
use std::i64;
|
||||
use std::ops::Neg;
|
||||
@ -25,6 +26,7 @@ pub struct Output {
|
||||
pub references: References,
|
||||
pub tail_call: Option<Symbol>,
|
||||
pub rigids: SendMap<Variable, Lowercase>,
|
||||
pub aliases: SendMap<Symbol, Alias>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@ -56,8 +58,8 @@ pub enum Expr {
|
||||
},
|
||||
|
||||
// Let
|
||||
LetRec(Vec<Def>, Box<Located<Expr>>, Variable),
|
||||
LetNonRec(Box<Def>, Box<Located<Expr>>, Variable),
|
||||
LetRec(Vec<Def>, Box<Located<Expr>>, Variable, Aliases),
|
||||
LetNonRec(Box<Def>, Box<Located<Expr>>, Variable, Aliases),
|
||||
|
||||
/// This is *only* for calling functions, not for tag application.
|
||||
/// The Tag variant contains any applied values inside it.
|
||||
@ -114,6 +116,8 @@ pub enum Expr {
|
||||
RuntimeError(RuntimeError),
|
||||
}
|
||||
|
||||
type Aliases = SendMap<Symbol, Alias>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Field {
|
||||
pub var: Variable,
|
||||
|
@ -11,10 +11,12 @@ use crate::module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||
use crate::parse::ast;
|
||||
use crate::region::{Located, Region};
|
||||
use crate::subs::{VarStore, Variable};
|
||||
use crate::types::Alias;
|
||||
use bumpalo::Bump;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleOutput {
|
||||
pub aliases: MutMap<Symbol, Alias>,
|
||||
pub declarations: Vec<Declaration>,
|
||||
pub exposed_imports: MutMap<Symbol, Variable>,
|
||||
pub lookups: Vec<(Symbol, Variable, Region)>,
|
||||
@ -98,7 +100,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
let (defs, scope, output) = canonicalize_defs(
|
||||
let (defs, populated_scope, output) = canonicalize_defs(
|
||||
&mut env,
|
||||
Output::default(),
|
||||
var_store,
|
||||
@ -178,9 +180,14 @@ pub fn canonicalize_module_defs<'a>(
|
||||
references.insert(symbol);
|
||||
}
|
||||
|
||||
dbg!(home, &references);
|
||||
let mut aliases = MutMap::default();
|
||||
|
||||
for (symbol, alias) in populated_scope.aliases() {
|
||||
aliases.insert(*symbol, alias.clone());
|
||||
}
|
||||
|
||||
Ok(ModuleOutput {
|
||||
aliases,
|
||||
declarations,
|
||||
references,
|
||||
exposed_imports: can_exposed_imports,
|
||||
|
@ -4,14 +4,7 @@ use crate::collections::ImMap;
|
||||
use crate::module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use crate::region::{Located, Region};
|
||||
use crate::subs::Variable;
|
||||
use crate::types::Type;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Alias {
|
||||
pub region: Region,
|
||||
pub vars: Vec<Located<(Lowercase, Variable)>>,
|
||||
pub typ: Type,
|
||||
}
|
||||
use crate::types::{Alias, Type};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Scope {
|
||||
|
@ -29,6 +29,7 @@ pub fn exists(flex_vars: Vec<Variable>, constraint: Constraint) -> Constraint {
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars,
|
||||
def_types: SendMap::default(),
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: constraint,
|
||||
ret_constraint: Constraint::True,
|
||||
}))
|
||||
|
@ -11,6 +11,7 @@ use crate::constrain::pattern::{constrain_pattern, PatternState};
|
||||
use crate::module::symbol::{ModuleId, Symbol};
|
||||
use crate::region::{Located, Region};
|
||||
use crate::subs::Variable;
|
||||
use crate::types::Alias;
|
||||
use crate::types::AnnotationSource::{self, *};
|
||||
use crate::types::Constraint::{self, *};
|
||||
use crate::types::Expected::{self, *};
|
||||
@ -42,6 +43,23 @@ pub fn exists(flex_vars: Vec<Variable>, constraint: Constraint) -> Constraint {
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars,
|
||||
def_types: SendMap::default(),
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: constraint,
|
||||
ret_constraint: Constraint::True,
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn exists_with_aliases(
|
||||
aliases: SendMap<Symbol, Alias>,
|
||||
flex_vars: Vec<Variable>,
|
||||
constraint: Constraint,
|
||||
) -> Constraint {
|
||||
Let(Box::new(LetConstraint {
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars,
|
||||
def_types: SendMap::default(),
|
||||
def_aliases: aliases,
|
||||
defs_constraint: constraint,
|
||||
ret_constraint: Constraint::True,
|
||||
}))
|
||||
@ -283,6 +301,7 @@ pub fn constrain_expr(
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: state.vars,
|
||||
def_types: state.headers,
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint,
|
||||
ret_constraint,
|
||||
})),
|
||||
@ -540,10 +559,11 @@ pub fn constrain_expr(
|
||||
),
|
||||
)
|
||||
}
|
||||
LetRec(defs, loc_ret, var) => {
|
||||
LetRec(defs, loc_ret, var, aliases) => {
|
||||
let body_con = constrain_expr(env, loc_ret.region, &loc_ret.value, expected.clone());
|
||||
|
||||
exists(
|
||||
exists_with_aliases(
|
||||
aliases.clone(),
|
||||
vec![*var],
|
||||
And(vec![
|
||||
constrain_recursive_defs(env, defs, body_con),
|
||||
@ -553,10 +573,11 @@ pub fn constrain_expr(
|
||||
]),
|
||||
)
|
||||
}
|
||||
LetNonRec(def, loc_ret, var) => {
|
||||
LetNonRec(def, loc_ret, var, aliases) => {
|
||||
let body_con = constrain_expr(env, loc_ret.region, &loc_ret.value, expected.clone());
|
||||
|
||||
exists(
|
||||
exists_with_aliases(
|
||||
aliases.clone(),
|
||||
vec![*var],
|
||||
And(vec![
|
||||
constrain_def(env, def, body_con),
|
||||
@ -638,6 +659,7 @@ fn constrain_when_branch(
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: state.vars,
|
||||
def_types: state.headers,
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: Constraint::And(state.constraints),
|
||||
ret_constraint,
|
||||
}))
|
||||
@ -716,10 +738,12 @@ pub fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
|
||||
|
||||
pattern_state.vars.push(expr_var);
|
||||
|
||||
let mut def_aliases = SendMap::default();
|
||||
let mut new_rigids = Vec::new();
|
||||
|
||||
let expr_con = match &def.annotation {
|
||||
Some((annotation, free_vars)) => {
|
||||
Some((annotation, free_vars, ann_def_aliases)) => {
|
||||
def_aliases = ann_def_aliases.clone();
|
||||
let mut annotation = annotation.clone();
|
||||
let rigids = &env.rigids;
|
||||
let mut ftv: ImMap<Lowercase, Type> = rigids.clone();
|
||||
@ -787,10 +811,12 @@ pub fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
|
||||
rigid_vars: new_rigids,
|
||||
flex_vars: pattern_state.vars,
|
||||
def_types: pattern_state.headers,
|
||||
def_aliases,
|
||||
defs_constraint: Let(Box::new(LetConstraint {
|
||||
rigid_vars: Vec::new(), // always empty
|
||||
flex_vars: Vec::new(), // empty, because our functions have no arguments
|
||||
def_types: SendMap::default(), // empty, because our functions have no arguments!
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: And(pattern_state.constraints),
|
||||
ret_constraint: expr_con,
|
||||
})),
|
||||
@ -815,6 +841,7 @@ pub fn rec_defs_help(
|
||||
mut rigid_info: Info,
|
||||
mut flex_info: Info,
|
||||
) -> Constraint {
|
||||
let mut def_aliases = SendMap::default();
|
||||
for def in defs {
|
||||
let expr_var = def.expr_var;
|
||||
let expr_type = Type::Variable(expr_var);
|
||||
@ -851,6 +878,7 @@ pub fn rec_defs_help(
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: Vec::new(), // empty because Roc function defs have no args
|
||||
def_types: SendMap::default(), // empty because Roc function defs have no args
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: True, // I think this is correct, once again because there are no args
|
||||
ret_constraint: expr_con,
|
||||
}));
|
||||
@ -860,7 +888,11 @@ pub fn rec_defs_help(
|
||||
flex_info.def_types.extend(pattern_state.headers);
|
||||
}
|
||||
|
||||
Some((annotation, seen_rigids)) => {
|
||||
Some((annotation, seen_rigids, ann_def_aliases)) => {
|
||||
for (symbol, alias) in ann_def_aliases.clone() {
|
||||
def_aliases.insert(symbol, alias);
|
||||
}
|
||||
|
||||
// TODO also do this for more complex patterns
|
||||
if let Pattern::Identifier(symbol) = def.loc_pattern.value {
|
||||
pattern_state.headers.insert(
|
||||
@ -910,6 +942,7 @@ pub fn rec_defs_help(
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: Vec::new(), // empty because Roc function defs have no args
|
||||
def_types: SendMap::default(), // empty because Roc function defs have no args
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: True, // I think this is correct, once again because there are no args
|
||||
ret_constraint: expr_con,
|
||||
}));
|
||||
@ -921,6 +954,7 @@ pub fn rec_defs_help(
|
||||
rigid_vars: new_rigids,
|
||||
flex_vars: Vec::new(), // no flex vars introduced
|
||||
def_types: SendMap::default(), // no headers introduced (at this level)
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: def_con,
|
||||
ret_constraint: True,
|
||||
})));
|
||||
@ -933,15 +967,18 @@ pub fn rec_defs_help(
|
||||
rigid_vars: rigid_info.vars,
|
||||
flex_vars: Vec::new(),
|
||||
def_types: rigid_info.def_types,
|
||||
def_aliases,
|
||||
defs_constraint: True,
|
||||
ret_constraint: Let(Box::new(LetConstraint {
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: flex_info.vars,
|
||||
def_types: flex_info.def_types.clone(),
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: Let(Box::new(LetConstraint {
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: Vec::new(),
|
||||
def_types: flex_info.def_types,
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: True,
|
||||
ret_constraint: And(flex_info.constraints),
|
||||
})),
|
||||
|
@ -151,6 +151,7 @@ fn constrain_imported_value(
|
||||
// Importing a value doesn't constrain this module at all.
|
||||
// All it does is introduce variables and provide def_types for lookups
|
||||
def_types,
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: True,
|
||||
ret_constraint: body_con,
|
||||
}))
|
||||
|
@ -9,7 +9,11 @@ pub fn infer_expr(
|
||||
constraint: &Constraint,
|
||||
expr_var: Variable,
|
||||
) -> (Content, Solved<Subs>) {
|
||||
let (solved, _) = solve::run(&SendMap::default(), problems, subs, constraint);
|
||||
let env = solve::Env {
|
||||
aliases: SendMap::default(),
|
||||
vars_by_symbol: SendMap::default(),
|
||||
};
|
||||
let (solved, _) = solve::run(&env, problems, subs, constraint);
|
||||
|
||||
let content = solved.inner().get_without_compacting(expr_var).content;
|
||||
|
||||
|
@ -10,7 +10,7 @@ use crate::parse::parser::{Fail, Parser, State};
|
||||
use crate::region::{Located, Region};
|
||||
use crate::solve::{self, ExposedModuleTypes, Solved, SolvedType, SubsByModule};
|
||||
use crate::subs::{Subs, VarStore, Variable};
|
||||
use crate::types::{Constraint, Problem};
|
||||
use crate::types::{Alias, Constraint, Problem};
|
||||
use bumpalo::Bump;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::read_to_string;
|
||||
@ -33,6 +33,7 @@ pub struct Module {
|
||||
pub exposed_imports: MutMap<Symbol, Variable>,
|
||||
pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
|
||||
pub references: MutSet<Symbol>,
|
||||
pub aliases: MutMap<Symbol, Alias>,
|
||||
}
|
||||
|
||||
pub struct LoadedModule {
|
||||
@ -78,7 +79,7 @@ enum Msg {
|
||||
solved_types: MutMap<Symbol, SolvedType>,
|
||||
subs: Arc<Solved<Subs>>,
|
||||
problems: Vec<Problem>,
|
||||
new_vars_by_symbol: SendMap<Symbol, Variable>,
|
||||
solved_env: solve::Env,
|
||||
},
|
||||
}
|
||||
|
||||
@ -194,7 +195,9 @@ pub async fn load<'a>(
|
||||
let mut solve_listeners: MutMap<ModuleId, Vec<ModuleId>> = MutMap::default();
|
||||
|
||||
let mut unsolved_modules: MutMap<ModuleId, (Module, Constraint, VarStore)> = MutMap::default();
|
||||
let mut vars_by_symbol = SendMap::default();
|
||||
|
||||
// TODO can be removed I think
|
||||
let vars_by_symbol = SendMap::default();
|
||||
|
||||
// Parse and canonicalize the module's deps
|
||||
while let Some(msg) = msg_rx.recv().await {
|
||||
@ -370,7 +373,7 @@ pub async fn load<'a>(
|
||||
solved_types,
|
||||
subs,
|
||||
problems,
|
||||
new_vars_by_symbol,
|
||||
..
|
||||
} => {
|
||||
all_problems.extend(problems);
|
||||
|
||||
@ -781,6 +784,12 @@ fn solve_module(
|
||||
|
||||
let exposed_vars_by_symbol: Vec<(Symbol, Variable)> = module.exposed_vars_by_symbol;
|
||||
|
||||
let mut aliases = SendMap::default();
|
||||
|
||||
for (symbol, alias) in module.aliases.clone() {
|
||||
aliases.insert(symbol, alias);
|
||||
}
|
||||
|
||||
// Start solving this module in the background.
|
||||
spawn_blocking(move || {
|
||||
// Now that the module is parsed, canonicalized, and constrained,
|
||||
@ -788,9 +797,13 @@ fn solve_module(
|
||||
let subs = Subs::new(var_store.into());
|
||||
let mut problems = Vec::new();
|
||||
|
||||
let env = solve::Env {
|
||||
vars_by_symbol,
|
||||
aliases,
|
||||
};
|
||||
|
||||
// Run the solver to populate Subs.
|
||||
let (solved_subs, new_vars_by_symbol) =
|
||||
solve::run(&vars_by_symbol, &mut problems, subs, &constraint);
|
||||
let (solved_subs, solved_env) = solve::run(&env, &mut problems, subs, &constraint);
|
||||
|
||||
let mut solved_types = MutMap::default();
|
||||
|
||||
@ -815,7 +828,7 @@ fn solve_module(
|
||||
module_id: home,
|
||||
subs: Arc::new(solved_subs),
|
||||
solved_types,
|
||||
new_vars_by_symbol,
|
||||
solved_env,
|
||||
problems,
|
||||
})
|
||||
.await
|
||||
@ -918,6 +931,7 @@ fn parse_and_constrain(
|
||||
ident_ids,
|
||||
exposed_vars_by_symbol,
|
||||
references,
|
||||
aliases,
|
||||
..
|
||||
}) => {
|
||||
let constraint = constrain_module(module_id, &declarations, lookups);
|
||||
@ -928,6 +942,7 @@ fn parse_and_constrain(
|
||||
exposed_imports,
|
||||
exposed_vars_by_symbol,
|
||||
references,
|
||||
aliases,
|
||||
};
|
||||
|
||||
(module, ident_ids, constraint)
|
||||
|
@ -124,7 +124,7 @@ fn from_can<'a>(
|
||||
Float(_, val) => Expr::Float(val),
|
||||
Str(string) | BlockStr(string) => Expr::Str(env.arena.alloc(string)),
|
||||
Var(symbol) => Expr::Load(symbol.emit()),
|
||||
LetNonRec(def, ret_expr, _) => {
|
||||
LetNonRec(def, ret_expr, _, _) => {
|
||||
let arena = env.arena;
|
||||
let loc_pattern = def.loc_pattern;
|
||||
let loc_expr = def.loc_expr;
|
||||
|
209
src/solve.rs
209
src/solve.rs
@ -3,6 +3,7 @@ use crate::collections::{ImMap, MutMap, SendMap};
|
||||
use crate::module::symbol::{ModuleId, Symbol};
|
||||
use crate::region::Located;
|
||||
use crate::subs::{Content, Descriptor, FlatType, Mark, OptVariable, Rank, Subs, Variable};
|
||||
use crate::types::Alias;
|
||||
use crate::types::Constraint::{self, *};
|
||||
use crate::types::Problem;
|
||||
use crate::types::Type::{self, *};
|
||||
@ -165,7 +166,11 @@ impl SolvedType {
|
||||
}
|
||||
}
|
||||
|
||||
type Env = SendMap<Symbol, Variable>;
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Env {
|
||||
pub vars_by_symbol: SendMap<Symbol, Variable>,
|
||||
pub aliases: SendMap<Symbol, Alias>,
|
||||
}
|
||||
|
||||
const DEFAULT_POOLS: usize = 8;
|
||||
|
||||
@ -218,7 +223,7 @@ impl Pools {
|
||||
|
||||
#[derive(Clone)]
|
||||
struct State {
|
||||
vars_by_symbol: Env,
|
||||
env: Env,
|
||||
mark: Mark,
|
||||
}
|
||||
|
||||
@ -238,32 +243,26 @@ impl<T> Solved<T> {
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
vars_by_symbol: &Env,
|
||||
env: &Env,
|
||||
problems: &mut Vec<Problem>,
|
||||
mut subs: Subs,
|
||||
constraint: &Constraint,
|
||||
) -> (Solved<Subs>, Env) {
|
||||
let mut pools = Pools::default();
|
||||
let state = State {
|
||||
vars_by_symbol: vars_by_symbol.clone(),
|
||||
env: env.clone(),
|
||||
mark: Mark::NONE.next(),
|
||||
};
|
||||
let rank = Rank::toplevel();
|
||||
let state = solve(
|
||||
vars_by_symbol,
|
||||
state,
|
||||
rank,
|
||||
&mut pools,
|
||||
problems,
|
||||
&mut subs,
|
||||
constraint,
|
||||
env, state, rank, &mut pools, problems, &mut subs, constraint,
|
||||
);
|
||||
|
||||
(Solved(subs), state.vars_by_symbol)
|
||||
(Solved(subs), state.env)
|
||||
}
|
||||
|
||||
fn solve(
|
||||
vars_by_symbol: &Env,
|
||||
env: &Env,
|
||||
state: State,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
@ -276,13 +275,19 @@ fn solve(
|
||||
SaveTheEnvironment => {
|
||||
let mut copy = state;
|
||||
|
||||
copy.vars_by_symbol = vars_by_symbol.clone();
|
||||
copy.env = env.clone();
|
||||
|
||||
copy
|
||||
}
|
||||
Eq(typ, expected_type, _region) => {
|
||||
let actual = type_to_var(subs, rank, pools, typ);
|
||||
let expected = type_to_var(subs, rank, pools, expected_type.get_type_ref());
|
||||
let actual = type_to_var(subs, rank, pools, &env.aliases, typ);
|
||||
let expected = type_to_var(
|
||||
subs,
|
||||
rank,
|
||||
pools,
|
||||
&env.aliases,
|
||||
expected_type.get_type_ref(),
|
||||
);
|
||||
let Unified { vars, mismatches } = unify(subs, actual, expected);
|
||||
|
||||
// TODO use region when reporting a problem
|
||||
@ -293,12 +298,12 @@ fn solve(
|
||||
state
|
||||
}
|
||||
Lookup(symbol, expected_type, _region) => {
|
||||
let var = *vars_by_symbol.get(&symbol).unwrap_or_else(|| {
|
||||
let var = *env.vars_by_symbol.get(&symbol).unwrap_or_else(|| {
|
||||
// TODO Instead of panicking, solve this as True and record
|
||||
// a Problem ("module Foo does not expose `bar`") for later.
|
||||
panic!(
|
||||
"Could not find symbol {:?} in vars_by_symbol {:?}",
|
||||
symbol, vars_by_symbol
|
||||
symbol, env.vars_by_symbol
|
||||
)
|
||||
});
|
||||
|
||||
@ -324,7 +329,13 @@ fn solve(
|
||||
// is being looked up in this module, then we use our Subs as both
|
||||
// the source and destination.
|
||||
let actual = deep_copy_var(subs, rank, pools, var);
|
||||
let expected = type_to_var(subs, rank, pools, expected_type.get_type_ref());
|
||||
let expected = type_to_var(
|
||||
subs,
|
||||
rank,
|
||||
pools,
|
||||
&env.aliases,
|
||||
expected_type.get_type_ref(),
|
||||
);
|
||||
let Unified { vars, mismatches } = unify(subs, actual, expected);
|
||||
|
||||
// TODO use region when reporting a problem
|
||||
@ -338,22 +349,14 @@ fn solve(
|
||||
let mut state = state;
|
||||
|
||||
for sub_constraint in sub_constraints.iter() {
|
||||
state = solve(
|
||||
vars_by_symbol,
|
||||
state,
|
||||
rank,
|
||||
pools,
|
||||
problems,
|
||||
subs,
|
||||
sub_constraint,
|
||||
);
|
||||
state = solve(env, state, rank, pools, problems, subs, sub_constraint);
|
||||
}
|
||||
|
||||
state
|
||||
}
|
||||
Pattern(_region, _category, typ, expected) => {
|
||||
let actual = type_to_var(subs, rank, pools, typ);
|
||||
let expected = type_to_var(subs, rank, pools, expected.get_type_ref());
|
||||
let actual = type_to_var(subs, rank, pools, &env.aliases, typ);
|
||||
let expected = type_to_var(subs, rank, pools, &env.aliases, expected.get_type_ref());
|
||||
let Unified { vars, mismatches } = unify(subs, actual, expected);
|
||||
|
||||
// TODO use region when reporting a problem
|
||||
@ -368,10 +371,16 @@ fn solve(
|
||||
True if let_con.rigid_vars.is_empty() => {
|
||||
introduce(subs, rank, pools, &let_con.flex_vars);
|
||||
|
||||
let mut new_env = env.clone();
|
||||
|
||||
for (symbol, alias) in let_con.def_aliases.iter() {
|
||||
new_env.aliases.insert(*symbol, alias.clone());
|
||||
}
|
||||
|
||||
// If the return expression is guaranteed to solve,
|
||||
// solve the assignments themselves and move on.
|
||||
solve(
|
||||
vars_by_symbol,
|
||||
&new_env,
|
||||
state,
|
||||
rank,
|
||||
pools,
|
||||
@ -382,7 +391,7 @@ fn solve(
|
||||
}
|
||||
ret_con if let_con.rigid_vars.is_empty() && let_con.flex_vars.is_empty() => {
|
||||
let state = solve(
|
||||
vars_by_symbol,
|
||||
env,
|
||||
state,
|
||||
rank,
|
||||
pools,
|
||||
@ -391,11 +400,17 @@ fn solve(
|
||||
&let_con.defs_constraint,
|
||||
);
|
||||
|
||||
let mut new_env = env.clone();
|
||||
|
||||
for (symbol, alias) in let_con.def_aliases.iter() {
|
||||
new_env.aliases.insert(*symbol, alias.clone());
|
||||
}
|
||||
|
||||
// Add a variable for each def to new_vars_by_env.
|
||||
let mut local_def_vars = ImMap::default();
|
||||
|
||||
for (symbol, loc_type) in let_con.def_types.iter() {
|
||||
let var = type_to_var(subs, rank, pools, &loc_type.value);
|
||||
let var = type_to_var(subs, rank, pools, &new_env.aliases, &loc_type.value);
|
||||
|
||||
local_def_vars.insert(
|
||||
symbol.clone(),
|
||||
@ -406,23 +421,13 @@ fn solve(
|
||||
);
|
||||
}
|
||||
|
||||
let mut new_vars_by_symbol = vars_by_symbol.clone();
|
||||
|
||||
for (symbol, loc_var) in local_def_vars.iter() {
|
||||
if !new_vars_by_symbol.contains_key(&symbol) {
|
||||
new_vars_by_symbol.insert(symbol.clone(), loc_var.value);
|
||||
if !new_env.vars_by_symbol.contains_key(&symbol) {
|
||||
new_env.vars_by_symbol.insert(symbol.clone(), loc_var.value);
|
||||
}
|
||||
}
|
||||
|
||||
let new_state = solve(
|
||||
&new_vars_by_symbol,
|
||||
state,
|
||||
rank,
|
||||
pools,
|
||||
problems,
|
||||
subs,
|
||||
ret_con,
|
||||
);
|
||||
let new_state = solve(&new_env, state, rank, pools, problems, subs, ret_con);
|
||||
|
||||
for (symbol, loc_var) in local_def_vars {
|
||||
check_for_infinite_type(subs, problems, symbol, loc_var);
|
||||
@ -451,12 +456,26 @@ fn solve(
|
||||
pool.extend(rigid_vars.iter());
|
||||
pool.extend(flex_vars.iter());
|
||||
|
||||
let mut new_env = env.clone();
|
||||
|
||||
for (symbol, alias) in let_con.def_aliases.iter() {
|
||||
new_env.aliases.insert(*symbol, alias.clone());
|
||||
}
|
||||
|
||||
// Add a variable for each def to local_def_vars.
|
||||
let mut local_def_vars = ImMap::default();
|
||||
|
||||
for (symbol, loc_type) in let_con.def_types.iter() {
|
||||
let def_type = loc_type.value.clone();
|
||||
let var = type_to_var(subs, next_rank, next_pools, &def_type);
|
||||
|
||||
// TODO should this use new aliases?
|
||||
let var = type_to_var(
|
||||
subs,
|
||||
next_rank,
|
||||
next_pools,
|
||||
&new_env.aliases,
|
||||
&def_type,
|
||||
);
|
||||
|
||||
local_def_vars.insert(
|
||||
symbol.clone(),
|
||||
@ -471,7 +490,7 @@ fn solve(
|
||||
|
||||
// Solve the assignments' constraints first.
|
||||
let new_state = solve(
|
||||
vars_by_symbol,
|
||||
&new_env,
|
||||
state,
|
||||
next_rank,
|
||||
next_pools,
|
||||
@ -516,31 +535,24 @@ fn solve(
|
||||
|
||||
failing.is_empty()
|
||||
});
|
||||
let mut new_vars_by_symbol = vars_by_symbol.clone();
|
||||
|
||||
for (symbol, loc_var) in local_def_vars.iter() {
|
||||
if !new_vars_by_symbol.contains_key(&symbol) {
|
||||
new_vars_by_symbol.insert(symbol.clone(), loc_var.value);
|
||||
if !new_env.vars_by_symbol.contains_key(&symbol) {
|
||||
new_env.vars_by_symbol.insert(symbol.clone(), loc_var.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Note that this vars_by_symbol is the one returned by the
|
||||
// previous call to solve()
|
||||
let temp_state = State {
|
||||
vars_by_symbol: new_state.vars_by_symbol,
|
||||
env: new_state.env,
|
||||
mark: final_mark,
|
||||
};
|
||||
|
||||
// Now solve the body, using the new vars_by_symbol which includes
|
||||
// the assignments' name-to-variable mappings.
|
||||
let new_state = solve(
|
||||
&new_vars_by_symbol,
|
||||
temp_state,
|
||||
rank,
|
||||
next_pools,
|
||||
problems,
|
||||
subs,
|
||||
&ret_con,
|
||||
&new_env, temp_state, rank, next_pools, problems, subs, &ret_con,
|
||||
);
|
||||
|
||||
for (symbol, loc_var) in local_def_vars {
|
||||
@ -562,30 +574,83 @@ fn solve(
|
||||
}
|
||||
}
|
||||
|
||||
fn type_to_var(subs: &mut Subs, rank: Rank, pools: &mut Pools, typ: &Type) -> Variable {
|
||||
type_to_variable(subs, rank, pools, &ImMap::default(), typ)
|
||||
fn type_to_var(
|
||||
subs: &mut Subs,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
aliases: &SendMap<Symbol, Alias>,
|
||||
typ: &Type,
|
||||
) -> Variable {
|
||||
type_to_variable(subs, rank, pools, aliases, typ)
|
||||
}
|
||||
|
||||
fn type_to_variable(
|
||||
subs: &mut Subs,
|
||||
rank: Rank,
|
||||
pools: &mut Pools,
|
||||
aliases: &ImMap<Lowercase, Variable>,
|
||||
aliases: &SendMap<Symbol, Alias>,
|
||||
typ: &Type,
|
||||
) -> Variable {
|
||||
match typ {
|
||||
Variable(var) => *var,
|
||||
Apply(symbol, args) => {
|
||||
let mut arg_vars = Vec::with_capacity(args.len());
|
||||
if let Some(alias) = aliases.get(symbol) {
|
||||
if args.len() != alias.vars.len() {
|
||||
panic!(
|
||||
"Alias {:?} applied to incorrect number of arguments",
|
||||
symbol
|
||||
);
|
||||
}
|
||||
|
||||
for arg in args {
|
||||
arg_vars.push(type_to_variable(subs, rank, pools, aliases, arg))
|
||||
let mut actual = alias.typ.clone();
|
||||
let mut substitution = ImMap::default();
|
||||
let mut arg_vars = Vec::with_capacity(args.len());
|
||||
|
||||
for (
|
||||
tipe,
|
||||
Located {
|
||||
value: (lowercase, var),
|
||||
..
|
||||
},
|
||||
) in args.iter().zip(alias.vars.iter())
|
||||
{
|
||||
let new_var = type_to_variable(subs, rank, pools, aliases, tipe);
|
||||
substitution.insert(*var, Type::Variable(new_var));
|
||||
arg_vars.push((lowercase.clone(), new_var));
|
||||
}
|
||||
|
||||
actual.substitute(&substitution);
|
||||
|
||||
// We must instantiate the recursion variable, otherwise all e.g. lists will be
|
||||
// unified, List Int ~ List Float
|
||||
if let Type::RecursiveTagUnion(rec_var, _, _) = actual {
|
||||
let new_rec_var = subs.fresh_unnamed_flex_var();
|
||||
substitution.clear();
|
||||
substitution.insert(rec_var, Type::Variable(new_rec_var));
|
||||
|
||||
actual.substitute(&substitution);
|
||||
|
||||
if let Type::RecursiveTagUnion(_, tags, ext_var) = actual {
|
||||
actual = Type::RecursiveTagUnion(new_rec_var, tags, ext_var);
|
||||
}
|
||||
}
|
||||
|
||||
let alias_var = type_to_variable(subs, rank, pools, aliases, &actual);
|
||||
let content = Content::Alias(*symbol, arg_vars, alias_var);
|
||||
|
||||
register(subs, rank, pools, content)
|
||||
} else {
|
||||
let mut arg_vars = Vec::with_capacity(args.len());
|
||||
|
||||
for arg in args {
|
||||
arg_vars.push(type_to_variable(subs, rank, pools, aliases, arg))
|
||||
}
|
||||
|
||||
let flat_type = FlatType::Apply(*symbol, arg_vars);
|
||||
let content = Content::Structure(flat_type);
|
||||
|
||||
register(subs, rank, pools, content)
|
||||
}
|
||||
|
||||
let flat_type = FlatType::Apply(*symbol, arg_vars);
|
||||
let content = Content::Structure(flat_type);
|
||||
|
||||
register(subs, rank, pools, content)
|
||||
}
|
||||
EmptyRec => {
|
||||
let content = Content::Structure(FlatType::EmptyRecord);
|
||||
@ -674,13 +739,13 @@ fn type_to_variable(
|
||||
let mut new_aliases = ImMap::default();
|
||||
|
||||
for (arg, arg_type) in args {
|
||||
let arg_var = type_to_variable(subs, rank, pools, &ImMap::default(), arg_type);
|
||||
let arg_var = type_to_variable(subs, rank, pools, aliases, arg_type);
|
||||
|
||||
arg_vars.push((arg.clone(), arg_var));
|
||||
new_aliases.insert(arg.clone(), arg_var);
|
||||
}
|
||||
|
||||
let alias_var = type_to_variable(subs, rank, pools, &new_aliases, alias_type);
|
||||
let alias_var = type_to_variable(subs, rank, pools, aliases, alias_type);
|
||||
let content = Content::Alias(*symbol, arg_vars, alias_var);
|
||||
|
||||
register(subs, rank, pools, content)
|
||||
|
@ -571,10 +571,18 @@ pub struct LetConstraint {
|
||||
pub rigid_vars: Vec<Variable>,
|
||||
pub flex_vars: Vec<Variable>,
|
||||
pub def_types: SendMap<Symbol, Located<Type>>,
|
||||
pub def_aliases: SendMap<Symbol, Alias>,
|
||||
pub defs_constraint: Constraint,
|
||||
pub ret_constraint: Constraint,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Alias {
|
||||
pub region: Region,
|
||||
pub vars: Vec<Located<(Lowercase, Variable)>>,
|
||||
pub typ: Type,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub enum Problem {
|
||||
CanonicalizationProblem,
|
||||
|
@ -5,7 +5,7 @@ use crate::can::ident::{Ident, Lowercase, TagName};
|
||||
use crate::can::pattern::{Pattern, RecordDestruct};
|
||||
use crate::collections::{ImMap, ImSet, SendMap};
|
||||
use crate::constrain::builtins;
|
||||
use crate::constrain::expr::{exists, Env, Info};
|
||||
use crate::constrain::expr::{exists, exists_with_aliases, Env, Info};
|
||||
use crate::module::symbol::{ModuleId, Symbol};
|
||||
use crate::region::{Located, Region};
|
||||
use crate::subs::{VarStore, Variable};
|
||||
@ -524,6 +524,7 @@ pub fn constrain_expr(
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: state.vars,
|
||||
def_types: state.headers,
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint,
|
||||
ret_constraint,
|
||||
})),
|
||||
@ -615,7 +616,7 @@ pub fn constrain_expr(
|
||||
]),
|
||||
)
|
||||
}
|
||||
LetRec(defs, loc_ret, var) => {
|
||||
LetRec(defs, loc_ret, var, aliases) => {
|
||||
// NOTE doesn't currently unregister bound symbols
|
||||
// may be a problem when symbols are not globally unique
|
||||
let body_con = constrain_expr(
|
||||
@ -627,7 +628,9 @@ pub fn constrain_expr(
|
||||
&loc_ret.value,
|
||||
expected.clone(),
|
||||
);
|
||||
exists(
|
||||
|
||||
exists_with_aliases(
|
||||
aliases.clone(),
|
||||
vec![*var],
|
||||
And(vec![
|
||||
constrain_recursive_defs(
|
||||
@ -644,7 +647,7 @@ pub fn constrain_expr(
|
||||
]),
|
||||
)
|
||||
}
|
||||
LetNonRec(def, loc_ret, var) => {
|
||||
LetNonRec(def, loc_ret, var, aliases) => {
|
||||
// NOTE doesn't currently unregister bound symbols
|
||||
// may be a problem when symbols are not globally unique
|
||||
let body_con = constrain_expr(
|
||||
@ -657,7 +660,8 @@ pub fn constrain_expr(
|
||||
expected.clone(),
|
||||
);
|
||||
|
||||
exists(
|
||||
exists_with_aliases(
|
||||
aliases.clone(),
|
||||
vec![*var],
|
||||
And(vec![
|
||||
constrain_def(
|
||||
@ -1212,6 +1216,7 @@ fn constrain_when_branch(
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: state.vars,
|
||||
def_types: state.headers,
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: Constraint::And(state.constraints),
|
||||
ret_constraint,
|
||||
}))
|
||||
@ -1420,10 +1425,12 @@ pub fn constrain_def(
|
||||
|
||||
pattern_state.vars.push(expr_var);
|
||||
|
||||
let mut def_aliases = SendMap::default();
|
||||
let mut new_rigids = Vec::new();
|
||||
|
||||
let expr_con = match &def.annotation {
|
||||
Some((annotation, free_vars)) => {
|
||||
Some((annotation, free_vars, ann_def_aliases)) => {
|
||||
def_aliases = ann_def_aliases.clone();
|
||||
let rigids = &env.rigids;
|
||||
let mut ftv: ImMap<Lowercase, Type> = rigids.clone();
|
||||
let (uniq_vars, annotation) = annotation_to_attr_type(var_store, annotation);
|
||||
@ -1482,10 +1489,12 @@ pub fn constrain_def(
|
||||
rigid_vars: new_rigids,
|
||||
flex_vars: pattern_state.vars,
|
||||
def_types: pattern_state.headers,
|
||||
def_aliases,
|
||||
defs_constraint: Let(Box::new(LetConstraint {
|
||||
rigid_vars: Vec::new(), // always empty
|
||||
flex_vars: Vec::new(), // empty, because our functions have no arguments
|
||||
def_types: SendMap::default(), // empty, because our functions have no arguments!
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: And(pattern_state.constraints),
|
||||
ret_constraint: expr_con,
|
||||
})),
|
||||
@ -1524,6 +1533,7 @@ pub fn rec_defs_help(
|
||||
mut rigid_info: Info,
|
||||
mut flex_info: Info,
|
||||
) -> Constraint {
|
||||
let mut def_aliases = SendMap::default();
|
||||
for def in defs {
|
||||
let expr_var = def.expr_var;
|
||||
let expr_type = Type::Variable(expr_var);
|
||||
@ -1545,6 +1555,7 @@ pub fn rec_defs_help(
|
||||
pattern_expected,
|
||||
);
|
||||
|
||||
// TODO see where aliases should go
|
||||
let mut new_rigids = Vec::new();
|
||||
match &def.annotation {
|
||||
None => {
|
||||
@ -1563,6 +1574,7 @@ pub fn rec_defs_help(
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: Vec::new(), // empty because Roc function defs have no args
|
||||
def_types: SendMap::default(), // empty because Roc function defs have no args
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: True, // I think this is correct, once again because there are no args
|
||||
ret_constraint: expr_con,
|
||||
}));
|
||||
@ -1572,7 +1584,11 @@ pub fn rec_defs_help(
|
||||
flex_info.def_types.extend(pattern_state.headers);
|
||||
}
|
||||
|
||||
Some((annotation, seen_rigids)) => {
|
||||
Some((annotation, seen_rigids, ann_def_aliases)) => {
|
||||
for (symbol, alias) in ann_def_aliases.clone() {
|
||||
def_aliases.insert(symbol, alias);
|
||||
}
|
||||
|
||||
let (uniq_vars, annotation) = annotation_to_attr_type(var_store, annotation);
|
||||
|
||||
// TODO also do this for more complex patterns
|
||||
@ -1657,6 +1673,7 @@ pub fn rec_defs_help(
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: Vec::new(), // empty because Roc function defs have no args
|
||||
def_types: SendMap::default(), // empty because Roc function defs have no args
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: True, // I think this is correct, once again because there are no args
|
||||
ret_constraint: expr_con,
|
||||
}));
|
||||
@ -1668,6 +1685,7 @@ pub fn rec_defs_help(
|
||||
rigid_vars: new_rigids,
|
||||
flex_vars: Vec::new(), // no flex vars introduced
|
||||
def_types: SendMap::default(), // no headers introduced (at this level)
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: def_con,
|
||||
ret_constraint: True,
|
||||
})));
|
||||
@ -1680,15 +1698,18 @@ pub fn rec_defs_help(
|
||||
rigid_vars: rigid_info.vars,
|
||||
flex_vars: Vec::new(),
|
||||
def_types: rigid_info.def_types,
|
||||
def_aliases,
|
||||
defs_constraint: True,
|
||||
ret_constraint: Let(Box::new(LetConstraint {
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: flex_info.vars,
|
||||
def_types: flex_info.def_types.clone(),
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: Let(Box::new(LetConstraint {
|
||||
rigid_vars: Vec::new(),
|
||||
flex_vars: Vec::new(),
|
||||
def_types: flex_info.def_types,
|
||||
def_aliases: SendMap::default(),
|
||||
defs_constraint: True,
|
||||
ret_constraint: And(flex_info.constraints),
|
||||
})),
|
||||
|
@ -338,11 +338,11 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) {
|
||||
annotate_usage(&loc_elem.value, usage);
|
||||
}
|
||||
}
|
||||
LetNonRec(def, loc_expr, _) => {
|
||||
LetNonRec(def, loc_expr, _, _) => {
|
||||
annotate_usage(&def.loc_expr.value, usage);
|
||||
annotate_usage(&loc_expr.value, usage);
|
||||
}
|
||||
LetRec(defs, loc_expr, _) => {
|
||||
LetRec(defs, loc_expr, _, _) => {
|
||||
// TODO test this with a practical example.
|
||||
if defs.len() == 1 {
|
||||
// just like a letrec, but mark defined symbol as Shared
|
||||
|
@ -222,7 +222,7 @@ mod test_canonicalize {
|
||||
|
||||
fn get_closure(expr: &Expr, i: usize) -> roc::can::expr::Recursive {
|
||||
match expr {
|
||||
LetRec(assignments, body, _) => {
|
||||
LetRec(assignments, body, _, _) => {
|
||||
match &assignments.get(i).map(|def| &def.loc_expr.value) {
|
||||
Some(Closure(_, _, recursion, _, _)) => recursion.clone(),
|
||||
Some(other @ _) => {
|
||||
@ -237,7 +237,7 @@ mod test_canonicalize {
|
||||
}
|
||||
}
|
||||
}
|
||||
LetNonRec(def, body, _) => {
|
||||
LetNonRec(def, body, _, _) => {
|
||||
if i > 0 {
|
||||
// recurse in the body (not the def!)
|
||||
get_closure(&body.value, i - 1)
|
||||
|
Loading…
Reference in New Issue
Block a user