fix checking of array literal compatability

This commit is contained in:
Dave Holoway
2020-06-15 16:57:00 +01:00
parent 2f3349c359
commit a8653f26df

View File

@@ -1645,20 +1645,14 @@ function checkAssignmentExpression(tokens, variable, op, value) {
addproblem(tokens, ParseProblem.Error(op, `Invalid assignment: left-hand side is not a variable`));
return;
}
let is_assignable;
// we need to special-case ArrayLiteral because it has no type associated with it
const is_assignable = isAssignable(variable.type, value);
if (!is_assignable) {
if (value instanceof ArrayLiteral) {
is_assignable = isArrayAssignable(variable.type, value);
if (!is_assignable) {
addproblem(tokens, ParseProblem.Error(op, `Array literal expression is not compatible with variable of type '${variable.type.fullyDottedTypeName}'`));
}
return;
}
is_assignable = isAssignable(variable.type, value);
if (!is_assignable) {
} else {
addproblem(tokens, ParseProblem.Error(op, `Incompatible types: Expression of type '${value.type.fullyDottedTypeName}' cannot be assigned to a variable of type '${variable.type.fullyDottedTypeName}'`));
}
}
if (value instanceof TernaryValue) {
checkAssignmentExpression(tokens, variable, value.colon, value.falseValue);
@@ -1667,35 +1661,20 @@ function checkAssignmentExpression(tokens, variable, op, value) {
/**
* @param {JavaType} variable_type
* @param {ArrayLiteral} value
* @param {ArrayLiteral} arr_literal_value
*/
function isArrayAssignable(variable_type, value) {
function isArrayAssignable(variable_type, arr_literal_value) {
if (!(variable_type instanceof ArrayType)) {
return false;
}
// empty array literals are compatible with all arrays
if (value.elements.length === 0) {
if (arr_literal_value.elements.length === 0) {
return true;
}
const required_element_type = variable_type.elementType;
for (let i=0; i < value.elements.length; i++) {
const element = value.elements[i];
let is_assignable;
if (required_element_type instanceof ArrayType) {
// the element must be another array literal expression or a value with a matching array type
if (element instanceof ArrayLiteral) {
is_assignable = isArrayAssignable(required_element_type, element);
} else {
is_assignable = element.variables[0] ? isAssignable(required_element_type, element.variables[0]) : false;
}
} else {
// base type = the element must match the (non-array) type
if (element instanceof ArrayLiteral) {
is_assignable = false;
} else {
is_assignable = element.variables[0] ? isAssignable(required_element_type, element.variables[0]) : false;
}
}
for (let i=0; i < arr_literal_value.elements.length; i++) {
const element_value = arr_literal_value.elements[i].variables[0];
let is_assignable = !!element_value && isAssignable(required_element_type, element_value);
if (!is_assignable) {
return false;
}
@@ -1712,6 +1691,9 @@ function isAssignable(type, value) {
if (value instanceof LiteralNumber) {
return value.isCompatibleWith(type);
}
if (value instanceof ArrayLiteral) {
return isArrayAssignable(type, value);
}
return isTypeAssignable(type, value.type);
}