Tue, 22 Oct 2013 10:08:49 +0200
8026857: AnnoConstruct.getAnnotationsByType does not search supertype for inherited annotations if @SomeContainer({}) is present
Summary: An empty container should not stop javac from looking at supertypes for inherited repeating annotations
Reviewed-by: jjg
duke@1 | 1 | /* |
jjg@1521 | 2 | * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. |
duke@1 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
duke@1 | 4 | * |
duke@1 | 5 | * This code is free software; you can redistribute it and/or modify it |
duke@1 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ohair@554 | 7 | * published by the Free Software Foundation. Oracle designates this |
duke@1 | 8 | * particular file as subject to the "Classpath" exception as provided |
ohair@554 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
duke@1 | 10 | * |
duke@1 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
duke@1 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
duke@1 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
duke@1 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
duke@1 | 15 | * accompanied this code). |
duke@1 | 16 | * |
duke@1 | 17 | * You should have received a copy of the GNU General Public License version |
duke@1 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
duke@1 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
duke@1 | 20 | * |
ohair@554 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
ohair@554 | 22 | * or visit www.oracle.com if you need additional information or have any |
ohair@554 | 23 | * questions. |
duke@1 | 24 | */ |
duke@1 | 25 | |
duke@1 | 26 | package com.sun.tools.javac.code; |
duke@1 | 27 | |
mcimadamore@341 | 28 | import java.lang.ref.SoftReference; |
jjg@1430 | 29 | import java.util.HashSet; |
jjg@1430 | 30 | import java.util.HashMap; |
jjg@1430 | 31 | import java.util.Locale; |
jjg@1430 | 32 | import java.util.Map; |
jjg@1430 | 33 | import java.util.Set; |
jjg@1430 | 34 | import java.util.WeakHashMap; |
duke@1 | 35 | |
mcimadamore@1882 | 36 | import javax.tools.JavaFileObject; |
mcimadamore@1882 | 37 | |
jjg@657 | 38 | import com.sun.tools.javac.code.Attribute.RetentionPolicy; |
mcimadamore@795 | 39 | import com.sun.tools.javac.code.Lint.LintCategory; |
mcimadamore@1338 | 40 | import com.sun.tools.javac.code.Type.UndetVar.InferenceBound; |
mcimadamore@1882 | 41 | import com.sun.tools.javac.comp.AttrContext; |
duke@1 | 42 | import com.sun.tools.javac.comp.Check; |
mcimadamore@1882 | 43 | import com.sun.tools.javac.comp.Enter; |
mcimadamore@1882 | 44 | import com.sun.tools.javac.comp.Env; |
jjg@1357 | 45 | import com.sun.tools.javac.jvm.ClassReader; |
jjg@1357 | 46 | import com.sun.tools.javac.util.*; |
jjg@1357 | 47 | import static com.sun.tools.javac.code.BoundKind.*; |
jjg@1357 | 48 | import static com.sun.tools.javac.code.Flags.*; |
mcimadamore@858 | 49 | import static com.sun.tools.javac.code.Scope.*; |
jjg@1357 | 50 | import static com.sun.tools.javac.code.Symbol.*; |
duke@1 | 51 | import static com.sun.tools.javac.code.Type.*; |
jjg@1374 | 52 | import static com.sun.tools.javac.code.TypeTag.*; |
rfield@1587 | 53 | import static com.sun.tools.javac.jvm.ClassFile.externalize; |
duke@1 | 54 | |
duke@1 | 55 | /** |
duke@1 | 56 | * Utility class containing various operations on types. |
duke@1 | 57 | * |
duke@1 | 58 | * <p>Unless other names are more illustrative, the following naming |
duke@1 | 59 | * conventions should be observed in this file: |
duke@1 | 60 | * |
duke@1 | 61 | * <dl> |
duke@1 | 62 | * <dt>t</dt> |
duke@1 | 63 | * <dd>If the first argument to an operation is a type, it should be named t.</dd> |
duke@1 | 64 | * <dt>s</dt> |
duke@1 | 65 | * <dd>Similarly, if the second argument to an operation is a type, it should be named s.</dd> |
duke@1 | 66 | * <dt>ts</dt> |
duke@1 | 67 | * <dd>If an operations takes a list of types, the first should be named ts.</dd> |
duke@1 | 68 | * <dt>ss</dt> |
duke@1 | 69 | * <dd>A second list of types should be named ss.</dd> |
duke@1 | 70 | * </dl> |
duke@1 | 71 | * |
jjg@581 | 72 | * <p><b>This is NOT part of any supported API. |
duke@1 | 73 | * If you write code that depends on this, you do so at your own risk. |
duke@1 | 74 | * This code and its internal interfaces are subject to change or |
duke@1 | 75 | * deletion without notice.</b> |
duke@1 | 76 | */ |
duke@1 | 77 | public class Types { |
duke@1 | 78 | protected static final Context.Key<Types> typesKey = |
duke@1 | 79 | new Context.Key<Types>(); |
duke@1 | 80 | |
duke@1 | 81 | final Symtab syms; |
mcimadamore@136 | 82 | final JavacMessages messages; |
jjg@113 | 83 | final Names names; |
duke@1 | 84 | final boolean allowBoxing; |
jjg@984 | 85 | final boolean allowCovariantReturns; |
jjg@984 | 86 | final boolean allowObjectToPrimitiveCast; |
mcimadamore@1393 | 87 | final boolean allowDefaultMethods; |
duke@1 | 88 | final ClassReader reader; |
duke@1 | 89 | final Check chk; |
mcimadamore@1882 | 90 | final Enter enter; |
mcimadamore@1348 | 91 | JCDiagnostic.Factory diags; |
duke@1 | 92 | List<Warner> warnStack = List.nil(); |
duke@1 | 93 | final Name capturedName; |
mcimadamore@1348 | 94 | private final FunctionDescriptorLookupError functionDescriptorLookupError; |
duke@1 | 95 | |
mcimadamore@1415 | 96 | public final Warner noWarnings; |
mcimadamore@1415 | 97 | |
duke@1 | 98 | // <editor-fold defaultstate="collapsed" desc="Instantiating"> |
duke@1 | 99 | public static Types instance(Context context) { |
duke@1 | 100 | Types instance = context.get(typesKey); |
duke@1 | 101 | if (instance == null) |
duke@1 | 102 | instance = new Types(context); |
duke@1 | 103 | return instance; |
duke@1 | 104 | } |
duke@1 | 105 | |
duke@1 | 106 | protected Types(Context context) { |
duke@1 | 107 | context.put(typesKey, this); |
duke@1 | 108 | syms = Symtab.instance(context); |
jjg@113 | 109 | names = Names.instance(context); |
jjg@984 | 110 | Source source = Source.instance(context); |
jjg@984 | 111 | allowBoxing = source.allowBoxing(); |
jjg@984 | 112 | allowCovariantReturns = source.allowCovariantReturns(); |
jjg@984 | 113 | allowObjectToPrimitiveCast = source.allowObjectToPrimitiveCast(); |
mcimadamore@1393 | 114 | allowDefaultMethods = source.allowDefaultMethods(); |
duke@1 | 115 | reader = ClassReader.instance(context); |
duke@1 | 116 | chk = Check.instance(context); |
mcimadamore@1882 | 117 | enter = Enter.instance(context); |
duke@1 | 118 | capturedName = names.fromString("<captured wildcard>"); |
mcimadamore@136 | 119 | messages = JavacMessages.instance(context); |
mcimadamore@1348 | 120 | diags = JCDiagnostic.Factory.instance(context); |
mcimadamore@1348 | 121 | functionDescriptorLookupError = new FunctionDescriptorLookupError(); |
mcimadamore@1415 | 122 | noWarnings = new Warner(null); |
duke@1 | 123 | } |
duke@1 | 124 | // </editor-fold> |
duke@1 | 125 | |
duke@1 | 126 | // <editor-fold defaultstate="collapsed" desc="upperBound"> |
duke@1 | 127 | /** |
duke@1 | 128 | * The "rvalue conversion".<br> |
duke@1 | 129 | * The upper bound of most types is the type |
duke@1 | 130 | * itself. Wildcards, on the other hand have upper |
duke@1 | 131 | * and lower bounds. |
duke@1 | 132 | * @param t a type |
duke@1 | 133 | * @return the upper bound of the given type |
duke@1 | 134 | */ |
duke@1 | 135 | public Type upperBound(Type t) { |
emc@1916 | 136 | return upperBound.visit(t).unannotatedType(); |
duke@1 | 137 | } |
duke@1 | 138 | // where |
duke@1 | 139 | private final MapVisitor<Void> upperBound = new MapVisitor<Void>() { |
duke@1 | 140 | |
duke@1 | 141 | @Override |
duke@1 | 142 | public Type visitWildcardType(WildcardType t, Void ignored) { |
duke@1 | 143 | if (t.isSuperBound()) |
duke@1 | 144 | return t.bound == null ? syms.objectType : t.bound.bound; |
duke@1 | 145 | else |
duke@1 | 146 | return visit(t.type); |
duke@1 | 147 | } |
duke@1 | 148 | |
duke@1 | 149 | @Override |
duke@1 | 150 | public Type visitCapturedType(CapturedType t, Void ignored) { |
duke@1 | 151 | return visit(t.bound); |
duke@1 | 152 | } |
duke@1 | 153 | }; |
duke@1 | 154 | // </editor-fold> |
duke@1 | 155 | |
duke@1 | 156 | // <editor-fold defaultstate="collapsed" desc="lowerBound"> |
duke@1 | 157 | /** |
duke@1 | 158 | * The "lvalue conversion".<br> |
duke@1 | 159 | * The lower bound of most types is the type |
duke@1 | 160 | * itself. Wildcards, on the other hand have upper |
duke@1 | 161 | * and lower bounds. |
duke@1 | 162 | * @param t a type |
duke@1 | 163 | * @return the lower bound of the given type |
duke@1 | 164 | */ |
duke@1 | 165 | public Type lowerBound(Type t) { |
duke@1 | 166 | return lowerBound.visit(t); |
duke@1 | 167 | } |
duke@1 | 168 | // where |
duke@1 | 169 | private final MapVisitor<Void> lowerBound = new MapVisitor<Void>() { |
duke@1 | 170 | |
duke@1 | 171 | @Override |
duke@1 | 172 | public Type visitWildcardType(WildcardType t, Void ignored) { |
duke@1 | 173 | return t.isExtendsBound() ? syms.botType : visit(t.type); |
duke@1 | 174 | } |
duke@1 | 175 | |
duke@1 | 176 | @Override |
duke@1 | 177 | public Type visitCapturedType(CapturedType t, Void ignored) { |
duke@1 | 178 | return visit(t.getLowerBound()); |
duke@1 | 179 | } |
duke@1 | 180 | }; |
duke@1 | 181 | // </editor-fold> |
duke@1 | 182 | |
duke@1 | 183 | // <editor-fold defaultstate="collapsed" desc="isUnbounded"> |
duke@1 | 184 | /** |
duke@1 | 185 | * Checks that all the arguments to a class are unbounded |
duke@1 | 186 | * wildcards or something else that doesn't make any restrictions |
duke@1 | 187 | * on the arguments. If a class isUnbounded, a raw super- or |
duke@1 | 188 | * subclass can be cast to it without a warning. |
duke@1 | 189 | * @param t a type |
duke@1 | 190 | * @return true iff the given type is unbounded or raw |
duke@1 | 191 | */ |
duke@1 | 192 | public boolean isUnbounded(Type t) { |
duke@1 | 193 | return isUnbounded.visit(t); |
duke@1 | 194 | } |
duke@1 | 195 | // where |
duke@1 | 196 | private final UnaryVisitor<Boolean> isUnbounded = new UnaryVisitor<Boolean>() { |
duke@1 | 197 | |
duke@1 | 198 | public Boolean visitType(Type t, Void ignored) { |
duke@1 | 199 | return true; |
duke@1 | 200 | } |
duke@1 | 201 | |
duke@1 | 202 | @Override |
duke@1 | 203 | public Boolean visitClassType(ClassType t, Void ignored) { |
duke@1 | 204 | List<Type> parms = t.tsym.type.allparams(); |
duke@1 | 205 | List<Type> args = t.allparams(); |
duke@1 | 206 | while (parms.nonEmpty()) { |
duke@1 | 207 | WildcardType unb = new WildcardType(syms.objectType, |
duke@1 | 208 | BoundKind.UNBOUND, |
duke@1 | 209 | syms.boundClass, |
jjg@1755 | 210 | (TypeVar)parms.head.unannotatedType()); |
duke@1 | 211 | if (!containsType(args.head, unb)) |
duke@1 | 212 | return false; |
duke@1 | 213 | parms = parms.tail; |
duke@1 | 214 | args = args.tail; |
duke@1 | 215 | } |
duke@1 | 216 | return true; |
duke@1 | 217 | } |
duke@1 | 218 | }; |
duke@1 | 219 | // </editor-fold> |
duke@1 | 220 | |
duke@1 | 221 | // <editor-fold defaultstate="collapsed" desc="asSub"> |
duke@1 | 222 | /** |
duke@1 | 223 | * Return the least specific subtype of t that starts with symbol |
duke@1 | 224 | * sym. If none exists, return null. The least specific subtype |
duke@1 | 225 | * is determined as follows: |
duke@1 | 226 | * |
duke@1 | 227 | * <p>If there is exactly one parameterized instance of sym that is a |
duke@1 | 228 | * subtype of t, that parameterized instance is returned.<br> |
duke@1 | 229 | * Otherwise, if the plain type or raw type `sym' is a subtype of |
duke@1 | 230 | * type t, the type `sym' itself is returned. Otherwise, null is |
duke@1 | 231 | * returned. |
duke@1 | 232 | */ |
duke@1 | 233 | public Type asSub(Type t, Symbol sym) { |
duke@1 | 234 | return asSub.visit(t, sym); |
duke@1 | 235 | } |
duke@1 | 236 | // where |
duke@1 | 237 | private final SimpleVisitor<Type,Symbol> asSub = new SimpleVisitor<Type,Symbol>() { |
duke@1 | 238 | |
duke@1 | 239 | public Type visitType(Type t, Symbol sym) { |
duke@1 | 240 | return null; |
duke@1 | 241 | } |
duke@1 | 242 | |
duke@1 | 243 | @Override |
duke@1 | 244 | public Type visitClassType(ClassType t, Symbol sym) { |
duke@1 | 245 | if (t.tsym == sym) |
duke@1 | 246 | return t; |
emc@2079 | 247 | Type base = asSuper(sym.type, t); |
duke@1 | 248 | if (base == null) |
duke@1 | 249 | return null; |
duke@1 | 250 | ListBuffer<Type> from = new ListBuffer<Type>(); |
duke@1 | 251 | ListBuffer<Type> to = new ListBuffer<Type>(); |
duke@1 | 252 | try { |
duke@1 | 253 | adapt(base, t, from, to); |
duke@1 | 254 | } catch (AdaptFailure ex) { |
duke@1 | 255 | return null; |
duke@1 | 256 | } |
duke@1 | 257 | Type res = subst(sym.type, from.toList(), to.toList()); |
duke@1 | 258 | if (!isSubtype(res, t)) |
duke@1 | 259 | return null; |
duke@1 | 260 | ListBuffer<Type> openVars = new ListBuffer<Type>(); |
duke@1 | 261 | for (List<Type> l = sym.type.allparams(); |
duke@1 | 262 | l.nonEmpty(); l = l.tail) |
duke@1 | 263 | if (res.contains(l.head) && !t.contains(l.head)) |
duke@1 | 264 | openVars.append(l.head); |
duke@1 | 265 | if (openVars.nonEmpty()) { |
duke@1 | 266 | if (t.isRaw()) { |
duke@1 | 267 | // The subtype of a raw type is raw |
duke@1 | 268 | res = erasure(res); |
duke@1 | 269 | } else { |
duke@1 | 270 | // Unbound type arguments default to ? |
duke@1 | 271 | List<Type> opens = openVars.toList(); |
duke@1 | 272 | ListBuffer<Type> qs = new ListBuffer<Type>(); |
duke@1 | 273 | for (List<Type> iter = opens; iter.nonEmpty(); iter = iter.tail) { |
jjg@1755 | 274 | qs.append(new WildcardType(syms.objectType, BoundKind.UNBOUND, syms.boundClass, (TypeVar) iter.head.unannotatedType())); |
duke@1 | 275 | } |
duke@1 | 276 | res = subst(res, opens, qs.toList()); |
duke@1 | 277 | } |
duke@1 | 278 | } |
duke@1 | 279 | return res; |
duke@1 | 280 | } |
duke@1 | 281 | |
duke@1 | 282 | @Override |
duke@1 | 283 | public Type visitErrorType(ErrorType t, Symbol sym) { |
duke@1 | 284 | return t; |
duke@1 | 285 | } |
duke@1 | 286 | }; |
duke@1 | 287 | // </editor-fold> |
duke@1 | 288 | |
duke@1 | 289 | // <editor-fold defaultstate="collapsed" desc="isConvertible"> |
duke@1 | 290 | /** |
mcimadamore@1071 | 291 | * Is t a subtype of or convertible via boxing/unboxing |
mcimadamore@1071 | 292 | * conversion to s? |
duke@1 | 293 | */ |
duke@1 | 294 | public boolean isConvertible(Type t, Type s, Warner warn) { |
vromero@1853 | 295 | if (t.hasTag(ERROR)) { |
mcimadamore@1071 | 296 | return true; |
vromero@1853 | 297 | } |
duke@1 | 298 | boolean tPrimitive = t.isPrimitive(); |
duke@1 | 299 | boolean sPrimitive = s.isPrimitive(); |
mcimadamore@795 | 300 | if (tPrimitive == sPrimitive) { |
duke@1 | 301 | return isSubtypeUnchecked(t, s, warn); |
mcimadamore@795 | 302 | } |
duke@1 | 303 | if (!allowBoxing) return false; |
duke@1 | 304 | return tPrimitive |
duke@1 | 305 | ? isSubtype(boxedClass(t).type, s) |
duke@1 | 306 | : isSubtype(unboxedType(t), s); |
duke@1 | 307 | } |
duke@1 | 308 | |
duke@1 | 309 | /** |
duke@1 | 310 | * Is t a subtype of or convertiable via boxing/unboxing |
duke@1 | 311 | * convertions to s? |
duke@1 | 312 | */ |
duke@1 | 313 | public boolean isConvertible(Type t, Type s) { |
mcimadamore@1415 | 314 | return isConvertible(t, s, noWarnings); |
duke@1 | 315 | } |
duke@1 | 316 | // </editor-fold> |
duke@1 | 317 | |
mcimadamore@1348 | 318 | // <editor-fold defaultstate="collapsed" desc="findSam"> |
mcimadamore@1348 | 319 | |
mcimadamore@1348 | 320 | /** |
mcimadamore@1348 | 321 | * Exception used to report a function descriptor lookup failure. The exception |
mcimadamore@1348 | 322 | * wraps a diagnostic that can be used to generate more details error |
mcimadamore@1348 | 323 | * messages. |
mcimadamore@1348 | 324 | */ |
mcimadamore@1348 | 325 | public static class FunctionDescriptorLookupError extends RuntimeException { |
mcimadamore@1348 | 326 | private static final long serialVersionUID = 0; |
mcimadamore@1348 | 327 | |
mcimadamore@1348 | 328 | JCDiagnostic diagnostic; |
mcimadamore@1348 | 329 | |
mcimadamore@1348 | 330 | FunctionDescriptorLookupError() { |
mcimadamore@1348 | 331 | this.diagnostic = null; |
mcimadamore@1348 | 332 | } |
mcimadamore@1348 | 333 | |
mcimadamore@1348 | 334 | FunctionDescriptorLookupError setMessage(JCDiagnostic diag) { |
mcimadamore@1348 | 335 | this.diagnostic = diag; |
mcimadamore@1348 | 336 | return this; |
mcimadamore@1348 | 337 | } |
mcimadamore@1348 | 338 | |
mcimadamore@1348 | 339 | public JCDiagnostic getDiagnostic() { |
mcimadamore@1348 | 340 | return diagnostic; |
mcimadamore@1348 | 341 | } |
mcimadamore@1348 | 342 | } |
mcimadamore@1348 | 343 | |
mcimadamore@1348 | 344 | /** |
mcimadamore@1348 | 345 | * A cache that keeps track of function descriptors associated with given |
mcimadamore@1348 | 346 | * functional interfaces. |
mcimadamore@1348 | 347 | */ |
mcimadamore@1348 | 348 | class DescriptorCache { |
mcimadamore@1348 | 349 | |
mcimadamore@1348 | 350 | private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<TypeSymbol, Entry>(); |
mcimadamore@1348 | 351 | |
mcimadamore@1348 | 352 | class FunctionDescriptor { |
mcimadamore@1348 | 353 | Symbol descSym; |
mcimadamore@1348 | 354 | |
mcimadamore@1348 | 355 | FunctionDescriptor(Symbol descSym) { |
mcimadamore@1348 | 356 | this.descSym = descSym; |
mcimadamore@1348 | 357 | } |
mcimadamore@1348 | 358 | |
mcimadamore@1348 | 359 | public Symbol getSymbol() { |
mcimadamore@1348 | 360 | return descSym; |
mcimadamore@1348 | 361 | } |
mcimadamore@1348 | 362 | |
mcimadamore@1510 | 363 | public Type getType(Type site) { |
mcimadamore@1579 | 364 | site = removeWildcards(site); |
mcimadamore@1579 | 365 | if (!chk.checkValidGenericType(site)) { |
mcimadamore@1579 | 366 | //if the inferred functional interface type is not well-formed, |
mcimadamore@1579 | 367 | //or if it's not a subtype of the original target, issue an error |
mcimadamore@1579 | 368 | throw failure(diags.fragment("no.suitable.functional.intf.inst", site)); |
mcimadamore@1510 | 369 | } |
mcimadamore@1510 | 370 | return memberType(site, descSym); |
mcimadamore@1348 | 371 | } |
mcimadamore@1348 | 372 | } |
mcimadamore@1348 | 373 | |
mcimadamore@1348 | 374 | class Entry { |
mcimadamore@1348 | 375 | final FunctionDescriptor cachedDescRes; |
mcimadamore@1348 | 376 | final int prevMark; |
mcimadamore@1348 | 377 | |
mcimadamore@1348 | 378 | public Entry(FunctionDescriptor cachedDescRes, |
mcimadamore@1348 | 379 | int prevMark) { |
mcimadamore@1348 | 380 | this.cachedDescRes = cachedDescRes; |
mcimadamore@1348 | 381 | this.prevMark = prevMark; |
mcimadamore@1348 | 382 | } |
mcimadamore@1348 | 383 | |
mcimadamore@1348 | 384 | boolean matches(int mark) { |
mcimadamore@1348 | 385 | return this.prevMark == mark; |
mcimadamore@1348 | 386 | } |
mcimadamore@1348 | 387 | } |
mcimadamore@1348 | 388 | |
mcimadamore@1348 | 389 | FunctionDescriptor get(TypeSymbol origin) throws FunctionDescriptorLookupError { |
mcimadamore@1348 | 390 | Entry e = _map.get(origin); |
mcimadamore@1348 | 391 | CompoundScope members = membersClosure(origin.type, false); |
mcimadamore@1348 | 392 | if (e == null || |
mcimadamore@1348 | 393 | !e.matches(members.getMark())) { |
mcimadamore@1348 | 394 | FunctionDescriptor descRes = findDescriptorInternal(origin, members); |
mcimadamore@1348 | 395 | _map.put(origin, new Entry(descRes, members.getMark())); |
mcimadamore@1348 | 396 | return descRes; |
mcimadamore@1348 | 397 | } |
mcimadamore@1348 | 398 | else { |
mcimadamore@1348 | 399 | return e.cachedDescRes; |
mcimadamore@1348 | 400 | } |
mcimadamore@1348 | 401 | } |
mcimadamore@1348 | 402 | |
mcimadamore@1348 | 403 | /** |
mcimadamore@1348 | 404 | * Compute the function descriptor associated with a given functional interface |
mcimadamore@1348 | 405 | */ |
vromero@1853 | 406 | public FunctionDescriptor findDescriptorInternal(TypeSymbol origin, |
vromero@1853 | 407 | CompoundScope membersCache) throws FunctionDescriptorLookupError { |
mcimadamore@1497 | 408 | if (!origin.isInterface() || (origin.flags() & ANNOTATION) != 0) { |
mcimadamore@1348 | 409 | //t must be an interface |
mcimadamore@1497 | 410 | throw failure("not.a.functional.intf", origin); |
mcimadamore@1348 | 411 | } |
mcimadamore@1348 | 412 | |
alundblad@2047 | 413 | final ListBuffer<Symbol> abstracts = new ListBuffer<>(); |
mcimadamore@1348 | 414 | for (Symbol sym : membersCache.getElements(new DescriptorFilter(origin))) { |
mcimadamore@1348 | 415 | Type mtype = memberType(origin.type, sym); |
mcimadamore@1348 | 416 | if (abstracts.isEmpty() || |
mcimadamore@1348 | 417 | (sym.name == abstracts.first().name && |
mcimadamore@1348 | 418 | overrideEquivalent(mtype, memberType(origin.type, abstracts.first())))) { |
mcimadamore@1348 | 419 | abstracts.append(sym); |
mcimadamore@1348 | 420 | } else { |
mcimadamore@1348 | 421 | //the target method(s) should be the only abstract members of t |
mcimadamore@1497 | 422 | throw failure("not.a.functional.intf.1", origin, |
mcimadamore@1348 | 423 | diags.fragment("incompatible.abstracts", Kinds.kindName(origin), origin)); |
mcimadamore@1348 | 424 | } |
mcimadamore@1348 | 425 | } |
mcimadamore@1348 | 426 | if (abstracts.isEmpty()) { |
mcimadamore@1348 | 427 | //t must define a suitable non-generic method |
mcimadamore@1497 | 428 | throw failure("not.a.functional.intf.1", origin, |
mcimadamore@1348 | 429 | diags.fragment("no.abstracts", Kinds.kindName(origin), origin)); |
mcimadamore@1348 | 430 | } else if (abstracts.size() == 1) { |
mcimadamore@1434 | 431 | return new FunctionDescriptor(abstracts.first()); |
mcimadamore@1348 | 432 | } else { // size > 1 |
mcimadamore@1348 | 433 | FunctionDescriptor descRes = mergeDescriptors(origin, abstracts.toList()); |
mcimadamore@1348 | 434 | if (descRes == null) { |
mcimadamore@1348 | 435 | //we can get here if the functional interface is ill-formed |
alundblad@2047 | 436 | ListBuffer<JCDiagnostic> descriptors = new ListBuffer<>(); |
mcimadamore@1348 | 437 | for (Symbol desc : abstracts) { |
mcimadamore@1348 | 438 | String key = desc.type.getThrownTypes().nonEmpty() ? |
mcimadamore@1348 | 439 | "descriptor.throws" : "descriptor"; |
mcimadamore@1348 | 440 | descriptors.append(diags.fragment(key, desc.name, |
mcimadamore@1348 | 441 | desc.type.getParameterTypes(), |
mcimadamore@1348 | 442 | desc.type.getReturnType(), |
mcimadamore@1348 | 443 | desc.type.getThrownTypes())); |
mcimadamore@1348 | 444 | } |
mcimadamore@1348 | 445 | JCDiagnostic.MultilineDiagnostic incompatibleDescriptors = |
mcimadamore@1348 | 446 | new JCDiagnostic.MultilineDiagnostic(diags.fragment("incompatible.descs.in.functional.intf", |
mcimadamore@1348 | 447 | Kinds.kindName(origin), origin), descriptors.toList()); |
mcimadamore@1348 | 448 | throw failure(incompatibleDescriptors); |
mcimadamore@1348 | 449 | } |
mcimadamore@1348 | 450 | return descRes; |
mcimadamore@1348 | 451 | } |
mcimadamore@1348 | 452 | } |
mcimadamore@1348 | 453 | |
mcimadamore@1348 | 454 | /** |
mcimadamore@1348 | 455 | * Compute a synthetic type for the target descriptor given a list |
mcimadamore@1348 | 456 | * of override-equivalent methods in the functional interface type. |
mcimadamore@1348 | 457 | * The resulting method type is a method type that is override-equivalent |
mcimadamore@1348 | 458 | * and return-type substitutable with each method in the original list. |
mcimadamore@1348 | 459 | */ |
mcimadamore@1348 | 460 | private FunctionDescriptor mergeDescriptors(TypeSymbol origin, List<Symbol> methodSyms) { |
mcimadamore@1348 | 461 | //pick argument types - simply take the signature that is a |
mcimadamore@1348 | 462 | //subsignature of all other signatures in the list (as per JLS 8.4.2) |
mcimadamore@1348 | 463 | List<Symbol> mostSpecific = List.nil(); |
mcimadamore@1348 | 464 | outer: for (Symbol msym1 : methodSyms) { |
mcimadamore@1348 | 465 | Type mt1 = memberType(origin.type, msym1); |
mcimadamore@1348 | 466 | for (Symbol msym2 : methodSyms) { |
mcimadamore@1348 | 467 | Type mt2 = memberType(origin.type, msym2); |
mcimadamore@1348 | 468 | if (!isSubSignature(mt1, mt2)) { |
mcimadamore@1348 | 469 | continue outer; |
mcimadamore@1348 | 470 | } |
mcimadamore@1348 | 471 | } |
mcimadamore@1348 | 472 | mostSpecific = mostSpecific.prepend(msym1); |
mcimadamore@1348 | 473 | } |
mcimadamore@1348 | 474 | if (mostSpecific.isEmpty()) { |
mcimadamore@1348 | 475 | return null; |
mcimadamore@1348 | 476 | } |
mcimadamore@1348 | 477 | |
mcimadamore@1348 | 478 | |
mcimadamore@1348 | 479 | //pick return types - this is done in two phases: (i) first, the most |
mcimadamore@1348 | 480 | //specific return type is chosen using strict subtyping; if this fails, |
mcimadamore@1348 | 481 | //a second attempt is made using return type substitutability (see JLS 8.4.5) |
mcimadamore@1348 | 482 | boolean phase2 = false; |
mcimadamore@1348 | 483 | Symbol bestSoFar = null; |
mcimadamore@1348 | 484 | while (bestSoFar == null) { |
mcimadamore@1348 | 485 | outer: for (Symbol msym1 : mostSpecific) { |
mcimadamore@1348 | 486 | Type mt1 = memberType(origin.type, msym1); |
mcimadamore@1348 | 487 | for (Symbol msym2 : methodSyms) { |
mcimadamore@1348 | 488 | Type mt2 = memberType(origin.type, msym2); |
mcimadamore@1348 | 489 | if (phase2 ? |
mcimadamore@1348 | 490 | !returnTypeSubstitutable(mt1, mt2) : |
mcimadamore@1348 | 491 | !isSubtypeInternal(mt1.getReturnType(), mt2.getReturnType())) { |
mcimadamore@1348 | 492 | continue outer; |
mcimadamore@1348 | 493 | } |
mcimadamore@1348 | 494 | } |
mcimadamore@1348 | 495 | bestSoFar = msym1; |
mcimadamore@1348 | 496 | } |
mcimadamore@1348 | 497 | if (phase2) { |
mcimadamore@1348 | 498 | break; |
mcimadamore@1348 | 499 | } else { |
mcimadamore@1348 | 500 | phase2 = true; |
mcimadamore@1348 | 501 | } |
mcimadamore@1348 | 502 | } |
mcimadamore@1348 | 503 | if (bestSoFar == null) return null; |
mcimadamore@1348 | 504 | |
mcimadamore@1348 | 505 | //merge thrown types - form the intersection of all the thrown types in |
mcimadamore@1348 | 506 | //all the signatures in the list |
vromero@1973 | 507 | boolean toErase = !bestSoFar.type.hasTag(FORALL); |
mcimadamore@1348 | 508 | List<Type> thrown = null; |
vromero@1973 | 509 | Type mt1 = memberType(origin.type, bestSoFar); |
vromero@1973 | 510 | for (Symbol msym2 : methodSyms) { |
vromero@1973 | 511 | Type mt2 = memberType(origin.type, msym2); |
vromero@1973 | 512 | List<Type> thrown_mt2 = mt2.getThrownTypes(); |
vromero@1973 | 513 | if (toErase) { |
vromero@1973 | 514 | thrown_mt2 = erasure(thrown_mt2); |
vromero@1973 | 515 | } else { |
vromero@1973 | 516 | /* If bestSoFar is generic then all the methods are generic. |
vromero@1973 | 517 | * The opposite is not true: a non generic method can override |
vromero@1973 | 518 | * a generic method (raw override) so it's safe to cast mt1 and |
vromero@1973 | 519 | * mt2 to ForAll. |
vromero@1973 | 520 | */ |
vromero@1973 | 521 | ForAll fa1 = (ForAll)mt1; |
vromero@1973 | 522 | ForAll fa2 = (ForAll)mt2; |
vromero@1973 | 523 | thrown_mt2 = subst(thrown_mt2, fa2.tvars, fa1.tvars); |
vromero@1973 | 524 | } |
mcimadamore@1348 | 525 | thrown = (thrown == null) ? |
vromero@1973 | 526 | thrown_mt2 : |
vromero@1973 | 527 | chk.intersect(thrown_mt2, thrown); |
mcimadamore@1348 | 528 | } |
mcimadamore@1348 | 529 | |
mcimadamore@1348 | 530 | final List<Type> thrown1 = thrown; |
mcimadamore@1348 | 531 | return new FunctionDescriptor(bestSoFar) { |
mcimadamore@1348 | 532 | @Override |
mcimadamore@1348 | 533 | public Type getType(Type origin) { |
mcimadamore@1348 | 534 | Type mt = memberType(origin, getSymbol()); |
mcimadamore@1600 | 535 | return createMethodTypeWithThrown(mt, thrown1); |
mcimadamore@1348 | 536 | } |
mcimadamore@1348 | 537 | }; |
mcimadamore@1348 | 538 | } |
mcimadamore@1348 | 539 | |
mcimadamore@1348 | 540 | boolean isSubtypeInternal(Type s, Type t) { |
mcimadamore@1348 | 541 | return (s.isPrimitive() && t.isPrimitive()) ? |
mcimadamore@1348 | 542 | isSameType(t, s) : |
mcimadamore@1348 | 543 | isSubtype(s, t); |
mcimadamore@1348 | 544 | } |
mcimadamore@1348 | 545 | |
mcimadamore@1348 | 546 | FunctionDescriptorLookupError failure(String msg, Object... args) { |
mcimadamore@1348 | 547 | return failure(diags.fragment(msg, args)); |
mcimadamore@1348 | 548 | } |
mcimadamore@1348 | 549 | |
mcimadamore@1348 | 550 | FunctionDescriptorLookupError failure(JCDiagnostic diag) { |
mcimadamore@1348 | 551 | return functionDescriptorLookupError.setMessage(diag); |
mcimadamore@1348 | 552 | } |
mcimadamore@1348 | 553 | } |
mcimadamore@1348 | 554 | |
mcimadamore@1348 | 555 | private DescriptorCache descCache = new DescriptorCache(); |
mcimadamore@1348 | 556 | |
mcimadamore@1348 | 557 | /** |
mcimadamore@1348 | 558 | * Find the method descriptor associated to this class symbol - if the |
mcimadamore@1348 | 559 | * symbol 'origin' is not a functional interface, an exception is thrown. |
mcimadamore@1348 | 560 | */ |
mcimadamore@1348 | 561 | public Symbol findDescriptorSymbol(TypeSymbol origin) throws FunctionDescriptorLookupError { |
mcimadamore@1348 | 562 | return descCache.get(origin).getSymbol(); |
mcimadamore@1348 | 563 | } |
mcimadamore@1348 | 564 | |
mcimadamore@1348 | 565 | /** |
mcimadamore@1348 | 566 | * Find the type of the method descriptor associated to this class symbol - |
mcimadamore@1348 | 567 | * if the symbol 'origin' is not a functional interface, an exception is thrown. |
mcimadamore@1348 | 568 | */ |
mcimadamore@1348 | 569 | public Type findDescriptorType(Type origin) throws FunctionDescriptorLookupError { |
mcimadamore@1348 | 570 | return descCache.get(origin.tsym).getType(origin); |
mcimadamore@1348 | 571 | } |
mcimadamore@1348 | 572 | |
mcimadamore@1348 | 573 | /** |
mcimadamore@1348 | 574 | * Is given type a functional interface? |
mcimadamore@1348 | 575 | */ |
mcimadamore@1348 | 576 | public boolean isFunctionalInterface(TypeSymbol tsym) { |
mcimadamore@1348 | 577 | try { |
mcimadamore@1348 | 578 | findDescriptorSymbol(tsym); |
mcimadamore@1348 | 579 | return true; |
mcimadamore@1348 | 580 | } catch (FunctionDescriptorLookupError ex) { |
mcimadamore@1348 | 581 | return false; |
mcimadamore@1348 | 582 | } |
mcimadamore@1348 | 583 | } |
mcimadamore@1510 | 584 | |
mcimadamore@1510 | 585 | public boolean isFunctionalInterface(Type site) { |
mcimadamore@1510 | 586 | try { |
mcimadamore@1510 | 587 | findDescriptorType(site); |
mcimadamore@1510 | 588 | return true; |
mcimadamore@1510 | 589 | } catch (FunctionDescriptorLookupError ex) { |
mcimadamore@1510 | 590 | return false; |
mcimadamore@1510 | 591 | } |
mcimadamore@1510 | 592 | } |
mcimadamore@1579 | 593 | |
mcimadamore@1579 | 594 | public Type removeWildcards(Type site) { |
mcimadamore@1605 | 595 | Type capturedSite = capture(site); |
mcimadamore@1605 | 596 | if (capturedSite != site) { |
mcimadamore@1579 | 597 | Type formalInterface = site.tsym.type; |
alundblad@2047 | 598 | ListBuffer<Type> typeargs = new ListBuffer<>(); |
mcimadamore@1579 | 599 | List<Type> actualTypeargs = site.getTypeArguments(); |
mcimadamore@1605 | 600 | List<Type> capturedTypeargs = capturedSite.getTypeArguments(); |
mcimadamore@1579 | 601 | //simply replace the wildcards with its bound |
mcimadamore@1579 | 602 | for (Type t : formalInterface.getTypeArguments()) { |
mcimadamore@1579 | 603 | if (actualTypeargs.head.hasTag(WILDCARD)) { |
jjg@1755 | 604 | WildcardType wt = (WildcardType)actualTypeargs.head.unannotatedType(); |
mcimadamore@1598 | 605 | Type bound; |
mcimadamore@1598 | 606 | switch (wt.kind) { |
mcimadamore@1605 | 607 | case EXTENDS: |
mcimadamore@1598 | 608 | case UNBOUND: |
jjg@1755 | 609 | CapturedType capVar = (CapturedType)capturedTypeargs.head.unannotatedType(); |
mcimadamore@1598 | 610 | //use declared bound if it doesn't depend on formal type-args |
mcimadamore@1605 | 611 | bound = capVar.bound.containsAny(capturedSite.getTypeArguments()) ? |
mcimadamore@1695 | 612 | wt.type : capVar.bound; |
mcimadamore@1598 | 613 | break; |
mcimadamore@1598 | 614 | default: |
mcimadamore@1598 | 615 | bound = wt.type; |
mcimadamore@1598 | 616 | } |
mcimadamore@1598 | 617 | typeargs.append(bound); |
mcimadamore@1579 | 618 | } else { |
mcimadamore@1579 | 619 | typeargs.append(actualTypeargs.head); |
mcimadamore@1579 | 620 | } |
mcimadamore@1579 | 621 | actualTypeargs = actualTypeargs.tail; |
mcimadamore@1605 | 622 | capturedTypeargs = capturedTypeargs.tail; |
mcimadamore@1579 | 623 | } |
mcimadamore@1579 | 624 | return subst(formalInterface, formalInterface.getTypeArguments(), typeargs.toList()); |
mcimadamore@1579 | 625 | } else { |
mcimadamore@1579 | 626 | return site; |
mcimadamore@1579 | 627 | } |
mcimadamore@1579 | 628 | } |
mcimadamore@1882 | 629 | |
mcimadamore@1882 | 630 | /** |
mcimadamore@1882 | 631 | * Create a symbol for a class that implements a given functional interface |
mcimadamore@1882 | 632 | * and overrides its functional descriptor. This routine is used for two |
mcimadamore@1882 | 633 | * main purposes: (i) checking well-formedness of a functional interface; |
mcimadamore@1882 | 634 | * (ii) perform functional interface bridge calculation. |
mcimadamore@1882 | 635 | */ |
mcimadamore@1882 | 636 | public ClassSymbol makeFunctionalInterfaceClass(Env<AttrContext> env, Name name, List<Type> targets, long cflags) { |
mcimadamore@1919 | 637 | if (targets.isEmpty() || !isFunctionalInterface(targets.head)) { |
mcimadamore@1919 | 638 | return null; |
mcimadamore@1919 | 639 | } |
mcimadamore@1882 | 640 | Symbol descSym = findDescriptorSymbol(targets.head.tsym); |
mcimadamore@1882 | 641 | Type descType = findDescriptorType(targets.head); |
mcimadamore@1882 | 642 | ClassSymbol csym = new ClassSymbol(cflags, name, env.enclClass.sym.outermostClass()); |
mcimadamore@1882 | 643 | csym.completer = null; |
mcimadamore@1882 | 644 | csym.members_field = new Scope(csym); |
mcimadamore@1882 | 645 | MethodSymbol instDescSym = new MethodSymbol(descSym.flags(), descSym.name, descType, csym); |
mcimadamore@1882 | 646 | csym.members_field.enter(instDescSym); |
mcimadamore@1882 | 647 | Type.ClassType ctype = new Type.ClassType(Type.noType, List.<Type>nil(), csym); |
mcimadamore@1882 | 648 | ctype.supertype_field = syms.objectType; |
mcimadamore@1882 | 649 | ctype.interfaces_field = targets; |
mcimadamore@1882 | 650 | csym.type = ctype; |
mcimadamore@1882 | 651 | csym.sourcefile = ((ClassSymbol)csym.owner).sourcefile; |
mcimadamore@1882 | 652 | return csym; |
mcimadamore@1882 | 653 | } |
mcimadamore@1882 | 654 | |
mcimadamore@1882 | 655 | /** |
mcimadamore@1882 | 656 | * Find the minimal set of methods that are overridden by the functional |
mcimadamore@1882 | 657 | * descriptor in 'origin'. All returned methods are assumed to have different |
mcimadamore@1882 | 658 | * erased signatures. |
mcimadamore@1882 | 659 | */ |
mcimadamore@1882 | 660 | public List<Symbol> functionalInterfaceBridges(TypeSymbol origin) { |
mcimadamore@1882 | 661 | Assert.check(isFunctionalInterface(origin)); |
mcimadamore@1882 | 662 | Symbol descSym = findDescriptorSymbol(origin); |
mcimadamore@1882 | 663 | CompoundScope members = membersClosure(origin.type, false); |
alundblad@2047 | 664 | ListBuffer<Symbol> overridden = new ListBuffer<>(); |
mcimadamore@1882 | 665 | outer: for (Symbol m2 : members.getElementsByName(descSym.name, bridgeFilter)) { |
mcimadamore@1882 | 666 | if (m2 == descSym) continue; |
mcimadamore@1882 | 667 | else if (descSym.overrides(m2, origin, Types.this, false)) { |
mcimadamore@1882 | 668 | for (Symbol m3 : overridden) { |
mcimadamore@1882 | 669 | if (isSameType(m3.erasure(Types.this), m2.erasure(Types.this)) || |
mcimadamore@1882 | 670 | (m3.overrides(m2, origin, Types.this, false) && |
mcimadamore@1882 | 671 | (pendingBridges((ClassSymbol)origin, m3.enclClass()) || |
mcimadamore@1882 | 672 | (((MethodSymbol)m2).binaryImplementation((ClassSymbol)m3.owner, Types.this) != null)))) { |
mcimadamore@1882 | 673 | continue outer; |
mcimadamore@1882 | 674 | } |
mcimadamore@1882 | 675 | } |
mcimadamore@1882 | 676 | overridden.add(m2); |
mcimadamore@1882 | 677 | } |
mcimadamore@1882 | 678 | } |
mcimadamore@1882 | 679 | return overridden.toList(); |
mcimadamore@1882 | 680 | } |
mcimadamore@1882 | 681 | //where |
mcimadamore@1882 | 682 | private Filter<Symbol> bridgeFilter = new Filter<Symbol>() { |
mcimadamore@1882 | 683 | public boolean accepts(Symbol t) { |
mcimadamore@1882 | 684 | return t.kind == Kinds.MTH && |
mcimadamore@1882 | 685 | t.name != names.init && |
mcimadamore@1882 | 686 | t.name != names.clinit && |
mcimadamore@1882 | 687 | (t.flags() & SYNTHETIC) == 0; |
mcimadamore@1882 | 688 | } |
mcimadamore@1882 | 689 | }; |
emc@2079 | 690 | private boolean pendingBridges(ClassSymbol origin, TypeSymbol sym) { |
mcimadamore@1882 | 691 | //a symbol will be completed from a classfile if (a) symbol has |
mcimadamore@1882 | 692 | //an associated file object with CLASS kind and (b) the symbol has |
mcimadamore@1882 | 693 | //not been entered |
mcimadamore@1882 | 694 | if (origin.classfile != null && |
mcimadamore@1882 | 695 | origin.classfile.getKind() == JavaFileObject.Kind.CLASS && |
mcimadamore@1882 | 696 | enter.getEnv(origin) == null) { |
mcimadamore@1882 | 697 | return false; |
mcimadamore@1882 | 698 | } |
emc@2079 | 699 | if (origin == sym) { |
mcimadamore@1882 | 700 | return true; |
mcimadamore@1882 | 701 | } |
mcimadamore@1882 | 702 | for (Type t : interfaces(origin.type)) { |
emc@2079 | 703 | if (pendingBridges((ClassSymbol)t.tsym, sym)) { |
mcimadamore@1882 | 704 | return true; |
mcimadamore@1882 | 705 | } |
mcimadamore@1882 | 706 | } |
mcimadamore@1882 | 707 | return false; |
mcimadamore@1882 | 708 | } |
mcimadamore@1348 | 709 | // </editor-fold> |
mcimadamore@1348 | 710 | |
mcimadamore@1436 | 711 | /** |
mcimadamore@1436 | 712 | * Scope filter used to skip methods that should be ignored (such as methods |
mcimadamore@1678 | 713 | * overridden by j.l.Object) during function interface conversion interface check |
mcimadamore@1436 | 714 | */ |
mcimadamore@1436 | 715 | class DescriptorFilter implements Filter<Symbol> { |
mcimadamore@1436 | 716 | |
mcimadamore@1436 | 717 | TypeSymbol origin; |
mcimadamore@1436 | 718 | |
mcimadamore@1436 | 719 | DescriptorFilter(TypeSymbol origin) { |
mcimadamore@1436 | 720 | this.origin = origin; |
mcimadamore@1436 | 721 | } |
mcimadamore@1436 | 722 | |
mcimadamore@1436 | 723 | @Override |
mcimadamore@1436 | 724 | public boolean accepts(Symbol sym) { |
mcimadamore@1436 | 725 | return sym.kind == Kinds.MTH && |
mcimadamore@1436 | 726 | (sym.flags() & (ABSTRACT | DEFAULT)) == ABSTRACT && |
mcimadamore@1436 | 727 | !overridesObjectMethod(origin, sym) && |
mcimadamore@1436 | 728 | (interfaceCandidates(origin.type, (MethodSymbol)sym).head.flags() & DEFAULT) == 0; |
mcimadamore@1436 | 729 | } |
mcimadamore@1436 | 730 | }; |
mcimadamore@1436 | 731 | |
duke@1 | 732 | // <editor-fold defaultstate="collapsed" desc="isSubtype"> |
duke@1 | 733 | /** |
duke@1 | 734 | * Is t an unchecked subtype of s? |
duke@1 | 735 | */ |
duke@1 | 736 | public boolean isSubtypeUnchecked(Type t, Type s) { |
mcimadamore@1415 | 737 | return isSubtypeUnchecked(t, s, noWarnings); |
duke@1 | 738 | } |
duke@1 | 739 | /** |
duke@1 | 740 | * Is t an unchecked subtype of s? |
duke@1 | 741 | */ |
duke@1 | 742 | public boolean isSubtypeUnchecked(Type t, Type s, Warner warn) { |
mcimadamore@1108 | 743 | boolean result = isSubtypeUncheckedInternal(t, s, warn); |
mcimadamore@1108 | 744 | if (result) { |
mcimadamore@1108 | 745 | checkUnsafeVarargsConversion(t, s, warn); |
mcimadamore@1108 | 746 | } |
mcimadamore@1108 | 747 | return result; |
mcimadamore@1108 | 748 | } |
mcimadamore@1108 | 749 | //where |
mcimadamore@1108 | 750 | private boolean isSubtypeUncheckedInternal(Type t, Type s, Warner warn) { |
jjg@1374 | 751 | if (t.hasTag(ARRAY) && s.hasTag(ARRAY)) { |
jjg@1521 | 752 | t = t.unannotatedType(); |
jjg@1521 | 753 | s = s.unannotatedType(); |
jjg@1374 | 754 | if (((ArrayType)t).elemtype.isPrimitive()) { |
mcimadamore@1108 | 755 | return isSameType(elemtype(t), elemtype(s)); |
mcimadamore@1108 | 756 | } else { |
mcimadamore@1108 | 757 | return isSubtypeUnchecked(elemtype(t), elemtype(s), warn); |
mcimadamore@795 | 758 | } |
mcimadamore@1108 | 759 | } else if (isSubtype(t, s)) { |
duke@1 | 760 | return true; |
vromero@1853 | 761 | } else if (t.hasTag(TYPEVAR)) { |
mcimadamore@1108 | 762 | return isSubtypeUnchecked(t.getUpperBound(), s, warn); |
vromero@1853 | 763 | } else if (!s.isRaw()) { |
emc@2079 | 764 | Type t2 = asSuper(t, s); |
mcimadamore@1108 | 765 | if (t2 != null && t2.isRaw()) { |
vromero@1853 | 766 | if (isReifiable(s)) { |
mcimadamore@1108 | 767 | warn.silentWarn(LintCategory.UNCHECKED); |
vromero@1853 | 768 | } else { |
mcimadamore@1108 | 769 | warn.warn(LintCategory.UNCHECKED); |
vromero@1853 | 770 | } |
mcimadamore@1108 | 771 | return true; |
mcimadamore@1108 | 772 | } |
mcimadamore@1108 | 773 | } |
mcimadamore@1108 | 774 | return false; |
duke@1 | 775 | } |
mcimadamore@1108 | 776 | |
mcimadamore@1108 | 777 | private void checkUnsafeVarargsConversion(Type t, Type s, Warner warn) { |
vromero@1853 | 778 | if (!t.hasTag(ARRAY) || isReifiable(t)) { |
jjg@1521 | 779 | return; |
vromero@1853 | 780 | } |
jjg@1521 | 781 | t = t.unannotatedType(); |
jjg@1521 | 782 | s = s.unannotatedType(); |
mcimadamore@1108 | 783 | ArrayType from = (ArrayType)t; |
mcimadamore@1108 | 784 | boolean shouldWarn = false; |
vromero@1853 | 785 | switch (s.getTag()) { |
mcimadamore@1108 | 786 | case ARRAY: |
mcimadamore@1108 | 787 | ArrayType to = (ArrayType)s; |
mcimadamore@1108 | 788 | shouldWarn = from.isVarargs() && |
mcimadamore@1108 | 789 | !to.isVarargs() && |
mcimadamore@1108 | 790 | !isReifiable(from); |
mcimadamore@1108 | 791 | break; |
mcimadamore@1108 | 792 | case CLASS: |
mcimadamore@1108 | 793 | shouldWarn = from.isVarargs(); |
mcimadamore@1108 | 794 | break; |
mcimadamore@1108 | 795 | } |
mcimadamore@1108 | 796 | if (shouldWarn) { |
mcimadamore@1108 | 797 | warn.warn(LintCategory.VARARGS); |
mcimadamore@1108 | 798 | } |
mcimadamore@1108 | 799 | } |
duke@1 | 800 | |
duke@1 | 801 | /** |
duke@1 | 802 | * Is t a subtype of s?<br> |
duke@1 | 803 | * (not defined for Method and ForAll types) |
duke@1 | 804 | */ |
duke@1 | 805 | final public boolean isSubtype(Type t, Type s) { |
duke@1 | 806 | return isSubtype(t, s, true); |
duke@1 | 807 | } |
duke@1 | 808 | final public boolean isSubtypeNoCapture(Type t, Type s) { |
duke@1 | 809 | return isSubtype(t, s, false); |
duke@1 | 810 | } |
duke@1 | 811 | public boolean isSubtype(Type t, Type s, boolean capture) { |
duke@1 | 812 | if (t == s) |
duke@1 | 813 | return true; |
duke@1 | 814 | |
jjg@1521 | 815 | t = t.unannotatedType(); |
jjg@1521 | 816 | s = s.unannotatedType(); |
jjg@1521 | 817 | |
jjg@1521 | 818 | if (t == s) |
jjg@1521 | 819 | return true; |
jjg@1521 | 820 | |
jjg@1374 | 821 | if (s.isPartial()) |
duke@1 | 822 | return isSuperType(s, t); |
duke@1 | 823 | |
mcimadamore@299 | 824 | if (s.isCompound()) { |
mcimadamore@299 | 825 | for (Type s2 : interfaces(s).prepend(supertype(s))) { |
mcimadamore@299 | 826 | if (!isSubtype(t, s2, capture)) |
mcimadamore@299 | 827 | return false; |
mcimadamore@299 | 828 | } |
mcimadamore@299 | 829 | return true; |
mcimadamore@299 | 830 | } |
mcimadamore@299 | 831 | |
duke@1 | 832 | Type lower = lowerBound(s); |
duke@1 | 833 | if (s != lower) |
duke@1 | 834 | return isSubtype(capture ? capture(t) : t, lower, false); |
duke@1 | 835 | |
duke@1 | 836 | return isSubtype.visit(capture ? capture(t) : t, s); |
duke@1 | 837 | } |
duke@1 | 838 | // where |
duke@1 | 839 | private TypeRelation isSubtype = new TypeRelation() |
duke@1 | 840 | { |
vromero@1853 | 841 | @Override |
duke@1 | 842 | public Boolean visitType(Type t, Type s) { |
vromero@1853 | 843 | switch (t.getTag()) { |
jjg@1374 | 844 | case BYTE: |
jjg@1374 | 845 | return (!s.hasTag(CHAR) && t.getTag().isSubRangeOf(s.getTag())); |
jjg@1374 | 846 | case CHAR: |
jjg@1374 | 847 | return (!s.hasTag(SHORT) && t.getTag().isSubRangeOf(s.getTag())); |
jjg@1374 | 848 | case SHORT: case INT: case LONG: |
jjg@1374 | 849 | case FLOAT: case DOUBLE: |
jjg@1374 | 850 | return t.getTag().isSubRangeOf(s.getTag()); |
jjg@1374 | 851 | case BOOLEAN: case VOID: |
jjg@1374 | 852 | return t.hasTag(s.getTag()); |
jjg@1374 | 853 | case TYPEVAR: |
jjg@1374 | 854 | return isSubtypeNoCapture(t.getUpperBound(), s); |
jjg@1374 | 855 | case BOT: |
jjg@1374 | 856 | return |
jjg@1374 | 857 | s.hasTag(BOT) || s.hasTag(CLASS) || |
jjg@1374 | 858 | s.hasTag(ARRAY) || s.hasTag(TYPEVAR); |
jjg@1374 | 859 | case WILDCARD: //we shouldn't be here - avoids crash (see 7034495) |
jjg@1374 | 860 | case NONE: |
jjg@1374 | 861 | return false; |
jjg@1374 | 862 | default: |
vromero@1853 | 863 | throw new AssertionError("isSubtype " + t.getTag()); |
jjg@1374 | 864 | } |
duke@1 | 865 | } |
duke@1 | 866 | |
duke@1 | 867 | private Set<TypePair> cache = new HashSet<TypePair>(); |
duke@1 | 868 | |
duke@1 | 869 | private boolean containsTypeRecursive(Type t, Type s) { |
duke@1 | 870 | TypePair pair = new TypePair(t, s); |
duke@1 | 871 | if (cache.add(pair)) { |
duke@1 | 872 | try { |
duke@1 | 873 | return containsType(t.getTypeArguments(), |
duke@1 | 874 | s.getTypeArguments()); |
duke@1 | 875 | } finally { |
duke@1 | 876 | cache.remove(pair); |
duke@1 | 877 | } |
duke@1 | 878 | } else { |
duke@1 | 879 | return containsType(t.getTypeArguments(), |
duke@1 | 880 | rewriteSupers(s).getTypeArguments()); |
duke@1 | 881 | } |
duke@1 | 882 | } |
duke@1 | 883 | |
duke@1 | 884 | private Type rewriteSupers(Type t) { |
duke@1 | 885 | if (!t.isParameterized()) |
duke@1 | 886 | return t; |
alundblad@2047 | 887 | ListBuffer<Type> from = new ListBuffer<>(); |
alundblad@2047 | 888 | ListBuffer<Type> to = new ListBuffer<>(); |
duke@1 | 889 | adaptSelf(t, from, to); |
duke@1 | 890 | if (from.isEmpty()) |
duke@1 | 891 | return t; |
alundblad@2047 | 892 | ListBuffer<Type> rewrite = new ListBuffer<>(); |
duke@1 | 893 | boolean changed = false; |
duke@1 | 894 | for (Type orig : to.toList()) { |
duke@1 | 895 | Type s = rewriteSupers(orig); |
duke@1 | 896 | if (s.isSuperBound() && !s.isExtendsBound()) { |
duke@1 | 897 | s = new WildcardType(syms.objectType, |
duke@1 | 898 | BoundKind.UNBOUND, |
duke@1 | 899 | syms.boundClass); |
duke@1 | 900 | changed = true; |
duke@1 | 901 | } else if (s != orig) { |
duke@1 | 902 | s = new WildcardType(upperBound(s), |
duke@1 | 903 | BoundKind.EXTENDS, |
duke@1 | 904 | syms.boundClass); |
duke@1 | 905 | changed = true; |
duke@1 | 906 | } |
duke@1 | 907 | rewrite.append(s); |
duke@1 | 908 | } |
duke@1 | 909 | if (changed) |
duke@1 | 910 | return subst(t.tsym.type, from.toList(), rewrite.toList()); |
duke@1 | 911 | else |
duke@1 | 912 | return t; |
duke@1 | 913 | } |
duke@1 | 914 | |
duke@1 | 915 | @Override |
duke@1 | 916 | public Boolean visitClassType(ClassType t, Type s) { |
emc@2079 | 917 | Type sup = asSuper(t, s); |
duke@1 | 918 | return sup != null |
duke@1 | 919 | && sup.tsym == s.tsym |
duke@1 | 920 | // You're not allowed to write |
duke@1 | 921 | // Vector<Object> vec = new Vector<String>(); |
duke@1 | 922 | // But with wildcards you can write |
duke@1 | 923 | // Vector<? extends Object> vec = new Vector<String>(); |
duke@1 | 924 | // which means that subtype checking must be done |
duke@1 | 925 | // here instead of same-type checking (via containsType). |
duke@1 | 926 | && (!s.isParameterized() || containsTypeRecursive(s, sup)) |
duke@1 | 927 | && isSubtypeNoCapture(sup.getEnclosingType(), |
duke@1 | 928 | s.getEnclosingType()); |
duke@1 | 929 | } |
duke@1 | 930 | |
duke@1 | 931 | @Override |
duke@1 | 932 | public Boolean visitArrayType(ArrayType t, Type s) { |
vromero@1853 | 933 | if (s.hasTag(ARRAY)) { |
jjg@1374 | 934 | if (t.elemtype.isPrimitive()) |
duke@1 | 935 | return isSameType(t.elemtype, elemtype(s)); |
duke@1 | 936 | else |
duke@1 | 937 | return isSubtypeNoCapture(t.elemtype, elemtype(s)); |
duke@1 | 938 | } |
duke@1 | 939 | |
vromero@1853 | 940 | if (s.hasTag(CLASS)) { |
duke@1 | 941 | Name sname = s.tsym.getQualifiedName(); |
duke@1 | 942 | return sname == names.java_lang_Object |
duke@1 | 943 | || sname == names.java_lang_Cloneable |
duke@1 | 944 | || sname == names.java_io_Serializable; |
duke@1 | 945 | } |
duke@1 | 946 | |
duke@1 | 947 | return false; |
duke@1 | 948 | } |
duke@1 | 949 | |
duke@1 | 950 | @Override |
duke@1 | 951 | public Boolean visitUndetVar(UndetVar t, Type s) { |
duke@1 | 952 | //todo: test against origin needed? or replace with substitution? |
vromero@1853 | 953 | if (t == s || t.qtype == s || s.hasTag(ERROR) || s.hasTag(UNKNOWN)) { |
duke@1 | 954 | return true; |
vromero@1853 | 955 | } else if (s.hasTag(BOT)) { |
mcimadamore@1093 | 956 | //if 's' is 'null' there's no instantiated type U for which |
mcimadamore@1093 | 957 | //U <: s (but 'null' itself, which is not a valid type) |
mcimadamore@1093 | 958 | return false; |
mcimadamore@1093 | 959 | } |
duke@1 | 960 | |
mcimadamore@1338 | 961 | t.addBound(InferenceBound.UPPER, s, Types.this); |
duke@1 | 962 | return true; |
duke@1 | 963 | } |
duke@1 | 964 | |
duke@1 | 965 | @Override |
duke@1 | 966 | public Boolean visitErrorType(ErrorType t, Type s) { |
duke@1 | 967 | return true; |
duke@1 | 968 | } |
duke@1 | 969 | }; |
duke@1 | 970 | |
duke@1 | 971 | /** |
duke@1 | 972 | * Is t a subtype of every type in given list `ts'?<br> |
duke@1 | 973 | * (not defined for Method and ForAll types)<br> |
duke@1 | 974 | * Allows unchecked conversions. |
duke@1 | 975 | */ |
duke@1 | 976 | public boolean isSubtypeUnchecked(Type t, List<Type> ts, Warner warn) { |
duke@1 | 977 | for (List<Type> l = ts; l.nonEmpty(); l = l.tail) |
duke@1 | 978 | if (!isSubtypeUnchecked(t, l.head, warn)) |
duke@1 | 979 | return false; |
duke@1 | 980 | return true; |
duke@1 | 981 | } |
duke@1 | 982 | |
duke@1 | 983 | /** |
duke@1 | 984 | * Are corresponding elements of ts subtypes of ss? If lists are |
duke@1 | 985 | * of different length, return false. |
duke@1 | 986 | */ |
duke@1 | 987 | public boolean isSubtypes(List<Type> ts, List<Type> ss) { |
duke@1 | 988 | while (ts.tail != null && ss.tail != null |
duke@1 | 989 | /*inlined: ts.nonEmpty() && ss.nonEmpty()*/ && |
duke@1 | 990 | isSubtype(ts.head, ss.head)) { |
duke@1 | 991 | ts = ts.tail; |
duke@1 | 992 | ss = ss.tail; |
duke@1 | 993 | } |
duke@1 | 994 | return ts.tail == null && ss.tail == null; |
duke@1 | 995 | /*inlined: ts.isEmpty() && ss.isEmpty();*/ |
duke@1 | 996 | } |
duke@1 | 997 | |
duke@1 | 998 | /** |
duke@1 | 999 | * Are corresponding elements of ts subtypes of ss, allowing |
duke@1 | 1000 | * unchecked conversions? If lists are of different length, |
duke@1 | 1001 | * return false. |
duke@1 | 1002 | **/ |
duke@1 | 1003 | public boolean isSubtypesUnchecked(List<Type> ts, List<Type> ss, Warner warn) { |
duke@1 | 1004 | while (ts.tail != null && ss.tail != null |
duke@1 | 1005 | /*inlined: ts.nonEmpty() && ss.nonEmpty()*/ && |
duke@1 | 1006 | isSubtypeUnchecked(ts.head, ss.head, warn)) { |
duke@1 | 1007 | ts = ts.tail; |
duke@1 | 1008 | ss = ss.tail; |
duke@1 | 1009 | } |
duke@1 | 1010 | return ts.tail == null && ss.tail == null; |
duke@1 | 1011 | /*inlined: ts.isEmpty() && ss.isEmpty();*/ |
duke@1 | 1012 | } |
duke@1 | 1013 | // </editor-fold> |
duke@1 | 1014 | |
duke@1 | 1015 | // <editor-fold defaultstate="collapsed" desc="isSuperType"> |
duke@1 | 1016 | /** |
duke@1 | 1017 | * Is t a supertype of s? |
duke@1 | 1018 | */ |
duke@1 | 1019 | public boolean isSuperType(Type t, Type s) { |
vromero@1853 | 1020 | switch (t.getTag()) { |
duke@1 | 1021 | case ERROR: |
duke@1 | 1022 | return true; |
duke@1 | 1023 | case UNDETVAR: { |
duke@1 | 1024 | UndetVar undet = (UndetVar)t; |
duke@1 | 1025 | if (t == s || |
duke@1 | 1026 | undet.qtype == s || |
vromero@1853 | 1027 | s.hasTag(ERROR) || |
vromero@1853 | 1028 | s.hasTag(BOT)) { |
vromero@1853 | 1029 | return true; |
vromero@1853 | 1030 | } |
mcimadamore@1338 | 1031 | undet.addBound(InferenceBound.LOWER, s, this); |
duke@1 | 1032 | return true; |
duke@1 | 1033 | } |
duke@1 | 1034 | default: |
duke@1 | 1035 | return isSubtype(s, t); |
duke@1 | 1036 | } |
duke@1 | 1037 | } |
duke@1 | 1038 | // </editor-fold> |
duke@1 | 1039 | |
duke@1 | 1040 | // <editor-fold defaultstate="collapsed" desc="isSameType"> |
duke@1 | 1041 | /** |
duke@1 | 1042 | * Are corresponding elements of the lists the same type? If |
duke@1 | 1043 | * lists are of different length, return false. |
duke@1 | 1044 | */ |
duke@1 | 1045 | public boolean isSameTypes(List<Type> ts, List<Type> ss) { |
mcimadamore@1550 | 1046 | return isSameTypes(ts, ss, false); |
mcimadamore@1550 | 1047 | } |
mcimadamore@1550 | 1048 | public boolean isSameTypes(List<Type> ts, List<Type> ss, boolean strict) { |
duke@1 | 1049 | while (ts.tail != null && ss.tail != null |
duke@1 | 1050 | /*inlined: ts.nonEmpty() && ss.nonEmpty()*/ && |
mcimadamore@1550 | 1051 | isSameType(ts.head, ss.head, strict)) { |
duke@1 | 1052 | ts = ts.tail; |
duke@1 | 1053 | ss = ss.tail; |
duke@1 | 1054 | } |
duke@1 | 1055 | return ts.tail == null && ss.tail == null; |
duke@1 | 1056 | /*inlined: ts.isEmpty() && ss.isEmpty();*/ |
duke@1 | 1057 | } |
duke@1 | 1058 | |
duke@1 | 1059 | /** |
vromero@1820 | 1060 | * A polymorphic signature method (JLS SE 7, 8.4.1) is a method that |
vromero@1820 | 1061 | * (i) is declared in the java.lang.invoke.MethodHandle class, (ii) takes |
vromero@1820 | 1062 | * a single variable arity parameter (iii) whose declared type is Object[], |
vromero@1820 | 1063 | * (iv) has a return type of Object and (v) is native. |
vromero@1820 | 1064 | */ |
vromero@1820 | 1065 | public boolean isSignaturePolymorphic(MethodSymbol msym) { |
vromero@1820 | 1066 | List<Type> argtypes = msym.type.getParameterTypes(); |
vromero@1820 | 1067 | return (msym.flags_field & NATIVE) != 0 && |
vromero@1820 | 1068 | msym.owner == syms.methodHandleType.tsym && |
vromero@1820 | 1069 | argtypes.tail.tail == null && |
vromero@1820 | 1070 | argtypes.head.hasTag(TypeTag.ARRAY) && |
vromero@1820 | 1071 | msym.type.getReturnType().tsym == syms.objectType.tsym && |
vromero@1820 | 1072 | ((ArrayType)argtypes.head).elemtype.tsym == syms.objectType.tsym; |
vromero@1820 | 1073 | } |
vromero@1820 | 1074 | |
vromero@1820 | 1075 | /** |
duke@1 | 1076 | * Is t the same type as s? |
duke@1 | 1077 | */ |
duke@1 | 1078 | public boolean isSameType(Type t, Type s) { |
mcimadamore@1550 | 1079 | return isSameType(t, s, false); |
mcimadamore@1550 | 1080 | } |
mcimadamore@1550 | 1081 | public boolean isSameType(Type t, Type s, boolean strict) { |
mcimadamore@1550 | 1082 | return strict ? |
mcimadamore@1550 | 1083 | isSameTypeStrict.visit(t, s) : |
mcimadamore@1550 | 1084 | isSameTypeLoose.visit(t, s); |
duke@1 | 1085 | } |
jjg@1755 | 1086 | public boolean isSameAnnotatedType(Type t, Type s) { |
jjg@1755 | 1087 | return isSameAnnotatedType.visit(t, s); |
jjg@1755 | 1088 | } |
duke@1 | 1089 | // where |
mcimadamore@1550 | 1090 | abstract class SameTypeVisitor extends TypeRelation { |
duke@1 | 1091 | |
duke@1 | 1092 | public Boolean visitType(Type t, Type s) { |
duke@1 | 1093 | if (t == s) |
duke@1 | 1094 | return true; |
duke@1 | 1095 | |
jjg@1374 | 1096 | if (s.isPartial()) |
duke@1 | 1097 | return visit(s, t); |
duke@1 | 1098 | |
vromero@1853 | 1099 | switch (t.getTag()) { |
duke@1 | 1100 | case BYTE: case CHAR: case SHORT: case INT: case LONG: case FLOAT: |
duke@1 | 1101 | case DOUBLE: case BOOLEAN: case VOID: case BOT: case NONE: |
vromero@1853 | 1102 | return t.hasTag(s.getTag()); |
mcimadamore@561 | 1103 | case TYPEVAR: { |
vromero@1853 | 1104 | if (s.hasTag(TYPEVAR)) { |
mcimadamore@561 | 1105 | //type-substitution does not preserve type-var types |
mcimadamore@561 | 1106 | //check that type var symbols and bounds are indeed the same |
jjg@1755 | 1107 | return sameTypeVars((TypeVar)t.unannotatedType(), (TypeVar)s.unannotatedType()); |
mcimadamore@561 | 1108 | } |
mcimadamore@561 | 1109 | else { |
mcimadamore@561 | 1110 | //special case for s == ? super X, where upper(s) = u |
mcimadamore@561 | 1111 | //check that u == t, where u has been set by Type.withTypeVar |
mcimadamore@561 | 1112 | return s.isSuperBound() && |
mcimadamore@561 | 1113 | !s.isExtendsBound() && |
mcimadamore@561 | 1114 | visit(t, upperBound(s)); |
mcimadamore@561 | 1115 | } |
mcimadamore@561 | 1116 | } |
duke@1 | 1117 | default: |
vromero@1853 | 1118 | throw new AssertionError("isSameType " + t.getTag()); |
duke@1 | 1119 | } |
duke@1 | 1120 | } |
duke@1 | 1121 | |
mcimadamore@1550 | 1122 | abstract boolean sameTypeVars(TypeVar tv1, TypeVar tv2); |
mcimadamore@1550 | 1123 | |
duke@1 | 1124 | @Override |
duke@1 | 1125 | public Boolean visitWildcardType(WildcardType t, Type s) { |
jjg@1374 | 1126 | if (s.isPartial()) |
duke@1 | 1127 | return visit(s, t); |
duke@1 | 1128 | else |
duke@1 | 1129 | return false; |
duke@1 | 1130 | } |
duke@1 | 1131 | |
duke@1 | 1132 | @Override |
duke@1 | 1133 | public Boolean visitClassType(ClassType t, Type s) { |
duke@1 | 1134 | if (t == s) |
duke@1 | 1135 | return true; |
duke@1 | 1136 | |
jjg@1374 | 1137 | if (s.isPartial()) |
duke@1 | 1138 | return visit(s, t); |
duke@1 | 1139 | |
duke@1 | 1140 | if (s.isSuperBound() && !s.isExtendsBound()) |
duke@1 | 1141 | return visit(t, upperBound(s)) && visit(t, lowerBound(s)); |
duke@1 | 1142 | |
duke@1 | 1143 | if (t.isCompound() && s.isCompound()) { |
duke@1 | 1144 | if (!visit(supertype(t), supertype(s))) |
duke@1 | 1145 | return false; |
duke@1 | 1146 | |
vromero@1452 | 1147 | HashSet<UniqueType> set = new HashSet<UniqueType>(); |
duke@1 | 1148 | for (Type x : interfaces(t)) |
emc@1916 | 1149 | set.add(new UniqueType(x.unannotatedType(), Types.this)); |
duke@1 | 1150 | for (Type x : interfaces(s)) { |
emc@1916 | 1151 | if (!set.remove(new UniqueType(x.unannotatedType(), Types.this))) |
duke@1 | 1152 | return false; |
duke@1 | 1153 | } |
jjg@789 | 1154 | return (set.isEmpty()); |
duke@1 | 1155 | } |
duke@1 | 1156 | return t.tsym == s.tsym |
duke@1 | 1157 | && visit(t.getEnclosingType(), s.getEnclosingType()) |
mcimadamore@1550 | 1158 | && containsTypes(t.getTypeArguments(), s.getTypeArguments()); |
duke@1 | 1159 | } |
duke@1 | 1160 | |
mcimadamore@1550 | 1161 | abstract protected boolean containsTypes(List<Type> ts1, List<Type> ts2); |
mcimadamore@1550 | 1162 | |
duke@1 | 1163 | @Override |
duke@1 | 1164 | public Boolean visitArrayType(ArrayType t, Type s) { |
duke@1 | 1165 | if (t == s) |
duke@1 | 1166 | return true; |
duke@1 | 1167 | |
jjg@1374 | 1168 | if (s.isPartial()) |
duke@1 | 1169 | return visit(s, t); |
duke@1 | 1170 | |
jjg@1374 | 1171 | return s.hasTag(ARRAY) |
duke@1 | 1172 | && containsTypeEquivalent(t.elemtype, elemtype(s)); |
duke@1 | 1173 | } |
duke@1 | 1174 | |
duke@1 | 1175 | @Override |
duke@1 | 1176 | public Boolean visitMethodType(MethodType t, Type s) { |
duke@1 | 1177 | // isSameType for methods does not take thrown |
duke@1 | 1178 | // exceptions into account! |
duke@1 | 1179 | return hasSameArgs(t, s) && visit(t.getReturnType(), s.getReturnType()); |
duke@1 | 1180 | } |
duke@1 | 1181 | |
duke@1 | 1182 | @Override |
duke@1 | 1183 | public Boolean visitPackageType(PackageType t, Type s) { |
duke@1 | 1184 | return t == s; |
duke@1 | 1185 | } |
duke@1 | 1186 | |
duke@1 | 1187 | @Override |
duke@1 | 1188 | public Boolean visitForAll(ForAll t, Type s) { |
vromero@1853 | 1189 | if (!s.hasTag(FORALL)) { |
duke@1 | 1190 | return false; |
vromero@1853 | 1191 | } |
duke@1 | 1192 | |
duke@1 | 1193 | ForAll forAll = (ForAll)s; |
duke@1 | 1194 | return hasSameBounds(t, forAll) |
duke@1 | 1195 | && visit(t.qtype, subst(forAll.qtype, forAll.tvars, t.tvars)); |
duke@1 | 1196 | } |
duke@1 | 1197 | |
duke@1 | 1198 | @Override |
duke@1 | 1199 | public Boolean visitUndetVar(UndetVar t, Type s) { |
vromero@1853 | 1200 | if (s.hasTag(WILDCARD)) { |
duke@1 | 1201 | // FIXME, this might be leftovers from before capture conversion |
duke@1 | 1202 | return false; |
vromero@1853 | 1203 | } |
vromero@1853 | 1204 | |
vromero@1853 | 1205 | if (t == s || t.qtype == s || s.hasTag(ERROR) || s.hasTag(UNKNOWN)) { |
duke@1 | 1206 | return true; |
vromero@1853 | 1207 | } |
duke@1 | 1208 | |
mcimadamore@1338 | 1209 | t.addBound(InferenceBound.EQ, s, Types.this); |
mcimadamore@1251 | 1210 | |
duke@1 | 1211 | return true; |
duke@1 | 1212 | } |
duke@1 | 1213 | |
duke@1 | 1214 | @Override |
duke@1 | 1215 | public Boolean visitErrorType(ErrorType t, Type s) { |
duke@1 | 1216 | return true; |
duke@1 | 1217 | } |
mcimadamore@1550 | 1218 | } |
mcimadamore@1550 | 1219 | |
mcimadamore@1550 | 1220 | /** |
mcimadamore@1550 | 1221 | * Standard type-equality relation - type variables are considered |
mcimadamore@1550 | 1222 | * equals if they share the same type symbol. |
mcimadamore@1550 | 1223 | */ |
jjg@1755 | 1224 | TypeRelation isSameTypeLoose = new LooseSameTypeVisitor(); |
jjg@1755 | 1225 | |
jjg@1755 | 1226 | private class LooseSameTypeVisitor extends SameTypeVisitor { |
mcimadamore@1550 | 1227 | @Override |
mcimadamore@1550 | 1228 | boolean sameTypeVars(TypeVar tv1, TypeVar tv2) { |
mcimadamore@1550 | 1229 | return tv1.tsym == tv2.tsym && visit(tv1.getUpperBound(), tv2.getUpperBound()); |
mcimadamore@1550 | 1230 | } |
mcimadamore@1550 | 1231 | @Override |
mcimadamore@1550 | 1232 | protected boolean containsTypes(List<Type> ts1, List<Type> ts2) { |
mcimadamore@1550 | 1233 | return containsTypeEquivalent(ts1, ts2); |
mcimadamore@1550 | 1234 | } |
mcimadamore@1550 | 1235 | }; |
mcimadamore@1550 | 1236 | |
mcimadamore@1550 | 1237 | /** |
mcimadamore@1550 | 1238 | * Strict type-equality relation - type variables are considered |
mcimadamore@1550 | 1239 | * equals if they share the same object identity. |
mcimadamore@1550 | 1240 | */ |
mcimadamore@1550 | 1241 | TypeRelation isSameTypeStrict = new SameTypeVisitor() { |
mcimadamore@1550 | 1242 | @Override |
mcimadamore@1550 | 1243 | boolean sameTypeVars(TypeVar tv1, TypeVar tv2) { |
mcimadamore@1550 | 1244 | return tv1 == tv2; |
mcimadamore@1550 | 1245 | } |
mcimadamore@1550 | 1246 | @Override |
mcimadamore@1550 | 1247 | protected boolean containsTypes(List<Type> ts1, List<Type> ts2) { |
mcimadamore@1550 | 1248 | return isSameTypes(ts1, ts2, true); |
mcimadamore@1550 | 1249 | } |
mcimadamore@1655 | 1250 | |
mcimadamore@1655 | 1251 | @Override |
mcimadamore@1655 | 1252 | public Boolean visitWildcardType(WildcardType t, Type s) { |
mcimadamore@1655 | 1253 | if (!s.hasTag(WILDCARD)) { |
mcimadamore@1655 | 1254 | return false; |
mcimadamore@1655 | 1255 | } else { |
jjg@1755 | 1256 | WildcardType t2 = (WildcardType)s.unannotatedType(); |
mcimadamore@1655 | 1257 | return t.kind == t2.kind && |
mcimadamore@1655 | 1258 | isSameType(t.type, t2.type, true); |
mcimadamore@1655 | 1259 | } |
mcimadamore@1655 | 1260 | } |
duke@1 | 1261 | }; |
jjg@1755 | 1262 | |
jjg@1755 | 1263 | /** |
jjg@1755 | 1264 | * A version of LooseSameTypeVisitor that takes AnnotatedTypes |
jjg@1755 | 1265 | * into account. |
jjg@1755 | 1266 | */ |
jjg@1755 | 1267 | TypeRelation isSameAnnotatedType = new LooseSameTypeVisitor() { |
jjg@1755 | 1268 | @Override |
jjg@1755 | 1269 | public Boolean visitAnnotatedType(AnnotatedType t, Type s) { |
jjg@1755 | 1270 | if (!s.isAnnotated()) |
jjg@1755 | 1271 | return false; |
jjg@1755 | 1272 | if (!t.getAnnotationMirrors().containsAll(s.getAnnotationMirrors())) |
jjg@1755 | 1273 | return false; |
jjg@1755 | 1274 | if (!s.getAnnotationMirrors().containsAll(t.getAnnotationMirrors())) |
jjg@1755 | 1275 | return false; |
jjg@2134 | 1276 | return visit(t.unannotatedType(), s); |
jjg@1755 | 1277 | } |
jjg@1755 | 1278 | }; |
duke@1 | 1279 | // </editor-fold> |
duke@1 | 1280 | |
duke@1 | 1281 | // <editor-fold defaultstate="collapsed" desc="Contains Type"> |
duke@1 | 1282 | public boolean containedBy(Type t, Type s) { |
vromero@1853 | 1283 | switch (t.getTag()) { |
duke@1 | 1284 | case UNDETVAR: |
vromero@1853 | 1285 | if (s.hasTag(WILDCARD)) { |
duke@1 | 1286 | UndetVar undetvar = (UndetVar)t; |
jjg@1755 | 1287 | WildcardType wt = (WildcardType)s.unannotatedType(); |
mcimadamore@210 | 1288 | switch(wt.kind) { |
mcimadamore@210 | 1289 | case UNBOUND: //similar to ? extends Object |
mcimadamore@210 | 1290 | case EXTENDS: { |
mcimadamore@210 | 1291 | Type bound = upperBound(s); |
mcimadamore@1338 | 1292 | undetvar.addBound(InferenceBound.UPPER, bound, this); |
mcimadamore@210 | 1293 | break; |
mcimadamore@210 | 1294 | } |
mcimadamore@210 | 1295 | case SUPER: { |
mcimadamore@210 | 1296 | Type bound = lowerBound(s); |
mcimadamore@1338 | 1297 | undetvar.addBound(InferenceBound.LOWER, bound, this); |
mcimadamore@210 | 1298 | break; |
mcimadamore@210 | 1299 | } |
mcimadamore@162 | 1300 | } |
duke@1 | 1301 | return true; |
duke@1 | 1302 | } else { |
duke@1 | 1303 | return isSameType(t, s); |
duke@1 | 1304 | } |
duke@1 | 1305 | case ERROR: |
duke@1 | 1306 | return true; |
duke@1 | 1307 | default: |
duke@1 | 1308 | return containsType(s, t); |
duke@1 | 1309 | } |
duke@1 | 1310 | } |
duke@1 | 1311 | |
duke@1 | 1312 | boolean containsType(List<Type> ts, List<Type> ss) { |
duke@1 | 1313 | while (ts.nonEmpty() && ss.nonEmpty() |
duke@1 | 1314 | && containsType(ts.head, ss.head)) { |
duke@1 | 1315 | ts = ts.tail; |
duke@1 | 1316 | ss = ss.tail; |
duke@1 | 1317 | } |
duke@1 | 1318 | return ts.isEmpty() && ss.isEmpty(); |
duke@1 | 1319 | } |
duke@1 | 1320 | |
duke@1 | 1321 | /** |
duke@1 | 1322 | * Check if t contains s. |
duke@1 | 1323 | * |
duke@1 | 1324 | * <p>T contains S if: |
duke@1 | 1325 | * |
duke@1 | 1326 | * <p>{@code L(T) <: L(S) && U(S) <: U(T)} |
duke@1 | 1327 | * |
duke@1 | 1328 | * <p>This relation is only used by ClassType.isSubtype(), that |
duke@1 | 1329 | * is, |
duke@1 | 1330 | * |
duke@1 | 1331 | * <p>{@code C<S> <: C<T> if T contains S.} |
duke@1 | 1332 | * |
duke@1 | 1333 | * <p>Because of F-bounds, this relation can lead to infinite |
duke@1 | 1334 | * recursion. Thus we must somehow break that recursion. Notice |
duke@1 | 1335 | * that containsType() is only called from ClassType.isSubtype(). |
duke@1 | 1336 | * Since the arguments have already been checked against their |
duke@1 | 1337 | * bounds, we know: |
duke@1 | 1338 | * |
duke@1 | 1339 | * <p>{@code U(S) <: U(T) if T is "super" bound (U(T) *is* the bound)} |
duke@1 | 1340 | * |
duke@1 | 1341 | * <p>{@code L(T) <: L(S) if T is "extends" bound (L(T) is bottom)} |
duke@1 | 1342 | * |
duke@1 | 1343 | * @param t a type |
duke@1 | 1344 | * @param s a type |
duke@1 | 1345 | */ |
duke@1 | 1346 | public boolean containsType(Type t, Type s) { |
duke@1 | 1347 | return containsType.visit(t, s); |
duke@1 | 1348 | } |
duke@1 | 1349 | // where |
duke@1 | 1350 | private TypeRelation containsType = new TypeRelation() { |
duke@1 | 1351 | |
duke@1 | 1352 | private Type U(Type t) { |
vromero@1853 | 1353 | while (t.hasTag(WILDCARD)) { |
jjg@1755 | 1354 | WildcardType w = (WildcardType)t.unannotatedType(); |
duke@1 | 1355 | if (w.isSuperBound()) |
duke@1 | 1356 | return w.bound == null ? syms.objectType : w.bound.bound; |
duke@1 | 1357 | else |
duke@1 | 1358 | t = w.type; |
duke@1 | 1359 | } |
duke@1 | 1360 | return t; |
duke@1 | 1361 | } |
duke@1 | 1362 | |
duke@1 | 1363 | private Type L(Type t) { |
vromero@1853 | 1364 | while (t.hasTag(WILDCARD)) { |
jjg@1755 | 1365 | WildcardType w = (WildcardType)t.unannotatedType(); |
duke@1 | 1366 | if (w.isExtendsBound()) |
duke@1 | 1367 | return syms.botType; |
duke@1 | 1368 | else |
duke@1 | 1369 | t = w.type; |
duke@1 | 1370 | } |
duke@1 | 1371 | return t; |
duke@1 | 1372 | } |
duke@1 | 1373 | |
duke@1 | 1374 | public Boolean visitType(Type t, Type s) { |
jjg@1374 | 1375 | if (s.isPartial()) |
duke@1 | 1376 | return containedBy(s, t); |
duke@1 | 1377 | else |
duke@1 | 1378 | return isSameType(t, s); |
duke@1 | 1379 | } |
duke@1 | 1380 | |
jjg@789 | 1381 | // void debugContainsType(WildcardType t, Type s) { |
jjg@789 | 1382 | // System.err.println(); |
jjg@789 | 1383 | // System.err.format(" does %s contain %s?%n", t, s); |
jjg@789 | 1384 | // System.err.format(" %s U(%s) <: U(%s) %s = %s%n", |
jjg@789 | 1385 | // upperBound(s), s, t, U(t), |
jjg@789 | 1386 | // t.isSuperBound() |
jjg@789 | 1387 | // || isSubtypeNoCapture(upperBound(s), U(t))); |
jjg@789 | 1388 | // System.err.format(" %s L(%s) <: L(%s) %s = %s%n", |
jjg@789 | 1389 | // L(t), t, s, lowerBound(s), |
jjg@789 | 1390 | // t.isExtendsBound() |
jjg@789 | 1391 | // || isSubtypeNoCapture(L(t), lowerBound(s))); |
jjg@789 | 1392 | // System.err.println(); |
jjg@789 | 1393 | // } |
duke@1 | 1394 | |
duke@1 | 1395 | @Override |
duke@1 | 1396 | public Boolean visitWildcardType(WildcardType t, Type s) { |
jjg@1374 | 1397 | if (s.isPartial()) |
duke@1 | 1398 | return containedBy(s, t); |
duke@1 | 1399 | else { |
jjg@789 | 1400 | // debugContainsType(t, s); |
duke@1 | 1401 | return isSameWildcard(t, s) |
duke@1 | 1402 | || isCaptureOf(s, t) |
duke@1 | 1403 | || ((t.isExtendsBound() || isSubtypeNoCapture(L(t), lowerBound(s))) && |
duke@1 | 1404 | (t.isSuperBound() || isSubtypeNoCapture(upperBound(s), U(t)))); |
duke@1 | 1405 | } |
duke@1 | 1406 | } |
duke@1 | 1407 | |
duke@1 | 1408 | @Override |
duke@1 | 1409 | public Boolean visitUndetVar(UndetVar t, Type s) { |
vromero@1853 | 1410 | if (!s.hasTag(WILDCARD)) { |
duke@1 | 1411 | return isSameType(t, s); |
vromero@1853 | 1412 | } else { |
duke@1 | 1413 | return false; |
vromero@1853 | 1414 | } |
duke@1 | 1415 | } |
duke@1 | 1416 | |
duke@1 | 1417 | @Override |
duke@1 | 1418 | public Boolean visitErrorType(ErrorType t, Type s) { |
duke@1 | 1419 | return true; |
duke@1 | 1420 | } |
duke@1 | 1421 | }; |
duke@1 | 1422 | |
duke@1 | 1423 | public boolean isCaptureOf(Type s, WildcardType t) { |
vromero@1853 | 1424 | if (!s.hasTag(TYPEVAR) || !((TypeVar)s.unannotatedType()).isCaptured()) |
duke@1 | 1425 | return false; |
jjg@1755 | 1426 | return isSameWildcard(t, ((CapturedType)s.unannotatedType()).wildcard); |
duke@1 | 1427 | } |
duke@1 | 1428 | |
duke@1 | 1429 | public boolean isSameWildcard(WildcardType t, Type s) { |
vromero@1853 | 1430 | if (!s.hasTag(WILDCARD)) |
duke@1 | 1431 | return false; |
jjg@1755 | 1432 | WildcardType w = (WildcardType)s.unannotatedType(); |
duke@1 | 1433 | return w.kind == t.kind && w.type == t.type; |
duke@1 | 1434 | } |
duke@1 | 1435 | |
duke@1 | 1436 | public boolean containsTypeEquivalent(List<Type> ts, List<Type> ss) { |
duke@1 | 1437 | while (ts.nonEmpty() && ss.nonEmpty() |
duke@1 | 1438 | && containsTypeEquivalent(ts.head, ss.head)) { |
duke@1 | 1439 | ts = ts.tail; |
duke@1 | 1440 | ss = ss.tail; |
duke@1 | 1441 | } |
duke@1 | 1442 | return ts.isEmpty() && ss.isEmpty(); |
duke@1 | 1443 | } |
duke@1 | 1444 | // </editor-fold> |
duke@1 | 1445 | |
emc@1869 | 1446 | /** |
emc@1869 | 1447 | * Can t and s be compared for equality? Any primitive == |
emc@1869 | 1448 | * primitive or primitive == object comparisons here are an error. |
emc@1869 | 1449 | * Unboxing and correct primitive == primitive comparisons are |
emc@1869 | 1450 | * already dealt with in Attr.visitBinary. |
emc@1869 | 1451 | * |
emc@1869 | 1452 | */ |
emc@1869 | 1453 | public boolean isEqualityComparable(Type s, Type t, Warner warn) { |
emc@1869 | 1454 | if (t.isNumeric() && s.isNumeric()) |
emc@1869 | 1455 | return true; |
emc@1869 | 1456 | |
emc@1869 | 1457 | boolean tPrimitive = t.isPrimitive(); |
emc@1869 | 1458 | boolean sPrimitive = s.isPrimitive(); |
emc@1869 | 1459 | if (!tPrimitive && !sPrimitive) { |
emc@1869 | 1460 | return isCastable(s, t, warn) || isCastable(t, s, warn); |
emc@1869 | 1461 | } else { |
emc@1869 | 1462 | return false; |
emc@1869 | 1463 | } |
emc@1869 | 1464 | } |
emc@1869 | 1465 | |
duke@1 | 1466 | // <editor-fold defaultstate="collapsed" desc="isCastable"> |
duke@1 | 1467 | public boolean isCastable(Type t, Type s) { |
mcimadamore@1415 | 1468 | return isCastable(t, s, noWarnings); |
duke@1 | 1469 | } |
duke@1 | 1470 | |
duke@1 | 1471 | /** |
duke@1 | 1472 | * Is t is castable to s?<br> |
duke@1 | 1473 | * s is assumed to be an erased type.<br> |
duke@1 | 1474 | * (not defined for Method and ForAll types). |
duke@1 | 1475 | */ |
duke@1 | 1476 | public boolean isCastable(Type t, Type s, Warner warn) { |
duke@1 | 1477 | if (t == s) |
duke@1 | 1478 | return true; |
duke@1 | 1479 | |
duke@1 | 1480 | if (t.isPrimitive() != s.isPrimitive()) |
jjg@984 | 1481 | return allowBoxing && ( |
jjg@984 | 1482 | isConvertible(t, s, warn) |
mcimadamore@1007 | 1483 | || (allowObjectToPrimitiveCast && |
mcimadamore@1007 | 1484 | s.isPrimitive() && |
mcimadamore@1007 | 1485 | isSubtype(boxedClass(s).type, t))); |
duke@1 | 1486 | if (warn != warnStack.head) { |
duke@1 | 1487 | try { |
duke@1 | 1488 | warnStack = warnStack.prepend(warn); |
mcimadamore@795 | 1489 | checkUnsafeVarargsConversion(t, s, warn); |
mcimadamore@185 | 1490 | return isCastable.visit(t,s); |
duke@1 | 1491 | } finally { |
duke@1 | 1492 | warnStack = warnStack.tail; |
duke@1 | 1493 | } |
duke@1 | 1494 | } else { |
mcimadamore@185 | 1495 | return isCastable.visit(t,s); |
duke@1 | 1496 | } |
duke@1 | 1497 | } |
duke@1 | 1498 | // where |
duke@1 | 1499 | private TypeRelation isCastable = new TypeRelation() { |
duke@1 | 1500 | |
duke@1 | 1501 | public Boolean visitType(Type t, Type s) { |
vromero@1853 | 1502 | if (s.hasTag(ERROR)) |
duke@1 | 1503 | return true; |
duke@1 | 1504 | |
vromero@1853 | 1505 | switch (t.getTag()) { |
duke@1 | 1506 | case BYTE: case CHAR: case SHORT: case INT: case LONG: case FLOAT: |
duke@1 | 1507 | case DOUBLE: |
jjg@1374 | 1508 | return s.isNumeric(); |
duke@1 | 1509 | case BOOLEAN: |
vromero@1853 | 1510 | return s.hasTag(BOOLEAN); |
duke@1 | 1511 | case VOID: |
duke@1 | 1512 | return false; |
duke@1 | 1513 | case BOT: |
duke@1 | 1514 | return isSubtype(t, s); |
duke@1 | 1515 | default: |
duke@1 | 1516 | throw new AssertionError(); |
duke@1 | 1517 | } |
duke@1 | 1518 | } |
duke@1 | 1519 | |
duke@1 | 1520 | @Override |
duke@1 | 1521 | public Boolean visitWildcardType(WildcardType t, Type s) { |
duke@1 | 1522 | return isCastable(upperBound(t), s, warnStack.head); |
duke@1 | 1523 | } |
duke@1 | 1524 | |
duke@1 | 1525 | @Override |
duke@1 | 1526 | public Boolean visitClassType(ClassType t, Type s) { |
vromero@1853 | 1527 | if (s.hasTag(ERROR) || s.hasTag(BOT)) |
duke@1 | 1528 | return true; |
duke@1 | 1529 | |
vromero@1853 | 1530 | if (s.hasTag(TYPEVAR)) { |
mcimadamore@1415 | 1531 | if (isCastable(t, s.getUpperBound(), noWarnings)) { |
mcimadamore@795 | 1532 | warnStack.head.warn(LintCategory.UNCHECKED); |
duke@1 | 1533 | return true; |
duke@1 | 1534 | } else { |
duke@1 | 1535 | return false; |
duke@1 | 1536 | } |
duke@1 | 1537 | } |
duke@1 | 1538 | |
mcimadamore@1653 | 1539 | if (t.isCompound() || s.isCompound()) { |
mcimadamore@1653 | 1540 | return !t.isCompound() ? |
jjg@1755 | 1541 | visitIntersectionType((IntersectionClassType)s.unannotatedType(), t, true) : |
jjg@1755 | 1542 | visitIntersectionType((IntersectionClassType)t.unannotatedType(), s, false); |
duke@1 | 1543 | } |
duke@1 | 1544 | |
vromero@1853 | 1545 | if (s.hasTag(CLASS) || s.hasTag(ARRAY)) { |
duke@1 | 1546 | boolean upcast; |
duke@1 | 1547 | if ((upcast = isSubtype(erasure(t), erasure(s))) |
duke@1 | 1548 | || isSubtype(erasure(s), erasure(t))) { |
vromero@1853 | 1549 | if (!upcast && s.hasTag(ARRAY)) { |
duke@1 | 1550 | if (!isReifiable(s)) |
mcimadamore@795 | 1551 | warnStack.head.warn(LintCategory.UNCHECKED); |
duke@1 | 1552 | return true; |
duke@1 | 1553 | } else if (s.isRaw()) { |
duke@1 | 1554 | return true; |
duke@1 | 1555 | } else if (t.isRaw()) { |
duke@1 | 1556 | if (!isUnbounded(s)) |
mcimadamore@795 | 1557 | warnStack.head.warn(LintCategory.UNCHECKED); |
duke@1 | 1558 | return true; |
duke@1 | 1559 | } |
duke@1 | 1560 | // Assume |a| <: |b| |
duke@1 | 1561 | final Type a = upcast ? t : s; |
duke@1 | 1562 | final Type b = upcast ? s : t; |
duke@1 | 1563 | final boolean HIGH = true; |
duke@1 | 1564 | final boolean LOW = false; |
duke@1 | 1565 | final boolean DONT_REWRITE_TYPEVARS = false; |
duke@1 | 1566 | Type aHigh = rewriteQuantifiers(a, HIGH, DONT_REWRITE_TYPEVARS); |
duke@1 | 1567 | Type aLow = rewriteQuantifiers(a, LOW, DONT_REWRITE_TYPEVARS); |
duke@1 | 1568 | Type bHigh = rewriteQuantifiers(b, HIGH, DONT_REWRITE_TYPEVARS); |
duke@1 | 1569 | Type bLow = rewriteQuantifiers(b, LOW, DONT_REWRITE_TYPEVARS); |
duke@1 | 1570 | Type lowSub = asSub(bLow, aLow.tsym); |
duke@1 | 1571 | Type highSub = (lowSub == null) ? null : asSub(bHigh, aHigh.tsym); |
duke@1 | 1572 | if (highSub == null) { |
duke@1 | 1573 | final boolean REWRITE_TYPEVARS = true; |
duke@1 | 1574 | aHigh = rewriteQuantifiers(a, HIGH, REWRITE_TYPEVARS); |
duke@1 | 1575 | aLow = rewriteQuantifiers(a, LOW, REWRITE_TYPEVARS); |
duke@1 | 1576 | bHigh = rewriteQuantifiers(b, HIGH, REWRITE_TYPEVARS); |
duke@1 | 1577 | bLow = rewriteQuantifiers(b, LOW, REWRITE_TYPEVARS); |
duke@1 | 1578 | lowSub = asSub(bLow, aLow.tsym); |
duke@1 | 1579 | highSub = (lowSub == null) ? null : asSub(bHigh, aHigh.tsym); |
duke@1 | 1580 | } |
duke@1 | 1581 | if (highSub != null) { |
jjg@816 | 1582 | if (!(a.tsym == highSub.tsym && a.tsym == lowSub.tsym)) { |
jjg@816 | 1583 | Assert.error(a.tsym + " != " + highSub.tsym + " != " + lowSub.tsym); |
jjg@816 | 1584 | } |
mcimadamore@185 | 1585 | if (!disjointTypes(aHigh.allparams(), highSub.allparams()) |
mcimadamore@185 | 1586 | && !disjointTypes(aHigh.allparams(), lowSub.allparams()) |
mcimadamore@185 | 1587 | && !disjointTypes(aLow.allparams(), highSub.allparams()) |
mcimadamore@185 | 1588 | && !disjointTypes(aLow.allparams(), lowSub.allparams())) { |
mcimadamore@779 | 1589 | if (upcast ? giveWarning(a, b) : |
mcimadamore@235 | 1590 | giveWarning(b, a)) |
mcimadamore@795 | 1591 | warnStack.head.warn(LintCategory.UNCHECKED); |
duke@1 | 1592 | return true; |
duke@1 | 1593 | } |
duke@1 | 1594 | } |
duke@1 | 1595 | if (isReifiable(s)) |
duke@1 | 1596 | return isSubtypeUnchecked(a, b); |
duke@1 | 1597 | else |
duke@1 | 1598 | return isSubtypeUnchecked(a, b, warnStack.head); |
duke@1 | 1599 | } |
duke@1 | 1600 | |
duke@1 | 1601 | // Sidecast |
vromero@1853 | 1602 | if (s.hasTag(CLASS)) { |
duke@1 | 1603 | if ((s.tsym.flags() & INTERFACE) != 0) { |
duke@1 | 1604 | return ((t.tsym.flags() & FINAL) == 0) |
duke@1 | 1605 | ? sideCast(t, s, warnStack.head) |
duke@1 | 1606 | : sideCastFinal(t, s, warnStack.head); |
duke@1 | 1607 | } else if ((t.tsym.flags() & INTERFACE) != 0) { |
duke@1 | 1608 | return ((s.tsym.flags() & FINAL) == 0) |
duke@1 | 1609 | ? sideCast(t, s, warnStack.head) |
duke@1 | 1610 | : sideCastFinal(t, s, warnStack.head); |
duke@1 | 1611 | } else { |
duke@1 | 1612 | // unrelated class types |
duke@1 | 1613 | return false; |
duke@1 | 1614 | } |
duke@1 | 1615 | } |
duke@1 | 1616 | } |
duke@1 | 1617 | return false; |
duke@1 | 1618 | } |
duke@1 | 1619 | |
mcimadamore@1653 | 1620 | boolean visitIntersectionType(IntersectionClassType ict, Type s, boolean reverse) { |
mcimadamore@1653 | 1621 | Warner warn = noWarnings; |
mcimadamore@1653 | 1622 | for (Type c : ict.getComponents()) { |
mcimadamore@1653 | 1623 | warn.clear(); |
mcimadamore@1653 | 1624 | if (reverse ? !isCastable(s, c, warn) : !isCastable(c, s, warn)) |
mcimadamore@1653 | 1625 | return false; |
mcimadamore@1653 | 1626 | } |
mcimadamore@1653 | 1627 | if (warn.hasLint(LintCategory.UNCHECKED)) |
mcimadamore@1653 | 1628 | warnStack.head.warn(LintCategory.UNCHECKED); |
mcimadamore@1653 | 1629 | return true; |
mcimadamore@1653 | 1630 | } |
mcimadamore@1653 | 1631 | |
duke@1 | 1632 | @Override |
duke@1 | 1633 | public Boolean visitArrayType(ArrayType t, Type s) { |
vromero@1853 | 1634 | switch (s.getTag()) { |
duke@1 | 1635 | case ERROR: |
duke@1 | 1636 | case BOT: |
duke@1 | 1637 | return true; |
duke@1 | 1638 | case TYPEVAR: |
mcimadamore@1415 | 1639 | if (isCastable(s, t, noWarnings)) { |
mcimadamore@795 | 1640 | warnStack.head.warn(LintCategory.UNCHECKED); |
duke@1 | 1641 | return true; |
duke@1 | 1642 | } else { |
duke@1 | 1643 | return false; |
duke@1 | 1644 | } |
duke@1 | 1645 | case CLASS: |
duke@1 | 1646 | return isSubtype(t, s); |
duke@1 | 1647 | case ARRAY: |
jjg@1374 | 1648 | if (elemtype(t).isPrimitive() || elemtype(s).isPrimitive()) { |
vromero@1853 | 1649 | return elemtype(t).hasTag(elemtype(s).getTag()); |
duke@1 | 1650 | } else { |
duke@1 | 1651 | return visit(elemtype(t), elemtype(s)); |
duke@1 | 1652 | } |
duke@1 | 1653 | default: |
duke@1 | 1654 | return false; |
duke@1 | 1655 | } |
duke@1 | 1656 | } |
duke@1 | 1657 | |
duke@1 | 1658 | @Override |
duke@1 | 1659 | public Boolean visitTypeVar(TypeVar t, Type s) { |
vromero@1853 | 1660 | switch (s.getTag()) { |
duke@1 | 1661 | case ERROR: |
duke@1 | 1662 | case BOT: |
duke@1 | 1663 | return true; |
duke@1 | 1664 | case TYPEVAR: |
duke@1 | 1665 | if (isSubtype(t, s)) { |
duke@1 | 1666 | return true; |
mcimadamore@1415 | 1667 | } else if (isCastable(t.bound, s, noWarnings)) { |
mcimadamore@795 | 1668 | warnStack.head.warn(LintCategory.UNCHECKED); |
duke@1 | 1669 | return true; |
duke@1 | 1670 | } else { |
duke@1 | 1671 | return false; |
duke@1 | 1672 | } |
duke@1 | 1673 | default: |
duke@1 | 1674 | return isCastable(t.bound, s, warnStack.head); |
duke@1 | 1675 | } |
duke@1 | 1676 | } |
duke@1 | 1677 | |
duke@1 | 1678 | @Override |
duke@1 | 1679 | public Boolean visitErrorType(ErrorType t, Type s) { |
duke@1 | 1680 | return true; |
duke@1 | 1681 | } |
duke@1 | 1682 | }; |
duke@1 | 1683 | // </editor-fold> |
duke@1 | 1684 | |
duke@1 | 1685 | // <editor-fold defaultstate="collapsed" desc="disjointTypes"> |
duke@1 | 1686 | public boolean disjointTypes(List<Type> ts, List<Type> ss) { |
duke@1 | 1687 | while (ts.tail != null && ss.tail != null) { |
duke@1 | 1688 | if (disjointType(ts.head, ss.head)) return true; |
duke@1 | 1689 | ts = ts.tail; |
duke@1 | 1690 | ss = ss.tail; |
duke@1 | 1691 | } |
duke@1 | 1692 | return false; |
duke@1 | 1693 | } |
duke@1 | 1694 | |
duke@1 | 1695 | /** |
duke@1 | 1696 | * Two types or wildcards are considered disjoint if it can be |
duke@1 | 1697 | * proven that no type can be contained in both. It is |
duke@1 | 1698 | * conservative in that it is allowed to say that two types are |
duke@1 | 1699 | * not disjoint, even though they actually are. |
duke@1 | 1700 | * |
jjg@1358 | 1701 | * The type {@code C<X>} is castable to {@code C<Y>} exactly if |
jjg@1358 | 1702 | * {@code X} and {@code Y} are not disjoint. |
duke@1 | 1703 | */ |
duke@1 | 1704 | public boolean disjointType(Type t, Type s) { |
duke@1 | 1705 | return disjointType.visit(t, s); |
duke@1 | 1706 | } |
duke@1 | 1707 | // where |
duke@1 | 1708 | private TypeRelation disjointType = new TypeRelation() { |
duke@1 | 1709 | |
duke@1 | 1710 | private Set<TypePair> cache = new HashSet<TypePair>(); |
duke@1 | 1711 | |
vromero@1853 | 1712 | @Override |
duke@1 | 1713 | public Boolean visitType(Type t, Type s) { |
vromero@1853 | 1714 | if (s.hasTag(WILDCARD)) |
duke@1 | 1715 | return visit(s, t); |
duke@1 | 1716 | else |
duke@1 | 1717 | return notSoftSubtypeRecursive(t, s) || notSoftSubtypeRecursive(s, t); |
duke@1 | 1718 | } |
duke@1 | 1719 | |
duke@1 | 1720 | private boolean isCastableRecursive(Type t, Type s) { |
duke@1 | 1721 | TypePair pair = new TypePair(t, s); |
duke@1 | 1722 | if (cache.add(pair)) { |
duke@1 | 1723 | try { |
duke@1 | 1724 | return Types.this.isCastable(t, s); |
duke@1 | 1725 | } finally { |
duke@1 | 1726 | cache.remove(pair); |
duke@1 | 1727 | } |
duke@1 | 1728 | } else { |
duke@1 | 1729 | return true; |
duke@1 | 1730 | } |
duke@1 | 1731 | } |
duke@1 | 1732 | |
duke@1 | 1733 | private boolean notSoftSubtypeRecursive(Type t, Type s) { |
duke@1 | 1734 | TypePair pair = new TypePair(t, s); |
duke@1 | 1735 | if (cache.add(pair)) { |
duke@1 | 1736 | try { |
duke@1 | 1737 | return Types.this.notSoftSubtype(t, s); |
duke@1 | 1738 | } finally { |
duke@1 | 1739 | cache.remove(pair); |
duke@1 | 1740 | } |
duke@1 | 1741 | } else { |
duke@1 | 1742 | return false; |
duke@1 | 1743 | } |
duke@1 | 1744 | } |
duke@1 | 1745 | |
duke@1 | 1746 | @Override |
duke@1 | 1747 | public Boolean visitWildcardType(WildcardType t, Type s) { |
duke@1 | 1748 | if (t.isUnbound()) |
duke@1 | 1749 | return false; |
duke@1 | 1750 | |
vromero@1853 | 1751 | if (!s.hasTag(WILDCARD)) { |
duke@1 | 1752 | if (t.isExtendsBound()) |
duke@1 | 1753 | return notSoftSubtypeRecursive(s, t.type); |
vromero@1853 | 1754 | else |
duke@1 | 1755 | return notSoftSubtypeRecursive(t.type, s); |
duke@1 | 1756 | } |
duke@1 | 1757 | |
duke@1 | 1758 | if (s.isUnbound()) |
duke@1 | 1759 | return false; |
duke@1 | 1760 | |
duke@1 | 1761 | if (t.isExtendsBound()) { |
duke@1 | 1762 | if (s.isExtendsBound()) |
duke@1 | 1763 | return !isCastableRecursive(t.type, upperBound(s)); |
duke@1 | 1764 | else if (s.isSuperBound()) |
duke@1 | 1765 | return notSoftSubtypeRecursive(lowerBound(s), t.type); |
duke@1 | 1766 | } else if (t.isSuperBound()) { |
duke@1 | 1767 | if (s.isExtendsBound()) |
duke@1 | 1768 | return notSoftSubtypeRecursive(t.type, upperBound(s)); |
duke@1 | 1769 | } |
duke@1 | 1770 | return false; |
duke@1 | 1771 | } |
duke@1 | 1772 | }; |
duke@1 | 1773 | // </editor-fold> |
duke@1 | 1774 | |
duke@1 | 1775 | // <editor-fold defaultstate="collapsed" desc="lowerBoundArgtypes"> |
duke@1 | 1776 | /** |
duke@1 | 1777 | * Returns the lower bounds of the formals of a method. |
duke@1 | 1778 | */ |
duke@1 | 1779 | public List<Type> lowerBoundArgtypes(Type t) { |
mcimadamore@1348 | 1780 | return lowerBounds(t.getParameterTypes()); |
mcimadamore@1348 | 1781 | } |
mcimadamore@1348 | 1782 | public List<Type> lowerBounds(List<Type> ts) { |
mcimadamore@1348 | 1783 | return map(ts, lowerBoundMapping); |
duke@1 | 1784 | } |
duke@1 | 1785 | private final Mapping lowerBoundMapping = new Mapping("lowerBound") { |
duke@1 | 1786 | public Type apply(Type t) { |
duke@1 | 1787 | return lowerBound(t); |
duke@1 | 1788 | } |
duke@1 | 1789 | }; |
duke@1 | 1790 | // </editor-fold> |
duke@1 | 1791 | |
duke@1 | 1792 | // <editor-fold defaultstate="collapsed" desc="notSoftSubtype"> |
duke@1 | 1793 | /** |
duke@1 | 1794 | * This relation answers the question: is impossible that |
duke@1 | 1795 | * something of type `t' can be a subtype of `s'? This is |
duke@1 | 1796 | * different from the question "is `t' not a subtype of `s'?" |
duke@1 | 1797 | * when type variables are involved: Integer is not a subtype of T |
jjg@1358 | 1798 | * where {@code <T extends Number>} but it is not true that Integer cannot |
duke@1 | 1799 | * possibly be a subtype of T. |
duke@1 | 1800 | */ |
duke@1 | 1801 | public boolean notSoftSubtype(Type t, Type s) { |
duke@1 | 1802 | if (t == s) return false; |
vromero@1853 | 1803 | if (t.hasTag(TYPEVAR)) { |
duke@1 | 1804 | TypeVar tv = (TypeVar) t; |
duke@1 | 1805 | return !isCastable(tv.bound, |
mcimadamore@640 | 1806 | relaxBound(s), |
mcimadamore@1415 | 1807 | noWarnings); |
duke@1 | 1808 | } |
vromero@1853 | 1809 | if (!s.hasTag(WILDCARD)) |
duke@1 | 1810 | s = upperBound(s); |
mcimadamore@640 | 1811 | |
mcimadamore@640 | 1812 | return !isSubtype(t, relaxBound(s)); |
mcimadamore@640 | 1813 | } |
mcimadamore@640 | 1814 | |
mcimadamore@640 | 1815 | private Type relaxBound(Type t) { |
vromero@1853 | 1816 | if (t.hasTag(TYPEVAR)) { |
vromero@1853 | 1817 | while (t.hasTag(TYPEVAR)) |
mcimadamore@640 | 1818 | t = t.getUpperBound(); |
mcimadamore@640 | 1819 | t = rewriteQuantifiers(t, true, true); |
mcimadamore@640 | 1820 | } |
mcimadamore@640 | 1821 | return t; |
duke@1 | 1822 | } |
duke@1 | 1823 | // </editor-fold> |
duke@1 | 1824 | |
duke@1 | 1825 | // <editor-fold defaultstate="collapsed" desc="isReifiable"> |
duke@1 | 1826 | public boolean isReifiable(Type t) { |
duke@1 | 1827 | return isReifiable.visit(t); |
duke@1 | 1828 | } |
duke@1 | 1829 | // where |
duke@1 | 1830 | private UnaryVisitor<Boolean> isReifiable = new UnaryVisitor<Boolean>() { |
duke@1 | 1831 | |
duke@1 | 1832 | public Boolean visitType(Type t, Void ignored) { |
duke@1 | 1833 | return true; |
duke@1 | 1834 | } |
duke@1 | 1835 | |
duke@1 | 1836 | @Override |
duke@1 | 1837 | public Boolean visitClassType(ClassType t, Void ignored) { |
mcimadamore@356 | 1838 | if (t.isCompound()) |
mcimadamore@356 | 1839 | return false; |
mcimadamore@356 | 1840 | else { |
mcimadamore@356 | 1841 | if (!t.isParameterized()) |
mcimadamore@356 | 1842 | return true; |
mcimadamore@356 | 1843 | |
mcimadamore@356 | 1844 | for (Type param : t.allparams()) { |
mcimadamore@356 | 1845 | if (!param.isUnbound()) |
mcimadamore@356 | 1846 | return false; |
mcimadamore@356 | 1847 | } |
duke@1 | 1848 | return true; |
duke@1 | 1849 | } |
duke@1 | 1850 | } |
duke@1 | 1851 | |
duke@1 | 1852 | @Override |
duke@1 | 1853 | public Boolean visitArrayType(ArrayType t, Void ignored) { |
duke@1 | 1854 | return visit(t.elemtype); |
duke@1 | 1855 | } |
duke@1 | 1856 | |
duke@1 | 1857 | @Override |
duke@1 | 1858 | public Boolean visitTypeVar(TypeVar t, Void ignored) { |
duke@1 | 1859 | return false; |
duke@1 | 1860 | } |
duke@1 | 1861 | }; |
duke@1 | 1862 | // </editor-fold> |
duke@1 | 1863 | |
duke@1 | 1864 | // <editor-fold defaultstate="collapsed" desc="Array Utils"> |
duke@1 | 1865 | public boolean isArray(Type t) { |
vromero@1853 | 1866 | while (t.hasTag(WILDCARD)) |
duke@1 | 1867 | t = upperBound(t); |
vromero@1853 | 1868 | return t.hasTag(ARRAY); |
duke@1 | 1869 | } |
duke@1 | 1870 | |
duke@1 | 1871 | /** |
duke@1 | 1872 | * The element type of an array. |
duke@1 | 1873 | */ |
duke@1 | 1874 | public Type elemtype(Type t) { |
vromero@1853 | 1875 | switch (t.getTag()) { |
duke@1 | 1876 | case WILDCARD: |
duke@1 | 1877 | return elemtype(upperBound(t)); |
duke@1 | 1878 | case ARRAY: |
jjg@1521 | 1879 | t = t.unannotatedType(); |
duke@1 | 1880 | return ((ArrayType)t).elemtype; |
duke@1 | 1881 | case FORALL: |
duke@1 | 1882 | return elemtype(((ForAll)t).qtype); |
duke@1 | 1883 | case ERROR: |
duke@1 | 1884 | return t; |
duke@1 | 1885 | default: |
duke@1 | 1886 | return null; |
duke@1 | 1887 | } |
duke@1 | 1888 | } |
duke@1 | 1889 | |
mcimadamore@787 | 1890 | public Type elemtypeOrType(Type t) { |
mcimadamore@787 | 1891 | Type elemtype = elemtype(t); |
mcimadamore@787 | 1892 | return elemtype != null ? |
mcimadamore@787 | 1893 | elemtype : |
mcimadamore@787 | 1894 | t; |
mcimadamore@787 | 1895 | } |
mcimadamore@787 | 1896 | |
duke@1 | 1897 | /** |
duke@1 | 1898 | * Mapping to take element type of an arraytype |
duke@1 | 1899 | */ |
duke@1 | 1900 | private Mapping elemTypeFun = new Mapping ("elemTypeFun") { |
duke@1 | 1901 | public Type apply(Type t) { return elemtype(t); } |
duke@1 | 1902 | }; |
duke@1 | 1903 | |
duke@1 | 1904 | /** |
duke@1 | 1905 | * The number of dimensions of an array type. |
duke@1 | 1906 | */ |
duke@1 | 1907 | public int dimensions(Type t) { |
duke@1 | 1908 | int result = 0; |
vromero@1853 | 1909 | while (t.hasTag(ARRAY)) { |
duke@1 | 1910 | result++; |
duke@1 | 1911 | t = elemtype(t); |
duke@1 | 1912 | } |
duke@1 | 1913 | return result; |
duke@1 | 1914 | } |
jfranck@1313 | 1915 | |
jfranck@1313 | 1916 | /** |
jfranck@1313 | 1917 | * Returns an ArrayType with the component type t |
jfranck@1313 | 1918 | * |
jfranck@1313 | 1919 | * @param t The component type of the ArrayType |
jfranck@1313 | 1920 | * @return the ArrayType for the given component |
jfranck@1313 | 1921 | */ |
jfranck@1313 | 1922 | public ArrayType makeArrayType(Type t) { |
vromero@1853 | 1923 | if (t.hasTag(VOID) || t.hasTag(PACKAGE)) { |
jjg@1374 | 1924 | Assert.error("Type t must not be a VOID or PACKAGE type, " + t.toString()); |
jfranck@1313 | 1925 | } |
jfranck@1313 | 1926 | return new ArrayType(t, syms.arrayClass); |
jfranck@1313 | 1927 | } |
duke@1 | 1928 | // </editor-fold> |
duke@1 | 1929 | |
duke@1 | 1930 | // <editor-fold defaultstate="collapsed" desc="asSuper"> |
duke@1 | 1931 | /** |
duke@1 | 1932 | * Return the (most specific) base type of t that starts with the |
duke@1 | 1933 | * given symbol. If none exists, return null. |
duke@1 | 1934 | * |
duke@1 | 1935 | * @param t a type |
duke@1 | 1936 | * @param sym a symbol |
duke@1 | 1937 | */ |
emc@2079 | 1938 | public Type asSuper(Type t, Symbol s) { |
emc@2079 | 1939 | return asSuper(t, s.type); |
emc@2079 | 1940 | } |
emc@2079 | 1941 | |
emc@2079 | 1942 | public Type asSuper(Type t, Type s) { |
emc@2079 | 1943 | return asSuper.visit(t, s); |
duke@1 | 1944 | } |
duke@1 | 1945 | // where |
emc@2079 | 1946 | private SimpleVisitor<Type,Type> asSuper = new SimpleVisitor<Type,Type>() { |
emc@2079 | 1947 | |
emc@2079 | 1948 | public Type visitType(Type t, Type s) { |
duke@1 | 1949 | return null; |
duke@1 | 1950 | } |
duke@1 | 1951 | |
duke@1 | 1952 | @Override |
emc@2079 | 1953 | public Type visitClassType(ClassType t, Type s) { |
emc@2079 | 1954 | if (t.tsym == s.tsym) |
duke@1 | 1955 | return t; |
duke@1 | 1956 | |
duke@1 | 1957 | Type st = supertype(t); |
emc@2079 | 1958 | |
emc@2079 | 1959 | switch(st.getTag()) { |
emc@2079 | 1960 | default: break; |
emc@2079 | 1961 | case CLASS: |
emc@2079 | 1962 | case ARRAY: |
emc@2079 | 1963 | case TYPEVAR: |
emc@2079 | 1964 | case ERROR: { |
emc@2079 | 1965 | Type x = asSuper(st, s); |
duke@1 | 1966 | if (x != null) |
duke@1 | 1967 | return x; |
emc@2079 | 1968 | } break; |
duke@1 | 1969 | } |
emc@2079 | 1970 | |
emc@2079 | 1971 | if ((s.tsym.flags() & INTERFACE) != 0) { |
duke@1 | 1972 | for (List<Type> l = interfaces(t); l.nonEmpty(); l = l.tail) { |
emc@2079 | 1973 | Type x = asSuper(l.head, s); |
duke@1 | 1974 | if (x != null) |
duke@1 | 1975 | return x; |
duke@1 | 1976 | } |
duke@1 | 1977 | } |
duke@1 | 1978 | return null; |
duke@1 | 1979 | } |
duke@1 | 1980 | |
duke@1 | 1981 | @Override |
emc@2079 | 1982 | public Type visitArrayType(ArrayType t, Type s) { |
emc@2079 | 1983 | return isSubtype(t, s) ? s : null; |
duke@1 | 1984 | } |
duke@1 | 1985 | |
duke@1 | 1986 | @Override |
emc@2079 | 1987 | public Type visitTypeVar(TypeVar t, Type s) { |
emc@2079 | 1988 | if (t.tsym == s.tsym) |
mcimadamore@19 | 1989 | return t; |
mcimadamore@19 | 1990 | else |
emc@2079 | 1991 | return asSuper(t.bound, s); |
duke@1 | 1992 | } |
duke@1 | 1993 | |
duke@1 | 1994 | @Override |
emc@2079 | 1995 | public Type visitErrorType(ErrorType t, Type s) { return t; } |
duke@1 | 1996 | }; |
duke@1 | 1997 | |
duke@1 | 1998 | /** |
duke@1 | 1999 | * Return the base type of t or any of its outer types that starts |
duke@1 | 2000 | * with the given symbol. If none exists, return null. |
duke@1 | 2001 | * |
duke@1 | 2002 | * @param t a type |
duke@1 | 2003 | * @param sym a symbol |
duke@1 | 2004 | */ |
duke@1 | 2005 | public Type asOuterSuper(Type t, Symbol sym) { |
vromero@1853 | 2006 | switch (t.getTag()) { |
duke@1 | 2007 | case CLASS: |
duke@1 | 2008 | do { |
duke@1 | 2009 | Type s = asSuper(t, sym); |
duke@1 | 2010 | if (s != null) return s; |
duke@1 | 2011 | t = t.getEnclosingType(); |
vromero@1853 | 2012 | } while (t.hasTag(CLASS)); |
duke@1 | 2013 | return null; |
duke@1 | 2014 | case ARRAY: |
duke@1 | 2015 | return isSubtype(t, sym.type) ? sym.type : null; |
duke@1 | 2016 | case TYPEVAR: |
duke@1 | 2017 | return asSuper(t, sym); |
duke@1 | 2018 | case ERROR: |
duke@1 | 2019 | return t; |
duke@1 | 2020 | default: |
duke@1 | 2021 | return null; |
duke@1 | 2022 | } |
duke@1 | 2023 | } |
duke@1 | 2024 | |
duke@1 | 2025 | /** |
duke@1 | 2026 | * Return the base type of t or any of its enclosing types that |
duke@1 | 2027 | * starts with the given symbol. If none exists, return null. |
duke@1 | 2028 | * |
duke@1 | 2029 | * @param t a type |
duke@1 | 2030 | * @param sym a symbol |
duke@1 | 2031 | */ |
duke@1 | 2032 | public Type asEnclosingSuper(Type t, Symbol sym) { |
vromero@1853 | 2033 | switch (t.getTag()) { |
duke@1 | 2034 | case CLASS: |
duke@1 | 2035 | do { |
duke@1 | 2036 | Type s = asSuper(t, sym); |
duke@1 | 2037 | if (s != null) return s; |
duke@1 | 2038 | Type outer = t.getEnclosingType(); |
vromero@1853 | 2039 | t = (outer.hasTag(CLASS)) ? outer : |
duke@1 | 2040 | (t.tsym.owner.enclClass() != null) ? t.tsym.owner.enclClass().type : |
duke@1 | 2041 | Type.noType; |
vromero@1853 | 2042 | } while (t.hasTag(CLASS)); |
duke@1 | 2043 | return null; |
duke@1 | 2044 | case ARRAY: |
duke@1 | 2045 | return isSubtype(t, sym.type) ? sym.type : null; |
duke@1 | 2046 | case TYPEVAR: |
duke@1 | 2047 | return asSuper(t, sym); |
duke@1 | 2048 | case ERROR: |
duke@1 | 2049 | return t; |
duke@1 | 2050 | default: |
duke@1 | 2051 | return null; |
duke@1 | 2052 | } |
duke@1 | 2053 | } |
duke@1 | 2054 | // </editor-fold> |
duke@1 | 2055 | |
duke@1 | 2056 | // <editor-fold defaultstate="collapsed" desc="memberType"> |
duke@1 | 2057 | /** |
duke@1 | 2058 | * The type of given symbol, seen as a member of t. |
duke@1 | 2059 | * |
duke@1 | 2060 | * @param t a type |
duke@1 | 2061 | * @param sym a symbol |
duke@1 | 2062 | */ |
duke@1 | 2063 | public Type memberType(Type t, Symbol sym) { |
duke@1 | 2064 | return (sym.flags() & STATIC) != 0 |
duke@1 | 2065 | ? sym.type |
duke@1 | 2066 | : memberType.visit(t, sym); |
mcimadamore@341 | 2067 | } |
duke@1 | 2068 | // where |
duke@1 | 2069 | private SimpleVisitor<Type,Symbol> memberType = new SimpleVisitor<Type,Symbol>() { |
duke@1 | 2070 | |
duke@1 | 2071 | public Type visitType(Type t, Symbol sym) { |
duke@1 | 2072 | return sym.type; |
duke@1 | 2073 | } |
duke@1 | 2074 | |
duke@1 | 2075 | @Override |
duke@1 | 2076 | public Type visitWildcardType(WildcardType t, Symbol sym) { |
duke@1 | 2077 | return memberType(upperBound(t), sym); |
duke@1 | 2078 | } |
duke@1 | 2079 | |
duke@1 | 2080 | @Override |
duke@1 | 2081 | public Type visitClassType(ClassType t, Symbol sym) { |
duke@1 | 2082 | Symbol owner = sym.owner; |
duke@1 | 2083 | long flags = sym.flags(); |
duke@1 | 2084 | if (((flags & STATIC) == 0) && owner.type.isParameterized()) { |
duke@1 | 2085 | Type base = asOuterSuper(t, owner); |
mcimadamore@134 | 2086 | //if t is an intersection type T = CT & I1 & I2 ... & In |
mcimadamore@134 | 2087 | //its supertypes CT, I1, ... In might contain wildcards |
mcimadamore@134 | 2088 | //so we need to go through capture conversion |
mcimadamore@134 | 2089 | base = t.isCompound() ? capture(base) : base; |
duke@1 | 2090 | if (base != null) { |
duke@1 | 2091 | List<Type> ownerParams = owner.type.allparams(); |
duke@1 | 2092 | List<Type> baseParams = base.allparams(); |
duke@1 | 2093 | if (ownerParams.nonEmpty()) { |
duke@1 | 2094 | if (baseParams.isEmpty()) { |
duke@1 | 2095 | // then base is a raw type |
duke@1 | 2096 | return erasure(sym.type); |
duke@1 | 2097 | } else { |
duke@1 | 2098 | return subst(sym.type, ownerParams, baseParams); |
duke@1 | 2099 | } |
duke@1 | 2100 | } |
duke@1 | 2101 | } |
duke@1 | 2102 | } |
duke@1 | 2103 | return sym.type; |
duke@1 | 2104 | } |
duke@1 | 2105 | |
duke@1 | 2106 | @Override |
duke@1 | 2107 | public Type visitTypeVar(TypeVar t, Symbol sym) { |
duke@1 | 2108 | return memberType(t.bound, sym); |
duke@1 | 2109 | } |
duke@1 | 2110 | |
duke@1 | 2111 | @Override |
duke@1 | 2112 | public Type visitErrorType(ErrorType t, Symbol sym) { |
duke@1 | 2113 | return t; |
duke@1 | 2114 | } |
duke@1 | 2115 | }; |
duke@1 | 2116 | // </editor-fold> |
duke@1 | 2117 | |
duke@1 | 2118 | // <editor-fold defaultstate="collapsed" desc="isAssignable"> |
duke@1 | 2119 | public boolean isAssignable(Type t, Type s) { |
mcimadamore@1415 | 2120 | return isAssignable(t, s, noWarnings); |
duke@1 | 2121 | } |
duke@1 | 2122 | |
duke@1 | 2123 | /** |
duke@1 | 2124 | * Is t assignable to s?<br> |
duke@1 | 2125 | * Equivalent to subtype except for constant values and raw |
duke@1 | 2126 | * types.<br> |
duke@1 | 2127 | * (not defined for Method and ForAll types) |
duke@1 | 2128 | */ |
duke@1 | 2129 | public boolean isAssignable(Type t, Type s, Warner warn) { |
vromero@1853 | 2130 | if (t.hasTag(ERROR)) |
duke@1 | 2131 | return true; |
vromero@1853 | 2132 | if (t.getTag().isSubRangeOf(INT) && t.constValue() != null) { |
duke@1 | 2133 | int value = ((Number)t.constValue()).intValue(); |
vromero@1853 | 2134 | switch (s.getTag()) { |
duke@1 | 2135 | case BYTE: |
duke@1 | 2136 | if (Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE) |
duke@1 | 2137 | return true; |
duke@1 | 2138 | break; |
duke@1 | 2139 | case CHAR: |
duke@1 | 2140 | if (Character.MIN_VALUE <= value && value <= Character.MAX_VALUE) |
duke@1 | 2141 | return true; |
duke@1 | 2142 | break; |
duke@1 | 2143 | case SHORT: |
duke@1 | 2144 | if (Short.MIN_VALUE <= value && value <= Short.MAX_VALUE) |
duke@1 | 2145 | return true; |
duke@1 | 2146 | break; |
duke@1 | 2147 | case INT: |
duke@1 | 2148 | return true; |
duke@1 | 2149 | case CLASS: |
vromero@1853 | 2150 | switch (unboxedType(s).getTag()) { |
duke@1 | 2151 | case BYTE: |
duke@1 | 2152 | case CHAR: |
duke@1 | 2153 | case SHORT: |
duke@1 | 2154 | return isAssignable(t, unboxedType(s), warn); |
duke@1 | 2155 | } |
duke@1 | 2156 | break; |
duke@1 | 2157 | } |
duke@1 | 2158 | } |
duke@1 | 2159 | return isConvertible(t, s, warn); |
duke@1 | 2160 | } |
duke@1 | 2161 | // </editor-fold> |
duke@1 | 2162 | |
duke@1 | 2163 | // <editor-fold defaultstate="collapsed" desc="erasure"> |
duke@1 | 2164 | /** |
duke@1 | 2165 | * The erasure of t {@code |t|} -- the type that results when all |
duke@1 | 2166 | * type parameters in t are deleted. |
duke@1 | 2167 | */ |
duke@1 | 2168 | public Type erasure(Type t) { |
sundar@1307 | 2169 | return eraseNotNeeded(t)? t : erasure(t, false); |
mcimadamore@30 | 2170 | } |
mcimadamore@30 | 2171 | //where |
sundar@1307 | 2172 | private boolean eraseNotNeeded(Type t) { |
sundar@1307 | 2173 | // We don't want to erase primitive types and String type as that |
sundar@1307 | 2174 | // operation is idempotent. Also, erasing these could result in loss |
sundar@1307 | 2175 | // of information such as constant values attached to such types. |
jjg@1374 | 2176 | return (t.isPrimitive()) || (syms.stringType.tsym == t.tsym); |
sundar@1307 | 2177 | } |
sundar@1307 | 2178 | |
mcimadamore@30 | 2179 | private Type erasure(Type t, boolean recurse) { |
jjg@1374 | 2180 | if (t.isPrimitive()) |
duke@1 | 2181 | return t; /* fast special case */ |
duke@1 | 2182 | else |
mcimadamore@30 | 2183 | return erasure.visit(t, recurse); |
mcimadamore@341 | 2184 | } |
duke@1 | 2185 | // where |
mcimadamore@30 | 2186 | private SimpleVisitor<Type, Boolean> erasure = new SimpleVisitor<Type, Boolean>() { |
mcimadamore@30 | 2187 | public Type visitType(Type t, Boolean recurse) { |
jjg@1374 | 2188 | if (t.isPrimitive()) |
duke@1 | 2189 | return t; /*fast special case*/ |
duke@1 | 2190 | else |
mcimadamore@30 | 2191 | return t.map(recurse ? erasureRecFun : erasureFun); |
duke@1 | 2192 | } |
duke@1 | 2193 | |
duke@1 | 2194 | @Override |
mcimadamore@30 | 2195 | public Type visitWildcardType(WildcardType t, Boolean recurse) { |
mcimadamore@30 | 2196 | return erasure(upperBound(t), recurse); |
duke@1 | 2197 | } |
duke@1 | 2198 | |
duke@1 | 2199 | @Override |
mcimadamore@30 | 2200 | public Type visitClassType(ClassType t, Boolean recurse) { |
mcimadamore@30 | 2201 | Type erased = t.tsym.erasure(Types.this); |
mcimadamore@30 | 2202 | if (recurse) { |
mcimadamore@30 | 2203 | erased = new ErasedClassType(erased.getEnclosingType(),erased.tsym); |
mcimadamore@30 | 2204 | } |
mcimadamore@30 | 2205 | return erased; |
duke@1 | 2206 | } |
duke@1 | 2207 | |
duke@1 | 2208 | @Override |
mcimadamore@30 | 2209 | public Type visitTypeVar(TypeVar t, Boolean recurse) { |
mcimadamore@30 | 2210 | return erasure(t.bound, recurse); |
duke@1 | 2211 | } |
duke@1 | 2212 | |
duke@1 | 2213 | @Override |
mcimadamore@30 | 2214 | public Type visitErrorType(ErrorType t, Boolean recurse) { |
duke@1 | 2215 | return t; |
duke@1 | 2216 | } |
jjg@1521 | 2217 | |
jjg@1521 | 2218 | @Override |
jjg@1521 | 2219 | public Type visitAnnotatedType(AnnotatedType t, Boolean recurse) { |
jjg@2134 | 2220 | Type erased = erasure(t.unannotatedType(), recurse); |
jjg@1644 | 2221 | if (erased.isAnnotated()) { |
jjg@1563 | 2222 | // This can only happen when the underlying type is a |
jjg@1563 | 2223 | // type variable and the upper bound of it is annotated. |
jjg@1563 | 2224 | // The annotation on the type variable overrides the one |
jjg@1563 | 2225 | // on the bound. |
jjg@2134 | 2226 | erased = ((AnnotatedType)erased).unannotatedType(); |
jjg@1563 | 2227 | } |
jjg@2134 | 2228 | return erased.annotatedType(t.getAnnotationMirrors()); |
jjg@1521 | 2229 | } |
duke@1 | 2230 | }; |
mcimadamore@30 | 2231 | |
duke@1 | 2232 | private Mapping erasureFun = new Mapping ("erasure") { |
duke@1 | 2233 | public Type apply(Type t) { return erasure(t); } |
duke@1 | 2234 | }; |
duke@1 | 2235 | |
mcimadamore@30 | 2236 | private Mapping erasureRecFun = new Mapping ("erasureRecursive") { |
mcimadamore@30 | 2237 | public Type apply(Type t) { return erasureRecursive(t); } |
mcimadamore@30 | 2238 | }; |
mcimadamore@30 | 2239 | |
duke@1 | 2240 | public List<Type> erasure(List<Type> ts) { |
duke@1 | 2241 | return Type.map(ts, erasureFun); |
duke@1 | 2242 | } |
mcimadamore@30 | 2243 | |
mcimadamore@30 | 2244 | public Type erasureRecursive(Type t) { |
mcimadamore@30 | 2245 | return erasure(t, true); |
mcimadamore@30 | 2246 | } |
mcimadamore@30 | 2247 | |
mcimadamore@30 | 2248 | public List<Type> erasureRecursive(List<Type> ts) { |
mcimadamore@30 | 2249 | return Type.map(ts, erasureRecFun); |
mcimadamore@30 | 2250 | } |
duke@1 | 2251 | // </editor-fold> |
duke@1 | 2252 | |
duke@1 | 2253 | // <editor-fold defaultstate="collapsed" desc="makeCompoundType"> |
duke@1 | 2254 | /** |
duke@1 | 2255 | * Make a compound type from non-empty list of types |
duke@1 | 2256 | * |
duke@1 | 2257 | * @param bounds the types from which the compound type is formed |
duke@1 | 2258 | * @param supertype is objectType if all bounds are interfaces, |
duke@1 | 2259 | * null otherwise. |
duke@1 | 2260 | */ |
mcimadamore@1436 | 2261 | public Type makeCompoundType(List<Type> bounds) { |
mcimadamore@1436 | 2262 | return makeCompoundType(bounds, bounds.head.tsym.isInterface()); |
mcimadamore@1436 | 2263 | } |
mcimadamore@1436 | 2264 | public Type makeCompoundType(List<Type> bounds, boolean allInterfaces) { |
mcimadamore@1436 | 2265 | Assert.check(bounds.nonEmpty()); |
mcimadamore@1436 | 2266 | Type firstExplicitBound = bounds.head; |
mcimadamore@1436 | 2267 | if (allInterfaces) { |
mcimadamore@1436 | 2268 | bounds = bounds.prepend(syms.objectType); |
mcimadamore@1436 | 2269 | } |
duke@1 | 2270 | ClassSymbol bc = |
duke@1 | 2271 | new ClassSymbol(ABSTRACT|PUBLIC|SYNTHETIC|COMPOUND|ACYCLIC, |
duke@1 | 2272 | Type.moreInfo |
duke@1 | 2273 | ? names.fromString(bounds.toString()) |
duke@1 | 2274 | : names.empty, |
mcimadamore@1436 | 2275 | null, |
duke@1 | 2276 | syms.noSymbol); |
mcimadamore@1436 | 2277 | bc.type = new IntersectionClassType(bounds, bc, allInterfaces); |
vromero@1853 | 2278 | bc.erasure_field = (bounds.head.hasTag(TYPEVAR)) ? |
mcimadamore@1436 | 2279 | syms.objectType : // error condition, recover |
mcimadamore@1436 | 2280 | erasure(firstExplicitBound); |
mcimadamore@1436 | 2281 | bc.members_field = new Scope(bc); |
mcimadamore@1436 | 2282 | return bc.type; |
duke@1 | 2283 | } |
duke@1 | 2284 | |
duke@1 | 2285 | /** |
duke@1 | 2286 | * A convenience wrapper for {@link #makeCompoundType(List)}; the |
duke@1 | 2287 | * arguments are converted to a list and passed to the other |
duke@1 | 2288 | * method. Note that this might cause a symbol completion. |
duke@1 | 2289 | * Hence, this version of makeCompoundType may not be called |
duke@1 | 2290 | * during a classfile read. |
duke@1 | 2291 | */ |
duke@1 | 2292 | public Type makeCompoundType(Type bound1, Type bound2) { |
duke@1 | 2293 | return makeCompoundType(List.of(bound1, bound2)); |
duke@1 | 2294 | } |
duke@1 | 2295 | // </editor-fold> |
duke@1 | 2296 | |
duke@1 | 2297 | // <editor-fold defaultstate="collapsed" desc="supertype"> |
duke@1 | 2298 | public Type supertype(Type t) { |
duke@1 | 2299 | return supertype.visit(t); |
duke@1 | 2300 | } |
duke@1 | 2301 | // where |
duke@1 | 2302 | private UnaryVisitor<Type> supertype = new UnaryVisitor<Type>() { |
duke@1 | 2303 | |
duke@1 | 2304 | public Type visitType(Type t, Void ignored) { |
duke@1 | 2305 | // A note on wildcards: there is no good way to |
duke@1 | 2306 | // determine a supertype for a super bounded wildcard. |
duke@1 | 2307 | return null; |
duke@1 | 2308 | } |
duke@1 | 2309 | |
duke@1 | 2310 | @Override |
duke@1 | 2311 | public Type visitClassType(ClassType t, Void ignored) { |
duke@1 | 2312 | if (t.supertype_field == null) { |
duke@1 | 2313 | Type supertype = ((ClassSymbol)t.tsym).getSuperclass(); |
duke@1 | 2314 | // An interface has no superclass; its supertype is Object. |
duke@1 | 2315 | if (t.isInterface()) |
duke@1 | 2316 | supertype = ((ClassType)t.tsym.type).supertype_field; |
duke@1 | 2317 | if (t.supertype_field == null) { |
duke@1 | 2318 | List<Type> actuals = classBound(t).allparams(); |
duke@1 | 2319 | List<Type> formals = t.tsym.type.allparams(); |
mcimadamore@30 | 2320 | if (t.hasErasedSupertypes()) { |
mcimadamore@30 | 2321 | t.supertype_field = erasureRecursive(supertype); |
mcimadamore@30 | 2322 | } else if (formals.nonEmpty()) { |
duke@1 | 2323 | t.supertype_field = subst(supertype, formals, actuals); |
duke@1 | 2324 | } |
mcimadamore@30 | 2325 | else { |
mcimadamore@30 | 2326 | t.supertype_field = supertype; |
mcimadamore@30 | 2327 | } |
duke@1 | 2328 | } |
duke@1 | 2329 | } |
duke@1 | 2330 | return t.supertype_field; |
duke@1 | 2331 | } |
duke@1 | 2332 | |
duke@1 | 2333 | /** |
duke@1 | 2334 | * The supertype is always a class type. If the type |
duke@1 | 2335 | * variable's bounds start with a class type, this is also |
duke@1 | 2336 | * the supertype. Otherwise, the supertype is |
duke@1 | 2337 | * java.lang.Object. |
duke@1 | 2338 | */ |
duke@1 | 2339 | @Override |
duke@1 | 2340 | public Type visitTypeVar(TypeVar t, Void ignored) { |
vromero@1853 | 2341 | if (t.bound.hasTag(TYPEVAR) || |
duke@1 | 2342 | (!t.bound.isCompound() && !t.bound.isInterface())) { |
duke@1 | 2343 | return t.bound; |
duke@1 | 2344 | } else { |
duke@1 | 2345 | return supertype(t.bound); |
duke@1 | 2346 | } |
duke@1 | 2347 | } |
duke@1 | 2348 | |
duke@1 | 2349 | @Override |
duke@1 | 2350 | public Type visitArrayType(ArrayType t, Void ignored) { |
duke@1 | 2351 | if (t.elemtype.isPrimitive() || isSameType(t.elemtype, syms.objectType)) |
duke@1 | 2352 | return arraySuperType(); |
duke@1 | 2353 | else |
duke@1 | 2354 | return new ArrayType(supertype(t.elemtype), t.tsym); |
duke@1 | 2355 | } |
duke@1 | 2356 | |
duke@1 | 2357 | @Override |
duke@1 | 2358 | public Type visitErrorType(ErrorType t, Void ignored) { |
mcimadamore@1902 | 2359 | return Type.noType; |
duke@1 | 2360 | } |
duke@1 | 2361 | }; |
duke@1 | 2362 | // </editor-fold> |
duke@1 | 2363 | |
duke@1 | 2364 | // <editor-fold defaultstate="collapsed" desc="interfaces"> |
duke@1 | 2365 | /** |
duke@1 | 2366 | * Return the interfaces implemented by this class. |
duke@1 | 2367 | */ |
duke@1 | 2368 | public List<Type> interfaces(Type t) { |
duke@1 | 2369 | return interfaces.visit(t); |
duke@1 | 2370 | } |
duke@1 | 2371 | // where |
duke@1 | 2372 | private UnaryVisitor<List<Type>> interfaces = new UnaryVisitor<List<Type>>() { |
duke@1 | 2373 | |
duke@1 | 2374 | public List<Type> visitType(Type t, Void ignored) { |
duke@1 | 2375 | return List.nil(); |
duke@1 | 2376 | } |
duke@1 | 2377 | |
duke@1 | 2378 | @Override |
duke@1 | 2379 | public List<Type> visitClassType(ClassType t, Void ignored) { |
duke@1 | 2380 | if (t.interfaces_field == null) { |
duke@1 | 2381 | List<Type> interfaces = ((ClassSymbol)t.tsym).getInterfaces(); |
duke@1 | 2382 | if (t.interfaces_field == null) { |
duke@1 | 2383 | // If t.interfaces_field is null, then t must |
duke@1 | 2384 | // be a parameterized type (not to be confused |
duke@1 | 2385 | // with a generic type declaration). |
duke@1 | 2386 | // Terminology: |
duke@1 | 2387 | // Parameterized type: List<String> |
duke@1 | 2388 | // Generic type declaration: class List<E> { ... } |
duke@1 | 2389 | // So t corresponds to List<String> and |
duke@1 | 2390 | // t.tsym.type corresponds to List<E>. |
duke@1 | 2391 | // The reason t must be parameterized type is |
duke@1 | 2392 | // that completion will happen as a side |
duke@1 | 2393 | // effect of calling |
duke@1 | 2394 | // ClassSymbol.getInterfaces. Since |
duke@1 | 2395 | // t.interfaces_field is null after |
duke@1 | 2396 | // completion, we can assume that t is not the |
duke@1 | 2397 | // type of a class/interface declaration. |
jjg@816 | 2398 | Assert.check(t != t.tsym.type, t); |
duke@1 | 2399 | List<Type> actuals = t.allparams(); |
duke@1 | 2400 | List<Type> formals = t.tsym.type.allparams(); |
mcimadamore@30 | 2401 | if (t.hasErasedSupertypes()) { |
mcimadamore@30 | 2402 | t.interfaces_field = erasureRecursive(interfaces); |
mcimadamore@30 | 2403 | } else if (formals.nonEmpty()) { |
duke@1 | 2404 | t.interfaces_field = |
duke@1 | 2405 | upperBounds(subst(interfaces, formals, actuals)); |
duke@1 | 2406 | } |
mcimadamore@30 | 2407 | else { |
mcimadamore@30 | 2408 | t.interfaces_field = interfaces; |
mcimadamore@30 | 2409 | } |
duke@1 | 2410 | } |
duke@1 | 2411 | } |
duke@1 | 2412 | return t.interfaces_field; |
duke@1 | 2413 | } |
duke@1 | 2414 | |
duke@1 | 2415 | @Override |
duke@1 | 2416 | public List<Type> visitTypeVar(TypeVar t, Void ignored) { |
duke@1 | 2417 | if (t.bound.isCompound()) |
duke@1 | 2418 | return interfaces(t.bound); |
duke@1 | 2419 | |
duke@1 | 2420 | if (t.bound.isInterface()) |
duke@1 | 2421 | return List.of(t.bound); |
duke@1 | 2422 | |
duke@1 | 2423 | return List.nil(); |
duke@1 | 2424 | } |
duke@1 | 2425 | }; |
mcimadamore@1393 | 2426 | |
emc@2050 | 2427 | public List<Type> directSupertypes(Type t) { |
emc@2050 | 2428 | return directSupertypes.visit(t); |
emc@2050 | 2429 | } |
emc@2050 | 2430 | // where |
emc@2050 | 2431 | private final UnaryVisitor<List<Type>> directSupertypes = new UnaryVisitor<List<Type>>() { |
emc@2050 | 2432 | |
emc@2050 | 2433 | public List<Type> visitType(final Type type, final Void ignored) { |
emc@2050 | 2434 | if (!type.isCompound()) { |
emc@2050 | 2435 | final Type sup = supertype(type); |
emc@2050 | 2436 | return (sup == Type.noType || sup == type || sup == null) |
emc@2050 | 2437 | ? interfaces(type) |
emc@2050 | 2438 | : interfaces(type).prepend(sup); |
emc@2050 | 2439 | } else { |
emc@2050 | 2440 | return visitIntersectionType((IntersectionClassType) type); |
emc@2050 | 2441 | } |
emc@2050 | 2442 | } |
emc@2050 | 2443 | |
emc@2050 | 2444 | private List<Type> visitIntersectionType(final IntersectionClassType it) { |
emc@2050 | 2445 | return it.getExplicitComponents(); |
emc@2050 | 2446 | } |
emc@2050 | 2447 | |
emc@2050 | 2448 | }; |
emc@2050 | 2449 | |
mcimadamore@1415 | 2450 | public boolean isDirectSuperInterface(TypeSymbol isym, TypeSymbol origin) { |
mcimadamore@1415 | 2451 | for (Type i2 : interfaces(origin.type)) { |
mcimadamore@1415 | 2452 | if (isym == i2.tsym) return true; |
mcimadamore@1393 | 2453 | } |
mcimadamore@1393 | 2454 | return false; |
mcimadamore@1393 | 2455 | } |
duke@1 | 2456 | // </editor-fold> |
duke@1 | 2457 | |
duke@1 | 2458 | // <editor-fold defaultstate="collapsed" desc="isDerivedRaw"> |
duke@1 | 2459 | Map<Type,Boolean> isDerivedRawCache = new HashMap<Type,Boolean>(); |
duke@1 | 2460 | |
duke@1 | 2461 | public boolean isDerivedRaw(Type t) { |
duke@1 | 2462 | Boolean result = isDerivedRawCache.get(t); |
duke@1 | 2463 | if (result == null) { |
duke@1 | 2464 | result = isDerivedRawInternal(t); |
duke@1 | 2465 | isDerivedRawCache.put(t, result); |
duke@1 | 2466 | } |
duke@1 | 2467 | return result; |
duke@1 | 2468 | } |
duke@1 | 2469 | |
duke@1 | 2470 | public boolean isDerivedRawInternal(Type t) { |
duke@1 | 2471 | if (t.isErroneous()) |
duke@1 | 2472 | return false; |
duke@1 | 2473 | return |
duke@1 | 2474 | t.isRaw() || |
duke@1 | 2475 | supertype(t) != null && isDerivedRaw(supertype(t)) || |
duke@1 | 2476 | isDerivedRaw(interfaces(t)); |
duke@1 | 2477 | } |
duke@1 | 2478 | |
duke@1 | 2479 | public boolean isDerivedRaw(List<Type> ts) { |
duke@1 | 2480 | List<Type> l = ts; |
duke@1 | 2481 | while (l.nonEmpty() && !isDerivedRaw(l.head)) l = l.tail; |
duke@1 | 2482 | return l.nonEmpty(); |
duke@1 | 2483 | } |
duke@1 | 2484 | // </editor-fold> |
duke@1 | 2485 | |
duke@1 | 2486 | // <editor-fold defaultstate="collapsed" desc="setBounds"> |
duke@1 | 2487 | /** |
duke@1 | 2488 | * Set the bounds field of the given type variable to reflect a |
duke@1 | 2489 | * (possibly multiple) list of bounds. |
duke@1 | 2490 | * @param t a type variable |
duke@1 | 2491 | * @param bounds the bounds, must be nonempty |
duke@1 | 2492 | * @param supertype is objectType if all bounds are interfaces, |
duke@1 | 2493 | * null otherwise. |
duke@1 | 2494 | */ |
mcimadamore@1436 | 2495 | public void setBounds(TypeVar t, List<Type> bounds) { |
mcimadamore@1436 | 2496 | setBounds(t, bounds, bounds.head.tsym.isInterface()); |
duke@1 | 2497 | } |
duke@1 | 2498 | |
duke@1 | 2499 | /** |
duke@1 | 2500 | * Same as {@link #setBounds(Type.TypeVar,List,Type)}, except that |
mcimadamore@563 | 2501 | * third parameter is computed directly, as follows: if all |
mcimadamore@563 | 2502 | * all bounds are interface types, the computed supertype is Object, |
mcimadamore@563 | 2503 | * otherwise the supertype is simply left null (in this case, the supertype |
mcimadamore@563 | 2504 | * is assumed to be the head of the bound list passed as second argument). |
mcimadamore@563 | 2505 | * Note that this check might cause a symbol completion. Hence, this version of |
duke@1 | 2506 | * setBounds may not be called during a classfile read. |
duke@1 | 2507 | */ |
mcimadamore@1436 | 2508 | public void setBounds(TypeVar t, List<Type> bounds, boolean allInterfaces) { |
mcimadamore@1436 | 2509 | t.bound = bounds.tail.isEmpty() ? |
mcimadamore@1436 | 2510 | bounds.head : |
mcimadamore@1436 | 2511 | makeCompoundType(bounds, allInterfaces); |
duke@1 | 2512 | t.rank_field = -1; |
duke@1 | 2513 | } |
duke@1 | 2514 | // </editor-fold> |
duke@1 | 2515 | |
duke@1 | 2516 | // <editor-fold defaultstate="collapsed" desc="getBounds"> |
duke@1 | 2517 | /** |
duke@1 | 2518 | * Return list of bounds of the given type variable. |
duke@1 | 2519 | */ |
duke@1 | 2520 | public List<Type> getBounds(TypeVar t) { |
mcimadamore@1436 | 2521 | if (t.bound.hasTag(NONE)) |
mcimadamore@1415 | 2522 | return List.nil(); |
mcimadamore@1415 | 2523 | else if (t.bound.isErroneous() || !t.bound.isCompound()) |
duke@1 | 2524 | return List.of(t.bound); |
duke@1 | 2525 | else if ((erasure(t).tsym.flags() & INTERFACE) == 0) |
duke@1 | 2526 | return interfaces(t).prepend(supertype(t)); |
duke@1 | 2527 | else |
duke@1 | 2528 | // No superclass was given in bounds. |
duke@1 | 2529 | // In this case, supertype is Object, erasure is first interface. |
duke@1 | 2530 | return interfaces(t); |
duke@1 | 2531 | } |
duke@1 | 2532 | // </editor-fold> |
duke@1 | 2533 | |
duke@1 | 2534 | // <editor-fold defaultstate="collapsed" desc="classBound"> |
duke@1 | 2535 | /** |
duke@1 | 2536 | * If the given type is a (possibly selected) type variable, |
duke@1 | 2537 | * return the bounding class of this type, otherwise return the |
duke@1 | 2538 | * type itself. |
duke@1 | 2539 | */ |
duke@1 | 2540 | public Type classBound(Type t) { |
duke@1 | 2541 | return classBound.visit(t); |
duke@1 | 2542 | } |
duke@1 | 2543 | // where |
duke@1 | 2544 | private UnaryVisitor<Type> classBound = new UnaryVisitor<Type>() { |
duke@1 | 2545 | |
duke@1 | 2546 | public Type visitType(Type t, Void ignored) { |
duke@1 | 2547 | return t; |
duke@1 | 2548 | } |
duke@1 | 2549 | |
duke@1 | 2550 | @Override |
duke@1 | 2551 | public Type visitClassType(ClassType t, Void ignored) { |
duke@1 | 2552 | Type outer1 = classBound(t.getEnclosingType()); |
duke@1 | 2553 | if (outer1 != t.getEnclosingType()) |
duke@1 | 2554 | return new ClassType(outer1, t.getTypeArguments(), t.tsym); |
duke@1 | 2555 | else |
duke@1 | 2556 | return t; |
duke@1 | 2557 | } |
duke@1 | 2558 | |
duke@1 | 2559 | @Override |
duke@1 | 2560 | public Type visitTypeVar(TypeVar t, Void ignored) { |
duke@1 | 2561 | return classBound(supertype(t)); |
duke@1 | 2562 | } |
duke@1 | 2563 | |
duke@1 | 2564 | @Override |
duke@1 | 2565 | public Type visitErrorType(ErrorType t, Void ignored) { |
duke@1 | 2566 | return t; |
duke@1 | 2567 | } |
duke@1 | 2568 | }; |
duke@1 | 2569 | // </editor-fold> |
duke@1 | 2570 | |
duke@1 | 2571 | // <editor-fold defaultstate="collapsed" desc="sub signature / override equivalence"> |
duke@1 | 2572 | /** |
duke@1 | 2573 | * Returns true iff the first signature is a <em>sub |
duke@1 | 2574 | * signature</em> of the other. This is <b>not</b> an equivalence |
duke@1 | 2575 | * relation. |
duke@1 | 2576 | * |
jjh@972 | 2577 | * @jls section 8.4.2. |
duke@1 | 2578 | * @see #overrideEquivalent(Type t, Type s) |
duke@1 | 2579 | * @param t first signature (possibly raw). |
duke@1 | 2580 | * @param s second signature (could be subjected to erasure). |
duke@1 | 2581 | * @return true if t is a sub signature of s. |
duke@1 | 2582 | */ |
duke@1 | 2583 | public boolean isSubSignature(Type t, Type s) { |
mcimadamore@907 | 2584 | return isSubSignature(t, s, true); |
mcimadamore@907 | 2585 | } |
mcimadamore@907 | 2586 | |
mcimadamore@907 | 2587 | public boolean isSubSignature(Type t, Type s, boolean strict) { |
mcimadamore@907 | 2588 | return hasSameArgs(t, s, strict) || hasSameArgs(t, erasure(s), strict); |
duke@1 | 2589 | } |
duke@1 | 2590 | |
duke@1 | 2591 | /** |
duke@1 | 2592 | * Returns true iff these signatures are related by <em>override |
duke@1 | 2593 | * equivalence</em>. This is the natural extension of |
duke@1 | 2594 | * isSubSignature to an equivalence relation. |
duke@1 | 2595 | * |
jjh@972 | 2596 | * @jls section 8.4.2. |
duke@1 | 2597 | * @see #isSubSignature(Type t, Type s) |
duke@1 | 2598 | * @param t a signature (possible raw, could be subjected to |
duke@1 | 2599 | * erasure). |
duke@1 | 2600 | * @param s a signature (possible raw, could be subjected to |
duke@1 | 2601 | * erasure). |
duke@1 | 2602 | * @return true if either argument is a sub signature of the other. |
duke@1 | 2603 | */ |
duke@1 | 2604 | public boolean overrideEquivalent(Type t, Type s) { |
duke@1 | 2605 | return hasSameArgs(t, s) || |
duke@1 | 2606 | hasSameArgs(t, erasure(s)) || hasSameArgs(erasure(t), s); |
duke@1 | 2607 | } |
duke@1 | 2608 | |
mcimadamore@1348 | 2609 | public boolean overridesObjectMethod(TypeSymbol origin, Symbol msym) { |
mcimadamore@1348 | 2610 | for (Scope.Entry e = syms.objectType.tsym.members().lookup(msym.name) ; e.scope != null ; e = e.next()) { |
mcimadamore@1348 | 2611 | if (msym.overrides(e.sym, origin, Types.this, true)) { |
mcimadamore@1348 | 2612 | return true; |
mcimadamore@1348 | 2613 | } |
mcimadamore@1348 | 2614 | } |
mcimadamore@1348 | 2615 | return false; |
mcimadamore@1348 | 2616 | } |
mcimadamore@1348 | 2617 | |
mcimadamore@673 | 2618 | // <editor-fold defaultstate="collapsed" desc="Determining method implementation in given site"> |
mcimadamore@673 | 2619 | class ImplementationCache { |
mcimadamore@673 | 2620 | |
mcimadamore@673 | 2621 | private WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, Entry>>> _map = |
mcimadamore@673 | 2622 | new WeakHashMap<MethodSymbol, SoftReference<Map<TypeSymbol, Entry>>>(); |
mcimadamore@673 | 2623 | |
mcimadamore@673 | 2624 | class Entry { |
mcimadamore@673 | 2625 | final MethodSymbol cachedImpl; |
mcimadamore@673 | 2626 | final Filter<Symbol> implFilter; |
mcimadamore@673 | 2627 | final boolean checkResult; |
mcimadamore@877 | 2628 | final int prevMark; |
mcimadamore@673 | 2629 | |
mcimadamore@673 | 2630 | public Entry(MethodSymbol cachedImpl, |
mcimadamore@673 | 2631 | Filter<Symbol> scopeFilter, |
mcimadamore@877 | 2632 | boolean checkResult, |
mcimadamore@877 | 2633 | int prevMark) { |
mcimadamore@673 | 2634 | this.cachedImpl = cachedImpl; |
mcimadamore@673 | 2635 | this.implFilter = scopeFilter; |
mcimadamore@673 | 2636 | this.checkResult = checkResult; |
mcimadamore@877 | 2637 | this.prevMark = prevMark; |
mcimadamore@673 | 2638 | } |
mcimadamore@673 | 2639 | |
mcimadamore@877 | 2640 | boolean matches(Filter<Symbol> scopeFilter, boolean checkResult, int mark) { |
mcimadamore@673 | 2641 | return this.implFilter == scopeFilter && |
mcimadamore@877 | 2642 | this.checkResult == checkResult && |
mcimadamore@877 | 2643 | this.prevMark == mark; |
mcimadamore@673 | 2644 | } |
mcimadamore@341 | 2645 | } |
mcimadamore@673 | 2646 | |
mcimadamore@858 | 2647 | MethodSymbol get(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter<Symbol> implFilter) { |
mcimadamore@673 | 2648 | SoftReference<Map<TypeSymbol, Entry>> ref_cache = _map.get(ms); |
mcimadamore@673 | 2649 | Map<TypeSymbol, Entry> cache = ref_cache != null ? ref_cache.get() : null; |
mcimadamore@673 | 2650 | if (cache == null) { |
mcimadamore@673 | 2651 | cache = new HashMap<TypeSymbol, Entry>(); |
mcimadamore@673 | 2652 | _map.put(ms, new SoftReference<Map<TypeSymbol, Entry>>(cache)); |
mcimadamore@673 | 2653 | } |
mcimadamore@673 | 2654 | Entry e = cache.get(origin); |
mcimadamore@1015 | 2655 | CompoundScope members = membersClosure(origin.type, true); |
mcimadamore@673 | 2656 | if (e == null || |
mcimadamore@877 | 2657 | !e.matches(implFilter, checkResult, members.getMark())) { |
mcimadamore@877 | 2658 | MethodSymbol impl = implementationInternal(ms, origin, checkResult, implFilter); |
mcimadamore@877 | 2659 | cache.put(origin, new Entry(impl, implFilter, checkResult, members.getMark())); |
mcimadamore@673 | 2660 | return impl; |
mcimadamore@673 | 2661 | } |
mcimadamore@673 | 2662 | else { |
mcimadamore@673 | 2663 | return e.cachedImpl; |
mcimadamore@673 | 2664 | } |
mcimadamore@673 | 2665 | } |
mcimadamore@673 | 2666 | |
mcimadamore@877 | 2667 | private MethodSymbol implementationInternal(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter<Symbol> implFilter) { |
vromero@1853 | 2668 | for (Type t = origin.type; t.hasTag(CLASS) || t.hasTag(TYPEVAR); t = supertype(t)) { |
vromero@1853 | 2669 | while (t.hasTag(TYPEVAR)) |
mcimadamore@341 | 2670 | t = t.getUpperBound(); |
mcimadamore@341 | 2671 | TypeSymbol c = t.tsym; |
mcimadamore@673 | 2672 | for (Scope.Entry e = c.members().lookup(ms.name, implFilter); |
mcimadamore@341 | 2673 | e.scope != null; |
mcimadamore@780 | 2674 | e = e.next(implFilter)) { |
mcimadamore@673 | 2675 | if (e.sym != null && |
mcimadamore@877 | 2676 | e.sym.overrides(ms, origin, Types.this, checkResult)) |
mcimadamore@673 | 2677 | return (MethodSymbol)e.sym; |
mcimadamore@341 | 2678 | } |
mcimadamore@341 | 2679 | } |
mcimadamore@673 | 2680 | return null; |
mcimadamore@341 | 2681 | } |
mcimadamore@341 | 2682 | } |
mcimadamore@341 | 2683 | |
mcimadamore@673 | 2684 | private ImplementationCache implCache = new ImplementationCache(); |
mcimadamore@673 | 2685 | |
mcimadamore@858 | 2686 | public MethodSymbol implementation(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter<Symbol> implFilter) { |
mcimadamore@858 | 2687 | return implCache.get(ms, origin, checkResult, implFilter); |
mcimadamore@673 | 2688 | } |
mcimadamore@673 | 2689 | // </editor-fold> |
mcimadamore@673 | 2690 | |
mcimadamore@858 | 2691 | // <editor-fold defaultstate="collapsed" desc="compute transitive closure of all members in given site"> |
mcimadamore@1015 | 2692 | class MembersClosureCache extends SimpleVisitor<CompoundScope, Boolean> { |
mcimadamore@1015 | 2693 | |
mcimadamore@1015 | 2694 | private WeakHashMap<TypeSymbol, Entry> _map = |
mcimadamore@1015 | 2695 | new WeakHashMap<TypeSymbol, Entry>(); |
mcimadamore@1015 | 2696 | |
mcimadamore@1015 | 2697 | class Entry { |
mcimadamore@1015 | 2698 | final boolean skipInterfaces; |
mcimadamore@1015 | 2699 | final CompoundScope compoundScope; |
mcimadamore@1015 | 2700 | |
mcimadamore@1015 | 2701 | public Entry(boolean skipInterfaces, CompoundScope compoundScope) { |
mcimadamore@1015 | 2702 | this.skipInterfaces = skipInterfaces; |
mcimadamore@1015 | 2703 | this.compoundScope = compoundScope; |
mcimadamore@1015 | 2704 | } |
mcimadamore@1015 | 2705 | |
mcimadamore@1015 | 2706 | boolean matches(boolean skipInterfaces) { |
mcimadamore@1015 | 2707 | return this.skipInterfaces == skipInterfaces; |
mcimadamore@1015 | 2708 | } |
mcimadamore@1015 | 2709 | } |
mcimadamore@1015 | 2710 | |
mcimadamore@1072 | 2711 | List<TypeSymbol> seenTypes = List.nil(); |
mcimadamore@1072 | 2712 | |
mcimadamore@1015 | 2713 | /** members closure visitor methods **/ |
mcimadamore@1015 | 2714 | |
mcimadamore@1015 | 2715 | public CompoundScope visitType(Type t, Boolean skipInterface) { |
mcimadamore@858 | 2716 | return null; |
mcimadamore@858 | 2717 | } |
mcimadamore@858 | 2718 | |
mcimadamore@858 | 2719 | @Override |
mcimadamore@1015 | 2720 | public CompoundScope visitClassType(ClassType t, Boolean skipInterface) { |
mcimadamore@1072 | 2721 | if (seenTypes.contains(t.tsym)) { |
mcimadamore@1072 | 2722 | //this is possible when an interface is implemented in multiple |
mcimadamore@1072 | 2723 | //superclasses, or when a classs hierarchy is circular - in such |
mcimadamore@1072 | 2724 | //cases we don't need to recurse (empty scope is returned) |
mcimadamore@1072 | 2725 | return new CompoundScope(t.tsym); |
mcimadamore@1072 | 2726 | } |
mcimadamore@1072 | 2727 | try { |
mcimadamore@1072 | 2728 | seenTypes = seenTypes.prepend(t.tsym); |
mcimadamore@1072 | 2729 | ClassSymbol csym = (ClassSymbol)t.tsym; |
mcimadamore@1072 | 2730 | Entry e = _map.get(csym); |
mcimadamore@1072 | 2731 | if (e == null || !e.matches(skipInterface)) { |
mcimadamore@1072 | 2732 | CompoundScope membersClosure = new CompoundScope(csym); |
mcimadamore@1072 | 2733 | if (!skipInterface) { |
mcimadamore@1072 | 2734 | for (Type i : interfaces(t)) { |
mcimadamore@1072 | 2735 | membersClosure.addSubScope(visit(i, skipInterface)); |
mcimadamore@1072 | 2736 | } |
mcimadamore@1015 | 2737 | } |
mcimadamore@1072 | 2738 | membersClosure.addSubScope(visit(supertype(t), skipInterface)); |
mcimadamore@1072 | 2739 | membersClosure.addSubScope(csym.members()); |
mcimadamore@1072 | 2740 | e = new Entry(skipInterface, membersClosure); |
mcimadamore@1072 | 2741 | _map.put(csym, e); |
mcimadamore@858 | 2742 | } |
mcimadamore@1072 | 2743 | return e.compoundScope; |
mcimadamore@858 | 2744 | } |
mcimadamore@1072 | 2745 | finally { |
mcimadamore@1072 | 2746 | seenTypes = seenTypes.tail; |
mcimadamore@1072 | 2747 | } |
mcimadamore@858 | 2748 | } |
mcimadamore@858 | 2749 | |
mcimadamore@858 | 2750 | @Override |
mcimadamore@1015 | 2751 | public CompoundScope visitTypeVar(TypeVar t, Boolean skipInterface) { |
mcimadamore@1015 | 2752 | return visit(t.getUpperBound(), skipInterface); |
mcimadamore@858 | 2753 | } |
mcimadamore@1015 | 2754 | } |
mcimadamore@1015 | 2755 | |
mcimadamore@1015 | 2756 | private MembersClosureCache membersCache = new MembersClosureCache(); |
mcimadamore@1015 | 2757 | |
mcimadamore@1015 | 2758 | public CompoundScope membersClosure(Type site, boolean skipInterface) { |
mcimadamore@1015 | 2759 | return membersCache.visit(site, skipInterface); |
mcimadamore@1015 | 2760 | } |
mcimadamore@858 | 2761 | // </editor-fold> |
mcimadamore@858 | 2762 | |
mcimadamore@1393 | 2763 | |
mcimadamore@1393 | 2764 | //where |
mcimadamore@1393 | 2765 | public List<MethodSymbol> interfaceCandidates(Type site, MethodSymbol ms) { |
mcimadamore@1415 | 2766 | Filter<Symbol> filter = new MethodFilter(ms, site); |
mcimadamore@1393 | 2767 | List<MethodSymbol> candidates = List.nil(); |
mcimadamore@1678 | 2768 | for (Symbol s : membersClosure(site, false).getElements(filter)) { |
mcimadamore@1678 | 2769 | if (!site.tsym.isInterface() && !s.owner.isInterface()) { |
mcimadamore@1678 | 2770 | return List.of((MethodSymbol)s); |
mcimadamore@1678 | 2771 | } else if (!candidates.contains(s)) { |
mcimadamore@1678 | 2772 | candidates = candidates.prepend((MethodSymbol)s); |
mcimadamore@1678 | 2773 | } |
mcimadamore@1393 | 2774 | } |
mcimadamore@1678 | 2775 | return prune(candidates); |
mcimadamore@1393 | 2776 | } |
mcimadamore@1393 | 2777 | |
mcimadamore@1582 | 2778 | public List<MethodSymbol> prune(List<MethodSymbol> methods) { |
alundblad@2047 | 2779 | ListBuffer<MethodSymbol> methodsMin = new ListBuffer<>(); |
mcimadamore@1393 | 2780 | for (MethodSymbol m1 : methods) { |
mcimadamore@1393 | 2781 | boolean isMin_m1 = true; |
mcimadamore@1393 | 2782 | for (MethodSymbol m2 : methods) { |
mcimadamore@1393 | 2783 | if (m1 == m2) continue; |
mcimadamore@1582 | 2784 | if (m2.owner != m1.owner && |
mcimadamore@1582 | 2785 | asSuper(m2.owner.type, m1.owner) != null) { |
mcimadamore@1393 | 2786 | isMin_m1 = false; |
mcimadamore@1393 | 2787 | break; |
mcimadamore@1393 | 2788 | } |
mcimadamore@1393 | 2789 | } |
mcimadamore@1393 | 2790 | if (isMin_m1) |
mcimadamore@1393 | 2791 | methodsMin.append(m1); |
mcimadamore@1393 | 2792 | } |
mcimadamore@1393 | 2793 | return methodsMin.toList(); |
mcimadamore@1393 | 2794 | } |
mcimadamore@1393 | 2795 | // where |
mcimadamore@1393 | 2796 | private class MethodFilter implements Filter<Symbol> { |
mcimadamore@1393 | 2797 | |
mcimadamore@1393 | 2798 | Symbol msym; |
mcimadamore@1393 | 2799 | Type site; |
mcimadamore@1415 | 2800 | |
mcimadamore@1415 | 2801 | MethodFilter(Symbol msym, Type site) { |
mcimadamore@1393 | 2802 | this.msym = msym; |
mcimadamore@1393 | 2803 | this.site = site; |
mcimadamore@1393 | 2804 | } |
mcimadamore@1393 | 2805 | |
mcimadamore@1393 | 2806 | public boolean accepts(Symbol s) { |
mcimadamore@1393 | 2807 | return s.kind == Kinds.MTH && |
mcimadamore@1393 | 2808 | s.name == msym.name && |
mcimadamore@1882 | 2809 | (s.flags() & SYNTHETIC) == 0 && |
mcimadamore@1393 | 2810 | s.isInheritedIn(site.tsym, Types.this) && |
mcimadamore@1393 | 2811 | overrideEquivalent(memberType(site, s), memberType(site, msym)); |
mcimadamore@1393 | 2812 | } |
mcimadamore@1393 | 2813 | }; |
mcimadamore@1393 | 2814 | // </editor-fold> |
mcimadamore@1393 | 2815 | |
duke@1 | 2816 | /** |
duke@1 | 2817 | * Does t have the same arguments as s? It is assumed that both |
duke@1 | 2818 | * types are (possibly polymorphic) method types. Monomorphic |
duke@1 | 2819 | * method types "have the same arguments", if their argument lists |
duke@1 | 2820 | * are equal. Polymorphic method types "have the same arguments", |
duke@1 | 2821 | * if they have the same arguments after renaming all type |
duke@1 | 2822 | * variables of one to corresponding type variables in the other, |
duke@1 | 2823 | * where correspondence is by position in the type parameter list. |
duke@1 | 2824 | */ |
duke@1 | 2825 | public boolean hasSameArgs(Type t, Type s) { |
mcimadamore@907 | 2826 | return hasSameArgs(t, s, true); |
mcimadamore@907 | 2827 | } |
mcimadamore@907 | 2828 | |
mcimadamore@907 | 2829 | public boolean hasSameArgs(Type t, Type s, boolean strict) { |
mcimadamore@907 | 2830 | return hasSameArgs(t, s, strict ? hasSameArgs_strict : hasSameArgs_nonstrict); |
mcimadamore@907 | 2831 | } |
mcimadamore@907 | 2832 | |
mcimadamore@907 | 2833 | private boolean hasSameArgs(Type t, Type s, TypeRelation hasSameArgs) { |
duke@1 | 2834 | return hasSameArgs.visit(t, s); |
duke@1 | 2835 | } |
duke@1 | 2836 | // where |
mcimadamore@907 | 2837 | private class HasSameArgs extends TypeRelation { |
mcimadamore@907 | 2838 | |
mcimadamore@907 | 2839 | boolean strict; |
mcimadamore@907 | 2840 | |
mcimadamore@907 | 2841 | public HasSameArgs(boolean strict) { |
mcimadamore@907 | 2842 | this.strict = strict; |
mcimadamore@907 | 2843 | } |
duke@1 | 2844 | |
duke@1 | 2845 | public Boolean visitType(Type t, Type s) { |
duke@1 | 2846 | throw new AssertionError(); |
duke@1 | 2847 | } |
duke@1 | 2848 | |
duke@1 | 2849 | @Override |
duke@1 | 2850 | public Boolean visitMethodType(MethodType t, Type s) { |
vromero@1853 | 2851 | return s.hasTag(METHOD) |
duke@1 | 2852 | && containsTypeEquivalent(t.argtypes, s.getParameterTypes()); |
duke@1 | 2853 | } |
duke@1 | 2854 | |
duke@1 | 2855 | @Override |
duke@1 | 2856 | public Boolean visitForAll(ForAll t, Type s) { |
vromero@1853 | 2857 | if (!s.hasTag(FORALL)) |
mcimadamore@907 | 2858 | return strict ? false : visitMethodType(t.asMethodType(), s); |
duke@1 | 2859 | |
duke@1 | 2860 | ForAll forAll = (ForAll)s; |
duke@1 | 2861 | return hasSameBounds(t, forAll) |
duke@1 | 2862 | && visit(t.qtype, subst(forAll.qtype, forAll.tvars, t.tvars)); |
duke@1 | 2863 | } |
duke@1 | 2864 | |
duke@1 | 2865 | @Override |
duke@1 | 2866 | public Boolean visitErrorType(ErrorType t, Type s) { |
duke@1 | 2867 | return false; |
duke@1 | 2868 | } |
duke@1 | 2869 | }; |
mcimadamore@907 | 2870 | |
mcimadamore@907 | 2871 | TypeRelation hasSameArgs_strict = new HasSameArgs(true); |
mcimadamore@907 | 2872 | TypeRelation hasSameArgs_nonstrict = new HasSameArgs(false); |
mcimadamore@907 | 2873 | |
duke@1 | 2874 | // </editor-fold> |
duke@1 | 2875 | |
duke@1 | 2876 | // <editor-fold defaultstate="collapsed" desc="subst"> |
duke@1 | 2877 | public List<Type> subst(List<Type> ts, |
duke@1 | 2878 | List<Type> from, |
duke@1 | 2879 | List<Type> to) { |
duke@1 | 2880 | return new Subst(from, to).subst(ts); |
duke@1 | 2881 | } |
duke@1 | 2882 | |
duke@1 | 2883 | /** |
duke@1 | 2884 | * Substitute all occurrences of a type in `from' with the |
duke@1 | 2885 | * corresponding type in `to' in 't'. Match lists `from' and `to' |
duke@1 | 2886 | * from the right: If lists have different length, discard leading |
duke@1 | 2887 | * elements of the longer list. |
duke@1 | 2888 | */ |
duke@1 | 2889 | public Type subst(Type t, List<Type> from, List<Type> to) { |
duke@1 | 2890 | return new Subst(from, to).subst(t); |
duke@1 | 2891 | } |
duke@1 | 2892 | |
duke@1 | 2893 | private class Subst extends UnaryVisitor<Type> { |
duke@1 | 2894 | List<Type> from; |
duke@1 | 2895 | List<Type> to; |
duke@1 | 2896 | |
duke@1 | 2897 | public Subst(List<Type> from, List<Type> to) { |
duke@1 | 2898 | int fromLength = from.length(); |
duke@1 | 2899 | int toLength = to.length(); |
duke@1 | 2900 | while (fromLength > toLength) { |
duke@1 | 2901 | fromLength--; |
duke@1 | 2902 | from = from.tail; |
duke@1 | 2903 | } |
duke@1 | 2904 | while (fromLength < toLength) { |
duke@1 | 2905 | toLength--; |
duke@1 | 2906 | to = to.tail; |
duke@1 | 2907 | } |
duke@1 | 2908 | this.from = from; |
duke@1 | 2909 | this.to = to; |
duke@1 | 2910 | } |
duke@1 | 2911 | |
duke@1 | 2912 | Type subst(Type t) { |
duke@1 | 2913 | if (from.tail == null) |
duke@1 | 2914 | return t; |
duke@1 | 2915 | else |
duke@1 | 2916 | return visit(t); |
mcimadamore@238 | 2917 | } |
duke@1 | 2918 | |
duke@1 | 2919 | List<Type> subst(List<Type> ts) { |
duke@1 | 2920 | if (from.tail == null) |
duke@1 | 2921 | return ts; |
duke@1 | 2922 | boolean wild = false; |
duke@1 | 2923 | if (ts.nonEmpty() && from.nonEmpty()) { |
duke@1 | 2924 | Type head1 = subst(ts.head); |
duke@1 | 2925 | List<Type> tail1 = subst(ts.tail); |
duke@1 | 2926 | if (head1 != ts.head || tail1 != ts.tail) |
duke@1 | 2927 | return tail1.prepend(head1); |
duke@1 | 2928 | } |
duke@1 | 2929 | return ts; |
duke@1 | 2930 | } |
duke@1 | 2931 | |
duke@1 | 2932 | public Type visitType(Type t, Void ignored) { |
duke@1 | 2933 | return t; |
duke@1 | 2934 | } |
duke@1 | 2935 | |
duke@1 | 2936 | @Override |
duke@1 | 2937 | public Type visitMethodType(MethodType t, Void ignored) { |
duke@1 | 2938 | List<Type> argtypes = subst(t.argtypes); |
duke@1 | 2939 | Type restype = subst(t.restype); |
duke@1 | 2940 | List<Type> thrown = subst(t.thrown); |
duke@1 | 2941 | if (argtypes == t.argtypes && |
duke@1 | 2942 | restype == t.restype && |
duke@1 | 2943 | thrown == t.thrown) |
duke@1 | 2944 | return t; |
duke@1 | 2945 | else |
duke@1 | 2946 | return new MethodType(argtypes, restype, thrown, t.tsym); |
duke@1 | 2947 | } |
duke@1 | 2948 | |
duke@1 | 2949 | @Override |
duke@1 | 2950 | public Type visitTypeVar(TypeVar t, Void ignored) { |
duke@1 | 2951 | for (List<Type> from = this.from, to = this.to; |
duke@1 | 2952 | from.nonEmpty(); |
duke@1 | 2953 | from = from.tail, to = to.tail) { |
duke@1 | 2954 | if (t == from.head) { |
duke@1 | 2955 | return to.head.withTypeVar(t); |
duke@1 | 2956 | } |
duke@1 | 2957 | } |
duke@1 | 2958 | return t; |
duke@1 | 2959 | } |
duke@1 | 2960 | |
duke@1 | 2961 | @Override |
duke@1 | 2962 | public Type visitClassType(ClassType t, Void ignored) { |
duke@1 | 2963 | if (!t.isCompound()) { |
duke@1 | 2964 | List<Type> typarams = t.getTypeArguments(); |
duke@1 | 2965 | List<Type> typarams1 = subst(typarams); |
duke@1 | 2966 | Type outer = t.getEnclosingType(); |
duke@1 | 2967 | Type outer1 = subst(outer); |
duke@1 | 2968 | if (typarams1 == typarams && outer1 == outer) |
duke@1 | 2969 | return t; |
duke@1 | 2970 | else |
duke@1 | 2971 | return new ClassType(outer1, typarams1, t.tsym); |
duke@1 | 2972 | } else { |
duke@1 | 2973 | Type st = subst(supertype(t)); |
duke@1 | 2974 | List<Type> is = upperBounds(subst(interfaces(t))); |
duke@1 | 2975 | if (st == supertype(t) && is == interfaces(t)) |
duke@1 | 2976 | return t; |
duke@1 | 2977 | else |
duke@1 | 2978 | return makeCompoundType(is.prepend(st)); |
duke@1 | 2979 | } |
duke@1 | 2980 | } |
duke@1 | 2981 | |
duke@1 | 2982 | @Override |
duke@1 | 2983 | public Type visitWildcardType(WildcardType t, Void ignored) { |
duke@1 | 2984 | Type bound = t.type; |
duke@1 | 2985 | if (t.kind != BoundKind.UNBOUND) |
duke@1 | 2986 | bound = subst(bound); |
duke@1 | 2987 | if (bound == t.type) { |
duke@1 | 2988 | return t; |
duke@1 | 2989 | } else { |
duke@1 | 2990 | if (t.isExtendsBound() && bound.isExtendsBound()) |
duke@1 | 2991 | bound = upperBound(bound); |
duke@1 | 2992 | return new WildcardType(bound, t.kind, syms.boundClass, t.bound); |
duke@1 | 2993 | } |
duke@1 | 2994 | } |
duke@1 | 2995 | |
duke@1 | 2996 | @Override |
duke@1 | 2997 | public Type visitArrayType(ArrayType t, Void ignored) { |
duke@1 | 2998 | Type elemtype = subst(t.elemtype); |
duke@1 | 2999 | if (elemtype == t.elemtype) |
duke@1 | 3000 | return t; |
duke@1 | 3001 | else |
mcimadamore@1901 | 3002 | return new ArrayType(elemtype, t.tsym); |
duke@1 | 3003 | } |
duke@1 | 3004 | |
duke@1 | 3005 | @Override |
duke@1 | 3006 | public Type visitForAll(ForAll t, Void ignored) { |
mcimadamore@846 | 3007 | if (Type.containsAny(to, t.tvars)) { |
mcimadamore@846 | 3008 | //perform alpha-renaming of free-variables in 't' |
mcimadamore@846 | 3009 | //if 'to' types contain variables that are free in 't' |
mcimadamore@846 | 3010 | List<Type> freevars = newInstances(t.tvars); |
mcimadamore@846 | 3011 | t = new ForAll(freevars, |
mcimadamore@846 | 3012 | Types.this.subst(t.qtype, t.tvars, freevars)); |
mcimadamore@846 | 3013 | } |
duke@1 | 3014 | List<Type> tvars1 = substBounds(t.tvars, from, to); |
duke@1 | 3015 | Type qtype1 = subst(t.qtype); |
duke@1 | 3016 | if (tvars1 == t.tvars && qtype1 == t.qtype) { |
duke@1 | 3017 | return t; |
duke@1 | 3018 | } else if (tvars1 == t.tvars) { |
duke@1 | 3019 | return new ForAll(tvars1, qtype1); |
duke@1 | 3020 | } else { |
duke@1 | 3021 | return new ForAll(tvars1, Types.this.subst(qtype1, t.tvars, tvars1)); |
duke@1 | 3022 | } |
duke@1 | 3023 | } |
duke@1 | 3024 | |
duke@1 | 3025 | @Override |
duke@1 | 3026 | public Type visitErrorType(ErrorType t, Void ignored) { |
duke@1 | 3027 | return t; |
duke@1 | 3028 | } |
duke@1 | 3029 | } |
duke@1 | 3030 | |
duke@1 | 3031 | public List<Type> substBounds(List<Type> tvars, |
duke@1 | 3032 | List<Type> from, |
duke@1 | 3033 | List<Type> to) { |
duke@1 | 3034 | if (tvars.isEmpty()) |
duke@1 | 3035 | return tvars; |
alundblad@2047 | 3036 | ListBuffer<Type> newBoundsBuf = new ListBuffer<>(); |
duke@1 | 3037 | boolean changed = false; |
duke@1 | 3038 | // calculate new bounds |
duke@1 | 3039 | for (Type t : tvars) { |
duke@1 | 3040 | TypeVar tv = (TypeVar) t; |
duke@1 | 3041 | Type bound = subst(tv.bound, from, to); |
duke@1 | 3042 | if (bound != tv.bound) |
duke@1 | 3043 | changed = true; |
duke@1 | 3044 | newBoundsBuf.append(bound); |
duke@1 | 3045 | } |
duke@1 | 3046 | if (!changed) |
duke@1 | 3047 | return tvars; |
alundblad@2047 | 3048 | ListBuffer<Type> newTvars = new ListBuffer<>(); |
duke@1 | 3049 | // create new type variables without bounds |
duke@1 | 3050 | for (Type t : tvars) { |
duke@1 | 3051 | newTvars.append(new TypeVar(t.tsym, null, syms.botType)); |
duke@1 | 3052 | } |
duke@1 | 3053 | // the new bounds should use the new type variables in place |
duke@1 | 3054 | // of the old |
duke@1 | 3055 | List<Type> newBounds = newBoundsBuf.toList(); |
duke@1 | 3056 | from = tvars; |
duke@1 | 3057 | to = newTvars.toList(); |
duke@1 | 3058 | for (; !newBounds.isEmpty(); newBounds = newBounds.tail) { |
duke@1 | 3059 | newBounds.head = subst(newBounds.head, from, to); |
duke@1 | 3060 | } |
duke@1 | 3061 | newBounds = newBoundsBuf.toList(); |
duke@1 | 3062 | // set the bounds of new type variables to the new bounds |
duke@1 | 3063 | for (Type t : newTvars.toList()) { |
duke@1 | 3064 | TypeVar tv = (TypeVar) t; |
duke@1 | 3065 | tv.bound = newBounds.head; |
duke@1 | 3066 | newBounds = newBounds.tail; |
duke@1 | 3067 | } |
duke@1 | 3068 | return newTvars.toList(); |
duke@1 | 3069 | } |
duke@1 | 3070 | |
duke@1 | 3071 | public TypeVar substBound(TypeVar t, List<Type> from, List<Type> to) { |
duke@1 | 3072 | Type bound1 = subst(t.bound, from, to); |
duke@1 | 3073 | if (bound1 == t.bound) |
duke@1 | 3074 | return t; |
mcimadamore@212 | 3075 | else { |
mcimadamore@212 | 3076 | // create new type variable without bounds |
mcimadamore@212 | 3077 | TypeVar tv = new TypeVar(t.tsym, null, syms.botType); |
mcimadamore@212 | 3078 | // the new bound should use the new type variable in place |
mcimadamore@212 | 3079 | // of the old |
mcimadamore@212 | 3080 | tv.bound = subst(bound1, List.<Type>of(t), List.<Type>of(tv)); |
mcimadamore@212 | 3081 | return tv; |
mcimadamore@212 | 3082 | } |
duke@1 | 3083 | } |
duke@1 | 3084 | // </editor-fold> |
duke@1 | 3085 | |
duke@1 | 3086 | // <editor-fold defaultstate="collapsed" desc="hasSameBounds"> |
duke@1 | 3087 | /** |
duke@1 | 3088 | * Does t have the same bounds for quantified variables as s? |
duke@1 | 3089 | */ |
vromero@2000 | 3090 | public boolean hasSameBounds(ForAll t, ForAll s) { |
duke@1 | 3091 | List<Type> l1 = t.tvars; |
duke@1 | 3092 | List<Type> l2 = s.tvars; |
duke@1 | 3093 | while (l1.nonEmpty() && l2.nonEmpty() && |
duke@1 | 3094 | isSameType(l1.head.getUpperBound(), |
duke@1 | 3095 | subst(l2.head.getUpperBound(), |
duke@1 | 3096 | s.tvars, |
duke@1 | 3097 | t.tvars))) { |
duke@1 | 3098 | l1 = l1.tail; |
duke@1 | 3099 | l2 = l2.tail; |
duke@1 | 3100 | } |
duke@1 | 3101 | return l1.isEmpty() && l2.isEmpty(); |
duke@1 | 3102 | } |
duke@1 | 3103 | // </editor-fold> |
duke@1 | 3104 | |
duke@1 | 3105 | // <editor-fold defaultstate="collapsed" desc="newInstances"> |
duke@1 | 3106 | /** Create new vector of type variables from list of variables |
duke@1 | 3107 | * changing all recursive bounds from old to new list. |
duke@1 | 3108 | */ |
duke@1 | 3109 | public List<Type> newInstances(List<Type> tvars) { |
duke@1 | 3110 | List<Type> tvars1 = Type.map(tvars, newInstanceFun); |
duke@1 | 3111 | for (List<Type> l = tvars1; l.nonEmpty(); l = l.tail) { |
duke@1 | 3112 | TypeVar tv = (TypeVar) l.head; |
duke@1 | 3113 | tv.bound = subst(tv.bound, tvars, tvars1); |
duke@1 | 3114 | } |
duke@1 | 3115 | return tvars1; |
duke@1 | 3116 | } |
vromero@1442 | 3117 | private static final Mapping newInstanceFun = new Mapping("newInstanceFun") { |
duke@1 | 3118 | public Type apply(Type t) { return new TypeVar(t.tsym, t.getUpperBound(), t.getLowerBound()); } |
duke@1 | 3119 | }; |
duke@1 | 3120 | // </editor-fold> |
duke@1 | 3121 | |
dlsmith@880 | 3122 | public Type createMethodTypeWithParameters(Type original, List<Type> newParams) { |
dlsmith@880 | 3123 | return original.accept(methodWithParameters, newParams); |
dlsmith@880 | 3124 | } |
dlsmith@880 | 3125 | // where |
dlsmith@880 | 3126 | private final MapVisitor<List<Type>> methodWithParameters = new MapVisitor<List<Type>>() { |
dlsmith@880 | 3127 | public Type visitType(Type t, List<Type> newParams) { |
dlsmith@880 | 3128 | throw new IllegalArgumentException("Not a method type: " + t); |
dlsmith@880 | 3129 | } |
dlsmith@880 | 3130 | public Type visitMethodType(MethodType t, List<Type> newParams) { |
dlsmith@880 | 3131 | return new MethodType(newParams, t.restype, t.thrown, t.tsym); |
dlsmith@880 | 3132 | } |
dlsmith@880 | 3133 | public Type visitForAll(ForAll t, List<Type> newParams) { |
dlsmith@880 | 3134 | return new ForAll(t.tvars, t.qtype.accept(this, newParams)); |
dlsmith@880 | 3135 | } |
dlsmith@880 | 3136 | }; |
dlsmith@880 | 3137 | |
dlsmith@880 | 3138 | public Type createMethodTypeWithThrown(Type original, List<Type> newThrown) { |
dlsmith@880 | 3139 | return original.accept(methodWithThrown, newThrown); |
dlsmith@880 | 3140 | } |
dlsmith@880 | 3141 | // where |
dlsmith@880 | 3142 | private final MapVisitor<List<Type>> methodWithThrown = new MapVisitor<List<Type>>() { |
dlsmith@880 | 3143 | public Type visitType(Type t, List<Type> newThrown) { |
dlsmith@880 | 3144 | throw new IllegalArgumentException("Not a method type: " + t); |
dlsmith@880 | 3145 | } |
dlsmith@880 | 3146 | public Type visitMethodType(MethodType t, List<Type> newThrown) { |
dlsmith@880 | 3147 | return new MethodType(t.argtypes, t.restype, newThrown, t.tsym); |
dlsmith@880 | 3148 | } |
dlsmith@880 | 3149 | public Type visitForAll(ForAll t, List<Type> newThrown) { |
dlsmith@880 | 3150 | return new ForAll(t.tvars, t.qtype.accept(this, newThrown)); |
dlsmith@880 | 3151 | } |
dlsmith@880 | 3152 | }; |
dlsmith@880 | 3153 | |
mcimadamore@950 | 3154 | public Type createMethodTypeWithReturn(Type original, Type newReturn) { |
mcimadamore@950 | 3155 | return original.accept(methodWithReturn, newReturn); |
mcimadamore@950 | 3156 | } |
mcimadamore@950 | 3157 | // where |
mcimadamore@950 | 3158 | private final MapVisitor<Type> methodWithReturn = new MapVisitor<Type>() { |
mcimadamore@950 | 3159 | public Type visitType(Type t, Type newReturn) { |
mcimadamore@950 | 3160 | throw new IllegalArgumentException("Not a method type: " + t); |
mcimadamore@950 | 3161 | } |
mcimadamore@950 | 3162 | public Type visitMethodType(MethodType t, Type newReturn) { |
mcimadamore@950 | 3163 | return new MethodType(t.argtypes, newReturn, t.thrown, t.tsym); |
mcimadamore@950 | 3164 | } |
mcimadamore@950 | 3165 | public Type visitForAll(ForAll t, Type newReturn) { |
mcimadamore@950 | 3166 | return new ForAll(t.tvars, t.qtype.accept(this, newReturn)); |
mcimadamore@950 | 3167 | } |
mcimadamore@950 | 3168 | }; |
mcimadamore@950 | 3169 | |
jjg@110 | 3170 | // <editor-fold defaultstate="collapsed" desc="createErrorType"> |
jjg@110 | 3171 | public Type createErrorType(Type originalType) { |
jjg@110 | 3172 | return new ErrorType(originalType, syms.errSymbol); |
jjg@110 | 3173 | } |
jjg@110 | 3174 | |
jjg@110 | 3175 | public Type createErrorType(ClassSymbol c, Type originalType) { |
jjg@110 | 3176 | return new ErrorType(c, originalType); |
jjg@110 | 3177 | } |
jjg@110 | 3178 | |
jjg@110 | 3179 | public Type createErrorType(Name name, TypeSymbol container, Type originalType) { |
jjg@110 | 3180 | return new ErrorType(name, container, originalType); |
jjg@110 | 3181 | } |
jjg@110 | 3182 | // </editor-fold> |
jjg@110 | 3183 | |
duke@1 | 3184 | // <editor-fold defaultstate="collapsed" desc="rank"> |
duke@1 | 3185 | /** |
duke@1 | 3186 | * The rank of a class is the length of the longest path between |
duke@1 | 3187 | * the class and java.lang.Object in the class inheritance |
duke@1 | 3188 | * graph. Undefined for all but reference types. |
duke@1 | 3189 | */ |
duke@1 | 3190 | public int rank(Type t) { |
jjg@1521 | 3191 | t = t.unannotatedType(); |
vromero@1853 | 3192 | switch(t.getTag()) { |
duke@1 | 3193 | case CLASS: { |
duke@1 | 3194 | ClassType cls = (ClassType)t; |
duke@1 | 3195 | if (cls.rank_field < 0) { |
duke@1 | 3196 | Name fullname = cls.tsym.getQualifiedName(); |
jjg@113 | 3197 | if (fullname == names.java_lang_Object) |
duke@1 | 3198 | cls.rank_field = 0; |
duke@1 | 3199 | else { |
duke@1 | 3200 | int r = rank(supertype(cls)); |
duke@1 | 3201 | for (List<Type> l = interfaces(cls); |
duke@1 | 3202 | l.nonEmpty(); |
duke@1 | 3203 | l = l.tail) { |
duke@1 | 3204 | if (rank(l.head) > r) |
duke@1 | 3205 | r = rank(l.head); |
duke@1 | 3206 | } |
duke@1 | 3207 | cls.rank_field = r + 1; |
duke@1 | 3208 | } |
duke@1 | 3209 | } |
duke@1 | 3210 | return cls.rank_field; |
duke@1 | 3211 | } |
duke@1 | 3212 | case TYPEVAR: { |
duke@1 | 3213 | TypeVar tvar = (TypeVar)t; |
duke@1 | 3214 | if (tvar.rank_field < 0) { |
duke@1 | 3215 | int r = rank(supertype(tvar)); |
duke@1 | 3216 | for (List<Type> l = interfaces(tvar); |
duke@1 | 3217 | l.nonEmpty(); |
duke@1 | 3218 | l = l.tail) { |
duke@1 | 3219 | if (rank(l.head) > r) r = rank(l.head); |
duke@1 | 3220 | } |
duke@1 | 3221 | tvar.rank_field = r + 1; |
duke@1 | 3222 | } |
duke@1 | 3223 | return tvar.rank_field; |
duke@1 | 3224 | } |
duke@1 | 3225 | case ERROR: |
duke@1 | 3226 | return 0; |
duke@1 | 3227 | default: |
duke@1 | 3228 | throw new AssertionError(); |
duke@1 | 3229 | } |
duke@1 | 3230 | } |
duke@1 | 3231 | // </editor-fold> |
duke@1 | 3232 | |
mcimadamore@121 | 3233 | /** |
mcimadamore@238 | 3234 | * Helper method for generating a string representation of a given type |
mcimadamore@121 | 3235 | * accordingly to a given locale |
mcimadamore@121 | 3236 | */ |
mcimadamore@121 | 3237 | public String toString(Type t, Locale locale) { |
mcimadamore@238 | 3238 | return Printer.createStandardPrinter(messages).visit(t, locale); |
mcimadamore@121 | 3239 | } |
mcimadamore@121 | 3240 | |
mcimadamore@121 | 3241 | /** |
mcimadamore@238 | 3242 | * Helper method for generating a string representation of a given type |
mcimadamore@121 | 3243 | * accordingly to a given locale |
mcimadamore@121 | 3244 | */ |
mcimadamore@121 | 3245 | public String toString(Symbol t, Locale locale) { |
mcimadamore@238 | 3246 | return Printer.createStandardPrinter(messages).visit(t, locale); |
mcimadamore@121 | 3247 | } |
mcimadamore@121 | 3248 | |
duke@1 | 3249 | // <editor-fold defaultstate="collapsed" desc="toString"> |
duke@1 | 3250 | /** |
duke@1 | 3251 | * This toString is slightly more descriptive than the one on Type. |
mcimadamore@121 | 3252 | * |
mcimadamore@121 | 3253 | * @deprecated Types.toString(Type t, Locale l) provides better support |
mcimadamore@121 | 3254 | * for localization |
duke@1 | 3255 | */ |
mcimadamore@121 | 3256 | @Deprecated |
duke@1 | 3257 | public String toString(Type t) { |
vromero@1853 | 3258 | if (t.hasTag(FORALL)) { |
duke@1 | 3259 | ForAll forAll = (ForAll)t; |
duke@1 | 3260 | return typaramsString(forAll.tvars) + forAll.qtype; |
duke@1 | 3261 | } |
duke@1 | 3262 | return "" + t; |
duke@1 | 3263 | } |
duke@1 | 3264 | // where |
duke@1 | 3265 | private String typaramsString(List<Type> tvars) { |
jjg@904 | 3266 | StringBuilder s = new StringBuilder(); |
duke@1 | 3267 | s.append('<'); |
duke@1 | 3268 | boolean first = true; |
duke@1 | 3269 | for (Type t : tvars) { |
duke@1 | 3270 | if (!first) s.append(", "); |
duke@1 | 3271 | first = false; |
jjg@1755 | 3272 | appendTyparamString(((TypeVar)t.unannotatedType()), s); |
duke@1 | 3273 | } |
duke@1 | 3274 | s.append('>'); |
duke@1 | 3275 | return s.toString(); |
duke@1 | 3276 | } |
jjg@904 | 3277 | private void appendTyparamString(TypeVar t, StringBuilder buf) { |
duke@1 | 3278 | buf.append(t); |
duke@1 | 3279 | if (t.bound == null || |
duke@1 | 3280 | t.bound.tsym.getQualifiedName() == names.java_lang_Object) |
duke@1 | 3281 | return; |
duke@1 | 3282 | buf.append(" extends "); // Java syntax; no need for i18n |
duke@1 | 3283 | Type bound = t.bound; |
duke@1 | 3284 | if (!bound.isCompound()) { |
duke@1 | 3285 | buf.append(bound); |
duke@1 | 3286 | } else if ((erasure(t).tsym.flags() & INTERFACE) == 0) { |
duke@1 | 3287 | buf.append(supertype(t)); |
duke@1 | 3288 | for (Type intf : interfaces(t)) { |
duke@1 | 3289 | buf.append('&'); |
duke@1 | 3290 | buf.append(intf); |
duke@1 | 3291 | } |
duke@1 | 3292 | } else { |
duke@1 | 3293 | // No superclass was given in bounds. |
duke@1 | 3294 | // In this case, supertype is Object, erasure is first interface. |
duke@1 | 3295 | boolean first = true; |
duke@1 | 3296 | for (Type intf : interfaces(t)) { |
duke@1 | 3297 | if (!first) buf.append('&'); |
duke@1 | 3298 | first = false; |
duke@1 | 3299 | buf.append(intf); |
duke@1 | 3300 | } |
duke@1 | 3301 | } |
duke@1 | 3302 | } |
duke@1 | 3303 | // </editor-fold> |
duke@1 | 3304 | |
duke@1 | 3305 | // <editor-fold defaultstate="collapsed" desc="Determining least upper bounds of types"> |
duke@1 | 3306 | /** |
duke@1 | 3307 | * A cache for closures. |
duke@1 | 3308 | * |
duke@1 | 3309 | * <p>A closure is a list of all the supertypes and interfaces of |
duke@1 | 3310 | * a class or interface type, ordered by ClassSymbol.precedes |
duke@1 | 3311 | * (that is, subclasses come first, arbitrary but fixed |
duke@1 | 3312 | * otherwise). |
duke@1 | 3313 | */ |
duke@1 | 3314 | private Map<Type,List<Type>> closureCache = new HashMap<Type,List<Type>>(); |
duke@1 | 3315 | |
duke@1 | 3316 | /** |
duke@1 | 3317 | * Returns the closure of a class or interface type. |
duke@1 | 3318 | */ |
duke@1 | 3319 | public List<Type> closure(Type t) { |
duke@1 | 3320 | List<Type> cl = closureCache.get(t); |
duke@1 | 3321 | if (cl == null) { |
duke@1 | 3322 | Type st = supertype(t); |
duke@1 | 3323 | if (!t.isCompound()) { |
vromero@1853 | 3324 | if (st.hasTag(CLASS)) { |
duke@1 | 3325 | cl = insert(closure(st), t); |
vromero@1853 | 3326 | } else if (st.hasTag(TYPEVAR)) { |
duke@1 | 3327 | cl = closure(st).prepend(t); |
duke@1 | 3328 | } else { |
duke@1 | 3329 | cl = List.of(t); |
duke@1 | 3330 | } |
duke@1 | 3331 | } else { |
duke@1 | 3332 | cl = closure(supertype(t)); |
duke@1 | 3333 | } |
duke@1 | 3334 | for (List<Type> l = interfaces(t); l.nonEmpty(); l = l.tail) |
duke@1 | 3335 | cl = union(cl, closure(l.head)); |
duke@1 | 3336 | closureCache.put(t, cl); |
duke@1 | 3337 | } |
duke@1 | 3338 | return cl; |
duke@1 | 3339 | } |
duke@1 | 3340 | |
duke@1 | 3341 | /** |
duke@1 | 3342 | * Insert a type in a closure |
duke@1 | 3343 | */ |
duke@1 | 3344 | public List<Type> insert(List<Type> cl, Type t) { |
duke@1 | 3345 | if (cl.isEmpty() || t.tsym.precedes(cl.head.tsym, this)) { |
duke@1 | 3346 | return cl.prepend(t); |
duke@1 | 3347 | } else if (cl.head.tsym.precedes(t.tsym, this)) { |
duke@1 | 3348 | return insert(cl.tail, t).prepend(cl.head); |
duke@1 | 3349 | } else { |
duke@1 | 3350 | return cl; |
duke@1 | 3351 | } |
duke@1 | 3352 | } |
duke@1 | 3353 | |
duke@1 | 3354 | /** |
duke@1 | 3355 | * Form the union of two closures |
duke@1 | 3356 | */ |
duke@1 | 3357 | public List<Type> union(List<Type> cl1, List<Type> cl2) { |
duke@1 | 3358 | if (cl1.isEmpty()) { |
duke@1 | 3359 | return cl2; |
duke@1 | 3360 | } else if (cl2.isEmpty()) { |
duke@1 | 3361 | return cl1; |
duke@1 | 3362 | } else if (cl1.head.tsym.precedes(cl2.head.tsym, this)) { |
duke@1 | 3363 | return union(cl1.tail, cl2).prepend(cl1.head); |
duke@1 | 3364 | } else if (cl2.head.tsym.precedes(cl1.head.tsym, this)) { |
duke@1 | 3365 | return union(cl1, cl2.tail).prepend(cl2.head); |
duke@1 | 3366 | } else { |
duke@1 | 3367 | return union(cl1.tail, cl2.tail).prepend(cl1.head); |
duke@1 | 3368 | } |
duke@1 | 3369 | } |
duke@1 | 3370 | |
duke@1 | 3371 | /** |
duke@1 | 3372 | * Intersect two closures |
duke@1 | 3373 | */ |
duke@1 | 3374 | public List<Type> intersect(List<Type> cl1, List<Type> cl2) { |
duke@1 | 3375 | if (cl1 == cl2) |
duke@1 | 3376 | return cl1; |
duke@1 | 3377 | if (cl1.isEmpty() || cl2.isEmpty()) |
duke@1 | 3378 | return List.nil(); |
duke@1 | 3379 | if (cl1.head.tsym.precedes(cl2.head.tsym, this)) |
duke@1 | 3380 | return intersect(cl1.tail, cl2); |
duke@1 | 3381 | if (cl2.head.tsym.precedes(cl1.head.tsym, this)) |
duke@1 | 3382 | return intersect(cl1, cl2.tail); |
duke@1 | 3383 | if (isSameType(cl1.head, cl2.head)) |
duke@1 | 3384 | return intersect(cl1.tail, cl2.tail).prepend(cl1.head); |
duke@1 | 3385 | if (cl1.head.tsym == cl2.head.tsym && |
vromero@1853 | 3386 | cl1.head.hasTag(CLASS) && cl2.head.hasTag(CLASS)) { |
duke@1 | 3387 | if (cl1.head.isParameterized() && cl2.head.isParameterized()) { |
duke@1 | 3388 | Type merge = merge(cl1.head,cl2.head); |
duke@1 | 3389 | return intersect(cl1.tail, cl2.tail).prepend(merge); |
duke@1 | 3390 | } |
duke@1 | 3391 | if (cl1.head.isRaw() || cl2.head.isRaw()) |
duke@1 | 3392 | return intersect(cl1.tail, cl2.tail).prepend(erasure(cl1.head)); |
duke@1 | 3393 | } |
duke@1 | 3394 | return intersect(cl1.tail, cl2.tail); |
duke@1 | 3395 | } |
duke@1 | 3396 | // where |
duke@1 | 3397 | class TypePair { |
duke@1 | 3398 | final Type t1; |
duke@1 | 3399 | final Type t2; |
duke@1 | 3400 | TypePair(Type t1, Type t2) { |
duke@1 | 3401 | this.t1 = t1; |
duke@1 | 3402 | this.t2 = t2; |
duke@1 | 3403 | } |
duke@1 | 3404 | @Override |
duke@1 | 3405 | public int hashCode() { |
vromero@1452 | 3406 | return 127 * Types.this.hashCode(t1) + Types.this.hashCode(t2); |
duke@1 | 3407 | } |
duke@1 | 3408 | @Override |
duke@1 | 3409 | public boolean equals(Object obj) { |
duke@1 | 3410 | if (!(obj instanceof TypePair)) |
duke@1 | 3411 | return false; |
duke@1 | 3412 | TypePair typePair = (TypePair)obj; |
duke@1 | 3413 | return isSameType(t1, typePair.t1) |
duke@1 | 3414 | && isSameType(t2, typePair.t2); |
duke@1 | 3415 | } |
duke@1 | 3416 | } |
duke@1 | 3417 | Set<TypePair> mergeCache = new HashSet<TypePair>(); |
duke@1 | 3418 | private Type merge(Type c1, Type c2) { |
duke@1 | 3419 | ClassType class1 = (ClassType) c1; |
duke@1 | 3420 | List<Type> act1 = class1.getTypeArguments(); |
duke@1 | 3421 | ClassType class2 = (ClassType) c2; |
duke@1 | 3422 | List<Type> act2 = class2.getTypeArguments(); |
duke@1 | 3423 | ListBuffer<Type> merged = new ListBuffer<Type>(); |
duke@1 | 3424 | List<Type> typarams = class1.tsym.type.getTypeArguments(); |
duke@1 | 3425 | |
duke@1 | 3426 | while (act1.nonEmpty() && act2.nonEmpty() && typarams.nonEmpty()) { |
duke@1 | 3427 | if (containsType(act1.head, act2.head)) { |
duke@1 | 3428 | merged.append(act1.head); |
duke@1 | 3429 | } else if (containsType(act2.head, act1.head)) { |
duke@1 | 3430 | merged.append(act2.head); |
duke@1 | 3431 | } else { |
duke@1 | 3432 | TypePair pair = new TypePair(c1, c2); |
duke@1 | 3433 | Type m; |
duke@1 | 3434 | if (mergeCache.add(pair)) { |
duke@1 | 3435 | m = new WildcardType(lub(upperBound(act1.head), |
duke@1 | 3436 | upperBound(act2.head)), |
duke@1 | 3437 | BoundKind.EXTENDS, |
duke@1 | 3438 | syms.boundClass); |
duke@1 | 3439 | mergeCache.remove(pair); |
duke@1 | 3440 | } else { |
duke@1 | 3441 | m = new WildcardType(syms.objectType, |
duke@1 | 3442 | BoundKind.UNBOUND, |
duke@1 | 3443 | syms.boundClass); |
duke@1 | 3444 | } |
duke@1 | 3445 | merged.append(m.withTypeVar(typarams.head)); |
duke@1 | 3446 | } |
duke@1 | 3447 | act1 = act1.tail; |
duke@1 | 3448 | act2 = act2.tail; |
duke@1 | 3449 | typarams = typarams.tail; |
duke@1 | 3450 | } |
jjg@816 | 3451 | Assert.check(act1.isEmpty() && act2.isEmpty() && typarams.isEmpty()); |
duke@1 | 3452 | return new ClassType(class1.getEnclosingType(), merged.toList(), class1.tsym); |
duke@1 | 3453 | } |
duke@1 | 3454 | |
duke@1 | 3455 | /** |
duke@1 | 3456 | * Return the minimum type of a closure, a compound type if no |
duke@1 | 3457 | * unique minimum exists. |
duke@1 | 3458 | */ |
duke@1 | 3459 | private Type compoundMin(List<Type> cl) { |
duke@1 | 3460 | if (cl.isEmpty()) return syms.objectType; |
duke@1 | 3461 | List<Type> compound = closureMin(cl); |
duke@1 | 3462 | if (compound.isEmpty()) |
duke@1 | 3463 | return null; |
duke@1 | 3464 | else if (compound.tail.isEmpty()) |
duke@1 | 3465 | return compound.head; |
duke@1 | 3466 | else |
duke@1 | 3467 | return makeCompoundType(compound); |
duke@1 | 3468 | } |
duke@1 | 3469 | |
duke@1 | 3470 | /** |
duke@1 | 3471 | * Return the minimum types of a closure, suitable for computing |
duke@1 | 3472 | * compoundMin or glb. |
duke@1 | 3473 | */ |
duke@1 | 3474 | private List<Type> closureMin(List<Type> cl) { |
alundblad@2047 | 3475 | ListBuffer<Type> classes = new ListBuffer<>(); |
alundblad@2047 | 3476 | ListBuffer<Type> interfaces = new ListBuffer<>(); |
duke@1 | 3477 | while (!cl.isEmpty()) { |
duke@1 | 3478 | Type current = cl.head; |
duke@1 | 3479 | if (current.isInterface()) |
duke@1 | 3480 | interfaces.append(current); |
duke@1 | 3481 | else |
duke@1 | 3482 | classes.append(current); |
alundblad@2047 | 3483 | ListBuffer<Type> candidates = new ListBuffer<>(); |
duke@1 | 3484 | for (Type t : cl.tail) { |
duke@1 | 3485 | if (!isSubtypeNoCapture(current, t)) |
duke@1 | 3486 | candidates.append(t); |
duke@1 | 3487 | } |
duke@1 | 3488 | cl = candidates.toList(); |
duke@1 | 3489 | } |
duke@1 | 3490 | return classes.appendList(interfaces).toList(); |
duke@1 | 3491 | } |
duke@1 | 3492 | |
duke@1 | 3493 | /** |
duke@1 | 3494 | * Return the least upper bound of pair of types. if the lub does |
duke@1 | 3495 | * not exist return null. |
duke@1 | 3496 | */ |
duke@1 | 3497 | public Type lub(Type t1, Type t2) { |
duke@1 | 3498 | return lub(List.of(t1, t2)); |
duke@1 | 3499 | } |
duke@1 | 3500 | |
duke@1 | 3501 | /** |
duke@1 | 3502 | * Return the least upper bound (lub) of set of types. If the lub |
duke@1 | 3503 | * does not exist return the type of null (bottom). |
duke@1 | 3504 | */ |
duke@1 | 3505 | public Type lub(List<Type> ts) { |
duke@1 | 3506 | final int ARRAY_BOUND = 1; |
duke@1 | 3507 | final int CLASS_BOUND = 2; |
duke@1 | 3508 | int boundkind = 0; |
duke@1 | 3509 | for (Type t : ts) { |
vromero@1853 | 3510 | switch (t.getTag()) { |
duke@1 | 3511 | case CLASS: |
duke@1 | 3512 | boundkind |= CLASS_BOUND; |
duke@1 | 3513 | break; |
duke@1 | 3514 | case ARRAY: |
duke@1 | 3515 | boundkind |= ARRAY_BOUND; |
duke@1 | 3516 | break; |
duke@1 | 3517 | case TYPEVAR: |
duke@1 | 3518 | do { |
duke@1 | 3519 | t = t.getUpperBound(); |
vromero@1853 | 3520 | } while (t.hasTag(TYPEVAR)); |
vromero@1853 | 3521 | if (t.hasTag(ARRAY)) { |
duke@1 | 3522 | boundkind |= ARRAY_BOUND; |
duke@1 | 3523 | } else { |
duke@1 | 3524 | boundkind |= CLASS_BOUND; |
duke@1 | 3525 | } |
duke@1 | 3526 | break; |
duke@1 | 3527 | default: |
duke@1 | 3528 | if (t.isPrimitive()) |
mcimadamore@5 | 3529 | return syms.errType; |
duke@1 | 3530 | } |
duke@1 | 3531 | } |
duke@1 | 3532 | switch (boundkind) { |
duke@1 | 3533 | case 0: |
duke@1 | 3534 | return syms.botType; |
duke@1 | 3535 | |
duke@1 | 3536 | case ARRAY_BOUND: |
duke@1 | 3537 | // calculate lub(A[], B[]) |
duke@1 | 3538 | List<Type> elements = Type.map(ts, elemTypeFun); |
duke@1 | 3539 | for (Type t : elements) { |
duke@1 | 3540 | if (t.isPrimitive()) { |
duke@1 | 3541 | // if a primitive type is found, then return |
duke@1 | 3542 | // arraySuperType unless all the types are the |
duke@1 | 3543 | // same |
duke@1 | 3544 | Type first = ts.head; |
duke@1 | 3545 | for (Type s : ts.tail) { |
duke@1 | 3546 | if (!isSameType(first, s)) { |
duke@1 | 3547 | // lub(int[], B[]) is Cloneable & Serializable |
duke@1 | 3548 | return arraySuperType(); |
duke@1 | 3549 | } |
duke@1 | 3550 | } |
duke@1 | 3551 | // all the array types are the same, return one |
duke@1 | 3552 | // lub(int[], int[]) is int[] |
duke@1 | 3553 | return first; |
duke@1 | 3554 | } |
duke@1 | 3555 | } |
duke@1 | 3556 | // lub(A[], B[]) is lub(A, B)[] |
duke@1 | 3557 | return new ArrayType(lub(elements), syms.arrayClass); |
duke@1 | 3558 | |
duke@1 | 3559 | case CLASS_BOUND: |
duke@1 | 3560 | // calculate lub(A, B) |
vromero@1853 | 3561 | while (!ts.head.hasTag(CLASS) && !ts.head.hasTag(TYPEVAR)) { |
duke@1 | 3562 | ts = ts.tail; |
vromero@1853 | 3563 | } |
jjg@816 | 3564 | Assert.check(!ts.isEmpty()); |
mcimadamore@896 | 3565 | //step 1 - compute erased candidate set (EC) |
mcimadamore@896 | 3566 | List<Type> cl = erasedSupertypes(ts.head); |
duke@1 | 3567 | for (Type t : ts.tail) { |
vromero@1853 | 3568 | if (t.hasTag(CLASS) || t.hasTag(TYPEVAR)) |
mcimadamore@896 | 3569 | cl = intersect(cl, erasedSupertypes(t)); |
duke@1 | 3570 | } |
mcimadamore@896 | 3571 | //step 2 - compute minimal erased candidate set (MEC) |
mcimadamore@896 | 3572 | List<Type> mec = closureMin(cl); |
mcimadamore@896 | 3573 | //step 3 - for each element G in MEC, compute lci(Inv(G)) |
mcimadamore@896 | 3574 | List<Type> candidates = List.nil(); |
mcimadamore@896 | 3575 | for (Type erasedSupertype : mec) { |
emc@2079 | 3576 | List<Type> lci = List.of(asSuper(ts.head, erasedSupertype)); |
mcimadamore@896 | 3577 | for (Type t : ts) { |
emc@2079 | 3578 | lci = intersect(lci, List.of(asSuper(t, erasedSupertype))); |
mcimadamore@896 | 3579 | } |
mcimadamore@896 | 3580 | candidates = candidates.appendList(lci); |
mcimadamore@896 | 3581 | } |
mcimadamore@896 | 3582 | //step 4 - let MEC be { G1, G2 ... Gn }, then we have that |
mcimadamore@896 | 3583 | //lub = lci(Inv(G1)) & lci(Inv(G2)) & ... & lci(Inv(Gn)) |
mcimadamore@896 | 3584 | return compoundMin(candidates); |
duke@1 | 3585 | |
duke@1 | 3586 | default: |
duke@1 | 3587 | // calculate lub(A, B[]) |
duke@1 | 3588 | List<Type> classes = List.of(arraySuperType()); |
duke@1 | 3589 | for (Type t : ts) { |
vromero@1853 | 3590 | if (!t.hasTag(ARRAY)) // Filter out any arrays |
duke@1 | 3591 | classes = classes.prepend(t); |
duke@1 | 3592 | } |
duke@1 | 3593 | // lub(A, B[]) is lub(A, arraySuperType) |
duke@1 | 3594 | return lub(classes); |
duke@1 | 3595 | } |
duke@1 | 3596 | } |
duke@1 | 3597 | // where |
mcimadamore@896 | 3598 | List<Type> erasedSupertypes(Type t) { |
alundblad@2047 | 3599 | ListBuffer<Type> buf = new ListBuffer<>(); |
mcimadamore@896 | 3600 | for (Type sup : closure(t)) { |
vromero@1853 | 3601 | if (sup.hasTag(TYPEVAR)) { |
mcimadamore@896 | 3602 | buf.append(sup); |
mcimadamore@896 | 3603 | } else { |
mcimadamore@896 | 3604 | buf.append(erasure(sup)); |
mcimadamore@896 | 3605 | } |
mcimadamore@896 | 3606 | } |
mcimadamore@896 | 3607 | return buf.toList(); |
mcimadamore@896 | 3608 | } |
mcimadamore@896 | 3609 | |
duke@1 | 3610 | private Type arraySuperType = null; |
duke@1 | 3611 | private Type arraySuperType() { |
duke@1 | 3612 | // initialized lazily to avoid problems during compiler startup |
duke@1 | 3613 | if (arraySuperType == null) { |
duke@1 | 3614 | synchronized (this) { |
duke@1 | 3615 | if (arraySuperType == null) { |
duke@1 | 3616 | // JLS 10.8: all arrays implement Cloneable and Serializable. |
duke@1 | 3617 | arraySuperType = makeCompoundType(List.of(syms.serializableType, |
mcimadamore@1436 | 3618 | syms.cloneableType), true); |
duke@1 | 3619 | } |
duke@1 | 3620 | } |
duke@1 | 3621 | } |
duke@1 | 3622 | return arraySuperType; |
duke@1 | 3623 | } |
duke@1 | 3624 | // </editor-fold> |
duke@1 | 3625 | |
duke@1 | 3626 | // <editor-fold defaultstate="collapsed" desc="Greatest lower bound"> |
mcimadamore@210 | 3627 | public Type glb(List<Type> ts) { |
mcimadamore@210 | 3628 | Type t1 = ts.head; |
mcimadamore@210 | 3629 | for (Type t2 : ts.tail) { |
mcimadamore@210 | 3630 | if (t1.isErroneous()) |
mcimadamore@210 | 3631 | return t1; |
mcimadamore@210 | 3632 | t1 = glb(t1, t2); |
mcimadamore@210 | 3633 | } |
mcimadamore@210 | 3634 | return t1; |
mcimadamore@210 | 3635 | } |
mcimadamore@210 | 3636 | //where |
duke@1 | 3637 | public Type glb(Type t, Type s) { |
duke@1 | 3638 | if (s == null) |
duke@1 | 3639 | return t; |
mcimadamore@753 | 3640 | else if (t.isPrimitive() || s.isPrimitive()) |
mcimadamore@753 | 3641 | return syms.errType; |
duke@1 | 3642 | else if (isSubtypeNoCapture(t, s)) |
duke@1 | 3643 | return t; |
duke@1 | 3644 | else if (isSubtypeNoCapture(s, t)) |
duke@1 | 3645 | return s; |
duke@1 | 3646 | |
duke@1 | 3647 | List<Type> closure = union(closure(t), closure(s)); |
duke@1 | 3648 | List<Type> bounds = closureMin(closure); |
duke@1 | 3649 | |
duke@1 | 3650 | if (bounds.isEmpty()) { // length == 0 |
duke@1 | 3651 | return syms.objectType; |
duke@1 | 3652 | } else if (bounds.tail.isEmpty()) { // length == 1 |
duke@1 | 3653 | return bounds.head; |
duke@1 | 3654 | } else { // length > 1 |
duke@1 | 3655 | int classCount = 0; |
duke@1 | 3656 | for (Type bound : bounds) |
duke@1 | 3657 | if (!bound.isInterface()) |
duke@1 | 3658 | classCount++; |
duke@1 | 3659 | if (classCount > 1) |
jjg@110 | 3660 | return createErrorType(t); |
duke@1 | 3661 | } |
duke@1 | 3662 | return makeCompoundType(bounds); |
duke@1 | 3663 | } |
duke@1 | 3664 | // </editor-fold> |
duke@1 | 3665 | |
duke@1 | 3666 | // <editor-fold defaultstate="collapsed" desc="hashCode"> |
duke@1 | 3667 | /** |
duke@1 | 3668 | * Compute a hash code on a type. |
duke@1 | 3669 | */ |
vromero@1452 | 3670 | public int hashCode(Type t) { |
duke@1 | 3671 | return hashCode.visit(t); |
duke@1 | 3672 | } |
duke@1 | 3673 | // where |
duke@1 | 3674 | private static final UnaryVisitor<Integer> hashCode = new UnaryVisitor<Integer>() { |
duke@1 | 3675 | |
duke@1 | 3676 | public Integer visitType(Type t, Void ignored) { |
vromero@1853 | 3677 | return t.getTag().ordinal(); |
duke@1 | 3678 | } |
duke@1 | 3679 | |
duke@1 | 3680 | @Override |
duke@1 | 3681 | public Integer visitClassType(ClassType t, Void ignored) { |
duke@1 | 3682 | int result = visit(t.getEnclosingType()); |
duke@1 | 3683 | result *= 127; |
duke@1 | 3684 | result += t.tsym.flatName().hashCode(); |
duke@1 | 3685 | for (Type s : t.getTypeArguments()) { |
duke@1 | 3686 | result *= 127; |
duke@1 | 3687 | result += visit(s); |
duke@1 | 3688 | } |
duke@1 | 3689 | return result; |
duke@1 | 3690 | } |
duke@1 | 3691 | |
duke@1 | 3692 | @Override |
vromero@1452 | 3693 | public Integer visitMethodType(MethodType t, Void ignored) { |
vromero@1452 | 3694 | int h = METHOD.ordinal(); |
vromero@1452 | 3695 | for (List<Type> thisargs = t.argtypes; |
vromero@1452 | 3696 | thisargs.tail != null; |
vromero@1452 | 3697 | thisargs = thisargs.tail) |
vromero@1452 | 3698 | h = (h << 5) + visit(thisargs.head); |
vromero@1452 | 3699 | return (h << 5) + visit(t.restype); |
vromero@1452 | 3700 | } |
vromero@1452 | 3701 | |
vromero@1452 | 3702 | @Override |
duke@1 | 3703 | public Integer visitWildcardType(WildcardType t, Void ignored) { |
duke@1 | 3704 | int result = t.kind.hashCode(); |
duke@1 | 3705 | if (t.type != null) { |
duke@1 | 3706 | result *= 127; |
duke@1 | 3707 | result += visit(t.type); |
duke@1 | 3708 | } |
duke@1 | 3709 | return result; |
duke@1 | 3710 | } |
duke@1 | 3711 | |
duke@1 | 3712 | @Override |
duke@1 | 3713 | public Integer visitArrayType(ArrayType t, Void ignored) { |
duke@1 | 3714 | return visit(t.elemtype) + 12; |
duke@1 | 3715 | } |
duke@1 | 3716 | |
duke@1 | 3717 | @Override |
duke@1 | 3718 | public Integer visitTypeVar(TypeVar t, Void ignored) { |
duke@1 | 3719 | return System.identityHashCode(t.tsym); |
duke@1 | 3720 | } |
duke@1 | 3721 | |
duke@1 | 3722 | @Override |
duke@1 | 3723 | public Integer visitUndetVar(UndetVar t, Void ignored) { |
duke@1 | 3724 | return System.identityHashCode(t); |
duke@1 | 3725 | } |
duke@1 | 3726 | |
duke@1 | 3727 | @Override |
duke@1 | 3728 | public Integer visitErrorType(ErrorType t, Void ignored) { |
duke@1 | 3729 | return 0; |
duke@1 | 3730 | } |
duke@1 | 3731 | }; |
duke@1 | 3732 | // </editor-fold> |
duke@1 | 3733 | |
duke@1 | 3734 | // <editor-fold defaultstate="collapsed" desc="Return-Type-Substitutable"> |
duke@1 | 3735 | /** |
duke@1 | 3736 | * Does t have a result that is a subtype of the result type of s, |
duke@1 | 3737 | * suitable for covariant returns? It is assumed that both types |
duke@1 | 3738 | * are (possibly polymorphic) method types. Monomorphic method |
duke@1 | 3739 | * types are handled in the obvious way. Polymorphic method types |
duke@1 | 3740 | * require renaming all type variables of one to corresponding |
duke@1 | 3741 | * type variables in the other, where correspondence is by |
duke@1 | 3742 | * position in the type parameter list. */ |
duke@1 | 3743 | public boolean resultSubtype(Type t, Type s, Warner warner) { |
duke@1 | 3744 | List<Type> tvars = t.getTypeArguments(); |
duke@1 | 3745 | List<Type> svars = s.getTypeArguments(); |
duke@1 | 3746 | Type tres = t.getReturnType(); |
duke@1 | 3747 | Type sres = subst(s.getReturnType(), svars, tvars); |
duke@1 | 3748 | return covariantReturnType(tres, sres, warner); |
duke@1 | 3749 | } |
duke@1 | 3750 | |
duke@1 | 3751 | /** |
duke@1 | 3752 | * Return-Type-Substitutable. |
jjh@972 | 3753 | * @jls section 8.4.5 |
duke@1 | 3754 | */ |
duke@1 | 3755 | public boolean returnTypeSubstitutable(Type r1, Type r2) { |
duke@1 | 3756 | if (hasSameArgs(r1, r2)) |
mcimadamore@1415 | 3757 | return resultSubtype(r1, r2, noWarnings); |
duke@1 | 3758 | else |
duke@1 | 3759 | return covariantReturnType(r1.getReturnType(), |
tbell@202 | 3760 | erasure(r2.getReturnType()), |
mcimadamore@1415 | 3761 | noWarnings); |
tbell@202 | 3762 | } |
tbell@202 | 3763 | |
tbell@202 | 3764 | public boolean returnTypeSubstitutable(Type r1, |
tbell@202 | 3765 | Type r2, Type r2res, |
tbell@202 | 3766 | Warner warner) { |
tbell@202 | 3767 | if (isSameType(r1.getReturnType(), r2res)) |
tbell@202 | 3768 | return true; |
tbell@202 | 3769 | if (r1.getReturnType().isPrimitive() || r2res.isPrimitive()) |
tbell@202 | 3770 | return false; |
tbell@202 | 3771 | |
tbell@202 | 3772 | if (hasSameArgs(r1, r2)) |
tbell@202 | 3773 | return covariantReturnType(r1.getReturnType(), r2res, warner); |
jjg@984 | 3774 | if (!allowCovariantReturns) |
tbell@202 | 3775 | return false; |
tbell@202 | 3776 | if (isSubtypeUnchecked(r1.getReturnType(), r2res, warner)) |
tbell@202 | 3777 | return true; |
tbell@202 | 3778 | if (!isSubtype(r1.getReturnType(), erasure(r2res))) |
tbell@202 | 3779 | return false; |
mcimadamore@795 | 3780 | warner.warn(LintCategory.UNCHECKED); |
tbell@202 | 3781 | return true; |
duke@1 | 3782 | } |
duke@1 | 3783 | |
duke@1 | 3784 | /** |
duke@1 | 3785 | * Is t an appropriate return type in an overrider for a |
duke@1 | 3786 | * method that returns s? |
duke@1 | 3787 | */ |
duke@1 | 3788 | public boolean covariantReturnType(Type t, Type s, Warner warner) { |
tbell@202 | 3789 | return |
tbell@202 | 3790 | isSameType(t, s) || |
jjg@984 | 3791 | allowCovariantReturns && |
duke@1 | 3792 | !t.isPrimitive() && |
tbell@202 | 3793 | !s.isPrimitive() && |
tbell@202 | 3794 | isAssignable(t, s, warner); |
duke@1 | 3795 | } |
duke@1 | 3796 | // </editor-fold> |
duke@1 | 3797 | |
duke@1 | 3798 | // <editor-fold defaultstate="collapsed" desc="Box/unbox support"> |
duke@1 | 3799 | /** |
duke@1 | 3800 | * Return the class that boxes the given primitive. |
duke@1 | 3801 | */ |
duke@1 | 3802 | public ClassSymbol boxedClass(Type t) { |
vromero@1853 | 3803 | return reader.enterClass(syms.boxedName[t.getTag().ordinal()]); |
duke@1 | 3804 | } |
duke@1 | 3805 | |
duke@1 | 3806 | /** |
mcimadamore@753 | 3807 | * Return the boxed type if 't' is primitive, otherwise return 't' itself. |
mcimadamore@753 | 3808 | */ |
mcimadamore@753 | 3809 | public Type boxedTypeOrType(Type t) { |
mcimadamore@753 | 3810 | return t.isPrimitive() ? |
mcimadamore@753 | 3811 | boxedClass(t).type : |
mcimadamore@753 | 3812 | t; |
mcimadamore@753 | 3813 | } |
mcimadamore@753 | 3814 | |
mcimadamore@753 | 3815 | /** |
duke@1 | 3816 | * Return the primitive type corresponding to a boxed type. |
duke@1 | 3817 | */ |
duke@1 | 3818 | public Type unboxedType(Type t) { |
duke@1 | 3819 | if (allowBoxing) { |
duke@1 | 3820 | for (int i=0; i<syms.boxedName.length; i++) { |
duke@1 | 3821 | Name box = syms.boxedName[i]; |
duke@1 | 3822 | if (box != null && |
duke@1 | 3823 | asSuper(t, reader.enterClass(box)) != null) |
duke@1 | 3824 | return syms.typeOfTag[i]; |
duke@1 | 3825 | } |
duke@1 | 3826 | } |
duke@1 | 3827 | return Type.noType; |
duke@1 | 3828 | } |
mcimadamore@1347 | 3829 | |
mcimadamore@1347 | 3830 | /** |
mcimadamore@1347 | 3831 | * Return the unboxed type if 't' is a boxed class, otherwise return 't' itself. |
mcimadamore@1347 | 3832 | */ |
mcimadamore@1347 | 3833 | public Type unboxedTypeOrType(Type t) { |
mcimadamore@1347 | 3834 | Type unboxedType = unboxedType(t); |
vromero@1853 | 3835 | return unboxedType.hasTag(NONE) ? t : unboxedType; |
mcimadamore@1347 | 3836 | } |
duke@1 | 3837 | // </editor-fold> |
duke@1 | 3838 | |
duke@1 | 3839 | // <editor-fold defaultstate="collapsed" desc="Capture conversion"> |
duke@1 | 3840 | /* |
jjh@972 | 3841 | * JLS 5.1.10 Capture Conversion: |
duke@1 | 3842 | * |
duke@1 | 3843 | * Let G name a generic type declaration with n formal type |
duke@1 | 3844 | * parameters A1 ... An with corresponding bounds U1 ... Un. There |
duke@1 | 3845 | * exists a capture conversion from G<T1 ... Tn> to G<S1 ... Sn>, |
duke@1 | 3846 | * where, for 1 <= i <= n: |
duke@1 | 3847 | * |
duke@1 | 3848 | * + If Ti is a wildcard type argument (4.5.1) of the form ? then |
duke@1 | 3849 | * Si is a fresh type variable whose upper bound is |
duke@1 | 3850 | * Ui[A1 := S1, ..., An := Sn] and whose lower bound is the null |
duke@1 | 3851 | * type. |
duke@1 | 3852 | * |
duke@1 | 3853 | * + If Ti is a wildcard type argument of the form ? extends Bi, |
duke@1 | 3854 | * then Si is a fresh type variable whose upper bound is |
duke@1 | 3855 | * glb(Bi, Ui[A1 := S1, ..., An := Sn]) and whose lower bound is |
duke@1 | 3856 | * the null type, where glb(V1,... ,Vm) is V1 & ... & Vm. It is |
duke@1 | 3857 | * a compile-time error if for any two classes (not interfaces) |
duke@1 | 3858 | * Vi and Vj,Vi is not a subclass of Vj or vice versa. |
duke@1 | 3859 | * |
duke@1 | 3860 | * + If Ti is a wildcard type argument of the form ? super Bi, |
duke@1 | 3861 | * then Si is a fresh type variable whose upper bound is |
duke@1 | 3862 | * Ui[A1 := S1, ..., An := Sn] and whose lower bound is Bi. |
duke@1 | 3863 | * |
duke@1 | 3864 | * + Otherwise, Si = Ti. |
duke@1 | 3865 | * |
duke@1 | 3866 | * Capture conversion on any type other than a parameterized type |
duke@1 | 3867 | * (4.5) acts as an identity conversion (5.1.1). Capture |
duke@1 | 3868 | * conversions never require a special action at run time and |
duke@1 | 3869 | * therefore never throw an exception at run time. |
duke@1 | 3870 | * |
duke@1 | 3871 | * Capture conversion is not applied recursively. |
duke@1 | 3872 | */ |
duke@1 | 3873 | /** |
jjh@972 | 3874 | * Capture conversion as specified by the JLS. |
duke@1 | 3875 | */ |
mcimadamore@299 | 3876 | |
mcimadamore@299 | 3877 | public List<Type> capture(List<Type> ts) { |
mcimadamore@299 | 3878 | List<Type> buf = List.nil(); |
mcimadamore@299 | 3879 | for (Type t : ts) { |
mcimadamore@299 | 3880 | buf = buf.prepend(capture(t)); |
mcimadamore@299 | 3881 | } |
mcimadamore@299 | 3882 | return buf.reverse(); |
mcimadamore@299 | 3883 | } |
duke@1 | 3884 | public Type capture(Type t) { |
vromero@1853 | 3885 | if (!t.hasTag(CLASS)) |
duke@1 | 3886 | return t; |
mcimadamore@637 | 3887 | if (t.getEnclosingType() != Type.noType) { |
mcimadamore@637 | 3888 | Type capturedEncl = capture(t.getEnclosingType()); |
mcimadamore@637 | 3889 | if (capturedEncl != t.getEnclosingType()) { |
mcimadamore@637 | 3890 | Type type1 = memberType(capturedEncl, t.tsym); |
mcimadamore@637 | 3891 | t = subst(type1, t.tsym.type.getTypeArguments(), t.getTypeArguments()); |
mcimadamore@637 | 3892 | } |
mcimadamore@637 | 3893 | } |
jjg@1521 | 3894 | t = t.unannotatedType(); |
duke@1 | 3895 | ClassType cls = (ClassType)t; |
duke@1 | 3896 | if (cls.isRaw() || !cls.isParameterized()) |
duke@1 | 3897 | return cls; |
duke@1 | 3898 | |
duke@1 | 3899 | ClassType G = (ClassType)cls.asElement().asType(); |
duke@1 | 3900 | List<Type> A = G.getTypeArguments(); |
duke@1 | 3901 | List<Type> T = cls.getTypeArguments(); |
duke@1 | 3902 | List<Type> S = freshTypeVariables(T); |
duke@1 | 3903 | |
duke@1 | 3904 | List<Type> currentA = A; |
duke@1 | 3905 | List<Type> currentT = T; |
duke@1 | 3906 | List<Type> currentS = S; |
duke@1 | 3907 | boolean captured = false; |
duke@1 | 3908 | while (!currentA.isEmpty() && |
duke@1 | 3909 | !currentT.isEmpty() && |
duke@1 | 3910 | !currentS.isEmpty()) { |
duke@1 | 3911 | if (currentS.head != currentT.head) { |
duke@1 | 3912 | captured = true; |
jjg@1755 | 3913 | WildcardType Ti = (WildcardType)currentT.head.unannotatedType(); |
duke@1 | 3914 | Type Ui = currentA.head.getUpperBound(); |
jjg@1755 | 3915 | CapturedType Si = (CapturedType)currentS.head.unannotatedType(); |
duke@1 | 3916 | if (Ui == null) |
duke@1 | 3917 | Ui = syms.objectType; |
duke@1 | 3918 | switch (Ti.kind) { |
duke@1 | 3919 | case UNBOUND: |
duke@1 | 3920 | Si.bound = subst(Ui, A, S); |
duke@1 | 3921 | Si.lower = syms.botType; |
duke@1 | 3922 | break; |
duke@1 | 3923 | case EXTENDS: |
duke@1 | 3924 | Si.bound = glb(Ti.getExtendsBound(), subst(Ui, A, S)); |
duke@1 | 3925 | Si.lower = syms.botType; |
duke@1 | 3926 | break; |
duke@1 | 3927 | case SUPER: |
duke@1 | 3928 | Si.bound = subst(Ui, A, S); |
duke@1 | 3929 | Si.lower = Ti.getSuperBound(); |
duke@1 | 3930 | break; |
duke@1 | 3931 | } |
duke@1 | 3932 | if (Si.bound == Si.lower) |
duke@1 | 3933 | currentS.head = Si.bound; |
duke@1 | 3934 | } |
duke@1 | 3935 | currentA = currentA.tail; |
duke@1 | 3936 | currentT = currentT.tail; |
duke@1 | 3937 | currentS = currentS.tail; |
duke@1 | 3938 | } |
duke@1 | 3939 | if (!currentA.isEmpty() || !currentT.isEmpty() || !currentS.isEmpty()) |
duke@1 | 3940 | return erasure(t); // some "rare" type involved |
duke@1 | 3941 | |
duke@1 | 3942 | if (captured) |
duke@1 | 3943 | return new ClassType(cls.getEnclosingType(), S, cls.tsym); |
duke@1 | 3944 | else |
duke@1 | 3945 | return t; |
duke@1 | 3946 | } |
duke@1 | 3947 | // where |
mcimadamore@238 | 3948 | public List<Type> freshTypeVariables(List<Type> types) { |
alundblad@2047 | 3949 | ListBuffer<Type> result = new ListBuffer<>(); |
duke@1 | 3950 | for (Type t : types) { |
vromero@1853 | 3951 | if (t.hasTag(WILDCARD)) { |
jjg@1755 | 3952 | t = t.unannotatedType(); |
duke@1 | 3953 | Type bound = ((WildcardType)t).getExtendsBound(); |
duke@1 | 3954 | if (bound == null) |
duke@1 | 3955 | bound = syms.objectType; |
duke@1 | 3956 | result.append(new CapturedType(capturedName, |
duke@1 | 3957 | syms.noSymbol, |
duke@1 | 3958 | bound, |
duke@1 | 3959 | syms.botType, |
duke@1 | 3960 | (WildcardType)t)); |
duke@1 | 3961 | } else { |
duke@1 | 3962 | result.append(t); |
duke@1 | 3963 | } |
duke@1 | 3964 | } |
duke@1 | 3965 | return result.toList(); |
duke@1 | 3966 | } |
duke@1 | 3967 | // </editor-fold> |
duke@1 | 3968 | |
duke@1 | 3969 | // <editor-fold defaultstate="collapsed" desc="Internal utility methods"> |
duke@1 | 3970 | private List<Type> upperBounds(List<Type> ss) { |
duke@1 | 3971 | if (ss.isEmpty()) return ss; |
duke@1 | 3972 | Type head = upperBound(ss.head); |
duke@1 | 3973 | List<Type> tail = upperBounds(ss.tail); |
duke@1 | 3974 | if (head != ss.head || tail != ss.tail) |
duke@1 | 3975 | return tail.prepend(head); |
duke@1 | 3976 | else |
duke@1 | 3977 | return ss; |
duke@1 | 3978 | } |
duke@1 | 3979 | |
duke@1 | 3980 | private boolean sideCast(Type from, Type to, Warner warn) { |
duke@1 | 3981 | // We are casting from type $from$ to type $to$, which are |
duke@1 | 3982 | // non-final unrelated types. This method |
duke@1 | 3983 | // tries to reject a cast by transferring type parameters |
duke@1 | 3984 | // from $to$ to $from$ by common superinterfaces. |
duke@1 | 3985 | boolean reverse = false; |
duke@1 | 3986 | Type target = to; |
duke@1 | 3987 | if ((to.tsym.flags() & INTERFACE) == 0) { |
jjg@816 | 3988 | Assert.check((from.tsym.flags() & INTERFACE) != 0); |
duke@1 | 3989 | reverse = true; |
duke@1 | 3990 | to = from; |
duke@1 | 3991 | from = target; |
duke@1 | 3992 | } |
duke@1 | 3993 | List<Type> commonSupers = superClosure(to, erasure(from)); |
duke@1 | 3994 | boolean giveWarning = commonSupers.isEmpty(); |
duke@1 | 3995 | // The arguments to the supers could be unified here to |
duke@1 | 3996 | // get a more accurate analysis |
duke@1 | 3997 | while (commonSupers.nonEmpty()) { |
emc@2079 | 3998 | Type t1 = asSuper(from, commonSupers.head); |
duke@1 | 3999 | Type t2 = commonSupers.head; // same as asSuper(to, commonSupers.head.tsym); |
duke@1 | 4000 | if (disjointTypes(t1.getTypeArguments(), t2.getTypeArguments())) |
duke@1 | 4001 | return false; |
duke@1 | 4002 | giveWarning = giveWarning || (reverse ? giveWarning(t2, t1) : giveWarning(t1, t2)); |
duke@1 | 4003 | commonSupers = commonSupers.tail; |
duke@1 | 4004 | } |
mcimadamore@187 | 4005 | if (giveWarning && !isReifiable(reverse ? from : to)) |
mcimadamore@795 | 4006 | warn.warn(LintCategory.UNCHECKED); |
jjg@984 | 4007 | if (!allowCovariantReturns) |
duke@1 | 4008 | // reject if there is a common method signature with |
duke@1 | 4009 | // incompatible return types. |
duke@1 | 4010 | chk.checkCompatibleAbstracts(warn.pos(), from, to); |
duke@1 | 4011 | return true; |
duke@1 | 4012 | } |
duke@1 | 4013 | |
duke@1 | 4014 | private boolean sideCastFinal(Type from, Type to, Warner warn) { |
duke@1 | 4015 | // We are casting from type $from$ to type $to$, which are |
duke@1 | 4016 | // unrelated types one of which is final and the other of |
duke@1 | 4017 | // which is an interface. This method |
duke@1 | 4018 | // tries to reject a cast by transferring type parameters |
duke@1 | 4019 | // from the final class to the interface. |
duke@1 | 4020 | boolean reverse = false; |
duke@1 | 4021 | Type target = to; |
duke@1 | 4022 | if ((to.tsym.flags() & INTERFACE) == 0) { |
jjg@816 | 4023 | Assert.check((from.tsym.flags() & INTERFACE) != 0); |
duke@1 | 4024 | reverse = true; |
duke@1 | 4025 | to = from; |
duke@1 | 4026 | from = target; |
duke@1 | 4027 | } |
jjg@816 | 4028 | Assert.check((from.tsym.flags() & FINAL) != 0); |
emc@2079 | 4029 | Type t1 = asSuper(from, to); |
duke@1 | 4030 | if (t1 == null) return false; |
duke@1 | 4031 | Type t2 = to; |
duke@1 | 4032 | if (disjointTypes(t1.getTypeArguments(), t2.getTypeArguments())) |
duke@1 | 4033 | return false; |
jjg@984 | 4034 | if (!allowCovariantReturns) |
duke@1 | 4035 | // reject if there is a common method signature with |
duke@1 | 4036 | // incompatible return types. |
duke@1 | 4037 | chk.checkCompatibleAbstracts(warn.pos(), from, to); |
duke@1 | 4038 | if (!isReifiable(target) && |
duke@1 | 4039 | (reverse ? giveWarning(t2, t1) : giveWarning(t1, t2))) |
mcimadamore@795 | 4040 | warn.warn(LintCategory.UNCHECKED); |
duke@1 | 4041 | return true; |
duke@1 | 4042 | } |
duke@1 | 4043 | |
duke@1 | 4044 | private boolean giveWarning(Type from, Type to) { |
mcimadamore@1653 | 4045 | List<Type> bounds = to.isCompound() ? |
jjg@1755 | 4046 | ((IntersectionClassType)to.unannotatedType()).getComponents() : List.of(to); |
mcimadamore@1653 | 4047 | for (Type b : bounds) { |
mcimadamore@1653 | 4048 | Type subFrom = asSub(from, b.tsym); |
mcimadamore@1653 | 4049 | if (b.isParameterized() && |
mcimadamore@1653 | 4050 | (!(isUnbounded(b) || |
mcimadamore@1653 | 4051 | isSubtype(from, b) || |
mcimadamore@1653 | 4052 | ((subFrom != null) && containsType(b.allparams(), subFrom.allparams()))))) { |
mcimadamore@1653 | 4053 | return true; |
mcimadamore@1653 | 4054 | } |
mcimadamore@1653 | 4055 | } |
mcimadamore@1653 | 4056 | return false; |
duke@1 | 4057 | } |
duke@1 | 4058 | |
duke@1 | 4059 | private List<Type> superClosure(Type t, Type s) { |
duke@1 | 4060 | List<Type> cl = List.nil(); |
duke@1 | 4061 | for (List<Type> l = interfaces(t); l.nonEmpty(); l = l.tail) { |
duke@1 | 4062 | if (isSubtype(s, erasure(l.head))) { |
duke@1 | 4063 | cl = insert(cl, l.head); |
duke@1 | 4064 | } else { |
duke@1 | 4065 | cl = union(cl, superClosure(l.head, s)); |
duke@1 | 4066 | } |
duke@1 | 4067 | } |
duke@1 | 4068 | return cl; |
duke@1 | 4069 | } |
duke@1 | 4070 | |
duke@1 | 4071 | private boolean containsTypeEquivalent(Type t, Type s) { |
duke@1 | 4072 | return |
duke@1 | 4073 | isSameType(t, s) || // shortcut |
duke@1 | 4074 | containsType(t, s) && containsType(s, t); |
duke@1 | 4075 | } |
duke@1 | 4076 | |
mcimadamore@138 | 4077 | // <editor-fold defaultstate="collapsed" desc="adapt"> |
duke@1 | 4078 | /** |
duke@1 | 4079 | * Adapt a type by computing a substitution which maps a source |
duke@1 | 4080 | * type to a target type. |
duke@1 | 4081 | * |
duke@1 | 4082 | * @param source the source type |
duke@1 | 4083 | * @param target the target type |
duke@1 | 4084 | * @param from the type variables of the computed substitution |
duke@1 | 4085 | * @param to the types of the computed substitution. |
duke@1 | 4086 | */ |
duke@1 | 4087 | public void adapt(Type source, |
duke@1 | 4088 | Type target, |
duke@1 | 4089 | ListBuffer<Type> from, |
duke@1 | 4090 | ListBuffer<Type> to) throws AdaptFailure { |
mcimadamore@138 | 4091 | new Adapter(from, to).adapt(source, target); |
mcimadamore@138 | 4092 | } |
mcimadamore@138 | 4093 | |
mcimadamore@138 | 4094 | class Adapter extends SimpleVisitor<Void, Type> { |
mcimadamore@138 | 4095 | |
mcimadamore@138 | 4096 | ListBuffer<Type> from; |
mcimadamore@138 | 4097 | ListBuffer<Type> to; |
mcimadamore@138 | 4098 | Map<Symbol,Type> mapping; |
mcimadamore@138 | 4099 | |
mcimadamore@138 | 4100 | Adapter(ListBuffer<Type> from, ListBuffer<Type> to) { |
mcimadamore@138 | 4101 | this.from = from; |
mcimadamore@138 | 4102 | this.to = to; |
mcimadamore@138 | 4103 | mapping = new HashMap<Symbol,Type>(); |
duke@1 | 4104 | } |
mcimadamore@138 | 4105 | |
mcimadamore@138 | 4106 | public void adapt(Type source, Type target) throws AdaptFailure { |
mcimadamore@138 | 4107 | visit(source, target); |
mcimadamore@138 | 4108 | List<Type> fromList = from.toList(); |
mcimadamore@138 | 4109 | List<Type> toList = to.toList(); |
mcimadamore@138 | 4110 | while (!fromList.isEmpty()) { |
mcimadamore@138 | 4111 | Type val = mapping.get(fromList.head.tsym); |
mcimadamore@138 | 4112 | if (toList.head != val) |
mcimadamore@138 | 4113 | toList.head = val; |
mcimadamore@138 | 4114 | fromList = fromList.tail; |
mcimadamore@138 | 4115 | toList = toList.tail; |
mcimadamore@138 | 4116 | } |
mcimadamore@138 | 4117 | } |
mcimadamore@138 | 4118 | |
mcimadamore@138 | 4119 | @Override |
mcimadamore@138 | 4120 | public Void visitClassType(ClassType source, Type target) throws AdaptFailure { |
vromero@1853 | 4121 | if (target.hasTag(CLASS)) |
mcimadamore@138 | 4122 | adaptRecursive(source.allparams(), target.allparams()); |
mcimadamore@138 | 4123 | return null; |
mcimadamore@138 | 4124 | } |
mcimadamore@138 | 4125 | |
mcimadamore@138 | 4126 | @Override |
mcimadamore@138 | 4127 | public Void visitArrayType(ArrayType source, Type target) throws AdaptFailure { |
vromero@1853 | 4128 | if (target.hasTag(ARRAY)) |
mcimadamore@138 | 4129 | adaptRecursive(elemtype(source), elemtype(target)); |
mcimadamore@138 | 4130 | return null; |
mcimadamore@138 | 4131 | } |
mcimadamore@138 | 4132 | |
mcimadamore@138 | 4133 | @Override |
mcimadamore@138 | 4134 | public Void visitWildcardType(WildcardType source, Type target) throws AdaptFailure { |
mcimadamore@138 | 4135 | if (source.isExtendsBound()) |
mcimadamore@138 | 4136 | adaptRecursive(upperBound(source), upperBound(target)); |
mcimadamore@138 | 4137 | else if (source.isSuperBound()) |
mcimadamore@138 | 4138 | adaptRecursive(lowerBound(source), lowerBound(target)); |
mcimadamore@138 | 4139 | return null; |
mcimadamore@138 | 4140 | } |
mcimadamore@138 | 4141 | |
mcimadamore@138 | 4142 | @Override |
mcimadamore@138 | 4143 | public Void visitTypeVar(TypeVar source, Type target) throws AdaptFailure { |
mcimadamore@138 | 4144 | // Check to see if there is |
mcimadamore@138 | 4145 | // already a mapping for $source$, in which case |
mcimadamore@138 | 4146 | // the old mapping will be merged with the new |
mcimadamore@138 | 4147 | Type val = mapping.get(source.tsym); |
mcimadamore@138 | 4148 | if (val != null) { |
mcimadamore@138 | 4149 | if (val.isSuperBound() && target.isSuperBound()) { |
mcimadamore@138 | 4150 | val = isSubtype(lowerBound(val), lowerBound(target)) |
mcimadamore@138 | 4151 | ? target : val; |
mcimadamore@138 | 4152 | } else if (val.isExtendsBound() && target.isExtendsBound()) { |
mcimadamore@138 | 4153 | val = isSubtype(upperBound(val), upperBound(target)) |
mcimadamore@138 | 4154 | ? val : target; |
mcimadamore@138 | 4155 | } else if (!isSameType(val, target)) { |
mcimadamore@138 | 4156 | throw new AdaptFailure(); |
duke@1 | 4157 | } |
mcimadamore@138 | 4158 | } else { |
mcimadamore@138 | 4159 | val = target; |
mcimadamore@138 | 4160 | from.append(source); |
mcimadamore@138 | 4161 | to.append(target); |
mcimadamore@138 | 4162 | } |
mcimadamore@138 | 4163 | mapping.put(source.tsym, val); |
mcimadamore@138 | 4164 | return null; |
mcimadamore@138 | 4165 | } |
mcimadamore@138 | 4166 | |
mcimadamore@138 | 4167 | @Override |
mcimadamore@138 | 4168 | public Void visitType(Type source, Type target) { |
mcimadamore@138 | 4169 | return null; |
mcimadamore@138 | 4170 | } |
mcimadamore@138 | 4171 | |
mcimadamore@138 | 4172 | private Set<TypePair> cache = new HashSet<TypePair>(); |
mcimadamore@138 | 4173 | |
mcimadamore@138 | 4174 | private void adaptRecursive(Type source, Type target) { |
mcimadamore@138 | 4175 | TypePair pair = new TypePair(source, target); |
mcimadamore@138 | 4176 | if (cache.add(pair)) { |
mcimadamore@138 | 4177 | try { |
mcimadamore@138 | 4178 | visit(source, target); |
mcimadamore@138 | 4179 | } finally { |
mcimadamore@138 | 4180 | cache.remove(pair); |
duke@1 | 4181 | } |
duke@1 | 4182 | } |
duke@1 | 4183 | } |
mcimadamore@138 | 4184 | |
mcimadamore@138 | 4185 | private void adaptRecursive(List<Type> source, List<Type> target) { |
mcimadamore@138 | 4186 | if (source.length() == target.length()) { |
mcimadamore@138 | 4187 | while (source.nonEmpty()) { |
mcimadamore@138 | 4188 | adaptRecursive(source.head, target.head); |
mcimadamore@138 | 4189 | source = source.tail; |
mcimadamore@138 | 4190 | target = target.tail; |
mcimadamore@138 | 4191 | } |
duke@1 | 4192 | } |
duke@1 | 4193 | } |
duke@1 | 4194 | } |
duke@1 | 4195 | |
mcimadamore@138 | 4196 | public static class AdaptFailure extends RuntimeException { |
mcimadamore@138 | 4197 | static final long serialVersionUID = -7490231548272701566L; |
mcimadamore@138 | 4198 | } |
mcimadamore@138 | 4199 | |
duke@1 | 4200 | private void adaptSelf(Type t, |
duke@1 | 4201 | ListBuffer<Type> from, |
duke@1 | 4202 | ListBuffer<Type> to) { |
duke@1 | 4203 | try { |
duke@1 | 4204 | //if (t.tsym.type != t) |
duke@1 | 4205 | adapt(t.tsym.type, t, from, to); |
duke@1 | 4206 | } catch (AdaptFailure ex) { |
duke@1 | 4207 | // Adapt should never fail calculating a mapping from |
duke@1 | 4208 | // t.tsym.type to t as there can be no merge problem. |
duke@1 | 4209 | throw new AssertionError(ex); |
duke@1 | 4210 | } |
duke@1 | 4211 | } |
mcimadamore@138 | 4212 | // </editor-fold> |
duke@1 | 4213 | |
duke@1 | 4214 | /** |
duke@1 | 4215 | * Rewrite all type variables (universal quantifiers) in the given |
duke@1 | 4216 | * type to wildcards (existential quantifiers). This is used to |
duke@1 | 4217 | * determine if a cast is allowed. For example, if high is true |
duke@1 | 4218 | * and {@code T <: Number}, then {@code List<T>} is rewritten to |
duke@1 | 4219 | * {@code List<? extends Number>}. Since {@code List<Integer> <: |
duke@1 | 4220 | * List<? extends Number>} a {@code List<T>} can be cast to {@code |
duke@1 | 4221 | * List<Integer>} with a warning. |
duke@1 | 4222 | * @param t a type |
duke@1 | 4223 | * @param high if true return an upper bound; otherwise a lower |
duke@1 | 4224 | * bound |
duke@1 | 4225 | * @param rewriteTypeVars only rewrite captured wildcards if false; |
duke@1 | 4226 | * otherwise rewrite all type variables |
duke@1 | 4227 | * @return the type rewritten with wildcards (existential |
duke@1 | 4228 | * quantifiers) only |
duke@1 | 4229 | */ |
duke@1 | 4230 | private Type rewriteQuantifiers(Type t, boolean high, boolean rewriteTypeVars) { |
mcimadamore@640 | 4231 | return new Rewriter(high, rewriteTypeVars).visit(t); |
mcimadamore@157 | 4232 | } |
mcimadamore@157 | 4233 | |
mcimadamore@157 | 4234 | class Rewriter extends UnaryVisitor<Type> { |
mcimadamore@157 | 4235 | |
mcimadamore@157 | 4236 | boolean high; |
mcimadamore@157 | 4237 | boolean rewriteTypeVars; |
mcimadamore@157 | 4238 | |
mcimadamore@157 | 4239 | Rewriter(boolean high, boolean rewriteTypeVars) { |
mcimadamore@157 | 4240 | this.high = high; |
mcimadamore@157 | 4241 | this.rewriteTypeVars = rewriteTypeVars; |
mcimadamore@157 | 4242 | } |
mcimadamore@157 | 4243 | |
mcimadamore@640 | 4244 | @Override |
mcimadamore@640 | 4245 | public Type visitClassType(ClassType t, Void s) { |
mcimadamore@157 | 4246 | ListBuffer<Type> rewritten = new ListBuffer<Type>(); |
mcimadamore@157 | 4247 | boolean changed = false; |
mcimadamore@640 | 4248 | for (Type arg : t.allparams()) { |
mcimadamore@157 | 4249 | Type bound = visit(arg); |
mcimadamore@157 | 4250 | if (arg != bound) { |
mcimadamore@157 | 4251 | changed = true; |
mcimadamore@157 | 4252 | } |
mcimadamore@157 | 4253 | rewritten.append(bound); |
duke@1 | 4254 | } |
mcimadamore@157 | 4255 | if (changed) |
mcimadamore@640 | 4256 | return subst(t.tsym.type, |
mcimadamore@640 | 4257 | t.tsym.type.allparams(), |
mcimadamore@640 | 4258 | rewritten.toList()); |
mcimadamore@157 | 4259 | else |
mcimadamore@157 | 4260 | return t; |
duke@1 | 4261 | } |
mcimadamore@157 | 4262 | |
mcimadamore@157 | 4263 | public Type visitType(Type t, Void s) { |
mcimadamore@157 | 4264 | return high ? upperBound(t) : lowerBound(t); |
mcimadamore@157 | 4265 | } |
mcimadamore@157 | 4266 | |
mcimadamore@157 | 4267 | @Override |
mcimadamore@157 | 4268 | public Type visitCapturedType(CapturedType t, Void s) { |
mcimadamore@1177 | 4269 | Type w_bound = t.wildcard.type; |
mcimadamore@1177 | 4270 | Type bound = w_bound.contains(t) ? |
mcimadamore@1177 | 4271 | erasure(w_bound) : |
mcimadamore@1177 | 4272 | visit(w_bound); |
mcimadamore@1177 | 4273 | return rewriteAsWildcardType(visit(bound), t.wildcard.bound, t.wildcard.kind); |
mcimadamore@157 | 4274 | } |
mcimadamore@157 | 4275 | |
mcimadamore@157 | 4276 | @Override |
mcimadamore@157 | 4277 | public Type visitTypeVar(TypeVar t, Void s) { |
mcimadamore@640 | 4278 | if (rewriteTypeVars) { |
mcimadamore@1177 | 4279 | Type bound = t.bound.contains(t) ? |
mcimadamore@779 | 4280 | erasure(t.bound) : |
mcimadamore@1177 | 4281 | visit(t.bound); |
mcimadamore@1177 | 4282 | return rewriteAsWildcardType(bound, t, EXTENDS); |
mcimadamore@1177 | 4283 | } else { |
mcimadamore@1177 | 4284 | return t; |
mcimadamore@640 | 4285 | } |
mcimadamore@157 | 4286 | } |
mcimadamore@157 | 4287 | |
mcimadamore@157 | 4288 | @Override |
mcimadamore@157 | 4289 | public Type visitWildcardType(WildcardType t, Void s) { |
mcimadamore@1177 | 4290 | Type bound2 = visit(t.type); |
mcimadamore@1177 | 4291 | return t.type == bound2 ? t : rewriteAsWildcardType(bound2, t.bound, t.kind); |
mcimadamore@640 | 4292 | } |
mcimadamore@640 | 4293 | |
mcimadamore@1177 | 4294 | private Type rewriteAsWildcardType(Type bound, TypeVar formal, BoundKind bk) { |
mcimadamore@1177 | 4295 | switch (bk) { |
mcimadamore@1177 | 4296 | case EXTENDS: return high ? |
mcimadamore@1177 | 4297 | makeExtendsWildcard(B(bound), formal) : |
mcimadamore@1177 | 4298 | makeExtendsWildcard(syms.objectType, formal); |
mcimadamore@1177 | 4299 | case SUPER: return high ? |
mcimadamore@1177 | 4300 | makeSuperWildcard(syms.botType, formal) : |
mcimadamore@1177 | 4301 | makeSuperWildcard(B(bound), formal); |
mcimadamore@1177 | 4302 | case UNBOUND: return makeExtendsWildcard(syms.objectType, formal); |
mcimadamore@1177 | 4303 | default: |
mcimadamore@1177 | 4304 | Assert.error("Invalid bound kind " + bk); |
mcimadamore@1177 | 4305 | return null; |
mcimadamore@1177 | 4306 | } |
mcimadamore@640 | 4307 | } |
mcimadamore@640 | 4308 | |
mcimadamore@640 | 4309 | Type B(Type t) { |
vromero@1853 | 4310 | while (t.hasTag(WILDCARD)) { |
jjg@1755 | 4311 | WildcardType w = (WildcardType)t.unannotatedType(); |
mcimadamore@640 | 4312 | t = high ? |
mcimadamore@640 | 4313 | w.getExtendsBound() : |
mcimadamore@640 | 4314 | w.getSuperBound(); |
mcimadamore@640 | 4315 | if (t == null) { |
mcimadamore@640 | 4316 | t = high ? syms.objectType : syms.botType; |
mcimadamore@640 | 4317 | } |
mcimadamore@640 | 4318 | } |
mcimadamore@640 | 4319 | return t; |
mcimadamore@157 | 4320 | } |
duke@1 | 4321 | } |
duke@1 | 4322 | |
mcimadamore@640 | 4323 | |
duke@1 | 4324 | /** |
duke@1 | 4325 | * Create a wildcard with the given upper (extends) bound; create |
duke@1 | 4326 | * an unbounded wildcard if bound is Object. |
duke@1 | 4327 | * |
duke@1 | 4328 | * @param bound the upper bound |
duke@1 | 4329 | * @param formal the formal type parameter that will be |
duke@1 | 4330 | * substituted by the wildcard |
duke@1 | 4331 | */ |
duke@1 | 4332 | private WildcardType makeExtendsWildcard(Type bound, TypeVar formal) { |
duke@1 | 4333 | if (bound == syms.objectType) { |
duke@1 | 4334 | return new WildcardType(syms.objectType, |
duke@1 | 4335 | BoundKind.UNBOUND, |
duke@1 | 4336 | syms.boundClass, |
duke@1 | 4337 | formal); |
duke@1 | 4338 | } else { |
duke@1 | 4339 | return new WildcardType(bound, |
duke@1 | 4340 | BoundKind.EXTENDS, |
duke@1 | 4341 | syms.boundClass, |
duke@1 | 4342 | formal); |
duke@1 | 4343 | } |
duke@1 | 4344 | } |
duke@1 | 4345 | |
duke@1 | 4346 | /** |
duke@1 | 4347 | * Create a wildcard with the given lower (super) bound; create an |
duke@1 | 4348 | * unbounded wildcard if bound is bottom (type of {@code null}). |
duke@1 | 4349 | * |
duke@1 | 4350 | * @param bound the lower bound |
duke@1 | 4351 | * @param formal the formal type parameter that will be |
duke@1 | 4352 | * substituted by the wildcard |
duke@1 | 4353 | */ |
duke@1 | 4354 | private WildcardType makeSuperWildcard(Type bound, TypeVar formal) { |
vromero@1853 | 4355 | if (bound.hasTag(BOT)) { |
duke@1 | 4356 | return new WildcardType(syms.objectType, |
duke@1 | 4357 | BoundKind.UNBOUND, |
duke@1 | 4358 | syms.boundClass, |
duke@1 | 4359 | formal); |
duke@1 | 4360 | } else { |
duke@1 | 4361 | return new WildcardType(bound, |
duke@1 | 4362 | BoundKind.SUPER, |
duke@1 | 4363 | syms.boundClass, |
duke@1 | 4364 | formal); |
duke@1 | 4365 | } |
duke@1 | 4366 | } |
duke@1 | 4367 | |
duke@1 | 4368 | /** |
duke@1 | 4369 | * A wrapper for a type that allows use in sets. |
duke@1 | 4370 | */ |
vromero@1452 | 4371 | public static class UniqueType { |
vromero@1452 | 4372 | public final Type type; |
vromero@1452 | 4373 | final Types types; |
vromero@1452 | 4374 | |
vromero@1452 | 4375 | public UniqueType(Type type, Types types) { |
vromero@1452 | 4376 | this.type = type; |
vromero@1452 | 4377 | this.types = types; |
duke@1 | 4378 | } |
vromero@1452 | 4379 | |
duke@1 | 4380 | public int hashCode() { |
vromero@1452 | 4381 | return types.hashCode(type); |
duke@1 | 4382 | } |
vromero@1452 | 4383 | |
duke@1 | 4384 | public boolean equals(Object obj) { |
vromero@1452 | 4385 | return (obj instanceof UniqueType) && |
jjg@1755 | 4386 | types.isSameAnnotatedType(type, ((UniqueType)obj).type); |
duke@1 | 4387 | } |
vromero@1452 | 4388 | |
duke@1 | 4389 | public String toString() { |
vromero@1452 | 4390 | return type.toString(); |
duke@1 | 4391 | } |
vromero@1452 | 4392 | |
duke@1 | 4393 | } |
duke@1 | 4394 | // </editor-fold> |
duke@1 | 4395 | |
duke@1 | 4396 | // <editor-fold defaultstate="collapsed" desc="Visitors"> |
duke@1 | 4397 | /** |
duke@1 | 4398 | * A default visitor for types. All visitor methods except |
duke@1 | 4399 | * visitType are implemented by delegating to visitType. Concrete |
duke@1 | 4400 | * subclasses must provide an implementation of visitType and can |
duke@1 | 4401 | * override other methods as needed. |
duke@1 | 4402 | * |
duke@1 | 4403 | * @param <R> the return type of the operation implemented by this |
duke@1 | 4404 | * visitor; use Void if no return type is needed. |
duke@1 | 4405 | * @param <S> the type of the second argument (the first being the |
duke@1 | 4406 | * type itself) of the operation implemented by this visitor; use |
duke@1 | 4407 | * Void if a second argument is not needed. |
duke@1 | 4408 | */ |
duke@1 | 4409 | public static abstract class DefaultTypeVisitor<R,S> implements Type.Visitor<R,S> { |
duke@1 | 4410 | final public R visit(Type t, S s) { return t.accept(this, s); } |
duke@1 | 4411 | public R visitClassType(ClassType t, S s) { return visitType(t, s); } |
duke@1 | 4412 | public R visitWildcardType(WildcardType t, S s) { return visitType(t, s); } |
duke@1 | 4413 | public R visitArrayType(ArrayType t, S s) { return visitType(t, s); } |
duke@1 | 4414 | public R visitMethodType(MethodType t, S s) { return visitType(t, s); } |
duke@1 | 4415 | public R visitPackageType(PackageType t, S s) { return visitType(t, s); } |
duke@1 | 4416 | public R visitTypeVar(TypeVar t, S s) { return visitType(t, s); } |
duke@1 | 4417 | public R visitCapturedType(CapturedType t, S s) { return visitType(t, s); } |
duke@1 | 4418 | public R visitForAll(ForAll t, S s) { return visitType(t, s); } |
duke@1 | 4419 | public R visitUndetVar(UndetVar t, S s) { return visitType(t, s); } |
duke@1 | 4420 | public R visitErrorType(ErrorType t, S s) { return visitType(t, s); } |
jjg@1521 | 4421 | // Pretend annotations don't exist |
jjg@2134 | 4422 | public R visitAnnotatedType(AnnotatedType t, S s) { return visit(t.unannotatedType(), s); } |
duke@1 | 4423 | } |
duke@1 | 4424 | |
duke@1 | 4425 | /** |
mcimadamore@121 | 4426 | * A default visitor for symbols. All visitor methods except |
mcimadamore@121 | 4427 | * visitSymbol are implemented by delegating to visitSymbol. Concrete |
mcimadamore@121 | 4428 | * subclasses must provide an implementation of visitSymbol and can |
mcimadamore@121 | 4429 | * override other methods as needed. |
mcimadamore@121 | 4430 | * |
mcimadamore@121 | 4431 | * @param <R> the return type of the operation implemented by this |
mcimadamore@121 | 4432 | * visitor; use Void if no return type is needed. |
mcimadamore@121 | 4433 | * @param <S> the type of the second argument (the first being the |
mcimadamore@121 | 4434 | * symbol itself) of the operation implemented by this visitor; use |
mcimadamore@121 | 4435 | * Void if a second argument is not needed. |
mcimadamore@121 | 4436 | */ |
mcimadamore@121 | 4437 | public static abstract class DefaultSymbolVisitor<R,S> implements Symbol.Visitor<R,S> { |
mcimadamore@121 | 4438 | final public R visit(Symbol s, S arg) { return s.accept(this, arg); } |
mcimadamore@121 | 4439 | public R visitClassSymbol(ClassSymbol s, S arg) { return visitSymbol(s, arg); } |
mcimadamore@121 | 4440 | public R visitMethodSymbol(MethodSymbol s, S arg) { return visitSymbol(s, arg); } |
mcimadamore@121 | 4441 | public R visitOperatorSymbol(OperatorSymbol s, S arg) { return visitSymbol(s, arg); } |
mcimadamore@121 | 4442 | public R visitPackageSymbol(PackageSymbol s, S arg) { return visitSymbol(s, arg); } |
mcimadamore@121 | 4443 | public R visitTypeSymbol(TypeSymbol s, S arg) { return visitSymbol(s, arg); } |
mcimadamore@121 | 4444 | public R visitVarSymbol(VarSymbol s, S arg) { return visitSymbol(s, arg); } |
mcimadamore@121 | 4445 | } |
mcimadamore@121 | 4446 | |
mcimadamore@121 | 4447 | /** |
duke@1 | 4448 | * A <em>simple</em> visitor for types. This visitor is simple as |
duke@1 | 4449 | * captured wildcards, for-all types (generic methods), and |
duke@1 | 4450 | * undetermined type variables (part of inference) are hidden. |
duke@1 | 4451 | * Captured wildcards are hidden by treating them as type |
duke@1 | 4452 | * variables and the rest are hidden by visiting their qtypes. |
duke@1 | 4453 | * |
duke@1 | 4454 | * @param <R> the return type of the operation implemented by this |
duke@1 | 4455 | * visitor; use Void if no return type is needed. |
duke@1 | 4456 | * @param <S> the type of the second argument (the first being the |
duke@1 | 4457 | * type itself) of the operation implemented by this visitor; use |
duke@1 | 4458 | * Void if a second argument is not needed. |
duke@1 | 4459 | */ |
duke@1 | 4460 | public static abstract class SimpleVisitor<R,S> extends DefaultTypeVisitor<R,S> { |
duke@1 | 4461 | @Override |
duke@1 | 4462 | public R visitCapturedType(CapturedType t, S s) { |
duke@1 | 4463 | return visitTypeVar(t, s); |
duke@1 | 4464 | } |
duke@1 | 4465 | @Override |
duke@1 | 4466 | public R visitForAll(ForAll t, S s) { |
duke@1 | 4467 | return visit(t.qtype, s); |
duke@1 | 4468 | } |
duke@1 | 4469 | @Override |
duke@1 | 4470 | public R visitUndetVar(UndetVar t, S s) { |
duke@1 | 4471 | return visit(t.qtype, s); |
duke@1 | 4472 | } |
duke@1 | 4473 | } |
duke@1 | 4474 | |
duke@1 | 4475 | /** |
duke@1 | 4476 | * A plain relation on types. That is a 2-ary function on the |
duke@1 | 4477 | * form Type × Type → Boolean. |
duke@1 | 4478 | * <!-- In plain text: Type x Type -> Boolean --> |
duke@1 | 4479 | */ |
duke@1 | 4480 | public static abstract class TypeRelation extends SimpleVisitor<Boolean,Type> {} |
duke@1 | 4481 | |
duke@1 | 4482 | /** |
duke@1 | 4483 | * A convenience visitor for implementing operations that only |
duke@1 | 4484 | * require one argument (the type itself), that is, unary |
duke@1 | 4485 | * operations. |
duke@1 | 4486 | * |
duke@1 | 4487 | * @param <R> the return type of the operation implemented by this |
duke@1 | 4488 | * visitor; use Void if no return type is needed. |
duke@1 | 4489 | */ |
duke@1 | 4490 | public static abstract class UnaryVisitor<R> extends SimpleVisitor<R,Void> { |
duke@1 | 4491 | final public R visit(Type t) { return t.accept(this, null); } |
duke@1 | 4492 | } |
duke@1 | 4493 | |
duke@1 | 4494 | /** |
duke@1 | 4495 | * A visitor for implementing a mapping from types to types. The |
duke@1 | 4496 | * default behavior of this class is to implement the identity |
duke@1 | 4497 | * mapping (mapping a type to itself). This can be overridden in |
duke@1 | 4498 | * subclasses. |
duke@1 | 4499 | * |
duke@1 | 4500 | * @param <S> the type of the second argument (the first being the |
duke@1 | 4501 | * type itself) of this mapping; use Void if a second argument is |
duke@1 | 4502 | * not needed. |
duke@1 | 4503 | */ |
duke@1 | 4504 | public static class MapVisitor<S> extends DefaultTypeVisitor<Type,S> { |
duke@1 | 4505 | final public Type visit(Type t) { return t.accept(this, null); } |
duke@1 | 4506 | public Type visitType(Type t, S s) { return t; } |
duke@1 | 4507 | } |
duke@1 | 4508 | // </editor-fold> |
jjg@657 | 4509 | |
jjg@657 | 4510 | |
jjg@657 | 4511 | // <editor-fold defaultstate="collapsed" desc="Annotation support"> |
jjg@657 | 4512 | |
jjg@657 | 4513 | public RetentionPolicy getRetention(Attribute.Compound a) { |
jfranck@1313 | 4514 | return getRetention(a.type.tsym); |
jfranck@1313 | 4515 | } |
jfranck@1313 | 4516 | |
jfranck@1313 | 4517 | public RetentionPolicy getRetention(Symbol sym) { |
jjg@657 | 4518 | RetentionPolicy vis = RetentionPolicy.CLASS; // the default |
jfranck@1313 | 4519 | Attribute.Compound c = sym.attribute(syms.retentionType.tsym); |
jjg@657 | 4520 | if (c != null) { |
jjg@657 | 4521 | Attribute value = c.member(names.value); |
jjg@657 | 4522 | if (value != null && value instanceof Attribute.Enum) { |
jjg@657 | 4523 | Name levelName = ((Attribute.Enum)value).value.name; |
jjg@657 | 4524 | if (levelName == names.SOURCE) vis = RetentionPolicy.SOURCE; |
jjg@657 | 4525 | else if (levelName == names.CLASS) vis = RetentionPolicy.CLASS; |
jjg@657 | 4526 | else if (levelName == names.RUNTIME) vis = RetentionPolicy.RUNTIME; |
jjg@657 | 4527 | else ;// /* fail soft */ throw new AssertionError(levelName); |
jjg@657 | 4528 | } |
jjg@657 | 4529 | } |
jjg@657 | 4530 | return vis; |
jjg@657 | 4531 | } |
jjg@657 | 4532 | // </editor-fold> |
rfield@1587 | 4533 | |
rfield@1587 | 4534 | // <editor-fold defaultstate="collapsed" desc="Signature Generation"> |
rfield@1587 | 4535 | |
rfield@1587 | 4536 | public static abstract class SignatureGenerator { |
rfield@1587 | 4537 | |
rfield@1587 | 4538 | private final Types types; |
rfield@1587 | 4539 | |
rfield@1587 | 4540 | protected abstract void append(char ch); |
rfield@1587 | 4541 | protected abstract void append(byte[] ba); |
rfield@1587 | 4542 | protected abstract void append(Name name); |
rfield@1587 | 4543 | protected void classReference(ClassSymbol c) { /* by default: no-op */ } |
rfield@1587 | 4544 | |
rfield@1587 | 4545 | protected SignatureGenerator(Types types) { |
rfield@1587 | 4546 | this.types = types; |
rfield@1587 | 4547 | } |
rfield@1587 | 4548 | |
rfield@1587 | 4549 | /** |
rfield@1587 | 4550 | * Assemble signature of given type in string buffer. |
rfield@1587 | 4551 | */ |
rfield@1587 | 4552 | public void assembleSig(Type type) { |
rfield@1587 | 4553 | type = type.unannotatedType(); |
rfield@1587 | 4554 | switch (type.getTag()) { |
rfield@1587 | 4555 | case BYTE: |
rfield@1587 | 4556 | append('B'); |
rfield@1587 | 4557 | break; |
rfield@1587 | 4558 | case SHORT: |
rfield@1587 | 4559 | append('S'); |
rfield@1587 | 4560 | break; |
rfield@1587 | 4561 | case CHAR: |
rfield@1587 | 4562 | append('C'); |
rfield@1587 | 4563 | break; |
rfield@1587 | 4564 | case INT: |
rfield@1587 | 4565 | append('I'); |
rfield@1587 | 4566 | break; |
rfield@1587 | 4567 | case LONG: |
rfield@1587 | 4568 | append('J'); |
rfield@1587 | 4569 | break; |
rfield@1587 | 4570 | case FLOAT: |
rfield@1587 | 4571 | append('F'); |
rfield@1587 | 4572 | break; |
rfield@1587 | 4573 | case DOUBLE: |
rfield@1587 | 4574 | append('D'); |
rfield@1587 | 4575 | break; |
rfield@1587 | 4576 | case BOOLEAN: |
rfield@1587 | 4577 | append('Z'); |
rfield@1587 | 4578 | break; |
rfield@1587 | 4579 | case VOID: |
rfield@1587 | 4580 | append('V'); |
rfield@1587 | 4581 | break; |
rfield@1587 | 4582 | case CLASS: |
rfield@1587 | 4583 | append('L'); |
rfield@1587 | 4584 | assembleClassSig(type); |
rfield@1587 | 4585 | append(';'); |
rfield@1587 | 4586 | break; |
rfield@1587 | 4587 | case ARRAY: |
rfield@1587 | 4588 | ArrayType at = (ArrayType) type; |
rfield@1587 | 4589 | append('['); |
rfield@1587 | 4590 | assembleSig(at.elemtype); |
rfield@1587 | 4591 | break; |
rfield@1587 | 4592 | case METHOD: |
rfield@1587 | 4593 | MethodType mt = (MethodType) type; |
rfield@1587 | 4594 | append('('); |
rfield@1587 | 4595 | assembleSig(mt.argtypes); |
rfield@1587 | 4596 | append(')'); |
rfield@1587 | 4597 | assembleSig(mt.restype); |
rfield@1587 | 4598 | if (hasTypeVar(mt.thrown)) { |
rfield@1587 | 4599 | for (List<Type> l = mt.thrown; l.nonEmpty(); l = l.tail) { |
rfield@1587 | 4600 | append('^'); |
rfield@1587 | 4601 | assembleSig(l.head); |
rfield@1587 | 4602 | } |
rfield@1587 | 4603 | } |
rfield@1587 | 4604 | break; |
rfield@1587 | 4605 | case WILDCARD: { |
rfield@1587 | 4606 | Type.WildcardType ta = (Type.WildcardType) type; |
rfield@1587 | 4607 | switch (ta.kind) { |
rfield@1587 | 4608 | case SUPER: |
rfield@1587 | 4609 | append('-'); |
rfield@1587 | 4610 | assembleSig(ta.type); |
rfield@1587 | 4611 | break; |
rfield@1587 | 4612 | case EXTENDS: |
rfield@1587 | 4613 | append('+'); |
rfield@1587 | 4614 | assembleSig(ta.type); |
rfield@1587 | 4615 | break; |
rfield@1587 | 4616 | case UNBOUND: |
rfield@1587 | 4617 | append('*'); |
rfield@1587 | 4618 | break; |
rfield@1587 | 4619 | default: |
rfield@1587 | 4620 | throw new AssertionError(ta.kind); |
rfield@1587 | 4621 | } |
rfield@1587 | 4622 | break; |
rfield@1587 | 4623 | } |
rfield@1587 | 4624 | case TYPEVAR: |
rfield@1587 | 4625 | append('T'); |
rfield@1587 | 4626 | append(type.tsym.name); |
rfield@1587 | 4627 | append(';'); |
rfield@1587 | 4628 | break; |
rfield@1587 | 4629 | case FORALL: |
rfield@1587 | 4630 | Type.ForAll ft = (Type.ForAll) type; |
rfield@1587 | 4631 | assembleParamsSig(ft.tvars); |
rfield@1587 | 4632 | assembleSig(ft.qtype); |
rfield@1587 | 4633 | break; |
rfield@1587 | 4634 | default: |
rfield@1587 | 4635 | throw new AssertionError("typeSig " + type.getTag()); |
rfield@1587 | 4636 | } |
rfield@1587 | 4637 | } |
rfield@1587 | 4638 | |
rfield@1587 | 4639 | public boolean hasTypeVar(List<Type> l) { |
rfield@1587 | 4640 | while (l.nonEmpty()) { |
rfield@1587 | 4641 | if (l.head.hasTag(TypeTag.TYPEVAR)) { |
rfield@1587 | 4642 | return true; |
rfield@1587 | 4643 | } |
rfield@1587 | 4644 | l = l.tail; |
rfield@1587 | 4645 | } |
rfield@1587 | 4646 | return false; |
rfield@1587 | 4647 | } |
rfield@1587 | 4648 | |
rfield@1587 | 4649 | public void assembleClassSig(Type type) { |
rfield@1587 | 4650 | type = type.unannotatedType(); |
rfield@1587 | 4651 | ClassType ct = (ClassType) type; |
rfield@1587 | 4652 | ClassSymbol c = (ClassSymbol) ct.tsym; |
rfield@1587 | 4653 | classReference(c); |
rfield@1587 | 4654 | Type outer = ct.getEnclosingType(); |
rfield@1587 | 4655 | if (outer.allparams().nonEmpty()) { |
rfield@1587 | 4656 | boolean rawOuter = |
rfield@1587 | 4657 | c.owner.kind == Kinds.MTH || // either a local class |
rfield@1587 | 4658 | c.name == types.names.empty; // or anonymous |
rfield@1587 | 4659 | assembleClassSig(rawOuter |
rfield@1587 | 4660 | ? types.erasure(outer) |
rfield@1587 | 4661 | : outer); |
rfield@1587 | 4662 | append('.'); |
rfield@1587 | 4663 | Assert.check(c.flatname.startsWith(c.owner.enclClass().flatname)); |
rfield@1587 | 4664 | append(rawOuter |
rfield@1587 | 4665 | ? c.flatname.subName(c.owner.enclClass().flatname.getByteLength() + 1, c.flatname.getByteLength()) |
rfield@1587 | 4666 | : c.name); |
rfield@1587 | 4667 | } else { |
rfield@1587 | 4668 | append(externalize(c.flatname)); |
rfield@1587 | 4669 | } |
rfield@1587 | 4670 | if (ct.getTypeArguments().nonEmpty()) { |
rfield@1587 | 4671 | append('<'); |
rfield@1587 | 4672 | assembleSig(ct.getTypeArguments()); |
rfield@1587 | 4673 | append('>'); |
rfield@1587 | 4674 | } |
rfield@1587 | 4675 | } |
rfield@1587 | 4676 | |
rfield@1587 | 4677 | public void assembleParamsSig(List<Type> typarams) { |
rfield@1587 | 4678 | append('<'); |
rfield@1587 | 4679 | for (List<Type> ts = typarams; ts.nonEmpty(); ts = ts.tail) { |
rfield@1587 | 4680 | Type.TypeVar tvar = (Type.TypeVar) ts.head; |
rfield@1587 | 4681 | append(tvar.tsym.name); |
rfield@1587 | 4682 | List<Type> bounds = types.getBounds(tvar); |
rfield@1587 | 4683 | if ((bounds.head.tsym.flags() & INTERFACE) != 0) { |
rfield@1587 | 4684 | append(':'); |
rfield@1587 | 4685 | } |
rfield@1587 | 4686 | for (List<Type> l = bounds; l.nonEmpty(); l = l.tail) { |
rfield@1587 | 4687 | append(':'); |
rfield@1587 | 4688 | assembleSig(l.head); |
rfield@1587 | 4689 | } |
rfield@1587 | 4690 | } |
rfield@1587 | 4691 | append('>'); |
rfield@1587 | 4692 | } |
rfield@1587 | 4693 | |
rfield@1587 | 4694 | private void assembleSig(List<Type> types) { |
rfield@1587 | 4695 | for (List<Type> ts = types; ts.nonEmpty(); ts = ts.tail) { |
rfield@1587 | 4696 | assembleSig(ts.head); |
rfield@1587 | 4697 | } |
rfield@1587 | 4698 | } |
rfield@1587 | 4699 | } |
rfield@1587 | 4700 | // </editor-fold> |
duke@1 | 4701 | } |