Added patch from #1437426: error in assign template
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / ArrayInitializer.java
1 /***********************************************************************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others. All rights reserved. This program and the accompanying materials are made
3  * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at
4  * http://www.eclipse.org/legal/cpl-v10.html
5  * 
6  * Contributors: IBM Corporation - initial API and implementation
7  **********************************************************************************************************************************/
8 package net.sourceforge.phpdt.internal.compiler.ast;
9
10 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
11 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
12 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
13 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
14 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
15 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
16 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
17
18 public class ArrayInitializer extends Expression {
19   public Expression[] expressions;
20
21   public ArrayBinding binding; //the type of the { , , , }
22
23   /**
24    * ArrayInitializer constructor comment.
25    */
26   public ArrayInitializer() {
27     super();
28   }
29
30   public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
31     if (expressions != null) {
32       for (int i = 0, max = expressions.length; i < max; i++) {
33         flowInfo = expressions[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
34       }
35     }
36     return flowInfo;
37   }
38
39   /**
40    * Code generation for a array initializer
41    */
42   //public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
43   //    // Flatten the values and compute the dimensions, by iterating in depth into nested array initializers
44   //
45   //    int pc = codeStream.position;
46   //    int expressionLength = (expressions == null) ? 0: expressions.length;
47   //    codeStream.generateInlinedValue(expressionLength);
48   //    codeStream.newArray(currentScope, binding);
49   //    if (expressions != null) {
50   //            // binding is an ArrayType, so I can just deal with the dimension
51   //            int elementsTypeID = binding.dimensions > 1 ? -1 : binding.leafComponentType.id;
52   //            for (int i = 0; i < expressionLength; i++) {
53   //                    Expression expr;
54   //                    if ((expr = expressions[i]).constant != NotAConstant) {
55   //                            switch (elementsTypeID) { // filter out initializations to default values
56   //                                    case T_int :
57   //                                    case T_short :
58   //                                    case T_byte :
59   //                                    case T_char :
60   //                                    case T_long :
61   //                                            if (expr.constant.longValue() != 0) {
62   //                                                    codeStream.dup();
63   //                                                    codeStream.generateInlinedValue(i);
64   //                                                    expr.generateCode(currentScope, codeStream, true);
65   //                                                    codeStream.arrayAtPut(elementsTypeID, false);
66   //                                            }
67   //                                            break;
68   //                                    case T_float :
69   //                                    case T_double :
70   //                                            double constantValue = expr.constant.doubleValue();
71   //                                            if (constantValue == -0.0 || constantValue != 0) {
72   //                                                    codeStream.dup();
73   //                                                    codeStream.generateInlinedValue(i);
74   //                                                    expr.generateCode(currentScope, codeStream, true);
75   //                                                    codeStream.arrayAtPut(elementsTypeID, false);
76   //                                            }
77   //                                            break;
78   //                                    case T_boolean :
79   //                                            if (expr.constant.booleanValue() != false) {
80   //                                                    codeStream.dup();
81   //                                                    codeStream.generateInlinedValue(i);
82   //                                                    expr.generateCode(currentScope, codeStream, true);
83   //                                                    codeStream.arrayAtPut(elementsTypeID, false);
84   //                                            }
85   //                                            break;
86   //                                    default :
87   //                                            if (!(expr instanceof NullLiteral)) {
88   //                                                    codeStream.dup();
89   //                                                    codeStream.generateInlinedValue(i);
90   //                                                    expr.generateCode(currentScope, codeStream, true);
91   //                                                    codeStream.arrayAtPut(elementsTypeID, false);
92   //                                            }
93   //                            }
94   //                    } else if (!(expr instanceof NullLiteral)) {
95   //                            codeStream.dup();
96   //                            codeStream.generateInlinedValue(i);
97   //                            expr.generateCode(currentScope, codeStream, true);
98   //                            codeStream.arrayAtPut(elementsTypeID, false);
99   //                    }
100   //            }
101   //    }
102   //    if (!valueRequired) {
103   //            codeStream.pop();
104   //    }
105   //    codeStream.recordPositionsFrom(pc, this.sourceStart);
106   //}
107   public StringBuffer printExpression(int indent, StringBuffer output) {
108
109     output.append('{');
110     if (expressions != null) {
111       int j = 20;
112       for (int i = 0; i < expressions.length; i++) {
113         if (i > 0)
114           output.append(", "); //$NON-NLS-1$
115         expressions[i].printExpression(0, output);
116         j--;
117         if (j == 0) {
118           output.append('\n');
119           printIndent(indent + 1, output);
120           j = 20;
121         }
122       }
123     }
124     return output.append('}');
125   }
126
127   public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedTb) {
128     // Array initializers can only occur on the right hand side of an assignment
129     // expression, therefore the expected type contains the valid information
130     // concerning the type that must be enforced by the elements of the array initializer.
131
132     // this method is recursive... (the test on isArrayType is the stop case)
133
134     constant = NotAConstant;
135     if (expectedTb.isArrayType()) {
136       binding = (ArrayBinding) expectedTb;
137       if (expressions == null)
138         return binding;
139       TypeBinding expectedElementsTb = binding.elementsType(scope);
140       if (expectedElementsTb.isBaseType()) {
141         for (int i = 0, length = expressions.length; i < length; i++) {
142           Expression expression = expressions[i];
143           TypeBinding expressionTb = (expression instanceof ArrayInitializer) ? expression.resolveTypeExpecting(scope,
144               expectedElementsTb) : expression.resolveType(scope);
145           if (expressionTb == null)
146             return null;
147
148           // Compile-time conversion required?
149           if (expression.isConstantValueOfTypeAssignableToType(expressionTb, expectedElementsTb)) {
150             expression.implicitWidening(expectedElementsTb, expressionTb);
151           } else if (BaseTypeBinding.isWidening(expectedElementsTb.id, expressionTb.id)) {
152             expression.implicitWidening(expectedElementsTb, expressionTb);
153           } else {
154             scope.problemReporter().typeMismatchErrorActualTypeExpectedType(expression, expressionTb, expectedElementsTb);
155             return null;
156           }
157         }
158       } else {
159         for (int i = 0, length = expressions.length; i < length; i++)
160           if (expressions[i].resolveTypeExpecting(scope, expectedElementsTb) == null)
161             return null;
162       }
163       return binding;
164     }
165
166     // infer initializer type for error reporting based on first element
167     TypeBinding leafElementType = null;
168     int dim = 1;
169     if (expressions == null) {
170       leafElementType = scope.getJavaLangObject();
171     } else {
172       Expression currentExpression = expressions[0];
173       while (currentExpression != null && currentExpression instanceof ArrayInitializer) {
174         dim++;
175         Expression[] subExprs = ((ArrayInitializer) currentExpression).expressions;
176         if (subExprs == null) {
177           leafElementType = scope.getJavaLangObject();
178           currentExpression = null;
179           break;
180         }
181         currentExpression = ((ArrayInitializer) currentExpression).expressions[0];
182       }
183       if (currentExpression != null) {
184         leafElementType = currentExpression.resolveType(scope);
185       }
186     }
187     if (leafElementType != null) {
188       TypeBinding probableTb = scope.createArray(leafElementType, dim);
189       scope.problemReporter().typeMismatchErrorActualTypeExpectedType(this, probableTb, expectedTb);
190     }
191     return null;
192   }
193
194   public String toStringExpression() {
195
196     String s = "{"; //$NON-NLS-1$
197     if (expressions != null) {
198       int j = 20;
199       for (int i = 0; i < expressions.length; i++) {
200         s = s + expressions[i].toStringExpression() + ","; //$NON-NLS-1$
201         j--;
202         if (j == 0) {
203           s = s + "\n                ";j = 20;}}}; //$NON-NLS-1$
204     s = s + "}"; //$NON-NLS-1$
205     return s;
206   }
207
208   public void traverse(ASTVisitor visitor, BlockScope scope) {
209     if (visitor.visit(this, scope)) {
210       if (expressions != null) {
211         int expressionsLength = expressions.length;
212         for (int i = 0; i < expressionsLength; i++)
213           expressions[i].traverse(visitor, scope);
214       }
215     }
216     visitor.endVisit(this, scope);
217   }
218 }