/* types.cc: Definitions for member functions that determine types. */ #include "utils.h" #include "AST.h" #include "decls.h" #include "compiler.h" #include "sharing.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: fatal_error(""); 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 = dynamic_cast(theClass())->deepClone(); 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 *MethodCallNode::declaredType() { const Decl &declaration = *method()->decl(); TypeNode * const declaredType = declaration.type()->declaredReturnType(); if (declaredType->hasReference()) return declaredType; else return declaredType->addModifiers( Local ); } TypeNode* MethodCallAssignNode::__type() { if (isRewrittenRHSOpOverload()) return args()->child(0)->type(); else 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; } typedef Common::Modifiers Modifiers; static Modifiers sharingLub(Modifiers mod1, Modifiers mod2) { Modifiers res = sharingToModifiers(lub(modifiersToSharing(mod1), modifiersToSharing(mod2))); if ((mod1 & Common::SharingInferred) && (mod2 & Common::SharingInferred)) res = (Modifiers) (res | Common::SharingInferred); return res; } static Modifiers localLub(Modifiers mod1, Modifiers mod2) { Modifiers res = Common::None; if ((mod1 & Common::LocalInferred) && (mod2 & Common::LocalInferred)) res = (Modifiers) (res | Common::LocalInferred); if ((mod1 & Common::Local) && (mod2 & Common::Local)) res = (Modifiers) (res | Common::Local); return res; } static Modifiers singleLub(Modifiers mod1, Modifiers mod2) { Modifiers res = Common::None; if ((mod1 & Common::Single) && (mod2 & Common::Single)) res = (Modifiers) (res | Common::Single); return res; } static Modifiers modifiersLub(Modifiers mod1, Modifiers mod2) { Modifiers res = Common::None; res = (Modifiers) (res | sharingLub(mod1, mod2)); res = (Modifiers) (res | localLub(mod1, mod2)); res = (Modifiers) (res | singleLub(mod1, mod2)); return res; } const Modifiers qualMask = (Modifiers) ~(Common::LocalInferred | Common::Local | Common::SharingInferred | Common::PolysharedQ | Common::NonsharedQ | Common::Single); TypeNode* IfExprNode::__type() { TypeNode* thenType = thenOpnd()->type(); TypeNode* elseType = elseOpnd()->type(); if (thenType->typeIdent(elseType)) return thenType; if (thenType->isNullType()) return elseType; else if (elseType->isNullType()) 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() || thenType->isImmutable()) { // This works for both references and immutables. For immutables, the // resulting modifiers will never include illegal ones such as local, // since the operands cannot include those modifiers. For the special // case of one operand being reference and the other immutable (Domain // and RectDomain), the resulting type will be Domain and so can have // any modifiers. Modifiers mod = None; thenType = thenType->clone(); elseType = elseType->clone(); mod = modifiersLub(thenType->modifiers(), elseType->modifiers()); thenType->modifiers((Modifiers) (mod | (thenType->modifiers() & qualMask))); elseType->modifiers((Modifiers) (mod | (elseType->modifiers() & qualMask))); if (thenType->isAssignableFromType(elseType)) return thenType; else return elseType; } 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_