< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java

Print this page

   1 /*
   2  * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any

 181      */
 182     public Type skipTypeVars(Type site, boolean capture) {
 183         while (site.hasTag(TYPEVAR)) {
 184             site = site.getUpperBound();
 185         }
 186         return capture ? capture(site) : site;
 187     }
 188     // </editor-fold>
 189 
 190     // <editor-fold defaultstate="collapsed" desc="projections">
 191 
 192     /**
 193      * A projection kind. See {@link TypeProjection}
 194      */
 195     enum ProjectionKind {
 196         UPWARDS() {
 197             @Override
 198             ProjectionKind complement() {
 199                 return DOWNWARDS;
 200             }










 201         },
 202         DOWNWARDS() {
 203             @Override
 204             ProjectionKind complement() {
 205                 return UPWARDS;
 206             }










































 207         };
 208 
 209         abstract ProjectionKind complement();


 210     }
 211 
 212     /**
 213      * This visitor performs upwards and downwards projections on types.
 214      *
 215      * A projection is defined as a function that takes a type T, a set of type variables V and that
 216      * produces another type S.
 217      *
 218      * An upwards projection maps a type T into a type S such that (i) T has no variables in V,
 219      * and (ii) S is an upper bound of T.
 220      *
 221      * A downwards projection maps a type T into a type S such that (i) T has no variables in V,
 222      * and (ii) S is a lower bound of T.
 223      *
 224      * Note that projections are only allowed to touch variables in V. Therefore, it is possible for
 225      * a projection to leave its input type unchanged if it does not contain any variables in V.
 226      *
 227      * Moreover, note that while an upwards projection is always defined (every type as an upper bound),
 228      * a downwards projection is not always defined.
 229      *
 230      * Examples:
 231      *
 232      * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
 233      * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
 234      * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
 235      * {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
 236      */
 237     class TypeProjection extends TypeMapping<ProjectionKind> {
 238 
 239         List<Type> vars;
 240         Set<Type> seen = new HashSet<>();
 241 
 242         public TypeProjection(List<Type> vars) {
 243             this.vars = vars;
 244         }
 245 
 246         @Override
 247         public Type visitClassType(ClassType t, ProjectionKind pkind) {
 248             if (t.isCompound()) {
 249                 List<Type> components = directSupertypes(t);
 250                 List<Type> components1 = components.map(c -> c.map(this, pkind));
 251                 if (components == components1) return t;
 252                 else return makeIntersectionType(components1);







 253             } else {
 254                 Type outer = t.getEnclosingType();
 255                 Type outer1 = visit(outer, pkind);
 256                 List<Type> typarams = t.getTypeArguments();
 257                 List<Type> formals = t.tsym.type.getTypeArguments();
 258                 ListBuffer<Type> typarams1 = new ListBuffer<>();
 259                 boolean changed = false;
 260                 for (Type actual : typarams) {
 261                     Type t2 = mapTypeArgument(t, formals.head.getUpperBound(), actual, pkind);
 262                     if (t2.hasTag(BOT)) {
 263                         //not defined
 264                         return syms.botType;
 265                     }
 266                     typarams1.add(t2);
 267                     changed |= actual != t2;
 268                     formals = formals.tail;
 269                 }
 270                 if (outer1 == outer && !changed) return t;
 271                 else return new ClassType(outer1, typarams1.toList(), t.tsym, t.getMetadata()) {
 272                     @Override

 287                 //undefined
 288                 return syms.botType;
 289             } else {
 290                 return new ArrayType(elemtype1, t.tsym, t.metadata) {
 291                     @Override
 292                     protected boolean needsStripping() {
 293                         return true;
 294                     }
 295                 };
 296             }
 297         }
 298 
 299         @Override
 300         public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
 301             if (vars.contains(t)) {
 302                 if (seen.add(t)) {
 303                     try {
 304                         final Type bound;
 305                         switch (pkind) {
 306                             case UPWARDS:

 307                                 bound = t.getUpperBound();
 308                                 break;
 309                             case DOWNWARDS:

 310                                 bound = (t.getLowerBound() == null) ?
 311                                         syms.botType :
 312                                         t.getLowerBound();
 313                                 break;
 314                             default:
 315                                 Assert.error();
 316                                 return null;
 317                         }
 318                         return bound.map(this, pkind);
 319                     } finally {
 320                         seen.remove(t);
 321                     }
 322                 } else {
 323                     //cycle
 324                     return pkind == ProjectionKind.UPWARDS ?
 325                             syms.objectType : syms.botType;
 326                 }
 327             } else {
 328                 return t;
 329             }
 330         }
 331 
 332         private Type mapTypeArgument(Type site, Type declaredBound, Type t, ProjectionKind pkind) {
 333             return t.containsAny(vars) ?
 334                     t.map(new TypeArgumentProjection(site, declaredBound), pkind) :
 335                     t;
 336         }
 337 
 338         class TypeArgumentProjection extends TypeMapping<ProjectionKind> {
 339 
 340             Type site;
 341             Type declaredBound;
 342 
 343             TypeArgumentProjection(Type site, Type declaredBound) {
 344                 this.site = site;
 345                 this.declaredBound = declaredBound;
 346             }
 347 
 348             @Override
 349             public Type visitType(Type t, ProjectionKind pkind) {
 350                 //type argument is some type containing restricted vars
 351                 if (pkind == ProjectionKind.DOWNWARDS) {
 352                     //not defined
 353                     return syms.botType;
 354                 }
 355                 Type upper = t.map(TypeProjection.this, ProjectionKind.UPWARDS);
 356                 Type lower = t.map(TypeProjection.this, ProjectionKind.DOWNWARDS);
 357                 List<Type> formals = site.tsym.type.getTypeArguments();
 358                 BoundKind bk;
 359                 Type bound;
 360                 if (!isSameType(upper, syms.objectType) &&
 361                         (declaredBound.containsAny(formals) ||
 362                          !isSubtype(declaredBound, upper))) {
 363                     bound = upper;
 364                     bk = EXTENDS;
 365                 } else if (!lower.hasTag(BOT)) {
 366                     bound = lower;
 367                     bk = SUPER;
 368                 } else {
 369                     bound = syms.objectType;
 370                     bk = UNBOUND;
 371                 }
 372                 return makeWildcard(bound, bk);
 373             }
 374 
 375             @Override
 376             public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
 377                 //type argument is some wildcard whose bound contains restricted vars
 378                 Type bound = syms.botType;
 379                 BoundKind bk = wt.kind;
 380                 switch (wt.kind) {
 381                     case EXTENDS:
 382                         bound = wt.type.map(TypeProjection.this, pkind);
 383                         if (bound.hasTag(BOT)) {
 384                             return syms.botType;
 385                         }
 386                         break;
 387                     case SUPER:
 388                         bound = wt.type.map(TypeProjection.this, pkind.complement());
 389                         if (bound.hasTag(BOT)) {
 390                             bound = syms.objectType;
 391                             bk = UNBOUND;
 392                         }
 393                         break;
 394                 }
 395                 return makeWildcard(bound, bk);
 396             }
 397 
 398             private Type makeWildcard(Type bound, BoundKind bk) {
 399                 return new WildcardType(bound, bk, syms.boundClass) {
 400                     @Override
 401                     protected boolean needsStripping() {
 402                         return true;
 403                     }
 404                 };
 405             }
 406         }
 407     }
 408 
 409     /**
 410      * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
 411      *
 412      * @param t the type to be projected
 413      * @param vars the set of type variables to be mapped
 414      * @return the type obtained as result of the projection
 415      */
 416     public Type upward(Type t, List<Type> vars) {
 417         return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);













 418     }
 419 
 420     /**
 421      * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
 422      * This routine is typically used to computed the input set of variables to be used during
 423      * an upwards projection (see {@link Types#upward(Type, List)}).
 424      *
 425      * @param t the type where occurrences of captured variables have to be found
 426      * @return the set of captured variables found in t
 427      */
 428     public List<Type> captures(Type t) {
 429         CaptureScanner cs = new CaptureScanner();
 430         Set<Type> captures = new HashSet<>();
 431         cs.visit(t, captures);
 432         return List.from(captures);
 433     }
 434 
 435     /**
 436      * This visitor scans a type recursively looking for occurrences of captured type variables.
 437      */

