dyon/lifetime/typecheck/
refine.rs

1use super::*;
2use crate::Dfn;
3
4use std::sync::Arc;
5
6fn report(
7    i: usize,
8    found: bool,
9    ambiguous: bool,
10    count: usize,
11    nodes: &[Node],
12    todo: &mut Vec<usize>,
13) -> Result<(), Range<String>> {
14    if !found {
15        if ambiguous {
16            // Delay completion of this call until extra type information matches.
17            todo.push(i);
18        } else if count > 0 {
19            use std::io::Write;
20
21            let mut buf: Vec<u8> = vec![];
22            write!(&mut buf, "Type mismatch (#230):\nThe argument type `").unwrap();
23            for (i, arg) in nodes[i]
24                .children
25                .iter()
26                .filter(|&&arg| nodes[arg].kind == Kind::CallArg && !nodes[arg].children.is_empty())
27                .map(|&arg| nodes[arg].children[0])
28                .enumerate()
29            {
30                if let Some(ref arg_ty) = nodes[arg].ty {
31                    if i != 0 {
32                        write!(&mut buf, ", ").unwrap()
33                    };
34                    write!(&mut buf, "{}", arg_ty.description()).unwrap();
35                }
36            }
37            write!(
38                &mut buf,
39                "` does not work with `{}`",
40                nodes[i].name().expect("Expected name")
41            )
42            .unwrap();
43            return Err(nodes[i].source.wrap(String::from_utf8(buf).unwrap()));
44        }
45    }
46    Ok(())
47}
48
49pub(crate) fn declaration(
50    i: usize,
51    decl: usize,
52    nodes: &[Node],
53    todo: &mut Vec<usize>,
54    this_ty: &mut Option<Type>,
55) -> Result<(), Range<String>> {
56    // Refine types using extra type information.
57    let mut found = false;
58    let mut ambiguous = false;
59    let mut count = 0;
60    'outer: for &ty in nodes[decl]
61        .children
62        .iter()
63        .filter(|&&ty| nodes[ty].kind == Kind::Ty)
64    {
65        count += 1;
66        let mut all = true;
67        let mut ty_vars: Vec<Option<Arc<String>>> = vec![None; nodes[ty].names.len()];
68        for (arg_expr, &ty_arg) in nodes[i]
69            .children
70            .iter()
71            .filter(|&&arg| nodes[arg].kind == Kind::CallArg && !nodes[arg].children.is_empty())
72            .map(|&arg| nodes[arg].children[0])
73            .zip(
74                nodes[ty]
75                    .children
76                    .iter()
77                    .filter(|&&ty_arg| nodes[ty_arg].kind == Kind::TyArg),
78            )
79        {
80            if nodes[arg_expr].ty.is_none() {
81                ambiguous = true;
82                break 'outer;
83            }
84            let found_arg =
85                if let (&Some(ref a), &Some(ref b)) = (&nodes[arg_expr].ty, &nodes[ty_arg].ty) {
86                    let b = b
87                        .bind_ty_vars(a, &nodes[ty].names, &mut ty_vars)
88                        .map_err(|err| nodes[arg_expr].source.wrap(err))?;
89                    if b.goes_with(a) {
90                        if b.ambiguous(a) {
91                            ambiguous = true;
92                            break 'outer;
93                        }
94                        true
95                    } else {
96                        false
97                    }
98                } else {
99                    false
100                };
101            if !found_arg {
102                all = false;
103                break;
104            }
105        }
106        if all {
107            if let Some(&ind) = nodes[ty]
108                .children
109                .iter()
110                .find(|&&ty| nodes[ty].kind == Kind::TyRet)
111            {
112                let mut new_ty = nodes[ind].ty.clone();
113                if let Some(ref mut new_ty) = new_ty {
114                    for i in 0..nodes[ty].names.len() {
115                        if let Some(ref val) = ty_vars[i] {
116                            new_ty.insert_var(&nodes[ty].names[i], val);
117                        } else {
118                            new_ty.insert_none_var(&nodes[ty].names[i]);
119                        }
120                    }
121                }
122                *this_ty = new_ty;
123                found = true;
124                break;
125            }
126        }
127    }
128
129    report(i, found, ambiguous, count, nodes, todo)
130}
131
132pub(crate) fn prelude(
133    i: usize,
134    f: &Dfn,
135    nodes: &[Node],
136    todo: &mut Vec<usize>,
137    this_ty: &mut Option<Type>,
138) -> Result<(), Range<String>> {
139    // Refine types using extra type information.
140    let mut found = false;
141    let mut ambiguous = false;
142    'outer: for ty in &f.ext {
143        let mut all = true;
144        let mut ty_vars: Vec<Option<Arc<String>>> = vec![None; ty.0.len()];
145        for (arg_expr, ty_arg) in nodes[i]
146            .children
147            .iter()
148            .filter(|&&arg| nodes[arg].kind == Kind::CallArg && !nodes[arg].children.is_empty())
149            .map(|&arg| nodes[arg].children[0])
150            .zip(ty.1.iter())
151        {
152            if nodes[arg_expr].ty.is_none() {
153                ambiguous = true;
154                break 'outer;
155            }
156            let found_arg = if let Some(ref a) = nodes[arg_expr].ty {
157                let ty_arg = ty_arg
158                    .bind_ty_vars(a, &ty.0, &mut ty_vars)
159                    .map_err(|err| nodes[arg_expr].source.wrap(err))?;
160                if ty_arg.goes_with(a) {
161                    if ty_arg.ambiguous(a) {
162                        ambiguous = true;
163                        break 'outer;
164                    }
165                    true
166                } else {
167                    false
168                }
169            } else {
170                false
171            };
172            if !found_arg {
173                all = false;
174                break;
175            }
176        }
177        if all {
178            let mut new_ty = ty.2.clone();
179            for i in 0..ty.0.len() {
180                if let Some(ref val) = ty_vars[i] {
181                    new_ty.insert_var(&ty.0[i], val);
182                } else {
183                    new_ty.insert_none_var(&ty.0[i]);
184                }
185            }
186
187            *this_ty = Some(new_ty);
188            found = true;
189            break;
190        }
191    }
192
193    report(i, found, ambiguous, f.ext.len(), nodes, todo)
194}