Package com.sun.tools.javac.comp

Source Code of com.sun.tools.javac.comp.PQLMagicTypeInference

/* Copyright (C) 2011, Christoph Reichenbach
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.  Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

package com.sun.tools.javac.comp;

import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.pql.PQLBody;
import com.sun.tools.javac.tree.pql.PQLMagicSubexpr;

import java.util.LinkedList;
import java.util.ArrayList;
import java.util.HashSet;
import edu.umass.pql.*;

/**
* Infer constants, types, and inner and outer pql queries whilst reporting errors.
*
* This pass is the PQL equivalent for Attr.  It does the following:
* (a) Determine all branches of the base node that are logical constants, and issue errors for all branches that are not constants but contain AST fragments that we don't support.
* (b) For all non-constant parts, perform type inference.
* (c) For all `inner queries', i.e., PQLExpr children that are NOT logical constants (wrt the base node), assert that type inference produced some type.
*/
public class PQLAttr extends JCTree.Visitor
{
    public static class Info
    {
  // inner expressions
  LinkedList<PQLExpr> inner_pq = new LinkedList<PQLExpr>();
  LinkedList<PQLExpr> outer_pq = new LinkedList<PQLExpr>();
  LinkedList<JCExpression> constants = new LinkedList<JCExpression>();
  JCTree one = null; // integer one, if observed

  Info()
  {
  }
    }

    public Info info = new Info();
    private HashSet<Symbol> current_variables; // known variables in the current context
    private HashSet<Symbol> observed_variables = new HashSet<Symbol>(); // variables observed in subexprs

    public static Type
    boxRecursively(Types types, Type base_type)
    {
  final List<Type> old_args = base_type.getTypeArguments();

  if (old_args == null || old_args == List.<Type>nil()) {
      if (base_type.isPrimitive())
    return types.boxedClass(base_type).type;
      else
    return base_type;
  }

  final ListBuffer<Type> new_args = new ListBuffer<Type>();

  for (Type ty : old_args) {
      new_args.add(boxRecursively(types, ty));
  }
  return new Type.ClassType(base_type.getEnclosingType(), new_args.toList(), base_type.tsym);
    }

    private Type
    boxRecursively(Type type)
    {
  return boxRecursively(attr.types, type);
    }

    public Type
    setTypeOf(Type elemtype)
    {
  return attr.types.cloneWithFreshArgs(attr.syms.setType, elemtype);
    }

    public Type
    collectionTypeOf(Type elemtype)
    {
  return attr.types.cloneWithFreshArgs(attr.syms.collectionType, elemtype);
    }

    public Type
    mapTypeOf(Type keytype, Type valuetype)
    {
  return new Type.MagicMapType(keytype, valuetype);
  //applyTypeTo(attr.syms.mapType, keytype, valuetype);
    }

    public Type
    javaUtilMapTypeOf(Type keytype, Type valuetype)
    {
  return attr.types.cloneWithFreshArgs(attr.syms.mapType, keytype, valuetype);
    }

    boolean
    isConstantX()
    {
  for (Symbol sym : this.observed_variables)
      if (this.current_variables.contains(sym)) {
    //System.err.println("[c] is-constant:  {"+sym+"} in " + this.current_variables);
    return false;
      }
  return true;
    }

    boolean
    isConstant()
    {
  boolean result = isConstantX();
  return result;
    }

    public Attr attr;

    private PQLAttr(Attr attr, HashSet<Symbol> symbols)
    {
  this.attr = attr;
  this.current_variables = symbols;
    }

    public void
    addConstant(JCExpression tree)
    {
  //System.err.println("[c] ++>> " + tree);
  // if (tree.toString().equals("11"))
  //     throw new RuntimeException("Whaaa?");
  if (tree != null) {
      this.info.constants.add(tree);
      attr.pt = Type.noType;
      tree.accept(attr); // name and type analysis, if not done yet
  }
    }

