Clover coverage report - DynamicJava Test Coverage (dynamicjava-20110903-r5436)
Coverage timestamp: Sat Sep 3 2011 03:02:20 CDT
file stats: LOC: 1,745   Methods: 96
NCLOC: 1,279   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
ExpressionChecker.java 36.1% 44.7% 53.1% 43.7%
coverage coverage
 1    /*
 2    * DynamicJava - Copyright (C) 1999-2001
 3    *
 4    * Permission is hereby granted, free of charge, to any person obtaining a
 5    * copy of this software and associated documentation files
 6    * (the "Software"), to deal in the Software without restriction, including
 7    * without limitation the rights to use, copy, modify, merge, publish,
 8    * distribute, sublicense, and/or sell copies of the Software, and to permit
 9    * persons to whom the Software is furnished to do so, subject to the
 10    * following conditions:
 11    * The above copyright notice and this permission notice shall be included
 12    * in all copies or substantial portions of the Software.
 13    *
 14    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 15    * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 16    * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 17    * IN NO EVENT SHALL DYADE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 19    * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 20    * DEALINGS IN THE SOFTWARE.
 21    *
 22    * Except as contained in this notice, the name of Dyade shall not be
 23    * used in advertising or otherwise to promote the sale, use or other
 24    * dealings in this Software without prior written authorization from
 25    * Dyade.
 26    *
 27    */
 28   
 29    /*BEGIN_COPYRIGHT_BLOCK
 30    *
 31    * This file is part of DrJava. Download the current version of this project:
 32    * http://sourceforge.net/projects/drjava/ or http://www.drjava.org/
 33    *
 34    * DrJava Open Source License
 35    *
 36    * Copyright (C) 2001-2010 JavaPLT group at Rice University (drjava@rice.edu)
 37    * All rights reserved.
 38    *
 39    * Developed by: Java Programming Languages Team
 40    * Rice University
 41    * http://www.cs.rice.edu/~javaplt/
 42    *
 43    * Permission is hereby granted, free of charge, to any person obtaining a
 44    * copy of this software and associated documentation files (the "Software"),
 45    * to deal with the Software without restriction, including without
 46    * limitation the rights to use, copy, modify, merge, publish, distribute,
 47    * sublicense, and/or sell copies of the Software, and to permit persons to
 48    * whom the Software is furnished to do so, subject to the following
 49    * conditions:
 50    *
 51    * - Redistributions of source code must retain the above copyright
 52    * notice, this list of conditions and the following disclaimers.
 53    * - Redistributions in binary form must reproduce the above copyright
 54    * notice, this list of conditions and the following disclaimers in the
 55    * documentation and/or other materials provided with the distribution.
 56    * - Neither the names of DrJava, the JavaPLT, Rice University, nor the
 57    * names of its contributors may be used to endorse or promote products
 58    * derived from this Software without specific prior written permission.
 59    * - Products derived from this software may not be called "DrJava" nor
 60    * use the term "DrJava" as part of their names without prior written
 61    * permission from the JavaPLT group. For permission, write to
 62    * drjava@rice.edu.
 63    *
 64    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 65    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 66    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 67    * THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 68    * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 69    * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 70    * OTHER DEALINGS WITH THE SOFTWARE.
 71    *
 72    END_COPYRIGHT_BLOCK*/
 73   
 74    package edu.rice.cs.dynamicjava.interpreter;
 75   
 76    import java.util.*;
 77    import edu.rice.cs.plt.iter.IterUtil;
 78    import edu.rice.cs.plt.collect.CollectUtil;
 79    import edu.rice.cs.plt.tuple.Pair;
 80    import edu.rice.cs.plt.tuple.Option;
 81    import edu.rice.cs.plt.lambda.Lambda;
 82    import edu.rice.cs.plt.lambda.Lambda2;
 83    import edu.rice.cs.plt.lambda.WrappedException;
 84   
 85    import edu.rice.cs.dynamicjava.Options;
 86    import edu.rice.cs.dynamicjava.symbol.*;
 87    import edu.rice.cs.dynamicjava.symbol.TypeSystem.*;
 88    import edu.rice.cs.dynamicjava.symbol.type.*;
 89   
 90    import koala.dynamicjava.tree.*;
 91    import koala.dynamicjava.tree.visitor.*;
 92    import koala.dynamicjava.interpreter.error.ExecutionError;
 93    import koala.dynamicjava.interpreter.TypeUtil;
 94   
 95    import static koala.dynamicjava.interpreter.NodeProperties.*;
 96    import static edu.rice.cs.plt.debug.DebugUtil.debug;
 97   
 98    /**
 99    * This tree visitor checks the typing rules for expressions and determines each expression's type.
 100    * The following properties (from {@code NodeProperties}) are set:<ul>
 101    * <li>TYPE on all {@code Expression}s and on {@code FormalParameter}s</li>
 102    * <li>CONVERTED_TYPE on any {@code CastExpression} subexpressions that require runtime conversion</li>
 103    * <li>CHECKED_TYPE on any {@code CastExpression} subexpressions, {@code FieldAccess}es, or
 104    * {@code MethodCall}s that require runtime checking</li>
 105    * <li>ERASED_TYPE on all {@code ArrayAllocation}s, and {@code ArrayInitializer}s,
 106    * and the nested type of {@code TypeExpression}s and {@code InstanceofExpression}s</li>
 107    * <li>LEFT_EXPRESSION on assignments, increments, and decrements that access the left expression in
 108    * order to evaluate the right expression</li>
 109    * <li>VARIABLE_TYPE on all lvalue expressions</li>
 110    * <li>SUPER_TYPE on all AnonymousInnerAllocations</li>
 111    * <li>VALUE on all constant expressions</li>
 112    * <li>DJCLASS on {@code AnonymousAllocation}s, {@code AnonymousInnerAllocation}s,
 113    * {@code ThisExpression}s, {@code SuperMethodCall}s, {@code SuperFieldAccess}es, and
 114    * non-static {@code SimpleMethodCall}s and {@code SimpleFieldAccess}es.</li>
 115    * <li>CONSTRUCTOR on {@code ConstructorCall}s and all allocations: {@code SimpleAllocation}s,
 116    * {@code InnerAllocation}s, {@code AnonymousAllocation}s, and {@code AnonymousInnerAllocation}s</li>
 117    * <li>ENCLOSING_THIS on {@code SimpleAllocation}s and {@code AnonymousAllocations}s that represent
 118    * inner allocations with a "this" value of the given class as the enclosing object</li>
 119    * <li>FIELD on all {@code FieldAccess}es</li>
 120    * <li>METHOD on all {@code MethodCall}s</li>
 121    * <li>VARIABLE on all {@code VariableAccess}es, {@code VariableDeclarations}, and {@code FormalParameters}</li>
 122    * <li>OPERATION on all {@code AddExpression}s, {@code AddAssignExpression}s, {@code EqualExpression}s, and
 123    * {@code NotEqualExpression}s</li>
 124    * </ul>
 125    */
 126    // TODO: Handle non-literal constant expressions
 127    public class ExpressionChecker {
 128   
 129    private final TypeContext context;
 130    private final TypeSystem ts;
 131    private final Options opt;
 132   
 133  1848 public ExpressionChecker(TypeContext ctx, Options options) {
 134  1848 context = ctx;
 135  1848 ts = options.typeSystem();
 136  1848 opt = options;
 137    }
 138   
 139  2339 public Type check(Expression e) {
 140  2339 return e.acceptVisitor(new ExpressionVisitor(Option.<Type>none()));
 141    }
 142   
 143  1328 public Type check(Expression e, Type expected) {
 144  1328 return e.acceptVisitor(new ExpressionVisitor(Option.some(expected)));
 145    }
 146   
 147  0 public Type check(Expression e, Option<Type> expected) {
 148  0 return e.acceptVisitor(new ExpressionVisitor(expected));
 149    }
 150   
 151  806 public Iterable<Type> checkList(Iterable<? extends Expression> l) {
 152  806 return IterUtil.mapSnapshot(l, new ExpressionVisitor(Option.<Type>none()));
 153    }
 154   
 155  24 public Iterable<Type> checkList(Iterable<? extends Expression> l, Type expected) {
 156  24 return IterUtil.mapSnapshot(l, new ExpressionVisitor(Option.some(expected)));
 157    }
 158   
 159  0 public Iterable<Type> checkList(Iterable<? extends Expression> l, Option<Type> expected) {
 160  0 return IterUtil.mapSnapshot(l, new ExpressionVisitor(expected));
 161    }
 162   
 163  590 private Type checkTypeName(TypeName t) {
 164  590 return new TypeNameChecker(context, opt).check(t);
 165    }
 166   
 167  737 private Iterable<Type> checkTypeNameList(Iterable<? extends TypeName> l) {
 168  737 return new TypeNameChecker(context, opt).checkList(l);
 169    }
 170   
 171    /**
 172    * Handle a valid constructor call: one that appears as the first line of a constructor.
 173    * ConstructorCalls handled via {@link #check(Expression)} will always be treated as errors.
 174    */
 175  69 public void checkConstructorCall(ConstructorCall node) {
 176  69 if (node.getExpression() != null) {
 177  0 throw new ExecutionError("not.implemented", node);
 178    }
 179   
 180  69 Iterable<? extends Expression> args = node.getArguments();
 181  69 checkList(args);
 182  69 Iterable<Type> targs = IterUtil.empty();
 183    // TODO: parse explicit type arguments in constructor calls
 184    //Iterable<Type> targs = checkTypeNameList(node.getTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 185   
 186  69 Type type;
 187  69 if (node.isSuper()) { type = context.getThis().immediateSuperclass(); }
 188  0 else { type = SymbolUtil.thisType(context.getThis()); }
 189  69 if (type == null) {
 190  0 throw new IllegalArgumentException("Can't check a ConstructorCall in this context");
 191    }
 192   
 193  69 try {
 194  69 ConstructorInvocation inv = ts.lookupConstructor(type, targs, args, Option.<Type>none(), context.accessModule());
 195    // Super constructor calls *have to* be accessible, even if accessibility
 196    // checking is turned off -- a call to a private constructor cannot be compiled
 197    // in a way that it will run successfully (since constructor calls are the only code
 198    // that is directly compiled rather than being interpreted, we don't have this problem
 199    // elsewhere)
 200  69 DJConstructor k = inv.constructor();
 201  69 if (k.accessibility().equals(Access.PRIVATE) && !k.accessModule().equals(context.accessModule())) {
 202  0 setErrorStrings(node, ts.typePrinter().print(type));
 203  0 throw new ExecutionError("inaccessible.super.call", node);
 204    }
 205  69 checkThrownExceptions(inv.thrown(), node);
 206  69 node.setArguments(CollectUtil.makeList(inv.args()));
 207  69 setConstructor(node, k);
 208  69 setType(node, type);
 209    }
 210    catch (InvalidTypeArgumentException e) {
 211  0 throw new ExecutionError("type.argument", node);
 212    }
 213    catch (UnmatchedLookupException e) {
 214  0 throw unmatchedFunctionError("constructor", e, node, type, "", targs, args, Option.<Type>none(), false);
 215    }
 216    }
 217   
 218    /**
 219    * Check an expression appearing as the switch case in an enum switch statement.
 220    * @return The field corresponding to the enum constant's value.
 221    */
 222  0 public DJField checkEnumSwitchCase(Expression exp, Type enumT) {
 223  0 if (!(exp instanceof AmbiguousName)) {
 224  0 throw new ExecutionError("invalid.enum.constant", exp);
 225    }
 226  0 List<IdentifierToken> ids = ((AmbiguousName) exp).getIdentifiers();
 227  0 if (ids.size() != 1) {
 228  0 throw new ExecutionError("invalid.enum.constant", exp);
 229    }
 230  0 String name = ids.get(0).image();
 231  0 Expression translation = new SimpleFieldAccess(name);
 232  0 setTranslation(exp, translation);
 233  0 try {
 234    // Should actually verify that that the name is a declared enum constant, not just
 235    // a static field. But that requires a lot of unimplemented support where we're
 236    // otherwise treating enums as syntactic sugar for normal class declarations.
 237  0 StaticFieldReference ref = ts.lookupStaticField(enumT, name, context.accessModule());
 238  0 setField(translation, ref.field());
 239  0 Type t = ts.capture(ref.type());
 240  0 if (!ts.isSubtype(t, enumT)) {
 241  0 throw new ExecutionError("invalid.enum.constant", exp);
 242    }
 243  0 addRuntimeCheck(translation, t, ref.field().type());
 244  0 setType(translation, t);
 245  0 setType(exp, t);
 246  0 if (hasValue(translation)) { setValue(exp, getValue(translation)); }
 247  0 return ref.field();
 248    }
 249    catch (UnmatchedLookupException e) {
 250  0 throw new ExecutionError("invalid.enum.constant", exp);
 251    }
 252    }
 253   
 254    /**
 255    * Dynamically determines the appropriate error message type and initializes ERROR_STRINGS with the following:
 256    * {@code 0=type, 1=name, 2=targs, 3=args, 4=expected, 5=candidates}.
 257    */
 258  17 private ExecutionError unmatchedFunctionError(String kind, UnmatchedLookupException e, Node node, Type type,
 259    String name, Iterable<? extends Type> targs,
 260    Iterable<? extends Expression> args, Option<Type> expected,
 261    boolean onlyStatic) {
 262  17 final TypePrinter printer = ts.typePrinter();
 263  17 String error = ((e.matches() > 1) ? "ambiguous." : "no.such.") + kind;
 264  17 Iterable<? extends Function> candidates = IterUtil.empty();
 265  17 boolean noMatch = false;
 266  17 if (e instanceof UnmatchedFunctionLookupException) {
 267  17 candidates = ((UnmatchedFunctionLookupException) e).candidates();
 268  0 if (IterUtil.isEmpty(candidates)) { noMatch = true; }
 269    }
 270  0 else if (e instanceof AmbiguousFunctionLookupException) {
 271  0 candidates = ((AmbiguousFunctionLookupException) e).candidates();
 272    }
 273  0 if (error.equals("no.such.method") && noMatch) { error += ".name"; }
 274    else {
 275  0 if (!IterUtil.isEmpty(targs)) { error += ".poly"; }
 276  10 if (expected.isSome()) { error += ".expected"; }
 277  17 if (!IterUtil.isEmpty(candidates)) { error += ".candidates"; }
 278    }
 279  17 String typeS = (onlyStatic ? "static " : "") + printer.print(type);
 280  17 String expectedS = expected.isSome() ? printer.print(expected.unwrap()) : "";
 281  17 String candidatesS;
 282  17 if (IterUtil.sizeOf(candidates, 2) == 1) {
 283  17 candidatesS = printer.print(IterUtil.first(candidates));
 284    }
 285    else {
 286  0 String prefix = "\n ";
 287  0 Lambda<Function, String> printSig = new Lambda<Function, String>() {
 288  0 public String value(Function f) { return printer.print(f); }
 289    };
 290  0 candidatesS = IterUtil.toString(IterUtil.map(candidates, printSig), prefix, prefix, "");
 291    }
 292  17 setErrorStrings(node, typeS, name, printer.print(targs), nodeTypesString(args, printer), expectedS, candidatesS);
 293  17 throw new ExecutionError(error, node);
 294    }
 295   
 296    /** Verify that the thrown exceptions are expected in this context. */
 297  789 private void checkThrownExceptions(Iterable<? extends Type> thrownTypes, Node node) {
 298  789 Iterable<Type> allowed = IterUtil.compose(TypeSystem.RUNTIME_EXCEPTION,
 299    context.getDeclaredThrownTypes());
 300  789 for (Type thrown : thrownTypes) {
 301  0 if (ts.isAssignable(TypeSystem.EXCEPTION, thrown)) {
 302  0 boolean valid = false;
 303  0 for (Type t : allowed) {
 304  0 if (ts.isAssignable(t, thrown)) { valid = true; break; }
 305    }
 306  0 if (!valid) {
 307  0 setErrorStrings(node, ts.typePrinter().print(thrown));
 308  0 throw new ExecutionError("uncaught.exception", node);
 309    }
 310    }
 311    }
 312    }
 313   
 314  416 private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualType) {
 315  416 if (!ts.isSubtype(ts.erase(declaredActualType), ts.erase(expectedType))) {
 316  3 setCheckedType(node, ts.erasedClass(expectedType));
 317    }
 318    }
 319   
 320  17 private String nodeTypesString(Iterable<? extends Node> nodes, TypePrinter printer) {
 321  17 return printer.print(IterUtil.map(nodes, NODE_TYPE));
 322    }
 323   
 324   
 325   
 326    private class ExpressionVisitor extends AbstractVisitor<Type> implements Lambda<Expression, Type> {
 327   
 328    // acts as a hint for inference; does not directly trigger type errors
 329    private final Option<Type> expected;
 330   
 331  4497 public ExpressionVisitor(Option<Type> exp) { expected = exp; }
 332   
 333  791 public Type value(Expression e) { return e.acceptVisitor(this); }
 334   
 335   
 336  1572 @Override public Type visit(AmbiguousName node) {
 337  1572 Node resolved = resolveAmbiguousName(node);
 338  1572 if (resolved instanceof ReferenceTypeName) {
 339  0 setErrorStrings(node, ((ReferenceTypeName) resolved).getRepresentation());
 340  0 throw new ExecutionError("undefined.name", node);
 341    }
 342    else {
 343  1572 Expression resolvedExp = (Expression) resolved;
 344  1572 setTranslation(node, resolvedExp);
 345  1572 resolvedExp.acceptVisitor(this);
 346    // VARIABLE_TYPE, TYPE, FIELD, and VARIABLE properties are important in the enclosing context;
 347    // others are not, and need not be copied to the AmbiguousName
 348  1572 if (hasVariableType(resolvedExp)) { setVariableType(node, getVariableType(resolvedExp)); }
 349  1 if (hasValue(resolvedExp)) { setValue(node, getValue(resolvedExp)); }
 350  178 if (hasField(resolvedExp)) { setField(node, getField(resolvedExp)); }
 351  1394 if (hasVariable(resolvedExp)) { setVariable(node, getVariable(resolvedExp)); }
 352  1572 return setType(node, getType(resolvedExp));
 353    }
 354    }
 355   
 356    /**
 357    * Produce an appropriate translation of an AmbiguousName. The result will be one of: VariableAccess,
 358    * SimpleFieldAccess, StaticFieldAccess, ObjectFieldAccess, or ReferenceTypeName. Note that a
 359    * ReferenceTypeName is not an Expression; its use should be detected and handled by callers.
 360    */
 361  1696 private Node resolveAmbiguousName(AmbiguousName node) {
 362  1696 Iterator<IdentifierToken> ids = node.getIdentifiers().iterator();
 363  1696 IdentifierToken first = ids.next();
 364  1696 Expression resultExp = null;
 365   
 366  1696 if (context.localVariableExists(first.image(), ts)) {
 367  1573 resultExp = new VariableAccess(first.image(), first.getSourceInfo());
 368    }
 369  123 else if (context.fieldExists(first.image(), ts)) {
 370  69 resultExp = new SimpleFieldAccess(first.image(), first.getSourceInfo());
 371    }
 372    else {
 373    // Try to match a class
 374  54 IdentifierToken last = first;
 375  54 String className = first.image();
 376  54 List<IdentifierToken> classIds = new LinkedList<IdentifierToken>();
 377  54 classIds.add(first);
 378  54 Type classType;
 379   
 380  54 while (!context.typeExists(className, ts)) {
 381  0 if (!ids.hasNext()) {
 382  0 setErrorStrings(node, className);
 383  0 throw new ExecutionError("undefined.name", node);
 384    }
 385  0 last = ids.next();
 386  0 className += "." + last.image();
 387  0 classIds.add(last);
 388    }
 389  54 try {
 390  54 DJClass c = context.getTopLevelClass(className, ts);
 391  54 if (c != null) {
 392  54 classType = ts.makeClassType(c);
 393    }
 394    else {
 395  0 classType = context.getTypeVariable(className, ts);
 396  0 if (classType == null) {
 397    // must be a member class (note that a simple name "Foo" can reference a member class)
 398  0 Type outer = context.typeContainingMemberClass(className, ts);
 399  0 classType = ts.lookupStaticClass(outer, className, IterUtil.<Type>empty(), context.accessModule());
 400    // TODO: Improve error when memberName is a non-static class
 401    }
 402    }
 403    }
 404    catch (AmbiguousNameException e) {
 405  0 setErrorStrings(node, className);
 406  0 throw new ExecutionError("ambiguous.name", node);
 407    }
 408  0 catch (InvalidTypeArgumentException e) { throw new ExecutionError("type.argument.arity", node); }
 409    catch (UnmatchedLookupException e) {
 410  0 if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
 411    else {
 412  0 setErrorStrings(node, className);
 413  0 throw new ExecutionError("ambiguous.name", node);
 414    }
 415    }
 416   
 417    // Append member names until a field is encountered (or until all names are used up)
 418  54 while (ids.hasNext() && resultExp == null) {
 419  1 IdentifierToken memberName = ids.next();
 420  1 if (ts.containsField(classType, memberName.image(), context.accessModule())) {
 421  1 ReferenceTypeName rt = new ReferenceTypeName(classIds, SourceInfo.span(first, last));
 422  1 resultExp = new StaticFieldAccess(rt, memberName.image(), SourceInfo.span(first, memberName));
 423    }
 424  0 else if (ts.containsClass(classType, memberName.image(), context.accessModule())) {
 425  0 last = memberName;
 426  0 className += "." + last.image();
 427  0 classIds.add(last);
 428  0 try {
 429  0 ClassType memberType = ts.lookupStaticClass(classType, memberName.image(), IterUtil.<Type>empty(),
 430    context.accessModule());
 431  0 classType = memberType;
 432    }
 433  0 catch (InvalidTypeArgumentException e) { throw new ExecutionError("type.argument.arity", node); }
 434    catch (UnmatchedLookupException e) {
 435  0 if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
 436    else {
 437  0 setErrorStrings(node, memberName.image());
 438  0 throw new ExecutionError("ambiguous.name", node);
 439    }
 440    }
 441    // TODO: Improve error when memberName is a non-static class
 442    }
 443    else {
 444  0 setErrorStrings(node, ts.typePrinter().print(classType), memberName.image());
 445  0 throw new ExecutionError("no.such.member", node);
 446    }
 447    }
 448   
 449  54 if (resultExp == null) { // there must be no more tokens; the name is the name of a class
 450  53 return new ReferenceTypeName(classIds, SourceInfo.span(first, last));
 451    }
 452    }
 453   
 454    // resultExp is now guaranteed to be defined; append any additional identifiers as field accesses
 455  1643 while (ids.hasNext()) {
 456  108 IdentifierToken field = ids.next();
 457  108 resultExp = new ObjectFieldAccess(resultExp, field.image(), SourceInfo.span(first, field));
 458    }
 459  1643 return resultExp;
 460    }
 461   
 462   
 463    /**
 464    * Visits a Literal
 465    * @return The type of the expression
 466    */
 467  921 @Override public Type visit(Literal node) {
 468  921 setValue(node, node.getValue());
 469  10 if (node instanceof NullLiteral) { return setType(node, TypeSystem.NULL); }
 470  380 else if (node instanceof StringLiteral) { return setType(node, TypeSystem.STRING); }
 471  531 else { return setType(node, SymbolUtil.typeOfPrimitiveClass(node.getType())); }
 472    }
 473   
 474  0 private DJClass resolveThis(Option<String> outerName, Node node) {
 475  0 DJClass result;
 476  0 if (outerName.isNone()) {
 477  0 result = context.getThis();
 478  0 if (result == null) { throw new ExecutionError("this.undefined", node); }
 479    }
 480    else {
 481  0 result = context.getThis(outerName.unwrap());
 482  0 if (result == null) {
 483  0 setErrorStrings(node, outerName.unwrap());
 484  0 throw new ExecutionError("undefined.class", node);
 485    }
 486    }
 487  0 return result;
 488    }
 489   
 490    /**
 491    * Visits a ThisExpression
 492    * @return The type of this, according to the context.
 493    */
 494  0 @Override public Type visit(ThisExpression node) {
 495  0 DJClass thisC = resolveThis(node.getClassName(), node);
 496  0 setDJClass(node, thisC);
 497  0 return setType(node, SymbolUtil.thisType(thisC));
 498    }
 499   
 500    /**
 501    * Visits a VariableAccess
 502    * @return The type of the expression
 503    */
 504  1573 @Override public Type visit(VariableAccess node) {
 505  1573 LocalVariable v = context.getLocalVariable(node.getVariableName(), ts);
 506  1573 setVariable(node, v);
 507  1573 setVariableType(node, v.type());
 508  1573 return setType(node, ts.capture(v.type()));
 509    }
 510   
 511    /**
 512    * Visits a SimpleFieldAccess
 513    * @return The type of the expression
 514    */
 515  69 @Override public Type visit(SimpleFieldAccess node) {
 516  69 try {
 517  69 ClassType t = context.typeContainingField(node.getFieldName(), ts);
 518  69 if (t == null) {
 519  0 setErrorStrings(node, node.getFieldName());
 520  0 throw new ExecutionError("undefined.name", node);
 521    }
 522  69 DJClass enclosingThis = context.getThis(t, ts);
 523  69 boolean onlyStatic = (enclosingThis == null);
 524  69 FieldReference ref;
 525  69 if (onlyStatic) {
 526  0 ref = ts.lookupStaticField(t, node.getFieldName(), context.accessModule());
 527    }
 528    else {
 529  69 Expression obj = TypeUtil.makeEmptyExpression(node);
 530  69 setType(obj, t);
 531  69 ref = ts.lookupField(obj, node.getFieldName(), context.accessModule());
 532    }
 533  69 setField(node, ref.field());
 534  69 Option<Object> val = ref.field().constantValue();
 535  0 if (val.isSome()) { setValue(node, val.unwrap()); }
 536  69 setVariableType(node, ref.type());
 537  69 if (!onlyStatic) { setDJClass(node, enclosingThis); }
 538  69 Type result = ts.capture(ref.type());
 539  69 addRuntimeCheck(node, result, ref.field().type());
 540  69 return setType(node, result);
 541    }
 542    catch (AmbiguousNameException e) {
 543  0 setErrorStrings(node, node.getFieldName());
 544  0 throw new ExecutionError("ambiguous.name", node);
 545    }
 546    catch (UnmatchedLookupException e) {
 547  0 if (e.matches() == 0) { throw new ExecutionError("undefined.name.noinfo", node); }
 548    else {
 549  0 setErrorStrings(node, node.getFieldName());
 550  0 throw new ExecutionError("ambiguous.name", node);
 551    }
 552    }
 553    }
 554   
 555    /**
 556    * Visits an ObjectFieldAccess
 557    * @return The type of the expression
 558    */
 559  108 @Override public Type visit(ObjectFieldAccess node) {
 560  108 Expression receiver = node.getExpression();
 561  108 Type receiverT = check(receiver);
 562  108 try {
 563  108 ObjectFieldReference ref = ts.lookupField(receiver, node.getFieldName(), context.accessModule());
 564  108 node.setExpression(ref.object());
 565  108 setField(node, ref.field());
 566  108 setVariableType(node, ref.type());
 567  108 Type result = ts.capture(ref.type());
 568  108 addRuntimeCheck(node, result, ref.field().type());
 569  108 return setType(node, result);
 570    }
 571    catch (UnmatchedLookupException e) {
 572  0 setErrorStrings(node, ts.typePrinter().print(receiverT), node.getFieldName());
 573  0 if (e.matches() > 1) { throw new ExecutionError("ambiguous.field", node); }
 574  0 else { throw new ExecutionError("no.such.field", node); }
 575    }
 576    }
 577   
 578    /**
 579    * Visits a SuperFieldAccess
 580    * @return The type of the expression
 581    */
 582  0 @Override public Type visit(SuperFieldAccess node) {
 583  0 DJClass c = resolveThis(node.getClassName(), node);
 584  0 Type t = c.immediateSuperclass();
 585  0 if (t == null) {
 586  0 throw new ExecutionError("super.undefined", node);
 587    }
 588  0 Expression obj = TypeUtil.makeEmptyExpression(node);
 589  0 setType(obj, t);
 590  0 try {
 591  0 FieldReference ref = ts.lookupField(obj, node.getFieldName(), context.accessModule());
 592  0 setField(node, ref.field());
 593  0 setDJClass(node, c);
 594  0 setVariableType(node, ref.type());
 595  0 Type result = ts.capture(ref.type());
 596  0 addRuntimeCheck(node, result, ref.field().type());
 597  0 return setType(node, result);
 598    }
 599    catch (UnmatchedLookupException e) {
 600  0 setErrorStrings(node, ts.typePrinter().print(t), node.getFieldName());
 601  0 if (e.matches() > 1) { throw new ExecutionError("ambiguous.field", node); }
 602  0 else { throw new ExecutionError("no.such.field", node); }
 603    }
 604    }
 605   
 606    /**
 607    * Visits a StaticFieldAccess
 608    * @return The type of the expression
 609    */
 610  1 @Override public Type visit(StaticFieldAccess node) {
 611  1 Type t = checkTypeName(node.getFieldType());
 612  1 try {
 613  1 FieldReference ref = ts.lookupStaticField(t, node.getFieldName(), context.accessModule());
 614  1 setField(node, ref.field());
 615  1 Option<Object> val = ref.field().constantValue();
 616  1 if (val.isSome()) { setValue(node, val.unwrap()); }
 617  1 setVariableType(node, ref.type());
 618  1 Type result = ts.capture(ref.type());
 619  1 addRuntimeCheck(node, result, ref.field().type());
 620  1 return setType(node, result);
 621    }
 622    catch (UnmatchedLookupException e) {
 623  0 setErrorStrings(node, ts.typePrinter().print(t), node.getFieldName());
 624  0 if (e.matches() > 1) { throw new ExecutionError("ambiguous.field", node); }
 625  0 else { throw new ExecutionError("no.such.static.field", node); }
 626    }
 627    }
 628   
 629    /**
 630    * Visits a SimpleMethodCall
 631    * @return The type of the expression
 632    */
 633  108 @Override public Type visit(SimpleMethodCall node) {
 634  108 Iterable<? extends Expression> args = node.getArguments();
 635  108 checkList(args);
 636  108 Iterable<Type> targs = checkTypeNameList(node.getTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 637   
 638  108 Type t;
 639  108 if (context.localFunctionExists(node.getMethodName(), ts)) {
 640  108 Iterable<LocalFunction> matches = context.getLocalFunctions(node.getMethodName(), ts);
 641  108 t = ts.makeClassType(new FunctionWrapperClass(context.accessModule(), matches));
 642    }
 643    else {
 644  0 t = context.typeContainingMethod(node.getMethodName(), ts);
 645  0 if (t == null) {
 646  0 setErrorStrings(node, node.getMethodName());
 647  0 throw new ExecutionError("undefined.name", node);
 648    }
 649    }
 650   
 651  108 DJClass enclosingThis = context.getThis(t, ts);
 652  108 boolean onlyStatic = (enclosingThis == null);
 653  108 try {
 654  108 MethodInvocation inv;
 655  108 if (onlyStatic) {
 656  108 inv = ts.lookupStaticMethod(t, node.getMethodName(), targs, args, expected, context.accessModule());
 657    }
 658    else {
 659  0 Expression obj = TypeUtil.makeEmptyExpression(node);
 660  0 setType(obj, t);
 661  0 inv = ts.lookupMethod(obj, node.getMethodName(), targs, args, expected, context.accessModule());
 662    }
 663  108 checkThrownExceptions(inv.thrown(), node);
 664  108 node.setArguments(CollectUtil.makeList(inv.args()));
 665  108 setMethod(node, inv.method());
 666  0 if (!onlyStatic) { setDJClass(node, enclosingThis); }
 667  108 Type result = ts.capture(inv.returnType());
 668  108 debug.logValue("Type of method call " + node.getMethodName(), ts.wrap(result));
 669  108 addRuntimeCheck(node, result, inv.method().returnType());
 670  108 return setType(node, result);
 671    }
 672    catch (InvalidTypeArgumentException e) {
 673  0 throw new ExecutionError("type.argument", node);
 674    }
 675    catch (UnmatchedLookupException e) {
 676  0 throw unmatchedFunctionError("method", e, node, t, node.getMethodName(), targs, args, expected, onlyStatic);
 677    }
 678    }
 679   
 680    /**
 681    * Visits an ObjectMethodCall
 682    * @return The type of the expression
 683    */
 684  146 @Override public Type visit(ObjectMethodCall node) {
 685  146 Expression receiver = node.getExpression();
 686  146 if (receiver instanceof AmbiguousName) {
 687  124 Node resolved = resolveAmbiguousName((AmbiguousName) receiver);
 688  124 if (resolved instanceof ReferenceTypeName) {
 689    // this is actually a StaticMethodCall
 690  53 Expression translation = new StaticMethodCall((ReferenceTypeName) resolved, node.getTypeArgs(),
 691    node.getMethodName(), node.getArguments(),
 692    node.getSourceInfo());
 693  53 setTranslation(node, translation);
 694  53 translation.acceptVisitor(this);
 695  47 return setType(node, getType(translation));
 696    }
 697  71 else { receiver = (Expression) resolved; }
 698    }
 699   
 700  93 Type receiverT = check(receiver);
 701   
 702  93 Iterable<? extends Expression> args = node.getArguments();
 703  93 checkList(args);
 704  93 Iterable<Type> targs = checkTypeNameList(node.getTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 705   
 706  93 try {
 707    // Note: Changes made below may also need to be made in the TypeSystem's boxing & unboxing implementations
 708  93 ObjectMethodInvocation inv = ts.lookupMethod(receiver, node.getMethodName(), targs, args, expected,
 709    context.accessModule());
 710  83 checkThrownExceptions(inv.thrown(), node);
 711  83 node.setExpression(inv.object());
 712  83 node.setArguments(CollectUtil.makeList(inv.args()));
 713  83 setMethod(node, inv.method());
 714  83 Type result = ts.capture(inv.returnType());
 715  83 debug.logValue("Type of method call " + node.getMethodName(), ts.wrap(result));
 716  83 addRuntimeCheck(node, result, inv.method().returnType());
 717  83 return setType(node, result);
 718    }
 719    catch (InvalidTypeArgumentException e) {
 720  0 throw new ExecutionError("type.argument", node);
 721    }
 722    catch (UnmatchedLookupException e) {
 723  10 throw unmatchedFunctionError("method", e, node, receiverT, node.getMethodName(), targs, args, expected, false);
 724    }
 725    }
 726   
 727    /**
 728    * Visits a SuperMethodCall
 729    * @return The type of the expression
 730    */
 731  0 @Override public Type visit(SuperMethodCall node) {
 732  0 DJClass c = resolveThis(node.getClassName(), node);
 733  0 Type t = c.immediateSuperclass();
 734  0 if (t == null) {
 735  0 throw new ExecutionError("super.undefined", node);
 736    }
 737   
 738  0 Iterable<? extends Expression> args = node.getArguments();
 739  0 checkList(args);
 740  0 Iterable<Type> targs = checkTypeNameList(node.getTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 741   
 742  0 Expression obj = TypeUtil.makeEmptyExpression(node);
 743  0 setType(obj, t);
 744  0 try {
 745  0 MethodInvocation inv = ts.lookupMethod(obj, node.getMethodName(), targs, args, expected,
 746    context.accessModule());
 747  0 checkThrownExceptions(inv.thrown(), node);
 748  0 node.setArguments(CollectUtil.makeList(inv.args()));
 749  0 setMethod(node, inv.method());
 750  0 setDJClass(node, c);
 751  0 Type result = ts.capture(inv.returnType());
 752  0 debug.logValue("Type of method call " + node.getMethodName(), ts.wrap(result));
 753  0 addRuntimeCheck(node, result, inv.method().returnType());
 754  0 return setType(node, result);
 755    }
 756    catch (InvalidTypeArgumentException e) {
 757  0 throw new ExecutionError("type.argument", node);
 758    }
 759    catch (UnmatchedLookupException e) {
 760  0 throw unmatchedFunctionError("method", e, node, t, node.getMethodName(), targs, args, expected, false);
 761    }
 762    }
 763   
 764    /**
 765    * Visits a StaticMethodCall
 766    * @return The type of the expression
 767    */
 768  53 @Override public Type visit(StaticMethodCall node) {
 769  53 Type t = checkTypeName(node.getMethodType());
 770   
 771  53 Iterable<? extends Expression> args = node.getArguments();
 772  53 checkList(args);
 773  53 Iterable<Type> targs = checkTypeNameList(node.getTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 774   
 775  53 try {
 776    // Note: Changes made below may also need to be made in the TypeSystem's boxing & unboxing implementations
 777  53 MethodInvocation inv = ts.lookupStaticMethod(t, node.getMethodName(), targs, args, expected,
 778    context.accessModule());
 779  47 checkThrownExceptions(inv.thrown(), node);
 780  47 node.setArguments(CollectUtil.makeList(inv.args()));
 781  47 setMethod(node, inv.method());
 782  47 Type result = ts.capture(inv.returnType());
 783  47 debug.logValue("Type of method call " + node.getMethodName(), ts.wrap(result));
 784  47 addRuntimeCheck(node, result, inv.method().returnType());
 785  47 return setType(node, result);
 786    }
 787    catch (InvalidTypeArgumentException e) {
 788  0 throw new ExecutionError("type.argument", node);
 789    }
 790    catch (UnmatchedLookupException e) {
 791  6 throw unmatchedFunctionError("method", e, node, t, node.getMethodName(), targs, args, expected, true);
 792    }
 793    }
 794   
 795    /** Visits an ArrayAllocation. JLS 15.10.
 796    * @return The type of the array
 797    */
 798  12 @Override public Type visit(ArrayAllocation node) {
 799  12 Type elementType = checkTypeName(node.getElementType());
 800  12 if (! ts.isReifiable(elementType)) {
 801  0 throw new ExecutionError("reifiable.type", node);
 802    }
 803  12 Type result = elementType;
 804  12 for (int i = 0; i < node.getDimension(); i++) {
 805  12 result = new SimpleArrayType(result);
 806    }
 807   
 808  12 checkList(node.getSizes(), TypeSystem.INT);
 809  12 List<Expression> newSizes = new ArrayList<Expression>(node.getSizes().size());
 810  12 for (Expression exp : node.getSizes()) {
 811  0 try {
 812  0 Expression newExp = ts.unaryPromote(ts.makePrimitive(exp));
 813  0 if (!(getType(newExp) instanceof IntType)) {
 814  0 throw new ExecutionError("array.dimension.type", node);
 815    }
 816  0 newSizes.add(newExp);
 817    }
 818    catch (UnsupportedConversionException e) {
 819  0 throw new ExecutionError("array.dimension.type", node);
 820    }
 821    }
 822  12 node.setSizes(newSizes);
 823   
 824  12 if (node.getInitialization() != null) { check(node.getInitialization(), result); }
 825   
 826  12 setErasedType(node, ts.erasedClass(result));
 827  12 return setType(node, result);
 828    }
 829   
 830    /**
 831    * Visits a ArrayInitializer. JLS 10.6.
 832    * @return The type of the initialized array
 833    */
 834  12 @Override public Type visit(ArrayInitializer node) {
 835    // there's some redundancy between "expected" and "node.getElementType()"
 836    // but while "expected" is a suggestion that can lead to no errors
 837    // (and that can be turned on or off depending on preferences),
 838    // the stated element type is always required and checked
 839    // TODO: Store the *Type* as an attribute on the initializer, instead of a *TypeName*?
 840  12 TypeName elementTypeName = node.getElementType();
 841  12 if (elementTypeName == null) {
 842  0 throw new ExecutionError("array.initializer.type", node);
 843    }
 844  12 Type elementType = checkTypeName(elementTypeName);
 845  12 if (expected.isSome() && ts.isArray(expected.unwrap())) {
 846  12 checkList(node.getCells(), ts.arrayElementType(expected.unwrap()));
 847    }
 848    else {
 849  0 checkList(node.getCells());
 850    }
 851  12 List<Expression> newCells = new ArrayList<Expression>(node.getCells().size());
 852  12 for (Expression exp : node.getCells()) {
 853  37 try { newCells.add(ts.assign(elementType, exp)); }
 854    catch (UnsupportedConversionException e) {
 855  0 Type expT = getType(exp);
 856  0 TypePrinter printer = ts.typePrinter();
 857  0 setErrorStrings(exp, printer.print(expT), printer.print(elementType));
 858  0 throw new ExecutionError("assignment.types", exp);
 859    }
 860    }
 861  12 node.setCells(newCells);
 862  12 Type result = new SimpleArrayType(elementType);
 863  12 setErasedType(node, ts.erasedClass(result));
 864  12 return setType(node, result);
 865    }
 866   
 867    /**
 868    * Visits a SimpleAllocation. JLS 15.10.
 869    * @return The type of the expression
 870    */
 871  484 @Override public Type visit(SimpleAllocation node) {
 872  484 Type t = checkTypeName(node.getCreationType());
 873  483 if (!ts.isConcrete(t)) {
 874  0 setErrorStrings(node, ts.typePrinter().print(t));
 875  0 throw new ExecutionError("allocation.type", node);
 876    }
 877   
 878  483 Option<Type> dynamicOuter = ts.dynamicallyEnclosingType(t);
 879  483 if (dynamicOuter.isSome()) {
 880  0 DJClass enclosingThis = context.getThis(dynamicOuter.unwrap(), ts);
 881  0 if (enclosingThis == null) {
 882  0 TypePrinter printer = ts.typePrinter();
 883  0 setErrorStrings(node, printer.print(t), printer.print(dynamicOuter.unwrap()));
 884  0 throw new ExecutionError("inner.allocation", node);
 885    }
 886  0 else { setEnclosingThis(node, enclosingThis); }
 887    }
 888   
 889  483 Iterable<? extends Expression> args = node.getArguments();
 890  483 checkList(args);
 891  483 Iterable<Type> targs = checkTypeNameList(node.getTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 892   
 893  483 try {
 894  483 ConstructorInvocation inv = ts.lookupConstructor(t, targs, args, expected, context.accessModule());
 895  482 checkThrownExceptions(inv.thrown(), node);
 896  482 node.setArguments(CollectUtil.makeList(inv.args()));
 897  482 setConstructor(node, inv.constructor());
 898  482 return setType(node, t);
 899    }
 900    catch (InvalidTypeArgumentException e) {
 901  0 throw new ExecutionError("type.argument", node);
 902    }
 903    catch (UnmatchedLookupException e) {
 904  1 throw unmatchedFunctionError("constructor", e, node, t, "", targs, args, expected, false);
 905    }
 906    }
 907   
 908    /**
 909    * Visits an AnonymousAllocation. JLS 15.9.
 910    * @return The type of the expression
 911    */
 912  0 @Override public Type visit(AnonymousAllocation node) {
 913  0 Type t = checkTypeName(node.getCreationType());
 914  0 if (!ts.isExtendable(t) && !ts.isImplementable(t)) {
 915  0 setErrorStrings(node, ts.typePrinter().print(t));
 916  0 throw new ExecutionError("invalid.supertype", node);
 917    }
 918   
 919  0 Option<Type> dynamicOuter = ts.dynamicallyEnclosingType(t);
 920  0 if (dynamicOuter.isSome()) {
 921  0 DJClass enclosingThis = context.getThis(dynamicOuter.unwrap(), ts);
 922  0 if (enclosingThis == null) {
 923  0 TypePrinter printer = ts.typePrinter();
 924  0 setErrorStrings(node, printer.print(t), printer.print(dynamicOuter.unwrap()));
 925  0 throw new ExecutionError("inner.allocation", node);
 926    }
 927  0 else { setEnclosingThis(node, enclosingThis); }
 928    }
 929   
 930  0 Iterable<? extends Expression> args = node.getArguments();
 931  0 checkList(args);
 932  0 Iterable<Type> targs = checkTypeNameList(node.getTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 933   
 934  0 if (!(IterUtil.isEmpty(args) && IterUtil.isEmpty(targs) && ts.isImplementable(t))) {
 935    // Super constructor invocation is something besides Object()
 936  0 try {
 937  0 ConstructorInvocation inv = ts.lookupConstructor(t, targs, args, expected, context.accessModule());
 938  0 checkThrownExceptions(inv.thrown(), node);
 939  0 node.setArguments(CollectUtil.makeList(inv.args()));
 940    }
 941    catch (InvalidTypeArgumentException e) {
 942  0 throw new ExecutionError("type.argument", node);
 943    }
 944    catch (UnmatchedLookupException e) {
 945  0 throw unmatchedFunctionError("constructor", e, node, t, "", targs, args, expected, false);
 946    }
 947    }
 948   
 949  0 TreeClassLoader loader = new TreeClassLoader(context.getClassLoader(), opt);
 950  0 TreeClass c = new TreeClass(context.makeAnonymousClassName(), null, context.accessModule(), node, loader, opt);
 951  0 setDJClass(node, c);
 952  0 ClassChecker checker = new ClassChecker(c, loader, context, opt);
 953  0 checker.initializeClassSignatures(node);
 954  0 checker.checkSignatures(node);
 955  0 checker.checkBodies(node);
 956   
 957  0 setConstructor(node, IterUtil.first(c.declaredConstructors()));
 958  0 return setType(node, ts.makeClassType(c));
 959    }
 960   
 961    /**
 962    * Visits a InnerAllocation. JLS 15.9.
 963    * @return The type of the expression
 964    */
 965  0 @Override public Type visit(InnerAllocation node) {
 966  0 Type enclosing = check(node.getExpression());
 967  0 Iterable<Type> classTargs = checkTypeNameList(node.getClassTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 968   
 969  0 try {
 970  0 ClassType t = ts.lookupClass(node.getExpression(), node.getClassName(), classTargs, context.accessModule());
 971  0 if (t.ofClass().isStatic()) {
 972  0 setErrorStrings(node, node.getClassName(), ts.typePrinter().print(getType(node.getExpression())));
 973  0 throw new ExecutionError("static.inner.allocation", node);
 974    }
 975  0 if (!ts.isConcrete(t)) {
 976  0 setErrorStrings(node, ts.typePrinter().print(t));
 977  0 throw new ExecutionError("allocation.type", node);
 978    }
 979   
 980  0 Iterable<? extends Expression> args = node.getArguments();
 981  0 checkList(args);
 982  0 Iterable<Type> targs = checkTypeNameList(node.getTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 983   
 984  0 try {
 985  0 ConstructorInvocation inv = ts.lookupConstructor(t, targs, args, expected, context.accessModule());
 986  0 checkThrownExceptions(inv.thrown(), node);
 987  0 node.setArguments(CollectUtil.makeList(inv.args()));
 988  0 setConstructor(node, inv.constructor());
 989  0 return setType(node, t);
 990    }
 991    catch (InvalidTypeArgumentException e) {
 992  0 throw new ExecutionError("type.argument", node);
 993    }
 994    catch (UnmatchedLookupException e) {
 995  0 throw unmatchedFunctionError("constructor", e, node, t, "", targs, args, expected, false);
 996    }
 997    }
 998    catch (InvalidTypeArgumentException e) {
 999  0 throw new ExecutionError("type.argument", node);
 1000    }
 1001    catch (UnmatchedLookupException e) {
 1002  0 setErrorStrings(node, ts.typePrinter().print(enclosing), node.getClassName());
 1003  0 if (e.matches() > 1) { throw new ExecutionError("ambiguous.inner.class", node); }
 1004  0 else { throw new ExecutionError("no.such.inner.class", node); }
 1005    }
 1006    }
 1007   
 1008    /**
 1009    * Visits an AnonymousInnerAllocation. JLS 15.9.
 1010    * @return The type of the expression
 1011    */
 1012  0 @Override public Type visit(AnonymousInnerAllocation node) {
 1013  0 Type enclosing = check(node.getExpression());
 1014  0 Iterable<Type> classTargs = checkTypeNameList(node.getClassTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 1015   
 1016  0 try {
 1017  0 ClassType t = ts.lookupClass(node.getExpression(), node.getClassName(), classTargs, context.accessModule());
 1018  0 if (t.ofClass().isStatic()) {
 1019  0 setErrorStrings(node, node.getClassName(), ts.typePrinter().print(getType(node.getExpression())));
 1020  0 throw new ExecutionError("static.inner.allocation", node);
 1021    }
 1022  0 if (!ts.isExtendable(t)) {
 1023  0 setErrorStrings(node, ts.typePrinter().print(t));
 1024  0 throw new ExecutionError("invalid.supertype", node);
 1025    }
 1026  0 setSuperType(node, t);
 1027   
 1028  0 Iterable<? extends Expression> args = node.getArguments();
 1029  0 checkList(args);
 1030  0 Iterable<Type> targs = checkTypeNameList(node.getTypeArgs().unwrap(Collections.<TypeName>emptyList()));
 1031   
 1032  0 try {
 1033  0 ConstructorInvocation inv = ts.lookupConstructor(t, targs, args, expected, context.accessModule());
 1034  0 checkThrownExceptions(inv.thrown(), node);
 1035  0 node.setArguments(CollectUtil.makeList(inv.args()));
 1036    }
 1037    catch (InvalidTypeArgumentException e) {
 1038  0 throw new ExecutionError("type.argument", node);
 1039    }
 1040    catch (UnmatchedLookupException e) {
 1041  0 throw unmatchedFunctionError("constructor", e, node, t, "", targs, args, expected, false);
 1042    }
 1043    }
 1044    catch (InvalidTypeArgumentException e) {
 1045  0 throw new ExecutionError("type.argument", node);
 1046    }
 1047    catch (UnmatchedLookupException e) {
 1048  0 setErrorStrings(node, ts.typePrinter().print(enclosing), node.getClassName());
 1049  0 if (e.matches() > 1) { throw new ExecutionError("ambiguous.inner.class", node); }
 1050  0 else { throw new ExecutionError("no.such.inner.class", node); }
 1051    }
 1052   
 1053  0 TreeClassLoader loader = new TreeClassLoader(context.getClassLoader(), opt);
 1054  0 TreeClass c = new TreeClass(context.makeAnonymousClassName(), null, context.accessModule(), node, loader, opt);
 1055  0 setDJClass(node, c);
 1056  0 ClassChecker checker = new ClassChecker(c, loader, context, opt);
 1057  0 checker.initializeClassSignatures(node);
 1058  0 checker.checkSignatures(node);
 1059  0 checker.checkBodies(node);
 1060   
 1061  0 setConstructor(node, IterUtil.first(c.declaredConstructors()));
 1062  0 return setType(node, ts.makeClassType(c));
 1063    }
 1064   
 1065  0 @Override public Type visit(ConstructorCall node) {
 1066  0 throw new ExecutionError("constructor.call", node);
 1067    }
 1068   
 1069   
 1070    /**
 1071    * Visits an ArrayAccess. JLS 15.13.
 1072    * @return The type of the expression
 1073    */
 1074  108 @Override public Type visit(ArrayAccess node) {
 1075  108 Type arrayType = check(node.getExpression());
 1076  108 if (!ts.isArray(arrayType)) {
 1077  0 setErrorStrings(node, ts.typePrinter().print(arrayType));
 1078  0 throw new ExecutionError("array.required", node);
 1079    }
 1080  108 Type elementType = ts.arrayElementType(arrayType);
 1081   
 1082  108 check(node.getCellNumber(), TypeSystem.INT);
 1083  108 try {
 1084  108 Expression cell = ts.unaryPromote(ts.makePrimitive(node.getCellNumber()));
 1085  108 if (!(getType(cell) instanceof IntType)) {
 1086  0 throw new ExecutionError("array.index.type", node);
 1087    }
 1088  108 node.setCellNumber(cell);
 1089    }
 1090    catch (UnsupportedConversionException e) {
 1091  0 throw new ExecutionError("array.index.type", node);
 1092    }
 1093   
 1094  108 setVariableType(node, elementType);
 1095  108 return setType(node, ts.capture(elementType));
 1096    // TODO: Does there need to be a runtime check here, as in field accesses?
 1097    }
 1098   
 1099    /**
 1100    * Visits a TypeExpression ({@code Foo.class}). JLS 15.8.2.
 1101    * @return The type of the expression
 1102    */
 1103  14 @Override public Type visit(TypeExpression node) {
 1104  14 Type t = checkTypeName(node.getType());
 1105  14 setErasedType(node.getType(), ts.erasedClass(t));
 1106   
 1107  14 Type targ = t;
 1108  1 if (ts.isEqual(t, TypeSystem.VOID)) { targ = TypeSystem.VOID_CLASS; }
 1109  13 else if (!ts.isReference(t)) {
 1110  7 Expression pseudoExp = TypeUtil.makeEmptyExpression(node.getType());
 1111  7 setType(pseudoExp, t);
 1112  7 try {
 1113  7 Expression boxedPseudoExp = ts.makeReference(pseudoExp);
 1114  7 targ = getType(boxedPseudoExp);
 1115    }
 1116    catch (UnsupportedConversionException e) {
 1117  0 throw new ExecutionError("reference.type", node);
 1118    }
 1119    }
 1120  14 return setType(node, ts.reflectionClassOf(targ));
 1121    }
 1122   
 1123    /**
 1124    * Visits a NotExpression ({@code !}). JLS 15.15.6.
 1125    * @return The type of the expression
 1126    */
 1127  199 @Override public Type visit(NotExpression node) {
 1128  199 check(node.getExpression(), TypeSystem.BOOLEAN);
 1129  199 try {
 1130  199 Expression exp = ts.makePrimitive(node.getExpression());
 1131  199 if (!(getType(exp) instanceof BooleanType)) {
 1132  0 throw new ExecutionError("not.expression.type", node);
 1133    }
 1134  199 node.setExpression(exp);
 1135  199 return setType(node, getType(exp));
 1136    }
 1137    catch (UnsupportedConversionException e) {
 1138  0 throw new ExecutionError("not.expression.type", node);
 1139    }
 1140    }
 1141   
 1142    /**
 1143    * Visits a ComplementExpression ({@code ~}). JLS 15.15.5.
 1144    * @return The type of the expression
 1145    */
 1146  0 @Override public Type visit(ComplementExpression node) {
 1147  0 check(node.getExpression());
 1148  0 try {
 1149  0 Expression exp = ts.unaryPromote(ts.makePrimitive(node.getExpression()));
 1150  0 if (!(getType(exp) instanceof IntegralType)) {
 1151  0 throw new ExecutionError("complement.expression.type", node);
 1152    }
 1153  0 node.setExpression(exp);
 1154  0 return setType(node, getType(exp));
 1155    }
 1156    catch (UnsupportedConversionException e) {
 1157  0 throw new ExecutionError("complement.expression.type", node);
 1158    }
 1159    }
 1160   
 1161  0 @Override public Type visit(PlusExpression node) { return handleNumericUnaryExpression(node); }
 1162   
 1163  4 @Override public Type visit(MinusExpression node) { return handleNumericUnaryExpression(node); }
 1164   
 1165    /**
 1166    * Handles a numeric unary operation ({@code +, -}). JLS 15.15.3, 15.15.4.
 1167    * @return The type of the expression
 1168    */
 1169  4 private Type handleNumericUnaryExpression(UnaryExpression node) {
 1170  4 check(node.getExpression());
 1171  4 try {
 1172  4 Expression exp = ts.unaryPromote(ts.makePrimitive(node.getExpression()));
 1173  4 node.setExpression(exp);
 1174  4 Type result = setType(node, getType(exp));
 1175  4 evaluateConstantExpression(node);
 1176  4 return result;
 1177    }
 1178    catch (UnsupportedConversionException e) {
 1179  0 throw new ExecutionError("numeric.expression.type", node);
 1180    }
 1181    }
 1182   
 1183    /**
 1184    * Visits an AddExpression. JLS 15.18.
 1185    * @return The type of the expression
 1186    */
 1187  126 @Override public Type visit(AddExpression node) {
 1188  126 Type leftT = check(node.getLeftExpression());
 1189  126 Type rightT = check(node.getRightExpression());
 1190  126 if (ts.isSubtype(leftT, TypeSystem.STRING) || ts.isSubtype(rightT, TypeSystem.STRING)) {
 1191  60 try {
 1192  60 Expression left = ts.makeReference(node.getLeftExpression());
 1193  60 Expression right = ts.makeReference(node.getRightExpression());
 1194  60 node.setLeftExpression(left);
 1195  60 node.setRightExpression(right);
 1196  60 setOperation(node, ExpressionEvaluator.CONCATENATE);
 1197  60 setType(node, TypeSystem.STRING);
 1198  60 evaluateConstantExpression(node);
 1199  60 return TypeSystem.STRING;
 1200    }
 1201    catch (UnsupportedConversionException e) {
 1202  0 throw new ExecutionError("addition.type", node);
 1203    }
 1204    }
 1205    else {
 1206  66 try {
 1207  66 Expression left = ts.makePrimitive(node.getLeftExpression());
 1208  66 Expression right = ts.makePrimitive(node.getRightExpression());
 1209  66 Pair<Expression, Expression> promoted = ts.binaryPromote(left, right);
 1210  66 node.setLeftExpression(promoted.first());
 1211  66 node.setRightExpression(promoted.second());
 1212  66 setOperation(node, ExpressionEvaluator.ADD);
 1213  66 Type result = setType(node, getType(promoted.first()));
 1214  66 evaluateConstantExpression(node);
 1215  66 return result;
 1216    }
 1217    catch (UnsupportedConversionException e) {
 1218  0 throw new ExecutionError("addition.type", node);
 1219    }
 1220    }
 1221    }
 1222   
 1223    /**
 1224    * Visits an AddAssignExpression. JLS 15.26.2.
 1225    * @return The type of the expression
 1226    */
 1227  0 @Override public Type visit(AddAssignExpression node) {
 1228  0 Type leftT = check(node.getLeftExpression());
 1229  0 Type rightT = check(node.getRightExpression());
 1230  0 if (ts.isEqual(leftT, TypeSystem.STRING)) {
 1231  0 try {
 1232  0 Expression right = ts.makeReference(node.getRightExpression());
 1233  0 setLeftExpression(node, node.getLeftExpression()); // not to be confused with node.setLeftExpression(...)
 1234  0 node.setRightExpression(right);
 1235  0 setOperation(node, ExpressionEvaluator.CONCATENATE);
 1236    }
 1237    catch (UnsupportedConversionException e) {
 1238  0 throw new ExecutionError("addition.type", node);
 1239    }
 1240    }
 1241  0 else if (ts.isSubtype(leftT, TypeSystem.STRING) || ts.isSubtype(rightT, TypeSystem.STRING)) {
 1242  0 throw new ExecutionError("addition.type", node);
 1243    }
 1244    else {
 1245  0 try {
 1246  0 Expression left = ts.makePrimitive(node.getLeftExpression());
 1247  0 Expression right = ts.makePrimitive(node.getRightExpression());
 1248  0 Pair<Expression, Expression> promoted = ts.binaryPromote(left, right);
 1249  0 setLeftExpression(node, promoted.first()); // not to be confused with node.setLeftExpression(...)
 1250  0 node.setRightExpression(promoted.second());
 1251  0 setOperation(node, ExpressionEvaluator.ADD);
 1252    }
 1253    catch (UnsupportedConversionException e) {
 1254  0 throw new ExecutionError("addition.type", node);
 1255    }
 1256    }
 1257   
 1258  0 if (!hasVariableType(node.getLeftExpression())) {
 1259  0 throw new ExecutionError("addition.type", node);
 1260    }
 1261   
 1262  0 return setType(node, leftT);
 1263    }
 1264   
 1265  3 @Override public Type visit(SubtractExpression node) { return handleNumericExpression(node); }
 1266   
 1267  0 @Override public Type visit(MultiplyExpression node) { return handleNumericExpression(node); }
 1268   
 1269  4 @Override public Type visit(DivideExpression node) { return handleNumericExpression(node); }
 1270   
 1271  0 @Override public Type visit(RemainderExpression node) { return handleNumericExpression(node); }
 1272   
 1273    /**
 1274    * Handles a numeric binary expression ({@code -, *, /, %}). JLS 15.17, 15.18.
 1275    * @return The type of the expression
 1276    */
 1277  7 private Type handleNumericExpression(BinaryExpression node) {
 1278  7 check(node.getLeftExpression());
 1279  7 check(node.getRightExpression());
 1280  7 try {
 1281  7 Expression left = ts.makePrimitive(node.getLeftExpression());
 1282  7 Expression right = ts.makePrimitive(node.getRightExpression());
 1283  7 Pair<Expression, Expression> promoted = ts.binaryPromote(left, right);
 1284  7 node.setLeftExpression(promoted.first());
 1285  7 node.setRightExpression(promoted.second());
 1286  7 Type result = setType(node, getType(promoted.first()));
 1287  7 evaluateConstantExpression(node);
 1288  7 return result;
 1289    }
 1290    catch (UnsupportedConversionException e) {
 1291  0 throw new ExecutionError("numeric.expression.type", node);
 1292    }
 1293    }
 1294   
 1295  0 @Override public Type visit(SubtractAssignExpression node) { return handleNumericAssignmentExpression(node); }
 1296   
 1297  0 @Override public Type visit(MultiplyAssignExpression node) { return handleNumericAssignmentExpression(node); }
 1298   
 1299  0 @Override public Type visit(DivideAssignExpression node) { return handleNumericAssignmentExpression(node); }
 1300   
 1301  0 @Override public Type visit(RemainderAssignExpression node) { return handleNumericAssignmentExpression(node); }
 1302   
 1303    /**
 1304    * Handles a numeric assignment expression ({@code -=, *=, /=, %=}). JLS 15.26.2.
 1305    * @return The type of the expression
 1306    */
 1307  0 private Type handleNumericAssignmentExpression(BinaryExpression node) {
 1308  0 Type result = check(node.getLeftExpression());
 1309  0 check(node.getRightExpression());
 1310  0 try {
 1311  0 Expression left = ts.makePrimitive(node.getLeftExpression());
 1312  0 Expression right = ts.makePrimitive(node.getRightExpression());
 1313  0 Pair<Expression, Expression> promoted = ts.binaryPromote(left, right);
 1314   
 1315  0 if (!hasVariableType(node.getLeftExpression())) {
 1316  0 throw new ExecutionError("numeric.expression.type", node);
 1317    }
 1318  0 setLeftExpression(node, promoted.first()); // not to be confused with node.setLeftExpression(...)
 1319  0 node.setRightExpression(promoted.second());
 1320  0 return setType(node, result);
 1321    }
 1322    catch (UnsupportedConversionException e) {
 1323  0 throw new ExecutionError("numeric.expression.type", node);
 1324    }
 1325    }
 1326   
 1327  50 @Override public Type visit(EqualExpression node) {
 1328  50 return handleEqualityExpression(node, ExpressionEvaluator.OBJECT_EQUAL,
 1329    ExpressionEvaluator.PRIMITIVE_EQUAL);
 1330    }
 1331   
 1332  4 @Override public Type visit(NotEqualExpression node) {
 1333  4 return handleEqualityExpression(node, ExpressionEvaluator.OBJECT_NOT_EQUAL,
 1334    ExpressionEvaluator.PRIMITIVE_NOT_EQUAL);
 1335    }
 1336   
 1337    /**
 1338    * Handles an equality expression ({@code ==, !=}). JLS 15.21.
 1339    * @return The type of the expression
 1340    */
 1341  54 private Type handleEqualityExpression(BinaryExpression node, Lambda2<Object, Object, Object> objectCase,
 1342    Lambda2<Object, Object, Object> primitiveCase) {
 1343  54 Type leftT = check(node.getLeftExpression());
 1344  54 Type rightT = check(node.getRightExpression());
 1345  54 if (ts.isReference(leftT) && ts.isReference(rightT)) {
 1346  0 if (ts.isDisjoint(leftT, rightT)) {
 1347  0 TypePrinter printer = ts.typePrinter();
 1348  0 setErrorStrings(node, printer.print(leftT), printer.print(rightT));
 1349  0 throw new ExecutionError("compare.type", node);
 1350    }
 1351  0 setOperation(node, objectCase);
 1352    }
 1353    else {
 1354  54 try {
 1355  54 Expression left = ts.makePrimitive(node.getLeftExpression());
 1356  54 Expression right = ts.makePrimitive(node.getRightExpression());
 1357   
 1358  54 if (getType(left) instanceof BooleanType && getType(right) instanceof BooleanType) {
 1359  0 node.setLeftExpression(left);
 1360  0 node.setRightExpression(right);
 1361    }
 1362  54 else if (getType(left) instanceof NumericType && getType(right) instanceof NumericType) {
 1363  54 Pair<Expression, Expression> promoted = ts.binaryPromote(left, right);
 1364  54 left = promoted.first();
 1365  54 right = promoted.second();
 1366  54 node.setLeftExpression(promoted.first());
 1367  54 node.setRightExpression(promoted.second());
 1368    }
 1369    else {
 1370  0 TypePrinter printer = ts.typePrinter();
 1371  0 setErrorStrings(node, printer.print(leftT), printer.print(rightT));
 1372  0 throw new ExecutionError("compare.type", node);
 1373    }
 1374  54 setOperation(node, primitiveCase);
 1375    }
 1376    catch (UnsupportedConversionException e) {
 1377  0 TypePrinter printer = ts.typePrinter();
 1378  0 setErrorStrings(node, printer.print(leftT), printer.print(rightT));
 1379  0 throw new ExecutionError("compare.type", node);
 1380    }
 1381    }
 1382  54 setType(node, TypeSystem.BOOLEAN);
 1383  54 evaluateConstantExpression(node);
 1384  54 return TypeSystem.BOOLEAN;
 1385    }
 1386   
 1387  123 @Override public Type visit(LessExpression node) { return handleRelationalExpression(node); }
 1388   
 1389  0 @Override public Type visit(LessOrEqualExpression node) { return handleRelationalExpression(node); }
 1390   
 1391  12 @Override public Type visit(GreaterExpression node) { return handleRelationalExpression(node); }
 1392   
 1393  0 @Override public Type visit(GreaterOrEqualExpression node) { return handleRelationalExpression(node); }
 1394   
 1395    /**
 1396    * Handles a relational expression ({@code <, <=, >, >=}). JLS 15.20.1.
 1397    * @return The type of the expression
 1398    */
 1399  135 private Type handleRelationalExpression(BinaryExpression node) {
 1400  135 check(node.getLeftExpression());
 1401  135 check(node.getRightExpression());
 1402  135 try {
 1403  135 Expression left = ts.makePrimitive(node.getLeftExpression());
 1404  135 Expression right = ts.makePrimitive(node.getRightExpression());
 1405  135 Pair<Expression, Expression> promoted = ts.binaryPromote(left, right);
 1406  135 node.setLeftExpression(promoted.first());
 1407  135 node.setRightExpression(promoted.second());
 1408  135 setType(node, TypeSystem.BOOLEAN);
 1409  135 evaluateConstantExpression(node);
 1410  135 return TypeSystem.BOOLEAN;
 1411    }
 1412    catch (UnsupportedConversionException e) {
 1413  0 TypePrinter printer = ts.typePrinter();
 1414  0 setErrorStrings(node, printer.print(getType(node.getLeftExpression())),
 1415    printer.print(getType(node.getRightExpression())));
 1416  0 throw new ExecutionError("compare.type", node);
 1417    }
 1418    }
 1419   
 1420  0 @Override public Type visit(BitAndExpression node) { return handleBitwiseExpression(node); }
 1421   
 1422  0 @Override public Type visit(BitOrExpression node) { return handleBitwiseExpression(node); }
 1423   
 1424  0 @Override public Type visit(ExclusiveOrExpression node) { return handleBitwiseExpression(node); }
 1425   
 1426    /**
 1427    * Handles a bitwise expression ({@code |, &, ^}). JLS 15.22.
 1428    * @return The type of the expression
 1429    */
 1430  0 private Type handleBitwiseExpression(BinaryExpression node) {
 1431  0 check(node.getLeftExpression());
 1432  0 check(node.getRightExpression());
 1433  0 try {
 1434  0 Expression left = ts.makePrimitive(node.getLeftExpression());
 1435  0 Expression right = ts.makePrimitive(node.getRightExpression());
 1436   
 1437  0 if (getType(left) instanceof BooleanType && getType(right) instanceof BooleanType) {
 1438    // Do nothing
 1439    }
 1440  0 else if (getType(left) instanceof IntegralType && getType(right) instanceof IntegralType) {
 1441  0 Pair<Expression, Expression> promoted = ts.binaryPromote(left, right);
 1442  0 left = promoted.first();
 1443  0 right = promoted.second();
 1444    }
 1445    else {
 1446  0 throw new ExecutionError("bitwise.expression.type", node);
 1447    }
 1448  0 node.setLeftExpression(left);
 1449  0 node.setRightExpression(right);
 1450  0 Type result = setType(node, getType(left));
 1451  0 evaluateConstantExpression(node);
 1452  0 return result;
 1453    }
 1454    catch (UnsupportedConversionException e) {
 1455  0 throw new ExecutionError("bitwise.expression.type", node);
 1456    }
 1457    }
 1458   
 1459  0 @Override public Type visit(BitAndAssignExpression node) { return handleBitwiseAssignmentExpression(node); }
 1460   
 1461  0 @Override public Type visit(BitOrAssignExpression node) { return handleBitwiseAssignmentExpression(node); }
 1462   
 1463  0 @Override public Type visit(ExclusiveOrAssignExpression node) { return handleBitwiseAssignmentExpression(node); }
 1464   
 1465    /**
 1466    * Handles a bitwise assignment expression ({@code &=, |=, ^=}). JLS 15.26.2.
 1467    * @return The type of the expression
 1468    */
 1469  0 private Type handleBitwiseAssignmentExpression(BinaryExpression node) {
 1470  0 Type result = check(node.getLeftExpression());
 1471  0 check(node.getRightExpression());
 1472  0 try {
 1473  0 Expression left = ts.makePrimitive(node.getLeftExpression());
 1474  0 Expression right = ts.makePrimitive(node.getRightExpression());
 1475  0 if (getType(left) instanceof BooleanType && getType(right) instanceof BooleanType) {
 1476    // Do nothing
 1477    }
 1478  0 else if (getType(left) instanceof IntegralType && getType(right) instanceof IntegralType) {
 1479  0 Pair<Expression, Expression> promoted = ts.binaryPromote(left, right);
 1480  0 left = promoted.first();
 1481  0 right = promoted.second();
 1482    }
 1483    else {
 1484  0 throw new ExecutionError("bitwise.expression.type", node);
 1485    }
 1486   
 1487  0 if (!hasVariableType(node.getLeftExpression())) {
 1488  0 throw new ExecutionError("bitwise.expression.type", node);
 1489    }
 1490  0 setLeftExpression(node, left); // not to be confused with node.setLeftExpression(...)
 1491  0 node.setRightExpression(right);
 1492  0 return setType(node, result);
 1493    }
 1494    catch (UnsupportedConversionException e) {
 1495  0 throw new ExecutionError("bitwise.expression.type", node);
 1496    }
 1497    }
 1498   
 1499  0 @Override public Type visit(ShiftLeftExpression node) { return handleShiftExpression(node); }
 1500   
 1501  0 @Override public Type visit(ShiftRightExpression node) { return handleShiftExpression(node); }
 1502   
 1503  0 @Override public Type visit(UnsignedShiftRightExpression node) { return handleShiftExpression(node); }
 1504   
 1505    /**
 1506    * Handles a shift expression ({@code <<, >>, >>>}). JLS 15.19.
 1507    * @return The type of the expression
 1508    */
 1509  0 private Type handleShiftExpression(BinaryExpression node) {
 1510  0 check(node.getLeftExpression());
 1511  0 check(node.getRightExpression());
 1512  0 try {
 1513  0 Expression left = ts.unaryPromote(ts.makePrimitive(node.getLeftExpression()));
 1514  0 Expression right = ts.unaryPromote(ts.makePrimitive(node.getRightExpression()));
 1515  0 node.setLeftExpression(left);
 1516  0 node.setRightExpression(right);
 1517   
 1518  0 if (!(getType(left) instanceof IntegralType) || !(getType(right) instanceof IntegralType)) {
 1519  0 throw new ExecutionError("shift.expression.type", node);
 1520    }
 1521   
 1522  0 Type result = setType(node, getType(left));
 1523  0 evaluateConstantExpression(node);
 1524  0 return result;
 1525    }
 1526    catch (UnsupportedConversionException e) {
 1527  0 throw new ExecutionError("shift.expression.type", node);
 1528    }
 1529    }
 1530   
 1531  0 @Override public Type visit(ShiftLeftAssignExpression node) { return handleShiftAssignmentExpression(node); }
 1532   
 1533  0 @Override public Type visit(ShiftRightAssignExpression node) { return handleShiftAssignmentExpression(node); }
 1534   
 1535  0 @Override public Type visit(UnsignedShiftRightAssignExpression node) { return handleShiftAssignmentExpression(node); }
 1536   
 1537    /**
 1538    * Handles a shift assignment expression (<<=, >>=, >>>=). JLS 15.26.2.
 1539    * @return The type of the expression
 1540    */
 1541  0 private Type handleShiftAssignmentExpression(BinaryExpression node) {
 1542  0 Type result = check(node.getLeftExpression());
 1543  0 check(node.getRightExpression());
 1544  0 try {
 1545  0 Expression left = ts.unaryPromote(ts.makePrimitive(node.getLeftExpression()));
 1546  0 Expression right = ts.unaryPromote(ts.makePrimitive(node.getRightExpression()));
 1547   
 1548  0 if (!(getType(left) instanceof IntegralType) || !(getType(right) instanceof IntegralType) ||
 1549    !hasVariableType(node.getLeftExpression())) {
 1550  0 throw new ExecutionError("shift.expression.type", node);
 1551    }
 1552   
 1553  0 setLeftExpression(node, left); // not to be confused with node.setLeftExpression(...)
 1554  0 node.setRightExpression(right);
 1555  0 return setType(node, result);
 1556    }
 1557    catch (UnsupportedConversionException e) {
 1558  0 throw new ExecutionError("shift.expression.type", node);
 1559    }
 1560    }
 1561   
 1562  0 @Override public Type visit(AndExpression node) { return handleBooleanExpression(node); }
 1563   
 1564  0 @Override public Type visit(OrExpression node) { return handleBooleanExpression(node); }
 1565   
 1566    /**
 1567    * Handles a boolean expression ({@code &&, ||}). JLS 15.23, 15.24.
 1568    * @return The type of the expression
 1569    */
 1570  0 private Type handleBooleanExpression(BinaryExpression node) {
 1571  0 check(node.getLeftExpression(), TypeSystem.BOOLEAN);
 1572  0 check(node.getRightExpression(), TypeSystem.BOOLEAN);
 1573  0 try {
 1574  0 Expression left = ts.makePrimitive(node.getLeftExpression());
 1575  0 Expression right = ts.makePrimitive(node.getRightExpression());
 1576  0 if (!(getType(left) instanceof BooleanType) || !(getType(right) instanceof BooleanType)) {
 1577  0 throw new ExecutionError("boolean.expression.type", node);
 1578    }
 1579  0 node.setLeftExpression(left);
 1580  0 node.setRightExpression(right);
 1581  0 setType(node, TypeSystem.BOOLEAN);
 1582  0 evaluateConstantExpression(node);
 1583  0 return TypeSystem.BOOLEAN;
 1584    }
 1585    catch (UnsupportedConversionException e) {
 1586  0 throw new ExecutionError("boolean.expression.type", node);
 1587    }
 1588    }
 1589   
 1590  322 private void evaluateConstantExpression(BinaryExpression node) {
 1591  322 if (hasValue(node.getLeftExpression()) && hasValue(node.getRightExpression())) {
 1592  20 try {
 1593  20 Object val = new ExpressionEvaluator(RuntimeBindings.EMPTY, opt).value(node);
 1594  20 setValue(node, val);
 1595    }
 1596    catch (WrappedException e) { /* failed to evaluate -- just ignore */ }
 1597    }
 1598    }
 1599   
 1600  4 private void evaluateConstantExpression(UnaryExpression node) {
 1601  4 if (hasValue(node.getExpression())) {
 1602  4 try {
 1603  4 Object val = new ExpressionEvaluator(RuntimeBindings.EMPTY, opt).value(node);
 1604  4 setValue(node, val);
 1605    }
 1606    catch (WrappedException e) { /* failed to evaluate -- just ignore */ }
 1607    }
 1608    }
 1609   
 1610    /**
 1611    * Visits a InstanceOfExpression. JLS 15.20.2.
 1612    * @return The type of the expression
 1613    */
 1614  0 @Override public Type visit(InstanceOfExpression node) {
 1615  0 Type expT = check(node.getExpression());
 1616  0 Type targetT = checkTypeName(node.getReferenceType());
 1617  0 if (!ts.isReference(expT) || !ts.isReference(targetT) || ts.isDisjoint(targetT, expT)) {
 1618  0 throw new ExecutionError("instanceof.type", node);
 1619    }
 1620  0 if (!ts.isReifiable(targetT)) {
 1621  0 throw new ExecutionError("reifiable.type", node);
 1622    }
 1623  0 setErasedType(node.getReferenceType(), ts.erasedClass(targetT));
 1624  0 return setType(node, TypeSystem.BOOLEAN);
 1625    }
 1626   
 1627    /**
 1628    * Visits a ConditionalExpression. JLS 15.25.
 1629    * @return The type of the expression
 1630    */
 1631  0 @Override public Type visit(ConditionalExpression node) {
 1632  0 check(node.getConditionExpression(), TypeSystem.BOOLEAN);
 1633  0 check(node.getIfTrueExpression(), expected);
 1634  0 check(node.getIfFalseExpression(), expected);
 1635   
 1636  0 try {
 1637  0 Expression cond = ts.makePrimitive(node.getConditionExpression());
 1638  0 if (!(getType(cond) instanceof BooleanType)) {
 1639  0 throw new ExecutionError("condition.type", node);
 1640    }
 1641  0 node.setConditionExpression(cond);
 1642    }
 1643    catch (UnsupportedConversionException e) {
 1644  0 throw new ExecutionError("condition.type", node);
 1645    }
 1646   
 1647  0 try {
 1648  0 Pair<Expression, Expression> joined = ts.mergeConditional(node.getIfTrueExpression(),
 1649    node.getIfFalseExpression());
 1650  0 node.setIfTrueExpression(joined.first());
 1651  0 node.setIfFalseExpression(joined.second());
 1652  0 return setType(node, ts.capture(getType(joined.first())));
 1653    }
 1654    catch (UnsupportedConversionException e) {
 1655  0 throw new ExecutionError("conditional.type", node);
 1656    }
 1657    }
 1658   
 1659    /**
 1660    * Visits a SimpleAssignExpression. JLS 15.26.
 1661    * @return The type of the expression.
 1662    */
 1663  235 @Override public Type visit(SimpleAssignExpression node) {
 1664  235 Expression left = node.getLeftExpression();
 1665  235 Type result = check(left);
 1666   
 1667  235 if (!hasVariableType(left)) {
 1668  0 throw new ExecutionError("left.expression", node);
 1669    }
 1670  235 if (hasVariable(left) && getVariable(left).isFinal()) {
 1671  0 setErrorStrings(node, getVariable(left).declaredName());
 1672  0 throw new ExecutionError("cannot.modify", node);
 1673    }
 1674  235 if (hasField(left) && getField(left).isFinal()) {
 1675  0 DJClass initializing = context.initializingClass();
 1676  0 if (initializing == null || !initializing.equals(getField(left).declaringClass())) {
 1677  0 setErrorStrings(node, getField(left).declaredName());
 1678  0 throw new ExecutionError("cannot.modify", node);
 1679    }
 1680    }
 1681  235 Type target = getVariableType(left);
 1682  235 Type rightT = check(node.getRightExpression(), target);
 1683  235 try {
 1684  235 Expression newRight = ts.assign(target, node.getRightExpression());
 1685  227 node.setRightExpression(newRight);
 1686  227 return setType(node, result);
 1687    }
 1688    catch (UnsupportedConversionException e) {
 1689  8 TypePrinter printer = ts.typePrinter();
 1690  8 setErrorStrings(node, printer.print(rightT), printer.print(target));
 1691  8 throw new ExecutionError("assignment.types", node);
 1692    }
 1693    }
 1694   
 1695  122 @Override public Type visit(PostIncrement node) { return handleIncrementExpression(node); }
 1696   
 1697  2 @Override public Type visit(PreIncrement node) { return handleIncrementExpression(node); }
 1698   
 1699  2 @Override public Type visit(PostDecrement node) { return handleIncrementExpression(node); }
 1700   
 1701  2 @Override public Type visit(PreDecrement node) { return handleIncrementExpression(node); }
 1702   
 1703    /**
 1704    * Handles an increment expression ({@code ++, --}). JLS 15.14, 15.15.1, 15.15.2.
 1705    * @return The type of the expression
 1706    */
 1707  128 private Type handleIncrementExpression(UnaryExpression node) {
 1708  128 Type result = check(node.getExpression());
 1709  128 try {
 1710  128 Expression exp = ts.makePrimitive(node.getExpression());
 1711   
 1712  128 if (!(getType(exp) instanceof NumericType) || !hasVariableType(node.getExpression())) {
 1713  0 throw new ExecutionError("increment.type", node);
 1714    }
 1715   
 1716  128 setLeftExpression(node, exp);
 1717  128 return setType(node, result);
 1718    }
 1719    catch (UnsupportedConversionException e) {
 1720  0 throw new ExecutionError("increment.type", node);
 1721    }
 1722    }
 1723   
 1724    /**
 1725    * Visits a CastExpression. JLS 15.16.
 1726    * @return The type of the expression
 1727    */
 1728  14 @Override public Type visit(CastExpression node) {
 1729  14 Type t = checkTypeName(node.getTargetType());
 1730  14 Type fromT = check(node.getExpression());
 1731  14 try {
 1732  14 Expression exp = ts.cast(t, node.getExpression());
 1733  14 node.setExpression(exp);
 1734  14 return setType(node, ts.capture(t));
 1735    }
 1736    catch (UnsupportedConversionException e) {
 1737  0 TypePrinter printer = ts.typePrinter();
 1738  0 setErrorStrings(node, printer.print(fromT), printer.print(t));
 1739  0 throw new ExecutionError("cast.types", node);
 1740    }
 1741    }
 1742   
 1743    }
 1744   
 1745    }