001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.lookup;
011:
012: import org.eclipse.jdt.core.compiler.CharOperation;
013: import org.eclipse.jdt.internal.compiler.ast.Wildcard;
014: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
015:
016: /**
017: * Binding for a type parameter, held by source/binary type or method.
018: */
019: public class TypeVariableBinding extends ReferenceBinding {
020:
021: public Binding declaringElement; // binding of declaring type or method
022: public int rank; // declaration rank, can be used to match variable in parameterized type
023:
024: /**
025: * Denote the first explicit (binding) bound amongst the supertypes (from declaration in source)
026: * If no superclass was specified, then it denotes the first superinterface, or null if none was specified.
027: */
028: public TypeBinding firstBound;
029:
030: // actual resolved variable supertypes (if no superclass bound, then associated to Object)
031: public ReferenceBinding super class;
032: public ReferenceBinding[] super Interfaces;
033: public char[] genericTypeSignature;
034:
035: public TypeVariableBinding(char[] sourceName,
036: Binding declaringElement, int rank) {
037: this .sourceName = sourceName;
038: this .declaringElement = declaringElement;
039: this .rank = rank;
040: this .modifiers = ClassFileConstants.AccPublic
041: | ExtraCompilerModifiers.AccGenericSignature; // treat type var as public
042: this .tagBits |= TagBits.HasTypeVariable;
043: }
044:
045: public int kind() {
046: return TYPE_PARAMETER;
047: }
048:
049: /**
050: * Returns true if the argument type satisfies all bounds of the type parameter
051: */
052: public int boundCheck(Substitution substitution,
053: TypeBinding argumentType) {
054:
055: if (argumentType == TypeBinding.NULL || argumentType == this )
056: return TypeConstants.OK;
057: boolean hasSubstitution = substitution != null;
058: if (!(argumentType instanceof ReferenceBinding || argumentType
059: .isArrayType()))
060: return TypeConstants.MISMATCH;
061: // special case for re-entrant source types (selection, code assist, etc)...
062: // can request additional types during hierarchy walk that are found as source types that also 'need' to connect their hierarchy
063: if (this .super class == null)
064: return TypeConstants.OK;
065:
066: if (argumentType.isWildcard()
067: && !argumentType.isIntersectionType()) {
068: WildcardBinding wildcard = (WildcardBinding) argumentType;
069: switch (wildcard.boundKind) {
070: case Wildcard.EXTENDS:
071: TypeBinding wildcardBound = wildcard.bound;
072: if (wildcardBound == this )
073: return TypeConstants.OK;
074: ReferenceBinding super classBound = hasSubstitution ? (ReferenceBinding) Scope
075: .substitute(substitution, this .super class)
076: : this .super class;
077: boolean isArrayBound = wildcardBound.isArrayType();
078: if (!wildcardBound.isInterface()) {
079: if (super classBound.id != TypeIds.T_JavaLangObject) {
080: if (isArrayBound) {
081: if (!wildcardBound
082: .isCompatibleWith(super classBound))
083: return TypeConstants.MISMATCH;
084: } else {
085: TypeBinding match = wildcardBound
086: .findSuperTypeWithSameErasure(super classBound);
087: if (match != null) {
088: if (!match
089: .isIntersectingWith(super classBound)) {
090: return TypeConstants.MISMATCH;
091: }
092: } else {
093: match = super classBound
094: .findSuperTypeWithSameErasure(wildcardBound);
095: if (match != null) {
096: if (!match
097: .isIntersectingWith(wildcardBound)) {
098: return TypeConstants.MISMATCH;
099: }
100: } else {
101: if (!wildcardBound.isTypeVariable()
102: && !super classBound
103: .isTypeVariable()) {
104: return TypeConstants.MISMATCH;
105: }
106: }
107: }
108: }
109: }
110: }
111: ReferenceBinding[] super InterfaceBounds = hasSubstitution ? Scope
112: .substitute(substitution, this .super Interfaces)
113: : this .super Interfaces;
114: int length = super InterfaceBounds.length;
115: boolean mustImplement = isArrayBound
116: || ((ReferenceBinding) wildcardBound).isFinal();
117: for (int i = 0; i < length; i++) {
118: TypeBinding super InterfaceBound = super InterfaceBounds[i];
119: if (isArrayBound) {
120: if (!wildcardBound
121: .isCompatibleWith(super InterfaceBound))
122: return TypeConstants.MISMATCH;
123: } else {
124: TypeBinding match = wildcardBound
125: .findSuperTypeWithSameErasure(super InterfaceBound);
126: if (match != null) {
127: if (!match
128: .isIntersectingWith(super InterfaceBound)) {
129: return TypeConstants.MISMATCH;
130: }
131: } else if (mustImplement) {
132: return TypeConstants.MISMATCH; // cannot be extended further to satisfy missing bounds
133: }
134: }
135:
136: }
137: break;
138:
139: case Wildcard.SUPER:
140: return boundCheck(substitution, wildcard.bound);
141:
142: case Wildcard.UNBOUND:
143: break;
144: }
145: return TypeConstants.OK;
146: }
147: boolean unchecked = false;
148: if (this .super class.id != TypeIds.T_JavaLangObject) {
149: TypeBinding super Type = this .super class;
150: if (super Type != argumentType) { // check identity before substituting (104649)
151: TypeBinding substitutedSuperType = hasSubstitution ? Scope
152: .substitute(substitution, super Type)
153: : super Type;
154: if (!argumentType
155: .isCompatibleWith(substitutedSuperType)) {
156: return TypeConstants.MISMATCH;
157: }
158: TypeBinding match = argumentType
159: .findSuperTypeWithSameErasure(substitutedSuperType);
160: if (match != null) {
161: // Enum#RAW is not a substitute for <E extends Enum<E>> (86838)
162: if (match.isRawType()
163: && substitutedSuperType
164: .isBoundParameterizedType())
165: unchecked = true;
166: }
167: }
168: }
169: for (int i = 0, length = this .super Interfaces.length; i < length; i++) {
170: TypeBinding super Type = this .super Interfaces[i];
171: if (super Type != argumentType) { // check identity before substituting (104649)
172: TypeBinding substitutedSuperType = hasSubstitution ? Scope
173: .substitute(substitution, super Type)
174: : super Type;
175: if (!argumentType
176: .isCompatibleWith(substitutedSuperType)) {
177: return TypeConstants.MISMATCH;
178: }
179: TypeBinding match = argumentType
180: .findSuperTypeWithSameErasure(substitutedSuperType);
181: if (match != null) {
182: // Enum#RAW is not a substitute for <E extends Enum<E>> (86838)
183: if (match.isRawType()
184: && substitutedSuperType
185: .isBoundParameterizedType())
186: unchecked = true;
187: }
188: }
189: }
190: return unchecked ? TypeConstants.UNCHECKED : TypeConstants.OK;
191: }
192:
193: /**
194: * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#canBeInstantiated()
195: */
196: public boolean canBeInstantiated() {
197: return false;
198: }
199:
200: /**
201: * Collect the substitutes into a map for certain type variables inside the receiver type
202: * e.g. Collection<T>.collectSubstitutes(Collection<List<X>>, Map), will populate Map with: T --> List<X>
203: * Constraints:
204: * A << F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_EXTENDS (1))
205: * A = F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_EQUAL (0))
206: * A >> F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_SUPER (2))
207: */
208: public void collectSubstitutes(Scope scope, TypeBinding actualType,
209: InferenceContext inferenceContext, int constraint) {
210:
211: // only infer for type params of the generic method
212: if (this .declaringElement != inferenceContext.genericMethod)
213: return;
214:
215: // cannot infer anything from a null type
216: switch (actualType.kind()) {
217: case Binding.BASE_TYPE:
218: if (actualType == TypeBinding.NULL)
219: return;
220: TypeBinding boxedType = scope.environment()
221: .computeBoxingType(actualType);
222: if (boxedType == actualType)
223: return;
224: actualType = boxedType;
225: break;
226: case Binding.WILDCARD_TYPE:
227: WildcardBinding actualWildcard = (WildcardBinding) actualType;
228: if (actualWildcard.otherBounds != null)
229: break; // intersection type
230: return; // wildcards are not true type expressions (JLS 15.12.2.7, p.453 2nd discussion)
231: }
232:
233: // reverse constraint, to reflect variable on rhs: A << T --> T >: A
234: int variableConstraint;
235: switch (constraint) {
236: case TypeConstants.CONSTRAINT_EQUAL:
237: variableConstraint = TypeConstants.CONSTRAINT_EQUAL;
238: break;
239: case TypeConstants.CONSTRAINT_EXTENDS:
240: variableConstraint = TypeConstants.CONSTRAINT_SUPER;
241: break;
242: default:
243: //case CONSTRAINT_SUPER :
244: variableConstraint = TypeConstants.CONSTRAINT_EXTENDS;
245: break;
246: }
247: inferenceContext.recordSubstitute(this , actualType,
248: variableConstraint);
249: }
250:
251: public char[] constantPoolName() { /* java/lang/Object */
252: if (this .firstBound != null) {
253: return this .firstBound.constantPoolName();
254: }
255: return this .super class.constantPoolName(); // java/lang/Object
256: }
257:
258: /*
259: * declaringUniqueKey : genericTypeSignature
260: * p.X<T> { ... } --> Lp/X;:TT;
261: * p.X { <T> void foo() {...} } --> Lp/X;.foo()V:TT;
262: */
263: public char[] computeUniqueKey(boolean isLeaf) {
264: StringBuffer buffer = new StringBuffer();
265: Binding declaring = this .declaringElement;
266: if (!isLeaf && declaring.kind() == Binding.METHOD) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=97902
267: MethodBinding methodBinding = (MethodBinding) declaring;
268: ReferenceBinding declaringClass = methodBinding.declaringClass;
269: buffer.append(declaringClass
270: .computeUniqueKey(false/*not a leaf*/));
271: buffer.append(':');
272: MethodBinding[] methods = declaringClass.methods();
273: if (methods != null)
274: for (int i = 0, length = methods.length; i < length; i++) {
275: MethodBinding binding = methods[i];
276: if (binding == methodBinding) {
277: buffer.append(i);
278: break;
279: }
280: }
281: } else {
282: buffer.append(declaring
283: .computeUniqueKey(false/*not a leaf*/));
284: buffer.append(':');
285: }
286: buffer.append(genericTypeSignature());
287: int length = buffer.length();
288: char[] uniqueKey = new char[length];
289: buffer.getChars(0, length, uniqueKey, 0);
290: return uniqueKey;
291: }
292:
293: /**
294: * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#debugName()
295: */
296: public String debugName() {
297: return new String(this .sourceName);
298: }
299:
300: public TypeBinding erasure() {
301: if (this .firstBound != null) {
302: return this .firstBound.erasure();
303: }
304: return this .super class; // java/lang/Object
305: }
306:
307: /**
308: * T::Ljava/util/Map;:Ljava/io/Serializable;
309: * T:LY<TT;>
310: */
311: public char[] genericSignature() {
312: StringBuffer sig = new StringBuffer(10);
313: sig.append(this .sourceName).append(':');
314: int interfaceLength = this .super Interfaces == null ? 0
315: : this .super Interfaces.length;
316: if (interfaceLength == 0 || this .firstBound == this .super class) {
317: if (this .super class != null)
318: sig.append(this .super class.genericTypeSignature());
319: }
320: for (int i = 0; i < interfaceLength; i++) {
321: sig.append(':').append(
322: this .super Interfaces[i].genericTypeSignature());
323: }
324: int sigLength = sig.length();
325: char[] genericSignature = new char[sigLength];
326: sig.getChars(0, sigLength, genericSignature, 0);
327: return genericSignature;
328: }
329:
330: /**
331: * T::Ljava/util/Map;:Ljava/io/Serializable;
332: * T:LY<TT;>
333: */
334: public char[] genericTypeSignature() {
335: if (this .genericTypeSignature != null)
336: return this .genericTypeSignature;
337: return this .genericTypeSignature = CharOperation.concat('T',
338: this .sourceName, ';');
339: }
340:
341: /**
342: * Returns true if the type variable is directly bound to a given type
343: */
344: public boolean isErasureBoundTo(TypeBinding type) {
345: if (this .super class.erasure() == type)
346: return true;
347: for (int i = 0, length = this .super Interfaces.length; i < length; i++) {
348: if (this .super Interfaces[i].erasure() == type)
349: return true;
350: }
351: return false;
352: }
353:
354: /**
355: * Returns true if the 2 variables are playing exact same role: they have
356: * the same bounds, providing one is substituted with the other: <T1 extends
357: * List<T1>> is interchangeable with <T2 extends List<T2>>.
358: */
359: public boolean isInterchangeableWith(
360: TypeVariableBinding otherVariable, Substitution substitute) {
361: if (this == otherVariable)
362: return true;
363: int length = this .super Interfaces.length;
364: if (length != otherVariable.super Interfaces.length)
365: return false;
366:
367: if (this .super class != Scope.substitute(substitute,
368: otherVariable.super class))
369: return false;
370:
371: next: for (int i = 0; i < length; i++) {
372: TypeBinding super Type = Scope.substitute(substitute,
373: otherVariable.super Interfaces[i]);
374: for (int j = 0; j < length; j++)
375: if (super Type == this .super Interfaces[j])
376: continue next;
377: return false; // not a match
378: }
379: return true;
380: }
381:
382: /**
383: * Returns true if the type was declared as a type variable
384: */
385: public boolean isTypeVariable() {
386: return true;
387: }
388:
389: /**
390: * Returns the original type variable for a given variable.
391: * Only different from receiver for type variables of generic methods of parameterized types
392: * e.g. X<U> { <V1 extends U> U foo(V1) } --> X<String> { <V2 extends String> String foo(V2) }
393: * and V2.original() --> V1
394: */
395: public TypeVariableBinding original() {
396: if (this .declaringElement.kind() == Binding.METHOD) {
397: MethodBinding originalMethod = ((MethodBinding) this .declaringElement)
398: .original();
399: if (originalMethod != this .declaringElement) {
400: return originalMethod.typeVariables[this .rank];
401: }
402: } else {
403: ReferenceBinding originalType = (ReferenceBinding) ((ReferenceBinding) this .declaringElement)
404: .erasure();
405: if (originalType != this .declaringElement) {
406: return originalType.typeVariables()[this .rank];
407: }
408: }
409: return this ;
410: }
411:
412: /**
413: * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#readableName()
414: */
415: public char[] readableName() {
416: return this .sourceName;
417: }
418:
419: ReferenceBinding resolve(LookupEnvironment environment) {
420: if ((this .modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)
421: return this ;
422:
423: TypeBinding oldSuperclass = this .super class, oldFirstInterface = null;
424: if (this .super class != null)
425: this .super class = BinaryTypeBinding.resolveType(
426: this .super class, environment, true);
427: ReferenceBinding[] interfaces = this .super Interfaces;
428: int length;
429: if ((length = interfaces.length) != 0) {
430: oldFirstInterface = interfaces[0];
431: for (int i = length; --i >= 0;) {
432: interfaces[i] = BinaryTypeBinding.resolveType(
433: interfaces[i], environment, true);
434: }
435: }
436: // refresh the firstBound in case it changed
437: if (this .firstBound != null) {
438: if (this .firstBound == oldSuperclass) {
439: this .firstBound = this .super class;
440: } else if (this .firstBound == oldFirstInterface) {
441: this .firstBound = interfaces[0];
442: }
443: }
444: this .modifiers &= ~ExtraCompilerModifiers.AccUnresolved;
445: return this ;
446: }
447:
448: /**
449: * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#shortReadableName()
450: */
451: public char[] shortReadableName() {
452: return this .readableName();
453: }
454:
455: public ReferenceBinding super class() {
456: return super class;
457: }
458:
459: public ReferenceBinding[] super Interfaces() {
460: return super Interfaces;
461: }
462:
463: /**
464: * @see java.lang.Object#toString()
465: */
466: public String toString() {
467: StringBuffer buffer = new StringBuffer(10);
468: buffer.append('<').append(this .sourceName);//.append('[').append(this.rank).append(']');
469: if (this .super class != null
470: && this .firstBound == this .super class) {
471: buffer
472: .append(" extends ").append(this .super class.debugName()); //$NON-NLS-1$
473: }
474: if (this .super Interfaces != null
475: && this .super Interfaces != Binding.NO_SUPERINTERFACES) {
476: if (this .firstBound != this .super class) {
477: buffer.append(" extends "); //$NON-NLS-1$
478: }
479: for (int i = 0, length = this .super Interfaces.length; i < length; i++) {
480: if (i > 0 || this .firstBound == this .super class) {
481: buffer.append(" & "); //$NON-NLS-1$
482: }
483: buffer.append(this .super Interfaces[i].debugName());
484: }
485: }
486: buffer.append('>');
487: return buffer.toString();
488: }
489:
490: /**
491: * Upper bound doesn't perform erasure
492: */
493: public TypeBinding upperBound() {
494: if (this .firstBound != null) {
495: return this .firstBound;
496: }
497: return this .super class; // java/lang/Object
498: }
499: }
|