001 /* 002 * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered 003 * by the modified BSD License. You should have received a copy of the 004 * modified BSD license with this compiler. 005 * 006 * Copyright (c) 2005-2008, Torbjorn Ekman 007 * All rights reserved. 008 */ 009 010 aspect AutoBoxing { 011 012 013 /* NumericTypes, BooleanTypes 014 TypeChecking (ensure that an expression of a certain type is valid in a particular context) 015 TypeComputation (compute the type of an expression) 016 CodeGeneration (output code including implicit type conversions and promotions) 017 018 NumericTypes: 019 binaryNumericPromotion, unaryNumericPromotion, assignmentConversion, methodInvocationConversion, castingConversion 020 numeric operations that do not use these kinds of conversions and promotions explicitly need to be refined 021 BooleanTypes: 022 assignmentConversion, methodInvocationConversion, castingConversion 023 024 */ 025 026 027 028 029 // 5.1.7 Boxing Conversion 030 031 syn boolean TypeDecl.boxingConversionTo(TypeDecl typeDecl) = false; 032 eq PrimitiveType.boxingConversionTo(TypeDecl typeDecl) = boxed() == typeDecl; 033 034 // Mapping between Primitive type and corresponding boxed Reference type 035 syn lazy TypeDecl TypeDecl.boxed() = unknownType(); 036 eq BooleanType.boxed() = lookupType("java.lang", "Boolean"); 037 eq ByteType.boxed() = lookupType("java.lang", "Byte"); 038 eq CharType.boxed() = lookupType("java.lang", "Character"); 039 eq ShortType.boxed() = lookupType("java.lang", "Short"); 040 eq IntType.boxed() = lookupType("java.lang", "Integer"); 041 eq LongType.boxed() = lookupType("java.lang", "Long"); 042 eq FloatType.boxed() = lookupType("java.lang", "Float"); 043 eq DoubleType.boxed() = lookupType("java.lang", "Double"); 044 045 // 5.1.8 Unboxing Conversion 046 047 syn boolean TypeDecl.unboxingConversionTo(TypeDecl typeDecl) = false; 048 eq ReferenceType.unboxingConversionTo(TypeDecl typeDecl) = unboxed() == typeDecl; 049 050 // Mapping between Reference type and corresponding unboxed Primitive type 051 syn lazy TypeDecl TypeDecl.unboxed() = unknownType(); 052 eq ReferenceType.unboxed() { 053 if(packageName().equals("java.lang") && isTopLevelType()) { 054 String n = name(); 055 if(n.equals("Boolean")) return typeBoolean(); 056 if(n.equals("Byte")) return typeByte(); 057 if(n.equals("Character")) return typeChar(); 058 if(n.equals("Short")) return typeShort(); 059 if(n.equals("Integer")) return typeInt(); 060 if(n.equals("Long")) return typeLong(); 061 if(n.equals("Float")) return typeFloat(); 062 if(n.equals("Double")) return typeDouble(); 063 } 064 return unknownType(); 065 } 066 inh TypeDecl ReferenceType.typeBoolean(); 067 inh TypeDecl ReferenceType.typeByte(); 068 inh TypeDecl ReferenceType.typeChar(); 069 inh TypeDecl ReferenceType.typeShort(); 070 inh TypeDecl ReferenceType.typeInt(); 071 inh TypeDecl ReferenceType.typeLong(); 072 inh TypeDecl ReferenceType.typeFloat(); 073 inh TypeDecl ReferenceType.typeDouble(); 074 075 076 // 5.2 Assignment Conversion 077 refine TypeConversion eq TypeDecl.assignConversionTo(TypeDecl type, Expr expr) { 078 if(refined(type, expr)) 079 return true; 080 boolean canBoxThis = this instanceof PrimitiveType; 081 boolean canBoxType = type instanceof PrimitiveType; 082 boolean canUnboxThis = !unboxed().isUnknown(); 083 boolean canUnboxType = !type.unboxed().isUnknown(); 084 TypeDecl t = !canUnboxThis && canUnboxType ? type.unboxed() : type; 085 boolean sourceIsConstant = expr != null ? expr.isConstant() : false; 086 if(sourceIsConstant && (isInt() || isChar() || isShort() || isByte()) && 087 (t.isByte() || t.isShort() || t.isChar()) && 088 narrowingConversionTo(t) && expr.representableIn(t)) 089 return true; 090 if(canBoxThis && !canBoxType && boxed().wideningConversionTo(type)) 091 return true; 092 else if(canUnboxThis && !canUnboxType && unboxed().wideningConversionTo(type)) 093 return true; 094 095 return false; 096 } 097 098 // 5.3 Method Invocation Conversion 099 refine TypeConversion eq TypeDecl.methodInvocationConversionTo(TypeDecl type) { 100 if(refined(type)) 101 return true; 102 boolean canBoxThis = this instanceof PrimitiveType; 103 boolean canBoxType = type instanceof PrimitiveType; 104 boolean canUnboxThis = !unboxed().isUnknown(); 105 boolean canUnboxType = !type.unboxed().isUnknown(); 106 if(canBoxThis && !canBoxType) 107 return boxed().wideningConversionTo(type); 108 else if(canUnboxThis && !canUnboxType) 109 return unboxed().wideningConversionTo(type); 110 return false; 111 } 112 113 // 5.5 Casting Conversion 114 refine TypeConversion eq TypeDecl.castingConversionTo(TypeDecl type) { 115 if(refined(type)) 116 return true; 117 boolean canBoxThis = this instanceof PrimitiveType; 118 boolean canBoxType = type instanceof PrimitiveType; 119 boolean canUnboxThis = !unboxed().isUnknown(); 120 boolean canUnboxType = !type.unboxed().isUnknown(); 121 if(canBoxThis && !canBoxType) 122 return boxed().wideningConversionTo(type); 123 else if(canUnboxThis && !canUnboxType) 124 return unboxed().wideningConversionTo(type); 125 return false; 126 /* 127 else if(boxingConversionTo(type)) 128 return true; 129 else if(unboxingConversionTo(type)) 130 return true; 131 return false; 132 */ 133 } 134 refine Generics eq ClassDecl.castingConversionTo(TypeDecl type) { 135 if(refined(type)) 136 return true; 137 boolean canUnboxThis = !unboxed().isUnknown(); 138 boolean canUnboxType = !type.unboxed().isUnknown(); 139 if(canUnboxThis && !canUnboxType) 140 return unboxed().wideningConversionTo(type); 141 return false; 142 /* 143 else if(unboxingConversionTo(type)) 144 return true; 145 return false; 146 */ 147 } 148 refine Generics eq InterfaceDecl.castingConversionTo(TypeDecl type) { 149 if(refined(type)) 150 return true; 151 boolean canUnboxThis = !unboxed().isUnknown(); 152 boolean canUnboxType = !type.unboxed().isUnknown(); 153 if(canUnboxThis && !canUnboxType) 154 return unboxed().wideningConversionTo(type); 155 return false; 156 /* 157 else if(unboxingConversionTo(type)) 158 return true; 159 return false; 160 */ 161 } 162 //eq PrimitiveType.castingConversionTo(TypeDecl type) = 163 // type.isReferenceType() ? boxed().castingConversionTo(type) : super.castingConversionTo(type); 164 165 //refine Generics eq ClassDecl.castingConversionTo(TypeDecl type) { 166 // return type.isPrimitiveType() && !unboxed().isUnknown() ? unboxed().castingConversionTo(type) : refined(type); 167 //} 168 169 // 5.6.1 Unary Numeric Promotion 170 eq ReferenceType.unaryNumericPromotion() = isNumericType() && !isUnknown() ? unboxed().unaryNumericPromotion() : this; 171 eq UnknownType.unaryNumericPromotion() = this; 172 173 // 5.6.2 Binary Numeric Promotion 174 eq ReferenceType.binaryNumericPromotion(TypeDecl type) = unboxed().binaryNumericPromotion(type); 175 refine NumericPromotion eq NumericType.binaryNumericPromotion(TypeDecl type) { 176 if(type.isReferenceType()) 177 type = type.unboxed(); 178 return refined(type); 179 } 180 181 refine TypeAnalysis eq ConditionalExpr.type() { 182 TypeDecl trueType = getTrueExpr().type(); 183 TypeDecl falseType = getFalseExpr().type(); 184 if(trueType.isBoolean() && falseType.isBoolean()) { 185 if(trueType == falseType) 186 return trueType; 187 if(trueType.isReferenceType()) 188 return trueType.unboxed(); 189 return trueType; 190 } 191 return refined(); 192 } 193 194 eq UnknownType.binaryNumericPromotion(TypeDecl type) = this; 195 196 eq ReferenceType.isNumericType() = 197 !unboxed().isUnknown() && unboxed().isNumericType(); 198 199 eq ReferenceType.isIntegralType() = 200 !unboxed().isUnknown() && unboxed().isIntegralType(); 201 202 eq ReferenceType.isPrimitive() = 203 !unboxed().isUnknown() && unboxed().isPrimitive(); 204 205 refine ConstantExpression eq Binary.binaryNumericPromotedType() { 206 TypeDecl leftType = left().type(); 207 TypeDecl rightType = right().type(); 208 if(leftType.isBoolean() && rightType.isBoolean()) { 209 return leftType.isReferenceType() ? leftType.unboxed() : leftType; 210 } 211 return refined(); 212 } 213 214 // Affects type checking of 14.9 If, 14.10 Assert, 14.12 While, 14.13 Do, 14.14 For 215 eq ReferenceType.isBoolean() = fullName().equals("java.lang.Boolean") && unboxed().isBoolean(); 216 // Code generation need to add unboxing if the conditional is a Boxed value 217 // this is done by inserting a new node with an explicit cast 218 219 220 221 // 15.15.6 Logical Complement Operator ! 222 // type() 223 224 // 15.21.2 Boolean Equality Operators == and != 225 // If the operands of an equality operator are both of type boolean, or if 226 // one operand is of type boolean and the other is of type Boolean, then 227 // the operation is boolean equality. The boolean equality operators are 228 // associative. If one of the operands is of type Boolean it is subjected 229 // to unboxing conversion (�5.1.8) 230 231 // 15.22.2 Boolean Logical Operators &, ^, and | 232 // emitCastTo(), type() 233 234 // When both operands of a &, ^, or | operator are of type boolean or 235 // Boolean, then the type of the bitwise operator expression is boolean. 236 // In all cases, the operands are subject to unboxing conversion (�5.1.8) 237 // as necessary. 238 239 // 15.23 Conditional-And Operator && 240 // Each operand of && must be of type boolean or Boolean, or a compile-time error occurs. 241 // At run time, the left-hand operand expression is evaluated first; if 242 // the result has type Boolean, it is subjected to unboxing conversion 243 // (�5.1.8); 244 245 // 15.24 Conditional-Or Operator || 246 // See 15.23 247 248 // 15.25 Conditional Operator ? : 249 // See Spec 250 251 252 }