    public void
    handleLists(List<? extends JCTree> ... elements)
    {
  int size = 0;
  for (List<? extends JCTree> l : elements)
      size += l.size();

  JCTree[] temp = new JCTree[size];
  int pos = 0;

  for (List<? extends JCTree> l : elements)
      for (JCTree t : l)
    temp[pos++] = t;

  handle(temp);
    }

    // static int depth = 0;

    public void
    handle(JCTree... elements)
    {
  // System.err.print("handle: [ ");
  // for (JCTree t : elements)
  //     try {
  //   System.err.print("{" + t + "} " );
  //     } catch (Throwable _) {
  //   System.err.print("(?"+t.getClass()+"?)");
  //     }
  // System.err.println("]");

  boolean has_constants = false;
  boolean has_variables = false;

  // System.err.print("[c]");
  // for (int i = 0; i < depth; i++)
  //     System.err.print("  ");
  // System.err.print(" {");
  // for (int i = 0; i < elements.length; i++) {
  //     if (i > 0)
  //   System.err.print(", ");
  //     System.err.print(elements[i]);
  // }
  // System.err.println("}");
  // ++depth;

  HashSet<Symbol> observed_symbol_accumulator = this.observed_variables;
  // System.err.println("[c] current-vars = " + current_variables);
  // System.err.println("[c] observed-vars = " + observed_variables);

  for (int offset = 0; offset < elements.length; offset++)
      if (elements[offset] != null) {
    elements[offset].accept(this);
    //System.err.println("[c] #" + offset + " is-constant=" + this.isConstant() + " hc=" + has_constants + " hv=" + has_variables);
    if (this.isConstant()) {
        has_constants = true;
        if (has_variables) // we're going to draw the line to constantness at this expression, so the constant branches must be remembered
      // [1] hypothesis:  all constants are JCExpressions
      // If not, then that will require a couple of changes elsewhere but it shouldn't be a big deal.
      addConstant((JCExpression) elements[offset]);
    } else {
        if (!has_variables) {
      has_variables = true;

      // If we've only seen constants so far and only just saw our first variable, we have to go back
      // and tag all observed constants
      for (int i = 0; i < offset; i++)
          // hypothesis:  all constants are JCExpressions (see [1] above)
          addConstant((JCExpression) elements[i]);
        }
    }
    if (offset + 1 < elements.length) {
        if (observed_symbol_accumulator == this.observed_variables) {
      this.observed_variables = new HashSet<Symbol>();
        } else {
      observed_symbol_accumulator.addAll(this.observed_variables);
      this.observed_variables.clear();
        }
    } else if (offset > 0)
        observed_symbol_accumulator.addAll(this.observed_variables);
      }
  this.observed_variables = observed_symbol_accumulator;

  for (JCTree t : elements)
      if (t != null)
    inferType(t);

  // --depth;
  // System.err.print("[c] ");
  // for (int i = 0; i < depth; i++)
  //     System.err.print("  ");
  // System.err.println("has_constants=" + has_constants + "; has_variables = " + has_variables + "; isConstant= " + isConstantX() + "; accum=" + observed_symbol_accumulator);
    }

    /**
     * Attribute tree and collect all expressions that do not depend on the specified variable symbols
     */
    public static Info
    attribute(Attr attr, PQLExpr tree)
    {
  final ArrayList<Symbol> variable_symbols = new ArrayList<Symbol>();
  HashSet<Symbol> symbols = new HashSet<Symbol>();
  for (JCVariableDecl decl: tree.decls)
      symbols.add(decl.sym);

  final PQLAttr pc = new PQLAttr(attr, symbols);
  tree.accept(pc);
  pc.solveTypes(tree);
  // if (pc.isConstant())
  //     pc.addConstant(tree);
  if (tree.type == null)
      pc.inferType(tree);

  return pc.info;
    }

    // --------------------------------------------------------------------------------
    public void visitBlock(JCBlock that)
    {
  handleLists(that.stats);
    }

    public void visitLabelled(JCLabeledStatement that)
    {
  handle(that.body);
    }

