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

Mon, 21 Jan 2013 20:13:56 +0000

author
mcimadamore
date
Mon, 21 Jan 2013 20:13:56 +0000
changeset 1510
7873d37f5b37
parent 1479
38d3d1027f5a
child 1519
97bd5e7151bc
permissions
-rw-r--r--

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

mercurial