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