    public void visitSwitch(JCSwitch that)
    {
  handleLists(List.of(that.selector), that.cases);
    }

    public void visitCase(JCCase that)
    {
  handleLists(List.of(that.pat), that.stats);
    }

    public void visitSynchronized(JCSynchronized that)
    {
  handle(that.lock, that.body);
    }

    public void visitTry(JCTry that)
    {
  handleLists(List.of(that.body, that.finalizer), that.catchers);
    }

    public void visitCatch(JCCatch that)
    {
  handle(that.param, that.body);
    }

    public void visitConditional(JCConditional that)
    {
  handle(that.cond, that.truepart, that.falsepart);
    }

    public void visitIf(JCIf that)
    {
  handle(that.cond, that.thenpart, that.elsepart);
    }

    public void visitExec(JCExpressionStatement that)
    {
  handle(that.expr);
    }

    public void visitReturn(JCReturn that)
    {
  handle(that.expr);
    }

    public void visitThrow(JCThrow that)
    {
  handle(that.expr);
    }

    public void visitAssert(JCAssert that)
    {
  handle(that.cond, that.detail);
    }

    public void visitApply(JCMethodInvocation that)
    {
  final boolean is_magic = PQLMagicSubexpr.isMagic(that);

  if (!is_magic)
      disallowQueryVariables();
  List<JCExpression> args = that.args;
  if (that.meth instanceof JCFieldAccess)
      args = args.prepend(((JCFieldAccess) that.meth).selected);
  handleLists(args);
  if (!is_magic)
      reallowQueryVariables();
    }

    int query_variables_disallowed = 0;
    void disallowQueryVariables() { ++query_variables_disallowed; }
    void reallowQueryVariables() { --query_variables_disallowed; }
    boolean queryVariablesAllowed() { return query_variables_disallowed == 0; }

    public void visitNewClass(JCNewClass that)
    {
  disallowQueryVariables();
  handleLists(List.<JCTree>of(that.encl), that.args);
  reallowQueryVariables();
    }

    public void visitNewArray(JCNewArray that)
    {
  disallowQueryVariables();
  handleLists(that.dims, that.elems);
  reallowQueryVariables();
    }

    public void visitParens(JCParens that)
    {
  handle(that.expr);
    }

    public void visitAssign(JCAssign that)
    {
  handle(that.lhs, that.rhs);
    }

    public void visitAssignop(JCAssignOp that)
    {
  handle(that.lhs, that.rhs);
    }

    public void visitUnary(JCUnary that)
    {
  handle(that.arg);
    }

    public void visitBinary(JCBinary that)
    {
  handle(that.lhs, that.rhs);
    }

    public void visitTypeCast(JCTypeCast that)
    {
  handle(that.expr);
    }

    public void visitTypeTest(JCInstanceOf that)
    {
  handle(that.expr);
  that.clazz.type = attr.chk.checkReifiableReferenceType(that.clazz.pos(), attr.attribType(that.clazz, attr.env));
    }

    public void visitIndexed(JCArrayAccess that)
    {
  handle(that.indexed, that.index);
    }

    public void visitSelect(JCFieldAccess that)
    {
  handle(that.selected);
    }

    public void visitIdent(JCIdent that)
    {
  attr.pt = Type.noType;
  that.accept(attr); // name and type analysis

  if (!queryVariablesAllowed()
      && that.sym.isQueryVariable()) {
      attr.log.error(that.pos(), "query.var.in.subexpr");
  }

  this.observed_variables.add(that.sym);
    }

