• 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.jspecify.nullness.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(@ullable Object obj)197     public final boolean equals(@Nullable 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       sb.append(elementType());
250       if (!annos().isEmpty()) {
251         sb.append(' ');
252         for (AnnoInfo anno : annos()) {
253           sb.append(anno);
254           sb.append(' ');
255         }
256       }
257       sb.append("[]");
258       return sb.toString();
259     }
260 
261     @Memoized
262     @Override
hashCode()263     public abstract int hashCode();
264   }
265 
266   /** A type variable. */
267   @AutoValue
268   abstract class TyVar implements Type {
269 
create(TyVarSymbol sym, ImmutableList<AnnoInfo> annos)270     public static TyVar create(TyVarSymbol sym, ImmutableList<AnnoInfo> annos) {
271       return new AutoValue_Type_TyVar(sym, annos);
272     }
273 
274     /** The type variable's symbol. */
sym()275     public abstract TyVarSymbol sym();
276 
277     @Override
tyKind()278     public TyKind tyKind() {
279       return TyKind.TY_VAR;
280     }
281 
282     @Override
toString()283     public final String toString() {
284       StringBuilder sb = new StringBuilder();
285       for (AnnoInfo anno : annos()) {
286         sb.append(anno);
287         sb.append(' ');
288       }
289       sb.append(sym().name());
290       return sb.toString();
291     }
292 
293     /** The type annotations. */
annos()294     public abstract ImmutableList<AnnoInfo> annos();
295 
296     @Memoized
297     @Override
hashCode()298     public abstract int hashCode();
299   }
300 
301   /** A primitive type. */
302   @AutoValue
303   abstract class PrimTy implements Type {
304 
create(TurbineConstantTypeKind tykind, ImmutableList<AnnoInfo> annos)305     public static PrimTy create(TurbineConstantTypeKind tykind, ImmutableList<AnnoInfo> annos) {
306       return new AutoValue_Type_PrimTy(tykind, annos);
307     }
308 
309     /** The primtive type kind. */
primkind()310     public abstract TurbineConstantTypeKind primkind();
311 
312     @Override
tyKind()313     public TyKind tyKind() {
314       return TyKind.PRIM_TY;
315     }
316 
317     /** The type annotations. */
annos()318     public abstract ImmutableList<AnnoInfo> annos();
319 
320     @Override
toString()321     public final String toString() {
322       StringBuilder sb = new StringBuilder();
323       for (AnnoInfo anno : annos()) {
324         sb.append(anno);
325         sb.append(' ');
326       }
327       sb.append(primkind());
328       return sb.toString();
329     }
330 
331     @Memoized
332     @Override
hashCode()333     public abstract int hashCode();
334   }
335 
336   /** A wildcard type, valid only inside (possibly nested) type arguments. */
337   abstract class WildTy implements Type {
338 
339     public enum BoundKind {
340       NONE,
341       UPPER,
342       LOWER
343     }
344 
boundKind()345     public abstract BoundKind boundKind();
346 
bound()347     public abstract Type bound();
348 
349     /** The type annotations. */
annotations()350     public abstract ImmutableList<AnnoInfo> annotations();
351 
352     @Override
tyKind()353     public TyKind tyKind() {
354       return TyKind.WILD_TY;
355     }
356   }
357 
358   /** An upper-bounded wildcard type. */
359   @AutoValue
360   abstract class WildUpperBoundedTy extends WildTy {
361 
create(Type bound, ImmutableList<AnnoInfo> annotations)362     public static WildUpperBoundedTy create(Type bound, ImmutableList<AnnoInfo> annotations) {
363       return new AutoValue_Type_WildUpperBoundedTy(annotations, bound);
364     }
365 
366     /** The upper bound. */
367     @Override
bound()368     public abstract Type bound();
369 
370     @Override
boundKind()371     public BoundKind boundKind() {
372       return BoundKind.UPPER;
373     }
374 
375     @Override
toString()376     public final String toString() {
377       StringBuilder sb = new StringBuilder();
378       for (AnnoInfo anno : annotations()) {
379         sb.append(anno);
380         sb.append(' ');
381       }
382       sb.append("? extends ");
383       sb.append(bound());
384       return sb.toString();
385     }
386 
387     @Memoized
388     @Override
hashCode()389     public abstract int hashCode();
390   }
391 
392   /** An lower-bounded wildcard type. */
393   @AutoValue
394   abstract class WildLowerBoundedTy extends WildTy {
395 
create(Type bound, ImmutableList<AnnoInfo> annotations)396     public static WildLowerBoundedTy create(Type bound, ImmutableList<AnnoInfo> annotations) {
397       return new AutoValue_Type_WildLowerBoundedTy(annotations, bound);
398     }
399 
400     /** The lower bound. */
401     @Override
bound()402     public abstract Type bound();
403 
404     @Override
boundKind()405     public BoundKind boundKind() {
406       return BoundKind.LOWER;
407     }
408 
409     @Override
toString()410     public final String toString() {
411       StringBuilder sb = new StringBuilder();
412       for (AnnoInfo anno : annotations()) {
413         sb.append(anno);
414         sb.append(' ');
415       }
416       sb.append("? super ");
417       sb.append(bound());
418       return sb.toString();
419     }
420 
421     @Memoized
422     @Override
hashCode()423     public abstract int hashCode();
424   }
425 
426   /** An unbounded wildcard type. */
427   @AutoValue
428   abstract class WildUnboundedTy extends WildTy {
429 
create(ImmutableList<AnnoInfo> annotations)430     public static WildUnboundedTy create(ImmutableList<AnnoInfo> annotations) {
431       return new AutoValue_Type_WildUnboundedTy(annotations);
432     }
433 
434     @Override
boundKind()435     public BoundKind boundKind() {
436       return BoundKind.NONE;
437     }
438 
439     @Override
bound()440     public Type bound() {
441       throw new IllegalStateException();
442     }
443 
444     @Override
toString()445     public final String toString() {
446       StringBuilder sb = new StringBuilder();
447       for (AnnoInfo anno : annotations()) {
448         sb.append(anno);
449         sb.append(' ');
450       }
451       sb.append('?');
452       return sb.toString();
453     }
454 
455     @Memoized
456     @Override
hashCode()457     public abstract int hashCode();
458   }
459 
460   /** An intersection type. */
461   @AutoValue
462   abstract class IntersectionTy implements Type {
463 
bounds()464     public abstract ImmutableList<Type> bounds();
465 
create(ImmutableList<Type> bounds)466     public static IntersectionTy create(ImmutableList<Type> bounds) {
467       return new AutoValue_Type_IntersectionTy(bounds);
468     }
469 
470     @Override
tyKind()471     public TyKind tyKind() {
472       return TyKind.INTERSECTION_TY;
473     }
474 
475     @Memoized
476     @Override
hashCode()477     public abstract int hashCode();
478 
479     @Override
toString()480     public final String toString() {
481       return Joiner.on('&').join(bounds());
482     }
483   }
484 
485   /** A method type. */
486   @AutoValue
487   abstract class MethodTy implements Type {
488 
tyParams()489     public abstract ImmutableSet<TyVarSymbol> tyParams();
490 
returnType()491     public abstract Type returnType();
492 
493     /** The type of the receiver parameter (see JLS 8.4.1). */
receiverType()494     public abstract @Nullable Type receiverType();
495 
parameters()496     public abstract ImmutableList<Type> parameters();
497 
thrown()498     public abstract ImmutableList<Type> thrown();
499 
create( ImmutableSet<TyVarSymbol> tyParams, Type returnType, Type receiverType, ImmutableList<Type> parameters, ImmutableList<Type> thrown)500     public static MethodTy create(
501         ImmutableSet<TyVarSymbol> tyParams,
502         Type returnType,
503         Type receiverType,
504         ImmutableList<Type> parameters,
505         ImmutableList<Type> thrown) {
506       return new AutoValue_Type_MethodTy(tyParams, returnType, receiverType, parameters, thrown);
507     }
508 
509     @Override
tyKind()510     public TyKind tyKind() {
511       return TyKind.METHOD_TY;
512     }
513 
514     @Override
toString()515     public final String toString() {
516       StringBuilder sb = new StringBuilder();
517       if (!tyParams().isEmpty()) {
518         sb.append('<');
519         Joiner.on(',').appendTo(sb, tyParams());
520         sb.append('>');
521       }
522       sb.append('(');
523       Joiner.on(',').appendTo(sb, parameters());
524       sb.append(')');
525       sb.append(returnType());
526       return sb.toString();
527     }
528 
529     @Memoized
530     @Override
hashCode()531     public abstract int hashCode();
532   }
533 
534   /** An error type. */
535   final class ErrorTy implements Type {
536 
537     private final String name;
538 
ErrorTy(String name)539     private ErrorTy(String name) {
540       this.name = requireNonNull(name);
541     }
542 
543     /**
544      * Best-effort syntactic context for use in diagnostics or by annotation processors. This may be
545      * a simple or qualified name; it is not a canonical qualified name.
546      */
name()547     public String name() {
548       return name;
549     }
550 
create(Iterable<Tree.Ident> names)551     public static ErrorTy create(Iterable<Tree.Ident> names) {
552       List<String> bits = new ArrayList<>();
553       for (Tree.Ident ident : names) {
554         bits.add(ident.value());
555       }
556       return create(Joiner.on('.').join(bits));
557     }
558 
create(String name)559     public static ErrorTy create(String name) {
560       return new ErrorTy(name);
561     }
562 
563     @Override
tyKind()564     public TyKind tyKind() {
565       return TyKind.ERROR_TY;
566     }
567 
568     @Override
toString()569     public final String toString() {
570       return name();
571     }
572 
573     @Override
hashCode()574     public final int hashCode() {
575       return System.identityHashCode(this);
576     }
577 
578     @Override
equals(@ullable Object other)579     public final boolean equals(@Nullable Object other) {
580       // The name associated with an error type is context for use in diagnostics or by annotations
581       // processors. Two error types with the same name don't necessarily represent the same type.
582 
583       // TODO(cushon): should error types compare equal to themselves if they correspond to the same
584       // source location? Investigate storing the source position for this type, or replacing with
585       // `this == other` (and removing interning in ModelFactory).
586 
587       return false;
588     }
589   }
590 }
591