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

Tue, 08 Jan 2013 10:15:30 +0100

author
mcimadamore
date
Tue, 08 Jan 2013 10:15:30 +0100
changeset 1479
38d3d1027f5a
parent 1415
01c9d4161882
child 1510
7873d37f5b37
permissions
-rw-r--r--

8005243: Restructure method check code to allow pluggable checkers
Summary: Add interface to perform a method check - to be implemented by helper classes
Reviewed-by: jjg

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

mercurial