use super::*;
use prelude::Dfn;
use std::sync::Arc;
fn report(
i: usize,
found: bool,
ambiguous: bool,
count: usize,
nodes: &[Node],
todo: &mut Vec<usize>
) -> Result<(), Range<String>> {
if !found {
if ambiguous {
todo.push(i);
} else if count > 0 {
use std::io::Write;
let mut buf: Vec<u8> = vec![];
write!(&mut buf, "Type mismatch (#230):\nThe argument type `").unwrap();
for (i, arg) in nodes[i].children.iter()
.filter(|&&arg| nodes[arg].kind == Kind::CallArg &&
!nodes[arg].children.is_empty())
.map(|&arg| nodes[arg].children[0])
.enumerate() {
if let Some(ref arg_ty) = nodes[arg].ty {
if i != 0 {write!(&mut buf, ", ").unwrap()};
write!(&mut buf, "{}", arg_ty.description()).unwrap();
}
}
write!(&mut buf, "` does not work with `{}`",
nodes[i].name().expect("Expected name")).unwrap();
return Err(nodes[i].source.wrap(String::from_utf8(buf).unwrap()))
}
}
Ok(())
}
pub(crate) fn declaration(
i: usize,
decl: usize,
nodes: &[Node],
todo: &mut Vec<usize>,
this_ty: &mut Option<Type>
) -> Result<(), Range<String>> {
let mut found = false;
let mut ambiguous = false;
let mut count = 0;
'outer: for &ty in nodes[decl].children.iter()
.filter(|&&ty| nodes[ty].kind == Kind::Ty)
{
count += 1;
let mut all = true;
let mut ty_vars: Vec<Option<Arc<String>>> = vec![None; nodes[ty].names.len()];
for (arg_expr, &ty_arg) in nodes[i].children.iter()
.filter(|&&arg| nodes[arg].kind == Kind::CallArg &&
!nodes[arg].children.is_empty())
.map(|&arg| nodes[arg].children[0])
.zip(nodes[ty].children.iter()
.filter(|&&ty_arg| nodes[ty_arg].kind == Kind::TyArg))
{
if nodes[arg_expr].ty.is_none() {
ambiguous = true;
break 'outer;
}
let found_arg = if let (&Some(ref a), &Some(ref b)) =
(&nodes[arg_expr].ty, &nodes[ty_arg].ty) {
let b = b.bind_ty_vars(a, &nodes[ty].names, &mut ty_vars)
.map_err(|err| nodes[arg_expr].source.wrap(err))?;
if b.goes_with(a) {
if b.ambiguous(a) {
ambiguous = true;
break 'outer;
}
true
} else {false}
}
else {false};
if !found_arg {
all = false;
break;
}
}
if all {
if let Some(&ind) = nodes[ty].children.iter()
.filter(|&&ty| nodes[ty].kind == Kind::TyRet)
.next() {
let mut new_ty = nodes[ind].ty.clone();
if let Some(ref mut new_ty) = new_ty {
for i in 0..nodes[ty].names.len() {
if let Some(ref val) = ty_vars[i] {
new_ty.insert_var(&nodes[ty].names[i], val);
} else {
new_ty.insert_none_var(&nodes[ty].names[i]);
}
}
}
*this_ty = new_ty;
found = true;
break;
}
}
}
report(i, found, ambiguous, count, nodes, todo)
}
pub(crate) fn prelude(
i: usize,
f: &Dfn,
nodes: &[Node],
todo: &mut Vec<usize>,
this_ty: &mut Option<Type>
) -> Result<(), Range<String>> {
let mut found = false;
let mut ambiguous = false;
'outer: for ty in &f.ext {
let mut all = true;
let mut ty_vars: Vec<Option<Arc<String>>> = vec![None; ty.0.len()];
for (arg_expr, ty_arg) in nodes[i].children.iter()
.filter(|&&arg| nodes[arg].kind == Kind::CallArg &&
!nodes[arg].children.is_empty())
.map(|&arg| nodes[arg].children[0])
.zip(ty.1.iter())
{
if nodes[arg_expr].ty.is_none() {
ambiguous = true;
break 'outer;
}
let found_arg = if let Some(ref a) = nodes[arg_expr].ty {
let ty_arg = ty_arg.bind_ty_vars(a, &ty.0, &mut ty_vars)
.map_err(|err| nodes[arg_expr].source.wrap(err))?;
if ty_arg.goes_with(a) {
if ty_arg.ambiguous(a) {
ambiguous = true;
break 'outer;
}
true
} else {false}
}
else {false};
if !found_arg {
all = false;
break;
}
}
if all {
let mut new_ty = ty.2.clone();
for i in 0..ty.0.len() {
if let Some(ref val) = ty_vars[i] {
new_ty.insert_var(&ty.0[i], val);
} else {
new_ty.insert_none_var(&ty.0[i]);
}
}
*this_ty = Some(new_ty);
found = true;
break;
}
}
report(i, found, ambiguous, f.ext.len(), nodes, todo)
}