5305                 return syms.doubleType;
5306             case ClassFile.CONSTANT_MethodHandle:
5307                 return syms.methodHandleType;
5308             case ClassFile.CONSTANT_MethodType:
5309                 return syms.methodTypeType;
5310             case ClassFile.CONSTANT_Dynamic:
5311                 return ((DynamicVarSymbol)c).type;
5312             default:
5313                 throw new AssertionError("Not a loadable constant: " + c.poolTag());
5314         }
5315     }
5316     // </editor-fold>
5317 
5318     public void newRound() {
5319         descCache._map.clear();
5320         isDerivedRawCache.clear();
5321         implCache._map.clear();
5322         membersCache._map.clear();
5323         closureCache.clear();
5324     }






5325 }

   1 /*
   2  * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any

 181      */
 182     public Type skipTypeVars(Type site, boolean capture) {
 183         while (site.hasTag(TYPEVAR)) {
 184             site = site.getUpperBound();
 185         }
 186         return capture ? capture(site) : site;
 187     }
 188     // </editor-fold>
 189 
 190     // <editor-fold defaultstate="collapsed" desc="projections">
 191 
 192     /**
 193      * A projection kind. See {@link TypeProjection}
 194      */
 195     enum ProjectionKind {
 196         UPWARDS() {
 197             @Override
 198             ProjectionKind complement() {
 199                 return DOWNWARDS;
 200             }
 201 
 202             @Override
 203             boolean allowIntersectionTypes() {
 204                 return true;
 205             }
 206 
 207             @Override
 208             ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
 209                 return allowIntersectionTypes ? this : UPWARDS_NO_INTERSECTION;
 210             }
 211         },
 212         DOWNWARDS() {
 213             @Override
 214             ProjectionKind complement() {
 215                 return UPWARDS;
 216             }
 217 
 218             @Override
 219             boolean allowIntersectionTypes() {
 220                 return true;
 221             }
 222 
 223             @Override
 224             ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
 225                 return allowIntersectionTypes ? this : DOWNWARDS_NO_INTERSECTION;
 226             }
 227         },
 228         UPWARDS_NO_INTERSECTION() {
 229             @Override
 230             ProjectionKind complement() {
 231                 return DOWNWARDS_NO_INTERSECTION;
 232             }
 233 
 234             @Override
 235             boolean allowIntersectionTypes() {
 236                 return false;
 237             }
 238 
 239             @Override
 240             ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
 241                 return allowIntersectionTypes ? UPWARDS : this;
 242             }
 243         },
 244         DOWNWARDS_NO_INTERSECTION() {
 245             @Override
 246             ProjectionKind complement() {
 247                 return UPWARDS_NO_INTERSECTION;
 248             }
 249 
 250             @Override
 251             boolean allowIntersectionTypes() {
 252                 return false;
 253             }
 254 
 255             @Override
 256             ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
 257                 return allowIntersectionTypes ? DOWNWARDS : this;
 258             }
 259         };
 260 
 261         abstract ProjectionKind complement();
 262         abstract boolean allowIntersectionTypes();
 263         abstract ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes);
 264     }
 265 
 266     /**
 267      * This visitor performs upwards and downwards projections on types.
 268      *
 269      * A projection is defined as a function that takes a type T, a set of type variables V and that
 270      * produces another type S.
 271      *
 272      * An upwards projection maps a type T into a type S such that (i) T has no variables in V,
 273      * and (ii) S is an upper bound of T.
 274      *
 275      * A downwards projection maps a type T into a type S such that (i) T has no variables in V,
 276      * and (ii) S is a lower bound of T.
 277      *
 278      * Note that projections are only allowed to touch variables in V. Therefore, it is possible for
 279      * a projection to leave its input type unchanged if it does not contain any variables in V.
 280      *
 281      * Moreover, note that while an upwards projection is always defined (every type as an upper bound),
 282      * a downwards projection is not always defined.
 283      *
 284      * Examples:
 285      *
 286      * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
 287      * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
 288      * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
 289      * {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
 290      */
 291     class TypeProjection extends TypeMapping<ProjectionKind> {
 292 
 293         List<Type> vars;
 294         Set<Type> seen = new HashSet<>();
 295 
 296         public TypeProjection(List<Type> vars) {
 297             this.vars = vars;
 298         }
 299 
 300         @Override
 301         public Type visitClassType(ClassType t, ProjectionKind pkind) {
 302             if (t.isUnion() || t.isIntersection()) {
 303                 if (pkind.allowIntersectionTypes()) {
 304                     List<Type> components = directSupertypes(t);
 305                     List<Type> components1 = components.map(c -> c.map(this, pkind));
 306                     if (components == components1) return t;
 307                     else return makeIntersectionType(components1);
 308                 } else if (t.isIntersection()) {
 309                     return visit(((IntersectionClassType)t).getExplicitComponents().head, pkind);
 310                 } else {
 311                     Assert.check(t.isUnion());
 312                     return visit(((UnionClassType)t).getLub(), pkind);
 313                 }
 314             } else {
 315                 Type outer = t.getEnclosingType();
 316                 Type outer1 = visit(outer, pkind);
 317                 List<Type> typarams = t.getTypeArguments();
 318                 List<Type> formals = t.tsym.type.getTypeArguments();
 319                 ListBuffer<Type> typarams1 = new ListBuffer<>();
 320                 boolean changed = false;
 321                 for (Type actual : typarams) {
 322                     Type t2 = mapTypeArgument(t, formals.head.getUpperBound(), actual, pkind);
 323                     if (t2.hasTag(BOT)) {
 324                         //not defined
 325                         return syms.botType;
 326                     }
 327                     typarams1.add(t2);
 328                     changed |= actual != t2;
 329                     formals = formals.tail;
 330                 }
 331                 if (outer1 == outer && !changed) return t;
 332                 else return new ClassType(outer1, typarams1.toList(), t.tsym, t.getMetadata()) {
 333                     @Override

 348                 //undefined
 349                 return syms.botType;
 350             } else {
 351                 return new ArrayType(elemtype1, t.tsym, t.metadata) {
 352                     @Override
 353                     protected boolean needsStripping() {
 354                         return true;
 355                     }
 356                 };
 357             }
 358         }
 359 
 360         @Override
 361         public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
 362             if (vars.contains(t)) {
 363                 if (seen.add(t)) {
 364                     try {
 365                         final Type bound;
 366                         switch (pkind) {
 367                             case UPWARDS:
 368                             case UPWARDS_NO_INTERSECTION:
 369                                 bound = t.getUpperBound();
 370                                 break;
 371                             case DOWNWARDS:
 372                             case DOWNWARDS_NO_INTERSECTION:
 373                                 bound = (t.getLowerBound() == null) ?
 374                                         syms.botType :
 375                                         t.getLowerBound();
 376                                 break;
 377                             default:
 378                                 Assert.error();
 379                                 return null;
 380                         }
 381                         return bound.map(this, pkind);
 382                     } finally {
 383                         seen.remove(t);
 384                     }
 385                 } else {
 386                     //cycle
 387                     return (pkind == ProjectionKind.UPWARDS || pkind == ProjectionKind.UPWARDS_NO_INTERSECTION) ?
 388                             syms.objectType : syms.botType;
 389                 }
 390             } else {
 391                 return t;
 392             }
 393         }
 394 
 395         private Type mapTypeArgument(Type site, Type declaredBound, Type t, ProjectionKind pkind) {
 396             return (t.containsAny(vars) || (!pkind.allowIntersectionTypes() && !chk.checkDenotable(t))) ?
 397                     t.map(new TypeArgumentProjection(site, declaredBound), pkind) :
 398                     t;
 399         }
 400 
 401         class TypeArgumentProjection extends TypeMapping<ProjectionKind> {
 402 
 403             Type site;
 404             Type declaredBound;
 405 
 406             TypeArgumentProjection(Type site, Type declaredBound) {
 407                 this.site = site;
 408                 this.declaredBound = declaredBound;
 409             }
 410 
 411             @Override
 412             public Type visitType(Type t, ProjectionKind pkind) {
 413                 //type argument is some type containing restricted vars
 414                 if (pkind == ProjectionKind.DOWNWARDS || pkind == ProjectionKind.DOWNWARDS_NO_INTERSECTION) {
 415                     //not defined
 416                     return syms.botType;
 417                 }
 418                 Type upper = t.map(TypeProjection.this, ProjectionKind.UPWARDS.withIntersectionTypes(pkind.allowIntersectionTypes()));
 419                 Type lower = t.map(TypeProjection.this, ProjectionKind.DOWNWARDS);
 420                 List<Type> formals = site.tsym.type.getTypeArguments();
 421                 BoundKind bk;
 422                 Type bound;
 423                 if (!isSameType(upper, syms.objectType) &&
 424                         (declaredBound.containsAny(formals) ||
 425                          !isSubtype(declaredBound, upper))) {
 426                     bound = upper;
 427                     bk = EXTENDS;
 428                 } else if (!lower.hasTag(BOT) && (!lower.isIntersection() || pkind.allowIntersectionTypes())) {
 429                     bound = lower;
 430                     bk = SUPER;
 431                 } else {
 432                     bound = syms.objectType;
 433                     bk = UNBOUND;
 434                 }
 435                 return makeWildcard(bound, bk);
 436             }
 437 
 438             @Override
 439             public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
 440                 //type argument is some wildcard whose bound contains restricted vars
 441                 Type bound = syms.botType;
 442                 BoundKind bk = wt.kind;
 443                 switch (wt.kind) {
 444                     case EXTENDS:
 445                         bound = wt.type.map(TypeProjection.this, pkind);
 446                         if (bound.hasTag(BOT)) {
 447                             return syms.botType;
 448                         }
 449                         break;
 450                     case SUPER:
 451                         bound = wt.type.map(TypeProjection.this, pkind.withIntersectionTypes(true).complement());
 452                         if (bound.hasTag(BOT) || (bound.isIntersection() && !pkind.allowIntersectionTypes())) {
 453                             bound = syms.objectType;
 454                             bk = UNBOUND;
 455                         }
 456                         break;
 457                 }
 458                 return makeWildcard(bound, bk);
 459             }
 460 
 461             private Type makeWildcard(Type bound, BoundKind bk) {
 462                 return new WildcardType(bound, bk, syms.boundClass) {
 463                     @Override
 464                     protected boolean needsStripping() {
 465                         return true;
 466                     }
 467                 };
 468             }
 469         }
 470     }
 471 
 472     /**
 473      * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
 474      *
 475      * @param t the type to be projected
 476      * @param vars the set of type variables to be mapped
 477      * @return the type obtained as result of the projection
 478      */
 479     public Type upward(Type t, List<Type> vars) {
 480         return upward(t, true, vars);
 481     }
 482 
 483     /**
 484      * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
 485      *
 486      * @param t the type to be projected
 487      * @param allowIntersection whether intersection types should be allowed in the projection
 488      * @param vars the set of type variables to be mapped
 489      * @return the type obtained as result of the projection
 490      */
 491     public Type upward(Type t, boolean allowIntersection, List<Type> vars) {
 492         return t.map(new TypeProjection(vars),
 493                 allowIntersection ? ProjectionKind.UPWARDS : ProjectionKind.UPWARDS_NO_INTERSECTION);
 494     }
 495 
 496     /**
 497      * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
 498      * This routine is typically used to computed the input set of variables to be used during
 499      * an upwards projection (see {@link Types#upward(Type, List)}).
 500      *
 501      * @param t the type where occurrences of captured variables have to be found
 502      * @return the set of captured variables found in t
 503      */
 504     public List<Type> captures(Type t) {
 505         CaptureScanner cs = new CaptureScanner();
 506         Set<Type> captures = new HashSet<>();
 507         cs.visit(t, captures);
 508         return List.from(captures);
 509     }
 510 
 511     /**
 512      * This visitor scans a type recursively looking for occurrences of captured type variables.
 513      */

5381                 return syms.doubleType;
5382             case ClassFile.CONSTANT_MethodHandle:
5383                 return syms.methodHandleType;
5384             case ClassFile.CONSTANT_MethodType:
5385                 return syms.methodTypeType;
5386             case ClassFile.CONSTANT_Dynamic:
5387                 return ((DynamicVarSymbol)c).type;
5388             default:
5389                 throw new AssertionError("Not a loadable constant: " + c.poolTag());
5390         }
5391     }
5392     // </editor-fold>
5393 
5394     public void newRound() {
5395         descCache._map.clear();
5396         isDerivedRawCache.clear();
5397         implCache._map.clear();
5398         membersCache._map.clear();
5399         closureCache.clear();
5400     }
5401 
5402     // code reflection
5403 
5404     public boolean isQuoted(Type type) {
5405         return type.tsym == syms.quotedType.tsym;
5406     }
5407 }
< prev index next >