mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
Update solve and unify
This commit is contained in:
parent
c41167ec6e
commit
5eb843326c
4 changed files with 188 additions and 115 deletions
51
src/can/ident.rs
Normal file
51
src/can/ident.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
use crate::ident::UnqualifiedIdent;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub struct ModuleName(Box<str>);
|
||||||
|
|
||||||
|
/// An uncapitalized identifier, such as a field name or local variable
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub struct Lowercase(Box<str>);
|
||||||
|
|
||||||
|
/// A capitalized identifier, such as a tag name or module name
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub struct Uppercase(Box<str>);
|
||||||
|
|
||||||
|
impl Lowercase {
|
||||||
|
pub fn from_unqualified_ident(ident: &UnqualifiedIdent<'_>) -> Self {
|
||||||
|
Self(ident.as_str().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Box<str>> for Lowercase {
|
||||||
|
fn into(self) -> Box<str> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rather than displaying as this:
|
||||||
|
///
|
||||||
|
/// Lowercase("foo")
|
||||||
|
///
|
||||||
|
/// ...instead display as this:
|
||||||
|
///
|
||||||
|
/// 'foo'
|
||||||
|
impl fmt::Debug for Lowercase {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "'{}'", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rather than displaying as this:
|
||||||
|
///
|
||||||
|
/// Uppercase("Foo")
|
||||||
|
///
|
||||||
|
/// ...instead display as this:
|
||||||
|
///
|
||||||
|
/// 'Foo'
|
||||||
|
impl fmt::Debug for Uppercase {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "'{}'", self.0)
|
||||||
|
}
|
||||||
|
}
|
33
src/solve.rs
33
src/solve.rs
|
@ -3,6 +3,7 @@ use crate::collections::ImMap;
|
||||||
use crate::subs::{Content, Descriptor, FlatType, Subs, Variable};
|
use crate::subs::{Content, Descriptor, FlatType, Subs, Variable};
|
||||||
use crate::types::Constraint::{self, *};
|
use crate::types::Constraint::{self, *};
|
||||||
use crate::types::Type::{self, *};
|
use crate::types::Type::{self, *};
|
||||||
|
use crate::unify::unify;
|
||||||
|
|
||||||
type Env = ImMap<Symbol, Variable>;
|
type Env = ImMap<Symbol, Variable>;
|
||||||
|
|
||||||
|
@ -11,10 +12,10 @@ pub fn solve(env: &Env, subs: &mut Subs, constraint: &Constraint) {
|
||||||
True => (),
|
True => (),
|
||||||
Eq(typ, expected_type, _region) => {
|
Eq(typ, expected_type, _region) => {
|
||||||
// TODO use region?
|
// TODO use region?
|
||||||
let actual = type_to_variable(subs, typ.clone());
|
let actual = type_to_var(subs, typ.clone());
|
||||||
let expected = type_to_variable(subs, expected_type.clone().get_type());
|
let expected = type_to_var(subs, expected_type.clone().get_type());
|
||||||
|
|
||||||
subs.union(actual, expected);
|
unify(subs, actual, expected);
|
||||||
}
|
}
|
||||||
Lookup(symbol, expected_type, _region) => {
|
Lookup(symbol, expected_type, _region) => {
|
||||||
// TODO use region?
|
// TODO use region?
|
||||||
|
@ -22,9 +23,9 @@ pub fn solve(env: &Env, subs: &mut Subs, constraint: &Constraint) {
|
||||||
subs.copy_var(*env.get(&symbol).unwrap_or_else(|| {
|
subs.copy_var(*env.get(&symbol).unwrap_or_else(|| {
|
||||||
panic!("Could not find symbol {:?} in env {:?}", symbol, env)
|
panic!("Could not find symbol {:?} in env {:?}", symbol, env)
|
||||||
}));
|
}));
|
||||||
let expected = type_to_variable(subs, expected_type.clone().get_type());
|
let expected = type_to_var(subs, expected_type.clone().get_type());
|
||||||
|
|
||||||
subs.union(actual, expected);
|
unify(subs, actual, expected);
|
||||||
}
|
}
|
||||||
And(sub_constraints) => {
|
And(sub_constraints) => {
|
||||||
for sub_constraint in sub_constraints.iter() {
|
for sub_constraint in sub_constraints.iter() {
|
||||||
|
@ -33,10 +34,10 @@ pub fn solve(env: &Env, subs: &mut Subs, constraint: &Constraint) {
|
||||||
}
|
}
|
||||||
Pattern(_region, _category, typ, expected) => {
|
Pattern(_region, _category, typ, expected) => {
|
||||||
// TODO use region?
|
// TODO use region?
|
||||||
let actual = type_to_variable(subs, typ.clone());
|
let actual = type_to_var(subs, typ.clone());
|
||||||
let expected = type_to_variable(subs, expected.clone().get_type());
|
let expected = type_to_var(subs, expected.clone().get_type());
|
||||||
|
|
||||||
subs.union(actual, expected);
|
unify(subs, actual, expected);
|
||||||
}
|
}
|
||||||
Let(let_con) => {
|
Let(let_con) => {
|
||||||
match &let_con.ret_constraint {
|
match &let_con.ret_constraint {
|
||||||
|
@ -58,7 +59,7 @@ pub fn solve(env: &Env, subs: &mut Subs, constraint: &Constraint) {
|
||||||
// inserted earlier in solving. (If we allowed
|
// inserted earlier in solving. (If we allowed
|
||||||
// shadowing, we'd need to do something fancier here.)
|
// shadowing, we'd need to do something fancier here.)
|
||||||
if !new_env.contains_key(&symbol) {
|
if !new_env.contains_key(&symbol) {
|
||||||
let var = type_to_variable(subs, loc_type.value.clone());
|
let var = type_to_var(subs, loc_type.value.clone());
|
||||||
|
|
||||||
new_env.insert(symbol.clone(), var);
|
new_env.insert(symbol.clone(), var);
|
||||||
}
|
}
|
||||||
|
@ -75,7 +76,11 @@ pub fn solve(env: &Env, subs: &mut Subs, constraint: &Constraint) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_to_variable(subs: &mut Subs, typ: Type) -> Variable {
|
fn type_to_var(subs: &mut Subs, typ: Type) -> Variable {
|
||||||
|
type_to_variable(subs, &ImMap::default(), typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_to_variable(subs: &mut Subs, aliases: &ImMap<Box<str>, Variable>, typ: Type) -> Variable {
|
||||||
match typ {
|
match typ {
|
||||||
Variable(var) => var,
|
Variable(var) => var,
|
||||||
Apply {
|
Apply {
|
||||||
|
@ -86,7 +91,7 @@ fn type_to_variable(subs: &mut Subs, typ: Type) -> Variable {
|
||||||
let mut arg_vars = Vec::with_capacity(args.len());
|
let mut arg_vars = Vec::with_capacity(args.len());
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
arg_vars.push(type_to_variable(subs, arg.clone()))
|
arg_vars.push(type_to_variable(subs, aliases, arg.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
let flat_type = FlatType::Apply {
|
let flat_type = FlatType::Apply {
|
||||||
|
@ -107,11 +112,11 @@ fn type_to_variable(subs: &mut Subs, typ: Type) -> Variable {
|
||||||
let mut arg_vars = Vec::with_capacity(args.len());
|
let mut arg_vars = Vec::with_capacity(args.len());
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
arg_vars.push(type_to_variable(subs, arg.clone()))
|
arg_vars.push(type_to_variable(subs, aliases, arg.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret_var = type_to_variable(subs, *ret_type);
|
let ret_var = type_to_variable(subs, aliases, *ret_type);
|
||||||
let content: Content = Content::Structure(FlatType::Func(arg_vars, ret_var));
|
let content = Content::Structure(FlatType::Func(arg_vars, ret_var));
|
||||||
|
|
||||||
subs.fresh(Descriptor::from(content))
|
subs.fresh(Descriptor::from(content))
|
||||||
}
|
}
|
||||||
|
|
80
src/subs.rs
80
src/subs.rs
|
@ -1,9 +1,47 @@
|
||||||
use crate::ena::unify::{InPlace, UnificationTable, UnifyKey};
|
use crate::ena::unify::{InPlace, UnificationTable, UnifyKey};
|
||||||
use crate::types::Problem;
|
use crate::types::Problem;
|
||||||
use crate::unify;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
|
pub struct Mark(u8);
|
||||||
|
|
||||||
|
impl Mark {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn none() -> Mark {
|
||||||
|
Mark(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn occurs() -> Mark {
|
||||||
|
Mark(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_var_names() -> Mark {
|
||||||
|
Mark(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn next(self) -> Mark {
|
||||||
|
Mark(self.0 - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Mark {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self == &Mark::none() {
|
||||||
|
write!(f, "Mark::none")
|
||||||
|
} else if self == &Mark::occurs() {
|
||||||
|
write!(f, "Mark::occurs")
|
||||||
|
} else if self == &Mark::get_var_names() {
|
||||||
|
write!(f, "Mark::get_var_names")
|
||||||
|
} else {
|
||||||
|
write!(f, "Mark({})", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Subs {
|
pub struct Subs {
|
||||||
utable: UnificationTable<InPlace<Variable>>,
|
utable: UnificationTable<InPlace<Variable>>,
|
||||||
|
@ -91,15 +129,11 @@ impl Subs {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unions two keys without the possibility of failure.
|
/// Unions two keys without the possibility of failure.
|
||||||
pub fn union(&mut self, left: Variable, right: Variable) {
|
pub fn union(&mut self, left: Variable, right: Variable, desc: Descriptor) {
|
||||||
let l_root = self.utable.get_root_key(left);
|
let l_root = self.utable.get_root_key(left);
|
||||||
let r_root = self.utable.get_root_key(right);
|
let r_root = self.utable.get_root_key(right);
|
||||||
|
|
||||||
if l_root != r_root {
|
self.utable.unify_roots(l_root, r_root, desc)
|
||||||
let combined = unify::unify_vars(self, l_root, r_root);
|
|
||||||
|
|
||||||
self.utable.unify_roots(l_root, r_root, combined)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&mut self, key: Variable) -> Descriptor {
|
pub fn get(&mut self, key: Variable) -> Descriptor {
|
||||||
|
@ -112,9 +146,8 @@ impl Subs {
|
||||||
|
|
||||||
pub fn set(&mut self, key: Variable, r_value: Descriptor) {
|
pub fn set(&mut self, key: Variable, r_value: Descriptor) {
|
||||||
let l_key = self.utable.get_root_key(key);
|
let l_key = self.utable.get_root_key(key);
|
||||||
let unified = unify::unify_var_val(self, l_key, &r_value);
|
|
||||||
|
|
||||||
self.utable.update_value(l_key, |node| node.value = unified);
|
self.utable.update_value(l_key, |node| node.value = r_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_var(&mut self, var: Variable) -> Variable {
|
pub fn copy_var(&mut self, var: Variable) -> Variable {
|
||||||
|
@ -123,20 +156,9 @@ impl Subs {
|
||||||
var
|
var
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn set_rank(&mut self, key: Variable, rank: usize) {
|
pub fn equivalent(&mut self, left: Variable, right: Variable) -> bool {
|
||||||
// let mut descriptor = self.utable.probe_value(key);
|
self.utable.unioned(left, right)
|
||||||
|
}
|
||||||
// descriptor.rank = rank;
|
|
||||||
|
|
||||||
// let result = self.utable.unify_var_value(key, descriptor);
|
|
||||||
|
|
||||||
// // Updating the rank should never fail!
|
|
||||||
// debug_assert_eq!(result, Ok(()));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn equivalent(&mut self, left: Variable, right: Variable) -> bool {
|
|
||||||
// self.utable.unioned(left, right)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -152,17 +174,23 @@ fn unnamed_flex_var() -> Content {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Descriptor {
|
pub struct Descriptor {
|
||||||
pub content: Content,
|
pub content: Content,
|
||||||
pub rank: usize,
|
pub rank: u8,
|
||||||
pub mark: u32,
|
pub mark: Mark,
|
||||||
pub copy: Option<Variable>,
|
pub copy: Option<Variable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Descriptor {
|
||||||
|
fn default() -> Self {
|
||||||
|
unnamed_flex_var().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Content> for Descriptor {
|
impl From<Content> for Descriptor {
|
||||||
fn from(content: Content) -> Descriptor {
|
fn from(content: Content) -> Descriptor {
|
||||||
Descriptor {
|
Descriptor {
|
||||||
content,
|
content,
|
||||||
rank: 0,
|
rank: 0,
|
||||||
mark: 2, // no mark
|
mark: Mark::none(),
|
||||||
copy: None,
|
copy: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
139
src/unify.rs
139
src/unify.rs
|
@ -1,61 +1,68 @@
|
||||||
use crate::subs::Content::{self, *};
|
use crate::subs::Content::{self, *};
|
||||||
use crate::subs::{Descriptor, FlatType, Subs, Variable};
|
use crate::subs::{Descriptor, FlatType, Mark, Subs, Variable};
|
||||||
use crate::types::Problem;
|
use crate::types::Problem;
|
||||||
|
|
||||||
#[inline(always)]
|
struct Context {
|
||||||
pub fn unify_vars(subs: &mut Subs, left_key: Variable, right_key: Variable) -> Descriptor {
|
first: Variable,
|
||||||
let right = subs.get(right_key);
|
first_desc: Descriptor,
|
||||||
|
second: Variable,
|
||||||
unify_var_val(subs, left_key, &right)
|
second_desc: Descriptor,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn unify_var_val(subs: &mut Subs, left_key: Variable, right: &Descriptor) -> Descriptor {
|
pub fn unify(subs: &mut Subs, var1: Variable, var2: Variable) {
|
||||||
let left = subs.get(left_key);
|
if !subs.equivalent(var1, var2) {
|
||||||
|
let ctx = Context {
|
||||||
|
first: var1,
|
||||||
|
first_desc: subs.get(var1),
|
||||||
|
second: var2,
|
||||||
|
second_desc: subs.get(var2),
|
||||||
|
};
|
||||||
|
|
||||||
unify(subs, &left, right)
|
unify_context(subs, &ctx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify(subs: &mut Subs, left: &Descriptor, right: &Descriptor) -> Descriptor {
|
fn unify_context(subs: &mut Subs, ctx: &Context) {
|
||||||
match left.content {
|
match ctx.first_desc.content {
|
||||||
FlexVar(ref opt_name) => unify_flex(opt_name, &right.content),
|
FlexVar(ref opt_name) => unify_flex(subs, ctx, opt_name, &ctx.second_desc.content),
|
||||||
RigidVar(ref name) => unify_rigid(name, &right.content),
|
RigidVar(ref name) => unify_rigid(subs, ctx, name, &ctx.second_desc.content),
|
||||||
Structure(ref flat_type) => unify_structure(subs, flat_type, &right.content),
|
Structure(ref flat_type) => unify_structure(subs, ctx, flat_type, &ctx.second_desc.content),
|
||||||
Error(ref problem) => {
|
Error(ref problem) => {
|
||||||
// Error propagates. Whatever we're comparing it to doesn't matter!
|
// Error propagates. Whatever we're comparing it to doesn't matter!
|
||||||
from_content(Error(problem.clone()))
|
merge(subs, ctx, Error(problem.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn unify_structure(subs: &mut Subs, flat_type: &FlatType, other: &Content) -> Descriptor {
|
fn unify_structure(subs: &mut Subs, ctx: &Context, flat_type: &FlatType, other: &Content) {
|
||||||
match other {
|
match other {
|
||||||
FlexVar(_) => {
|
FlexVar(_) => {
|
||||||
// If the other is flex, Structure wins!
|
// If the other is flex, Structure wins!
|
||||||
from_content(Structure(flat_type.clone()))
|
merge(subs, ctx, Structure(flat_type.clone()))
|
||||||
}
|
}
|
||||||
RigidVar(_) => {
|
RigidVar(_) => {
|
||||||
// Type mismatch! Rigid can only unify with flex.
|
// Type mismatch! Rigid can only unify with flex.
|
||||||
from_content(Error(Problem::GenericMismatch))
|
merge(subs, ctx, Error(Problem::GenericMismatch))
|
||||||
}
|
}
|
||||||
Structure(ref other_flat_type) => {
|
Structure(ref other_flat_type) => {
|
||||||
// Unify the two flat types
|
// Unify the two flat types
|
||||||
unify_flat_type(subs, flat_type, other_flat_type)
|
unify_flat_type(subs, ctx, flat_type, other_flat_type)
|
||||||
}
|
}
|
||||||
Error(problem) => {
|
Error(problem) => {
|
||||||
// Error propagates.
|
// Error propagates.
|
||||||
from_content(Error(problem.clone()))
|
merge(subs, ctx, Error(problem.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn unify_flat_type(subs: &mut Subs, left: &FlatType, right: &FlatType) -> Descriptor {
|
fn unify_flat_type(subs: &mut Subs, ctx: &Context, left: &FlatType, right: &FlatType) {
|
||||||
use crate::subs::FlatType::*;
|
use crate::subs::FlatType::*;
|
||||||
|
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
(EmptyRecord, EmptyRecord) => from_content(Structure(left.clone())),
|
(EmptyRecord, EmptyRecord) => merge(subs, ctx, Structure(left.clone())),
|
||||||
(
|
(
|
||||||
Apply {
|
Apply {
|
||||||
module_name: l_module_name,
|
module_name: l_module_name,
|
||||||
|
@ -68,103 +75,85 @@ fn unify_flat_type(subs: &mut Subs, left: &FlatType, right: &FlatType) -> Descri
|
||||||
args: r_args,
|
args: r_args,
|
||||||
},
|
},
|
||||||
) if l_module_name == r_module_name && l_type_name == r_type_name => {
|
) if l_module_name == r_module_name && l_type_name == r_type_name => {
|
||||||
let args = unify_args(subs, l_args.iter(), r_args.iter());
|
unify_zip(subs, l_args.iter(), r_args.iter());
|
||||||
let flat_type = Apply {
|
|
||||||
module_name: l_module_name.clone(),
|
|
||||||
name: l_type_name.clone(),
|
|
||||||
args,
|
|
||||||
};
|
|
||||||
|
|
||||||
from_content(Structure(flat_type))
|
merge(
|
||||||
|
subs,
|
||||||
|
ctx,
|
||||||
|
Structure(Apply {
|
||||||
|
module_name: (*r_module_name).clone(),
|
||||||
|
name: (*r_type_name).clone(),
|
||||||
|
args: (*r_args).clone(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
(Func(l_args, l_ret), Func(r_args, r_ret)) => {
|
(Func(l_args, l_ret), Func(r_args, r_ret)) => {
|
||||||
if l_args.len() == r_args.len() {
|
if l_args.len() == r_args.len() {
|
||||||
let args = unify_args(subs, l_args.iter(), r_args.iter());
|
unify_zip(subs, l_args.iter(), r_args.iter());
|
||||||
let ret = union_vars(subs, *l_ret, *r_ret);
|
unify(subs, *l_ret, *r_ret);
|
||||||
let flat_type = Func(args, ret);
|
|
||||||
|
|
||||||
from_content(Structure(flat_type))
|
merge(subs, ctx, Structure(Func((*r_args).clone(), *r_ret)))
|
||||||
} else if l_args.len() > r_args.len() {
|
} else if l_args.len() > r_args.len() {
|
||||||
from_content(Error(Problem::ExtraArguments))
|
merge(subs, ctx, Error(Problem::ExtraArguments))
|
||||||
} else {
|
} else {
|
||||||
from_content(Error(Problem::MissingArguments))
|
merge(subs, ctx, Error(Problem::MissingArguments))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => from_content(Error(Problem::GenericMismatch)),
|
_ => merge(subs, ctx, Error(Problem::GenericMismatch)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify_args<'a, I>(subs: &mut Subs, left_iter: I, right_iter: I) -> Vec<Variable>
|
fn unify_zip<'a, I>(subs: &mut Subs, left_iter: I, right_iter: I)
|
||||||
where
|
where
|
||||||
I: Iterator<Item = &'a Variable>,
|
I: Iterator<Item = &'a Variable>,
|
||||||
{
|
{
|
||||||
left_iter
|
for (&l_var, &r_var) in left_iter.zip(right_iter) {
|
||||||
.zip(right_iter)
|
unify(subs, l_var, r_var);
|
||||||
.map(|(&l_var, &r_var)| {
|
}
|
||||||
// Look up the descriptors we have for these variables, and unify them.
|
|
||||||
let descriptor = unify_vars(subs, l_var, r_var);
|
|
||||||
|
|
||||||
// set r_var to be the unioned value, then union l_var to r_var
|
|
||||||
subs.set(r_var, descriptor);
|
|
||||||
subs.union(l_var, r_var);
|
|
||||||
|
|
||||||
r_var
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn union_vars(subs: &mut Subs, l_var: Variable, r_var: Variable) -> Variable {
|
|
||||||
// Look up the descriptors we have for these variables, and unify them.
|
|
||||||
let descriptor = unify_vars(subs, l_var, r_var);
|
|
||||||
|
|
||||||
// set r_var to be the unioned value, then union l_var to r_var
|
|
||||||
subs.set(r_var, descriptor);
|
|
||||||
subs.union(l_var, r_var);
|
|
||||||
|
|
||||||
r_var
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn unify_rigid(name: &str, other: &Content) -> Descriptor {
|
fn unify_rigid(subs: &mut Subs, ctx: &Context, name: &str, other: &Content) {
|
||||||
match other {
|
match other {
|
||||||
FlexVar(_) => {
|
FlexVar(_) => {
|
||||||
// If the other is flex, rigid wins!
|
// If the other is flex, rigid wins!
|
||||||
from_content(RigidVar(name.into()))
|
merge(subs, ctx, RigidVar(name.into()))
|
||||||
}
|
}
|
||||||
RigidVar(_) | Structure(_) => {
|
RigidVar(_) | Structure(_) => {
|
||||||
// Type mismatch! Rigid can only unify with flex, even if the
|
// Type mismatch! Rigid can only unify with flex, even if the
|
||||||
// rigid names are the same.
|
// rigid names are the same.
|
||||||
from_content(Error(Problem::GenericMismatch))
|
merge(subs, ctx, Error(Problem::GenericMismatch))
|
||||||
}
|
}
|
||||||
Error(problem) => {
|
Error(problem) => {
|
||||||
// Error propagates.
|
// Error propagates.
|
||||||
from_content(Error(problem.clone()))
|
merge(subs, ctx, Error(problem.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn unify_flex(opt_name: &Option<Box<str>>, other: &Content) -> Descriptor {
|
fn unify_flex(subs: &mut Subs, ctx: &Context, opt_name: &Option<Box<str>>, other: &Content) {
|
||||||
match other {
|
match other {
|
||||||
FlexVar(None) => {
|
FlexVar(None) => {
|
||||||
// If both are flex, and only left has a name, keep the name around.
|
// If both are flex, and only left has a name, keep the name around.
|
||||||
from_content(FlexVar(opt_name.clone()))
|
merge(subs, ctx, FlexVar(opt_name.clone()))
|
||||||
}
|
}
|
||||||
FlexVar(Some(_)) | RigidVar(_) | Structure(_) | Error(_) => {
|
FlexVar(Some(_)) | RigidVar(_) | Structure(_) | Error(_) => {
|
||||||
// In all other cases, if left is flex, defer to right.
|
// In all other cases, if left is flex, defer to right.
|
||||||
// (This includes using right's name if both are flex and named.)
|
// (This includes using right's name if both are flex and named.)
|
||||||
from_content(other.clone())
|
merge(subs, ctx, other.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO this was f/k/a merge() - got rid of the rank stuff...good idea? Bad?
|
fn merge(subs: &mut Subs, ctx: &Context, content: Content) {
|
||||||
/// TODO it used to be { rank: std::cmp::min(left_rank, right_rank), ... }
|
let rank = ctx.first_desc.rank.min(ctx.second_desc.rank);
|
||||||
fn from_content(content: Content) -> Descriptor {
|
let desc = Descriptor {
|
||||||
Descriptor {
|
|
||||||
content,
|
content,
|
||||||
rank: 0,
|
rank,
|
||||||
mark: 2, // no mark
|
mark: Mark::none(),
|
||||||
copy: None,
|
copy: None,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
subs.union(ctx.first, ctx.second, desc);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue