Exemplo n.º 1
0
  public TypeBinding resolveType(BlockScope scope) {
    // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference
    this.constant = Constant.NotAConstant;
    if (!(this.lhs instanceof Reference) || this.lhs.isThis()) {
      scope.problemReporter().expressionShouldBeAVariable(this.lhs);
      return null;
    }
    TypeBinding lhsType = lhs.resolveType(scope);
    this.expression.setExpectedType(lhsType); // needed in case of generic method invocation
    if (lhsType != null) {
      this.resolvedType = lhsType.capture(scope, this.sourceEnd);
    }
    TypeBinding rhsType = this.expression.resolveType(scope);
    if (lhsType == null || rhsType == null) {
      return null;
    }
    // check for assignment with no effect
    Binding left = getDirectBinding(this.lhs);
    if (left != null && left == getDirectBinding(this.expression)) {
      scope.problemReporter().assignmentHasNoEffect(this, left.shortReadableName());
    }

    // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character
    // may require to widen the rhs expression at runtime
    if (lhsType != rhsType) { // must call before computeConversion() and typeMismatchError()
      scope.compilationUnitScope().recordTypeConversion(lhsType, rhsType);
    }
    if ((this.expression.isConstantValueOfTypeAssignableToType(rhsType, lhsType)
            || (lhsType.isBaseType() && BaseTypeBinding.isWidening(lhsType.id, rhsType.id)))
        || rhsType.isCompatibleWith(lhsType)) {
      this.expression.computeConversion(scope, lhsType, rhsType);
      checkAssignment(scope, lhsType, rhsType);
      if (this.expression instanceof CastExpression
          && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) {
        CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression);
      }
      return this.resolvedType;
    } else if (scope.isBoxingCompatibleWith(rhsType, lhsType)
        || (rhsType.isBaseType() // narrowing then boxing ?
            && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
            && !lhsType.isBaseType()
            && this.expression.isConstantValueOfTypeAssignableToType(
                rhsType, scope.environment().computeBoxingType(lhsType)))) {
      this.expression.computeConversion(scope, lhsType, rhsType);
      if (this.expression instanceof CastExpression
          && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) {
        CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression);
      }
      return this.resolvedType;
    }
    scope.problemReporter().typeMismatchError(rhsType, lhsType, this.expression, this.lhs);
    return lhsType;
  }
 /**
  * Returns true if the argument type satisfies all bounds of the type parameter
  *
  * @param location if non-null this may be used for reporting errors relating to null type
  *     annotations (if enabled)
  */
 public TypeConstants.BoundCheckStatus boundCheck(
     Substitution substitution, TypeBinding argumentType, Scope scope, ASTNode location) {
   TypeConstants.BoundCheckStatus code =
       internalBoundCheck(substitution, argumentType, scope, location);
   if (code == BoundCheckStatus.MISMATCH) {
     if (argumentType instanceof TypeVariableBinding && scope != null) {
       TypeBinding bound = ((TypeVariableBinding) argumentType).firstBound;
       if (bound instanceof ParameterizedTypeBinding) {
         BoundCheckStatus code2 =
             boundCheck(
                 substitution,
                 bound.capture(scope, -1, -1),
                 scope,
                 location); // no capture position needed as this capture will never escape this
                            // context
         return code.betterOf(code2);
       }
     }
   }
   return code;
 }
  private Object reduceSubType(Scope scope, TypeBinding subCandidate, TypeBinding superCandidate) {
    // 18.2.3 Subtyping Constraints
    if (subCandidate.isProperType(true) && superCandidate.isProperType(true)) {
      if (subCandidate.isCompatibleWith(superCandidate, scope)) return TRUE;
      return FALSE;
    }
    if (subCandidate.id == TypeIds.T_null) return TRUE;
    if (superCandidate.id == TypeIds.T_null) return FALSE;
    if (subCandidate instanceof InferenceVariable)
      return new TypeBound((InferenceVariable) subCandidate, superCandidate, SUBTYPE, this.isSoft);
    if (superCandidate instanceof InferenceVariable)
      return new TypeBound(
          (InferenceVariable) superCandidate,
          subCandidate,
          SUPERTYPE,
          this.isSoft); // normalize to have variable on LHS
    switch (superCandidate.kind()) {
      case Binding.GENERIC_TYPE:
      case Binding.TYPE:
      case Binding.RAW_TYPE:
        {
          if (subCandidate.isSubtypeOf(superCandidate)) return TRUE;
          return FALSE;
        }
      case Binding.PARAMETERIZED_TYPE:
        {
          List<ConstraintFormula> constraints = new ArrayList<>();
          while (superCandidate != null
              && superCandidate.kind() == Binding.PARAMETERIZED_TYPE
              && subCandidate != null) {
            if (!addConstraintsFromTypeParameters(
                subCandidate, (ParameterizedTypeBinding) superCandidate, constraints)) return FALSE;
            // travel to enclosing types to check if they have type parameters, too:
            superCandidate = superCandidate.enclosingType();
            subCandidate = subCandidate.enclosingType();
          }
          switch (constraints.size()) {
            case 0:
              return TRUE;
            case 1:
              return constraints.get(0);
            default:
              return constraints.toArray(new ConstraintFormula[constraints.size()]);
          }
        }
      case Binding.ARRAY_TYPE:
        TypeBinding tPrime = ((ArrayBinding) superCandidate).elementsType();
        // let S'[] be the most specific array type that is a supertype of S (or S itself)
        ArrayBinding sPrimeArray = null;
        switch (subCandidate.kind()) {
          case Binding.INTERSECTION_TYPE:
            {
              WildcardBinding intersection = (WildcardBinding) subCandidate;
              sPrimeArray =
                  findMostSpecificSuperArray(
                      intersection.bound, intersection.otherBounds, intersection);
              break;
            }
          case Binding.ARRAY_TYPE:
            sPrimeArray = (ArrayBinding) subCandidate;
            break;
          case Binding.TYPE_PARAMETER:
            {
              TypeVariableBinding subTVB = (TypeVariableBinding) subCandidate;
              sPrimeArray =
                  findMostSpecificSuperArray(subTVB.firstBound, subTVB.otherUpperBounds(), subTVB);
              break;
            }
          default:
            return FALSE;
        }
        if (sPrimeArray == null) return FALSE;
        TypeBinding sPrime = sPrimeArray.elementsType();
        if (!tPrime.isPrimitiveType() && !sPrime.isPrimitiveType()) {
          return ConstraintTypeFormula.create(sPrime, tPrime, SUBTYPE, this.isSoft);
        }
        return TypeBinding.equalsEquals(tPrime, sPrime) ? TRUE : FALSE; // same primitive type?

        // "type variable" has two implementations in JDT:
      case Binding.WILDCARD_TYPE:
        if (subCandidate.kind() == Binding.INTERSECTION_TYPE) {
          ReferenceBinding[] intersectingTypes = subCandidate.getIntersectingTypes();
          if (intersectingTypes != null)
            for (int i = 0; i < intersectingTypes.length; i++)
              if (TypeBinding.equalsEquals(intersectingTypes[i], superCandidate)) return true;
        }
        WildcardBinding variable = (WildcardBinding) superCandidate;
        if (variable.boundKind == Wildcard.SUPER)
          return ConstraintTypeFormula.create(subCandidate, variable.bound, SUBTYPE, this.isSoft);
        return FALSE;
      case Binding.TYPE_PARAMETER:
        // similar to wildcard, but different queries for lower bound
        if (subCandidate.kind() == Binding.INTERSECTION_TYPE) {
          ReferenceBinding[] intersectingTypes = subCandidate.getIntersectingTypes();
          if (intersectingTypes != null)
            for (int i = 0; i < intersectingTypes.length; i++)
              if (TypeBinding.equalsEquals(intersectingTypes[i], superCandidate)) return true;
        }
        if (superCandidate instanceof CaptureBinding) {
          CaptureBinding capture = (CaptureBinding) superCandidate;
          if (capture.lowerBound != null
              && (capture.firstBound == null || capture.firstBound.id == TypeIds.T_JavaLangObject))
            return ConstraintTypeFormula.create(
                subCandidate, capture.lowerBound, SUBTYPE, this.isSoft);
        }
        return FALSE;
      case Binding.INTERSECTION_TYPE:
        superCandidate = ((WildcardBinding) superCandidate).allBounds();
        // $FALL-THROUGH$
      case Binding.INTERSECTION_TYPE18:
        TypeBinding[] intersectingTypes =
            ((IntersectionTypeBinding18) superCandidate).intersectingTypes;
        ConstraintFormula[] result = new ConstraintFormula[intersectingTypes.length];
        for (int i = 0; i < intersectingTypes.length; i++) {
          result[i] =
              ConstraintTypeFormula.create(
                  subCandidate, intersectingTypes[i], SUBTYPE, this.isSoft);
        }
        return result;
      case Binding.POLY_TYPE:
        PolyTypeBinding poly = (PolyTypeBinding) superCandidate;
        Invocation invocation = (Invocation) poly.expression;
        MethodBinding binding = invocation.binding();
        if (binding == null || !binding.isValidBinding()) return FALSE;
        TypeBinding returnType =
            binding.isConstructor() ? binding.declaringClass : binding.returnType;
        return reduceSubType(
            scope,
            subCandidate,
            returnType.capture(scope, invocation.sourceStart(), invocation.sourceEnd()));
    }
    throw new IllegalStateException("Unexpected RHS " + superCandidate); // $NON-NLS-1$
  }
