return NULL;
struct expr_node *node = expr_allocate_binary (e, optype, lhs, rhs);
- bool lhs_ok = type_coercion (e, node, 0);
- bool rhs_ok = type_coercion (e, node, 1);
-
- if (!lhs_ok || !rhs_ok)
+ if (!is_coercible (node, 0) || !is_coercible (node, 1))
{
bool both = false;
for (size_t i = 0; i < n_ops; i++)
_("Both operands of %s must be strings."), name);
msg_at (SN, expr_location (e, node->args[0]),
- _("The left-hand operand of %s has type '%s'."),
- name, atom_type_name (expr_node_returns (node->args[0])));
+ _("This operand has type '%s'."),
+ atom_type_name (expr_node_returns (node->args[0])));
msg_at (SN, expr_location (e, node->args[1]),
- _("The right-hand operand of %s has type '%s'."),
- name, atom_type_name (expr_node_returns (node->args[1])));
+ _("This operand has type '%s'."),
+ atom_type_name (expr_node_returns (node->args[1])));
return NULL;
}
+ if (!type_coercion (e, node, 0) || !type_coercion (e, node, 1))
+ NOT_REACHED ();
+
lhs = node;
}
}
atom_type_name (atom_type type)
{
assert (is_atom (type));
- return operations[type].name;
+
+ /* The Boolean type is purely an internal concept that the documentation
+ doesn't mention, so it might confuse users if we talked about them in
+ diagnostics. */
+ return type == OP_boolean ? "number" : operations[type].name;
}
struct expr_node *