This function traverses the expression tree. It creates keys on the fly. This is not possible for many kinds of type systems, in which case the functions requires a context with a mapping of e.g. Variable -> Key. The context can be built during a first pass over the tree.
(tc: &mut VarlessTypeChecker<Variant>, expr: &Expression)
| 121 | /// requires a context with a mapping of e.g. Variable -> Key. The context can be built during a first pass over the |
| 122 | /// tree. |
| 123 | fn tc_expr(tc: &mut VarlessTypeChecker<Variant>, expr: &Expression) -> Result<TcKey, TcErr<Variant>> { |
| 124 | use Expression::*; |
| 125 | let key_result = tc.new_term_key(); // will be returned |
| 126 | match expr { |
| 127 | ConstInt(c) => { |
| 128 | let width = (128 - c.leading_zeros()).try_into().unwrap(); |
| 129 | tc.impose(key_result.concretizes_explicit(Variant::Integer(width)))?; |
| 130 | } |
| 131 | ConstFixed(i, f) => { |
| 132 | let int_width = (64 - i.leading_zeros()).try_into().unwrap(); |
| 133 | let frac_width = (64 - f.leading_zeros()).try_into().unwrap(); |
| 134 | tc.impose(key_result.concretizes_explicit(Variant::Fixed(int_width, frac_width)))?; |
| 135 | } |
| 136 | ConstBool(_) => tc.impose(key_result.concretizes_explicit(Variant::Bool))?, |
| 137 | Conditional { cond, cons, alt } => { |
| 138 | let key_cond = tc_expr(tc, cond)?; |
| 139 | let key_cons = tc_expr(tc, cons)?; |
| 140 | let key_alt = tc_expr(tc, alt)?; |
| 141 | tc.impose(key_cond.concretizes_explicit(Variant::Bool))?; |
| 142 | tc.impose(key_result.is_meet_of(key_cons, key_alt))?; |
| 143 | } |
| 144 | PolyFn { name: _, param_constraints, args, returns } => { |
| 145 | // Note: The following line cannot be replaced by `vec![param_constraints.len(); tc.new_key()]` as this |
| 146 | // would copy the keys rather than creating new ones. |
| 147 | let params: Vec<(Option<Variant>, TcKey)> = |
| 148 | param_constraints.iter().map(|p| (*p, tc.new_term_key())).collect(); |
| 149 | |
| 150 | for (arg_ty, arg_expr) in args { |
| 151 | let arg_key = tc_expr(tc, arg_expr)?; |
| 152 | match arg_ty { |
| 153 | ParamType::ParamId(id) => { |
| 154 | let (p_constr, p_key) = params[*id]; |
| 155 | // We need to enforce that the parameter is more concrete than the passed argument and that the |
| 156 | // passed argument satisfies the constraints imposed on the parametric type. |
| 157 | tc.impose(p_key.concretizes(arg_key))?; |
| 158 | if let Some(c) = p_constr { |
| 159 | tc.impose(arg_key.concretizes_explicit(c))?; |
| 160 | } |
| 161 | } |
| 162 | ParamType::Abstract(at) => tc.impose(arg_key.concretizes_explicit(*at))?, |
| 163 | }; |
| 164 | } |
| 165 | match returns { |
| 166 | ParamType::Abstract(at) => tc.impose(key_result.concretizes_explicit(*at))?, |
| 167 | ParamType::ParamId(id) => { |
| 168 | let (constr, key) = params[*id]; |
| 169 | if let Some(c) = constr { |
| 170 | tc.impose(key_result.concretizes_explicit(c))?; |
| 171 | } |
| 172 | tc.impose(key_result.equate_with(key))?; |
| 173 | } |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | Ok(key_result) |
| 178 | } |
| 179 | |
| 180 | fn main() { |
no test coverage detected