/* st-sglobal_infer.cc: infer sglobal qualifiers for methods */ #include "AST.h" #include "compiler.h" #include "decls.h" #include "errors.h" static bool change; static Decl *currentMethod; static void markMethodSglobal() { if (!(currentMethod->modifiers() & Common::Sglobal)) { currentMethod->modifiers((Common::Modifiers)(currentMethod->modifiers() | Common::Sglobal)); change = true; } } // Set sglobal on a method if it assigns a single field or a single // array element (with exception of this.field in constructors) static bool inConstructor; void TreeNode::sglobalData() { foriter (p, allChildren(), ChildIter) (*p)->sglobalData(); } void TemplateDeclNode::sglobalData() { } // Class members void MethodSignatureNode::sglobalData() { // nothing to do } void FieldDeclNode::sglobalData() { } void StaticInitNode::sglobalData() { } void InstanceInitNode::sglobalData() { // TODO: what are the single rules for instance initializers? } void MethodDeclNode::sglobalData() { bool declaredSingle = (decl()->modifiers() & Sglobal) != 0; if (!declaredSingle) { currentMethod = decl(); inConstructor = false; TreeNode::sglobalData(); currentMethod = NULL; } } void ConstructorDeclNode::sglobalData() { bool declaredSingle = (decl()->modifiers() & Sglobal) != 0; if (!declaredSingle) { currentMethod = decl(); inConstructor = true; TreeNode::sglobalData(); currentMethod = NULL; } } void IncrDecrNode::sglobalData() { child(0)->sglobalDataAssign(); } void BinaryArithAssignNode::sglobalData() { child(0)->sglobalDataAssign(); } void ShiftAssignNode::sglobalData() { child(0)->sglobalDataAssign(); } void BitwiseAssignNode::sglobalData() { child(0)->sglobalDataAssign(); } void AssignNode::sglobalData() { child(0)->sglobalDataAssign(); } void StringConcatAssignNode::sglobalData() { child(0)->sglobalDataAssign(); } void MethodCallAssignNode::sglobalData() { method()->object()->sglobalDataAssign(); } void TreeNode::sglobalDataAssign() { undefined("sglobalDataAssign"); } void ObjectNode::sglobalDataAssign() { // Local variables don't count } void ArrayAccessNode::sglobalDataAssign() { if (array()->type()->elementType()->isSingle()) markMethodSglobal(); } void FieldAccessNode::sglobalDataAssign() { if (decl()->type()->isSingle()) markMethodSglobal(); } void ThisFieldAccessNode::sglobalDataAssign() { if (decl()->type()->isSingle() && ((decl()->modifiers() & Static) || !inConstructor)) markMethodSglobal(); } // Set sglobal on a method whenever it may call a method that is sglobal void TreeNode::sglobalCall() { foriter (p, allChildren(), ChildIter) (*p)->sglobalCall(); } void TemplateDeclNode::sglobalCall() { } // Class members void MethodSignatureNode::sglobalCall() { // nothing to do } void FieldDeclNode::sglobalCall() { } void StaticInitNode::sglobalCall() { } void InstanceInitNode::sglobalCall() { // TODO: what are the single rules for instance initializers? } void MethodDeclNode::sglobalCall() { bool declaredSingle = (decl()->modifiers() & Sglobal) != 0; if (!declaredSingle) { currentMethod = decl(); TreeNode::sglobalCall(); currentMethod = NULL; } #if 0 /* disabled for now - if we really want to support it this has to happen before typechecking, otherwise we get type errors due to mismatched types */ if (decl()->isMain()) { /* main's args are implicitly single */ TypeNode *paramtype = params()->child(0)->decl()->type(); paramtype->modifiers((Common::Modifiers)(paramtype->modifiers() | Common::Single)); paramtype->elementType()->modifiers( (Common::Modifiers)(paramtype->elementType()->modifiers() | Common::Single)); } #endif } void ConstructorDeclNode::sglobalCall() { bool declaredSingle = (decl()->modifiers() & Sglobal) != 0; if (!declaredSingle) { currentMethod = decl(); TreeNode::sglobalCall(); currentMethod = NULL; } } void MethodCallNode::sglobalCall() { if (isGlobalCall(decl())) markMethodSglobal(); } void MethodCallAssignNode::sglobalCall() { if (isGlobalCall(decl())) markMethodSglobal(); } void ThisConstructorCallNode::sglobalCall() { if (isGlobalCall(decl())) markMethodSglobal(); } void SuperConstructorCallNode::sglobalCall() { if (decl() && isGlobalCall(decl())) markMethodSglobal(); } void AllocateNode::sglobalCall() { if (isGlobalCall(decl())) markMethodSglobal(); } void BroadcastNode::sglobalCall() { markMethodSglobal(); } //////////////////////////////////////////////////////////////////////// void TreeNode::checkSglobal() const { undefined( "checkSglobal" ); } void CompileUnitNode::checkSglobal() const { foriter (type, types()->allChildren(), TreeNode::ChildIter) (*type)->checkSglobal(); } void TemplateDeclNode::checkSglobal() const { } void ClassDeclNode::checkSglobal() const { foriter (member, members()->allChildren(), TreeNode::ChildIter) (*member)->checkSglobal(); } void MethodNode::checkSglobal() const { Decl *d = decl(); Decl *od = d->overrides(); int global = (d->modifiers() & Common::Sglobal); if (global && od && !(od->modifiers() & Common::Sglobal)) { error() << "overriding of " << od->errorName() << " adds 'single'" << endl; } const MethodSet &implements = d->implements(); for (MethodSet::const_iterator interface = implements.begin(); interface != implements.end(); ++interface) { if (global && !((*interface)->modifiers() & Common::Sglobal)) { error() << "overriding of " << (*interface)->errorName() << " adds 'single'" << endl; } } } void MethodDeclNode::checkSglobal() const { MethodNode::checkSglobal(); } void InterfaceDeclNode::checkSglobal() const { foriter (member, members()->allChildren(), TreeNode::ChildIter) (*member)->checkSglobal(); } void FieldDeclNode::checkSglobal() const { } void StaticInitNode::checkSglobal() const { } void InstanceInitNode::checkSglobal() const { } void ConstructorDeclNode::checkSglobal() const { } void MethodSignatureNode::checkSglobal() const { MethodNode::checkSglobal(); } void OmittedNode::checkSglobal() const { } //////////////////////////////////////////////////////////////////////// void sglobalInference(void) { foreach (f, llist, *allFiles) (*f)->sglobalData(); do { change = false; foreach (f, llist, *allFiles) (*f)->sglobalCall(); } while (change); foreach(f, llist, *allFiles) (*f)->checkSglobal(); }