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