/* types.cc: Definitions for member functions that determine types. */ #include "utils.h" #include "AST.h" #include "decls.h" #include "compiler.h" /* The type of this node (only makes sense for ExprNodes, but I'll set */ /* it for other types as well) */ TypeNode* TreeNode::type() { return theVoidType; } // Memoize expression types TypeNode* ExprNode::type() { if (_type == NULL) _type = __type(); return _type; } void ExprNode::type(TypeNode *t) { _type = t; } TypeNode* IncrDecrNode::__type() { return opnd0()->type(); } TypeNode* UnaryArithNode::__type() { return arithPromoteType(opnd0()->type()); } TypeNode* BinaryArithNode::__type() { return arithPromoteType(opnd0()->type(), opnd1()->type()); } TypeNode* BinaryArithAssignNode::__type() { return opnd0()->type(); } TypeNode* ShiftNode::__type() { return arithPromoteType(opnd0()->type()); } TypeNode* ShiftAssignNode::__type() { return opnd0()->type(); } TypeNode* RelationNode::__type() { return theBoolType; } TypeNode* EqualityNode::__type() { return theBoolType; } TypeNode* BitwiseNode::__type() { return arithPromoteType(opnd0()->type(), opnd1()->type()); } TypeNode* BitwiseAssignNode::__type() { return opnd0()->type(); } TypeNode* LogCondNode::__type() { return theBoolType; } TypeNode* PrimitiveLitNode::__type() { switch (literal().kind()) { case Common::ByteKind: return theByteType; case Common::ShortKind: return theShortType; case Common::CharKind: return theCharType; case Common::IntKind: return theIntType; case Common::LongKind: return theLongType; case Common::FloatKind: return theFloatType; case Common::DoubleKind: return theDoubleType; case Common::BoolKind: return theBoolType; default: assert(0); return 0; } } TypeNode* StringLitNode::__type() { static TypeNode * const localString = StringDecl->asType()->addModifiers(Local); return localString; } TypeNode* ArrayInitNode::__type() { return theArrayInitializerType; } TypeNode* NullPntrNode::__type() { return theNullType; } TypeNode* ThisNode::__type() { TypeNode *t = new TypeNameNode(theClass()->name()); t->modifiers( (Modifiers) (flags() & (Local | NonsharedQ | PolysharedQ)) ); return t; } TypeNode *TypeNode::componentAccessType( bool nearby ) { if (nearby) if (hasReference()) return this; else return addModifiers( Local ); else return removeModifiers( (Modifiers) (Local | LocalInferred) ); } TypeNode* ArrayAccessNode::__type() { const TypeNode *atype = array()->type(); if (!atype->isArrayType()) // error return theIntType; return atype->elementType()->componentAccessType( atype->isLocal() ); } TypeNode* ObjectNode::__type() { const Decl &declaration = *decl(); TypeNode * const declaredType = declaration.type(); if (declaredType->hasReference()) return declaredType; else return declaredType->addModifiers( Local ); } TypeNode* FieldAccessNode::__type() { const Decl * const fieldDecl = decl(); if (fieldDecl) { const bool nearby = (fieldDecl->modifiers() & Static) || accessedObjectType()->isLocal(); // If PR #327 ever gets fixed, change this so that "nearby" is // false for statics: // // const bool nearby = accessedObjectType()->isLocal(); // // That should work because I think that accessedObjectType() // always returns a global type for static fields. return fieldDecl->type()->componentAccessType( nearby ); } else return 0; } TypeNode* MethodCallNode::__type() { const Decl &declaration = *method()->decl(); TypeNode * const declaredType = declaration.type()->returnType(); if (declaredType->hasReference()) return declaredType; else return declaredType->addModifiers( Local ); } TypeNode* MethodCallAssignNode::__type() { return method()->object()->type(); } TypeNode* AllocateNode::__type() { TypeNode *t = dtype(); // Result of NEW... is local if the class is not immutable. if (dtype()->kind() == ClassKind) t = t->addModifiers( Local ); return t; } TypeNode* AllocateSpaceNode::__type() { TypeNode *t = dtype(); // Result of NEW... is local if the class is not immutable. if (dtype()->kind() == ClassKind) t = t->addModifiers( Local ); return t; } TypeNode* AllocateArrayNode::__type() { TypeNode *t = makeTiArrayType(dtype(), dimExprs(), 0); // Result of NEW... is local if (dimExprs()->arity()) t = t->addModifiers( Local ); return t; } TypeNode* ComplementNode::__type() { return arithPromoteType(opnd0()->type()); } TypeNode* NotNode::__type() { return theBoolType; } TypeNode* HasNoOverlapNode::__type() { return theBoolType; } TypeNode* CastNode::__type() { return dtype(); } TypeNode* PlusNode::__type() { TypeNode *type0 = opnd0()->type(); TypeNode *type1 = opnd1()->type(); if (type0->isStringType() || type1->isStringType()) { static TypeNode * const localString = StringDecl->asType()->addModifiers(Local); return localString; } else return arithPromoteType(type0, type1); } TypeNode* StringConcatNode::__type() { static TypeNode * const localString = StringDecl->asType()->addModifiers(Local); return localString; } TypeNode* StringConcatAssignPreLoweringNode::__type() { static TypeNode * const localString = StringDecl->asType()->addModifiers(Local); return localString; } TypeNode* InstanceOfNode::__type() { return theBoolType; } static bool validIf(TreeNode *e1, TypeNode *t1, TreeNode *e2, TypeNode *t2, Common::Kind kind) { return t1->kind() == kind && t1->isAssignableFromConstant(e2) || t2->kind() == kind && t2->isAssignableFromConstant(e1); } TypeNode* CodeLiteralExprNode::__type() { return theVoidType; } TypeNode* CodeLiteralFieldAccessNode::__type() { return theVoidType; } TypeNode* IfExprNode::__type() { TypeNode* thenType = thenOpnd()->type(); TypeNode* elseType = elseOpnd()->type(); if (thenType->typeIdent(elseType)) return thenType; if (thenType->isArithType()) { if ((thenType->kind() == ByteKind && elseType->kind() == ShortKind) || (thenType->kind() == ShortKind && elseType->kind() == ByteKind)) return theShortType; if (validIf(thenOpnd(), thenType, elseOpnd(), elseType, ByteKind)) return theByteType; if (validIf(thenOpnd(), thenType, elseOpnd(), elseType, ShortKind)) return theShortType; if (validIf(thenOpnd(), thenType, elseOpnd(), elseType, CharKind)) return theCharType; } else if (thenType->isReference()) if (thenType->isAssignableFromType(elseType)) return thenType; else return elseType; else if (thenType->isImmutable()) return thenType; return arithPromoteType(thenType, elseType); } TypeNode* AssignNode::__type() { return opnd0()->type(); } TypeNode* PointNode::__type() { return makePointType(args()->arity()); } TypeNode* DomainNode::__type() { int arity = args()->arity(); // Handle both domain syntaxes if (arity == 1) // the expressions should be points, return arity of first point { TypeNode *type1 = args()->child(0)->child(0)->type(); if (type1->isPointType()) arity = type1->tiArity(); } return makeRectDomainType(arity); } // Return true if immutable type t contains no reference type, single non-static fields static bool hasNoSingleReferences(const TypeNode *t) { foriter (field, t->decl()->environ()->allDecls(Decl::Field), EnvironIter) if (!(field->modifiers() & Common::Static) && field->type()->isSingle() && field->type()->isReference()) return false; return true; } #define BROADCASTNODE_(nodetype) \ TypeNode* nodetype::__type() \ { \ const TypeNode &exprType = *expr()->type(); \ const Modifiers exprMods = exprType.modifiers(); \ \ int resultMods = exprMods & ~(Local | LocalInferred); \ if (exprType.isImmutable() && hasNoSingleReferences(&exprType) || \ exprType.isPrimitive() || \ /* Make sure points & co behave like immutables even if the */ \ /* ti.internal spec suggests they aren't */ \ exprType.isPointType() || \ exprType.isDomainType() || \ exprType.isRectDomainType()) \ resultMods |= Single; \ else \ resultMods &= ~Single; \ \ return exprType.newModifiers((Modifiers) resultMods); \ } BROADCASTNODE_(BroadcastNode) BROADCASTNODE_(IBroadcastNode) #undef BROADCASTNODE_