    public void visitPQLExpr(PQLExpr that)
    {
  if (that.default_expr != null) {
      handle(that.default_expr); // process before locally quantified variables are considered
      if (this.isConstant())
    addConstant(that.default_expr);
      this.observed_variables.clear();
  }

  final Env<AttrContext> old_env = attr.env;
  // Enter scope:
  final Env<AttrContext> localEnv = attr.memberEnter.queryEnv(that, attr.env);

  final Symbol.QuantificationQuasiSymbol qqs = new Symbol.QuantificationQuasiSymbol(that, attr.env.info.scope.owner);
  for (JCVariableDecl decl : that.decls) {
      this.current_variables.add(decl.sym);
      Type ty = null;
      // resolve types, where present
      if (decl.vartype != null) {
    ty = attr.attribType(decl.vartype, localEnv);
      }
      attr.attribStat(decl, localEnv);
      if (decl.type == null) {
    decl.type = ty;
    decl.sym.type = ty;
      }
      decl.sym.owner = qqs;
      localEnv.info.scope.enter(decl.sym);
  }
  attr.env = localEnv;
  handle(that.expr);
  // for (JCVariableDecl decl : that.decls) {
  //     this.current_variables.remove(decl.sym);

  //     try {
  //   decl.sym.type = decl.sym.type.elimQTyVars();
  //     } catch (Type.CouldNotInferTypeException exn) {
  //   exn.log(attr.log, decl.pos(), decl.sym);
  //     }
  // }

  if (this.isConstant())
      this.info.outer_pq.add(that);
  else
      this.info.inner_pq.add(that);

  // Leave scope:
  localEnv.info.scope.leave();
  attr.env = old_env;
    }

    public void visitTree(JCTree that)
    {
    }

    public void visitSkip(JCSkip that)          { visitTree(that); }
    public void visitBreak(JCBreak that)        { visitTree(that); }
    public void visitContinue(JCContinue that)  { visitTree(that); }
    public void visitClassDef(JCClassDecl that) { visitTree(that); }

    public void visitTopLevel(JCCompilationUnit that)    { err(that); }
    public void visitImport(JCImport that)               { err(that); }
    public void visitMethodDef(JCMethodDecl that)        { err(that); }
    public void visitVarDef(JCVariableDecl that)         { err(that); }
    public void visitDoLoop(JCDoWhileLoop that)          { err(that); }
    public void visitWhileLoop(JCWhileLoop that)         { err(that); }
    public void visitForLoop(JCForLoop that)             { err(that); }
    public void visitForeachLoop(JCEnhancedForLoop that) { err(that); }
    public void visitLetExpr(LetExpr that)     { err(that); }
    public void err(JCTree that)                    { throw new RuntimeException("PQLAttr: Unsupported JCTree within PQL query: " + that.getClass() + ": " + that); }



    // ----------------------------------------
    // Type inference
    PQLTypeInferencer type_inferencer = new PQLTypeInferencer();

    public void
    inferType(JCTree t)
    {
  try {
      if (t.type == null)
    type_inferencer.infer(t);
  } catch (Type.CouldNotInferTypeException e) {
      type_inferencer.defer(t);
      //e.log(attr.log, t.pos(), t);
      //t.type = attr.syms.botType;
  } catch (Type.TypeMismatchException e) {
      e.log(attr.log, t.pos());
      t.type = attr.syms.botType;
  }
    }

    public void
    assertInferred(PQLExpr that)
    {
  for (JCVariableDecl decl : that.decls) {
      try {
    decl.sym.type = decl.sym.type.elimQTyVars();
    if (decl.sym.type.tag == TypeTags.QTYVAR)
        throw new RuntimeException();
      } catch (Exception _) {
    decl.sym.type = decl.sym.type.unifyWith(attr.syms.objectType, attr.types).elimQTyVars();
    if (decl.sym.type.tag == TypeTags.QTYVAR)
        throw new Type.CouldNotInferTypeException(decl.sym.type);
      }
  }
    }

    public void
    solveTypes(PQLExpr expr)
    {
  this.type_inferencer.solve();

  assertInferred(expr);
  for (PQLExpr e : this.info.inner_pq)
      assertInferred(e);
    }

    class PQLTypeInferencer extends JCTree.Visitor
    {
  // Nonstandard:  for invocations, we have upper bounds on types that we need to enforce after type inference is complete.
  LinkedList<JCMethodInvocation> invocations_type_check = new LinkedList<JCMethodInvocation>();