Exemplo n.º 4
0
  /**
   * Initialize capture bounds using substituted supertypes e.g. given X<U, V extends X<U, V>>,
   * capture(X<E,?>) = X<E,capture>, where capture extends X<E,capture>
   */
  public void initializeBounds(Scope scope, ParameterizedTypeBinding capturedParameterizedType) {
    TypeVariableBinding wildcardVariable = this.wildcard.typeVariable();
    if (wildcardVariable == null) {
      // error resilience when capturing Zork<?>
      // no substitution for wildcard bound (only formal bounds from type variables are to be
      // substituted: 104082)
      TypeBinding originalWildcardBound = this.wildcard.bound;
      switch (this.wildcard.boundKind) {
        case Wildcard.EXTENDS:
          // still need to capture bound supertype as well so as not to expose wildcards to the
          // outside (111208)
          TypeBinding capturedWildcardBound = originalWildcardBound.capture(scope, this.position);
          if (originalWildcardBound.isInterface()) {
            this.superclass = scope.getJavaLangObject();
            this.superInterfaces =
                new ReferenceBinding[] {(ReferenceBinding) capturedWildcardBound};
          } else {
            // the wildcard bound should be a subtype of variable superclass
            // it may occur that the bound is less specific, then consider glb (202404)
            if (capturedWildcardBound.isArrayType() || capturedWildcardBound == this) {
              this.superclass = scope.getJavaLangObject();
            } else {
              this.superclass = (ReferenceBinding) capturedWildcardBound;
            }
            this.superInterfaces = Binding.NO_SUPERINTERFACES;
          }
          this.firstBound = capturedWildcardBound;
          if ((capturedWildcardBound.tagBits & TagBits.HasTypeVariable) == 0)
            this.tagBits &= ~TagBits.HasTypeVariable;
          break;
        case Wildcard.UNBOUND:
          this.superclass = scope.getJavaLangObject();
          this.superInterfaces = Binding.NO_SUPERINTERFACES;
          this.tagBits &= ~TagBits.HasTypeVariable;
          break;
        case Wildcard.SUPER:
          this.superclass = scope.getJavaLangObject();
          this.superInterfaces = Binding.NO_SUPERINTERFACES;
          this.lowerBound = this.wildcard.bound;
          if ((originalWildcardBound.tagBits & TagBits.HasTypeVariable) == 0)
            this.tagBits &= ~TagBits.HasTypeVariable;
          break;
      }
      return;
    }
    ReferenceBinding originalVariableSuperclass = wildcardVariable.superclass;
    ReferenceBinding substitutedVariableSuperclass =
        (ReferenceBinding) Scope.substitute(capturedParameterizedType, originalVariableSuperclass);
    // prevent cyclic capture: given X<T>, capture(X<? extends T> could yield a circular type
    if (substitutedVariableSuperclass == this)
      substitutedVariableSuperclass = originalVariableSuperclass;

    ReferenceBinding[] originalVariableInterfaces = wildcardVariable.superInterfaces();
    ReferenceBinding[] substitutedVariableInterfaces =
        Scope.substitute(capturedParameterizedType, originalVariableInterfaces);
    if (substitutedVariableInterfaces != originalVariableInterfaces) {
      // prevent cyclic capture: given X<T>, capture(X<? extends T> could yield a circular type
      for (int i = 0, length = substitutedVariableInterfaces.length; i < length; i++) {
        if (substitutedVariableInterfaces[i] == this)
          substitutedVariableInterfaces[i] = originalVariableInterfaces[i];
      }
    }
    // no substitution for wildcard bound (only formal bounds from type variables are to be
    // substituted: 104082)
    TypeBinding originalWildcardBound = this.wildcard.bound;

    switch (this.wildcard.boundKind) {
      case Wildcard.EXTENDS:
        // still need to capture bound supertype as well so as not to expose wildcards to the
        // outside (111208)
        TypeBinding capturedWildcardBound = originalWildcardBound.capture(scope, this.position);
        if (originalWildcardBound.isInterface()) {
          this.superclass = substitutedVariableSuperclass;
          // merge wildcard bound into variable superinterfaces using glb
          if (substitutedVariableInterfaces == Binding.NO_SUPERINTERFACES) {
            this.superInterfaces =
                new ReferenceBinding[] {(ReferenceBinding) capturedWildcardBound};
          } else {
            int length = substitutedVariableInterfaces.length;
            System.arraycopy(
                substitutedVariableInterfaces,
                0,
                substitutedVariableInterfaces = new ReferenceBinding[length + 1],
                1,
                length);
            substitutedVariableInterfaces[0] = (ReferenceBinding) capturedWildcardBound;
            this.superInterfaces = Scope.greaterLowerBound(substitutedVariableInterfaces);
          }
        } else {
          // the wildcard bound should be a subtype of variable superclass
          // it may occur that the bound is less specific, then consider glb (202404)
          if (capturedWildcardBound.isArrayType() || capturedWildcardBound == this) {
            this.superclass = substitutedVariableSuperclass;
          } else {
            this.superclass = (ReferenceBinding) capturedWildcardBound;
            if (this.superclass.isSuperclassOf(substitutedVariableSuperclass)) {
              this.superclass = substitutedVariableSuperclass;
            }
          }
          this.superInterfaces = substitutedVariableInterfaces;
        }
        this.firstBound = capturedWildcardBound;
        if ((capturedWildcardBound.tagBits & TagBits.HasTypeVariable) == 0)
          this.tagBits &= ~TagBits.HasTypeVariable;
        break;
      case Wildcard.UNBOUND:
        this.superclass = substitutedVariableSuperclass;
        this.superInterfaces = substitutedVariableInterfaces;
        this.tagBits &= ~TagBits.HasTypeVariable;
        break;
      case Wildcard.SUPER:
        this.superclass = substitutedVariableSuperclass;
        if (wildcardVariable.firstBound == substitutedVariableSuperclass
            || originalWildcardBound == substitutedVariableSuperclass) {
          this.firstBound = substitutedVariableSuperclass;
        }
        this.superInterfaces = substitutedVariableInterfaces;
        this.lowerBound = originalWildcardBound;
        if ((originalWildcardBound.tagBits & TagBits.HasTypeVariable) == 0)
          this.tagBits &= ~TagBits.HasTypeVariable;
        break;
    }
  }