duke@1: /* ohair@798: * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.comp; duke@1: mcimadamore@674: import com.sun.tools.javac.tree.JCTree; mcimadamore@674: import com.sun.tools.javac.tree.JCTree.JCTypeCast; mcimadamore@820: import com.sun.tools.javac.tree.TreeInfo; duke@1: import com.sun.tools.javac.util.*; duke@1: import com.sun.tools.javac.util.List; duke@1: import com.sun.tools.javac.code.*; duke@1: import com.sun.tools.javac.code.Type.*; mcimadamore@396: import com.sun.tools.javac.code.Type.ForAll.ConstraintKind; mcimadamore@299: import com.sun.tools.javac.code.Symbol.*; mcimadamore@89: import com.sun.tools.javac.util.JCDiagnostic; duke@1: duke@1: import static com.sun.tools.javac.code.TypeTags.*; duke@1: duke@1: /** Helper class for type parameter inference, used by the attribution phase. duke@1: * jjg@581: *

This is NOT part of any supported API. jjg@581: * If you write code that depends on this, you do so at your own risk. duke@1: * This code and its internal interfaces are subject to change or duke@1: * deletion without notice. duke@1: */ duke@1: public class Infer { duke@1: protected static final Context.Key inferKey = duke@1: new Context.Key(); duke@1: duke@1: /** A value for prototypes that admit any type, including polymorphic ones. */ duke@1: public static final Type anyPoly = new Type(NONE, null); duke@1: duke@1: Symtab syms; duke@1: Types types; mcimadamore@396: Check chk; mcimadamore@299: Resolve rs; mcimadamore@89: JCDiagnostic.Factory diags; duke@1: duke@1: public static Infer instance(Context context) { duke@1: Infer instance = context.get(inferKey); duke@1: if (instance == null) duke@1: instance = new Infer(context); duke@1: return instance; duke@1: } duke@1: duke@1: protected Infer(Context context) { duke@1: context.put(inferKey, this); duke@1: syms = Symtab.instance(context); duke@1: types = Types.instance(context); mcimadamore@299: rs = Resolve.instance(context); mcimadamore@396: chk = Check.instance(context); mcimadamore@89: diags = JCDiagnostic.Factory.instance(context); mcimadamore@89: ambiguousNoInstanceException = mcimadamore@89: new NoInstanceException(true, diags); mcimadamore@89: unambiguousNoInstanceException = mcimadamore@89: new NoInstanceException(false, diags); mcimadamore@299: invalidInstanceException = mcimadamore@299: new InvalidInstanceException(diags); mcimadamore@299: duke@1: } duke@1: mcimadamore@689: public static class InferenceException extends Resolve.InapplicableMethodException { duke@1: private static final long serialVersionUID = 0; duke@1: mcimadamore@299: InferenceException(JCDiagnostic.Factory diags) { mcimadamore@689: super(diags); duke@1: } mcimadamore@299: } mcimadamore@299: mcimadamore@299: public static class NoInstanceException extends InferenceException { mcimadamore@299: private static final long serialVersionUID = 1; mcimadamore@299: mcimadamore@299: boolean isAmbiguous; // exist several incomparable best instances? mcimadamore@299: mcimadamore@299: NoInstanceException(boolean isAmbiguous, JCDiagnostic.Factory diags) { mcimadamore@299: super(diags); mcimadamore@299: this.isAmbiguous = isAmbiguous; duke@1: } duke@1: } mcimadamore@299: mcimadamore@299: public static class InvalidInstanceException extends InferenceException { mcimadamore@299: private static final long serialVersionUID = 2; mcimadamore@299: mcimadamore@299: InvalidInstanceException(JCDiagnostic.Factory diags) { mcimadamore@299: super(diags); mcimadamore@299: } mcimadamore@299: } mcimadamore@299: mcimadamore@89: private final NoInstanceException ambiguousNoInstanceException; mcimadamore@89: private final NoInstanceException unambiguousNoInstanceException; mcimadamore@299: private final InvalidInstanceException invalidInstanceException; duke@1: duke@1: /*************************************************************************** duke@1: * Auxiliary type values and classes duke@1: ***************************************************************************/ duke@1: duke@1: /** A mapping that turns type variables into undetermined type variables. duke@1: */ duke@1: Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") { duke@1: public Type apply(Type t) { duke@1: if (t.tag == TYPEVAR) return new UndetVar(t); duke@1: else return t.map(this); duke@1: } duke@1: }; duke@1: duke@1: /** A mapping that returns its type argument with every UndetVar replaced duke@1: * by its `inst' field. Throws a NoInstanceException duke@1: * if this not possible because an `inst' field is null. mcimadamore@635: * Note: mutually referring undertvars will be left uninstantiated mcimadamore@635: * (that is, they will be replaced by the underlying type-variable). duke@1: */ mcimadamore@635: duke@1: Mapping getInstFun = new Mapping("getInstFun") { duke@1: public Type apply(Type t) { duke@1: switch (t.tag) { mcimadamore@635: case UNKNOWN: duke@1: throw ambiguousNoInstanceException mcimadamore@635: .setMessage("undetermined.type"); mcimadamore@635: case UNDETVAR: mcimadamore@635: UndetVar that = (UndetVar) t; mcimadamore@635: if (that.inst == null) mcimadamore@635: throw ambiguousNoInstanceException mcimadamore@635: .setMessage("type.variable.has.undetermined.type", mcimadamore@635: that.qtype); mcimadamore@635: return isConstraintCyclic(that) ? mcimadamore@635: that.qtype : mcimadamore@635: apply(that.inst); mcimadamore@635: default: mcimadamore@635: return t.map(this); duke@1: } duke@1: } mcimadamore@635: mcimadamore@635: private boolean isConstraintCyclic(UndetVar uv) { mcimadamore@635: Types.UnaryVisitor constraintScanner = mcimadamore@635: new Types.UnaryVisitor() { mcimadamore@635: mcimadamore@635: List seen = List.nil(); mcimadamore@635: mcimadamore@635: Boolean visit(List ts) { mcimadamore@635: for (Type t : ts) { mcimadamore@635: if (visit(t)) return true; mcimadamore@635: } mcimadamore@635: return false; mcimadamore@635: } mcimadamore@635: mcimadamore@635: public Boolean visitType(Type t, Void ignored) { mcimadamore@635: return false; mcimadamore@635: } mcimadamore@635: mcimadamore@635: @Override mcimadamore@635: public Boolean visitClassType(ClassType t, Void ignored) { mcimadamore@635: if (t.isCompound()) { mcimadamore@635: return visit(types.supertype(t)) || mcimadamore@635: visit(types.interfaces(t)); mcimadamore@635: } else { mcimadamore@635: return visit(t.getTypeArguments()); mcimadamore@635: } mcimadamore@635: } mcimadamore@635: @Override mcimadamore@635: public Boolean visitWildcardType(WildcardType t, Void ignored) { mcimadamore@635: return visit(t.type); mcimadamore@635: } mcimadamore@635: mcimadamore@635: @Override mcimadamore@635: public Boolean visitUndetVar(UndetVar t, Void ignored) { mcimadamore@635: if (seen.contains(t)) { mcimadamore@635: return true; mcimadamore@635: } else { mcimadamore@635: seen = seen.prepend(t); mcimadamore@635: return visit(t.inst); mcimadamore@635: } mcimadamore@635: } mcimadamore@635: }; mcimadamore@635: return constraintScanner.visit(uv); mcimadamore@635: } duke@1: }; duke@1: duke@1: /*************************************************************************** duke@1: * Mini/Maximization of UndetVars duke@1: ***************************************************************************/ duke@1: duke@1: /** Instantiate undetermined type variable to its minimal upper bound. duke@1: * Throw a NoInstanceException if this not possible. duke@1: */ duke@1: void maximizeInst(UndetVar that, Warner warn) throws NoInstanceException { mcimadamore@828: List hibounds = Type.filter(that.hibounds, errorFilter); duke@1: if (that.inst == null) { mcimadamore@828: if (hibounds.isEmpty()) duke@1: that.inst = syms.objectType; mcimadamore@828: else if (hibounds.tail.isEmpty()) mcimadamore@828: that.inst = hibounds.head; mcimadamore@210: else mcimadamore@828: that.inst = types.glb(hibounds); duke@1: } mcimadamore@210: if (that.inst == null || mcimadamore@298: that.inst.isErroneous()) mcimadamore@210: throw ambiguousNoInstanceException mcimadamore@210: .setMessage("no.unique.maximal.instance.exists", mcimadamore@828: that.qtype, hibounds); duke@1: } duke@1: //where duke@1: private boolean isSubClass(Type t, final List ts) { duke@1: t = t.baseType(); duke@1: if (t.tag == TYPEVAR) { duke@1: List bounds = types.getBounds((TypeVar)t); duke@1: for (Type s : ts) { duke@1: if (!types.isSameType(t, s.baseType())) { duke@1: for (Type bound : bounds) { duke@1: if (!isSubClass(bound, List.of(s.baseType()))) duke@1: return false; duke@1: } duke@1: } duke@1: } duke@1: } else { duke@1: for (Type s : ts) { duke@1: if (!t.tsym.isSubClass(s.baseType().tsym, types)) duke@1: return false; duke@1: } duke@1: } duke@1: return true; duke@1: } duke@1: mcimadamore@828: private Filter errorFilter = new Filter() { mcimadamore@828: @Override mcimadamore@828: public boolean accepts(Type t) { mcimadamore@828: return !t.isErroneous(); mcimadamore@828: } mcimadamore@828: }; mcimadamore@828: jjg@110: /** Instantiate undetermined type variable to the lub of all its lower bounds. duke@1: * Throw a NoInstanceException if this not possible. duke@1: */ duke@1: void minimizeInst(UndetVar that, Warner warn) throws NoInstanceException { mcimadamore@828: List lobounds = Type.filter(that.lobounds, errorFilter); duke@1: if (that.inst == null) { mcimadamore@828: if (lobounds.isEmpty()) duke@1: that.inst = syms.botType; mcimadamore@828: else if (lobounds.tail.isEmpty()) mcimadamore@828: that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head; duke@1: else { mcimadamore@828: that.inst = types.lub(lobounds); mcimadamore@5: } jjg@110: if (that.inst == null || that.inst.tag == ERROR) duke@1: throw ambiguousNoInstanceException duke@1: .setMessage("no.unique.minimal.instance.exists", mcimadamore@828: that.qtype, lobounds); duke@1: // VGJ: sort of inlined maximizeInst() below. Adding duke@1: // bounds can cause lobounds that are above hibounds. mcimadamore@828: List hibounds = Type.filter(that.hibounds, errorFilter); mcimadamore@828: if (hibounds.isEmpty()) duke@1: return; duke@1: Type hb = null; mcimadamore@828: if (hibounds.tail.isEmpty()) mcimadamore@828: hb = hibounds.head; mcimadamore@828: else for (List bs = hibounds; duke@1: bs.nonEmpty() && hb == null; duke@1: bs = bs.tail) { mcimadamore@828: if (isSubClass(bs.head, hibounds)) duke@1: hb = types.fromUnknownFun.apply(bs.head); duke@1: } duke@1: if (hb == null || mcimadamore@828: !types.isSubtypeUnchecked(hb, hibounds, warn) || duke@1: !types.isSubtypeUnchecked(that.inst, hb, warn)) duke@1: throw ambiguousNoInstanceException; duke@1: } duke@1: } duke@1: duke@1: /*************************************************************************** duke@1: * Exported Methods duke@1: ***************************************************************************/ duke@1: duke@1: /** Try to instantiate expression type `that' to given type `to'. duke@1: * If a maximal instantiation exists which makes this type duke@1: * a subtype of type `to', return the instantiated type. duke@1: * If no instantiation exists, or if several incomparable duke@1: * best instantiations exist throw a NoInstanceException. duke@1: */ duke@1: public Type instantiateExpr(ForAll that, duke@1: Type to, mcimadamore@299: Warner warn) throws InferenceException { duke@1: List undetvars = Type.map(that.tvars, fromTypeVarFun); duke@1: for (List l = undetvars; l.nonEmpty(); l = l.tail) { mcimadamore@396: UndetVar uv = (UndetVar) l.head; mcimadamore@396: TypeVar tv = (TypeVar)uv.qtype; duke@1: ListBuffer hibounds = new ListBuffer(); mcimadamore@615: for (Type t : that.getConstraints(tv, ConstraintKind.EXTENDS)) { mcimadamore@635: hibounds.append(types.subst(t, that.tvars, undetvars)); duke@1: } mcimadamore@635: mcimadamore@396: List inst = that.getConstraints(tv, ConstraintKind.EQUAL); mcimadamore@396: if (inst.nonEmpty() && inst.head.tag != BOT) { mcimadamore@396: uv.inst = inst.head; mcimadamore@396: } mcimadamore@396: uv.hibounds = hibounds.toList(); duke@1: } duke@1: Type qtype1 = types.subst(that.qtype, that.tvars, undetvars); mcimadamore@753: if (!types.isSubtype(qtype1, mcimadamore@753: qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) { duke@1: throw unambiguousNoInstanceException mcimadamore@689: .setMessage("infer.no.conforming.instance.exists", duke@1: that.tvars, that.qtype, to); duke@1: } duke@1: for (List l = undetvars; l.nonEmpty(); l = l.tail) duke@1: maximizeInst((UndetVar) l.head, warn); duke@1: // System.out.println(" = " + qtype1.map(getInstFun));//DEBUG duke@1: duke@1: // check bounds duke@1: List targs = Type.map(undetvars, getInstFun); mcimadamore@635: if (Type.containsAny(targs, that.tvars)) { mcimadamore@635: //replace uninferred type-vars mcimadamore@635: targs = types.subst(targs, mcimadamore@635: that.tvars, mcimadamore@635: instaniateAsUninferredVars(undetvars, that.tvars)); mcimadamore@635: } mcimadamore@396: return chk.checkType(warn.pos(), that.inst(targs, types), to); duke@1: } mcimadamore@635: //where mcimadamore@635: private List instaniateAsUninferredVars(List undetvars, List tvars) { mcimadamore@635: ListBuffer new_targs = ListBuffer.lb(); mcimadamore@635: //step 1 - create syntethic captured vars mcimadamore@635: for (Type t : undetvars) { mcimadamore@635: UndetVar uv = (UndetVar)t; mcimadamore@635: Type newArg = new CapturedType(t.tsym.name, t.tsym, uv.inst, syms.botType, null); mcimadamore@635: new_targs = new_targs.append(newArg); mcimadamore@635: } mcimadamore@635: //step 2 - replace synthetic vars in their bounds mcimadamore@635: for (Type t : new_targs.toList()) { mcimadamore@635: CapturedType ct = (CapturedType)t; mcimadamore@635: ct.bound = types.subst(ct.bound, tvars, new_targs.toList()); mcimadamore@635: WildcardType wt = new WildcardType(ct.bound, BoundKind.EXTENDS, syms.boundClass); mcimadamore@635: ct.wildcard = wt; mcimadamore@635: } mcimadamore@635: return new_targs.toList(); mcimadamore@635: } duke@1: duke@1: /** Instantiate method type `mt' by finding instantiations of duke@1: * `tvars' so that method can be applied to `argtypes'. duke@1: */ mcimadamore@547: public Type instantiateMethod(final Env env, mcimadamore@547: List tvars, duke@1: MethodType mt, mcimadamore@580: final Symbol msym, mcimadamore@299: final List argtypes, mcimadamore@299: final boolean allowBoxing, mcimadamore@299: final boolean useVarargs, mcimadamore@299: final Warner warn) throws InferenceException { duke@1: //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG duke@1: List undetvars = Type.map(tvars, fromTypeVarFun); duke@1: List formals = mt.argtypes; mcimadamore@299: //need to capture exactly once - otherwise subsequent mcimadamore@299: //applicability checks might fail mcimadamore@299: final List capturedArgs = types.capture(argtypes); mcimadamore@299: List actuals = capturedArgs; mcimadamore@299: List actualsNoCapture = argtypes; duke@1: // instantiate all polymorphic argument types and duke@1: // set up lower bounds constraints for undetvars duke@1: Type varargsFormal = useVarargs ? formals.last() : null; mcimadamore@689: if (varargsFormal == null && mcimadamore@689: actuals.size() != formals.size()) { mcimadamore@689: throw unambiguousNoInstanceException mcimadamore@689: .setMessage("infer.arg.length.mismatch"); mcimadamore@689: } mcimadamore@299: while (actuals.nonEmpty() && formals.head != varargsFormal) { mcimadamore@299: Type formal = formals.head; mcimadamore@299: Type actual = actuals.head.baseType(); mcimadamore@299: Type actualNoCapture = actualsNoCapture.head.baseType(); mcimadamore@299: if (actual.tag == FORALL) mcimadamore@299: actual = instantiateArg((ForAll)actual, formal, tvars, warn); mcimadamore@299: Type undetFormal = types.subst(formal, tvars, undetvars); duke@1: boolean works = allowBoxing mcimadamore@299: ? types.isConvertible(actual, undetFormal, warn) mcimadamore@299: : types.isSubtypeUnchecked(actual, undetFormal, warn); duke@1: if (!works) { duke@1: throw unambiguousNoInstanceException mcimadamore@689: .setMessage("infer.no.conforming.assignment.exists", mcimadamore@299: tvars, actualNoCapture, formal); duke@1: } duke@1: formals = formals.tail; mcimadamore@299: actuals = actuals.tail; mcimadamore@299: actualsNoCapture = actualsNoCapture.tail; duke@1: } mcimadamore@689: mcimadamore@689: if (formals.head != varargsFormal) // not enough args mcimadamore@689: throw unambiguousNoInstanceException.setMessage("infer.arg.length.mismatch"); duke@1: duke@1: // for varargs arguments as well duke@1: if (useVarargs) { mcimadamore@299: Type elemType = types.elemtype(varargsFormal); mcimadamore@299: Type elemUndet = types.subst(elemType, tvars, undetvars); mcimadamore@299: while (actuals.nonEmpty()) { mcimadamore@299: Type actual = actuals.head.baseType(); mcimadamore@299: Type actualNoCapture = actualsNoCapture.head.baseType(); mcimadamore@299: if (actual.tag == FORALL) mcimadamore@299: actual = instantiateArg((ForAll)actual, elemType, tvars, warn); mcimadamore@299: boolean works = types.isConvertible(actual, elemUndet, warn); duke@1: if (!works) { duke@1: throw unambiguousNoInstanceException mcimadamore@689: .setMessage("infer.no.conforming.assignment.exists", mcimadamore@299: tvars, actualNoCapture, elemType); duke@1: } mcimadamore@299: actuals = actuals.tail; mcimadamore@299: actualsNoCapture = actualsNoCapture.tail; duke@1: } duke@1: } duke@1: duke@1: // minimize as yet undetermined type variables duke@1: for (Type t : undetvars) duke@1: minimizeInst((UndetVar) t, warn); duke@1: duke@1: /** Type variables instantiated to bottom */ duke@1: ListBuffer restvars = new ListBuffer(); duke@1: mcimadamore@396: /** Undet vars instantiated to bottom */ mcimadamore@396: final ListBuffer restundet = new ListBuffer(); mcimadamore@396: duke@1: /** Instantiated types or TypeVars if under-constrained */ duke@1: ListBuffer insttypes = new ListBuffer(); duke@1: duke@1: /** Instantiated types or UndetVars if under-constrained */ duke@1: ListBuffer undettypes = new ListBuffer(); duke@1: duke@1: for (Type t : undetvars) { duke@1: UndetVar uv = (UndetVar)t; duke@1: if (uv.inst.tag == BOT) { duke@1: restvars.append(uv.qtype); mcimadamore@396: restundet.append(uv); duke@1: insttypes.append(uv.qtype); duke@1: undettypes.append(uv); duke@1: uv.inst = null; duke@1: } else { duke@1: insttypes.append(uv.inst); duke@1: undettypes.append(uv.inst); duke@1: } duke@1: } duke@1: checkWithinBounds(tvars, undettypes.toList(), warn); duke@1: mcimadamore@299: mt = (MethodType)types.subst(mt, tvars, insttypes.toList()); mcimadamore@299: duke@1: if (!restvars.isEmpty()) { duke@1: // if there are uninstantiated variables, duke@1: // quantify result type with them mcimadamore@299: final List inferredTypes = insttypes.toList(); mcimadamore@299: final List all_tvars = tvars; //this is the wrong tvars mcimadamore@299: final MethodType mt2 = new MethodType(mt.argtypes, null, mt.thrown, syms.methodClass); mcimadamore@299: mt2.restype = new ForAll(restvars.toList(), mt.restype) { mcimadamore@299: @Override mcimadamore@396: public List getConstraints(TypeVar tv, ConstraintKind ck) { mcimadamore@396: for (Type t : restundet.toList()) { mcimadamore@396: UndetVar uv = (UndetVar)t; mcimadamore@396: if (uv.qtype == tv) { mcimadamore@396: switch (ck) { mcimadamore@615: case EXTENDS: return uv.hibounds.appendList(types.subst(types.getBounds(tv), all_tvars, inferredTypes)); mcimadamore@396: case SUPER: return uv.lobounds; mcimadamore@396: case EQUAL: return uv.inst != null ? List.of(uv.inst) : List.nil(); mcimadamore@396: } mcimadamore@396: } mcimadamore@396: } mcimadamore@396: return List.nil(); mcimadamore@396: } mcimadamore@396: mcimadamore@396: @Override mcimadamore@299: public Type inst(List inferred, Types types) throws NoInstanceException { mcimadamore@299: List formals = types.subst(mt2.argtypes, tvars, inferred); mcimadamore@396: if (!rs.argumentsAcceptable(capturedArgs, formals, mcimadamore@299: allowBoxing, useVarargs, warn)) { mcimadamore@299: // inferred method is not applicable mcimadamore@299: throw invalidInstanceException.setMessage("inferred.do.not.conform.to.params", formals, argtypes); mcimadamore@396: } mcimadamore@396: // check that inferred bounds conform to their bounds mcimadamore@396: checkWithinBounds(all_tvars, mcimadamore@299: types.subst(inferredTypes, tvars, inferred), warn); mcimadamore@547: if (useVarargs) { mcimadamore@795: chk.checkVararg(env.tree.pos(), formals, msym); mcimadamore@547: } mcimadamore@396: return super.inst(inferred, types); mcimadamore@299: }}; mcimadamore@299: return mt2; duke@1: } mcimadamore@299: else if (!rs.argumentsAcceptable(capturedArgs, mt.getParameterTypes(), allowBoxing, useVarargs, warn)) { mcimadamore@299: // inferred method is not applicable mcimadamore@299: throw invalidInstanceException.setMessage("inferred.do.not.conform.to.params", mt.getParameterTypes(), argtypes); mcimadamore@299: } mcimadamore@299: else { mcimadamore@299: // return instantiated version of method type mcimadamore@299: return mt; mcimadamore@299: } duke@1: } duke@1: //where duke@1: duke@1: /** Try to instantiate argument type `that' to given type `to'. duke@1: * If this fails, try to insantiate `that' to `to' where duke@1: * every occurrence of a type variable in `tvars' is replaced duke@1: * by an unknown type. duke@1: */ duke@1: private Type instantiateArg(ForAll that, duke@1: Type to, duke@1: List tvars, mcimadamore@299: Warner warn) throws InferenceException { duke@1: List targs; duke@1: try { duke@1: return instantiateExpr(that, to, warn); duke@1: } catch (NoInstanceException ex) { duke@1: Type to1 = to; duke@1: for (List l = tvars; l.nonEmpty(); l = l.tail) duke@1: to1 = types.subst(to1, List.of(l.head), List.of(syms.unknownType)); duke@1: return instantiateExpr(that, to1, warn); duke@1: } duke@1: } duke@1: duke@1: /** check that type parameters are within their bounds. duke@1: */ mcimadamore@615: void checkWithinBounds(List tvars, duke@1: List arguments, duke@1: Warner warn) mcimadamore@299: throws InvalidInstanceException { duke@1: for (List tvs = tvars, args = arguments; duke@1: tvs.nonEmpty(); duke@1: tvs = tvs.tail, args = args.tail) { mcimadamore@828: if (args.head instanceof UndetVar || mcimadamore@828: tvars.head.getUpperBound().isErroneous()) continue; duke@1: List bounds = types.subst(types.getBounds((TypeVar)tvs.head), tvars, arguments); duke@1: if (!types.isSubtypeUnchecked(args.head, bounds, warn)) mcimadamore@299: throw invalidInstanceException duke@1: .setMessage("inferred.do.not.conform.to.bounds", mcimadamore@299: args.head, bounds); duke@1: } duke@1: } mcimadamore@674: mcimadamore@674: /** mcimadamore@674: * Compute a synthetic method type corresponding to the requested polymorphic mcimadamore@820: * method signature. The target return type is computed from the immediately mcimadamore@820: * enclosing scope surrounding the polymorphic-signature call. mcimadamore@674: */ mcimadamore@674: Type instantiatePolymorphicSignatureInstance(Env env, Type site, mcimadamore@674: Name name, mcimadamore@674: MethodSymbol spMethod, // sig. poly. method or null if none mcimadamore@820: List argtypes) { mcimadamore@674: final Type restype; mcimadamore@716: mcimadamore@820: //The return type for a polymorphic signature call is computed from mcimadamore@820: //the enclosing tree E, as follows: if E is a cast, then use the mcimadamore@820: //target type of the cast expression as a return type; if E is an mcimadamore@820: //expression statement, the return type is 'void' - otherwise the mcimadamore@820: //return type is simply 'Object'. A correctness check ensures that mcimadamore@820: //env.next refers to the lexically enclosing environment in which mcimadamore@820: //the polymorphic signature call environment is nested. mcimadamore@820: mcimadamore@820: switch (env.next.tree.getTag()) { mcimadamore@820: case JCTree.TYPECAST: mcimadamore@820: JCTypeCast castTree = (JCTypeCast)env.next.tree; mcimadamore@820: restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ? mcimadamore@820: castTree.clazz.type : mcimadamore@820: syms.objectType; mcimadamore@820: break; mcimadamore@820: case JCTree.EXEC: mcimadamore@820: JCTree.JCExpressionStatement execTree = mcimadamore@820: (JCTree.JCExpressionStatement)env.next.tree; mcimadamore@820: restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ? mcimadamore@820: syms.voidType : mcimadamore@820: syms.objectType; mcimadamore@820: break; mcimadamore@820: default: mcimadamore@820: restype = syms.objectType; mcimadamore@674: } mcimadamore@674: mcimadamore@674: List paramtypes = Type.map(argtypes, implicitArgType); mcimadamore@674: List exType = spMethod != null ? mcimadamore@674: spMethod.getThrownTypes() : mcimadamore@674: List.of(syms.throwableType); // make it throw all exceptions mcimadamore@674: mcimadamore@674: MethodType mtype = new MethodType(paramtypes, mcimadamore@674: restype, mcimadamore@674: exType, mcimadamore@674: syms.methodClass); mcimadamore@674: return mtype; mcimadamore@674: } mcimadamore@674: //where mcimadamore@674: Mapping implicitArgType = new Mapping ("implicitArgType") { mcimadamore@674: public Type apply(Type t) { mcimadamore@674: t = types.erasure(t); mcimadamore@674: if (t.tag == BOT) mcimadamore@674: // nulls type as the marker type Null (which has no instances) mcimadamore@674: // infer as java.lang.Void for now mcimadamore@674: t = types.boxedClass(syms.voidType).type; mcimadamore@674: return t; mcimadamore@674: } mcimadamore@674: }; duke@1: }