/** * propagate types through an InstrGraph, starting with root defs * in start and constant instructions. * * Note that per SCCP, types in dead arms of constant conditionals * are set to UN. * * Algorithm outline: we maintain two structures: a worklist * of instructions to evaluate, and a set of instructions * marked reachable. * * Initialize: * 1. Mark the instructions in the root block as reachable. * 2. For each instruction, if it's a root (no uses), then * enque each reachable use. Otherwise set all defs to _ * (bottom). * Propagate: * 1. while worklist not empty, deque instruction I * 2. evaluate I's output types using TypeAnalyzer * 3. If any types changed, AvmAssert(old-T <: new-T) and * enque reachable uses. * 4. If I is a branch, mark and enque reachable arms. */ void propagateTypes(InstrGraph* ir) { Allocator scratch; SCCP sccp(scratch, ir); sccp.init(); sccp.analyze(); AvmAssert(checkTypes(ir, false)); }
void checkErrors(Node* ast, Table* symbols, Table* main) { if(ast->n_type == NODE_CALL) { ast->type = checkifIDExists(ast->id->id,TABLE_METHOD,symbols,main); } else if(ast->n_type == NODE_ID) { ast->type = checkifIDExists(ast->value,TABLE_DECL,symbols,main); } else if(ast->n_type == NODE_INTLIT){ validIntLit(ast->value); } checkTypes(ast,main); }
void checkTypes(SymbolEntry entry, Symbol returnType) { if (entry.isArray()) { SymbolList list; SymbolArray array = entry.array(); for (int i = 0; i < array.count(); ++i) checkTypes(array[i], returnType); } if (!entry.isSymbol()) return; Symbol symbol = entry.symbol(); switch (symbol.atom()) { case atomLogicalOr: case atomLogicalAnd: assertTypeBoolean(symbol[1].symbol()); assertTypeBoolean(symbol[2].symbol()); break; case atomFunctionCall: { Symbol function = symbol[1].symbol(); SymbolArray parameterTypes = typeOf(function)[2].array(); SymbolArray argumentTypes = typeOf(symbol[2]).array(); if (parameterTypes != argumentTypes) spanOf(symbol).throwError( "function requires arguments of types " + typesToString(parameterTypes) + " but passed arguments of types " + typesToString(argumentTypes)); } break; case atomFunctionDefinitionStatement: checkTypes(symbol[3], returnType); checkTypes(symbol[4], symbol[1].symbol()); return; case atomVariableDefinitionStatement: { Symbol initializerType = typeOf(symbol[3]); Symbol variableType = typeOf(symbol[1]); if (variableType != initializerType) spanOf(symbol).throwError("variable declared as type " + typeToString(variableType) + " but initialized with expression of type " + typeToString(initializerType)); } break; case atomIfStatement: assertTypeBoolean(symbol[1].symbol()); break; case atomSwitchStatement: { Symbol type = typeOf(symbol[1]); SymbolArray cases = symbol[2].array(); for (int i = 0; i < cases.count(); ++i) { Symbol c = cases[i]; SymbolArray expressions = c[1].array(); for (int j = 0; j < expressions.count(); ++j) { Symbol expression = expressions[j]; Symbol expressionType = typeOf(expression); if (type != expressionType) spanOf(expression).throwError( "can't compare an expression of type " + typeToString(type) + " to an expression of type " + typeToString(expressionType)); } } } break; case atomReturnStatement: { Symbol expression = symbol[1].symbol(); Symbol type; if (expression.valid()) type = typeOf(expression); else type = Symbol(atomVoid); if (type != returnType) spanOf(symbol).throwError( "returning an expression of type " + typeToString(type) + " from a function with return type " + typeToString(returnType)); } break; case atomIncludeStatement: { Symbol expression = symbol[1].symbol(); Symbol type = typeOf(expression); if (type.atom() != atomString) spanOf(expression).throwError( "argument to include is of type " + typeToString(type) + ", expected String"); } break; case atomFromStatement: { Symbol expression = symbol[1].symbol(); Symbol type = typeOf(expression); if (type.atom() != atomString) spanOf(expression).throwError( "argument to from is of type " + typeToString(type) + ", expected String"); } break; case atomWhileStatement: case atomUntilStatement: case atomForStatement: assertTypeBoolean(symbol[2].symbol()); break; case atomGotoStatement: { Symbol expression = symbol[1].symbol(); Symbol type = typeOf(expression); if (type.atom() != atomLabel) if (type.atom() != atomLabel) spanOf(expression).throwError( "expression is of type " + typeToString(type) + ", Label expected"); } break; case atomEmit: // TODO: Check that type of argument is Sequence<Compiler.Instruction> break; } const SymbolTail* tail = symbol.tail(); while (tail != 0) { checkTypes(tail->head(), returnType); tail = tail->tail(); } }