  // standard worklist
  LinkedList<JCTree> worklist = new LinkedList<JCTree>();

  public void
  infer(JCTree t)
  {
      t.accept(this);
  }

  /**
   * Resolve later
   */
  public void
  defer(JCTree t)
  {
      t.type = tyvar();
      worklist.add(t);
  }

  public void
  solve()
  {
      int start_count;
      // compute lfp
      do {
    final LinkedList<JCTree> wl = this.worklist;
    start_count = wl.size();
    this.worklist = new LinkedList<JCTree>();

    for (JCTree t : wl) {
        final Type ty = t.type;
        infer(t);
        t.type = ty.unifyWith(t.type, attr.types);
    }

    if (start_count >= this.worklist.size()) {
        for (JCTree t : this.worklist)
      throw new RuntimeException("Cannot infer type for " + t);
    }

      } while (start_count > 0);

      for (JCMethodInvocation invoc : this.invocations_type_check)
    checkMethodInvocation(invoc);
  }

  public void
  checkMethodInvocation(final JCMethodInvocation invocation)
  {
      PQLMagicSubexpr checker =
    new PQLMagicSubexpr() {

    @Override
    public void
    handleContains(JCExpression set, JCExpression element)
    {
        set.type = boxRecursively(set.type.elimQTyVars());
        element.type = element.type.elimQTyVars();

        //set.type.unifyWith(collectionTypeOf(element.type), attr.types);

        if (!attr.types.isSubtype(set.type, collectionTypeOf(element.type))) {
            attr.log.error(invocation.pos(), "prob.found.req", JCDiagnostic.fragment("incompatible.types"), set.type, collectionTypeOf(element.type));
        }
    }

    @Override
    public void
    handleMapGet(JCExpression map, JCExpression key)
    {
        map.type = boxRecursively(map.type.elimQTyVars());
        key.type = key.type.elimQTyVars();
        invocation.type = invocation.type.elimQTyVars();
        final Type expected_type = mapTypeOf(key.type, invocation.type);

        //expected_type.unifyWith(map.type, attr.types);

        if (!attr.types.isSubtype(map.type, expected_type)) {
           attr.log.error(invocation.pos(), "prob.found.req", JCDiagnostic.fragment("incompatible.types"),
               map.type, expected_type);
        }
    }

    @Override
    public void
    handleSize(JCExpression container)
    {
        container.type = container.type.elimQTyVars();
    }

    @Override
    public void
    handleRange(JCExpression first, JCExpression last)
    {
    }

    @Override
    public void
    handleRangeContains(JCExpression first, JCExpression last, JCExpression body)
    {
    }

    };
      checker.process(invocation);
  }

  public Type
  tyvar()
  {
      return new QInferredType(null);
  }

  // ================================================================================

  public Symbol.MethodSymbol
  checkResolvedReductor(PQLExpr owner, JCExpression reductor, Type reduction_type)
  {
      System.err.println("Reduction type = " + reduction_type);
      Env<AttrContext> localEnv = attr.env.dup(owner, attr.env.info.dup());
      // first, attribute method
            final Type mpt = attr.newMethTemplate(List.of(reduction_type, reduction_type), List.<Type>nil());
            attr.env.info.varArgs = false;
            Type mtype = attr.attribExpr(reductor, localEnv, mpt);
      // this will trigger a type error if there is no matching/visible method.

      System.err.println("reductor : " + reductor.getClass());
      // while (reductor.getTag() == JCTree.SELECT)
      //   reductor = ((JCFieldAccess) reductor).selected;
      // System.err.println("post-reductor = " + reductor);

      // assert reductor.getTag() == JCTree.IDENT;
      // final JCIdent ident = (JCIdent) reductor;
      final Symbol.MethodSymbol sym;

      if (reductor.getTag() == JCTree.IDENT)
    sym = (Symbol.MethodSymbol) ((JCIdent) reductor).sym;
      else
    sym = (Symbol.MethodSymbol) ((JCFieldAccess) reductor).sym;

      if (sym == null)
    return null;

      // Final checks:
      // method static?
      if ((sym.flags_field & Flags.STATIC) == 0)
    attr.log.error(reductor.pos, "reductors.must.be.static", sym);

      // method return type matches?
      Type.MethodType mty = (Type.MethodType) sym.type;
      mty.restype.unifyWith(reduction_type, attr.types);

      // all types match suitably?
      if (!attr.types.isSameType(mty.argtypes.tail.head.elimQTyVars(), mty.argtypes.head.elimQTyVars()))
    attr.log.error(reductor.pos, "reductors.must.have.matching.argtypes", sym);
      if (!attr.types.isSameType(mty.restype.elimQTyVars(), (mty.argtypes.head)))
    attr.log.error(reductor.pos, "reductors.must.have.matching.result", sym);

      return sym;
  }

