mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 15:51:12 +00:00
Canonicalize with VarStore over Subs
This commit is contained in:
parent
acc0933c65
commit
e1fb0fa4e9
5 changed files with 99 additions and 58 deletions
|
@ -19,7 +19,7 @@ use crate::graph::{strongly_connected_component, topological_sort};
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::parse::ast::{self, Def};
|
use crate::parse::ast::{self, Def};
|
||||||
use crate::region::{Located, Region};
|
use crate::region::{Located, Region};
|
||||||
use crate::subs::{Subs, Variable};
|
use crate::subs::{VarStore, Variable};
|
||||||
use crate::types::AnnotationSource::*;
|
use crate::types::AnnotationSource::*;
|
||||||
use crate::types::Constraint::{self, *};
|
use crate::types::Constraint::{self, *};
|
||||||
use crate::types::Expected::{self, *};
|
use crate::types::Expected::{self, *};
|
||||||
|
@ -48,7 +48,7 @@ type Rigids = ImMap<Box<str>, Type>;
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn canonicalize_declaration<'a>(
|
pub fn canonicalize_declaration<'a>(
|
||||||
arena: &Bump,
|
arena: &Bump,
|
||||||
subs: &mut Subs,
|
var_store: &VarStore,
|
||||||
home: Box<str>,
|
home: Box<str>,
|
||||||
name: Box<str>,
|
name: Box<str>,
|
||||||
region: Region,
|
region: Region,
|
||||||
|
@ -74,7 +74,7 @@ pub fn canonicalize_declaration<'a>(
|
||||||
let (loc_expr, output) = canonicalize_expr(
|
let (loc_expr, output) = canonicalize_expr(
|
||||||
&ImMap::default(),
|
&ImMap::default(),
|
||||||
&mut env,
|
&mut env,
|
||||||
subs,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
region,
|
region,
|
||||||
&loc_expr.value,
|
&loc_expr.value,
|
||||||
|
@ -104,7 +104,7 @@ impl Output {
|
||||||
fn canonicalize_expr(
|
fn canonicalize_expr(
|
||||||
rigids: &Rigids,
|
rigids: &Rigids,
|
||||||
env: &mut Env,
|
env: &mut Env,
|
||||||
subs: &mut Subs,
|
var_store: &VarStore,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
region: Region,
|
region: Region,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
|
@ -115,13 +115,18 @@ fn canonicalize_expr(
|
||||||
let (expr, output) = match expr {
|
let (expr, output) = match expr {
|
||||||
ast::Expr::Int(string) => {
|
ast::Expr::Int(string) => {
|
||||||
let (constraint, answer) =
|
let (constraint, answer) =
|
||||||
int_expr_from_result(subs, finish_parsing_int(string), env, expected, region);
|
int_expr_from_result(var_store, finish_parsing_int(string), env, expected, region);
|
||||||
|
|
||||||
(answer, Output::new(constraint))
|
(answer, Output::new(constraint))
|
||||||
}
|
}
|
||||||
ast::Expr::Float(string) => {
|
ast::Expr::Float(string) => {
|
||||||
let (constraint, answer) =
|
let (constraint, answer) = float_expr_from_result(
|
||||||
float_expr_from_result(subs, finish_parsing_float(string), env, expected, region);
|
var_store,
|
||||||
|
finish_parsing_float(string),
|
||||||
|
env,
|
||||||
|
expected,
|
||||||
|
region,
|
||||||
|
);
|
||||||
|
|
||||||
(answer, Output::new(constraint))
|
(answer, Output::new(constraint))
|
||||||
}
|
}
|
||||||
|
@ -147,19 +152,19 @@ fn canonicalize_expr(
|
||||||
}
|
}
|
||||||
ast::Expr::List(loc_elems) => {
|
ast::Expr::List(loc_elems) => {
|
||||||
if loc_elems.is_empty() {
|
if loc_elems.is_empty() {
|
||||||
let list_var = subs.mk_flex_var();
|
let list_var = var_store.fresh();
|
||||||
let constraint = Eq(constrain::empty_list_type(list_var), expected, region);
|
let constraint = Eq(constrain::empty_list_type(list_var), expected, region);
|
||||||
|
|
||||||
(List(list_var, Vec::new()), Output::new(constraint))
|
(List(list_var, Vec::new()), Output::new(constraint))
|
||||||
} else {
|
} else {
|
||||||
let mut can_elems = Vec::with_capacity(loc_elems.len());
|
let mut can_elems = Vec::with_capacity(loc_elems.len());
|
||||||
let list_var = subs.mk_flex_var(); // `v` in the type (List v)
|
let list_var = var_store.fresh(); // `v` in the type (List v)
|
||||||
let list_type = Type::Variable(list_var);
|
let list_type = Type::Variable(list_var);
|
||||||
let mut constraints = Vec::with_capacity(1 + (loc_elems.len() * 2));
|
let mut constraints = Vec::with_capacity(1 + (loc_elems.len() * 2));
|
||||||
let mut references = References::new();
|
let mut references = References::new();
|
||||||
|
|
||||||
for loc_elem in loc_elems.iter() {
|
for loc_elem in loc_elems.iter() {
|
||||||
let elem_var = subs.mk_flex_var();
|
let elem_var = var_store.fresh();
|
||||||
let elem_type = Variable(elem_var);
|
let elem_type = Variable(elem_var);
|
||||||
let elem_expected = NoExpectation(elem_type.clone());
|
let elem_expected = NoExpectation(elem_type.clone());
|
||||||
let list_elem_constraint = Eq(
|
let list_elem_constraint = Eq(
|
||||||
|
@ -170,7 +175,7 @@ fn canonicalize_expr(
|
||||||
let (can_expr, elem_out) = canonicalize_expr(
|
let (can_expr, elem_out) = canonicalize_expr(
|
||||||
rigids,
|
rigids,
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
loc_elem.region,
|
loc_elem.region,
|
||||||
&loc_elem.value,
|
&loc_elem.value,
|
||||||
|
@ -229,7 +234,7 @@ fn canonicalize_expr(
|
||||||
ast::Expr::Apply(loc_fn, loc_args, application_style) => {
|
ast::Expr::Apply(loc_fn, loc_args, application_style) => {
|
||||||
// The expression that evaluates to the function being called, e.g. `foo` in
|
// The expression that evaluates to the function being called, e.g. `foo` in
|
||||||
// (foo) bar baz
|
// (foo) bar baz
|
||||||
let fn_var = subs.mk_flex_var();
|
let fn_var = var_store.fresh();
|
||||||
let fn_type = Variable(fn_var);
|
let fn_type = Variable(fn_var);
|
||||||
let fn_region = loc_fn.region;
|
let fn_region = loc_fn.region;
|
||||||
let fn_expected = NoExpectation(fn_type.clone());
|
let fn_expected = NoExpectation(fn_type.clone());
|
||||||
|
@ -242,7 +247,7 @@ fn canonicalize_expr(
|
||||||
let (fn_expr, mut output) = canonicalize_expr(
|
let (fn_expr, mut output) = canonicalize_expr(
|
||||||
rigids,
|
rigids,
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
loc_fn.region,
|
loc_fn.region,
|
||||||
&loc_fn.value,
|
&loc_fn.value,
|
||||||
|
@ -250,7 +255,7 @@ fn canonicalize_expr(
|
||||||
);
|
);
|
||||||
|
|
||||||
// The function's return type
|
// The function's return type
|
||||||
let ret_var = subs.mk_flex_var();
|
let ret_var = var_store.fresh();
|
||||||
let ret_type = Variable(ret_var);
|
let ret_type = Variable(ret_var);
|
||||||
|
|
||||||
// This will be used in the occurs check
|
// This will be used in the occurs check
|
||||||
|
@ -267,7 +272,7 @@ fn canonicalize_expr(
|
||||||
|
|
||||||
for (index, loc_arg) in loc_args.iter().enumerate() {
|
for (index, loc_arg) in loc_args.iter().enumerate() {
|
||||||
let region = loc_arg.region;
|
let region = loc_arg.region;
|
||||||
let arg_var = subs.mk_flex_var();
|
let arg_var = var_store.fresh();
|
||||||
let arg_type = Variable(arg_var);
|
let arg_type = Variable(arg_var);
|
||||||
// TODO look up the name and use NamedFnArg if possible.
|
// TODO look up the name and use NamedFnArg if possible.
|
||||||
let reason = Reason::AnonymousFnArg {
|
let reason = Reason::AnonymousFnArg {
|
||||||
|
@ -277,7 +282,7 @@ fn canonicalize_expr(
|
||||||
let (arg_expr, arg_out) = canonicalize_expr(
|
let (arg_expr, arg_out) = canonicalize_expr(
|
||||||
rigids,
|
rigids,
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
loc_arg.region,
|
loc_arg.region,
|
||||||
&loc_arg.value,
|
&loc_arg.value,
|
||||||
|
@ -354,7 +359,7 @@ fn canonicalize_expr(
|
||||||
let mut output = Output::new(Lookup(symbol, expected, region));
|
let mut output = Output::new(Lookup(symbol, expected, region));
|
||||||
let ident = Ident::new(module_parts, name);
|
let ident = Ident::new(module_parts, name);
|
||||||
let can_expr = match resolve_ident(&env, &scope, ident, &mut output.references) {
|
let can_expr = match resolve_ident(&env, &scope, ident, &mut output.references) {
|
||||||
Ok(symbol) => Var(subs.mk_flex_var(), symbol),
|
Ok(symbol) => Var(var_store.fresh(), symbol),
|
||||||
Err(ident) => {
|
Err(ident) => {
|
||||||
let loc_ident = Located {
|
let loc_ident = Located {
|
||||||
region,
|
region,
|
||||||
|
@ -454,7 +459,15 @@ fn canonicalize_expr(
|
||||||
ast::Expr::Defs(defs, loc_ret) => {
|
ast::Expr::Defs(defs, loc_ret) => {
|
||||||
// The body expression gets a new scope for canonicalization,
|
// The body expression gets a new scope for canonicalization,
|
||||||
// so clone it.
|
// so clone it.
|
||||||
can_defs(rigids, env, subs, scope.clone(), defs, expected, loc_ret)
|
can_defs(
|
||||||
|
rigids,
|
||||||
|
env,
|
||||||
|
var_store,
|
||||||
|
scope.clone(),
|
||||||
|
defs,
|
||||||
|
expected,
|
||||||
|
loc_ret,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ast::Expr::Closure(loc_arg_patterns, loc_body_expr) => {
|
ast::Expr::Closure(loc_arg_patterns, loc_body_expr) => {
|
||||||
// The globally unique symbol that will refer to this closure once it gets converted
|
// The globally unique symbol that will refer to this closure once it gets converted
|
||||||
|
@ -495,7 +508,7 @@ fn canonicalize_expr(
|
||||||
let mut shadowable_idents = scope.idents.clone();
|
let mut shadowable_idents = scope.idents.clone();
|
||||||
remove_idents(&loc_pattern.value, &mut shadowable_idents);
|
remove_idents(&loc_pattern.value, &mut shadowable_idents);
|
||||||
|
|
||||||
let pattern_var = subs.mk_flex_var();
|
let pattern_var = var_store.fresh();
|
||||||
let pattern_type = Type::Variable(pattern_var);
|
let pattern_type = Type::Variable(pattern_var);
|
||||||
let pattern_expected = PExpected::NoExpectation(pattern_type.clone());
|
let pattern_expected = PExpected::NoExpectation(pattern_type.clone());
|
||||||
|
|
||||||
|
@ -504,7 +517,7 @@ fn canonicalize_expr(
|
||||||
let can_arg = canonicalize_pattern(
|
let can_arg = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
&mut state,
|
&mut state,
|
||||||
subs,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
FunctionArg,
|
FunctionArg,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
|
@ -518,7 +531,7 @@ fn canonicalize_expr(
|
||||||
can_args.push(can_arg);
|
can_args.push(can_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret_var = subs.mk_flex_var();
|
let ret_var = var_store.fresh();
|
||||||
let ret_type = Type::Variable(ret_var);
|
let ret_type = Type::Variable(ret_var);
|
||||||
|
|
||||||
state.vars.push(ret_var);
|
state.vars.push(ret_var);
|
||||||
|
@ -529,7 +542,7 @@ fn canonicalize_expr(
|
||||||
let (loc_body_expr, mut output) = canonicalize_expr(
|
let (loc_body_expr, mut output) = canonicalize_expr(
|
||||||
rigids,
|
rigids,
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
loc_body_expr.region,
|
loc_body_expr.region,
|
||||||
&loc_body_expr.value,
|
&loc_body_expr.value,
|
||||||
|
@ -588,12 +601,12 @@ fn canonicalize_expr(
|
||||||
|
|
||||||
ast::Expr::Case(loc_cond, branches) => {
|
ast::Expr::Case(loc_cond, branches) => {
|
||||||
// Infer the condition expression's type.
|
// Infer the condition expression's type.
|
||||||
let cond_var = subs.mk_flex_var();
|
let cond_var = var_store.fresh();
|
||||||
let cond_type = Variable(cond_var);
|
let cond_type = Variable(cond_var);
|
||||||
let (can_cond, mut output) = canonicalize_expr(
|
let (can_cond, mut output) = canonicalize_expr(
|
||||||
rigids,
|
rigids,
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
region,
|
region,
|
||||||
&loc_cond.value,
|
&loc_cond.value,
|
||||||
|
@ -615,7 +628,7 @@ fn canonicalize_expr(
|
||||||
let (can_pattern, loc_can_expr, branch_con, branch_references) =
|
let (can_pattern, loc_can_expr, branch_con, branch_references) =
|
||||||
canonicalize_case_branch(
|
canonicalize_case_branch(
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
rigids,
|
rigids,
|
||||||
scope,
|
scope,
|
||||||
region,
|
region,
|
||||||
|
@ -649,7 +662,7 @@ fn canonicalize_expr(
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let branch_var = subs.mk_flex_var();
|
let branch_var = var_store.fresh();
|
||||||
let branch_type = Variable(branch_var);
|
let branch_type = Variable(branch_var);
|
||||||
let mut branch_cons = Vec::with_capacity(branches.len());
|
let mut branch_cons = Vec::with_capacity(branches.len());
|
||||||
|
|
||||||
|
@ -661,7 +674,7 @@ fn canonicalize_expr(
|
||||||
let (can_pattern, loc_can_expr, branch_con, branch_references) =
|
let (can_pattern, loc_can_expr, branch_con, branch_references) =
|
||||||
canonicalize_case_branch(
|
canonicalize_case_branch(
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
rigids,
|
rigids,
|
||||||
scope,
|
scope,
|
||||||
region,
|
region,
|
||||||
|
@ -737,17 +750,17 @@ fn canonicalize_expr(
|
||||||
}
|
}
|
||||||
ast::Expr::BinaryInt(string) => {
|
ast::Expr::BinaryInt(string) => {
|
||||||
let (constraint, answer) =
|
let (constraint, answer) =
|
||||||
int_expr_from_result(subs, finish_parsing_bin(string), env, expected, region);
|
int_expr_from_result(var_store, finish_parsing_bin(string), env, expected, region);
|
||||||
(answer, Output::new(constraint))
|
(answer, Output::new(constraint))
|
||||||
}
|
}
|
||||||
ast::Expr::HexInt(string) => {
|
ast::Expr::HexInt(string) => {
|
||||||
let (constraint, answer) =
|
let (constraint, answer) =
|
||||||
int_expr_from_result(subs, finish_parsing_hex(string), env, expected, region);
|
int_expr_from_result(var_store, finish_parsing_hex(string), env, expected, region);
|
||||||
(answer, Output::new(constraint))
|
(answer, Output::new(constraint))
|
||||||
}
|
}
|
||||||
ast::Expr::OctalInt(string) => {
|
ast::Expr::OctalInt(string) => {
|
||||||
let (constraint, answer) =
|
let (constraint, answer) =
|
||||||
int_expr_from_result(subs, finish_parsing_oct(string), env, expected, region);
|
int_expr_from_result(var_store, finish_parsing_oct(string), env, expected, region);
|
||||||
(answer, Output::new(constraint))
|
(answer, Output::new(constraint))
|
||||||
}
|
}
|
||||||
// Below this point, we shouln't see any of these nodes anymore because
|
// Below this point, we shouln't see any of these nodes anymore because
|
||||||
|
@ -805,7 +818,7 @@ fn canonicalize_expr(
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn canonicalize_case_branch<'a>(
|
fn canonicalize_case_branch<'a>(
|
||||||
env: &mut Env,
|
env: &mut Env,
|
||||||
subs: &mut Subs,
|
var_store: &VarStore,
|
||||||
rigids: &Rigids,
|
rigids: &Rigids,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
region: Region,
|
region: Region,
|
||||||
|
@ -836,7 +849,7 @@ fn canonicalize_case_branch<'a>(
|
||||||
let (can_expr, branch_output) = canonicalize_expr(
|
let (can_expr, branch_output) = canonicalize_expr(
|
||||||
rigids,
|
rigids,
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
region,
|
region,
|
||||||
&loc_expr.value,
|
&loc_expr.value,
|
||||||
|
@ -871,7 +884,7 @@ fn canonicalize_case_branch<'a>(
|
||||||
let loc_can_pattern = canonicalize_pattern(
|
let loc_can_pattern = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
&mut state,
|
&mut state,
|
||||||
subs,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
CaseBranch,
|
CaseBranch,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
|
@ -1363,7 +1376,7 @@ fn closure_recursivity(symbol: Symbol, closures: &MutMap<Symbol, References>) ->
|
||||||
fn can_defs<'a>(
|
fn can_defs<'a>(
|
||||||
rigids: &Rigids,
|
rigids: &Rigids,
|
||||||
env: &mut Env,
|
env: &mut Env,
|
||||||
subs: &mut Subs,
|
var_store: &VarStore,
|
||||||
scope: Scope,
|
scope: Scope,
|
||||||
defs: &'a bumpalo::collections::Vec<'a, &'a Located<Def<'a>>>,
|
defs: &'a bumpalo::collections::Vec<'a, &'a Located<Def<'a>>>,
|
||||||
expected: Expected<Type>,
|
expected: Expected<Type>,
|
||||||
|
@ -1394,7 +1407,7 @@ fn can_defs<'a>(
|
||||||
|
|
||||||
for loc_def in iter {
|
for loc_def in iter {
|
||||||
// Make types for the body expr, even if we won't end up having a body.
|
// Make types for the body expr, even if we won't end up having a body.
|
||||||
let expr_var = subs.mk_flex_var();
|
let expr_var = var_store.fresh();
|
||||||
let expr_type = Type::Variable(expr_var);
|
let expr_type = Type::Variable(expr_var);
|
||||||
|
|
||||||
// Each def gets to have all the idents in scope that are defined in this
|
// Each def gets to have all the idents in scope that are defined in this
|
||||||
|
@ -1437,7 +1450,7 @@ fn can_defs<'a>(
|
||||||
let mut shadowable_idents = scope.idents.clone();
|
let mut shadowable_idents = scope.idents.clone();
|
||||||
remove_idents(&loc_pattern.value, &mut shadowable_idents);
|
remove_idents(&loc_pattern.value, &mut shadowable_idents);
|
||||||
|
|
||||||
let pattern_var = subs.mk_flex_var();
|
let pattern_var = var_store.fresh();
|
||||||
let pattern_type = Type::Variable(pattern_var);
|
let pattern_type = Type::Variable(pattern_var);
|
||||||
let pattern_expected = PExpected::NoExpectation(pattern_type);
|
let pattern_expected = PExpected::NoExpectation(pattern_type);
|
||||||
|
|
||||||
|
@ -1450,7 +1463,7 @@ fn can_defs<'a>(
|
||||||
let loc_can_pattern = canonicalize_pattern(
|
let loc_can_pattern = canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
&mut state,
|
&mut state,
|
||||||
subs,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
Assignment,
|
Assignment,
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
|
@ -1487,7 +1500,7 @@ fn can_defs<'a>(
|
||||||
let (mut loc_can_expr, can_output) = canonicalize_expr(
|
let (mut loc_can_expr, can_output) = canonicalize_expr(
|
||||||
rigids,
|
rigids,
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
loc_expr.region,
|
loc_expr.region,
|
||||||
&loc_expr.value,
|
&loc_expr.value,
|
||||||
|
@ -1625,7 +1638,7 @@ fn can_defs<'a>(
|
||||||
let (ret_expr, mut output) = canonicalize_expr(
|
let (ret_expr, mut output) = canonicalize_expr(
|
||||||
rigids,
|
rigids,
|
||||||
env,
|
env,
|
||||||
subs,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
loc_ret.region,
|
loc_ret.region,
|
||||||
&loc_ret.value,
|
&loc_ret.value,
|
||||||
|
@ -1758,7 +1771,7 @@ fn can_defs<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
Defs(subs.mk_flex_var(), can_defs, Box::new(ret_expr)),
|
Defs(var_store.fresh(), can_defs, Box::new(ret_expr)),
|
||||||
output,
|
output,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::can::problem::Problem;
|
||||||
use crate::can::problem::RuntimeError::*;
|
use crate::can::problem::RuntimeError::*;
|
||||||
use crate::constrain;
|
use crate::constrain;
|
||||||
use crate::region::Region;
|
use crate::region::Region;
|
||||||
use crate::subs::Subs;
|
use crate::subs::VarStore;
|
||||||
use crate::types::Constraint::{self, *};
|
use crate::types::Constraint::{self, *};
|
||||||
use crate::types::Expected;
|
use crate::types::Expected;
|
||||||
use crate::types::Type;
|
use crate::types::Type;
|
||||||
|
@ -12,7 +12,7 @@ use std::i64;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn int_expr_from_result(
|
pub fn int_expr_from_result(
|
||||||
subs: &mut Subs,
|
var_store: &VarStore,
|
||||||
result: Result<i64, &str>,
|
result: Result<i64, &str>,
|
||||||
env: &mut Env,
|
env: &mut Env,
|
||||||
expected: Expected<Type>,
|
expected: Expected<Type>,
|
||||||
|
@ -20,7 +20,7 @@ pub fn int_expr_from_result(
|
||||||
) -> (Constraint, Expr) {
|
) -> (Constraint, Expr) {
|
||||||
match result {
|
match result {
|
||||||
Ok(int) => (
|
Ok(int) => (
|
||||||
constrain::int_literal(subs, expected, region),
|
constrain::int_literal(var_store, expected, region),
|
||||||
Expr::Int(int),
|
Expr::Int(int),
|
||||||
),
|
),
|
||||||
Err(raw) => {
|
Err(raw) => {
|
||||||
|
@ -35,7 +35,7 @@ pub fn int_expr_from_result(
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn float_expr_from_result(
|
pub fn float_expr_from_result(
|
||||||
subs: &mut Subs,
|
var_store: &VarStore,
|
||||||
result: Result<f64, &str>,
|
result: Result<f64, &str>,
|
||||||
env: &mut Env,
|
env: &mut Env,
|
||||||
expected: Expected<Type>,
|
expected: Expected<Type>,
|
||||||
|
@ -43,7 +43,7 @@ pub fn float_expr_from_result(
|
||||||
) -> (Constraint, Expr) {
|
) -> (Constraint, Expr) {
|
||||||
match result {
|
match result {
|
||||||
Ok(float) => (
|
Ok(float) => (
|
||||||
constrain::float_literal(subs, expected, region),
|
constrain::float_literal(var_store, expected, region),
|
||||||
Expr::Float(float),
|
Expr::Float(float),
|
||||||
),
|
),
|
||||||
Err(raw) => {
|
Err(raw) => {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::collections::ImMap;
|
||||||
use crate::ident::{Ident, VariantName};
|
use crate::ident::{Ident, VariantName};
|
||||||
use crate::parse::ast;
|
use crate::parse::ast;
|
||||||
use crate::region::{Located, Region};
|
use crate::region::{Located, Region};
|
||||||
use crate::subs::Subs;
|
use crate::subs::VarStore;
|
||||||
use crate::subs::Variable;
|
use crate::subs::Variable;
|
||||||
use crate::types::{Constraint, PExpected, PatternCategory, Type};
|
use crate::types::{Constraint, PExpected, PatternCategory, Type};
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ pub enum PatternType {
|
||||||
pub fn canonicalize_pattern<'a>(
|
pub fn canonicalize_pattern<'a>(
|
||||||
env: &'a mut Env,
|
env: &'a mut Env,
|
||||||
state: &'a mut PatternState,
|
state: &'a mut PatternState,
|
||||||
subs: &mut Subs,
|
var_store: &VarStore,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
pattern: &'a ast::Pattern<'a>,
|
pattern: &'a ast::Pattern<'a>,
|
||||||
|
@ -125,7 +125,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
.insert(new_ident.clone(), symbol_and_region.clone());
|
.insert(new_ident.clone(), symbol_and_region.clone());
|
||||||
shadowable_idents.insert(new_ident, symbol_and_region.clone());
|
shadowable_idents.insert(new_ident, symbol_and_region.clone());
|
||||||
|
|
||||||
Pattern::Identifier(subs.mk_flex_var(), symbol)
|
Pattern::Identifier(var_store.fresh(), symbol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
|
|
||||||
if env.variants.contains_key(&symbol) {
|
if env.variants.contains_key(&symbol) {
|
||||||
// No problems; the qualified variant name was in scope!
|
// No problems; the qualified variant name was in scope!
|
||||||
Pattern::Variant(subs.mk_flex_var(), symbol)
|
Pattern::Variant(var_store.fresh(), symbol)
|
||||||
} else {
|
} else {
|
||||||
let loc_name = Located {
|
let loc_name = Located {
|
||||||
region,
|
region,
|
||||||
|
@ -192,7 +192,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
},
|
},
|
||||||
|
|
||||||
&Underscore => match pattern_type {
|
&Underscore => match pattern_type {
|
||||||
CaseBranch | FunctionArg => Pattern::Underscore(subs.mk_flex_var()),
|
CaseBranch | FunctionArg => Pattern::Underscore(var_store.fresh()),
|
||||||
Assignment => unsupported_pattern(env, Assignment, region),
|
Assignment => unsupported_pattern(env, Assignment, region),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ pub fn canonicalize_pattern<'a>(
|
||||||
return canonicalize_pattern(
|
return canonicalize_pattern(
|
||||||
env,
|
env,
|
||||||
state,
|
state,
|
||||||
subs,
|
var_store,
|
||||||
scope,
|
scope,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
sub_pattern,
|
sub_pattern,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::collections::ImMap;
|
use crate::collections::ImMap;
|
||||||
use crate::region::Region;
|
use crate::region::Region;
|
||||||
use crate::subs::{Subs, Variable};
|
use crate::subs::{VarStore, Variable};
|
||||||
use crate::types::Constraint::{self, *};
|
use crate::types::Constraint::{self, *};
|
||||||
use crate::types::Expected::{self, *};
|
use crate::types::Expected::{self, *};
|
||||||
use crate::types::Type::{self, *};
|
use crate::types::Type::{self, *};
|
||||||
|
@ -16,30 +16,30 @@ pub fn exists(flex_vars: Vec<Variable>, constraint: Constraint) -> Constraint {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn int_literal(subs: &mut Subs, expected: Expected<Type>, region: Region) -> Constraint {
|
pub fn int_literal(var_store: &VarStore, expected: Expected<Type>, region: Region) -> Constraint {
|
||||||
let typ = number_literal_type("Int", "Integer");
|
let typ = number_literal_type("Int", "Integer");
|
||||||
let reason = Reason::IntLiteral;
|
let reason = Reason::IntLiteral;
|
||||||
|
|
||||||
num_literal(subs, typ, reason, expected, region)
|
num_literal(var_store, typ, reason, expected, region)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn float_literal(subs: &mut Subs, expected: Expected<Type>, region: Region) -> Constraint {
|
pub fn float_literal(var_store: &VarStore, expected: Expected<Type>, region: Region) -> Constraint {
|
||||||
let typ = number_literal_type("Float", "FloatingPoint");
|
let typ = number_literal_type("Float", "FloatingPoint");
|
||||||
let reason = Reason::FloatLiteral;
|
let reason = Reason::FloatLiteral;
|
||||||
|
|
||||||
num_literal(subs, typ, reason, expected, region)
|
num_literal(var_store, typ, reason, expected, region)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn num_literal(
|
fn num_literal(
|
||||||
subs: &mut Subs,
|
var_store: &VarStore,
|
||||||
literal_type: Type,
|
literal_type: Type,
|
||||||
reason: Reason,
|
reason: Reason,
|
||||||
expected: Expected<Type>,
|
expected: Expected<Type>,
|
||||||
region: Region,
|
region: Region,
|
||||||
) -> Constraint {
|
) -> Constraint {
|
||||||
let num_var = subs.mk_flex_var();
|
let num_var = var_store.fresh();
|
||||||
let num_type = Variable(num_var);
|
let num_type = Variable(num_var);
|
||||||
let expected_literal = ForReason(reason, literal_type, region);
|
let expected_literal = ForReason(reason, literal_type, region);
|
||||||
|
|
||||||
|
|
28
src/subs.rs
28
src/subs.rs
|
@ -2,12 +2,40 @@ use crate::ena::unify::{InPlace, UnificationTable, UnifyKey};
|
||||||
use crate::types::Problem;
|
use crate::types::Problem;
|
||||||
use crate::unify;
|
use crate::unify;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Subs {
|
pub struct Subs {
|
||||||
utable: UnificationTable<InPlace<Variable>>,
|
utable: UnificationTable<InPlace<Variable>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct VarStore {
|
||||||
|
next: AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarStore {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
VarStore {
|
||||||
|
next: AtomicUsize::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fresh(&self) -> Variable {
|
||||||
|
// Increment the counter and return the previous value.
|
||||||
|
//
|
||||||
|
// Since the counter starts at 0, this will return 0 on first invocation,
|
||||||
|
// and var_store.into() will return the number of Variables distributed
|
||||||
|
// (in this case, 1).
|
||||||
|
Variable(AtomicUsize::fetch_add(&self.next, 1, Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Variable> for VarStore {
|
||||||
|
fn into(self) -> Variable {
|
||||||
|
Variable(self.next.into_inner())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, PartialEq, Eq, Clone, Hash)]
|
#[derive(Copy, PartialEq, Eq, Clone, Hash)]
|
||||||
pub struct Variable(usize);
|
pub struct Variable(usize);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue