import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / lookup / TypeVariableBinding.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.lookup;
12
13 import java.util.Map;
14 import org.eclipse.jdt.core.compiler.CharOperation;
15 import org.eclipse.jdt.internal.compiler.ast.Wildcard;
16
17 /**
18  * Binding for a type parameter, held by source/binary type or method.
19  */
20 public class TypeVariableBinding extends ReferenceBinding {
21
22         public Binding declaringElement; // binding of declaring type or method 
23         public int rank; // declaration rank, can be used to match variable in parameterized type
24
25         /**
26          * Denote the first explicit (binding) bound amongst the supertypes (from declaration in source)
27          * If no superclass was specified, then it denotes the first superinterface, or null if none was specified.
28          */
29         public ReferenceBinding firstBound; 
30
31         // actual resolved variable supertypes (if no superclass bound, then associated to Object)
32         public ReferenceBinding superclass;
33         public ReferenceBinding[] superInterfaces; 
34         public char[] genericTypeSignature;
35
36         public TypeVariableBinding(char[] sourceName, Binding declaringElement, int rank) {
37                 this.sourceName = sourceName;
38                 this.declaringElement = declaringElement;
39                 this.rank = rank;
40                 this.modifiers = AccPublic | AccGenericSignature; // treat type var as public
41                 this.tagBits |= HasTypeVariable;
42         }
43
44         public int kind() {
45                 return TYPE_PARAMETER;
46         }       
47         
48         /**
49          * Returns true if the argument type satisfies all bounds of the type parameter
50          */
51         public boolean boundCheck(Substitution substitution, TypeBinding argumentType) {
52                 if (argumentType == NullBinding || this == argumentType) 
53                         return true;
54                 if (!(argumentType instanceof ReferenceBinding || argumentType.isArrayType()))
55                         return false;   
56                 
57             if (argumentType.isWildcard()) {
58                 WildcardBinding wildcard = (WildcardBinding) argumentType;
59                 switch (wildcard.kind) {
60                         case Wildcard.SUPER :
61                             if (!boundCheck(substitution, wildcard.bound)) return false;
62                             break;
63                                 case Wildcard.UNBOUND :
64                                         if (this == wildcard.typeVariable()) 
65                                                 return true;
66                                         break;                          
67                 }
68             }
69 //              if (this == argumentType) 
70 //                      return true;
71                 boolean hasSubstitution = substitution != null;
72                 if (this.superclass.id != T_JavaLangObject && !argumentType.isCompatibleWith(hasSubstitution ? substitution.substitute(this.superclass) : this.superclass)) {
73                     return false;
74                 }
75             for (int i = 0, length = this.superInterfaces.length; i < length; i++) {
76                 if (!argumentType.isCompatibleWith(hasSubstitution ? substitution.substitute(this.superInterfaces[i]) : this.superInterfaces[i])) {
77                                 return false;
78                 }
79             }
80             return true;
81         }
82         
83         /**
84          * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#canBeInstantiated()
85          */
86         public boolean canBeInstantiated() {
87                 return false;
88         }
89         /**
90          * Collect the substitutes into a map for certain type variables inside the receiver type
91          * e.g.   Collection<T>.findSubstitute(T, Collection<List<X>>):   T --> List<X>
92          */
93         public void collectSubstitutes(TypeBinding otherType, Map substitutes) {
94                 // cannot infer anything from a null type
95                 if (otherType == NullBinding) return;
96                 
97             TypeBinding[] variableSubstitutes = (TypeBinding[])substitutes.get(this);
98             if (variableSubstitutes != null) {
99                 int length = variableSubstitutes.length;
100                 for (int i = 0; i < length; i++) {
101                         TypeBinding substitute = variableSubstitutes[i];
102                     if (substitute == otherType) return; // already there
103                     if (substitute == null) {
104                         variableSubstitutes[i] = otherType;
105                         return;
106                     }
107                 }
108                 // no free spot found, need to grow
109                 System.arraycopy(variableSubstitutes, 0, variableSubstitutes = new TypeBinding[2*length], 0, length);
110                 variableSubstitutes[length] = otherType;
111                 substitutes.put(this, variableSubstitutes);
112             }
113         }
114         
115         public char[] constantPoolName() { /* java/lang/Object */ 
116             if (this.firstBound != null) {
117                         return this.firstBound.constantPoolName();
118             }
119             return this.superclass.constantPoolName(); // java/lang/Object
120         }
121         /*
122          * declaringUniqueKey : genericTypeSignature
123          * p.X<T> { ... } --> Lp/X<TT;>;:TT;
124          */
125         public char[] computeUniqueKey() {
126                 char[] declaringKey = this.declaringElement.computeUniqueKey();
127                 int declaringLength = declaringKey.length;
128                 char[] sig = genericTypeSignature();
129                 int sigLength = sig.length;
130                 char[] uniqueKey = new char[declaringLength + 1 + sigLength];
131                 System.arraycopy(declaringKey, 0, uniqueKey, 0, declaringLength);
132                 uniqueKey[declaringLength] = ':';
133                 System.arraycopy(sig, 0, uniqueKey, declaringLength+1, sigLength);
134                 return uniqueKey;
135         }
136         /**
137          * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#debugName()
138          */
139         public String debugName() {
140             return new String(this.sourceName);         
141         }               
142         public TypeBinding erasure() {
143             if (this.firstBound != null) {
144                         return this.firstBound.erasure();
145             }
146             return this.superclass; // java/lang/Object
147         }       
148
149 /**
150  * Find supertype which erases to a given well-known type, or null if not found
151  * (using id avoids triggering the load of well-known type: 73740)
152  * NOTE: only works for erasures of well-known types, as random other types may share
153  * same id though being distincts.
154  * Override super-method since erasure() is answering firstBound (first supertype) already
155  */
156 public ReferenceBinding findSuperTypeErasingTo(int erasureId, boolean erasureIsClass) {
157
158 //    if (this.id == erasureId) return this; // no ID for type variable
159     ReferenceBinding currentType = this;
160     // iterate superclass to avoid recording interfaces if searched supertype is class
161     if (erasureIsClass) {
162                 while ((currentType = currentType.superclass()) != null) { 
163                         if (currentType.erasure().id == erasureId) return currentType;
164                 }    
165                 return null;
166     }
167         ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
168         int lastPosition = -1;
169         do {
170                 ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
171                 if (itsInterfaces != NoSuperInterfaces) {
172                         if (++lastPosition == interfacesToVisit.length)
173                                 System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
174                         interfacesToVisit[lastPosition] = itsInterfaces;
175                 }
176         } while ((currentType = currentType.superclass()) != null);
177                         
178         for (int i = 0; i <= lastPosition; i++) {
179                 ReferenceBinding[] interfaces = interfacesToVisit[i];
180                 for (int j = 0, length = interfaces.length; j < length; j++) {
181                         if ((currentType = interfaces[j]).erasure().id == erasureId)
182                                 return currentType;
183
184                         ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
185                         if (itsInterfaces != NoSuperInterfaces) {
186                                 if (++lastPosition == interfacesToVisit.length)
187                                         System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
188                                 interfacesToVisit[lastPosition] = itsInterfaces;
189                         }
190                 }
191         }
192         return null;
193 }
194 /**
195  * Find supertype which erases to a given type, or null if not found
196  * Override super-method since erasure() is answering firstBound (first supertype) already
197  */
198 public ReferenceBinding findSuperTypeErasingTo(ReferenceBinding erasure) {
199
200     if (this == erasure) return this;
201     ReferenceBinding currentType = this;
202     if (erasure.isClass()) {
203                 while ((currentType = currentType.superclass()) != null) {
204                         if (currentType.erasure() == erasure) return currentType;
205                 }
206                 return null;
207     }
208         ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
209         int lastPosition = -1;
210         do {
211                 ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
212                 if (itsInterfaces != NoSuperInterfaces) {
213                         if (++lastPosition == interfacesToVisit.length)
214                                 System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
215                         interfacesToVisit[lastPosition] = itsInterfaces;
216                 }
217         } while ((currentType = currentType.superclass()) != null);
218                         
219         for (int i = 0; i <= lastPosition; i++) {
220                 ReferenceBinding[] interfaces = interfacesToVisit[i];
221                 for (int j = 0, length = interfaces.length; j < length; j++) {
222                         if ((currentType = interfaces[j]).erasure() == erasure)
223                                 return currentType;
224
225                         ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
226                         if (itsInterfaces != NoSuperInterfaces) {
227                                 if (++lastPosition == interfacesToVisit.length)
228                                         System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
229                                 interfacesToVisit[lastPosition] = itsInterfaces;
230                         }
231                 }
232         }
233         return null;
234 }
235         
236         /**
237          * T::Ljava/util/Map;:Ljava/io/Serializable;
238          * T:LY<TT;>
239          */
240         public char[] genericSignature() {
241             StringBuffer sig = new StringBuffer(10);
242             sig.append(this.sourceName).append(':');
243                 int interfaceLength = this.superInterfaces.length;
244             if (interfaceLength == 0 || this.firstBound == this.superclass) {
245                 sig.append(this.superclass.genericTypeSignature());
246             }
247                 for (int i = 0; i < interfaceLength; i++) {
248                     sig.append(':').append(this.superInterfaces[i].genericTypeSignature());
249                 }
250                 int sigLength = sig.length();
251                 char[] genericSignature = new char[sigLength];
252                 sig.getChars(0, sigLength, genericSignature, 0);                                        
253                 return genericSignature;
254         }
255         /**
256          * T::Ljava/util/Map;:Ljava/io/Serializable;
257          * T:LY<TT;>
258          */
259         public char[] genericTypeSignature() {
260             if (this.genericTypeSignature != null) return this.genericTypeSignature;
261                 return this.genericTypeSignature = CharOperation.concat('T', this.sourceName, ';');
262         }
263
264         /**
265          * Returns true if the type variable is directly bound to a given type
266          */
267         public boolean isErasureBoundTo(TypeBinding type) {
268                 if (this.superclass.erasure() == type) 
269                         return true;
270                 for (int i = 0, length = this.superInterfaces.length; i < length; i++) {
271                         if (this.superInterfaces[i].erasure() == type)
272                                 return true;
273                 }
274                 return false;
275         }
276         /**
277          * Returns true if the type was declared as a type variable
278          */
279         public boolean isTypeVariable() {
280             return true;
281         }
282         /**
283      * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#readableName()
284      */
285     public char[] readableName() {
286         return this.sourceName;
287     }
288    
289         ReferenceBinding resolve(LookupEnvironment environment) {
290                 if ((this.modifiers & AccUnresolved) == 0)
291                         return this;
292         
293                 if (this.superclass != null)
294                         this.superclass = BinaryTypeBinding.resolveUnresolvedType(this.superclass, environment, true);
295                 if (this.firstBound != null)
296                         this.firstBound = BinaryTypeBinding.resolveUnresolvedType(this.firstBound, environment, true);
297                 ReferenceBinding[] interfaces = this.superInterfaces;
298                 for (int i = interfaces.length; --i >= 0;)
299                         interfaces[i] = BinaryTypeBinding.resolveUnresolvedType(interfaces[i], environment, true);
300                 this.modifiers &= ~AccUnresolved;
301         
302                 // finish resolving the types
303                 if (this.superclass != null)
304                         this.superclass = BinaryTypeBinding.resolveType(this.superclass, environment, true);
305                 if (this.firstBound != null)
306                         this.firstBound = BinaryTypeBinding.resolveType(this.firstBound, environment, true);
307                 for (int i = interfaces.length; --i >= 0;)
308                         interfaces[i] = BinaryTypeBinding.resolveType(interfaces[i], environment, true);
309                 return this;
310         }
311         
312         /**
313      * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#shortReadableName()
314      */
315     public char[] shortReadableName() {
316         return this.readableName();
317     }
318         public ReferenceBinding superclass() {
319                 return superclass;
320         }
321         public ReferenceBinding[] superInterfaces() {
322                 return superInterfaces;
323         }       
324         /**
325          * @see java.lang.Object#toString()
326          */
327         public String toString() {
328                 StringBuffer buffer = new StringBuffer(10);
329                 buffer.append('<').append(this.sourceName);//.append('[').append(this.rank).append(']');
330                 if (this.superclass != null && this.firstBound == this.superclass) {
331                     buffer.append(" extends ").append(this.superclass.debugName()); //$NON-NLS-1$
332                 }
333                 if (this.superInterfaces != null && this.superInterfaces != NoSuperInterfaces) {
334                    if (this.firstBound != this.superclass) {
335                         buffer.append(" extends "); //$NON-NLS-1$
336                 }
337                     for (int i = 0, length = this.superInterfaces.length; i < length; i++) {
338                         if (i > 0 || this.firstBound == this.superclass) {
339                             buffer.append(" & "); //$NON-NLS-1$
340                         }
341                                 buffer.append(this.superInterfaces[i].debugName());
342                         }
343                 }
344                 buffer.append('>');
345                 return buffer.toString();
346         }       
347 }