  public void visitPQLExpr(PQLExpr that)
  {
      switch (that.query_kind) {
      case EXISTENTIAL:
      case UNIVERSAL:
    that.type = attr.syms.booleanType;

    break;
      case SET: {
    Type elemtype = PQLBody.normalisedType(attr.syms, attr.types, that.decls.head.sym.type);

    that.type = setTypeOf(elemtype);
    break;
      }
      case DEFAULT_MAP:
      case MAP: {
    Type keytype = PQLBody.normalisedType(attr.syms, attr.types, that.decls.head.sym.type);
    Type valuetype = PQLBody.normalisedType(attr.syms, attr.types, that.decls.tail.head.sym.type);

    that.type = javaUtilMapTypeOf(keytype, valuetype);
    break;
      }
      case REDUCTION:
    System.err.println("Reduction subresult = " + that.decls.head.sym.type);
    that.type = that.decls.head.sym.type;//PQLBody.normalisedType(attr.syms, attr.types, that.decls.head.sym.type);
    that.resolved_reductor = checkResolvedReductor(that, that.reductor, that.type);
    that.type = PQLBody.normalisedType(attr.syms, attr.types, that.type);
    break;

      default:
        throw new RuntimeException("Unsupported PQL query kind: " + that.query_kind);
      }
  }

        public void visitIndexed(JCArrayAccess that)
  {
      Type ret_ty = tyvar();

      that.indexed.type = that.indexed.type.unifyWith(mapTypeOf(that.index.type, ret_ty), attr.types);
      //Make no assumptions aobut the index type-- we allow this notation to be used for maps
      //that.index.type = that.index.type.unifyWith(attr.syms.intType, attr.types);

      that.type = ret_ty.unifyWith(ret_ty, attr.types);
  }

        public void visitUnary(JCUnary that)
  {
      final Type inner = that.arg.type;

      switch (that.getTag()) {
      case JCTree.POS:
      case JCTree.NEG:
      case JCTree.COMPL:
    that.type = inner;
    break;

      case JCTree.NOT:
    that.type = attr.syms.booleanType;
    break;

      default:
    throw new RuntimeException("Unsupported unary expression: " + that);
      }
  }

        public void visitBinary(JCBinary that)
  {
      final Type left = that.lhs.type;
      final Type right = that.rhs.type;

      Type result;

      // parameters
      if (that.getTag() != JCTree.TYPETEST) {
        left.unifyWith(right, attr.types);
      }

      // return type
      switch (that.getTag()) {
      case JCTree.EQ:
      case JCTree.NE:
      case JCTree.LT:
      case JCTree.GT:
      case JCTree.LE:
      case JCTree.GE:
      case JCTree.OR:
      case JCTree.AND:
      case JCTree.IMPLIES:
        result = attr.syms.booleanType;
        break;
      default:
        result = left;
        if (result.tag == TypeTags.BYTE
            || result.tag == TypeTags.SHORT)
            result = attr.syms.intType;
      }
      that.type = result;
  }

