Package org.eclipse.jdt.internal.compiler.lookup

Source Code of org.eclipse.jdt.internal.compiler.lookup.ConstraintExceptionFormula

/*******************************************************************************
* Copyright (c) 2013, 2014 GK Software AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Stephan Herrmann - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression;
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression;

/**
* Constraint formula expressing that a given expression must have an exception type.
* <ul>
* <li>Expression contains<sub>throws</sub> T</li>
* </ul>
*/
public class ConstraintExceptionFormula extends ConstraintFormula {

  FunctionalExpression left;
 
  public ConstraintExceptionFormula(FunctionalExpression left, TypeBinding type) {
    this.left = left;
    this.right = type;
    this.relation = EXCEPTIONS_CONTAINED;
  }
 
  public Object reduce(InferenceContext18 inferenceContext) {
    // JLS 18.2.5
    Scope scope = inferenceContext.scope;
    if (!this.right.isFunctionalInterface(scope))
      return FALSE;
    MethodBinding sam = this.right.getSingleAbstractMethod(scope, true);
    if (sam == null)
      return FALSE;
    if (this.left instanceof LambdaExpression) {
      if (((LambdaExpression)this.left).argumentsTypeElided()) {
        int nParam = sam.parameters.length;
        for (int i = 0; i < nParam; i++)
          if (!sam.parameters[i].isProperType(true))
            return FALSE;
      }
      if (sam.returnType != TypeBinding.VOID && !sam.returnType.isProperType(true))
        return FALSE;
    } else { // reference expression
      if (!((ReferenceExpression)this.left).isExactMethodReference()) {         
        int nParam = sam.parameters.length;
        for (int i = 0; i < nParam; i++)
          if (!sam.parameters[i].isProperType(true))
            return FALSE;
        if (sam.returnType != TypeBinding.VOID && !sam.returnType.isProperType(true))
          return FALSE;
      }
    }
    TypeBinding[] thrown = sam.thrownExceptions;
    InferenceVariable[] e = new InferenceVariable[thrown.length];
    int n = 0;
    for (int i = 0; i < thrown.length; i++)
      if (!thrown[i].isProperType(true))
        e[n++] = (InferenceVariable) thrown[i]; // thrown[i] is not a proper type, since it's an exception it must be an inferenceVariable, right?
   
    /* If throw specification does not encode any type parameters, there are no constraints to be gleaned/gathered from the throw sites.
       See also that thrown exceptions are not allowed to influence compatibility and overload resolution.
    */
    if (n == 0)
      return TRUE;
   
    TypeBinding[] ePrime = null;
    if (this.left instanceof LambdaExpression) {
      LambdaExpression lambda = ((LambdaExpression) this.left).getResolvedCopyForInferenceTargeting(this.right);
      if (lambda == null)
        return TRUE; // cannot make use of this buggy constraint
      Set<TypeBinding> ePrimeSet = lambda.getThrownExceptions();
      ePrime = ePrimeSet.toArray(new TypeBinding[ePrimeSet.size()]);
    } else {
      ReferenceExpression referenceExpression = (ReferenceExpression)this.left;
      MethodBinding method = referenceExpression.findCompileTimeMethodTargeting(this.right, scope);
      if (method != null)
        ePrime = method.thrownExceptions;
    }
    if (ePrime == null)
      return TRUE;
    int m = ePrime.length;
    List<ConstraintFormula> result = new ArrayList<ConstraintFormula>();
    actual: for (int i = 0; i < m; i++) {
      if (ePrime[i].isUncheckedException(false))
        continue;
      for (int j = 0; j < thrown.length; j++)
        if (thrown[j].isProperType(true) && ePrime[i].isCompatibleWith(thrown[j]))
          continue actual;
      for (int j = 0; j < n; j++)
        result.add(ConstraintTypeFormula.create(ePrime[i], e[j], SUBTYPE));
    }       
    for (int j = 0; j < n; j++)
      inferenceContext.currentBounds.inThrows.add(e[j]);
    return result.toArray(new ConstraintFormula[result.size()]);
  }

  Collection<InferenceVariable> inputVariables(final InferenceContext18 context) {
    // from 18.5.2.
    if (this.left instanceof LambdaExpression) {
      if (this.right instanceof InferenceVariable) {
        return Collections.singletonList((InferenceVariable)this.right);
      }
      if (this.right.isFunctionalInterface(context.scope)) {
        LambdaExpression lambda = (LambdaExpression) this.left;
        MethodBinding sam = this.right.getSingleAbstractMethod(context.scope, true); // TODO derive with target type?
        final Set<InferenceVariable> variables = new HashSet<InferenceVariable>();
        if (lambda.argumentsTypeElided()) {
          // i)
          int len = sam.parameters.length;
          for (int i = 0; i < len; i++) {
            sam.parameters[i].collectInferenceVariables(variables);
          }
        }
        if (sam.returnType != TypeBinding.VOID) {
          // ii)
          sam.returnType.collectInferenceVariables(variables);
        }
        return variables;
      }
    } else if (this.left instanceof ReferenceExpression) {
      if (this.right instanceof InferenceVariable) {
        return Collections.singletonList((InferenceVariable)this.right);
      }
      if (this.right.isFunctionalInterface(context.scope)) { // TODO: && this.left is inexact
        MethodBinding sam = this.right.getSingleAbstractMethod(context.scope, true); // TODO derive with target type?
        final Set<InferenceVariable> variables = new HashSet<InferenceVariable>();
        int len = sam.parameters.length;
        for (int i = 0; i < len; i++) {
          sam.parameters[i].collectInferenceVariables(variables);
        }
        sam.returnType.collectInferenceVariables(variables);
        return variables;
      }
    }
    return EMPTY_VARIABLE_LIST;
  }

  public String toString() {
    StringBuffer buf = new StringBuffer().append(LEFT_ANGLE_BRACKET);
    this.left.printExpression(4, buf);
    buf.append(" \u2286throws "); //$NON-NLS-1$
    appendTypeName(buf, this.right);
    buf.append(RIGHT_ANGLE_BRACKET);
    return buf.toString();
  }
}
TOP

Related Classes of org.eclipse.jdt.internal.compiler.lookup.ConstraintExceptionFormula

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.