src/share/classes/com/sun/tools/javac/comp/Infer.java

Tue, 25 Sep 2012 11:56:46 +0100

author
mcimadamore
date
Tue, 25 Sep 2012 11:56:46 +0100
changeset 1338
ad2ca2a4ab5e
parent 1337
2eca84194807
child 1347
1408af4cd8b0
permissions
-rw-r--r--

7177306: Regression: unchecked method call does not erase return type
Summary: Spurious extra call to Attr.checkMethod when method call is unchecked
Reviewed-by: jjg, dlsmith

duke@1 1 /*
mcimadamore@1178 2 * Copyright (c) 1999, 2012, 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.comp;
duke@1 27
mcimadamore@1337 28 import com.sun.tools.javac.code.*;
mcimadamore@1337 29 import com.sun.tools.javac.code.Symbol.*;
mcimadamore@1337 30 import com.sun.tools.javac.code.Type.*;
mcimadamore@1338 31 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
mcimadamore@1337 32 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
mcimadamore@1337 33 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
mcimadamore@674 34 import com.sun.tools.javac.tree.JCTree;
mcimadamore@674 35 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
mcimadamore@820 36 import com.sun.tools.javac.tree.TreeInfo;
duke@1 37 import com.sun.tools.javac.util.*;
duke@1 38 import com.sun.tools.javac.util.List;
mcimadamore@1114 39 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
duke@1 40
mcimadamore@1337 41 import java.util.HashMap;
mcimadamore@1337 42 import java.util.Map;
mcimadamore@1338 43 import java.util.Set;
mcimadamore@1337 44
duke@1 45 import static com.sun.tools.javac.code.TypeTags.*;
duke@1 46
duke@1 47 /** Helper class for type parameter inference, used by the attribution phase.
duke@1 48 *
jjg@581 49 * <p><b>This is NOT part of any supported API.
jjg@581 50 * If you write code that depends on this, you do so at your own risk.
duke@1 51 * This code and its internal interfaces are subject to change or
duke@1 52 * deletion without notice.</b>
duke@1 53 */
duke@1 54 public class Infer {
duke@1 55 protected static final Context.Key<Infer> inferKey =
duke@1 56 new Context.Key<Infer>();
duke@1 57
duke@1 58 /** A value for prototypes that admit any type, including polymorphic ones. */
duke@1 59 public static final Type anyPoly = new Type(NONE, null);
duke@1 60
duke@1 61 Symtab syms;
duke@1 62 Types types;
mcimadamore@396 63 Check chk;
mcimadamore@299 64 Resolve rs;
mcimadamore@1114 65 Log log;
mcimadamore@89 66 JCDiagnostic.Factory diags;
duke@1 67
duke@1 68 public static Infer instance(Context context) {
duke@1 69 Infer instance = context.get(inferKey);
duke@1 70 if (instance == null)
duke@1 71 instance = new Infer(context);
duke@1 72 return instance;
duke@1 73 }
duke@1 74
duke@1 75 protected Infer(Context context) {
duke@1 76 context.put(inferKey, this);
duke@1 77 syms = Symtab.instance(context);
duke@1 78 types = Types.instance(context);
mcimadamore@299 79 rs = Resolve.instance(context);
mcimadamore@1114 80 log = Log.instance(context);
mcimadamore@396 81 chk = Check.instance(context);
mcimadamore@89 82 diags = JCDiagnostic.Factory.instance(context);
mcimadamore@1298 83 inferenceException = new InferenceException(diags);
duke@1 84 }
duke@1 85
mcimadamore@1337 86 /**
mcimadamore@1337 87 * This exception class is design to store a list of diagnostics corresponding
mcimadamore@1337 88 * to inference errors that can arise during a method applicability check.
mcimadamore@1337 89 */
mcimadamore@1186 90 public static class InferenceException extends InapplicableMethodException {
duke@1 91 private static final long serialVersionUID = 0;
duke@1 92
mcimadamore@1337 93 List<JCDiagnostic> messages = List.nil();
mcimadamore@1337 94
mcimadamore@299 95 InferenceException(JCDiagnostic.Factory diags) {
mcimadamore@689 96 super(diags);
duke@1 97 }
mcimadamore@1337 98
mcimadamore@1337 99 @Override
mcimadamore@1337 100 InapplicableMethodException setMessage(JCDiagnostic diag) {
mcimadamore@1337 101 messages = messages.append(diag);
mcimadamore@1337 102 return this;
mcimadamore@1337 103 }
mcimadamore@1337 104
mcimadamore@1337 105 @Override
mcimadamore@1337 106 public JCDiagnostic getDiagnostic() {
mcimadamore@1337 107 return messages.head;
mcimadamore@1337 108 }
mcimadamore@1337 109
mcimadamore@1337 110 void clear() {
mcimadamore@1337 111 messages = List.nil();
mcimadamore@1337 112 }
mcimadamore@299 113 }
mcimadamore@299 114
mcimadamore@1298 115 private final InferenceException inferenceException;
duke@1 116
duke@1 117 /***************************************************************************
duke@1 118 * Mini/Maximization of UndetVars
duke@1 119 ***************************************************************************/
duke@1 120
duke@1 121 /** Instantiate undetermined type variable to its minimal upper bound.
duke@1 122 * Throw a NoInstanceException if this not possible.
duke@1 123 */
mcimadamore@1337 124 void maximizeInst(UndetVar that, Warner warn) throws InferenceException {
mcimadamore@1338 125 List<Type> hibounds = Type.filter(that.getBounds(InferenceBound.UPPER), boundFilter);
mcimadamore@1338 126 if (that.getBounds(InferenceBound.EQ).isEmpty()) {
mcimadamore@828 127 if (hibounds.isEmpty())
duke@1 128 that.inst = syms.objectType;
mcimadamore@828 129 else if (hibounds.tail.isEmpty())
mcimadamore@828 130 that.inst = hibounds.head;
mcimadamore@210 131 else
mcimadamore@828 132 that.inst = types.glb(hibounds);
mcimadamore@1251 133 } else {
mcimadamore@1338 134 that.inst = that.getBounds(InferenceBound.EQ).head;
duke@1 135 }
mcimadamore@210 136 if (that.inst == null ||
mcimadamore@298 137 that.inst.isErroneous())
mcimadamore@1298 138 throw inferenceException
mcimadamore@210 139 .setMessage("no.unique.maximal.instance.exists",
mcimadamore@828 140 that.qtype, hibounds);
duke@1 141 }
duke@1 142
mcimadamore@1337 143 private Filter<Type> boundFilter = new Filter<Type>() {
mcimadamore@828 144 @Override
mcimadamore@828 145 public boolean accepts(Type t) {
mcimadamore@1337 146 return !t.isErroneous() && t.tag != BOT;
mcimadamore@828 147 }
mcimadamore@828 148 };
mcimadamore@828 149
jjg@110 150 /** Instantiate undetermined type variable to the lub of all its lower bounds.
duke@1 151 * Throw a NoInstanceException if this not possible.
duke@1 152 */
mcimadamore@1298 153 void minimizeInst(UndetVar that, Warner warn) throws InferenceException {
mcimadamore@1338 154 List<Type> lobounds = Type.filter(that.getBounds(InferenceBound.LOWER), boundFilter);
mcimadamore@1338 155 if (that.getBounds(InferenceBound.EQ).isEmpty()) {
mcimadamore@1337 156 if (lobounds.isEmpty()) {
mcimadamore@1337 157 //do nothing - the inference variable is under-constrained
mcimadamore@1337 158 return;
mcimadamore@1337 159 } else if (lobounds.tail.isEmpty())
mcimadamore@828 160 that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head;
duke@1 161 else {
mcimadamore@828 162 that.inst = types.lub(lobounds);
mcimadamore@5 163 }
jjg@110 164 if (that.inst == null || that.inst.tag == ERROR)
mcimadamore@1298 165 throw inferenceException
duke@1 166 .setMessage("no.unique.minimal.instance.exists",
mcimadamore@828 167 that.qtype, lobounds);
mcimadamore@1251 168 } else {
mcimadamore@1338 169 that.inst = that.getBounds(InferenceBound.EQ).head;
duke@1 170 }
duke@1 171 }
duke@1 172
duke@1 173 /***************************************************************************
duke@1 174 * Exported Methods
duke@1 175 ***************************************************************************/
duke@1 176
mcimadamore@1337 177 /**
mcimadamore@1337 178 * Instantiate uninferred inference variables (JLS 15.12.2.8). First
mcimadamore@1337 179 * if the method return type is non-void, we derive constraints from the
mcimadamore@1337 180 * expected type - then we use declared bound well-formedness to derive additional
mcimadamore@1337 181 * constraints. If no instantiation exists, or if several incomparable
mcimadamore@1337 182 * best instantiations exist throw a NoInstanceException.
duke@1 183 */
mcimadamore@1337 184 public void instantiateUninferred(DiagnosticPosition pos,
mcimadamore@1337 185 InferenceContext inferenceContext,
mcimadamore@1337 186 MethodType mtype,
mcimadamore@1337 187 Attr.ResultInfo resultInfo,
mcimadamore@1337 188 Warner warn) throws InferenceException {
mcimadamore@1268 189 Type to = resultInfo.pt;
mcimadamore@1268 190 if (to.tag == NONE) {
mcimadamore@1268 191 to = mtype.getReturnType().tag <= VOID ?
mcimadamore@1268 192 mtype.getReturnType() : syms.objectType;
mcimadamore@1268 193 }
mcimadamore@1337 194 Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types);
mcimadamore@753 195 if (!types.isSubtype(qtype1,
mcimadamore@753 196 qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) {
mcimadamore@1298 197 throw inferenceException
mcimadamore@1337 198 .setMessage("infer.no.conforming.instance.exists",
mcimadamore@1337 199 inferenceContext.restvars(), mtype.getReturnType(), to);
duke@1 200 }
duke@1 201
mcimadamore@1251 202 while (true) {
mcimadamore@1251 203 boolean stuck = true;
mcimadamore@1337 204 for (Type t : inferenceContext.undetvars) {
mcimadamore@1251 205 UndetVar uv = (UndetVar)t;
mcimadamore@1338 206 if (uv.inst == null && (uv.getBounds(InferenceBound.EQ).nonEmpty() ||
mcimadamore@1338 207 !inferenceContext.free(uv.getBounds(InferenceBound.UPPER)))) {
mcimadamore@1251 208 maximizeInst((UndetVar)t, warn);
mcimadamore@1251 209 stuck = false;
mcimadamore@1251 210 }
mcimadamore@1251 211 }
mcimadamore@1337 212 if (inferenceContext.restvars().isEmpty()) {
mcimadamore@1251 213 //all variables have been instantiated - exit
mcimadamore@1251 214 break;
mcimadamore@1251 215 } else if (stuck) {
mcimadamore@1251 216 //some variables could not be instantiated because of cycles in
mcimadamore@1251 217 //upper bounds - provide a (possibly recursive) default instantiation
mcimadamore@1337 218 instantiateAsUninferredVars(inferenceContext);
mcimadamore@1251 219 break;
mcimadamore@1251 220 } else {
mcimadamore@1251 221 //some variables have been instantiated - replace newly instantiated
mcimadamore@1251 222 //variables in remaining upper bounds and continue
mcimadamore@1337 223 for (Type t : inferenceContext.undetvars) {
mcimadamore@1251 224 UndetVar uv = (UndetVar)t;
mcimadamore@1338 225 uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), types);
mcimadamore@1251 226 }
mcimadamore@1251 227 }
mcimadamore@635 228 }
duke@1 229 }
mcimadamore@1251 230
mcimadamore@1251 231 /**
mcimadamore@1251 232 * Infer cyclic inference variables as described in 15.12.2.8.
mcimadamore@1251 233 */
mcimadamore@1337 234 private void instantiateAsUninferredVars(InferenceContext inferenceContext) {
mcimadamore@1251 235 ListBuffer<Type> todo = ListBuffer.lb();
mcimadamore@1251 236 //step 1 - create fresh tvars
mcimadamore@1337 237 for (Type t : inferenceContext.undetvars) {
mcimadamore@635 238 UndetVar uv = (UndetVar)t;
mcimadamore@1251 239 if (uv.inst == null) {
mcimadamore@1251 240 TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
mcimadamore@1338 241 fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.getBounds(InferenceBound.UPPER)), null);
mcimadamore@1251 242 todo.append(uv);
mcimadamore@1251 243 uv.inst = fresh_tvar.type;
mcimadamore@1251 244 }
mcimadamore@635 245 }
mcimadamore@1251 246 //step 2 - replace fresh tvars in their bounds
mcimadamore@1337 247 List<Type> formals = inferenceContext.inferenceVars();
mcimadamore@1251 248 for (Type t : todo) {
mcimadamore@1251 249 UndetVar uv = (UndetVar)t;
mcimadamore@1251 250 TypeVar ct = (TypeVar)uv.inst;
mcimadamore@1337 251 ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types));
mcimadamore@1251 252 if (ct.bound.isErroneous()) {
mcimadamore@1251 253 //report inference error if glb fails
mcimadamore@1251 254 reportBoundError(uv, BoundErrorKind.BAD_UPPER);
mcimadamore@1251 255 }
mcimadamore@1178 256 formals = formals.tail;
mcimadamore@635 257 }
mcimadamore@635 258 }
duke@1 259
mcimadamore@1337 260 /** Instantiate a generic method type by finding instantiations for all its
mcimadamore@1337 261 * inference variables so that it can be applied to a given argument type list.
duke@1 262 */
mcimadamore@1268 263 public Type instantiateMethod(Env<AttrContext> env,
mcimadamore@547 264 List<Type> tvars,
duke@1 265 MethodType mt,
mcimadamore@1268 266 Attr.ResultInfo resultInfo,
mcimadamore@1268 267 Symbol msym,
mcimadamore@1268 268 List<Type> argtypes,
mcimadamore@1268 269 boolean allowBoxing,
mcimadamore@1268 270 boolean useVarargs,
mcimadamore@1268 271 Warner warn) throws InferenceException {
duke@1 272 //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
mcimadamore@1338 273 final InferenceContext inferenceContext = new InferenceContext(tvars, this);
mcimadamore@1337 274 inferenceException.clear();
mcimadamore@689 275
mcimadamore@1337 276 try {
mcimadamore@1337 277 rs.checkRawArgumentsAcceptable(env, inferenceContext, argtypes, mt.getParameterTypes(),
mcimadamore@1337 278 allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext));
duke@1 279
mcimadamore@1337 280 // minimize as yet undetermined type variables
mcimadamore@1337 281 for (Type t : inferenceContext.undetvars) {
mcimadamore@1337 282 minimizeInst((UndetVar)t, warn);
mcimadamore@1337 283 }
duke@1 284
mcimadamore@1337 285 checkWithinBounds(inferenceContext, warn);
duke@1 286
mcimadamore@1337 287 mt = (MethodType)inferenceContext.asInstType(mt, types);
mcimadamore@396 288
mcimadamore@1337 289 List<Type> restvars = inferenceContext.restvars();
duke@1 290
mcimadamore@1337 291 if (!restvars.isEmpty()) {
mcimadamore@1338 292 if (resultInfo != null && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
mcimadamore@1337 293 instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn);
mcimadamore@1337 294 checkWithinBounds(inferenceContext, warn);
mcimadamore@1337 295 mt = (MethodType)inferenceContext.asInstType(mt, types);
mcimadamore@1337 296 if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
mcimadamore@1337 297 log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
mcimadamore@1337 298 }
mcimadamore@1337 299 }
mcimadamore@1337 300 }
duke@1 301
mcimadamore@1337 302 // return instantiated version of method type
mcimadamore@1337 303 return mt;
mcimadamore@1337 304 } finally {
mcimadamore@1337 305 inferenceContext.notifyChange(types);
duke@1 306 }
duke@1 307 }
duke@1 308 //where
duke@1 309
mcimadamore@1186 310 /** inference check handler **/
mcimadamore@1186 311 class InferenceCheckHandler implements Resolve.MethodCheckHandler {
mcimadamore@1186 312
mcimadamore@1337 313 InferenceContext inferenceContext;
mcimadamore@1186 314
mcimadamore@1337 315 public InferenceCheckHandler(InferenceContext inferenceContext) {
mcimadamore@1337 316 this.inferenceContext = inferenceContext;
mcimadamore@1186 317 }
mcimadamore@1186 318
mcimadamore@1186 319 public InapplicableMethodException arityMismatch() {
mcimadamore@1337 320 return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars());
mcimadamore@1186 321 }
mcimadamore@1296 322 public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
mcimadamore@1186 323 String key = varargs ?
mcimadamore@1296 324 "infer.varargs.argument.mismatch" :
mcimadamore@1296 325 "infer.no.conforming.assignment.exists";
mcimadamore@1298 326 return inferenceException.setMessage(key,
mcimadamore@1337 327 inferenceContext.inferenceVars(), details);
mcimadamore@1186 328 }
mcimadamore@1186 329 public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
mcimadamore@1298 330 return inferenceException.setMessage("inaccessible.varargs.type",
mcimadamore@1186 331 expected, Kinds.kindName(location), location);
mcimadamore@1186 332 }
mcimadamore@1186 333 }
mcimadamore@1186 334
mcimadamore@1251 335 /** check that type parameters are within their bounds.
mcimadamore@895 336 */
mcimadamore@1337 337 void checkWithinBounds(InferenceContext inferenceContext,
mcimadamore@1338 338 Warner warn) throws InferenceException {
mcimadamore@1338 339 //step 1 - check compatibility of instantiated type w.r.t. initial bounds
mcimadamore@1337 340 for (Type t : inferenceContext.undetvars) {
mcimadamore@1251 341 UndetVar uv = (UndetVar)t;
mcimadamore@1338 342 uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), types);
mcimadamore@1337 343 checkCompatibleUpperBounds(uv, inferenceContext.inferenceVars());
mcimadamore@1338 344 if (!inferenceContext.restvars().contains(uv.qtype)) {
mcimadamore@1337 345 Type inst = inferenceContext.asInstType(t, types);
mcimadamore@1338 346 for (Type u : uv.getBounds(InferenceBound.UPPER)) {
mcimadamore@1337 347 if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u, types), warn)) {
mcimadamore@1251 348 reportBoundError(uv, BoundErrorKind.UPPER);
mcimadamore@1251 349 }
mcimadamore@1251 350 }
mcimadamore@1338 351 for (Type l : uv.getBounds(InferenceBound.LOWER)) {
mcimadamore@1338 352 Assert.check(!inferenceContext.free(l));
mcimadamore@1338 353 if (!types.isSubtypeUnchecked(l, inst, warn)) {
mcimadamore@1251 354 reportBoundError(uv, BoundErrorKind.LOWER);
mcimadamore@1251 355 }
mcimadamore@1251 356 }
mcimadamore@1338 357 for (Type e : uv.getBounds(InferenceBound.EQ)) {
mcimadamore@1338 358 Assert.check(!inferenceContext.free(e));
mcimadamore@1338 359 if (!types.isSameType(inst, e)) {
mcimadamore@1251 360 reportBoundError(uv, BoundErrorKind.EQ);
mcimadamore@1251 361 }
mcimadamore@1251 362 }
mcimadamore@1251 363 }
mcimadamore@1338 364 }
mcimadamore@1338 365
mcimadamore@1338 366 //step 2 - check that eq bounds are consistent w.r.t. eq/lower bounds
mcimadamore@1338 367 for (Type t : inferenceContext.undetvars) {
mcimadamore@1338 368 UndetVar uv = (UndetVar)t;
mcimadamore@1338 369 //check eq bounds consistency
mcimadamore@1338 370 Type eq = null;
mcimadamore@1338 371 for (Type e : uv.getBounds(InferenceBound.EQ)) {
mcimadamore@1338 372 Assert.check(!inferenceContext.free(e));
mcimadamore@1338 373 if (eq != null && !types.isSameType(e, eq)) {
mcimadamore@1338 374 reportBoundError(uv, BoundErrorKind.EQ);
mcimadamore@1338 375 }
mcimadamore@1338 376 eq = e;
mcimadamore@1338 377 for (Type l : uv.getBounds(InferenceBound.LOWER)) {
mcimadamore@1338 378 Assert.check(!inferenceContext.free(l));
mcimadamore@1338 379 if (!types.isSubtypeUnchecked(l, e, warn)) {
mcimadamore@1338 380 reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER);
mcimadamore@1338 381 }
mcimadamore@1338 382 }
mcimadamore@1338 383 for (Type u : uv.getBounds(InferenceBound.UPPER)) {
mcimadamore@1338 384 if (inferenceContext.free(u)) continue;
mcimadamore@1338 385 if (!types.isSubtypeUnchecked(e, u, warn)) {
mcimadamore@1338 386 reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER);
mcimadamore@1338 387 }
mcimadamore@1338 388 }
mcimadamore@1338 389 }
duke@1 390 }
mcimadamore@895 391 }
duke@1 392
mcimadamore@1251 393 void checkCompatibleUpperBounds(UndetVar uv, List<Type> tvars) {
mcimadamore@1251 394 // VGJ: sort of inlined maximizeInst() below. Adding
mcimadamore@1251 395 // bounds can cause lobounds that are above hibounds.
mcimadamore@1251 396 ListBuffer<Type> hiboundsNoVars = ListBuffer.lb();
mcimadamore@1338 397 for (Type t : Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter)) {
mcimadamore@1251 398 if (!t.containsAny(tvars)) {
mcimadamore@1251 399 hiboundsNoVars.append(t);
mcimadamore@1251 400 }
duke@1 401 }
mcimadamore@1251 402 List<Type> hibounds = hiboundsNoVars.toList();
mcimadamore@1251 403 Type hb = null;
mcimadamore@1251 404 if (hibounds.isEmpty())
mcimadamore@1251 405 hb = syms.objectType;
mcimadamore@1251 406 else if (hibounds.tail.isEmpty())
mcimadamore@1251 407 hb = hibounds.head;
mcimadamore@1251 408 else
mcimadamore@1251 409 hb = types.glb(hibounds);
mcimadamore@1251 410 if (hb == null || hb.isErroneous())
mcimadamore@1251 411 reportBoundError(uv, BoundErrorKind.BAD_UPPER);
mcimadamore@1251 412 }
mcimadamore@1251 413
mcimadamore@1251 414 enum BoundErrorKind {
mcimadamore@1251 415 BAD_UPPER() {
mcimadamore@1251 416 @Override
mcimadamore@1251 417 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 418 return ex.setMessage("incompatible.upper.bounds", uv.qtype,
mcimadamore@1338 419 uv.getBounds(InferenceBound.UPPER));
mcimadamore@1338 420 }
mcimadamore@1338 421 },
mcimadamore@1338 422 BAD_EQ_UPPER() {
mcimadamore@1338 423 @Override
mcimadamore@1338 424 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 425 return ex.setMessage("incompatible.eq.upper.bounds", uv.qtype,
mcimadamore@1338 426 uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.UPPER));
mcimadamore@1338 427 }
mcimadamore@1338 428 },
mcimadamore@1338 429 BAD_EQ_LOWER() {
mcimadamore@1338 430 @Override
mcimadamore@1338 431 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 432 return ex.setMessage("incompatible.eq.lower.bounds", uv.qtype,
mcimadamore@1338 433 uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.LOWER));
mcimadamore@1251 434 }
mcimadamore@1251 435 },
mcimadamore@1251 436 UPPER() {
mcimadamore@1251 437 @Override
mcimadamore@1251 438 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 439 return ex.setMessage("inferred.do.not.conform.to.upper.bounds", uv.inst,
mcimadamore@1338 440 uv.getBounds(InferenceBound.UPPER));
mcimadamore@1251 441 }
mcimadamore@1251 442 },
mcimadamore@1251 443 LOWER() {
mcimadamore@1251 444 @Override
mcimadamore@1251 445 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 446 return ex.setMessage("inferred.do.not.conform.to.lower.bounds", uv.inst,
mcimadamore@1338 447 uv.getBounds(InferenceBound.LOWER));
mcimadamore@1251 448 }
mcimadamore@1251 449 },
mcimadamore@1251 450 EQ() {
mcimadamore@1251 451 @Override
mcimadamore@1251 452 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1338 453 return ex.setMessage("inferred.do.not.conform.to.eq.bounds", uv.inst,
mcimadamore@1338 454 uv.getBounds(InferenceBound.EQ));
mcimadamore@1251 455 }
mcimadamore@1251 456 };
mcimadamore@1251 457
mcimadamore@1251 458 abstract InapplicableMethodException setMessage(InferenceException ex, UndetVar uv);
mcimadamore@1251 459 }
mcimadamore@1251 460 //where
mcimadamore@1251 461 void reportBoundError(UndetVar uv, BoundErrorKind bk) {
mcimadamore@1298 462 throw bk.setMessage(inferenceException, uv);
duke@1 463 }
mcimadamore@674 464
mcimadamore@674 465 /**
mcimadamore@674 466 * Compute a synthetic method type corresponding to the requested polymorphic
mcimadamore@820 467 * method signature. The target return type is computed from the immediately
mcimadamore@820 468 * enclosing scope surrounding the polymorphic-signature call.
mcimadamore@674 469 */
mcimadamore@1239 470 Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
mcimadamore@674 471 MethodSymbol spMethod, // sig. poly. method or null if none
mcimadamore@820 472 List<Type> argtypes) {
mcimadamore@674 473 final Type restype;
mcimadamore@716 474
mcimadamore@820 475 //The return type for a polymorphic signature call is computed from
mcimadamore@820 476 //the enclosing tree E, as follows: if E is a cast, then use the
mcimadamore@820 477 //target type of the cast expression as a return type; if E is an
mcimadamore@820 478 //expression statement, the return type is 'void' - otherwise the
mcimadamore@820 479 //return type is simply 'Object'. A correctness check ensures that
mcimadamore@820 480 //env.next refers to the lexically enclosing environment in which
mcimadamore@820 481 //the polymorphic signature call environment is nested.
mcimadamore@820 482
mcimadamore@820 483 switch (env.next.tree.getTag()) {
jjg@1127 484 case TYPECAST:
mcimadamore@820 485 JCTypeCast castTree = (JCTypeCast)env.next.tree;
mcimadamore@820 486 restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ?
mcimadamore@820 487 castTree.clazz.type :
mcimadamore@820 488 syms.objectType;
mcimadamore@820 489 break;
jjg@1127 490 case EXEC:
mcimadamore@820 491 JCTree.JCExpressionStatement execTree =
mcimadamore@820 492 (JCTree.JCExpressionStatement)env.next.tree;
mcimadamore@820 493 restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ?
mcimadamore@820 494 syms.voidType :
mcimadamore@820 495 syms.objectType;
mcimadamore@820 496 break;
mcimadamore@820 497 default:
mcimadamore@820 498 restype = syms.objectType;
mcimadamore@674 499 }
mcimadamore@674 500
mcimadamore@674 501 List<Type> paramtypes = Type.map(argtypes, implicitArgType);
mcimadamore@674 502 List<Type> exType = spMethod != null ?
mcimadamore@674 503 spMethod.getThrownTypes() :
mcimadamore@674 504 List.of(syms.throwableType); // make it throw all exceptions
mcimadamore@674 505
mcimadamore@674 506 MethodType mtype = new MethodType(paramtypes,
mcimadamore@674 507 restype,
mcimadamore@674 508 exType,
mcimadamore@674 509 syms.methodClass);
mcimadamore@674 510 return mtype;
mcimadamore@674 511 }
mcimadamore@674 512 //where
mcimadamore@674 513 Mapping implicitArgType = new Mapping ("implicitArgType") {
mcimadamore@674 514 public Type apply(Type t) {
mcimadamore@674 515 t = types.erasure(t);
mcimadamore@674 516 if (t.tag == BOT)
mcimadamore@674 517 // nulls type as the marker type Null (which has no instances)
mcimadamore@674 518 // infer as java.lang.Void for now
mcimadamore@674 519 t = types.boxedClass(syms.voidType).type;
mcimadamore@674 520 return t;
mcimadamore@674 521 }
mcimadamore@674 522 };
mcimadamore@1337 523
mcimadamore@1337 524 /**
mcimadamore@1337 525 * Mapping that turns inference variables into undet vars
mcimadamore@1337 526 * (used by inference context)
mcimadamore@1337 527 */
mcimadamore@1338 528 Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") {
mcimadamore@1337 529 public Type apply(Type t) {
mcimadamore@1338 530 if (t.tag == TYPEVAR) return new UndetVar((TypeVar)t, types);
mcimadamore@1337 531 else return t.map(this);
mcimadamore@1337 532 }
mcimadamore@1337 533 };
mcimadamore@1337 534
mcimadamore@1337 535 /**
mcimadamore@1337 536 * An inference context keeps track of the set of variables that are free
mcimadamore@1337 537 * in the current context. It provides utility methods for opening/closing
mcimadamore@1337 538 * types to their corresponding free/closed forms. It also provide hooks for
mcimadamore@1337 539 * attaching deferred post-inference action (see PendingCheck). Finally,
mcimadamore@1337 540 * it can be used as an entry point for performing upper/lower bound inference
mcimadamore@1337 541 * (see InferenceKind).
mcimadamore@1337 542 */
mcimadamore@1337 543 static class InferenceContext {
mcimadamore@1337 544
mcimadamore@1337 545 /**
mcimadamore@1337 546 * Single-method-interface for defining inference callbacks. Certain actions
mcimadamore@1337 547 * (i.e. subtyping checks) might need to be redone after all inference variables
mcimadamore@1337 548 * have been fixed.
mcimadamore@1337 549 */
mcimadamore@1337 550 interface FreeTypeListener {
mcimadamore@1337 551 void typesInferred(InferenceContext inferenceContext);
mcimadamore@1337 552 }
mcimadamore@1337 553
mcimadamore@1337 554 /** list of inference vars as undet vars */
mcimadamore@1337 555 List<Type> undetvars;
mcimadamore@1337 556
mcimadamore@1337 557 /** list of inference vars in this context */
mcimadamore@1337 558 List<Type> inferencevars;
mcimadamore@1337 559
mcimadamore@1337 560 java.util.Map<FreeTypeListener, List<Type>> freeTypeListeners =
mcimadamore@1337 561 new java.util.HashMap<FreeTypeListener, List<Type>>();
mcimadamore@1337 562
mcimadamore@1337 563 List<FreeTypeListener> freetypeListeners = List.nil();
mcimadamore@1337 564
mcimadamore@1338 565 public InferenceContext(List<Type> inferencevars, Infer infer) {
mcimadamore@1338 566 this.undetvars = Type.map(inferencevars, infer.fromTypeVarFun);
mcimadamore@1337 567 this.inferencevars = inferencevars;
mcimadamore@1337 568 }
mcimadamore@1337 569
mcimadamore@1337 570 /**
mcimadamore@1337 571 * returns the list of free variables (as type-variables) in this
mcimadamore@1337 572 * inference context
mcimadamore@1337 573 */
mcimadamore@1337 574 List<Type> inferenceVars() {
mcimadamore@1337 575 return inferencevars;
mcimadamore@1337 576 }
mcimadamore@1337 577
mcimadamore@1337 578 /**
mcimadamore@1337 579 * returns the list of uninstantiated variables (as type-variables) in this
mcimadamore@1337 580 * inference context (usually called after instantiate())
mcimadamore@1337 581 */
mcimadamore@1337 582 List<Type> restvars() {
mcimadamore@1337 583 List<Type> undetvars = this.undetvars;
mcimadamore@1337 584 ListBuffer<Type> restvars = ListBuffer.lb();
mcimadamore@1337 585 for (Type t : instTypes()) {
mcimadamore@1337 586 UndetVar uv = (UndetVar)undetvars.head;
mcimadamore@1337 587 if (uv.qtype == t) {
mcimadamore@1337 588 restvars.append(t);
mcimadamore@1337 589 }
mcimadamore@1337 590 undetvars = undetvars.tail;
mcimadamore@1337 591 }
mcimadamore@1337 592 return restvars.toList();
mcimadamore@1337 593 }
mcimadamore@1337 594
mcimadamore@1337 595 /**
mcimadamore@1337 596 * is this type free?
mcimadamore@1337 597 */
mcimadamore@1337 598 final boolean free(Type t) {
mcimadamore@1337 599 return t.containsAny(inferencevars);
mcimadamore@1337 600 }
mcimadamore@1337 601
mcimadamore@1337 602 final boolean free(List<Type> ts) {
mcimadamore@1337 603 for (Type t : ts) {
mcimadamore@1337 604 if (free(t)) return true;
mcimadamore@1337 605 }
mcimadamore@1337 606 return false;
mcimadamore@1337 607 }
mcimadamore@1337 608
mcimadamore@1337 609 /**
mcimadamore@1337 610 * Returns a list of free variables in a given type
mcimadamore@1337 611 */
mcimadamore@1337 612 final List<Type> freeVarsIn(Type t) {
mcimadamore@1337 613 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 614 for (Type iv : inferenceVars()) {
mcimadamore@1337 615 if (t.contains(iv)) {
mcimadamore@1337 616 buf.add(iv);
mcimadamore@1337 617 }
mcimadamore@1337 618 }
mcimadamore@1337 619 return buf.toList();
mcimadamore@1337 620 }
mcimadamore@1337 621
mcimadamore@1337 622 final List<Type> freeVarsIn(List<Type> ts) {
mcimadamore@1337 623 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 624 for (Type t : ts) {
mcimadamore@1337 625 buf.appendList(freeVarsIn(t));
mcimadamore@1337 626 }
mcimadamore@1337 627 ListBuffer<Type> buf2 = ListBuffer.lb();
mcimadamore@1337 628 for (Type t : buf) {
mcimadamore@1337 629 if (!buf2.contains(t)) {
mcimadamore@1337 630 buf2.add(t);
mcimadamore@1337 631 }
mcimadamore@1337 632 }
mcimadamore@1337 633 return buf2.toList();
mcimadamore@1337 634 }
mcimadamore@1337 635
mcimadamore@1337 636 /**
mcimadamore@1337 637 * Replace all free variables in a given type with corresponding
mcimadamore@1337 638 * undet vars (used ahead of subtyping/compatibility checks to allow propagation
mcimadamore@1337 639 * of inference constraints).
mcimadamore@1337 640 */
mcimadamore@1337 641 final Type asFree(Type t, Types types) {
mcimadamore@1337 642 return types.subst(t, inferencevars, undetvars);
mcimadamore@1337 643 }
mcimadamore@1337 644
mcimadamore@1337 645 final List<Type> asFree(List<Type> ts, Types types) {
mcimadamore@1337 646 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 647 for (Type t : ts) {
mcimadamore@1337 648 buf.append(asFree(t, types));
mcimadamore@1337 649 }
mcimadamore@1337 650 return buf.toList();
mcimadamore@1337 651 }
mcimadamore@1337 652
mcimadamore@1337 653 List<Type> instTypes() {
mcimadamore@1337 654 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 655 for (Type t : undetvars) {
mcimadamore@1337 656 UndetVar uv = (UndetVar)t;
mcimadamore@1337 657 buf.append(uv.inst != null ? uv.inst : uv.qtype);
mcimadamore@1337 658 }
mcimadamore@1337 659 return buf.toList();
mcimadamore@1337 660 }
mcimadamore@1337 661
mcimadamore@1337 662 /**
mcimadamore@1337 663 * Replace all free variables in a given type with corresponding
mcimadamore@1337 664 * instantiated types - if one or more free variable has not been
mcimadamore@1337 665 * fully instantiated, it will still be available in the resulting type.
mcimadamore@1337 666 */
mcimadamore@1337 667 Type asInstType(Type t, Types types) {
mcimadamore@1337 668 return types.subst(t, inferencevars, instTypes());
mcimadamore@1337 669 }
mcimadamore@1337 670
mcimadamore@1337 671 List<Type> asInstTypes(List<Type> ts, Types types) {
mcimadamore@1337 672 ListBuffer<Type> buf = ListBuffer.lb();
mcimadamore@1337 673 for (Type t : ts) {
mcimadamore@1337 674 buf.append(asInstType(t, types));
mcimadamore@1337 675 }
mcimadamore@1337 676 return buf.toList();
mcimadamore@1337 677 }
mcimadamore@1337 678
mcimadamore@1337 679 /**
mcimadamore@1337 680 * Add custom hook for performing post-inference action
mcimadamore@1337 681 */
mcimadamore@1337 682 void addFreeTypeListener(List<Type> types, FreeTypeListener ftl) {
mcimadamore@1337 683 freeTypeListeners.put(ftl, freeVarsIn(types));
mcimadamore@1337 684 }
mcimadamore@1337 685
mcimadamore@1337 686 /**
mcimadamore@1337 687 * Mark the inference context as complete and trigger evaluation
mcimadamore@1337 688 * of all deferred checks.
mcimadamore@1337 689 */
mcimadamore@1337 690 void notifyChange(Types types) {
mcimadamore@1337 691 InferenceException thrownEx = null;
mcimadamore@1337 692 for (Map.Entry<FreeTypeListener, List<Type>> entry :
mcimadamore@1337 693 new HashMap<FreeTypeListener, List<Type>>(freeTypeListeners).entrySet()) {
mcimadamore@1337 694 if (!Type.containsAny(entry.getValue(), restvars())) {
mcimadamore@1337 695 try {
mcimadamore@1337 696 entry.getKey().typesInferred(this);
mcimadamore@1337 697 freeTypeListeners.remove(entry.getKey());
mcimadamore@1337 698 } catch (InferenceException ex) {
mcimadamore@1337 699 if (thrownEx == null) {
mcimadamore@1337 700 thrownEx = ex;
mcimadamore@1337 701 }
mcimadamore@1337 702 }
mcimadamore@1337 703 }
mcimadamore@1337 704 }
mcimadamore@1337 705 //inference exception multiplexing - present any inference exception
mcimadamore@1337 706 //thrown when processing listeners as a single one
mcimadamore@1337 707 if (thrownEx != null) {
mcimadamore@1337 708 throw thrownEx;
mcimadamore@1337 709 }
mcimadamore@1337 710 }
mcimadamore@895 711 }
mcimadamore@1337 712
mcimadamore@1338 713 final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), this);
mcimadamore@1337 714 }

mercurial