• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.turbine.type;
18 
19 import static com.google.common.collect.Iterables.getLast;
20 import static java.util.Objects.requireNonNull;
21 
22 import com.google.auto.value.AutoValue;
23 import com.google.auto.value.extension.memoized.Memoized;
24 import com.google.common.base.Joiner;
25 import com.google.common.collect.ImmutableList;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.common.collect.Iterables;
28 import com.google.turbine.binder.sym.ClassSymbol;
29 import com.google.turbine.binder.sym.TyVarSymbol;
30 import com.google.turbine.model.TurbineConstantTypeKind;
31 import com.google.turbine.tree.Tree;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35 import org.checkerframework.checker.nullness.qual.Nullable;
36 
37 /** JLS 4 types. */
38 public interface Type {
39 
40   /** A type kind. */
41   enum TyKind {
42     /** A primitive type. */
43     PRIM_TY,
44     /**
45      * The void type.
46      *
47      * <p>It isn't actually a type in the spec, but it's included here for convenience.
48      */
49     VOID_TY,
50     /** A class type. */
51     CLASS_TY,
52     /** An array type. */
53     ARRAY_TY,
54     /** A type variable type. */
55     TY_VAR,
56     /** A wildcard type. */
57     WILD_TY,
58     /** An intersection type. */
59     INTERSECTION_TY,
60     /** A method type. */
61     METHOD_TY,
62 
63     ERROR_TY,
64     NONE_TY,
65   }
66 
67   /** The type kind. */
tyKind()68   TyKind tyKind();
69 
70   /** The void type. */
71   Type VOID =
72       new Type() {
73         @Override
74         public TyKind tyKind() {
75           return TyKind.VOID_TY;
76         }
77 
78         @Override
79         public final String toString() {
80           return "void";
81         }
82       };
83 
84   /** The void type. */
85   Type NONE =
86       new Type() {
87         @Override
88         public TyKind tyKind() {
89           return TyKind.NONE_TY;
90         }
91 
92         @Override
93         public final String toString() {
94           return "none";
95         }
96       };
97 
98   /**
99    * A class type.
100    *
101    * <p>Qualified types (e.g. {@code OuterClass<Foo>.InnerClass<Bar>}) are repesented as a list
102    * {@link SimpleClassTy}s (enclosing types first), each of which contains a {@link ClassSymbol}
103    * and an optional list of type arguments.
104    */
105   @AutoValue
106   abstract class ClassTy implements Type {
107 
108     /**
109      * The {@link ClassTy} for {@code java.lang.Object}. There's nothing special about this
110      * instance, it's just to avoid some boilerplate.
111      */
112     public static final ClassTy OBJECT = asNonParametricClassTy(ClassSymbol.OBJECT);
113 
114     /** The {@link ClassTy} for {@code java.lang.String}. */
115     public static final ClassTy STRING = asNonParametricClassTy(ClassSymbol.STRING);
116 
117     public static final ClassTy CLONEABLE = asNonParametricClassTy(ClassSymbol.CLONEABLE);
118     public static final ClassTy SERIALIZABLE = asNonParametricClassTy(ClassSymbol.SERIALIZABLE);
119 
120     /** Returns a {@link ClassTy} with no type arguments for the given {@link ClassSymbol}. */
asNonParametricClassTy(ClassSymbol i)121     public static ClassTy asNonParametricClassTy(ClassSymbol i) {
122       return ClassTy.create(
123           Arrays.asList(SimpleClassTy.create(i, ImmutableList.of(), ImmutableList.of())));
124     }
125 
classes()126     public abstract ImmutableList<SimpleClassTy> classes();
127 
create(Iterable<SimpleClassTy> classes)128     public static ClassTy create(Iterable<SimpleClassTy> classes) {
129       return new AutoValue_Type_ClassTy(ImmutableList.copyOf(classes));
130     }
131 
132     @Override
tyKind()133     public TyKind tyKind() {
134       return TyKind.CLASS_TY;
135     }
136 
137     /** The class symbol. */
sym()138     public ClassSymbol sym() {
139       return getLast(classes()).sym();
140     }
141 
142     @Override
toString()143     public final String toString() {
144       StringBuilder sb = new StringBuilder();
145       boolean first = true;
146       for (SimpleClassTy c : classes()) {
147         for (AnnoInfo anno : c.annos()) {
148           sb.append(anno);
149           sb.append(' ');
150         }
151         if (!first) {
152           sb.append('.');
153           sb.append(c.sym().binaryName().substring(c.sym().binaryName().lastIndexOf('$') + 1));
154         } else {
155           sb.append(c.sym().binaryName().replace('/', '.').replace('$', '.'));
156         }
157         if (!c.targs().isEmpty()) {
158           sb.append('<');
159           Joiner.on(',').appendTo(sb, c.targs());
160           sb.append('>');
161         }
162         first = false;
163       }
164       return sb.toString();
165     }
166 
167     /** One element of a qualified {@link ClassTy}. */
168     @AutoValue
169     public abstract static class SimpleClassTy {
170 
create( ClassSymbol sym, ImmutableList<Type> targs, ImmutableList<AnnoInfo> annos)171       public static SimpleClassTy create(
172           ClassSymbol sym, ImmutableList<Type> targs, ImmutableList<AnnoInfo> annos) {
173         return new AutoValue_Type_ClassTy_SimpleClassTy(sym, targs, annos);
174       }
175 
176       /** The class symbol of the element. */
sym()177       public abstract ClassSymbol sym();
178 
179       /** The type arguments. */
targs()180       public abstract ImmutableList<Type> targs();
181 
182       /** The type annotations. */
annos()183       public abstract ImmutableList<AnnoInfo> annos();
184 
185       @Memoized
186       @Override
hashCode()187       public abstract int hashCode();
188     }
189 
190     @Memoized
191     @Override
hashCode()192     public int hashCode() {
193       return Iterables.getLast(classes()).hashCode();
194     }
195 
196     @Override
equals(Object obj)197     public final boolean equals(Object obj) {
198       if (!(obj instanceof ClassTy)) {
199         return false;
200       }
201       ClassTy that = (ClassTy) obj;
202       int i = this.classes().size() - 1;
203       int j = that.classes().size() - 1;
204       for (; i >= 0 && j >= 0; i--, j--) {
205         if (!this.classes().get(i).equals(that.classes().get(j))) {
206           return false;
207         }
208       }
209       // don't rely on canonical form for simple class names
210       if (hasTargs(this.classes(), i) || hasTargs(that.classes(), j)) {
211         return false;
212       }
213       return true;
214     }
215 
hasTargs(ImmutableList<SimpleClassTy> classes, int idx)216     private static boolean hasTargs(ImmutableList<SimpleClassTy> classes, int idx) {
217       for (; idx >= 0; idx--) {
218         SimpleClassTy simple = classes.get(idx);
219         if (!simple.targs().isEmpty() || !simple.annos().isEmpty()) {
220           return true;
221         }
222       }
223       return false;
224     }
225   }
226 
227   /** An array type. */
228   @AutoValue
229   abstract class ArrayTy implements Type {
230 
create(Type elem, ImmutableList<AnnoInfo> annos)231     public static ArrayTy create(Type elem, ImmutableList<AnnoInfo> annos) {
232       return new AutoValue_Type_ArrayTy(elem, annos);
233     }
234 
235     /** The element type of the array. */
elementType()236     public abstract Type elementType();
237 
238     @Override
tyKind()239     public TyKind tyKind() {
240       return TyKind.ARRAY_TY;
241     }
242 
243     /** The type annotations. */
annos()244     public abstract ImmutableList<AnnoInfo> annos();
245 
246     @Override
toString()247     public final String toString() {
248       StringBuilder sb = new StringBuilder();
249       for (AnnoInfo anno : annos()) {
250         sb.append(anno);
251         sb.append(' ');
252       }
253       sb.append(elementType());
254       sb.append("[]");
255       return sb.toString();
256     }
257 
258     @Memoized
259     @Override
hashCode()260     public abstract int hashCode();
261   }
262 
263   /** A type variable. */
264   @AutoValue
265   abstract class TyVar implements Type {
266 
create(TyVarSymbol sym, ImmutableList<AnnoInfo> annos)267     public static TyVar create(TyVarSymbol sym, ImmutableList<AnnoInfo> annos) {
268       return new AutoValue_Type_TyVar(sym, annos);
269     }
270 
271     /** The type variable's symbol. */
sym()272     public abstract TyVarSymbol sym();
273 
274     @Override
tyKind()275     public TyKind tyKind() {
276       return TyKind.TY_VAR;
277     }
278 
279     @Override
toString()280     public final String toString() {
281       StringBuilder sb = new StringBuilder();
282       for (AnnoInfo anno : annos()) {
283         sb.append(anno);
284         sb.append(' ');
285       }
286       sb.append(sym().name());
287       return sb.toString();
288     }
289 
290     /** The type annotations. */
annos()291     public abstract ImmutableList<AnnoInfo> annos();
292 
293     @Memoized
294     @Override
hashCode()295     public abstract int hashCode();
296   }
297 
298   /** A primitive type. */
299   @AutoValue
300   abstract class PrimTy implements Type {
301 
create(TurbineConstantTypeKind tykind, ImmutableList<AnnoInfo> annos)302     public static PrimTy create(TurbineConstantTypeKind tykind, ImmutableList<AnnoInfo> annos) {
303       return new AutoValue_Type_PrimTy(tykind, annos);
304     }
305 
306     /** The primtive type kind. */
primkind()307     public abstract TurbineConstantTypeKind primkind();
308 
309     @Override
tyKind()310     public TyKind tyKind() {
311       return TyKind.PRIM_TY;
312     }
313 
314     /** The type annotations. */
annos()315     public abstract ImmutableList<AnnoInfo> annos();
316 
317     @Override
toString()318     public final String toString() {
319       StringBuilder sb = new StringBuilder();
320       for (AnnoInfo anno : annos()) {
321         sb.append(anno);
322         sb.append(' ');
323       }
324       sb.append(primkind());
325       return sb.toString();
326     }
327 
328     @Memoized
329     @Override
hashCode()330     public abstract int hashCode();
331   }
332 
333   /** A wildcard type, valid only inside (possibly nested) type arguments. */
334   abstract class WildTy implements Type {
335 
336     public enum BoundKind {
337       NONE,
338       UPPER,
339       LOWER
340     }
341 
boundKind()342     public abstract BoundKind boundKind();
343 
bound()344     public abstract Type bound();
345 
346     /** The type annotations. */
annotations()347     public abstract ImmutableList<AnnoInfo> annotations();
348 
349     @Override
tyKind()350     public TyKind tyKind() {
351       return TyKind.WILD_TY;
352     }
353   }
354 
355   /** An upper-bounded wildcard type. */
356   @AutoValue
357   abstract class WildUpperBoundedTy extends WildTy {
358 
create(Type bound, ImmutableList<AnnoInfo> annotations)359     public static WildUpperBoundedTy create(Type bound, ImmutableList<AnnoInfo> annotations) {
360       return new AutoValue_Type_WildUpperBoundedTy(annotations, bound);
361     }
362 
363     /** The upper bound. */
364     @Override
bound()365     public abstract Type bound();
366 
367     @Override
boundKind()368     public BoundKind boundKind() {
369       return BoundKind.UPPER;
370     }
371 
372     @Override
toString()373     public final String toString() {
374       StringBuilder sb = new StringBuilder();
375       for (AnnoInfo anno : annotations()) {
376         sb.append(anno);
377         sb.append(' ');
378       }
379       sb.append("? extends ");
380       sb.append(bound());
381       return sb.toString();
382     }
383 
384     @Memoized
385     @Override
hashCode()386     public abstract int hashCode();
387   }
388 
389   /** An lower-bounded wildcard type. */
390   @AutoValue
391   abstract class WildLowerBoundedTy extends WildTy {
392 
create(Type bound, ImmutableList<AnnoInfo> annotations)393     public static WildLowerBoundedTy create(Type bound, ImmutableList<AnnoInfo> annotations) {
394       return new AutoValue_Type_WildLowerBoundedTy(annotations, bound);
395     }
396 
397     /** The lower bound. */
398     @Override
bound()399     public abstract Type bound();
400 
401     @Override
boundKind()402     public BoundKind boundKind() {
403       return BoundKind.LOWER;
404     }
405 
406     @Override
toString()407     public final String toString() {
408       StringBuilder sb = new StringBuilder();
409       for (AnnoInfo anno : annotations()) {
410         sb.append(anno);
411         sb.append(' ');
412       }
413       sb.append("? super ");
414       sb.append(bound());
415       return sb.toString();
416     }
417 
418     @Memoized
419     @Override
hashCode()420     public abstract int hashCode();
421   }
422 
423   /** An unbounded wildcard type. */
424   @AutoValue
425   abstract class WildUnboundedTy extends WildTy {
426 
create(ImmutableList<AnnoInfo> annotations)427     public static WildUnboundedTy create(ImmutableList<AnnoInfo> annotations) {
428       return new AutoValue_Type_WildUnboundedTy(annotations);
429     }
430 
431     @Override
boundKind()432     public BoundKind boundKind() {
433       return BoundKind.NONE;
434     }
435 
436     @Override
bound()437     public Type bound() {
438       throw new IllegalStateException();
439     }
440 
441     @Override
toString()442     public final String toString() {
443       StringBuilder sb = new StringBuilder();
444       for (AnnoInfo anno : annotations()) {
445         sb.append(anno);
446         sb.append(' ');
447       }
448       sb.append('?');
449       return sb.toString();
450     }
451 
452     @Memoized
453     @Override
hashCode()454     public abstract int hashCode();
455   }
456 
457   /** An intersection type. */
458   @AutoValue
459   abstract class IntersectionTy implements Type {
460 
bounds()461     public abstract ImmutableList<Type> bounds();
462 
create(ImmutableList<Type> bounds)463     public static IntersectionTy create(ImmutableList<Type> bounds) {
464       return new AutoValue_Type_IntersectionTy(bounds);
465     }
466 
467     @Override
tyKind()468     public TyKind tyKind() {
469       return TyKind.INTERSECTION_TY;
470     }
471 
472     @Memoized
473     @Override
hashCode()474     public abstract int hashCode();
475 
476     @Override
toString()477     public final String toString() {
478       return Joiner.on('&').join(bounds());
479     }
480   }
481 
482   /** A method type. */
483   @AutoValue
484   abstract class MethodTy implements Type {
485 
tyParams()486     public abstract ImmutableSet<TyVarSymbol> tyParams();
487 
returnType()488     public abstract Type returnType();
489 
490     /** The type of the receiver parameter (see JLS 8.4.1). */
491     @Nullable
receiverType()492     public abstract Type receiverType();
493 
parameters()494     public abstract ImmutableList<Type> parameters();
495 
thrown()496     public abstract ImmutableList<Type> thrown();
497 
create( ImmutableSet<TyVarSymbol> tyParams, Type returnType, Type receiverType, ImmutableList<Type> parameters, ImmutableList<Type> thrown)498     public static MethodTy create(
499         ImmutableSet<TyVarSymbol> tyParams,
500         Type returnType,
501         Type receiverType,
502         ImmutableList<Type> parameters,
503         ImmutableList<Type> thrown) {
504       return new AutoValue_Type_MethodTy(tyParams, returnType, receiverType, parameters, thrown);
505     }
506 
507     @Override
tyKind()508     public TyKind tyKind() {
509       return TyKind.METHOD_TY;
510     }
511 
512     @Override
toString()513     public final String toString() {
514       StringBuilder sb = new StringBuilder();
515       if (!tyParams().isEmpty()) {
516         sb.append('<');
517         Joiner.on(',').appendTo(sb, tyParams());
518         sb.append('>');
519       }
520       sb.append('(');
521       Joiner.on(',').appendTo(sb, parameters());
522       sb.append(')');
523       sb.append(returnType());
524       return sb.toString();
525     }
526 
527     @Memoized
528     @Override
hashCode()529     public abstract int hashCode();
530   }
531 
532   /** An error type. */
533   final class ErrorTy implements Type {
534 
535     private final String name;
536 
ErrorTy(String name)537     private ErrorTy(String name) {
538       this.name = requireNonNull(name);
539     }
540 
541     /**
542      * Best-effort syntactic context for use in diagnostics or by annotation processors. This may be
543      * a simple or qualified name; it is not a canonical qualified name.
544      */
name()545     public String name() {
546       return name;
547     }
548 
create(Iterable<Tree.Ident> names)549     public static ErrorTy create(Iterable<Tree.Ident> names) {
550       List<String> bits = new ArrayList<>();
551       for (Tree.Ident ident : names) {
552         bits.add(ident.value());
553       }
554       return create(Joiner.on('.').join(bits));
555     }
556 
create(String name)557     public static ErrorTy create(String name) {
558       return new ErrorTy(name);
559     }
560 
561     @Override
tyKind()562     public TyKind tyKind() {
563       return TyKind.ERROR_TY;
564     }
565 
566     @Override
toString()567     public final String toString() {
568       return name();
569     }
570 
571     @Override
hashCode()572     public final int hashCode() {
573       return System.identityHashCode(this);
574     }
575 
576     @Override
equals(Object other)577     public final boolean equals(Object other) {
578       // The name associated with an error type is context for use in diagnostics or by annotations
579       // processors. Two error types with the same name don't necessarily represent the same type.
580 
581       // TODO(cushon): should error types compare equal to themselves if they correspond to the same
582       // source location? Investigate storing the source position for this type, or replacing with
583       // `this == other` (and removing interning in ModelFactory).
584 
585       return false;
586     }
587   }
588 }
589