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    }