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