summaryrefslogtreecommitdiff
path: root/ast_to_hir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ast_to_hir.cpp')
-rw-r--r--ast_to_hir.cpp58
1 files changed, 49 insertions, 9 deletions
diff --git a/ast_to_hir.cpp b/ast_to_hir.cpp
index 62f2068b3a..f7c82fab4b 100644
--- a/ast_to_hir.cpp
+++ b/ast_to_hir.cpp
@@ -331,6 +331,45 @@ relational_result_type(const struct glsl_type *type_a,
}
+/**
+ * Validates that a value can be assigned to a location with a specified type
+ *
+ * Validates that \c rhs can be assigned to some location. If the types are
+ * not an exact match but an automatic conversion is possible, \c rhs will be
+ * converted.
+ *
+ * \return
+ * \c NULL if \c rhs cannot be assigned to a location with type \c lhs_type.
+ * Otherwise the actual RHS to be assigned will be returned. This may be
+ * \c rhs, or it may be \c rhs after some type conversion.
+ *
+ * \note
+ * In addition to being used for assignments, this function is used to
+ * type-check return values.
+ */
+ir_instruction *
+validate_assignment(const glsl_type *lhs_type, ir_instruction *rhs)
+{
+ const glsl_type *const rhs_type = rhs->type;
+
+ /* If there is already some error in the RHS, just return it. Anything
+ * else will lead to an avalanche of error message back to the user.
+ */
+ if (rhs_type->is_error())
+ return rhs;
+
+ /* FINISHME: For GLSL 1.10, check that the types are not arrays. */
+
+ /* If the types are identical, the assignment can trivially proceed.
+ */
+ if (rhs_type == lhs_type)
+ return rhs;
+
+ /* FINISHME: Check for and apply automatic conversions. */
+ return NULL;
+}
+
+
ir_instruction *
ast_node::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
@@ -448,8 +487,11 @@ ast_expression::hir(exec_list *instructions,
}
}
- /* FINISHME: Check that the LHS and RHS have matching types. */
- /* FINISHME: For GLSL 1.10, check that the types are not arrays. */
+ ir_instruction *rhs = validate_assignment(op[0]->type, op[1]);
+ if (rhs == NULL) {
+ type = glsl_error_type;
+ rhs = op[1];
+ }
ir_instruction *tmp = new ir_assignment(op[0], op[1], NULL);
instructions->push_tail(tmp);
@@ -650,7 +692,7 @@ ast_expression::hir(exec_list *instructions,
if (var != NULL) {
type = result->type;
} else {
- _mesa_glsl_error(& loc, NULL, "`%s' undeclared",
+ _mesa_glsl_error(& loc, state, "`%s' undeclared",
this->primary_expression.identifier);
error_emitted = true;
@@ -704,7 +746,7 @@ ast_expression::hir(exec_list *instructions,
}
if (is_error_type(type) && !error_emitted)
- _mesa_glsl_error(& loc, NULL, "type mismatch");
+ _mesa_glsl_error(& loc, state, "type mismatch");
return result;
}
@@ -769,7 +811,7 @@ type_specifier_to_glsl_type(const struct ast_type_specifier *spec,
*name = spec->type_name;
/* FINISHME: Handle array declarations. Note that this requires complete
- * FINSIHME: handling of constant expressions.
+ * FINISHME: handling of constant expressions.
*/
}
@@ -869,7 +911,7 @@ ast_declarator_list::hir(exec_list *instructions,
var = new ir_variable(var_type, decl->identifier);
- /* FINSIHME: Variables that are attribute, uniform, varying, in, or
+ /* FINISHME: Variables that are attribute, uniform, varying, in, or
* FINISHME: out varibles must be declared either at global scope or
* FINISHME: in a parameter list (in and out only).
*/
@@ -1053,9 +1095,7 @@ ast_function_definition::hir(exec_list *instructions,
"non-function", name);
signature = NULL;
} else {
- f = new ir_function();
- f->name = name;
-
+ f = new ir_function(name);
state->symbols->add_function(f->name, f);
}