mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
8067767: type inference performance regression
Overhaul implememntation of inference incorporation Reviewed-by: vromero
This commit is contained in:
parent
54029caa26
commit
875bccb11e
11 changed files with 641 additions and 762 deletions
|
@ -175,8 +175,8 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visitUndetVar(UndetVar t, Locale locale) {
|
public String visitUndetVar(UndetVar t, Locale locale) {
|
||||||
if (t.inst != null) {
|
if (t.getInst() != null) {
|
||||||
return printAnnotations(t) + visit(t.inst, locale);
|
return printAnnotations(t) + visit(t.getInst(), locale);
|
||||||
} else {
|
} else {
|
||||||
return printAnnotations(t) + visit(t.qtype, locale) + "?";
|
return printAnnotations(t) + visit(t.qtype, locale) + "?";
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,19 +26,20 @@
|
||||||
package com.sun.tools.javac.code;
|
package com.sun.tools.javac.code;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import javax.lang.model.type.*;
|
import javax.lang.model.type.*;
|
||||||
|
|
||||||
import com.sun.tools.javac.code.Symbol.*;
|
import com.sun.tools.javac.code.Symbol.*;
|
||||||
import com.sun.tools.javac.code.TypeMetadata.Entry;
|
import com.sun.tools.javac.code.TypeMetadata.Entry;
|
||||||
|
import com.sun.tools.javac.comp.Infer.IncorporationAction;
|
||||||
import com.sun.tools.javac.util.*;
|
import com.sun.tools.javac.util.*;
|
||||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||||
|
|
||||||
import static com.sun.tools.javac.code.BoundKind.*;
|
import static com.sun.tools.javac.code.BoundKind.*;
|
||||||
import static com.sun.tools.javac.code.Flags.*;
|
import static com.sun.tools.javac.code.Flags.*;
|
||||||
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
||||||
|
@ -1826,17 +1827,15 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
*/
|
*/
|
||||||
public interface UndetVarListener {
|
public interface UndetVarListener {
|
||||||
/** called when some inference variable bounds (of given kinds ibs) change */
|
/** called when some inference variable bounds (of given kinds ibs) change */
|
||||||
void varChanged(UndetVar uv, Set<InferenceBound> ibs);
|
void varBoundChanged(UndetVar uv, InferenceBound ib, Type bound, boolean update);
|
||||||
|
/** called when the inferred type is set on some inference variable */
|
||||||
|
default void varInstantiated(UndetVar uv) { Assert.error(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inference variable bound kinds
|
* Inference variable bound kinds
|
||||||
*/
|
*/
|
||||||
public enum InferenceBound {
|
public enum InferenceBound {
|
||||||
/** upper bounds */
|
|
||||||
UPPER {
|
|
||||||
public InferenceBound complement() { return LOWER; }
|
|
||||||
},
|
|
||||||
/** lower bounds */
|
/** lower bounds */
|
||||||
LOWER {
|
LOWER {
|
||||||
public InferenceBound complement() { return UPPER; }
|
public InferenceBound complement() { return UPPER; }
|
||||||
|
@ -1844,16 +1843,38 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
/** equality constraints */
|
/** equality constraints */
|
||||||
EQ {
|
EQ {
|
||||||
public InferenceBound complement() { return EQ; }
|
public InferenceBound complement() { return EQ; }
|
||||||
|
},
|
||||||
|
/** upper bounds */
|
||||||
|
UPPER {
|
||||||
|
public InferenceBound complement() { return LOWER; }
|
||||||
};
|
};
|
||||||
|
|
||||||
public abstract InferenceBound complement();
|
public abstract InferenceBound complement();
|
||||||
|
|
||||||
|
public boolean lessThan(InferenceBound that) {
|
||||||
|
if (that == this) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
switch (that) {
|
||||||
|
case UPPER: return true;
|
||||||
|
case LOWER: return false;
|
||||||
|
case EQ: return (this != UPPER);
|
||||||
|
default:
|
||||||
|
Assert.error("Cannot get here!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** list of incorporation actions (used by the incorporation engine). */
|
||||||
|
public ArrayDeque<IncorporationAction> incorporationActions = new ArrayDeque<>();
|
||||||
|
|
||||||
/** inference variable bounds */
|
/** inference variable bounds */
|
||||||
protected Map<InferenceBound, List<Type>> bounds;
|
protected Map<InferenceBound, List<Type>> bounds;
|
||||||
|
|
||||||
/** inference variable's inferred type (set from Infer.java) */
|
/** inference variable's inferred type (set from Infer.java) */
|
||||||
public Type inst = null;
|
private Type inst = null;
|
||||||
|
|
||||||
/** number of declared (upper) bounds */
|
/** number of declared (upper) bounds */
|
||||||
public int declaredCount;
|
public int declaredCount;
|
||||||
|
@ -1866,15 +1887,20 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
return v.visitUndetVar(this, s);
|
return v.visitUndetVar(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UndetVar(TypeVar origin, Types types) {
|
public UndetVar(TypeVar origin, UndetVarListener listener, Types types) {
|
||||||
// This is a synthesized internal type, so we cannot annotate it.
|
// This is a synthesized internal type, so we cannot annotate it.
|
||||||
super(UNDETVAR, origin);
|
super(UNDETVAR, origin);
|
||||||
|
this.listener = listener;
|
||||||
bounds = new EnumMap<>(InferenceBound.class);
|
bounds = new EnumMap<>(InferenceBound.class);
|
||||||
List<Type> declaredBounds = types.getBounds(origin);
|
List<Type> declaredBounds = types.getBounds(origin);
|
||||||
declaredCount = declaredBounds.length();
|
declaredCount = declaredBounds.length();
|
||||||
bounds.put(InferenceBound.UPPER, declaredBounds);
|
bounds.put(InferenceBound.UPPER, List.nil());
|
||||||
bounds.put(InferenceBound.LOWER, List.<Type>nil());
|
bounds.put(InferenceBound.LOWER, List.nil());
|
||||||
bounds.put(InferenceBound.EQ, List.<Type>nil());
|
bounds.put(InferenceBound.EQ, List.nil());
|
||||||
|
for (Type t : declaredBounds.reverse()) {
|
||||||
|
//add bound works in reverse order
|
||||||
|
addBound(InferenceBound.UPPER, t, types, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||||
|
@ -1904,6 +1930,32 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new copy of this undet var.
|
||||||
|
*/
|
||||||
|
public UndetVar dup(Types types) {
|
||||||
|
UndetVar uv2 = new UndetVar((TypeVar)qtype, listener, types);
|
||||||
|
dupTo(uv2, types);
|
||||||
|
return uv2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps the contents of this undet var on another undet var.
|
||||||
|
*/
|
||||||
|
public void dupTo(UndetVar uv2, Types types) {
|
||||||
|
uv2.listener = null;
|
||||||
|
uv2.bounds.clear();
|
||||||
|
for (InferenceBound ib : InferenceBound.values()) {
|
||||||
|
uv2.bounds.put(ib, List.nil());
|
||||||
|
for (Type t : getBounds(ib)) {
|
||||||
|
uv2.addBound(ib, t, types, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uv2.inst = inst;
|
||||||
|
uv2.listener = listener;
|
||||||
|
uv2.incorporationActions = new ArrayDeque<>(incorporationActions);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UndetVar cloneWithMetadata(TypeMetadata md) {
|
public UndetVar cloneWithMetadata(TypeMetadata md) {
|
||||||
throw new AssertionError("Cannot add metadata to an UndetVar type");
|
throw new AssertionError("Cannot add metadata to an UndetVar type");
|
||||||
|
@ -1919,6 +1971,17 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
return (inst == null) ? this : inst.baseType();
|
return (inst == null) ? this : inst.baseType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type getInst() {
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInst(Type inst) {
|
||||||
|
this.inst = inst;
|
||||||
|
if (listener != null) {
|
||||||
|
listener.varInstantiated(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** get all bounds of a given kind */
|
/** get all bounds of a given kind */
|
||||||
public List<Type> getBounds(InferenceBound... ibs) {
|
public List<Type> getBounds(InferenceBound... ibs) {
|
||||||
ListBuffer<Type> buf = new ListBuffer<>();
|
ListBuffer<Type> buf = new ListBuffer<>();
|
||||||
|
@ -1952,13 +2015,14 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
protected void addBound(InferenceBound ib, Type bound, Types types, boolean update) {
|
protected void addBound(InferenceBound ib, Type bound, Types types, boolean update) {
|
||||||
Type bound2 = bound.map(toTypeVarMap).baseType();
|
Type bound2 = bound.map(toTypeVarMap).baseType();
|
||||||
List<Type> prevBounds = bounds.get(ib);
|
List<Type> prevBounds = bounds.get(ib);
|
||||||
|
if (bound == qtype) return;
|
||||||
for (Type b : prevBounds) {
|
for (Type b : prevBounds) {
|
||||||
//check for redundancy - use strict version of isSameType on tvars
|
//check for redundancy - use strict version of isSameType on tvars
|
||||||
//(as the standard version will lead to false positives w.r.t. clones ivars)
|
//(as the standard version will lead to false positives w.r.t. clones ivars)
|
||||||
if (types.isSameType(b, bound2, true) || bound == qtype) return;
|
if (types.isSameType(b, bound2, true)) return;
|
||||||
}
|
}
|
||||||
bounds.put(ib, prevBounds.prepend(bound2));
|
bounds.put(ib, prevBounds.prepend(bound2));
|
||||||
notifyChange(EnumSet.of(ib));
|
notifyBoundChange(ib, bound2, false);
|
||||||
}
|
}
|
||||||
//where
|
//where
|
||||||
TypeMapping<Void> toTypeVarMap = new TypeMapping<Void>() {
|
TypeMapping<Void> toTypeVarMap = new TypeMapping<Void>() {
|
||||||
|
@ -1970,16 +2034,14 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
|
|
||||||
/** replace types in all bounds - this might trigger listener notification */
|
/** replace types in all bounds - this might trigger listener notification */
|
||||||
public void substBounds(List<Type> from, List<Type> to, Types types) {
|
public void substBounds(List<Type> from, List<Type> to, Types types) {
|
||||||
List<Type> instVars = from.diff(to);
|
final ListBuffer<Pair<InferenceBound, Type>> boundsChanged = new ListBuffer<>();
|
||||||
//if set of instantiated ivars is empty, there's nothing to do!
|
|
||||||
if (instVars.isEmpty()) return;
|
|
||||||
final EnumSet<InferenceBound> boundsChanged = EnumSet.noneOf(InferenceBound.class);
|
|
||||||
UndetVarListener prevListener = listener;
|
UndetVarListener prevListener = listener;
|
||||||
try {
|
try {
|
||||||
//setup new listener for keeping track of changed bounds
|
//setup new listener for keeping track of changed bounds
|
||||||
listener = new UndetVarListener() {
|
listener = new UndetVarListener() {
|
||||||
public void varChanged(UndetVar uv, Set<InferenceBound> ibs) {
|
public void varBoundChanged(UndetVar uv, InferenceBound ib, Type t, boolean _ignored) {
|
||||||
boundsChanged.addAll(ibs);
|
Assert.check(uv == UndetVar.this);
|
||||||
|
boundsChanged.add(new Pair<>(ib, t));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) {
|
for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) {
|
||||||
|
@ -1989,7 +2051,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
ListBuffer<Type> deps = new ListBuffer<>();
|
ListBuffer<Type> deps = new ListBuffer<>();
|
||||||
//step 1 - re-add bounds that are not dependent on ivars
|
//step 1 - re-add bounds that are not dependent on ivars
|
||||||
for (Type t : prevBounds) {
|
for (Type t : prevBounds) {
|
||||||
if (!t.containsAny(instVars)) {
|
if (!t.containsAny(from)) {
|
||||||
newBounds.append(t);
|
newBounds.append(t);
|
||||||
} else {
|
} else {
|
||||||
deps.append(t);
|
deps.append(t);
|
||||||
|
@ -2004,15 +2066,15 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
listener = prevListener;
|
listener = prevListener;
|
||||||
if (!boundsChanged.isEmpty()) {
|
for (Pair<InferenceBound, Type> boundUpdate : boundsChanged) {
|
||||||
notifyChange(boundsChanged);
|
notifyBoundChange(boundUpdate.fst, boundUpdate.snd, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyChange(EnumSet<InferenceBound> ibs) {
|
private void notifyBoundChange(InferenceBound ib, Type bound, boolean update) {
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.varChanged(this, ibs);
|
listener.varBoundChanged(this, ib, bound, update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2029,10 +2091,10 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
*/
|
*/
|
||||||
public static class CapturedUndetVar extends UndetVar {
|
public static class CapturedUndetVar extends UndetVar {
|
||||||
|
|
||||||
public CapturedUndetVar(CapturedType origin, Types types) {
|
public CapturedUndetVar(CapturedType origin, UndetVarListener listener, Types types) {
|
||||||
super(origin, types);
|
super(origin, listener, types);
|
||||||
if (!origin.lower.hasTag(BOT)) {
|
if (!origin.lower.hasTag(BOT)) {
|
||||||
bounds.put(InferenceBound.LOWER, List.of(origin.lower));
|
addBound(InferenceBound.LOWER, origin.lower, types, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2051,6 +2113,12 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||||
public boolean isCaptured() {
|
public boolean isCaptured() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UndetVar dup(Types types) {
|
||||||
|
UndetVar uv2 = new CapturedUndetVar((CapturedType)qtype, listener, types);
|
||||||
|
dupTo(uv2, types);
|
||||||
|
return uv2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Represents NONE.
|
/** Represents NONE.
|
||||||
|
|
|
@ -3843,7 +3843,7 @@ public class Types {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer visitTypeVar(TypeVar t, Void ignored) {
|
public Integer visitTypeVar(TypeVar t, Void ignored) {
|
||||||
return System.identityHashCode(t.tsym);
|
return System.identityHashCode(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -39,6 +39,7 @@ import com.sun.tools.javac.code.Type.TypeVar;
|
||||||
import com.sun.tools.javac.code.Type.UndetVar;
|
import com.sun.tools.javac.code.Type.UndetVar;
|
||||||
import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
|
import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
|
||||||
import com.sun.tools.javac.code.Type.WildcardType;
|
import com.sun.tools.javac.code.Type.WildcardType;
|
||||||
|
import com.sun.tools.javac.code.TypeTag;
|
||||||
import com.sun.tools.javac.code.Types;
|
import com.sun.tools.javac.code.Types;
|
||||||
import com.sun.tools.javac.comp.Infer.FreeTypeListener;
|
import com.sun.tools.javac.comp.Infer.FreeTypeListener;
|
||||||
import com.sun.tools.javac.comp.Infer.GraphSolver;
|
import com.sun.tools.javac.comp.Infer.GraphSolver;
|
||||||
|
@ -52,8 +53,6 @@ import com.sun.tools.javac.util.List;
|
||||||
import com.sun.tools.javac.util.ListBuffer;
|
import com.sun.tools.javac.util.ListBuffer;
|
||||||
import com.sun.tools.javac.util.Warner;
|
import com.sun.tools.javac.util.Warner;
|
||||||
|
|
||||||
import static com.sun.tools.javac.code.TypeTag.UNDETVAR;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An inference context keeps track of the set of variables that are free
|
* An inference context keeps track of the set of variables that are free
|
||||||
* in the current context. It provides utility methods for opening/closing
|
* in the current context. It provides utility methods for opening/closing
|
||||||
|
@ -118,7 +117,7 @@ class InferenceContext {
|
||||||
List<Type> restvars() {
|
List<Type> restvars() {
|
||||||
return filterVars(new Filter<UndetVar>() {
|
return filterVars(new Filter<UndetVar>() {
|
||||||
public boolean accepts(UndetVar uv) {
|
public boolean accepts(UndetVar uv) {
|
||||||
return uv.inst == null;
|
return uv.getInst() == null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -130,7 +129,7 @@ class InferenceContext {
|
||||||
List<Type> instvars() {
|
List<Type> instvars() {
|
||||||
return filterVars(new Filter<UndetVar>() {
|
return filterVars(new Filter<UndetVar>() {
|
||||||
public boolean accepts(UndetVar uv) {
|
public boolean accepts(UndetVar uv) {
|
||||||
return uv.inst != null;
|
return uv.getInst() != null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -224,7 +223,7 @@ class InferenceContext {
|
||||||
ListBuffer<Type> buf = new ListBuffer<>();
|
ListBuffer<Type> buf = new ListBuffer<>();
|
||||||
for (Type t : undetvars) {
|
for (Type t : undetvars) {
|
||||||
UndetVar uv = (UndetVar)t;
|
UndetVar uv = (UndetVar)t;
|
||||||
buf.append(uv.inst != null ? uv.inst : uv.qtype);
|
buf.append(uv.getInst() != null ? uv.getInst() : uv.qtype);
|
||||||
}
|
}
|
||||||
return buf.toList();
|
return buf.toList();
|
||||||
}
|
}
|
||||||
|
@ -289,15 +288,7 @@ class InferenceContext {
|
||||||
List<Type> save() {
|
List<Type> save() {
|
||||||
ListBuffer<Type> buf = new ListBuffer<>();
|
ListBuffer<Type> buf = new ListBuffer<>();
|
||||||
for (Type t : undetvars) {
|
for (Type t : undetvars) {
|
||||||
UndetVar uv = (UndetVar)t;
|
buf.add(((UndetVar)t).dup(infer.types));
|
||||||
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();
|
return buf.toList();
|
||||||
}
|
}
|
||||||
|
@ -315,10 +306,7 @@ class InferenceContext {
|
||||||
UndetVar uv = (UndetVar)undetvars.head;
|
UndetVar uv = (UndetVar)undetvars.head;
|
||||||
UndetVar uv_saved = (UndetVar)saved_undet.head;
|
UndetVar uv_saved = (UndetVar)saved_undet.head;
|
||||||
if (uv.qtype == uv_saved.qtype) {
|
if (uv.qtype == uv_saved.qtype) {
|
||||||
for (InferenceBound ib : InferenceBound.values()) {
|
uv_saved.dupTo(uv, types);
|
||||||
uv.setBounds(ib, uv_saved.getBounds(ib));
|
|
||||||
}
|
|
||||||
uv.inst = uv_saved.inst;
|
|
||||||
undetvars = undetvars.tail;
|
undetvars = undetvars.tail;
|
||||||
saved_undet = saved_undet.tail;
|
saved_undet = saved_undet.tail;
|
||||||
newUndetVars.add(uv);
|
newUndetVars.add(uv);
|
||||||
|
@ -367,7 +355,7 @@ class InferenceContext {
|
||||||
ListBuffer<Type> minUndetVars = new ListBuffer<>();
|
ListBuffer<Type> minUndetVars = new ListBuffer<>();
|
||||||
for (Type minVar : minVars) {
|
for (Type minVar : minVars) {
|
||||||
UndetVar uv = (UndetVar)asUndetVar(minVar);
|
UndetVar uv = (UndetVar)asUndetVar(minVar);
|
||||||
UndetVar uv2 = new UndetVar((TypeVar)minVar, types);
|
UndetVar uv2 = new UndetVar((TypeVar)minVar, infer.incorporationEngine(), types);
|
||||||
for (InferenceBound ib : InferenceBound.values()) {
|
for (InferenceBound ib : InferenceBound.values()) {
|
||||||
List<Type> newBounds = uv.getBounds(ib).stream()
|
List<Type> newBounds = uv.getBounds(ib).stream()
|
||||||
.filter(b -> !redundantVars.contains(b))
|
.filter(b -> !redundantVars.contains(b))
|
||||||
|
@ -416,7 +404,7 @@ class InferenceContext {
|
||||||
Set<Type> deps = minMap.getOrDefault(t.qtype, new HashSet<>(Collections.singleton(t.qtype)));
|
Set<Type> deps = minMap.getOrDefault(t.qtype, new HashSet<>(Collections.singleton(t.qtype)));
|
||||||
for (Type b : t.getBounds(InferenceBound.values())) {
|
for (Type b : t.getBounds(InferenceBound.values())) {
|
||||||
Type undet = asUndetVar(b);
|
Type undet = asUndetVar(b);
|
||||||
if (!undet.hasTag(UNDETVAR)) {
|
if (!undet.hasTag(TypeTag.UNDETVAR)) {
|
||||||
visit(undet);
|
visit(undet);
|
||||||
} else if (isEquiv((UndetVar)undet, b)){
|
} else if (isEquiv((UndetVar)undet, b)){
|
||||||
deps.add(b);
|
deps.add(b);
|
||||||
|
@ -438,7 +426,7 @@ class InferenceContext {
|
||||||
@Override
|
@Override
|
||||||
public Void visitTypeVar(TypeVar t, Void aVoid) {
|
public Void visitTypeVar(TypeVar t, Void aVoid) {
|
||||||
Type undet = asUndetVar(t);
|
Type undet = asUndetVar(t);
|
||||||
if (undet.hasTag(UNDETVAR)) {
|
if (undet.hasTag(TypeTag.UNDETVAR)) {
|
||||||
visitUndetVar((UndetVar)undet, null);
|
visitUndetVar((UndetVar)undet, null);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -519,23 +507,23 @@ class InferenceContext {
|
||||||
/**
|
/**
|
||||||
* Apply a set of inference steps
|
* Apply a set of inference steps
|
||||||
*/
|
*/
|
||||||
private boolean solveBasic(EnumSet<InferenceStep> steps) {
|
private List<Type> solveBasic(EnumSet<InferenceStep> steps) {
|
||||||
return solveBasic(inferencevars, steps);
|
return solveBasic(inferencevars, steps);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean solveBasic(List<Type> varsToSolve, EnumSet<InferenceStep> steps) {
|
List<Type> solveBasic(List<Type> varsToSolve, EnumSet<InferenceStep> steps) {
|
||||||
boolean changed = false;
|
ListBuffer<Type> solvedVars = new ListBuffer<>();
|
||||||
for (Type t : varsToSolve.intersect(restvars())) {
|
for (Type t : varsToSolve.intersect(restvars())) {
|
||||||
UndetVar uv = (UndetVar)asUndetVar(t);
|
UndetVar uv = (UndetVar)asUndetVar(t);
|
||||||
for (InferenceStep step : steps) {
|
for (InferenceStep step : steps) {
|
||||||
if (step.accepts(uv, this)) {
|
if (step.accepts(uv, this)) {
|
||||||
uv.inst = step.solve(uv, this);
|
uv.setInst(step.solve(uv, this));
|
||||||
changed = true;
|
solvedVars.add(uv.qtype);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return changed;
|
return solvedVars.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -547,11 +535,11 @@ class InferenceContext {
|
||||||
*/
|
*/
|
||||||
public void solveLegacy(boolean partial, Warner warn, EnumSet<InferenceStep> steps) {
|
public void solveLegacy(boolean partial, Warner warn, EnumSet<InferenceStep> steps) {
|
||||||
while (true) {
|
while (true) {
|
||||||
boolean stuck = !solveBasic(steps);
|
List<Type> solvedVars = solveBasic(steps);
|
||||||
if (restvars().isEmpty() || partial) {
|
if (restvars().isEmpty() || partial) {
|
||||||
//all variables have been instantiated - exit
|
//all variables have been instantiated - exit
|
||||||
break;
|
break;
|
||||||
} else if (stuck) {
|
} else if (solvedVars.isEmpty()) {
|
||||||
//some variables could not be instantiated because of cycles in
|
//some variables could not be instantiated because of cycles in
|
||||||
//upper bounds - provide a (possibly recursive) default instantiation
|
//upper bounds - provide a (possibly recursive) default instantiation
|
||||||
infer.instantiateAsUninferredVars(restvars(), this);
|
infer.instantiateAsUninferredVars(restvars(), this);
|
||||||
|
@ -561,11 +549,11 @@ class InferenceContext {
|
||||||
//variables in remaining upper bounds and continue
|
//variables in remaining upper bounds and continue
|
||||||
for (Type t : undetvars) {
|
for (Type t : undetvars) {
|
||||||
UndetVar uv = (UndetVar)t;
|
UndetVar uv = (UndetVar)t;
|
||||||
uv.substBounds(inferenceVars(), instTypes(), types);
|
uv.substBounds(solvedVars, asInstTypes(solvedVars), types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
infer.checkWithinBounds(this, warn);
|
infer.doIncorporation(this, warn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1981,18 +1981,6 @@ compiler.misc.incompatible.upper.lower.bounds=\
|
||||||
upper bounds: {1}\n\
|
upper bounds: {1}\n\
|
||||||
lower bounds: {2}
|
lower bounds: {2}
|
||||||
|
|
||||||
# 0: type, 1: list of type, 2: list of type
|
|
||||||
compiler.misc.incompatible.upper.eq.bounds=\
|
|
||||||
inference variable {0} has incompatible bounds\n\
|
|
||||||
upper bounds: {1}\n\
|
|
||||||
equality constraints: {2}
|
|
||||||
|
|
||||||
# 0: type, 1: list of type, 2: list of type
|
|
||||||
compiler.misc.incompatible.eq.lower.bounds=\
|
|
||||||
inference variable {0} has incompatible bounds\n\
|
|
||||||
equality constraints: {1}\n\
|
|
||||||
lower bounds: {2}
|
|
||||||
|
|
||||||
# 0: type, 1: list of type, 2: list of type
|
# 0: type, 1: list of type, 2: list of type
|
||||||
compiler.misc.incompatible.eq.lower.bounds=\
|
compiler.misc.incompatible.eq.lower.bounds=\
|
||||||
inference variable {0} has incompatible bounds\n\
|
inference variable {0} has incompatible bounds\n\
|
||||||
|
|
|
@ -114,4 +114,3 @@ compiler.warn.file.from.future # warning for future mod
|
||||||
compiler.err.cant.inherit.from.anon # error for subclass of anonymous class
|
compiler.err.cant.inherit.from.anon # error for subclass of anonymous class
|
||||||
compiler.misc.bad.class.file # class file is malformed
|
compiler.misc.bad.class.file # class file is malformed
|
||||||
compiler.misc.bad.const.pool.entry # constant pool entry has wrong type
|
compiler.misc.bad.const.pool.entry # constant pool entry has wrong type
|
||||||
compiler.misc.incompatible.upper.eq.bounds
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
T7154127.java:20:49: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.bounds: Y, T7154127.B<U>,T7154127.D)
|
T7154127.java:20:49: compiler.err.prob.found.req: (compiler.misc.incompatible.upper.bounds: U, T7154127.B<Y>,T7154127.E)
|
||||||
1 error
|
1 error
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8067767
|
||||||
|
* @summary type inference performance regression
|
||||||
|
* @compile T8067767.java
|
||||||
|
*/
|
||||||
|
class T8067767 {
|
||||||
|
|
||||||
|
static class Pair<A, B> {
|
||||||
|
static <A, B> Pair<A, B> of(A a, B b) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class List<T> {
|
||||||
|
static <T> List<T> of(T... tx) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final List<Pair<String, String>> PAIRS = List.of(
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"),
|
||||||
|
Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"), Pair.of("a", "b"));
|
||||||
|
}
|
|
@ -1,2 +1,2 @@
|
||||||
TargetType28.java:20:32: compiler.err.prob.found.req: (compiler.misc.incompatible.eq.upper.bounds: X, R,java.lang.String, java.lang.Object,java.lang.Number)
|
TargetType28.java:20:32: compiler.err.prob.found.req: (compiler.misc.incompatible.eq.upper.bounds: X, java.lang.String, java.lang.Object,java.lang.Number)
|
||||||
1 error
|
1 error
|
||||||
|
|
|
@ -1304,7 +1304,7 @@ public class DPrinter {
|
||||||
for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
|
for (UndetVar.InferenceBound ib: UndetVar.InferenceBound.values())
|
||||||
printList("bounds." + ib, type.getBounds(ib));
|
printList("bounds." + ib, type.getBounds(ib));
|
||||||
printInt("declaredCount", type.declaredCount);
|
printInt("declaredCount", type.declaredCount);
|
||||||
printType("inst", type.inst, Details.SUMMARY);
|
printType("inst", type.getInst(), Details.SUMMARY);
|
||||||
return visitDelegatedType(type);
|
return visitDelegatedType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue