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

Thu, 31 May 2012 17:42:14 +0100

author
mcimadamore
date
Thu, 31 May 2012 17:42:14 +0100
changeset 1268
af6a4c24f4e3
parent 1251
6f0ed5a89c25
child 1296
cddc2c894cc6
permissions
-rw-r--r--

7166552: Inference: cleanup usage of Type.ForAll
Summary: Remove hack to callback into type-inference from assignment context
Reviewed-by: dlsmith, 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@674 28 import com.sun.tools.javac.tree.JCTree;
mcimadamore@674 29 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
mcimadamore@820 30 import com.sun.tools.javac.tree.TreeInfo;
duke@1 31 import com.sun.tools.javac.util.*;
duke@1 32 import com.sun.tools.javac.util.List;
duke@1 33 import com.sun.tools.javac.code.*;
duke@1 34 import com.sun.tools.javac.code.Type.*;
mcimadamore@299 35 import com.sun.tools.javac.code.Symbol.*;
mcimadamore@1186 36 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
mcimadamore@1114 37 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
mcimadamore@1114 38 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
duke@1 39
duke@1 40 import static com.sun.tools.javac.code.TypeTags.*;
duke@1 41
duke@1 42 /** Helper class for type parameter inference, used by the attribution phase.
duke@1 43 *
jjg@581 44 * <p><b>This is NOT part of any supported API.
jjg@581 45 * If you write code that depends on this, you do so at your own risk.
duke@1 46 * This code and its internal interfaces are subject to change or
duke@1 47 * deletion without notice.</b>
duke@1 48 */
duke@1 49 public class Infer {
duke@1 50 protected static final Context.Key<Infer> inferKey =
duke@1 51 new Context.Key<Infer>();
duke@1 52
duke@1 53 /** A value for prototypes that admit any type, including polymorphic ones. */
duke@1 54 public static final Type anyPoly = new Type(NONE, null);
duke@1 55
duke@1 56 Symtab syms;
duke@1 57 Types types;
mcimadamore@396 58 Check chk;
mcimadamore@299 59 Resolve rs;
mcimadamore@1114 60 Log log;
mcimadamore@89 61 JCDiagnostic.Factory diags;
duke@1 62
duke@1 63 public static Infer instance(Context context) {
duke@1 64 Infer instance = context.get(inferKey);
duke@1 65 if (instance == null)
duke@1 66 instance = new Infer(context);
duke@1 67 return instance;
duke@1 68 }
duke@1 69
duke@1 70 protected Infer(Context context) {
duke@1 71 context.put(inferKey, this);
duke@1 72 syms = Symtab.instance(context);
duke@1 73 types = Types.instance(context);
mcimadamore@299 74 rs = Resolve.instance(context);
mcimadamore@1114 75 log = Log.instance(context);
mcimadamore@396 76 chk = Check.instance(context);
mcimadamore@89 77 diags = JCDiagnostic.Factory.instance(context);
mcimadamore@89 78 ambiguousNoInstanceException =
mcimadamore@89 79 new NoInstanceException(true, diags);
mcimadamore@89 80 unambiguousNoInstanceException =
mcimadamore@89 81 new NoInstanceException(false, diags);
mcimadamore@299 82 invalidInstanceException =
mcimadamore@299 83 new InvalidInstanceException(diags);
mcimadamore@299 84
duke@1 85 }
duke@1 86
mcimadamore@1186 87 public static class InferenceException extends InapplicableMethodException {
duke@1 88 private static final long serialVersionUID = 0;
duke@1 89
mcimadamore@299 90 InferenceException(JCDiagnostic.Factory diags) {
mcimadamore@689 91 super(diags);
duke@1 92 }
mcimadamore@299 93 }
mcimadamore@299 94
mcimadamore@299 95 public static class NoInstanceException extends InferenceException {
mcimadamore@299 96 private static final long serialVersionUID = 1;
mcimadamore@299 97
mcimadamore@299 98 boolean isAmbiguous; // exist several incomparable best instances?
mcimadamore@299 99
mcimadamore@299 100 NoInstanceException(boolean isAmbiguous, JCDiagnostic.Factory diags) {
mcimadamore@299 101 super(diags);
mcimadamore@299 102 this.isAmbiguous = isAmbiguous;
duke@1 103 }
duke@1 104 }
mcimadamore@299 105
mcimadamore@299 106 public static class InvalidInstanceException extends InferenceException {
mcimadamore@299 107 private static final long serialVersionUID = 2;
mcimadamore@299 108
mcimadamore@299 109 InvalidInstanceException(JCDiagnostic.Factory diags) {
mcimadamore@299 110 super(diags);
mcimadamore@299 111 }
mcimadamore@299 112 }
mcimadamore@299 113
mcimadamore@89 114 private final NoInstanceException ambiguousNoInstanceException;
mcimadamore@89 115 private final NoInstanceException unambiguousNoInstanceException;
mcimadamore@299 116 private final InvalidInstanceException invalidInstanceException;
duke@1 117
duke@1 118 /***************************************************************************
duke@1 119 * Auxiliary type values and classes
duke@1 120 ***************************************************************************/
duke@1 121
duke@1 122 /** A mapping that turns type variables into undetermined type variables.
duke@1 123 */
mcimadamore@1251 124 List<Type> makeUndetvars(List<Type> tvars) {
mcimadamore@1251 125 List<Type> undetvars = Type.map(tvars, fromTypeVarFun);
mcimadamore@1251 126 for (Type t : undetvars) {
mcimadamore@1251 127 UndetVar uv = (UndetVar)t;
mcimadamore@1251 128 uv.hibounds = types.getBounds((TypeVar)uv.qtype);
mcimadamore@1251 129 }
mcimadamore@1251 130 return undetvars;
mcimadamore@1251 131 }
mcimadamore@1251 132 //where
mcimadamore@1251 133 Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") {
mcimadamore@1251 134 public Type apply(Type t) {
mcimadamore@1251 135 if (t.tag == TYPEVAR) return new UndetVar(t);
mcimadamore@1251 136 else return t.map(this);
duke@1 137 }
mcimadamore@1251 138 };
duke@1 139
duke@1 140 /***************************************************************************
duke@1 141 * Mini/Maximization of UndetVars
duke@1 142 ***************************************************************************/
duke@1 143
duke@1 144 /** Instantiate undetermined type variable to its minimal upper bound.
duke@1 145 * Throw a NoInstanceException if this not possible.
duke@1 146 */
duke@1 147 void maximizeInst(UndetVar that, Warner warn) throws NoInstanceException {
mcimadamore@828 148 List<Type> hibounds = Type.filter(that.hibounds, errorFilter);
mcimadamore@1251 149 if (that.eq.isEmpty()) {
mcimadamore@828 150 if (hibounds.isEmpty())
duke@1 151 that.inst = syms.objectType;
mcimadamore@828 152 else if (hibounds.tail.isEmpty())
mcimadamore@828 153 that.inst = hibounds.head;
mcimadamore@210 154 else
mcimadamore@828 155 that.inst = types.glb(hibounds);
mcimadamore@1251 156 } else {
mcimadamore@1251 157 that.inst = that.eq.head;
duke@1 158 }
mcimadamore@210 159 if (that.inst == null ||
mcimadamore@298 160 that.inst.isErroneous())
mcimadamore@210 161 throw ambiguousNoInstanceException
mcimadamore@210 162 .setMessage("no.unique.maximal.instance.exists",
mcimadamore@828 163 that.qtype, hibounds);
duke@1 164 }
duke@1 165
mcimadamore@828 166 private Filter<Type> errorFilter = new Filter<Type>() {
mcimadamore@828 167 @Override
mcimadamore@828 168 public boolean accepts(Type t) {
mcimadamore@828 169 return !t.isErroneous();
mcimadamore@828 170 }
mcimadamore@828 171 };
mcimadamore@828 172
jjg@110 173 /** Instantiate undetermined type variable to the lub of all its lower bounds.
duke@1 174 * Throw a NoInstanceException if this not possible.
duke@1 175 */
duke@1 176 void minimizeInst(UndetVar that, Warner warn) throws NoInstanceException {
mcimadamore@828 177 List<Type> lobounds = Type.filter(that.lobounds, errorFilter);
mcimadamore@1251 178 if (that.eq.isEmpty()) {
mcimadamore@828 179 if (lobounds.isEmpty())
duke@1 180 that.inst = syms.botType;
mcimadamore@828 181 else if (lobounds.tail.isEmpty())
mcimadamore@828 182 that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head;
duke@1 183 else {
mcimadamore@828 184 that.inst = types.lub(lobounds);
mcimadamore@5 185 }
jjg@110 186 if (that.inst == null || that.inst.tag == ERROR)
duke@1 187 throw ambiguousNoInstanceException
duke@1 188 .setMessage("no.unique.minimal.instance.exists",
mcimadamore@828 189 that.qtype, lobounds);
mcimadamore@1251 190 } else {
mcimadamore@1251 191 that.inst = that.eq.head;
duke@1 192 }
duke@1 193 }
duke@1 194
mcimadamore@1186 195 Type asUndetType(Type t, List<Type> undetvars) {
mcimadamore@1186 196 return types.subst(t, inferenceVars(undetvars), undetvars);
mcimadamore@1186 197 }
mcimadamore@1186 198
mcimadamore@1186 199 List<Type> inferenceVars(List<Type> undetvars) {
mcimadamore@1186 200 ListBuffer<Type> tvars = ListBuffer.lb();
mcimadamore@1186 201 for (Type uv : undetvars) {
mcimadamore@1186 202 tvars.append(((UndetVar)uv).qtype);
mcimadamore@1186 203 }
mcimadamore@1186 204 return tvars.toList();
mcimadamore@1186 205 }
mcimadamore@1186 206
duke@1 207 /***************************************************************************
duke@1 208 * Exported Methods
duke@1 209 ***************************************************************************/
duke@1 210
duke@1 211 /** Try to instantiate expression type `that' to given type `to'.
duke@1 212 * If a maximal instantiation exists which makes this type
duke@1 213 * a subtype of type `to', return the instantiated type.
duke@1 214 * If no instantiation exists, or if several incomparable
duke@1 215 * best instantiations exist throw a NoInstanceException.
duke@1 216 */
mcimadamore@1268 217 public List<Type> instantiateUninferred(DiagnosticPosition pos,
mcimadamore@1268 218 List<Type> undetvars,
mcimadamore@1268 219 List<Type> tvars,
mcimadamore@1268 220 MethodType mtype,
mcimadamore@1268 221 Attr.ResultInfo resultInfo,
mcimadamore@299 222 Warner warn) throws InferenceException {
mcimadamore@1268 223 Type to = resultInfo.pt;
mcimadamore@1268 224 if (to.tag == NONE) {
mcimadamore@1268 225 to = mtype.getReturnType().tag <= VOID ?
mcimadamore@1268 226 mtype.getReturnType() : syms.objectType;
mcimadamore@1268 227 }
mcimadamore@1268 228 Type qtype1 = types.subst(mtype.getReturnType(), tvars, undetvars);
mcimadamore@753 229 if (!types.isSubtype(qtype1,
mcimadamore@753 230 qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) {
duke@1 231 throw unambiguousNoInstanceException
mcimadamore@689 232 .setMessage("infer.no.conforming.instance.exists",
mcimadamore@1268 233 tvars, mtype.getReturnType(), to);
duke@1 234 }
duke@1 235
mcimadamore@1251 236 List<Type> insttypes;
mcimadamore@1251 237 while (true) {
mcimadamore@1251 238 boolean stuck = true;
mcimadamore@1251 239 insttypes = List.nil();
mcimadamore@1251 240 for (Type t : undetvars) {
mcimadamore@1251 241 UndetVar uv = (UndetVar)t;
mcimadamore@1268 242 if (uv.inst == null && (uv.eq.nonEmpty() || !Type.containsAny(uv.hibounds, tvars))) {
mcimadamore@1251 243 maximizeInst((UndetVar)t, warn);
mcimadamore@1251 244 stuck = false;
mcimadamore@1251 245 }
mcimadamore@1251 246 insttypes = insttypes.append(uv.inst == null ? uv.qtype : uv.inst);
mcimadamore@1251 247 }
mcimadamore@1268 248 if (!Type.containsAny(insttypes, tvars)) {
mcimadamore@1251 249 //all variables have been instantiated - exit
mcimadamore@1251 250 break;
mcimadamore@1251 251 } else if (stuck) {
mcimadamore@1251 252 //some variables could not be instantiated because of cycles in
mcimadamore@1251 253 //upper bounds - provide a (possibly recursive) default instantiation
mcimadamore@1251 254 insttypes = types.subst(insttypes,
mcimadamore@1268 255 tvars,
mcimadamore@1268 256 instantiateAsUninferredVars(undetvars, tvars));
mcimadamore@1251 257 break;
mcimadamore@1251 258 } else {
mcimadamore@1251 259 //some variables have been instantiated - replace newly instantiated
mcimadamore@1251 260 //variables in remaining upper bounds and continue
mcimadamore@1251 261 for (Type t : undetvars) {
mcimadamore@1251 262 UndetVar uv = (UndetVar)t;
mcimadamore@1268 263 uv.hibounds = types.subst(uv.hibounds, tvars, insttypes);
mcimadamore@1251 264 }
mcimadamore@1251 265 }
mcimadamore@635 266 }
mcimadamore@1268 267 return insttypes;
duke@1 268 }
mcimadamore@1251 269
mcimadamore@1251 270 /**
mcimadamore@1251 271 * Infer cyclic inference variables as described in 15.12.2.8.
mcimadamore@1251 272 */
mcimadamore@1178 273 private List<Type> instantiateAsUninferredVars(List<Type> undetvars, List<Type> tvars) {
mcimadamore@1178 274 Assert.check(undetvars.length() == tvars.length());
mcimadamore@1251 275 ListBuffer<Type> insttypes = ListBuffer.lb();
mcimadamore@1251 276 ListBuffer<Type> todo = ListBuffer.lb();
mcimadamore@1251 277 //step 1 - create fresh tvars
mcimadamore@635 278 for (Type t : undetvars) {
mcimadamore@635 279 UndetVar uv = (UndetVar)t;
mcimadamore@1251 280 if (uv.inst == null) {
mcimadamore@1251 281 TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
mcimadamore@1251 282 fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.hibounds), null);
mcimadamore@1251 283 todo.append(uv);
mcimadamore@1251 284 uv.inst = fresh_tvar.type;
mcimadamore@1251 285 }
mcimadamore@1251 286 insttypes.append(uv.inst);
mcimadamore@635 287 }
mcimadamore@1251 288 //step 2 - replace fresh tvars in their bounds
mcimadamore@1178 289 List<Type> formals = tvars;
mcimadamore@1251 290 for (Type t : todo) {
mcimadamore@1251 291 UndetVar uv = (UndetVar)t;
mcimadamore@1251 292 TypeVar ct = (TypeVar)uv.inst;
mcimadamore@1251 293 ct.bound = types.glb(types.subst(types.getBounds(ct), tvars, insttypes.toList()));
mcimadamore@1251 294 if (ct.bound.isErroneous()) {
mcimadamore@1251 295 //report inference error if glb fails
mcimadamore@1251 296 reportBoundError(uv, BoundErrorKind.BAD_UPPER);
mcimadamore@1251 297 }
mcimadamore@1178 298 formals = formals.tail;
mcimadamore@635 299 }
mcimadamore@1251 300 return insttypes.toList();
mcimadamore@635 301 }
duke@1 302
duke@1 303 /** Instantiate method type `mt' by finding instantiations of
duke@1 304 * `tvars' so that method can be applied to `argtypes'.
duke@1 305 */
mcimadamore@1268 306 public Type instantiateMethod(Env<AttrContext> env,
mcimadamore@547 307 List<Type> tvars,
duke@1 308 MethodType mt,
mcimadamore@1268 309 Attr.ResultInfo resultInfo,
mcimadamore@1268 310 Symbol msym,
mcimadamore@1268 311 List<Type> argtypes,
mcimadamore@1268 312 boolean allowBoxing,
mcimadamore@1268 313 boolean useVarargs,
mcimadamore@1268 314 Warner warn) throws InferenceException {
duke@1 315 //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
mcimadamore@1268 316 List<Type> undetvars = makeUndetvars(tvars);
mcimadamore@689 317
mcimadamore@1268 318 List<Type> capturedArgs =
mcimadamore@1186 319 rs.checkRawArgumentsAcceptable(env, undetvars, argtypes, mt.getParameterTypes(),
mcimadamore@1186 320 allowBoxing, useVarargs, warn, new InferenceCheckHandler(undetvars));
duke@1 321
duke@1 322 // minimize as yet undetermined type variables
duke@1 323 for (Type t : undetvars)
duke@1 324 minimizeInst((UndetVar) t, warn);
duke@1 325
duke@1 326 /** Type variables instantiated to bottom */
duke@1 327 ListBuffer<Type> restvars = new ListBuffer<Type>();
duke@1 328
mcimadamore@396 329 /** Undet vars instantiated to bottom */
mcimadamore@396 330 final ListBuffer<Type> restundet = new ListBuffer<Type>();
mcimadamore@396 331
duke@1 332 /** Instantiated types or TypeVars if under-constrained */
duke@1 333 ListBuffer<Type> insttypes = new ListBuffer<Type>();
duke@1 334
duke@1 335 /** Instantiated types or UndetVars if under-constrained */
duke@1 336 ListBuffer<Type> undettypes = new ListBuffer<Type>();
duke@1 337
duke@1 338 for (Type t : undetvars) {
duke@1 339 UndetVar uv = (UndetVar)t;
duke@1 340 if (uv.inst.tag == BOT) {
duke@1 341 restvars.append(uv.qtype);
mcimadamore@396 342 restundet.append(uv);
duke@1 343 insttypes.append(uv.qtype);
duke@1 344 undettypes.append(uv);
duke@1 345 uv.inst = null;
duke@1 346 } else {
duke@1 347 insttypes.append(uv.inst);
duke@1 348 undettypes.append(uv.inst);
duke@1 349 }
duke@1 350 }
mcimadamore@1251 351 checkWithinBounds(tvars, undetvars, insttypes.toList(), warn);
duke@1 352
mcimadamore@299 353 mt = (MethodType)types.subst(mt, tvars, insttypes.toList());
mcimadamore@299 354
mcimadamore@1268 355 if (!restvars.isEmpty() && resultInfo != null) {
mcimadamore@1268 356 List<Type> restInferred =
mcimadamore@1268 357 instantiateUninferred(env.tree.pos(), restundet.toList(), restvars.toList(), mt, resultInfo, warn);
mcimadamore@1268 358 checkWithinBounds(tvars, undetvars,
mcimadamore@1268 359 types.subst(insttypes.toList(), restvars.toList(), restInferred), warn);
mcimadamore@1268 360 mt = (MethodType)types.subst(mt, restvars.toList(), restInferred);
mcimadamore@1268 361 if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
mcimadamore@1268 362 log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
mcimadamore@1268 363 }
duke@1 364 }
mcimadamore@1268 365
mcimadamore@1268 366 if (restvars.isEmpty() || resultInfo != null) {
mcimadamore@845 367 // check that actuals conform to inferred formals
mcimadamore@845 368 checkArgumentsAcceptable(env, capturedArgs, mt.getParameterTypes(), allowBoxing, useVarargs, warn);
mcimadamore@299 369 }
mcimadamore@1268 370 // return instantiated version of method type
mcimadamore@1268 371 return mt;
duke@1 372 }
duke@1 373 //where
duke@1 374
mcimadamore@1186 375 /** inference check handler **/
mcimadamore@1186 376 class InferenceCheckHandler implements Resolve.MethodCheckHandler {
mcimadamore@1186 377
mcimadamore@1186 378 List<Type> undetvars;
mcimadamore@1186 379
mcimadamore@1186 380 public InferenceCheckHandler(List<Type> undetvars) {
mcimadamore@1186 381 this.undetvars = undetvars;
mcimadamore@1186 382 }
mcimadamore@1186 383
mcimadamore@1186 384 public InapplicableMethodException arityMismatch() {
mcimadamore@1186 385 return unambiguousNoInstanceException.setMessage("infer.arg.length.mismatch");
mcimadamore@1186 386 }
mcimadamore@1186 387 public InapplicableMethodException argumentMismatch(boolean varargs, Type found, Type expected) {
mcimadamore@1186 388 String key = varargs ?
mcimadamore@1186 389 "infer.varargs.argument.mismatch" :
mcimadamore@1186 390 "infer.no.conforming.assignment.exists";
mcimadamore@1186 391 return unambiguousNoInstanceException.setMessage(key,
mcimadamore@1186 392 inferenceVars(undetvars), found, expected);
mcimadamore@1186 393 }
mcimadamore@1186 394 public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
mcimadamore@1186 395 return unambiguousNoInstanceException.setMessage("inaccessible.varargs.type",
mcimadamore@1186 396 expected, Kinds.kindName(location), location);
mcimadamore@1186 397 }
mcimadamore@1186 398 }
mcimadamore@1186 399
mcimadamore@845 400 private void checkArgumentsAcceptable(Env<AttrContext> env, List<Type> actuals, List<Type> formals,
mcimadamore@845 401 boolean allowBoxing, boolean useVarargs, Warner warn) {
mcimadamore@845 402 try {
mcimadamore@845 403 rs.checkRawArgumentsAcceptable(env, actuals, formals,
mcimadamore@845 404 allowBoxing, useVarargs, warn);
mcimadamore@845 405 }
mcimadamore@1186 406 catch (InapplicableMethodException ex) {
mcimadamore@845 407 // inferred method is not applicable
mcimadamore@845 408 throw invalidInstanceException.setMessage(ex.getDiagnostic());
mcimadamore@845 409 }
mcimadamore@845 410 }
mcimadamore@845 411
mcimadamore@1251 412 /** check that type parameters are within their bounds.
mcimadamore@895 413 */
mcimadamore@1251 414 void checkWithinBounds(List<Type> tvars,
mcimadamore@1251 415 List<Type> undetvars,
mcimadamore@1251 416 List<Type> arguments,
mcimadamore@1251 417 Warner warn)
mcimadamore@1251 418 throws InvalidInstanceException {
mcimadamore@1251 419 List<Type> args = arguments;
mcimadamore@1251 420 for (Type t : undetvars) {
mcimadamore@1251 421 UndetVar uv = (UndetVar)t;
mcimadamore@1251 422 uv.hibounds = types.subst(uv.hibounds, tvars, arguments);
mcimadamore@1251 423 uv.lobounds = types.subst(uv.lobounds, tvars, arguments);
mcimadamore@1251 424 uv.eq = types.subst(uv.eq, tvars, arguments);
mcimadamore@1251 425 checkCompatibleUpperBounds(uv, tvars);
mcimadamore@1251 426 if (args.head.tag != TYPEVAR || !args.head.containsAny(tvars)) {
mcimadamore@1251 427 Type inst = args.head;
mcimadamore@1251 428 for (Type u : uv.hibounds) {
mcimadamore@1251 429 if (!types.isSubtypeUnchecked(inst, types.subst(u, tvars, undetvars), warn)) {
mcimadamore@1251 430 reportBoundError(uv, BoundErrorKind.UPPER);
mcimadamore@1251 431 }
mcimadamore@1251 432 }
mcimadamore@1251 433 for (Type l : uv.lobounds) {
mcimadamore@1251 434 if (!types.isSubtypeUnchecked(types.subst(l, tvars, undetvars), inst, warn)) {
mcimadamore@1251 435 reportBoundError(uv, BoundErrorKind.LOWER);
mcimadamore@1251 436 }
mcimadamore@1251 437 }
mcimadamore@1251 438 for (Type e : uv.eq) {
mcimadamore@1251 439 if (!types.isSameType(inst, types.subst(e, tvars, undetvars))) {
mcimadamore@1251 440 reportBoundError(uv, BoundErrorKind.EQ);
mcimadamore@1251 441 }
mcimadamore@1251 442 }
mcimadamore@1251 443 }
mcimadamore@1251 444 args = args.tail;
duke@1 445 }
mcimadamore@895 446 }
duke@1 447
mcimadamore@1251 448 void checkCompatibleUpperBounds(UndetVar uv, List<Type> tvars) {
mcimadamore@1251 449 // VGJ: sort of inlined maximizeInst() below. Adding
mcimadamore@1251 450 // bounds can cause lobounds that are above hibounds.
mcimadamore@1251 451 ListBuffer<Type> hiboundsNoVars = ListBuffer.lb();
mcimadamore@1251 452 for (Type t : Type.filter(uv.hibounds, errorFilter)) {
mcimadamore@1251 453 if (!t.containsAny(tvars)) {
mcimadamore@1251 454 hiboundsNoVars.append(t);
mcimadamore@1251 455 }
duke@1 456 }
mcimadamore@1251 457 List<Type> hibounds = hiboundsNoVars.toList();
mcimadamore@1251 458 Type hb = null;
mcimadamore@1251 459 if (hibounds.isEmpty())
mcimadamore@1251 460 hb = syms.objectType;
mcimadamore@1251 461 else if (hibounds.tail.isEmpty())
mcimadamore@1251 462 hb = hibounds.head;
mcimadamore@1251 463 else
mcimadamore@1251 464 hb = types.glb(hibounds);
mcimadamore@1251 465 if (hb == null || hb.isErroneous())
mcimadamore@1251 466 reportBoundError(uv, BoundErrorKind.BAD_UPPER);
mcimadamore@1251 467 }
mcimadamore@1251 468
mcimadamore@1251 469 enum BoundErrorKind {
mcimadamore@1251 470 BAD_UPPER() {
mcimadamore@1251 471 @Override
mcimadamore@1251 472 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1251 473 return ex.setMessage("incompatible.upper.bounds", uv.qtype, uv.hibounds);
mcimadamore@1251 474 }
mcimadamore@1251 475 },
mcimadamore@1251 476 UPPER() {
mcimadamore@1251 477 @Override
mcimadamore@1251 478 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1251 479 return ex.setMessage("inferred.do.not.conform.to.upper.bounds", uv.inst, uv.hibounds);
mcimadamore@1251 480 }
mcimadamore@1251 481 },
mcimadamore@1251 482 LOWER() {
mcimadamore@1251 483 @Override
mcimadamore@1251 484 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1251 485 return ex.setMessage("inferred.do.not.conform.to.lower.bounds", uv.inst, uv.lobounds);
mcimadamore@1251 486 }
mcimadamore@1251 487 },
mcimadamore@1251 488 EQ() {
mcimadamore@1251 489 @Override
mcimadamore@1251 490 InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) {
mcimadamore@1251 491 return ex.setMessage("inferred.do.not.conform.to.eq.bounds", uv.inst, uv.eq);
mcimadamore@1251 492 }
mcimadamore@1251 493 };
mcimadamore@1251 494
mcimadamore@1251 495 abstract InapplicableMethodException setMessage(InferenceException ex, UndetVar uv);
mcimadamore@1251 496 }
mcimadamore@1251 497 //where
mcimadamore@1251 498 void reportBoundError(UndetVar uv, BoundErrorKind bk) {
mcimadamore@1251 499 throw bk.setMessage(uv.inst == null ? ambiguousNoInstanceException : invalidInstanceException, uv);
duke@1 500 }
mcimadamore@674 501
mcimadamore@674 502 /**
mcimadamore@674 503 * Compute a synthetic method type corresponding to the requested polymorphic
mcimadamore@820 504 * method signature. The target return type is computed from the immediately
mcimadamore@820 505 * enclosing scope surrounding the polymorphic-signature call.
mcimadamore@674 506 */
mcimadamore@1239 507 Type instantiatePolymorphicSignatureInstance(Env<AttrContext> env,
mcimadamore@674 508 MethodSymbol spMethod, // sig. poly. method or null if none
mcimadamore@820 509 List<Type> argtypes) {
mcimadamore@674 510 final Type restype;
mcimadamore@716 511
mcimadamore@820 512 //The return type for a polymorphic signature call is computed from
mcimadamore@820 513 //the enclosing tree E, as follows: if E is a cast, then use the
mcimadamore@820 514 //target type of the cast expression as a return type; if E is an
mcimadamore@820 515 //expression statement, the return type is 'void' - otherwise the
mcimadamore@820 516 //return type is simply 'Object'. A correctness check ensures that
mcimadamore@820 517 //env.next refers to the lexically enclosing environment in which
mcimadamore@820 518 //the polymorphic signature call environment is nested.
mcimadamore@820 519
mcimadamore@820 520 switch (env.next.tree.getTag()) {
jjg@1127 521 case TYPECAST:
mcimadamore@820 522 JCTypeCast castTree = (JCTypeCast)env.next.tree;
mcimadamore@820 523 restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ?
mcimadamore@820 524 castTree.clazz.type :
mcimadamore@820 525 syms.objectType;
mcimadamore@820 526 break;
jjg@1127 527 case EXEC:
mcimadamore@820 528 JCTree.JCExpressionStatement execTree =
mcimadamore@820 529 (JCTree.JCExpressionStatement)env.next.tree;
mcimadamore@820 530 restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ?
mcimadamore@820 531 syms.voidType :
mcimadamore@820 532 syms.objectType;
mcimadamore@820 533 break;
mcimadamore@820 534 default:
mcimadamore@820 535 restype = syms.objectType;
mcimadamore@674 536 }
mcimadamore@674 537
mcimadamore@674 538 List<Type> paramtypes = Type.map(argtypes, implicitArgType);
mcimadamore@674 539 List<Type> exType = spMethod != null ?
mcimadamore@674 540 spMethod.getThrownTypes() :
mcimadamore@674 541 List.of(syms.throwableType); // make it throw all exceptions
mcimadamore@674 542
mcimadamore@674 543 MethodType mtype = new MethodType(paramtypes,
mcimadamore@674 544 restype,
mcimadamore@674 545 exType,
mcimadamore@674 546 syms.methodClass);
mcimadamore@674 547 return mtype;
mcimadamore@674 548 }
mcimadamore@674 549 //where
mcimadamore@674 550 Mapping implicitArgType = new Mapping ("implicitArgType") {
mcimadamore@674 551 public Type apply(Type t) {
mcimadamore@674 552 t = types.erasure(t);
mcimadamore@674 553 if (t.tag == BOT)
mcimadamore@674 554 // nulls type as the marker type Null (which has no instances)
mcimadamore@674 555 // infer as java.lang.Void for now
mcimadamore@674 556 t = types.boxedClass(syms.voidType).type;
mcimadamore@674 557 return t;
mcimadamore@674 558 }
mcimadamore@674 559 };
mcimadamore@895 560 }

mercurial