[qfcc] Promote types before expanding scalars

This fixes the internal error generated by the likes of
`(sv_gravity * '0 0 1')` where sv_gravity is a float and `'0 0 1'` is an
ivec3: the vector is promoted to vec3 first so that expanding sv_gravity
is expanded to vec3 instead of ivec3 (which is not permitted for a
float: expansion requires the destination base type to be the same as
the source).
This commit is contained in:
Bill Currie 2022-09-14 14:39:09 +09:00
parent 47ac7b924f
commit 942ea22266
1 changed files with 46 additions and 24 deletions

View File

@ -853,13 +853,16 @@ entity_compare (int op, expr_t *e1, expr_t *e2)
return e;
}
#define invalid_binary_expr(_op, _e1, _e2) \
_invalid_binary_expr(_op, _e1, _e2, __FILE__, __LINE__)
static expr_t *
invalid_binary_expr (int op, expr_t *e1, expr_t *e2)
_invalid_binary_expr (int op, expr_t *e1, expr_t *e2,
const char *file, int line)
{
type_t *t1, *t2;
t1 = get_type (e1);
t2 = get_type (e2);
return error (e1, "invalid binary expression: %s %s %s",
return _error (e1, file, line, "invalid binary expression: %s %s %s",
get_type_string (t1), get_op_string (op),
get_type_string (t2));
}
@ -977,6 +980,15 @@ static int is_call (expr_t *e)
return e->type == ex_block && e->e.block.is_call;
}
static type_t *
promote_type (type_t *dst, type_t *src)
{
if (is_vector (dst) || is_quaternion (dst)) {
return dst;
}
return vector_type (base_type (dst), type_width (src));
}
expr_t *
binary_expr (int op, expr_t *e1, expr_t *e2)
{
@ -1056,6 +1068,38 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
// vector/quaternion and scalar won't get here as vector and quaternion
// are distict types with type.width == 1, but vector and vec3 WILL get
// here because of vec3 being float{3}
if (t1 != t2) {
type_t *pt1 = t1;
type_t *pt2 = t2;
if (is_float (base_type (t1)) && is_double (base_type (t2))
&& e2->implicit) {
pt2 = promote_type (t1, t2);
} else if (is_double (base_type (t1)) && is_float (base_type (t2))
&& e1->implicit) {
pt1 = promote_type (t2, t1);
} else if (type_promotes (base_type (t1), base_type (t2))) {
pt2 = promote_type (t1, t2);
} else if (type_promotes (base_type (t2), base_type (t1))) {
pt1 = promote_type (t2, t1);
} else if (base_type (t1) == base_type (t2)) {
if (is_vector (t1) || is_quaternion (t1)) {
pt2 = t1;
} else if (is_vector (t2) || is_quaternion (t2)) {
pt1 = t2;
}
} else {
debug (e1, "%d %d\n", e1->implicit, e2->implicit);
return invalid_binary_expr (op, e1, e2);
}
if (pt1 != t1) {
e1 = cast_expr (pt1, e1);
t1 = pt1;
}
if (pt2 != t2) {
e2 = cast_expr (pt2, e2);
t2 = pt2;
}
}
if (type_width (t1) == 1) {
// scalar op vec
if (!(e = convert_scalar (e1, op, e2))) {
@ -1076,28 +1120,6 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
// vec op vec of different widths
return invalid_binary_expr (op, e1, e2);
}
if (t1 != t2) {
if (is_float (base_type (t1)) && is_double (base_type (t2))
&& e2->implicit) {
e2 = cast_expr (t1, e2);
} else if (is_double (base_type (t1)) && is_float (base_type (t2))
&& e1->implicit) {
e1 = cast_expr (t2, e1);
} else if (type_promotes (base_type (t1), base_type (t2))) {
e2 = cast_expr (t1, e2);
} else if (type_promotes (base_type (t2), base_type (t1))) {
e1 = cast_expr (t2, e1);
} else if (base_type (t1) == base_type (t2)) {
if (is_vector (t1) || is_quaternion (t1)) {
e2 = cast_expr (t1, e2);
} else if (is_vector (t2) || is_quaternion (t2)) {
e1 = cast_expr (t2, e1);
}
} else {
debug (e1, "%d %d\n", e1->implicit, e2->implicit);
return invalid_binary_expr (op, e1, e2);
}
}
t1 = get_type (e1);
t2 = get_type (e2);
et1 = low_level_type (t1);