        public void visitParens(JCParens that)
  {
      that.type = that.expr.type;
  }

        public void visitAssign(JCAssign that)
  {
      that.lhs.type = that.lhs.type.unifyWith(that.rhs.type, attr.types);
      that.type = attr.syms.booleanType;
  }

  public Type visitSize(JCExpression container)
  {
      container.type = container.type.unifyWith(new Type.MagicSizeType(), attr.types);
      return attr.syms.intType;
  }

        public void visitSelect(JCFieldAccess that)
  {
      if (that.name.toString().equals("length")) {
    that.type = visitSize(that.selected);
    return;
      }

      // has to be an object field access, otherwise it would be a logical constant.
      // Or a method call, but those are not subject to type inference (either errors or treated specially, cf. JCApply).
      final Type inner_type = that.selected.type = that.selected.type.elimQTyVars();

      if (inner_type.tag == TypeTags.QTYVAR) {
    // Don't know the type yet, so we can't infer or check the field type.
    defer(that);
      } else {
    if (inner_type.tag == TypeTags.BOT) {
        that.type = attr.syms.botType;
        return;
    }
    if (inner_type.tag != TypeTags.CLASS) {
        attr.log.error(that.pos(), "primitive.type.field", inner_type);
        that.type = attr.syms.botType;
        return;
    }

    ClassType ct = (ClassType) inner_type;

    // resolve field
    final Name name = that.name;

    Type site = ct;

    if (name == attr.names._class) { // x.class
        Type t = attr.syms.classType;
        List<Type> typeargs = attr.allowGenerics
      ? List.of(attr.types.erasure(site))
      : List.<Type>nil();
        t = new ClassType(t.getEnclosingType(), typeargs, t.tsym);
        VarSymbol sym = new VarSymbol(Flags.STATIC | Flags.PUBLIC | Flags.FINAL, attr.names._class, t, site.tsym);
        that.sym = sym;
        that.type = t;
    } else { // x.f
                    Symbol sym = attr.rs.findIdentInType(attr.env, site, name, Kinds.VAL);
        sym = attr.rs.access(sym, that.pos(), site, name, true);
        that.sym = sym;
        that.type = sym.type;
    }
      }
  }

        public void visitApply(final JCMethodInvocation that)
  {
      class PQLMagicTypeInference extends PQLMagicSubexpr
      {
    public Type type;

    @Override
    public void
    handleSize(JCExpression container)
    {
        type = visitSize(container);
    }

    @Override
    public void
    handleContains(JCExpression set, JCExpression element)
    {
        set.type = set.type.unifyWith(collectionTypeOf(element.type), attr.types);
        type = attr.syms.booleanType;
    }

    @Override
    public void
    handleMapGet(JCExpression map, JCExpression key)
    {
        Type result_tyvar = new QInferredType(null);
        map.type = map.type.unifyWith(mapTypeOf(key.type, result_tyvar), attr.types);
        type = result_tyvar;
    }

    @Override
    public void
    handleRange(JCExpression first, JCExpression last)
    {
        first.type = first.type.unifyWith(attr.syms.intType, attr.types);
        last.type = last.type.unifyWith(attr.syms.intType, attr.types);
        type = collectionTypeOf(attr.syms.intType);
    }

    @Override
    public void
    handleRangeContains(JCExpression first, JCExpression last, JCExpression body)
    {
        first.type = first.type.unifyWith(attr.syms.intType, attr.types);
        last.type = last.type.unifyWith(attr.syms.intType, attr.types);
        body.type = body.type.unifyWith(attr.syms.intType, attr.types);
        type = attr.syms.booleanType;
    }
      };

      PQLMagicTypeInference inferencer = new PQLMagicTypeInference();
      if (inferencer.process(that)) {
    that.type = inferencer.type;
    assert that.type != null;
    invocations_type_check.add(that);
      } else
    visitTree(that); // not a magic expression?  -> generic error
  }

