langtools/test/tools/javac/types/TypeHarness.java
changeset 7640 5d199da591db
child 8037 b3f278fe95d6
equal deleted inserted replaced
7639:4e42f74e986f 7640:5d199da591db
       
     1 /*
       
     2  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import com.sun.tools.javac.code.BoundKind;
       
    25 import com.sun.tools.javac.code.Flags;
       
    26 import com.sun.tools.javac.util.Context;
       
    27 import com.sun.tools.javac.code.Types;
       
    28 import com.sun.tools.javac.code.Symtab;
       
    29 import com.sun.tools.javac.code.Type;
       
    30 import com.sun.tools.javac.code.Type.*;
       
    31 import com.sun.tools.javac.code.Symbol.*;
       
    32 import com.sun.tools.javac.util.List;
       
    33 import com.sun.tools.javac.util.ListBuffer;
       
    34 import com.sun.tools.javac.util.Name;
       
    35 import com.sun.tools.javac.util.Names;
       
    36 import com.sun.tools.javac.file.JavacFileManager;
       
    37 
       
    38 /**
       
    39  * Test harness whose goal is to simplify the task of writing type-system
       
    40  * regression test. It provides functionalities to build custom types as well
       
    41  * as to access the underlying javac's symbol table in order to retrieve
       
    42  * predefined types. Among the features supported by the harness are: type
       
    43  * substitution, type containment, subtyping, cast-conversion, assigment
       
    44  * conversion.
       
    45  *
       
    46  * This class is meant to be a common super class for all concrete type test
       
    47  * classes. A subclass can access the type-factory and the test methods so as
       
    48  * to write compact tests. An example is reported below:
       
    49  *
       
    50  * <pre>
       
    51  * Type X = fac.TypeVariable();
       
    52  * Type Y = fac.TypeVariable();
       
    53  * Type A_X_Y = fac.Class(0, X, Y);
       
    54  * Type A_Obj_Obj = fac.Class(0,
       
    55  *           predef.objectType,
       
    56  *           predef.objectType);
       
    57  * checkSameType(A_Obj_Obj, subst(A_X_Y,
       
    58  *           Mapping(X, predef.objectType),
       
    59  *           Mapping(Y, predef.objectType)));
       
    60  * </pre>
       
    61  *
       
    62  * The above code is used to create two class types, namely {@code A<X,Y>} and
       
    63  * {@code A<Object,Object>} where both {@code X} and {@code Y} are type-variables.
       
    64  * The code then verifies that {@code [X:=Object,Y:=Object]A<X,Y> == A<Object,Object>}.
       
    65  *
       
    66  * @author mcimadamore
       
    67  */
       
    68 public class TypeHarness {
       
    69 
       
    70     protected Types types;
       
    71     protected Symtab predef;
       
    72     protected Names names;
       
    73     protected Factory fac;
       
    74 
       
    75     protected TypeHarness() {
       
    76         Context ctx = new Context();
       
    77         JavacFileManager.preRegister(ctx);
       
    78         types = Types.instance(ctx);
       
    79         predef = Symtab.instance(ctx);
       
    80         names = Names.instance(ctx);
       
    81         fac = new Factory();
       
    82     }
       
    83 
       
    84     // <editor-fold defaultstate="collapsed" desc="type assertions">
       
    85 
       
    86     /** assert that 's' is a subtype of 't' */
       
    87     public void assertSubtype(Type s, Type t) {
       
    88         assertSubtype(s, t, true);
       
    89     }
       
    90 
       
    91     /** assert that 's' is/is not a subtype of 't' */
       
    92     public void assertSubtype(Type s, Type t, boolean expected) {
       
    93         if (types.isSubtype(s, t) != expected) {
       
    94             String msg = expected ?
       
    95                 " is not a subtype of " :
       
    96                 " is a subtype of ";
       
    97             error(s + msg + t);
       
    98         }
       
    99     }
       
   100 
       
   101     /** assert that 's' is the same type as 't' */
       
   102     public void assertSameType(Type s, Type t) {
       
   103         assertSameType(s, t, true);
       
   104     }
       
   105 
       
   106     /** assert that 's' is/is not the same type as 't' */
       
   107     public void assertSameType(Type s, Type t, boolean expected) {
       
   108         if (types.isSameType(s, t) != expected) {
       
   109             String msg = expected ?
       
   110                 " is not the same type as " :
       
   111                 " is the same type as ";
       
   112             error(s + msg + t);
       
   113         }
       
   114     }
       
   115 
       
   116     /** assert that 's' is castable to 't' */
       
   117     public void assertCastable(Type s, Type t) {
       
   118         assertCastable(s, t, true);
       
   119     }
       
   120 
       
   121     /** assert that 's' is/is not castable to 't' */
       
   122     public void assertCastable(Type s, Type t, boolean expected) {
       
   123         if (types.isCastable(s, t) != expected) {
       
   124             String msg = expected ?
       
   125                 " is not castable to " :
       
   126                 " is castable to ";
       
   127             error(s + msg + t);
       
   128         }
       
   129     }
       
   130 
       
   131     /** assert that 's' is convertible (method invocation conversion) to 't' */
       
   132     public void assertConvertible(Type s, Type t) {
       
   133         assertCastable(s, t, true);
       
   134     }
       
   135 
       
   136     /** assert that 's' is/is not convertible (method invocation conversion) to 't' */
       
   137     public void assertConvertible(Type s, Type t, boolean expected) {
       
   138         if (types.isConvertible(s, t) != expected) {
       
   139             String msg = expected ?
       
   140                 " is not convertible to " :
       
   141                 " is convertible to ";
       
   142             error(s + msg + t);
       
   143         }
       
   144     }
       
   145 
       
   146     /** assert that 's' is assignable to 't' */
       
   147     public void assertAssignable(Type s, Type t) {
       
   148         assertCastable(s, t, true);
       
   149     }
       
   150 
       
   151     /** assert that 's' is/is not assignable to 't' */
       
   152     public void assertAssignable(Type s, Type t, boolean expected) {
       
   153         if (types.isAssignable(s, t) != expected) {
       
   154             String msg = expected ?
       
   155                 " is not assignable to " :
       
   156                 " is assignable to ";
       
   157             error(s + msg + t);
       
   158         }
       
   159     }
       
   160     // </editor-fold>
       
   161 
       
   162     private void error(String msg) {
       
   163         throw new AssertionError("Unexpected result: " + msg);
       
   164     }
       
   165 
       
   166     // <editor-fold defaultstate="collapsed" desc="type functions">
       
   167 
       
   168     /** compute the erasure of a type 't' */
       
   169     public Type erasure(Type t) {
       
   170         return types.erasure(t);
       
   171     }
       
   172 
       
   173     /** compute the capture of a type 't' */
       
   174     public Type capture(Type t) {
       
   175         return types.capture(t);
       
   176     }
       
   177 
       
   178     /** compute the boxed type associated with 't' */
       
   179     public Type box(Type t) {
       
   180         if (!t.isPrimitive()) {
       
   181             throw new AssertionError("Cannot box non-primitive type: " + t);
       
   182         }
       
   183         return types.boxedClass(t).type;
       
   184     }
       
   185 
       
   186     /** compute the unboxed type associated with 't' */
       
   187     public Type unbox(Type t) {
       
   188         Type u = types.unboxedType(t);
       
   189         if (t == null) {
       
   190             throw new AssertionError("Cannot unbox reference type: " + t);
       
   191         } else {
       
   192             return u;
       
   193         }
       
   194     }
       
   195 
       
   196     /** compute a type substitution on 't' given a list of type mappings */
       
   197     public Type subst(Type t, Mapping... maps) {
       
   198         ListBuffer<Type> from = ListBuffer.lb();
       
   199         ListBuffer<Type> to = ListBuffer.lb();
       
   200         for (Mapping tm : maps) {
       
   201             from.append(tm.from);
       
   202             to.append(tm.to);
       
   203         }
       
   204         return types.subst(t, from.toList(), to.toList());
       
   205     }
       
   206 
       
   207     /** create a fresh type mapping from a type to another */
       
   208     public Mapping Mapping(Type from, Type to) {
       
   209         return new Mapping(from, to);
       
   210     }
       
   211 
       
   212     public static class Mapping {
       
   213         Type from;
       
   214         Type to;
       
   215         private Mapping(Type from, Type to) {
       
   216             this.from = from;
       
   217             this.to = to;
       
   218         }
       
   219     }
       
   220     // </editor-fold>
       
   221 
       
   222     // <editor-fold defaultstate="collapsed" desc="type factory">
       
   223 
       
   224     /**
       
   225      * This class is used to create Java types in a simple way. All main
       
   226      * kinds of type are supported: primitive, reference, non-denotable. The
       
   227      * factory also supports creation of constant types (used by the compiler
       
   228      * to represent the type of a literal).
       
   229      */
       
   230     public class Factory {
       
   231 
       
   232         private int synthNameCount = 0;
       
   233 
       
   234         private Name syntheticName() {
       
   235             return names.fromString("A$" + synthNameCount++);
       
   236         }
       
   237 
       
   238         public ClassType Class(long flags, Type... typeArgs) {
       
   239             ClassSymbol csym = new ClassSymbol(flags, syntheticName(), predef.noSymbol);
       
   240             csym.type = new ClassType(Type.noType, List.from(typeArgs), csym);
       
   241             ((ClassType)csym.type).supertype_field = predef.objectType;
       
   242             return (ClassType)csym.type;
       
   243         }
       
   244 
       
   245         public ClassType Class(Type... typeArgs) {
       
   246             return Class(0, typeArgs);
       
   247         }
       
   248 
       
   249         public ClassType Interface(Type... typeArgs) {
       
   250             return Class(Flags.INTERFACE, typeArgs);
       
   251         }
       
   252 
       
   253         public ClassType Interface(long flags, Type... typeArgs) {
       
   254             return Class(Flags.INTERFACE | flags, typeArgs);
       
   255         }
       
   256 
       
   257         public Type Constant(byte b) {
       
   258             return predef.byteType.constType(b);
       
   259         }
       
   260 
       
   261         public Type Constant(short s) {
       
   262             return predef.shortType.constType(s);
       
   263         }
       
   264 
       
   265         public Type Constant(int i) {
       
   266             return predef.intType.constType(i);
       
   267         }
       
   268 
       
   269         public Type Constant(long l) {
       
   270             return predef.longType.constType(l);
       
   271         }
       
   272 
       
   273         public Type Constant(float f) {
       
   274             return predef.floatType.constType(f);
       
   275         }
       
   276 
       
   277         public Type Constant(double d) {
       
   278             return predef.doubleType.constType(d);
       
   279         }
       
   280 
       
   281         public Type Constant(char c) {
       
   282             return predef.charType.constType(c + 0);
       
   283         }
       
   284 
       
   285         public ArrayType Array(Type elemType) {
       
   286             return new ArrayType(elemType, predef.arrayClass);
       
   287         }
       
   288 
       
   289         public TypeVar TypeVariable() {
       
   290             return TypeVariable(predef.objectType);
       
   291         }
       
   292 
       
   293         public TypeVar TypeVariable(Type bound) {
       
   294             TypeSymbol tvsym = new TypeSymbol(0, syntheticName(), null, predef.noSymbol);
       
   295             tvsym.type = new TypeVar(tvsym, bound, null);
       
   296             return (TypeVar)tvsym.type;
       
   297         }
       
   298 
       
   299         public WildcardType Wildcard(BoundKind bk, Type bound) {
       
   300             return new WildcardType(bound, bk, predef.boundClass);
       
   301         }
       
   302 
       
   303         public CapturedType CapturedVariable(Type upper, Type lower) {
       
   304             return new CapturedType(syntheticName(), predef.noSymbol, upper, lower, null);
       
   305         }
       
   306 
       
   307         public ClassType Intersection(Type classBound, Type... intfBounds) {
       
   308             ClassType ct = Class(Flags.COMPOUND);
       
   309             ct.supertype_field = classBound;
       
   310             ct.interfaces_field = List.from(intfBounds);
       
   311             return ct;
       
   312         }
       
   313     }
       
   314     // </editor-fold>
       
   315 }