# HG changeset patch # User vromero # Date 1437777405 25200 # Node ID dd96ac308ab88a48ae9c3bf5757de95dba68922d # Parent deb1cda4dc79fc577ca45cc67d3a5e5828ffa62b 8132215: class InferenceContext should live in a separate file Reviewed-by: mcimadamore, jlahoda diff -r deb1cda4dc79 -r dd96ac308ab8 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Fri Jul 24 13:08:36 2015 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Fri Jul 24 15:36:45 2015 -0700 @@ -44,7 +44,6 @@ import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError; import com.sun.tools.javac.comp.Check.CheckContext; import com.sun.tools.javac.comp.DeferredAttr.AttrMode; -import com.sun.tools.javac.comp.Infer.InferenceContext; import com.sun.tools.javac.comp.Infer.FreeTypeListener; import com.sun.tools.javac.jvm.*; import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond; diff -r deb1cda4dc79 -r dd96ac308ab8 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Fri Jul 24 13:08:36 2015 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java Fri Jul 24 15:36:45 2015 -0700 @@ -43,13 +43,10 @@ import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Lint.LintCategory; -import com.sun.tools.javac.code.Scope.CompoundScope; -import com.sun.tools.javac.code.Scope.NamedImportScope; import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext; -import com.sun.tools.javac.comp.Infer.InferenceContext; import com.sun.tools.javac.comp.Infer.FreeTypeListener; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*; @@ -456,7 +453,7 @@ */ public Warner checkWarner(DiagnosticPosition pos, Type found, Type req); - public Infer.InferenceContext inferenceContext(); + public InferenceContext inferenceContext(); public DeferredAttr.DeferredAttrContext deferredAttrContext(); } @@ -486,7 +483,7 @@ return enclosingContext.checkWarner(pos, found, req); } - public Infer.InferenceContext inferenceContext() { + public InferenceContext inferenceContext() { return enclosingContext.inferenceContext(); } @@ -535,7 +532,7 @@ } Type checkType(final DiagnosticPosition pos, final Type found, final Type req, final CheckContext checkContext) { - final Infer.InferenceContext inferenceContext = checkContext.inferenceContext(); + final InferenceContext inferenceContext = checkContext.inferenceContext(); if (inferenceContext.free(req) || inferenceContext.free(found)) { inferenceContext.addFreeTypeListener(List.of(req, found), new FreeTypeListener() { @Override diff -r deb1cda4dc79 -r dd96ac308ab8 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Fri Jul 24 13:08:36 2015 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Fri Jul 24 15:36:45 2015 -0700 @@ -38,7 +38,6 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.comp.Attr.ResultInfo; -import com.sun.tools.javac.comp.Infer.InferenceContext; import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; @@ -1013,7 +1012,7 @@ class CheckStuckPolicy extends PolyScanner implements DeferredStuckPolicy, Infer.FreeTypeListener { Type pt; - Infer.InferenceContext inferenceContext; + InferenceContext inferenceContext; Set stuckVars = new LinkedHashSet<>(); Set depVars = new LinkedHashSet<>(); diff -r deb1cda4dc79 -r dd96ac308ab8 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Fri Jul 24 13:08:36 2015 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java Fri Jul 24 15:36:45 2015 -0700 @@ -25,7 +25,6 @@ package com.sun.tools.javac.comp; -import com.sun.tools.javac.code.Type.TypeMapping; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.TreeInfo; @@ -112,6 +111,8 @@ && options.isUnset("useLegacyInference"); dependenciesFolder = options.get("dumpInferenceGraphsTo"); pendingGraphs = List.nil(); + + emptyContext = new InferenceContext(this, List.nil()); } /** A value for prototypes that admit any type, including polymorphic ones. */ @@ -170,7 +171,7 @@ Resolve.MethodResolutionContext resolveContext, Warner warn) throws InferenceException { //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG - final InferenceContext inferenceContext = new InferenceContext(tvars); //B0 + final InferenceContext inferenceContext = new InferenceContext(this, tvars); //B0 inferenceException.clear(); try { DeferredAttr.DeferredAttrContext deferredAttrContext = @@ -410,7 +411,7 @@ /** * Infer cyclic inference variables as described in 15.12.2.8. */ - private void instantiateAsUninferredVars(List vars, InferenceContext inferenceContext) { + void instantiateAsUninferredVars(List vars, InferenceContext inferenceContext) { ListBuffer todo = new ListBuffer<>(); //step 1 - create fresh tvars for (Type t : vars) { @@ -528,7 +529,7 @@ } else { Type formalInterface = funcInterface.tsym.type; InferenceContext funcInterfaceContext = - new InferenceContext(funcInterface.tsym.type.getTypeArguments()); + new InferenceContext(this, funcInterface.tsym.type.getTypeArguments()); Assert.check(paramTypes != null); //get constraints from explicit params (this is done by @@ -710,7 +711,7 @@ */ CHECK_BOUNDS() { public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), infer.types); infer.checkCompatibleUpperBounds(uv, inferenceContext); if (uv.inst != null) { @@ -746,7 +747,7 @@ */ EQ_CHECK_LEGACY() { public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; Type eq = null; for (Type e : uv.getBounds(InferenceBound.EQ)) { Assert.check(!inferenceContext.free(e)); @@ -780,7 +781,7 @@ EQ_CHECK() { @Override public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; for (Type e : uv.getBounds(InferenceBound.EQ)) { if (e.containsAny(inferenceContext.inferenceVars())) continue; for (Type u : uv.getBounds(InferenceBound.UPPER)) { @@ -807,7 +808,7 @@ */ CROSS_UPPER_LOWER() { public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; for (Type b1 : uv.getBounds(InferenceBound.UPPER)) { for (Type b2 : uv.getBounds(InferenceBound.LOWER)) { if (!isSubtype(inferenceContext.asUndetVar(b2), inferenceContext.asUndetVar(b1), warn , infer)) { @@ -830,7 +831,7 @@ */ CROSS_UPPER_EQ() { public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; for (Type b1 : uv.getBounds(InferenceBound.UPPER)) { for (Type b2 : uv.getBounds(InferenceBound.EQ)) { if (!isSubtype(inferenceContext.asUndetVar(b2), inferenceContext.asUndetVar(b1), warn, infer)) { @@ -853,7 +854,7 @@ */ CROSS_EQ_LOWER() { public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; for (Type b1 : uv.getBounds(InferenceBound.EQ)) { for (Type b2 : uv.getBounds(InferenceBound.LOWER)) { if (!isSubtype(inferenceContext.asUndetVar(b2), inferenceContext.asUndetVar(b1), warn, infer)) { @@ -878,7 +879,7 @@ CROSS_UPPER_UPPER() { @Override public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; List boundList = uv.getBounds(InferenceBound.UPPER).stream() .collect(infer.types.closureCollector(true, infer.types::isSameType)); List boundListTail = boundList.tail; @@ -928,7 +929,7 @@ */ CROSS_EQ_EQ() { public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; for (Type b1 : uv.getBounds(InferenceBound.EQ)) { for (Type b2 : uv.getBounds(InferenceBound.EQ)) { if (b1 != b2) { @@ -952,7 +953,7 @@ */ PROP_UPPER() { public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; for (Type b : uv.getBounds(InferenceBound.UPPER)) { if (inferenceContext.inferenceVars().contains(b)) { UndetVar uv2 = (UndetVar)inferenceContext.asUndetVar(b); @@ -984,7 +985,7 @@ */ PROP_LOWER() { public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; for (Type b : uv.getBounds(InferenceBound.LOWER)) { if (inferenceContext.inferenceVars().contains(b)) { UndetVar uv2 = (UndetVar)inferenceContext.asUndetVar(b); @@ -1016,7 +1017,7 @@ */ PROP_EQ() { public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; for (Type b : uv.getBounds(InferenceBound.EQ)) { if (inferenceContext.inferenceVars().contains(b)) { UndetVar uv2 = (UndetVar)inferenceContext.asUndetVar(b); @@ -1524,7 +1525,7 @@ LOWER(InferenceBound.LOWER) { @Override Type solve(UndetVar uv, InferenceContext inferenceContext) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; List lobounds = filterBounds(uv, inferenceContext); //note: lobounds should have at least one element Type owntype = lobounds.tail.tail == null ? lobounds.head : infer.types.lub(lobounds); @@ -1553,7 +1554,7 @@ //not an unbounded undet var return false; } - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; for (Type db : t.getDeclaredBounds()) { if (t.isInterface()) continue; if (infer.types.asSuper(infer.syms.runtimeExceptionType, db.tsym) != null) { @@ -1567,7 +1568,7 @@ @Override Type solve(UndetVar uv, InferenceContext inferenceContext) { - return inferenceContext.infer().syms.runtimeExceptionType; + return inferenceContext.infer.syms.runtimeExceptionType; } }, /** @@ -1577,7 +1578,7 @@ UPPER(InferenceBound.UPPER) { @Override Type solve(UndetVar uv, InferenceContext inferenceContext) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; List hibounds = filterBounds(uv, inferenceContext); //note: hibounds should have at least one element Type owntype = hibounds.tail.tail == null ? hibounds.head : infer.types.glb(hibounds); @@ -1618,7 +1619,7 @@ @Override Type solve(UndetVar uv, InferenceContext inferenceContext) { - Infer infer = inferenceContext.infer(); + Infer infer = inferenceContext.infer; Type upper = UPPER.filterBounds(uv, inferenceContext).nonEmpty() ? UPPER.solve(uv, inferenceContext) : infer.syms.objectType; @@ -2082,419 +2083,6 @@ void typesInferred(InferenceContext inferenceContext); } - /** - * An inference context keeps track of the set of variables that are free - * in the current context. It provides utility methods for opening/closing - * types to their corresponding free/closed forms. It also provide hooks for - * attaching deferred post-inference action (see PendingCheck). Finally, - * it can be used as an entry point for performing upper/lower bound inference - * (see InferenceKind). - */ - class InferenceContext { - - /** list of inference vars as undet vars */ - List undetvars; - - /** list of inference vars in this context */ - List inferencevars; - - Map> freeTypeListeners = new HashMap<>(); - - List freetypeListeners = List.nil(); - - public InferenceContext(List inferencevars) { - this.undetvars = inferencevars.map(fromTypeVarFun); - this.inferencevars = inferencevars; - } - //where - TypeMapping fromTypeVarFun = new TypeMapping() { - @Override - public Type visitTypeVar(TypeVar tv, Void aVoid) { - return new UndetVar(tv, types); - } - - @Override - public Type visitCapturedType(CapturedType t, Void aVoid) { - return new CapturedUndetVar(t, types); - } - }; - - /** - * add a new inference var to this inference context - */ - void addVar(TypeVar t) { - this.undetvars = this.undetvars.prepend(fromTypeVarFun.apply(t)); - this.inferencevars = this.inferencevars.prepend(t); - } - - /** - * returns the list of free variables (as type-variables) in this - * inference context - */ - List inferenceVars() { - return inferencevars; - } - - /** - * returns the list of uninstantiated variables (as type-variables) in this - * inference context - */ - List restvars() { - return filterVars(new Filter() { - public boolean accepts(UndetVar uv) { - return uv.inst == null; - } - }); - } - - /** - * returns the list of instantiated variables (as type-variables) in this - * inference context - */ - List instvars() { - return filterVars(new Filter() { - public boolean accepts(UndetVar uv) { - return uv.inst != null; - } - }); - } - - /** - * Get list of bounded inference variables (where bound is other than - * declared bounds). - */ - final List boundedVars() { - return filterVars(new Filter() { - public boolean accepts(UndetVar uv) { - return uv.getBounds(InferenceBound.UPPER) - .diff(uv.getDeclaredBounds()) - .appendList(uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)).nonEmpty(); - } - }); - } - - /* Returns the corresponding inference variables. - */ - private List filterVars(Filter fu) { - ListBuffer res = new ListBuffer<>(); - for (Type t : undetvars) { - UndetVar uv = (UndetVar)t; - if (fu.accepts(uv)) { - res.append(uv.qtype); - } - } - return res.toList(); - } - - /** - * is this type free? - */ - final boolean free(Type t) { - return t.containsAny(inferencevars); - } - - final boolean free(List ts) { - for (Type t : ts) { - if (free(t)) return true; - } - return false; - } - - /** - * Returns a list of free variables in a given type - */ - final List freeVarsIn(Type t) { - ListBuffer buf = new ListBuffer<>(); - for (Type iv : inferenceVars()) { - if (t.contains(iv)) { - buf.add(iv); - } - } - return buf.toList(); - } - - final List freeVarsIn(List ts) { - ListBuffer buf = new ListBuffer<>(); - for (Type t : ts) { - buf.appendList(freeVarsIn(t)); - } - ListBuffer buf2 = new ListBuffer<>(); - for (Type t : buf) { - if (!buf2.contains(t)) { - buf2.add(t); - } - } - return buf2.toList(); - } - - /** - * Replace all free variables in a given type with corresponding - * undet vars (used ahead of subtyping/compatibility checks to allow propagation - * of inference constraints). - */ - final Type asUndetVar(Type t) { - return types.subst(t, inferencevars, undetvars); - } - - final List asUndetVars(List ts) { - ListBuffer buf = new ListBuffer<>(); - for (Type t : ts) { - buf.append(asUndetVar(t)); - } - return buf.toList(); - } - - List instTypes() { - ListBuffer buf = new ListBuffer<>(); - for (Type t : undetvars) { - UndetVar uv = (UndetVar)t; - buf.append(uv.inst != null ? uv.inst : uv.qtype); - } - return buf.toList(); - } - - /** - * Replace all free variables in a given type with corresponding - * instantiated types - if one or more free variable has not been - * fully instantiated, it will still be available in the resulting type. - */ - Type asInstType(Type t) { - return types.subst(t, inferencevars, instTypes()); - } - - List asInstTypes(List ts) { - ListBuffer buf = new ListBuffer<>(); - for (Type t : ts) { - buf.append(asInstType(t)); - } - return buf.toList(); - } - - /** - * Add custom hook for performing post-inference action - */ - void addFreeTypeListener(List types, FreeTypeListener ftl) { - freeTypeListeners.put(ftl, freeVarsIn(types)); - } - - /** - * Mark the inference context as complete and trigger evaluation - * of all deferred checks. - */ - void notifyChange() { - notifyChange(inferencevars.diff(restvars())); - } - - void notifyChange(List inferredVars) { - InferenceException thrownEx = null; - for (Map.Entry> entry : - new HashMap<>(freeTypeListeners).entrySet()) { - if (!Type.containsAny(entry.getValue(), inferencevars.diff(inferredVars))) { - try { - entry.getKey().typesInferred(this); - freeTypeListeners.remove(entry.getKey()); - } catch (InferenceException ex) { - if (thrownEx == null) { - thrownEx = ex; - } - } - } - } - //inference exception multiplexing - present any inference exception - //thrown when processing listeners as a single one - if (thrownEx != null) { - throw thrownEx; - } - } - - /** - * Save the state of this inference context - */ - List save() { - ListBuffer buf = new ListBuffer<>(); - for (Type t : undetvars) { - UndetVar uv = (UndetVar)t; - UndetVar uv2 = new UndetVar((TypeVar)uv.qtype, types); - for (InferenceBound ib : InferenceBound.values()) { - for (Type b : uv.getBounds(ib)) { - uv2.addBound(ib, b, types); - } - } - uv2.inst = uv.inst; - buf.add(uv2); - } - return buf.toList(); - } - - /** - * Restore the state of this inference context to the previous known checkpoint - */ - void rollback(List saved_undet) { - Assert.check(saved_undet != null && saved_undet.length() == undetvars.length()); - //restore bounds (note: we need to preserve the old instances) - for (Type t : undetvars) { - UndetVar uv = (UndetVar)t; - UndetVar uv_saved = (UndetVar)saved_undet.head; - for (InferenceBound ib : InferenceBound.values()) { - uv.setBounds(ib, uv_saved.getBounds(ib)); - } - uv.inst = uv_saved.inst; - saved_undet = saved_undet.tail; - } - } - - /** - * Copy variable in this inference context to the given context - */ - void dupTo(final InferenceContext that) { - that.inferencevars = that.inferencevars.appendList( - inferencevars.diff(that.inferencevars)); - that.undetvars = that.undetvars.appendList( - undetvars.diff(that.undetvars)); - //set up listeners to notify original inference contexts as - //propagated vars are inferred in new context - for (Type t : inferencevars) { - that.freeTypeListeners.put(new FreeTypeListener() { - public void typesInferred(InferenceContext inferenceContext) { - InferenceContext.this.notifyChange(); - } - }, List.of(t)); - } - } - - private void solve(GraphStrategy ss, Warner warn) { - solve(ss, new HashMap>(), warn); - } - - /** - * Solve with given graph strategy. - */ - private void solve(GraphStrategy ss, Map> stuckDeps, Warner warn) { - GraphSolver s = new GraphSolver(this, stuckDeps, warn); - s.solve(ss); - } - - /** - * Solve all variables in this context. - */ - public void solve(Warner warn) { - solve(new LeafSolver() { - public boolean done() { - return restvars().isEmpty(); - } - }, warn); - } - - /** - * Solve all variables in the given list. - */ - public void solve(final List vars, Warner warn) { - solve(new BestLeafSolver(vars) { - public boolean done() { - return !free(asInstTypes(vars)); - } - }, warn); - } - - /** - * Solve at least one variable in given list. - */ - public void solveAny(List varsToSolve, Map> optDeps, Warner warn) { - solve(new BestLeafSolver(varsToSolve.intersect(restvars())) { - public boolean done() { - return instvars().intersect(varsToSolve).nonEmpty(); - } - }, optDeps, warn); - } - - /** - * Apply a set of inference steps - */ - private boolean solveBasic(EnumSet steps) { - return solveBasic(inferencevars, steps); - } - - private boolean solveBasic(List varsToSolve, EnumSet steps) { - boolean changed = false; - for (Type t : varsToSolve.intersect(restvars())) { - UndetVar uv = (UndetVar)asUndetVar(t); - for (InferenceStep step : steps) { - if (step.accepts(uv, this)) { - uv.inst = step.solve(uv, this); - changed = true; - break; - } - } - } - return changed; - } - - /** - * Instantiate inference variables in legacy mode (JLS 15.12.2.7, 15.12.2.8). - * During overload resolution, instantiation is done by doing a partial - * inference process using eq/lower bound instantiation. During check, - * we also instantiate any remaining vars by repeatedly using eq/upper - * instantiation, until all variables are solved. - */ - public void solveLegacy(boolean partial, Warner warn, EnumSet steps) { - while (true) { - boolean stuck = !solveBasic(steps); - if (restvars().isEmpty() || partial) { - //all variables have been instantiated - exit - break; - } else if (stuck) { - //some variables could not be instantiated because of cycles in - //upper bounds - provide a (possibly recursive) default instantiation - instantiateAsUninferredVars(restvars(), this); - break; - } else { - //some variables have been instantiated - replace newly instantiated - //variables in remaining upper bounds and continue - for (Type t : undetvars) { - UndetVar uv = (UndetVar)t; - uv.substBounds(inferenceVars(), instTypes(), types); - } - } - } - checkWithinBounds(this, warn); - } - - private Infer infer() { - //back-door to infer - return Infer.this; - } - - @Override - public String toString() { - return "Inference vars: " + inferencevars + '\n' + - "Undet vars: " + undetvars; - } - - /* Method Types.capture() generates a new type every time it's applied - * to a wildcard parameterized type. This is intended functionality but - * there are some cases when what you need is not to generate a new - * captured type but to check that a previously generated captured type - * is correct. There are cases when caching a captured type for later - * reuse is sound. In general two captures from the same AST are equal. - * This is why the tree is used as the key of the map below. This map - * stores a Type per AST. - */ - Map captureTypeCache = new HashMap<>(); - - Type cachedCapture(JCTree tree, Type t, boolean readOnly) { - Type captured = captureTypeCache.get(tree); - if (captured != null) { - return captured; - } - - Type result = types.capture(t); - if (result != t && !readOnly) { // then t is a wildcard parameterized type - captureTypeCache.put(tree, result); - } - return result; - } - } - - final InferenceContext emptyContext = new InferenceContext(List.nil()); + final InferenceContext emptyContext; // } diff -r deb1cda4dc79 -r dd96ac308ab8 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java Fri Jul 24 15:36:45 2015 -0700 @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.comp; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Type.CapturedType; +import com.sun.tools.javac.code.Type.CapturedUndetVar; +import com.sun.tools.javac.code.Type.TypeMapping; +import com.sun.tools.javac.code.Type.TypeVar; +import com.sun.tools.javac.code.Type.UndetVar; +import com.sun.tools.javac.code.Type.UndetVar.InferenceBound; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.comp.Infer.BestLeafSolver; +import com.sun.tools.javac.comp.Infer.FreeTypeListener; +import com.sun.tools.javac.comp.Infer.GraphSolver; +import com.sun.tools.javac.comp.Infer.GraphStrategy; +import com.sun.tools.javac.comp.Infer.InferenceException; +import com.sun.tools.javac.comp.Infer.InferenceStep; +import com.sun.tools.javac.comp.Infer.LeafSolver; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.Assert; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Filter; +import com.sun.tools.javac.util.JCDiagnostic; +import com.sun.tools.javac.util.JCDiagnostic.Factory; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Warner; + +/** + * An inference context keeps track of the set of variables that are free + * in the current context. It provides utility methods for opening/closing + * types to their corresponding free/closed forms. It also provide hooks for + * attaching deferred post-inference action (see PendingCheck). Finally, + * it can be used as an entry point for performing upper/lower bound inference + * (see InferenceKind). + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +class InferenceContext { + + /** list of inference vars as undet vars */ + List undetvars; + + /** list of inference vars in this context */ + List inferencevars; + + Map> freeTypeListeners = new HashMap<>(); + + List freetypeListeners = List.nil(); + + Types types; + Infer infer; + + public InferenceContext(Infer infer, List inferencevars) { + this.inferencevars = inferencevars; + + this.infer = infer; + this.types = infer.types; + + fromTypeVarFun = new TypeMapping() { + @Override + public Type visitTypeVar(TypeVar tv, Void aVoid) { + return new UndetVar(tv, types); + } + + @Override + public Type visitCapturedType(CapturedType t, Void aVoid) { + return new CapturedUndetVar(t, types); + } + }; + this.undetvars = inferencevars.map(fromTypeVarFun); + } + + TypeMapping fromTypeVarFun; + + /** + * add a new inference var to this inference context + */ + void addVar(TypeVar t) { + this.undetvars = this.undetvars.prepend(fromTypeVarFun.apply(t)); + this.inferencevars = this.inferencevars.prepend(t); + } + + /** + * returns the list of free variables (as type-variables) in this + * inference context + */ + List inferenceVars() { + return inferencevars; + } + + /** + * returns the list of uninstantiated variables (as type-variables) in this + * inference context + */ + List restvars() { + return filterVars(new Filter() { + public boolean accepts(UndetVar uv) { + return uv.inst == null; + } + }); + } + + /** + * returns the list of instantiated variables (as type-variables) in this + * inference context + */ + List instvars() { + return filterVars(new Filter() { + public boolean accepts(UndetVar uv) { + return uv.inst != null; + } + }); + } + + /** + * Get list of bounded inference variables (where bound is other than + * declared bounds). + */ + final List boundedVars() { + return filterVars(new Filter() { + public boolean accepts(UndetVar uv) { + return uv.getBounds(InferenceBound.UPPER) + .diff(uv.getDeclaredBounds()) + .appendList(uv.getBounds(InferenceBound.EQ, InferenceBound.LOWER)).nonEmpty(); + } + }); + } + + /* Returns the corresponding inference variables. + */ + private List filterVars(Filter fu) { + ListBuffer res = new ListBuffer<>(); + for (Type t : undetvars) { + UndetVar uv = (UndetVar)t; + if (fu.accepts(uv)) { + res.append(uv.qtype); + } + } + return res.toList(); + } + + /** + * is this type free? + */ + final boolean free(Type t) { + return t.containsAny(inferencevars); + } + + final boolean free(List ts) { + for (Type t : ts) { + if (free(t)) return true; + } + return false; + } + + /** + * Returns a list of free variables in a given type + */ + final List freeVarsIn(Type t) { + ListBuffer buf = new ListBuffer<>(); + for (Type iv : inferenceVars()) { + if (t.contains(iv)) { + buf.add(iv); + } + } + return buf.toList(); + } + + final List freeVarsIn(List ts) { + ListBuffer buf = new ListBuffer<>(); + for (Type t : ts) { + buf.appendList(freeVarsIn(t)); + } + ListBuffer buf2 = new ListBuffer<>(); + for (Type t : buf) { + if (!buf2.contains(t)) { + buf2.add(t); + } + } + return buf2.toList(); + } + + /** + * Replace all free variables in a given type with corresponding + * undet vars (used ahead of subtyping/compatibility checks to allow propagation + * of inference constraints). + */ + final Type asUndetVar(Type t) { + return types.subst(t, inferencevars, undetvars); + } + + final List asUndetVars(List ts) { + ListBuffer buf = new ListBuffer<>(); + for (Type t : ts) { + buf.append(asUndetVar(t)); + } + return buf.toList(); + } + + List instTypes() { + ListBuffer buf = new ListBuffer<>(); + for (Type t : undetvars) { + UndetVar uv = (UndetVar)t; + buf.append(uv.inst != null ? uv.inst : uv.qtype); + } + return buf.toList(); + } + + /** + * Replace all free variables in a given type with corresponding + * instantiated types - if one or more free variable has not been + * fully instantiated, it will still be available in the resulting type. + */ + Type asInstType(Type t) { + return types.subst(t, inferencevars, instTypes()); + } + + List asInstTypes(List ts) { + ListBuffer buf = new ListBuffer<>(); + for (Type t : ts) { + buf.append(asInstType(t)); + } + return buf.toList(); + } + + /** + * Add custom hook for performing post-inference action + */ + void addFreeTypeListener(List types, FreeTypeListener ftl) { + freeTypeListeners.put(ftl, freeVarsIn(types)); + } + + /** + * Mark the inference context as complete and trigger evaluation + * of all deferred checks. + */ + void notifyChange() { + notifyChange(inferencevars.diff(restvars())); + } + + void notifyChange(List inferredVars) { + InferenceException thrownEx = null; + for (Map.Entry> entry : + new HashMap<>(freeTypeListeners).entrySet()) { + if (!Type.containsAny(entry.getValue(), inferencevars.diff(inferredVars))) { + try { + entry.getKey().typesInferred(this); + freeTypeListeners.remove(entry.getKey()); + } catch (InferenceException ex) { + if (thrownEx == null) { + thrownEx = ex; + } + } + } + } + //inference exception multiplexing - present any inference exception + //thrown when processing listeners as a single one + if (thrownEx != null) { + throw thrownEx; + } + } + + /** + * Save the state of this inference context + */ + List save() { + ListBuffer buf = new ListBuffer<>(); + for (Type t : undetvars) { + UndetVar uv = (UndetVar)t; + UndetVar uv2 = new UndetVar((TypeVar)uv.qtype, types); + for (InferenceBound ib : InferenceBound.values()) { + for (Type b : uv.getBounds(ib)) { + uv2.addBound(ib, b, types); + } + } + uv2.inst = uv.inst; + buf.add(uv2); + } + return buf.toList(); + } + + /** + * Restore the state of this inference context to the previous known checkpoint + */ + void rollback(List saved_undet) { + Assert.check(saved_undet != null && saved_undet.length() == undetvars.length()); + //restore bounds (note: we need to preserve the old instances) + for (Type t : undetvars) { + UndetVar uv = (UndetVar)t; + UndetVar uv_saved = (UndetVar)saved_undet.head; + for (InferenceBound ib : InferenceBound.values()) { + uv.setBounds(ib, uv_saved.getBounds(ib)); + } + uv.inst = uv_saved.inst; + saved_undet = saved_undet.tail; + } + } + + /** + * Copy variable in this inference context to the given context + */ + void dupTo(final InferenceContext that) { + that.inferencevars = that.inferencevars.appendList( + inferencevars.diff(that.inferencevars)); + that.undetvars = that.undetvars.appendList( + undetvars.diff(that.undetvars)); + //set up listeners to notify original inference contexts as + //propagated vars are inferred in new context + for (Type t : inferencevars) { + that.freeTypeListeners.put(new FreeTypeListener() { + public void typesInferred(InferenceContext inferenceContext) { + InferenceContext.this.notifyChange(); + } + }, List.of(t)); + } + } + + private void solve(GraphStrategy ss, Warner warn) { + solve(ss, new HashMap>(), warn); + } + + /** + * Solve with given graph strategy. + */ + private void solve(GraphStrategy ss, Map> stuckDeps, Warner warn) { + GraphSolver s = infer.new GraphSolver(this, stuckDeps, warn); + s.solve(ss); + } + + /** + * Solve all variables in this context. + */ + public void solve(Warner warn) { + solve(infer.new LeafSolver() { + public boolean done() { + return restvars().isEmpty(); + } + }, warn); + } + + /** + * Solve all variables in the given list. + */ + public void solve(final List vars, Warner warn) { + solve(infer.new BestLeafSolver(vars) { + public boolean done() { + return !free(asInstTypes(vars)); + } + }, warn); + } + + /** + * Solve at least one variable in given list. + */ + public void solveAny(List varsToSolve, Map> optDeps, Warner warn) { + solve(infer.new BestLeafSolver(varsToSolve.intersect(restvars())) { + public boolean done() { + return instvars().intersect(varsToSolve).nonEmpty(); + } + }, optDeps, warn); + } + + /** + * Apply a set of inference steps + */ + private boolean solveBasic(EnumSet steps) { + return solveBasic(inferencevars, steps); + } + + boolean solveBasic(List varsToSolve, EnumSet steps) { + boolean changed = false; + for (Type t : varsToSolve.intersect(restvars())) { + UndetVar uv = (UndetVar)asUndetVar(t); + for (InferenceStep step : steps) { + if (step.accepts(uv, this)) { + uv.inst = step.solve(uv, this); + changed = true; + break; + } + } + } + return changed; + } + + /** + * Instantiate inference variables in legacy mode (JLS 15.12.2.7, 15.12.2.8). + * During overload resolution, instantiation is done by doing a partial + * inference process using eq/lower bound instantiation. During check, + * we also instantiate any remaining vars by repeatedly using eq/upper + * instantiation, until all variables are solved. + */ + public void solveLegacy(boolean partial, Warner warn, EnumSet steps) { + while (true) { + boolean stuck = !solveBasic(steps); + if (restvars().isEmpty() || partial) { + //all variables have been instantiated - exit + break; + } else if (stuck) { + //some variables could not be instantiated because of cycles in + //upper bounds - provide a (possibly recursive) default instantiation + infer.instantiateAsUninferredVars(restvars(), this); + break; + } else { + //some variables have been instantiated - replace newly instantiated + //variables in remaining upper bounds and continue + for (Type t : undetvars) { + UndetVar uv = (UndetVar)t; + uv.substBounds(inferenceVars(), instTypes(), types); + } + } + } + infer.checkWithinBounds(this, warn); + } + + @Override + public String toString() { + return "Inference vars: " + inferencevars + '\n' + + "Undet vars: " + undetvars; + } + + /* Method Types.capture() generates a new type every time it's applied + * to a wildcard parameterized type. This is intended functionality but + * there are some cases when what you need is not to generate a new + * captured type but to check that a previously generated captured type + * is correct. There are cases when caching a captured type for later + * reuse is sound. In general two captures from the same AST are equal. + * This is why the tree is used as the key of the map below. This map + * stores a Type per AST. + */ + Map captureTypeCache = new HashMap<>(); + + Type cachedCapture(JCTree tree, Type t, boolean readOnly) { + Type captured = captureTypeCache.get(tree); + if (captured != null) { + return captured; + } + + Type result = types.capture(t); + if (result != t && !readOnly) { // then t is a wildcard parameterized type + captureTypeCache.put(tree, result); + } + return result; + } +} diff -r deb1cda4dc79 -r dd96ac308ab8 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Jul 24 13:08:36 2015 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Jul 24 15:36:45 2015 -0700 @@ -35,7 +35,6 @@ import com.sun.tools.javac.comp.DeferredAttr.AttrMode; import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext; import com.sun.tools.javac.comp.DeferredAttr.DeferredType; -import com.sun.tools.javac.comp.Infer.InferenceContext; import com.sun.tools.javac.comp.Infer.FreeTypeListener; import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate; import com.sun.tools.javac.comp.Resolve.MethodResolutionDiagHelper.Template;