|
Lines 17-28
Link Here
|
| 17 |
*******************************************************************************/ |
17 |
*******************************************************************************/ |
| 18 |
package org.eclipse.jdt.internal.compiler.ast; |
18 |
package org.eclipse.jdt.internal.compiler.ast; |
| 19 |
|
19 |
|
|
|
20 |
import org.eclipse.jdt.core.compiler.CharOperation; |
| 20 |
import org.eclipse.jdt.internal.compiler.ASTVisitor; |
21 |
import org.eclipse.jdt.internal.compiler.ASTVisitor; |
| 21 |
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
22 |
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| 22 |
import org.eclipse.jdt.internal.compiler.codegen.*; |
23 |
import org.eclipse.jdt.internal.compiler.codegen.*; |
| 23 |
import org.eclipse.jdt.internal.compiler.flow.*; |
24 |
import org.eclipse.jdt.internal.compiler.flow.*; |
| 24 |
import org.eclipse.jdt.internal.compiler.impl.Constant; |
25 |
import org.eclipse.jdt.internal.compiler.impl.Constant; |
| 25 |
import org.eclipse.jdt.internal.compiler.lookup.*; |
26 |
import org.eclipse.jdt.internal.compiler.lookup.*; |
|
|
27 |
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable; |
| 26 |
|
28 |
|
| 27 |
public class AllocationExpression extends Expression implements InvocationSite { |
29 |
public class AllocationExpression extends Expression implements InvocationSite { |
| 28 |
|
30 |
|
|
Lines 260-270
Link Here
|
| 260 |
// initialization of an enum constant |
262 |
// initialization of an enum constant |
| 261 |
this.resolvedType = scope.enclosingReceiverType(); |
263 |
this.resolvedType = scope.enclosingReceiverType(); |
| 262 |
} else { |
264 |
} else { |
| 263 |
if ((this.type.bits & ASTNode.IsDiamond) != 0) { |
265 |
this.resolvedType = this.type.resolveType(scope, true /* check bounds*/); |
| 264 |
this.resolvedType = null; // can be done only after type arguments and method arguments resolution. |
|
|
| 265 |
} else { |
| 266 |
this.resolvedType = this.type.resolveType(scope, true /* check bounds*/); |
| 267 |
} |
| 268 |
// check for parameterized allocation deferred to below. |
266 |
// check for parameterized allocation deferred to below. |
| 269 |
} |
267 |
} |
| 270 |
// will check for null after args are resolved |
268 |
// will check for null after args are resolved |
|
Lines 338-346
Link Here
|
| 338 |
return this.resolvedType; |
336 |
return this.resolvedType; |
| 339 |
} |
337 |
} |
| 340 |
} |
338 |
} |
| 341 |
if (this.type != null && (this.type.bits & ASTNode.IsDiamond) != 0) { |
339 |
if (this.resolvedType == null || !this.resolvedType.isValidBinding()) { |
| 342 |
// Perform diamond inference here. (Not done yet.) |
340 |
return null; |
| 343 |
this.resolvedType = this.type.resolveType(scope, true /* check bounds*/); // for now just do what we do for 1.6- |
341 |
} |
|
|
342 |
|
| 343 |
// null type denotes fake allocation for enum constant inits |
| 344 |
if (this.type != null && !this.resolvedType.canBeInstantiated()) { |
| 345 |
scope.problemReporter().cannotInstantiate(this.type, this.resolvedType); |
| 346 |
return this.resolvedType; |
| 347 |
} |
| 348 |
if (this.type != null && this.resolvedType != null && (this.type.bits & ASTNode.IsDiamond) != 0) { |
| 349 |
TypeBinding [] inferredTypes = inferElidedTypes(((ParameterizedTypeBinding) this.resolvedType).genericType(), argumentTypes, scope); |
| 350 |
this.resolvedType = this.type.resolvedType = scope.environment().createParameterizedType(((ParameterizedTypeBinding) this.resolvedType).genericType(), inferredTypes, ((ParameterizedTypeBinding) this.resolvedType).enclosingType()); |
| 351 |
// inject inferred args ?? |
| 344 |
} |
352 |
} |
| 345 |
checkParameterizedAllocation: { |
353 |
checkParameterizedAllocation: { |
| 346 |
if (this.type instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>() |
354 |
if (this.type instanceof ParameterizedQualifiedTypeReference) { // disallow new X<String>.Y<Integer>() |
|
Lines 360-374
Link Here
|
| 360 |
} |
368 |
} |
| 361 |
} |
369 |
} |
| 362 |
} |
370 |
} |
| 363 |
if (this.resolvedType == null || !this.resolvedType.isValidBinding()) { |
|
|
| 364 |
return null; |
| 365 |
} |
| 366 |
|
371 |
|
| 367 |
// null type denotes fake allocation for enum constant inits |
|
|
| 368 |
if (this.type != null && !this.resolvedType.canBeInstantiated()) { |
| 369 |
scope.problemReporter().cannotInstantiate(this.type, this.resolvedType); |
| 370 |
return this.resolvedType; |
| 371 |
} |
| 372 |
ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType; |
372 |
ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType; |
| 373 |
if (!(this.binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) { |
373 |
if (!(this.binding = scope.getConstructor(allocationType, argumentTypes, this)).isValidBinding()) { |
| 374 |
if (this.binding.declaringClass == null) { |
374 |
if (this.binding.declaringClass == null) { |
|
Lines 394-399
Link Here
|
| 394 |
return allocationType; |
394 |
return allocationType; |
| 395 |
} |
395 |
} |
| 396 |
|
396 |
|
|
|
397 |
public TypeBinding[] inferElidedTypes(ReferenceBinding allocationType, TypeBinding[] argumentTypes, final BlockScope scope) { |
| 398 |
MethodBinding factory = getStaticFactory(allocationType, argumentTypes, scope); |
| 399 |
if (factory instanceof ParameterizedGenericMethodBinding) { |
| 400 |
return ((ParameterizedGenericMethodBinding) factory).typeArguments; |
| 401 |
} |
| 402 |
// Either inference failed or no inference was needed (exact match) ... |
| 403 |
int arity = allocationType.typeVariables().length; |
| 404 |
TypeBinding [] inferredTypes = new TypeBinding[arity]; |
| 405 |
for (int i = 0; i < arity; i++) { |
| 406 |
inferredTypes[i] = new ProblemReferenceBinding(CharOperation.NO_CHAR_CHAR, null, ProblemReasons.InferenceFailed); |
| 407 |
} |
| 408 |
return inferredTypes; |
| 409 |
} |
| 410 |
|
| 411 |
private MethodBinding getStaticFactory (ReferenceBinding allocationType, TypeBinding[] argumentTypes, final BlockScope scope) { |
| 412 |
TypeVariableBinding[] classTypeVariables = allocationType.typeVariables(); |
| 413 |
int classTypeVariablesArity = classTypeVariables.length; |
| 414 |
MethodBinding[] methods = allocationType.getMethods(TypeConstants.INIT, argumentTypes.length); |
| 415 |
MethodBinding [] staticFactories = new MethodBinding[methods.length]; |
| 416 |
int sfi = 0; |
| 417 |
for (int i = 0, length = methods.length; i < length; i++) { |
| 418 |
MethodBinding method = methods[i]; |
| 419 |
|
| 420 |
// if (method.parameters.length == argumentTypes.length) { |
| 421 |
// TypeBinding[] toMatch = method.parameters; |
| 422 |
// for (int iarg = 0, argCount = argumentTypes.length; iarg < argCount; iarg++) { |
| 423 |
// if (toMatch[iarg] != argumentTypes[iarg]) |
| 424 |
// break; |
| 425 |
// } |
| 426 |
// // we have an exact match, no inference is called for ... |
| 427 |
// return method; |
| 428 |
// } |
| 429 |
|
| 430 |
TypeVariableBinding[] methodTypeVariables = method.typeVariables(); |
| 431 |
int methodTypeVariablesArity = methodTypeVariables.length; |
| 432 |
|
| 433 |
if (this.genericTypeArguments != null && this.genericTypeArguments.length < methodTypeVariablesArity) |
| 434 |
continue; // wrong tree, don't bark. |
| 435 |
MethodBinding staticFactory = new MethodBinding(method.modifiers | ClassFileConstants.AccStatic, TypeConstants.SYNTHETIC_STATIC_FACTORY, |
| 436 |
null, null, null, method.declaringClass); |
| 437 |
staticFactory.typeVariables = new TypeVariableBinding[classTypeVariablesArity + (this.genericTypeArguments == null ? methodTypeVariablesArity : 0)]; |
| 438 |
final SimpleLookupTable map = new SimpleLookupTable(classTypeVariablesArity + methodTypeVariablesArity); |
| 439 |
// Rename each type variable T of the type to T' |
| 440 |
for (int j = 0; j < classTypeVariablesArity; j++) { |
| 441 |
map.put(classTypeVariables[j], staticFactory.typeVariables[j] = new TypeVariableBinding(CharOperation.concat(classTypeVariables[j].sourceName, "'".toCharArray()), //$NON-NLS-1$ |
| 442 |
staticFactory, j, scope.environment())); |
| 443 |
} |
| 444 |
// Rename each type variable U of method U to U'' if not explicitly parameterized. Otherwise use the parameterizing type. |
| 445 |
for (int j = classTypeVariablesArity, max = classTypeVariablesArity + methodTypeVariablesArity; j < max; j++) { |
| 446 |
map.put(methodTypeVariables[j - classTypeVariablesArity], |
| 447 |
this.genericTypeArguments != null ? this.genericTypeArguments[j - classTypeVariablesArity] : |
| 448 |
(staticFactory.typeVariables[j] = new TypeVariableBinding(CharOperation.concat(methodTypeVariables[j - classTypeVariablesArity].sourceName, "''".toCharArray()), //$NON-NLS-1$ |
| 449 |
staticFactory, j, scope.environment()))); |
| 450 |
} |
| 451 |
|
| 452 |
Substitution substitution = new Substitution() { |
| 453 |
public LookupEnvironment environment() { |
| 454 |
return scope.environment(); |
| 455 |
} |
| 456 |
public boolean isRawSubstitution() { |
| 457 |
return false; |
| 458 |
} |
| 459 |
public TypeBinding substitute(TypeVariableBinding typeVariable) { |
| 460 |
return (TypeBinding) map.get(typeVariable); |
| 461 |
} |
| 462 |
}; |
| 463 |
|
| 464 |
staticFactory.parameters = Scope.substitute(substitution, method.parameters); |
| 465 |
|
| 466 |
// initialize new variable bounds |
| 467 |
for (int j = 0, max = classTypeVariablesArity + methodTypeVariablesArity; j < max; j++) { |
| 468 |
TypeVariableBinding originalVariable = j < classTypeVariablesArity ? classTypeVariables[j] : methodTypeVariables[j - classTypeVariablesArity]; |
| 469 |
TypeBinding substitutedType = (TypeBinding) map.get(originalVariable); |
| 470 |
if (substitutedType instanceof TypeVariableBinding) { |
| 471 |
TypeVariableBinding substitutedVariable = (TypeVariableBinding) substitutedType; |
| 472 |
TypeBinding substitutedSuperclass = Scope.substitute(substitution, originalVariable.superclass); |
| 473 |
ReferenceBinding[] substitutedInterfaces = Scope.substitute(substitution, originalVariable.superInterfaces); |
| 474 |
if (originalVariable.firstBound != null) { |
| 475 |
substitutedVariable.firstBound = originalVariable.firstBound == originalVariable.superclass |
| 476 |
? substitutedSuperclass // could be array type or interface |
| 477 |
: substitutedInterfaces[0]; |
| 478 |
} |
| 479 |
switch (substitutedSuperclass.kind()) { |
| 480 |
case Binding.ARRAY_TYPE : |
| 481 |
substitutedVariable.superclass = scope.environment().getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null); |
| 482 |
substitutedVariable.superInterfaces = substitutedInterfaces; |
| 483 |
break; |
| 484 |
default: |
| 485 |
if (substitutedSuperclass.isInterface()) { |
| 486 |
substitutedVariable.superclass = scope.environment().getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null); |
| 487 |
int interfaceCount = substitutedInterfaces.length; |
| 488 |
System.arraycopy(substitutedInterfaces, 0, substitutedInterfaces = new ReferenceBinding[interfaceCount+1], 1, interfaceCount); |
| 489 |
substitutedInterfaces[0] = (ReferenceBinding) substitutedSuperclass; |
| 490 |
substitutedVariable.superInterfaces = substitutedInterfaces; |
| 491 |
} else { |
| 492 |
substitutedVariable.superclass = (ReferenceBinding) substitutedSuperclass; // typeVar was extending other typeVar which got substituted with interface |
| 493 |
substitutedVariable.superInterfaces = substitutedInterfaces; |
| 494 |
} |
| 495 |
} |
| 496 |
} |
| 497 |
} |
| 498 |
TypeVariableBinding[] returnTypeParameters = new TypeVariableBinding[classTypeVariablesArity]; |
| 499 |
for (int j = 0; j < classTypeVariablesArity; j++) { |
| 500 |
returnTypeParameters[j] = (TypeVariableBinding) map.get(classTypeVariables[j]); |
| 501 |
} |
| 502 |
staticFactory.returnType = scope.environment().createParameterizedType(allocationType, returnTypeParameters, allocationType.enclosingType()); |
| 503 |
staticFactory.thrownExceptions = Scope.substitute(substitution, method.thrownExceptions); |
| 504 |
if (staticFactory.thrownExceptions == null) { |
| 505 |
staticFactory.thrownExceptions = Binding.NO_EXCEPTIONS; |
| 506 |
} |
| 507 |
ParameterizedMethodBinding aFactory = new ParameterizedMethodBinding((ParameterizedTypeBinding) scope.environment().convertToParameterizedType(staticFactory.declaringClass), |
| 508 |
staticFactory); |
| 509 |
staticFactories[sfi++] = aFactory; |
| 510 |
} |
| 511 |
if (sfi != methods.length) { |
| 512 |
System.arraycopy(staticFactories, 0, staticFactories = new MethodBinding[sfi], 0, sfi); |
| 513 |
} |
| 514 |
MethodBinding[] compatible = new MethodBinding[sfi]; |
| 515 |
int compatibleIndex = 0; |
| 516 |
for (int i = 0; i < sfi; i++) { |
| 517 |
MethodBinding compatibleMethod = scope.computeCompatibleMethod(staticFactories[i], argumentTypes, this); |
| 518 |
if (compatibleMethod != null) { |
| 519 |
if (compatibleMethod.isValidBinding()) |
| 520 |
compatible[compatibleIndex++] = compatibleMethod; |
| 521 |
} |
| 522 |
} |
| 523 |
|
| 524 |
if (compatibleIndex == 0) { |
| 525 |
return null; |
| 526 |
} |
| 527 |
MethodBinding[] visible = new MethodBinding[compatibleIndex]; |
| 528 |
int visibleIndex = 0; |
| 529 |
for (int i = 0; i < compatibleIndex; i++) { |
| 530 |
MethodBinding method = compatible[i]; |
| 531 |
if (method.canBeSeenBy(this, scope)) |
| 532 |
visible[visibleIndex++] = method; |
| 533 |
} |
| 534 |
if (visibleIndex == 0) { |
| 535 |
return null; |
| 536 |
} |
| 537 |
return visibleIndex == 1 ? visible[0] : scope.mostSpecificMethodBinding(visible, visibleIndex, argumentTypes, this, allocationType); |
| 538 |
} |
| 539 |
|
| 397 |
public void setActualReceiverType(ReferenceBinding receiverType) { |
540 |
public void setActualReceiverType(ReferenceBinding receiverType) { |
| 398 |
// ignored |
541 |
// ignored |
| 399 |
} |
542 |
} |