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