error (errNode, "I am unable to determine the size of this variable (since I am unable to determine the size of the array elements)");
}
return -1;
}
if (arrayType->sizeExpr == NULL) {
if (wantPrinting) {
error (errNode, "I am unable to determine the size of this variable since the number of array elements is unspecified; use something like 'array [100] of ...'");
}
return -1;
}
intConst = (IntConst *) arrayType->sizeExpr;
if (intConst->op != INT_CONST) {
if (wantPrinting) {
error (errNode, "I am unable to determine the size of this variable since the number of array elements cannot be determined at compile time; try using a constant integer value");
}
return -1;
}
size = intConst->ivalue * elementSize + 4; // 4 bytes for "number of elements"
if (intConst->ivalue <= 0) {
if (wantPrinting) {
error (errNode, "The number of array elements must be greater than zero");
if (wantPrinting && ((RecordType *) node)->sizeInBytes == -1) {
error (errNode, "I am unable to determine the size of this variable (since I am unable to determine the size of its RecordType)");
}
return ((RecordType *) node)->sizeInBytes;
case FUNCTION_TYPE:
if (wantPrinting) {
error (errNode, "You may not have a variable with type 'function' since it has no specific size (Perhaps you can use a 'ptr to function'...)");
}
return -1;
case CLASS_DEF:
if (wantPrinting && ((ClassDef *) node)->sizeInBytes == -1) {
error (errNode, "I am unable to determine the size of this variable (since I am unable to determine the size of its Class type)");
}
return ((ClassDef *) node)->sizeInBytes;
case INTERFACE:
if (wantPrinting) {
error (errNode, "You may not have a variable whose type is an interface since I cannot determine the size of the object (Perhaps you can use a ptr to it...)");
}
return -1;
case TYPE_PARM:
if (((TypeParm *) node)->fourByteRestricted) {
return 4;
} else {
if (wantPrinting) {
error (node, "This Type Parameter is used in way that requires its size to be known, but it cannot be known at compile-time");
error2 (errNode, "Here is the place where the problem was noticed");
// Make sure it is the same kind. (This is not strictly necessary, since if
// they are different kinds, there will always be another error message.)
if (meth->kind != proto->kind) {
error (meth, "This method is not the same kind (infix, prefix, keyword, normal) as the corresponding prototype");
error2 (proto, "Here is the prototype");
}
// Make sure each parameter type matches according to contra-variance...
protoParm = proto->parmList;
methParm = meth->parmList;
while (1) {
if ((protoParm == NULL) && (methParm == NULL)) break;
if ((protoParm == NULL) || (methParm == NULL)) {
error (meth, "This method does not have the same number of parameters as the corresponding prototype");
error2 (proto, "Here is the prototype");
break;
}
if (! assignable (methParm->type, protoParm->type)) {
error (methParm, "The type of this parameter fails to match the type of the corresponding parameter in the prototype (perhaps the type is not general enough)");
error2 (proto, "Here is the method prototype");
errorWithType ("The type of the method parameter is", methParm->type);
errorWithType ("The expected type is", protoParm->type);
}
// Make sure that the parameters have the same names...
if (protoParm->id != methParm->id) {
error (methParm, "The name of this parameter does not match the name of the corresponding parameter in the method prototype");
error2 (protoParm, "Here is the name used in the method prototype");
}
protoParm = (Parameter *) protoParm->next;
methParm = (Parameter *) methParm->next;
}
// Make sure the return types match according to covariance...
if (! assignable (proto->retType, meth->retType)) {
error (meth, "The return type of this method fails to match the corresponding prototype (perhaps the type is too general)");
error2 (proto, "Here is the method prototype");
errorWithType ("The return type of this method is", meth->retType);
errorWithType ("The expected type is", proto->retType);
}
// Make this MethodProto point to this Method, and the Method
// point to the MethodProto...
}
}
// Run through all methods that override something from the superclass...
for (meth = cl->methods; meth; meth=meth->next) {
// printf ("Looking at method %s\n", meth->selector->chars);
// See if we have prototypes for this method and for an inherited version...
programLogicError ("Should have two non-NULL protos");
}
// printf ("Looking at protoSuper = ");
// pretty (protoSuper);
// printf (" protoSub = ");
// pretty (protoSub);
// They should have the same kind...
if (protoSuper->kind != protoSub->kind) {
programLogicError ("Kind mismatch in checkProtos");
}
// Make sure each parm type matches according to contra-variance...
protoParm = protoSuper->parmList;
subParm = protoSub->parmList;
while (1) {
if ((protoParm == NULL) && (subParm == NULL)) break;
if ((protoParm == NULL) || (subParm == NULL)) {
error (protoSub, "This method does not have the same number of parameters as the corresponding method in the super class");
error2 (protoSuper, "Here is the prototype from the super class");
break;
}
if (! assignable (subParm->type, protoParm->type)) {
error (subParm, "When overriding a method... the type of this parameter fails to match the type of the corresponding parameter in the method from the super class (perhaps it is not general enough)");
error2 (protoSuper, "Here is the method from the super class");
errorWithType ("The parameter type in the subclass is", subParm->type);
errorWithType ("The expected type is", protoParm->type);
}
protoParm = (Parameter *) protoParm->next;
subParm = (Parameter *) subParm->next;
}
// Make sure the return types match according to covariance...
if (! assignable (protoSuper->retType, protoSub->retType)) {
error (protoSub, "When overriding a method... the return type of this method fails to match the corresponding method from the super class (perhaps it is too general)");
error2 (protoSuper, "Here is the method from the super class");
errorWithType ("The type returned in the subclass is", protoSub->retType);
errorWithType ("The expected type is", protoSuper->retType);
}
}
// checkProtos2 (protoSuper, protoSub)
//
// This routine is passed two MethodProtos. It checks to make sure they are compatable
// according to co- and contra-variance. It will print error messages if not.
//
// This routine differs from "checkProtos" in that it is used for checking "extends"
// among interfaces. The code is the same, but the error message texts differ slightly.
programLogicError ("Should have two non-NULL protos");
}
// printf ("Looking at protoSuper = ");
// pretty (protoSuper);
// printf (" protoSub = ");
// pretty (protoSub);
// They should have the same kind...
if (protoSuper->kind != protoSub->kind) {
programLogicError ("Kind mismatch in checkProtos2");
}
// Make sure each parm type matches according to contra-variance...
protoParm = protoSuper->parmList;
subParm = protoSub->parmList;
while (1) {
if ((protoParm == NULL) && (subParm == NULL)) break;
if ((protoParm == NULL) || (subParm == NULL)) {
error (protoSub, "This message does not have the same number of parameters as the corresponding message in an interface we are extending");
error2 (protoSuper, "Here is the prototype from the super-interface");
break;
}
if (! assignable (subParm->type, protoParm->type)) {
error (subParm, "The type of this parameter fails to match the type of the corresponding parameter in the same message in an interface we are extending (perhaps it is not general enough)");
error2 (protoSuper, "Here is the message from the super-interface");
errorWithType ("The parameter type in the sub-interface is", subParm->type);
errorWithType ("The expected type is", protoParm->type);
}
protoParm = (Parameter *) protoParm->next;
subParm = (Parameter *) subParm->next;
}
// Make sure the return types match according to covariance...
if (! assignable (protoSuper->retType, protoSub->retType)) {
error (protoSub, "The return type of this message fails to match the corresponding message in an interface we are extending (perhaps it is too general)");
error2 (protoSuper, "Here is the message from the super-interface");
errorWithType ("The type returned in the sub-interface is", protoSub->retType);
errorWithType ("The expected type is", protoSuper->retType);
}
}
// checkProtos3 (proto1, proto2)
//
// This routine is passed two MethodProtos. It checks to make sure their parameter and
// return types are equal. It will print error messages if not.
programLogicError ("Should have two non-NULL protos in checkProtos3");
}
// printf ("Looking at proto1 = ");
// pretty (proto1);
// printf (" proto2 = ");
// pretty (proto2);
// They should have the same kind...
if (proto1->kind != proto2->kind) {
programLogicError ("Kind mismatch in checkProtos3");
}
// Make sure each parm type matches exactly...
parm1 = proto1->parmList;
parm2 = proto2->parmList;
while (1) {
if ((parm1 == NULL) && (parm2 == NULL)) break;
if ((parm1 == NULL) || (parm2 == NULL)) {
error (inter, "This interface extends two other interfaces; both contain the same message but the messages do not have the same number of parameters");
error2 (proto1, "Here is the message in one super-interface");
error2 (proto2, "Here is the message in the other super-interface");
break;
}
if (! typesEqual (parm1->type, parm2->type)) {
error (inter, "This interface extends two other interfaces and both contain the same message; since there is no corresponding message in this interface, the types of the parameters must match exactly, but they do not (You might consider adding a message in this interface with a parameter type that is more general)");
error2 (parm2, "Here is the parameter from one super-interface");
error2 (parm1, "Here is the parameter from the other super-interface");
}
parm1 = (Parameter *) parm1->next;
parm2 = (Parameter *) parm2->next;
}
// Make sure the return types match according to covariance...
if (! typesEqual (proto2->retType, proto1->retType)) {
error (inter, "This interface extends two other interfaces and both contain the same message; since there is no corresponding message in this interface, the return types of must match exactly, but they do not (You might consider adding a message in this interface with a more specific return type)");
error2 (proto1, "Here is the message from one super interface");
error2 (proto2, "Here is the message from the other super interface");
}
}
// checkExtends (hdr)
//
// This routine runs through each interface and for each, checks the following:
//
// 1. If this interface provides a message that is also inherited, we make sure
// that the parameter and return types respect co- and contra-variance.
// 2. If this interface inherits the same message from different sources,
// but does not contain the message itself, we check to make sure that
// the parameter and return types are equal on all versions of the inherited
// Check to see if this selector could override a built-in operator.
// For example, overriding "+" makes "ptrToObj + xxx" ambiguous. However,
// some methods are okay. For example, we can have a method for "*" since
// "ptrToObj * x" would otherwise be illegal...
if (methodProto->kind == PREFIX) {
switch (methodProto->selector->primitiveSymbol) {
case UNARY_STAR:
error (methodProto, "Defining a prefix method with this selector causes confusion with the built-in dereference operator, in '* ptrToObj'");
break;
case UNARY_BANG:
error (methodProto, "Defining a prefix method with this selector causes confusion with a built-in operator in the boolean expression '! ptrToObj'");
break;
case UNARY_AMP:
error (methodProto, "Defining a prefix method with this selector causes confusion with the built-in address-of operator");
break;
}
}
if (methodProto->kind == INFIX) {
switch (methodProto->selector->primitiveSymbol) {
case MINUS:
error (methodProto, "Defining an infix method with this selector causes confusion with built-in pointer subtraction in 'ptrToObj - x'");
break;
case PLUS:
error (methodProto, "Defining an infix method with this selector causes confusion with built-in pointer addition in 'ptrToObj + x'");
break;
case BAR_BAR:
error (methodProto, "Defining an infix method with this selector causes confusion with a built-in operator in the boolean expression 'ptrToObj || x'");
break;
case AMP_AMP:
error (methodProto, "Defining an infix method with this selector causes confusion with a built-in operator in the boolean expression 'ptrToObj && x'");
break;
case EQUAL_EQUAL:
error (methodProto, "Defining an infix method with this selector causes confusion with the built-in EQUALS operator");
break;
case NOT_EQUAL:
error (methodProto, "Defining an infix method with this selector causes confusion with the built-in NOT-EQUALS operator");
// Make sure that the constraint type is not a basic type...
if (isCharType (typeParm->type) ||
isIntType (typeParm->type) ||
isBoolType (typeParm->type) ||
isDoubleType (typeParm->type) ||
isVoidType (typeParm->type) ||
isTypeOfNullType (typeParm->type)) {
error (typeParm, "The constraint on this type parameter is a basic type; this is meaningless, since this parameter can only be instantiated by that type itself");
errorWithType ("The constraint is", typeParm->type);
}
t = checkTypes (typeParm->type);
t = checkTypes (typeParm->next);
return NULL;
case TYPE_ARG: // in checkTypes
typeArg = (TypeArg *) node;
t = checkTypes (typeArg->type);
t = checkTypes (typeArg->next);
return NULL;
case CHAR_TYPE: // in checkTypes
return NULL;
case INT_TYPE: // in checkTypes
return NULL;
case DOUBLE_TYPE: // in checkTypes
return NULL;
case BOOL_TYPE: // in checkTypes
return NULL;
case VOID_TYPE: // in checkTypes
return NULL;
case TYPE_OF_NULL_TYPE: // in checkTypes
return NULL;
case ANY_TYPE: // in checkTypes
return NULL;
case PTR_TYPE: // in checkTypes
pType = (PtrType *) node;
t = checkTypes (pType->baseType);
if (pType->baseType && pType->baseType->op == VOID_TYPE && safe) {
error (pType, "Using 'ptr to void' is unsafe; you must compile with the 'unsafe' option if you wish to do this");
}
return NULL;
case ARRAY_TYPE: // in checkTypes
aType = (ArrayType *) node;
t = checkTypes (aType->sizeExpr);
if (t && !isIntType (t)) {
error (aType, "The array size expression must have type 'int'");
}
if ((aType->sizeExpr) && (aType->sizeExpr->op != INT_CONST)) {
error (aType, "The array size expression must be an integer value determinable at compile-time");
}
t = checkTypes (aType->baseType);
return NULL;
case RECORD_TYPE: // in checkTypes
rType = (RecordType *) node;
t = checkTypes (rType->fields);
return NULL;
case FUNCTION_TYPE: // in checkTypes
fType = (FunctionType *) node;
t = checkTypes (fType->parmTypes);
t = checkTypes (fType->retType);
setParmSizeInFunctionType (fType);
return NULL;
case NAMED_TYPE: // in checkTypes
nType = (NamedType *) node;
t = checkTypes (nType->typeArgs);
if (nType->myDef != NULL) {
switch (nType->myDef->op) {
case TYPE_PARM:
if (nType->typeArgs) {
error (node, "This is the name of a type parameter of this class or interface; this type must not be followed with '[TypeArgs]'");
}
break;
case INTERFACE:
interface = (Interface *) nType->myDef;
checkTypeInstantiation (nType->typeArgs,
interface->typeParms,
interface,
nType);
break;
case CLASS_DEF:
cl = (ClassDef *) nType->myDef;
checkTypeInstantiation (nType->typeArgs,
cl->typeParms,
cl,
nType);
break;
case TYPE_DEF:
if (nType->typeArgs) {
error (node, "This is the name of a defined type; this type must not be followed with '[TypeArgs]'");
error2 (nType->myDef, "Here is the type definition");
}
break;
default:
programLogicError ("NamedType->myDef is an unexpected value");
}
}
return NULL;
case IF_STMT: // in checkTypes
ifStmt = (IfStmt *) node;
// t = checkTypes (ifStmt->expr); // This is done in checkAssignment
// Make sure the conditional expression has type boolean...
ifStmt->expr = checkAssignment (
ifStmt->expr,
basicBoolType,
"The conditional expression in this IF statement does not have type 'bool'",
NULL);
t = checkTypes (ifStmt->thenStmts);
t = checkTypes (ifStmt->elseStmts);
t = checkTypes (ifStmt->next);
return NULL;
case ASSIGN_STMT: // in checkTypes
assignStmt = (AssignStmt *) node;
// printf ("\n---------------------- About to process: ");
// pretty (node);
// printf (" The lefthand side is:\n");
// printAst (12, assignStmt->lvalue);
// printf (" The righthand side is:\n");
// printAst (12, assignStmt->expr);
// pretty (checkTypes (assignStmt->expr));
t2 = checkTypes (assignStmt->lvalue);
if (!isLValue (assignStmt->lvalue)) {
error (assignStmt->lvalue, "The lefthand side of this assignment is not an l-value; it is not something that can be assigned to");
error (returnStmt->expr, "This method/function returns a value, yet none is provided in this RETURN statement");
}
}
}
t = checkTypes (returnStmt->next);
return NULL;
case FOR_STMT: // in checkTypes
forStmt = (ForStmt *) node;
// printf ("\n---------------------- About to process: ");
// pretty (node);
t2 = checkTypes (forStmt->lvalue);
if (isPtrType (t2)) {
if (safe) {
error (forStmt->lvalue, "Using a ptr as an index in a FOR statement is an unsafe operation; you must compile with the 'unsafe' option if you wish to do this");
}
} else if (!isIntType (t2)) {
error (forStmt->lvalue, "The index of this FOR statement must have type 'int'");
}
if (!isLValue (forStmt->lvalue)) {
error (forStmt->lvalue, "The index of this FOR statement is not an l-value; it is not something that can be assigned to");
}
if (!isPtrType (t2) || !isPtrType (checkTypes (forStmt->expr1))) {
forStmt->expr1 = checkAssignment (
forStmt->expr1,
basicIntType,
"The starting value in this FOR statement does not have the correct type",
NULL);
}
if (!isPtrType (t2) || !isPtrType (checkTypes (forStmt->expr2))) {
forStmt->expr2= checkAssignment (
forStmt->expr2,
basicIntType,
"The stopping value in this FOR statement does not have the correct type",
NULL);
}
// t = checkTypes (forStmt->expr3); // Checked below in checkAssignment
forStmt->expr3 = checkAssignment (
forStmt->expr3,
basicIntType,
"The increment value in this FOR statement does not have the correct type",
NULL);
intConst = (IntConst *) forStmt->expr3;
if (intConst &&
(intConst->op == INT_CONST) &&
(intConst->ivalue < 1)) {
error (forStmt->expr3, "The step expression in this FOR loop is negative");
}
t = checkTypes (forStmt->stmts);
t = checkTypes (forStmt->next);
return NULL;
case SWITCH_STMT: // in checkTypes
switchStmt = (SwitchStmt *) node;
// printf ("\n---------------------- About to process: ");
// pretty (node);
// t = checkTypes (switchStmt->expr);
switchStmt->expr = checkAssignment (
switchStmt->expr,
basicIntType,
"The expression in this SWITCH statement must have type 'int'",
NULL);
// Run through the case clauses and process them...
numberOfCases = 0;
for (cas = switchStmt->caseList; cas != NULL; cas = cas->next) {
numberOfCases = numberOfCases + 1;
// t = checkTypes (cas->expr);
cas->expr = checkAssignment (
cas->expr,
basicIntType,
"The expression following CASE must have type 'int'",
// printf ("\n---------------------- About to process: ");
// pretty (node);
t = checkTypes (freeStmt->expr);
if (!isPtrType (t)) {
error (freeStmt->expr, "The expression in this FREE statement is not a pointer");
}
if (safe) {
error (node, "Using the FREE statement is an unsafe operation; you must compile with the 'unsafe' option if you wish to do this");
}
t = checkTypes (freeStmt->next);
return NULL;
case DEBUG_STMT: // in checkTypes
debugStmt = (DebugStmt *) node;
// printf ("\n---------------------- About to process: ");
// pretty (node);
t = checkTypes (debugStmt->next);
return NULL;
case CASE: // in checkTypes
programLogicError ("This is handled in SWITCH_STMT");
return NULL;
case CATCH: // in checkTypes
cat = (Catch *) node;
t = checkTypes (cat->parmList);
// Take a look at the errorDecl...
if (cat->myDef) {
// Make sure each parm type matches according to contra-variance...
protoParm = cat->myDef->parmList;
subParm = cat->parmList;
while (1) {
if ((protoParm == NULL) && (subParm == NULL)) break;
if ((protoParm == NULL) || (subParm == NULL)) {
error (cat, "This catch does not have the same number of parameters as the corresponding error declaration");
error2 (cat->myDef, "Here is the error declaration");
break;
}
if (! assignable (subParm->type, protoParm->type)) {
error (subParm, "The type of this parameter fails to match the type of the corresponding parameter in the error declaration (perhaps it is not general enough)");
error2 (cat->myDef, "Here is the error declaration");
errorWithType ("The type of this parameter in the error declaration is",
protoParm->type);
errorWithType ("The type of this parameter in the catch clause is",
subParm->type);
}
protoParm = (Parameter *) protoParm->next;
subParm = (Parameter *) subParm->next;
}
}
t = checkTypes (cat->stmts);
// At this point the "offset"s have been assigned sequentially; these
// args will be pushed using these offsets during a throw. Go through
// the parms and copy all offsets into the "throwSideOffset"s.
error (sendExpr, "Taking the address of a function is not allowed; just use the function name directly and a 'ptr to function' will be understood");
}
}
if (isLValue (sendExpr->receiver)) {
sendExpr->primitiveSymbol = PRIMITIVE_ADDRESS_OF;
pType = new PtrType ();
pType->positionAt (sendExpr);
pType->baseType = t;
// If we are compiling with "safe"
if (safe) {
if (sendExpr->receiver->op == FIELD_ACCESS) {
error (sendExpr, "Taking the address of field within a record or object is an unsafe operation; you must compile with the 'unsafe' option if you wish to do this");
}
if (sendExpr->receiver->op == ARRAY_ACCESS) {
error (sendExpr, "Taking the address of an element within an array is an unsafe operation; you must compile with the 'unsafe' option if you wish to do this");
}
if (sendExpr->receiver->op == VARIABLE_EXPR) {
var = (VariableExpr *) sendExpr->receiver;
varDecl = (VarDecl *) var->myDef;
if ((varDecl != NULL) &&
(varDecl->op != GLOBAL)) {
error (sendExpr, "Taking the address of a non-global variable is an unsafe operation; you must compile with the 'unsafe' option if you wish to do this");
// checkTypeInstantiation (typeArgList, typeParmList, proto, invocation)
//
// This routine checks to make sure this arg list matches the parm list in the
// prototype. It is used to check NamedTypes, like:
// List [int]
//
// It checks that every argument is a subtype of the corresponding
// parameter type.
//
// The 'proto' and 'invocation' args are used for error messages only.
//
void checkTypeInstantiation (TypeArg * typeArg,
TypeParm * typeParm,
AstNode * proto,
AstNode * invocation) {
int i;
// Run thru the lists of typeParms and typeArgs in parallel. Check each pair...
while (1) {
if ((typeParm == NULL) && (typeArg == NULL)) break;
if (typeArg == NULL) {
error (invocation, "This class or interface is parameterized but you have given too few types; please add more types in 'Type [Type, Type, ...]'");
error2 (typeParm, "Here is a parameter for which there is no type");
break;
}
if (typeParm == NULL) {
error (invocation, "You have supplied too many type arguments in 'Type [ Type, Type, ...]'");
error2 (proto, "Here is the interface or class definition");
break;
}
if (!isSubType (typeArg->type, typeParm->type)) {
error (invocation, "One of the arguments in 'Type [Type, Type, ...]' fails to match the corresponding constraint type in the interface or class definition");
error2 (typeArg, "Here is the argument that is incorrect");
errorWithType ("It should be equal to (or a subtype of)", typeParm->type);
}
if (typeParm->fourByteRestricted) {
i = sizeInBytesOfWhole (typeArg->type, typeArg->type, 0);
if ((i > 4) || (i == -1)) {
error (invocation, "One of the arguments in 'Type [Type, Type, ...]' has a size that is not 4 bytes or smaller");
error2 (typeArg, "Here is the argument that is causing the problem");
error2 (typeParm, "This type parameter was used in a variable declaration somewhere within the class; this restricts it to being instantiated only with types of size 4 bytes or smaller");
error (assignStmt->lvalue, "In this object assignment, there is no subtype relation between the left-hand side type and the right-hand side type; this object copy cannot succeed at runtime");
errorWithType ("The type of the left-hand side is", expectedType);
errorWithType ("The type of the right-hand side is", t);
return expr;
}
// We can just check class name, e.g., List ?= List. Since we have already
// checked that a subtype relation holds, we can't have something
// like "List[Person] ?= List[Student]...
// printf (" Need to insert dynamic check that both point to same class of object at runtime.\n");
// printf (" Will perform a 'dynamic' object copy.\n");
error (assignStmt->lvalue, "In this object assignment, there is a type error; the pointer on the left-hand side cannot possibly point to an object of the same class as on the right-hand side");
errorWithType ("The type of the left-hand side is", expectedType);
errorWithType ("The type of the right-hand side is", t);
return expr;
}
// We can just check class name, e.g., List ?= List. Since we have already
// checked that a subtype relation holds, we can't have something
// like "List[Person] ?= List[Student]...
// printf (" Inserting dynamic class check to check that *objPtr has class: ");
// pretty (t);
classDef = getClassDef (t);
if (classDef == NULL) {
error (expr, errorMsg);
error2 (expr, "This object assignment calls for a dynamic class-check, but the type of this expression is not a class");
errorWithType ("The type of the expression is", t);
errorWithType ("The expected type is", expectedType);
return expr;
}
// printf (" Will copy %d bytes.\n", classDef->sizeInBytes);
assignStmt->dynamicCheck = 2;
assignStmt->classDef = classDef;
return expr;
// Case 3: OBJECT ASSIGNMENT: x = *objPtr...
} else {
// printf ("===> OBJECT ASSIGNMENT: x = *objPtr...\n");
if (! isSubType (expectedType, t)) {
error (assignStmt->lvalue, "In this object assignment, there is a type error; the pointer on the right-hand side cannot possibly point to an object of the same class as on the left-hand side");
errorWithType ("The type of the left-hand side is", expectedType);
errorWithType ("The type of the right-hand side is", t);
return expr;
}
// We can just check class name, e.g., List ?= List. Since we have already
// checked that a subtype relation holds, we can't have something
// like "List[Person] ?= List[Student]...
// printf (" Inserting dynamic class check to check that *objPtr has class: ");
// pretty (expectedType);
classDef = getClassDef (expectedType);
if (classDef == NULL) {
error (expr, errorMsg);
error2 (expr, "This object assignment calls for a dynamic class-check, but the type of this expression is not a class");
errorWithType ("The type of the expression is", t);
errorWithType ("The expected type is", expectedType);
return expr;
}
// printf (" Will copy %d bytes.\n", classDef->sizeInBytes);
assignStmt->dynamicCheck = 3;
assignStmt->classDef = classDef;
return expr;
}
// ARRAY ASSIGNMENT: array = array
} else if (assignStmt &&
(aType1 = getArrayType (expectedType)) &&
(aType2 = getArrayType (t))) {
// Make sure the base types are type-equal...
if (!typesEqual (aType1->baseType, aType2->baseType)) {
error (assignStmt->lvalue, "In this array assignment statement, the types of the array elements must be the same");
errorWithType ("The type of the left-hand side is", aType1);
errorWithType ("The type of the right-hand side is", aType2);
return expr;
}
// Here are the possible cases...
// arr[10] = arr[10]
// arr[10] = arr[*]
// arr[*] = arr[10]
// arr[*] = arr[*]
// Case 4: ARRAY ASSIGNMENT: arr[10] = arr[10]...
if ((aType1->sizeInBytes >= 0) && (aType2->sizeInBytes >= 0)) {
// printf (" Need to insert dynamic array copy (size not known at compile time)...\n");
// printf (" Must check that sizes are equal at runtime.\n");
i = aType1->sizeOfElements;
// printf (" Will copy 4 + N * %d bytes. (ok to round up to multiple of 4 at runtime)\n", i);
assignStmt->dynamicCheck = 7;
assignStmt->arraySize = i; // Store the size of each element
return expr;
}
} else { // This is not an Assignment Statement...
// Case 8: OBJECT COPY: ... := *objPtr
if (isDeref (expr) && isObjectType (t)) {
// printf ("===> OBJECT COPY: ... := *objPtr\n");
// Make sure that we are expecting a class type.
classDef = getClassDef (expectedType);
if (classDef == NULL) {
error (expr, errorMsg);
error2 (expr, "Dereferencing a ptr to an object calls for dynamic class-check, but the expected type is not a class");
errorWithType ("The type of the expression is", t);
errorWithType ("The expected type is", expectedType);
return expr;
}
if (!isSubType (expectedType, t)) {
error (expr, errorMsg);
errorWithType ("This expression cannot point to the expected class of object; at runtime the class of the object will be... (or one of its subclasses)", t);
errorWithType ("The expected class is", expectedType);
return expr;
}
// We can just check class name, e.g., List ?= List. Since we have already
// checked that a subtype relation holds, we can't have something
// like "List[Person] ?= List[Student]...
// Note: the expected type may contain TypeParms, e.g., "ListImpl2[T1]"...
// printf (" Need to insert dynamic check that this expr has class: ");
// pretty (expectedType);
// Need to insert something...
if (expr->op != DYNAMIC_CHECK) {
dynamicCheck = new DynamicCheck ();
dynamicCheck->positionAt (expr);
dynamicCheck->expr = expr;
dynamicCheck->kind = 8;
dynamicCheck->expectedClassDef = classDef;
return dynamicCheck;
} else {
return expr;
}
// ARRAY COPY: ... := array
} else if ((aType1 = getArrayType (expectedType)) &&
(aType2 = getArrayType (t))) {
// Make sure the base types are type-equal...
if (!typesEqual (aType1->baseType, aType2->baseType)) {
error (expr, errorMsg);
error2 (expr, "When copying an array, the types of the array elements must be the same");
errorWithType ("The type of the expression is", aType1);
errorWithType ("The expected type is", aType2);
return expr;
}
// Here are the possible cases...
// arr[10] = arr[10]
// arr[10] = arr[*]
// arr[*] = arr[10]
// arr[*] = arr[*]
// Case 9: ARRAY COPY: arr[10] = arr[10]...
if ((aType1->sizeInBytes >= 0) && (aType2->sizeInBytes >= 0)) {
if (prevOff != offset) { // This error occurs in "test9>>F>>mess2"
// printf ("***** CONFLICT (1): selector = %s\n",
// sel->chars);
// printf (" abs = %s prevOff = %d\n",
// abs->id->chars, prevOff->ivalue);
// printf (" nextAbs = %s offset = %d\n",
// nextAbs->id->chars, offset->ivalue);
error (abs, "A problem has been encountered when laying out the dispatch table for this class or interface. This class or interface inherits a message from two or more classes or interfaces which are in a different package from the one being compiled now. When the other package was compiled, this message happens to have been assigned different offsets in the different super-classes or super-interfaces. This was possible since the classes or interfaces in the other package were unrelated (e.g., had no common sub-class or sub-interface). The class or interface in which this problem is arising inherits this message from these previously unrelated classes or interfaces. The problem is that it is not possible now to assign this message a single offset consistent with all super-classes and super-interfaces, without changing the offset assigned to this message in the super-classes or super-interfaces. You may resolve this problem by forcing this message to be given identical offsets in all relevant super-classes and super-interfaces. This can be done by adding a dummy class or interface to the other package and making it extend all relevant classes or interfaces in that other package. (Inheritance conflict type 1)");
// If we found an abstract which has this selector at a different offset...
if (prevOff != offset) {
// printf ("***** CONFLICT (2): selector = %s\n",
// sel->chars);
// printf (" abs = %s prevOff = %d\n",
// abs->id->chars, prevOff->ivalue);
// printf (" nextAbs = ? offset = %d\n",
// offset->ivalue);
error (abs, "A problem has been encountered when laying out the dispatch table for this class or interface. This class or interface shares a message with other classes or interfaces via inheritance. Two or more related classes or interfaces in this package inherit this message from classes or interfaces which are in a different package from the one being compiled now. When the other package was compiled, this message happens to have been assigned different offsets in the different super-classes or super-interfaces in that package. This was possible since the classes or interfaces in the other package were unrelated (e.g., had no common sub-class or sub-interface). The class or interface in which this problem is arising must assign an offset to this message that is compatible with these (previously unrelated) classes or interfaces in the other package. The problem is that it is not possible now to assign this message a single offset consistent with all related classes and interfaces, since it is not possible to change the offset assigned to this message in classes or interfaces in other packages. You may resolve this problem by forcing this message to be given identical offsets in all relevant super-classes and super-interfaces. This can be done by adding a dummy class or interface to the other package and making it extend all relevant classes or interfaces in that other package. (Inheritance conflict type 2)");