        public void visitConditional(JCConditional that)
        {
      that.type = that.truepart.type.unifyWith(that.falsepart.type, attr.types);
      that.cond.type = that.cond.type.unifyWith(attr.syms.booleanType, attr.types);
  }

        public void visitTypeTest(JCInstanceOf that)
  {
      that.type = attr.syms.booleanType;
  }


  // ----------------------------------------
  // FIXME:

        public void visitTypeCast(JCTypeCast that)                 { err(that); }

  // ----------------------------------------
  // the following should never occur because type inference isn't needed for them:
        public void visitLiteral(JCLiteral that)
  {
      attr.pt = Type.noType;
      that.accept(attr);
      //throw new RuntimeException("Type inference for JCLiteral shouldn't be needed: " + that);
  }

        public void visitIdent(JCIdent that)
  {
      throw new RuntimeException("Type inference for JCIdent shouldn't be needed!");
  }

  // ----------------------------------------
  // disallowed for now:

        public void visitIf(JCIf that)                             { err(that); }
        public void visitNewClass(JCNewClass that)                 { err(that); }
        public void visitNewArray(JCNewArray that)                 { err(that); }

  // ----------------------------------------
  // the following will only arise if type variables occur in disallowed contexts:

        public void visitTypeIdent(JCPrimitiveTypeTree that)       { visitTree(that); }
        public void visitTypeArray(JCArrayTypeTree that)           { visitTree(that); }
        public void visitTypeApply(JCTypeApply that)               { visitTree(that); }
        public void visitTypeParameter(JCTypeParameter that)       { visitTree(that); }
        public void visitWildcard(JCWildcard that)                 { visitTree(that); }
        public void visitTypeBoundKind(TypeBoundKind that)         { visitTree(that); }
        public void visitAnnotation(JCAnnotation that)             { visitTree(that); }
        public void visitModifiers(JCModifiers that)               { visitTree(that); }
        public void visitReturn(JCReturn that)                     { visitTree(that); }
        public void visitAssert(JCAssert that)                     { visitTree(that); }
        public void visitExec(JCExpressionStatement that)          { visitTree(that); }
        public void visitBreak(JCBreak that)                       { visitTree(that); }
        public void visitContinue(JCContinue that)                 { visitTree(that); }
        public void visitThrow(JCThrow that)                       { visitTree(that); }
        public void visitAssignop(JCAssignOp that)                 { visitTree(that); }
        public void visitErroneous(JCErroneous that)               { }
        public void visitClassDef(JCClassDecl that)                { visitTree(that); }
        public void visitSkip(JCSkip that)                         { visitTree(that); }
        public void visitBlock(JCBlock that)                       { visitTree(that); }
        public void visitLabelled(JCLabeledStatement that)         { visitTree(that); }
        public void visitSwitch(JCSwitch that)                     { visitTree(that); }
        public void visitCase(JCCase that)                         { visitTree(that); }
        public void visitSynchronized(JCSynchronized that)         { visitTree(that); }
        public void visitTry(JCTry that)                           { visitTree(that); }
        public void visitCatch(JCCatch that)                       { visitTree(that); }
  public void visitTree(JCTree that)         {}


  public void visitTopLevel(JCCompilationUnit that)    { err(that); }
  public void visitImport(JCImport that)               { err(that); }
  public void visitMethodDef(JCMethodDecl that)        { err(that); }
  public void visitVarDef(JCVariableDecl that)         { err(that); }
  public void visitDoLoop(JCDoWhileLoop that)          { err(that); }
  public void visitWhileLoop(JCWhileLoop that)         { err(that); }
  public void visitForLoop(JCForLoop that)             { err(that); }
  public void visitForeachLoop(JCEnhancedForLoop that) { err(that); }
  public void visitLetExpr(LetExpr that)     { err(that); }

  public void err(JCTree that)
  {
      that.type = attr.syms.botType;
  }

    }
}
TOP

Related Classes of com.sun.tools.javac.comp.PQLMagicTypeInference

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.