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

Tue, 25 Sep 2012 11:55:34 +0100

author
mcimadamore
date
Tue, 25 Sep 2012 11:55:34 +0100
changeset 1337
2eca84194807
parent 1298
2d75e7c952b8
child 1338
ad2ca2a4ab5e
permissions
-rw-r--r--

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

mercurial