mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
7175433: Inference cleanup: add helper class to handle inference variables
Add class to handle inference variables instantiation and associated info Reviewed-by: jjg, dlsmith
This commit is contained in:
parent
07155682a1
commit
d4c5fca16a
5 changed files with 427 additions and 193 deletions
|
@ -40,6 +40,8 @@ import com.sun.tools.javac.code.Lint;
|
||||||
import com.sun.tools.javac.code.Lint.LintCategory;
|
import com.sun.tools.javac.code.Lint.LintCategory;
|
||||||
import com.sun.tools.javac.code.Type.*;
|
import com.sun.tools.javac.code.Type.*;
|
||||||
import com.sun.tools.javac.code.Symbol.*;
|
import com.sun.tools.javac.code.Symbol.*;
|
||||||
|
import com.sun.tools.javac.comp.Infer.InferenceContext;
|
||||||
|
import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
|
||||||
|
|
||||||
import static com.sun.tools.javac.code.Flags.*;
|
import static com.sun.tools.javac.code.Flags.*;
|
||||||
import static com.sun.tools.javac.code.Flags.ANNOTATION;
|
import static com.sun.tools.javac.code.Flags.ANNOTATION;
|
||||||
|
@ -429,6 +431,8 @@ public class Check {
|
||||||
* Obtain a warner for this check context
|
* Obtain a warner for this check context
|
||||||
*/
|
*/
|
||||||
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req);
|
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req);
|
||||||
|
|
||||||
|
public Infer.InferenceContext inferenceContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -455,6 +459,10 @@ public class Check {
|
||||||
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
|
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
|
||||||
return enclosingContext.checkWarner(pos, found, req);
|
return enclosingContext.checkWarner(pos, found, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Infer.InferenceContext inferenceContext() {
|
||||||
|
return enclosingContext.inferenceContext();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -471,6 +479,10 @@ public class Check {
|
||||||
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
|
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
|
||||||
return convertWarner(pos, found, req);
|
return convertWarner(pos, found, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InferenceContext inferenceContext() {
|
||||||
|
return infer.emptyContext;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Check that a given type is assignable to a given proto-type.
|
/** Check that a given type is assignable to a given proto-type.
|
||||||
|
@ -483,7 +495,16 @@ public class Check {
|
||||||
return checkType(pos, found, req, basicHandler);
|
return checkType(pos, found, req, basicHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type checkType(final DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) {
|
Type checkType(final DiagnosticPosition pos, final Type found, final Type req, final CheckContext checkContext) {
|
||||||
|
final Infer.InferenceContext inferenceContext = checkContext.inferenceContext();
|
||||||
|
if (inferenceContext.free(req)) {
|
||||||
|
inferenceContext.addFreeTypeListener(List.of(req), new FreeTypeListener() {
|
||||||
|
@Override
|
||||||
|
public void typesInferred(InferenceContext inferenceContext) {
|
||||||
|
checkType(pos, found, inferenceContext.asInstType(req, types), checkContext);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
if (req.tag == ERROR)
|
if (req.tag == ERROR)
|
||||||
return req;
|
return req;
|
||||||
if (req.tag == NONE)
|
if (req.tag == NONE)
|
||||||
|
|
|
@ -25,18 +25,21 @@
|
||||||
|
|
||||||
package com.sun.tools.javac.comp;
|
package com.sun.tools.javac.comp;
|
||||||
|
|
||||||
|
import com.sun.tools.javac.code.*;
|
||||||
|
import com.sun.tools.javac.code.Symbol.*;
|
||||||
|
import com.sun.tools.javac.code.Type.*;
|
||||||
|
import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
|
||||||
|
import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
|
||||||
import com.sun.tools.javac.tree.JCTree;
|
import com.sun.tools.javac.tree.JCTree;
|
||||||
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
|
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
|
||||||
import com.sun.tools.javac.tree.TreeInfo;
|
import com.sun.tools.javac.tree.TreeInfo;
|
||||||
import com.sun.tools.javac.util.*;
|
import com.sun.tools.javac.util.*;
|
||||||
import com.sun.tools.javac.util.List;
|
import com.sun.tools.javac.util.List;
|
||||||
import com.sun.tools.javac.code.*;
|
|
||||||
import com.sun.tools.javac.code.Type.*;
|
|
||||||
import com.sun.tools.javac.code.Symbol.*;
|
|
||||||
import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
|
|
||||||
import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
|
|
||||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static com.sun.tools.javac.code.TypeTags.*;
|
import static com.sun.tools.javac.code.TypeTags.*;
|
||||||
|
|
||||||
/** Helper class for type parameter inference, used by the attribution phase.
|
/** Helper class for type parameter inference, used by the attribution phase.
|
||||||
|
@ -76,41 +79,39 @@ public class Infer {
|
||||||
chk = Check.instance(context);
|
chk = Check.instance(context);
|
||||||
diags = JCDiagnostic.Factory.instance(context);
|
diags = JCDiagnostic.Factory.instance(context);
|
||||||
inferenceException = new InferenceException(diags);
|
inferenceException = new InferenceException(diags);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This exception class is design to store a list of diagnostics corresponding
|
||||||
|
* to inference errors that can arise during a method applicability check.
|
||||||
|
*/
|
||||||
public static class InferenceException extends InapplicableMethodException {
|
public static class InferenceException extends InapplicableMethodException {
|
||||||
private static final long serialVersionUID = 0;
|
private static final long serialVersionUID = 0;
|
||||||
|
|
||||||
|
List<JCDiagnostic> messages = List.nil();
|
||||||
|
|
||||||
InferenceException(JCDiagnostic.Factory diags) {
|
InferenceException(JCDiagnostic.Factory diags) {
|
||||||
super(diags);
|
super(diags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
InapplicableMethodException setMessage(JCDiagnostic diag) {
|
||||||
|
messages = messages.append(diag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JCDiagnostic getDiagnostic() {
|
||||||
|
return messages.head;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
messages = List.nil();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final InferenceException inferenceException;
|
private final InferenceException inferenceException;
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Auxiliary type values and classes
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
/** A mapping that turns type variables into undetermined type variables.
|
|
||||||
*/
|
|
||||||
List<Type> makeUndetvars(List<Type> tvars) {
|
|
||||||
List<Type> undetvars = Type.map(tvars, fromTypeVarFun);
|
|
||||||
for (Type t : undetvars) {
|
|
||||||
UndetVar uv = (UndetVar)t;
|
|
||||||
uv.hibounds = types.getBounds((TypeVar)uv.qtype);
|
|
||||||
}
|
|
||||||
return undetvars;
|
|
||||||
}
|
|
||||||
//where
|
|
||||||
Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") {
|
|
||||||
public Type apply(Type t) {
|
|
||||||
if (t.tag == TYPEVAR) return new UndetVar(t);
|
|
||||||
else return t.map(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Mini/Maximization of UndetVars
|
* Mini/Maximization of UndetVars
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
@ -118,8 +119,8 @@ public class Infer {
|
||||||
/** Instantiate undetermined type variable to its minimal upper bound.
|
/** Instantiate undetermined type variable to its minimal upper bound.
|
||||||
* Throw a NoInstanceException if this not possible.
|
* Throw a NoInstanceException if this not possible.
|
||||||
*/
|
*/
|
||||||
void maximizeInst(UndetVar that, Warner warn) throws InferenceException {
|
void maximizeInst(UndetVar that, Warner warn) throws InferenceException {
|
||||||
List<Type> hibounds = Type.filter(that.hibounds, errorFilter);
|
List<Type> hibounds = Type.filter(that.hibounds, boundFilter);
|
||||||
if (that.eq.isEmpty()) {
|
if (that.eq.isEmpty()) {
|
||||||
if (hibounds.isEmpty())
|
if (hibounds.isEmpty())
|
||||||
that.inst = syms.objectType;
|
that.inst = syms.objectType;
|
||||||
|
@ -137,10 +138,10 @@ public class Infer {
|
||||||
that.qtype, hibounds);
|
that.qtype, hibounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Filter<Type> errorFilter = new Filter<Type>() {
|
private Filter<Type> boundFilter = new Filter<Type>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accepts(Type t) {
|
public boolean accepts(Type t) {
|
||||||
return !t.isErroneous();
|
return !t.isErroneous() && t.tag != BOT;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,11 +149,12 @@ public class Infer {
|
||||||
* Throw a NoInstanceException if this not possible.
|
* Throw a NoInstanceException if this not possible.
|
||||||
*/
|
*/
|
||||||
void minimizeInst(UndetVar that, Warner warn) throws InferenceException {
|
void minimizeInst(UndetVar that, Warner warn) throws InferenceException {
|
||||||
List<Type> lobounds = Type.filter(that.lobounds, errorFilter);
|
List<Type> lobounds = Type.filter(that.lobounds, boundFilter);
|
||||||
if (that.eq.isEmpty()) {
|
if (that.eq.isEmpty()) {
|
||||||
if (lobounds.isEmpty())
|
if (lobounds.isEmpty()) {
|
||||||
that.inst = syms.botType;
|
//do nothing - the inference variable is under-constrained
|
||||||
else if (lobounds.tail.isEmpty())
|
return;
|
||||||
|
} else if (lobounds.tail.isEmpty())
|
||||||
that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head;
|
that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head;
|
||||||
else {
|
else {
|
||||||
that.inst = types.lub(lobounds);
|
that.inst = types.lub(lobounds);
|
||||||
|
@ -166,90 +168,70 @@ public class Infer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type asUndetType(Type t, List<Type> undetvars) {
|
|
||||||
return types.subst(t, inferenceVars(undetvars), undetvars);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Type> inferenceVars(List<Type> undetvars) {
|
|
||||||
ListBuffer<Type> tvars = ListBuffer.lb();
|
|
||||||
for (Type uv : undetvars) {
|
|
||||||
tvars.append(((UndetVar)uv).qtype);
|
|
||||||
}
|
|
||||||
return tvars.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Exported Methods
|
* Exported Methods
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/** Try to instantiate expression type `that' to given type `to'.
|
/**
|
||||||
* If a maximal instantiation exists which makes this type
|
* Instantiate uninferred inference variables (JLS 15.12.2.8). First
|
||||||
* a subtype of type `to', return the instantiated type.
|
* if the method return type is non-void, we derive constraints from the
|
||||||
* If no instantiation exists, or if several incomparable
|
* expected type - then we use declared bound well-formedness to derive additional
|
||||||
* best instantiations exist throw a NoInstanceException.
|
* constraints. If no instantiation exists, or if several incomparable
|
||||||
|
* best instantiations exist throw a NoInstanceException.
|
||||||
*/
|
*/
|
||||||
public List<Type> instantiateUninferred(DiagnosticPosition pos,
|
public void instantiateUninferred(DiagnosticPosition pos,
|
||||||
List<Type> undetvars,
|
InferenceContext inferenceContext,
|
||||||
List<Type> tvars,
|
MethodType mtype,
|
||||||
MethodType mtype,
|
Attr.ResultInfo resultInfo,
|
||||||
Attr.ResultInfo resultInfo,
|
Warner warn) throws InferenceException {
|
||||||
Warner warn) throws InferenceException {
|
|
||||||
Type to = resultInfo.pt;
|
Type to = resultInfo.pt;
|
||||||
if (to.tag == NONE) {
|
if (to.tag == NONE) {
|
||||||
to = mtype.getReturnType().tag <= VOID ?
|
to = mtype.getReturnType().tag <= VOID ?
|
||||||
mtype.getReturnType() : syms.objectType;
|
mtype.getReturnType() : syms.objectType;
|
||||||
}
|
}
|
||||||
Type qtype1 = types.subst(mtype.getReturnType(), tvars, undetvars);
|
Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types);
|
||||||
if (!types.isSubtype(qtype1,
|
if (!types.isSubtype(qtype1,
|
||||||
qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) {
|
qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) {
|
||||||
throw inferenceException
|
throw inferenceException
|
||||||
.setMessage("infer.no.conforming.instance.exists",
|
.setMessage("infer.no.conforming.instance.exists",
|
||||||
tvars, mtype.getReturnType(), to);
|
inferenceContext.restvars(), mtype.getReturnType(), to);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Type> insttypes;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
boolean stuck = true;
|
boolean stuck = true;
|
||||||
insttypes = List.nil();
|
for (Type t : inferenceContext.undetvars) {
|
||||||
for (Type t : undetvars) {
|
|
||||||
UndetVar uv = (UndetVar)t;
|
UndetVar uv = (UndetVar)t;
|
||||||
if (uv.inst == null && (uv.eq.nonEmpty() || !Type.containsAny(uv.hibounds, tvars))) {
|
if (uv.inst == null && (uv.eq.nonEmpty() || !inferenceContext.free(uv.hibounds))) {
|
||||||
maximizeInst((UndetVar)t, warn);
|
maximizeInst((UndetVar)t, warn);
|
||||||
stuck = false;
|
stuck = false;
|
||||||
}
|
}
|
||||||
insttypes = insttypes.append(uv.inst == null ? uv.qtype : uv.inst);
|
|
||||||
}
|
}
|
||||||
if (!Type.containsAny(insttypes, tvars)) {
|
if (inferenceContext.restvars().isEmpty()) {
|
||||||
//all variables have been instantiated - exit
|
//all variables have been instantiated - exit
|
||||||
break;
|
break;
|
||||||
} else if (stuck) {
|
} else if (stuck) {
|
||||||
//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
|
||||||
insttypes = types.subst(insttypes,
|
instantiateAsUninferredVars(inferenceContext);
|
||||||
tvars,
|
|
||||||
instantiateAsUninferredVars(undetvars, tvars));
|
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
//some variables have been instantiated - replace newly instantiated
|
//some variables have been instantiated - replace newly instantiated
|
||||||
//variables in remaining upper bounds and continue
|
//variables in remaining upper bounds and continue
|
||||||
for (Type t : undetvars) {
|
for (Type t : inferenceContext.undetvars) {
|
||||||
UndetVar uv = (UndetVar)t;
|
UndetVar uv = (UndetVar)t;
|
||||||
uv.hibounds = types.subst(uv.hibounds, tvars, insttypes);
|
uv.hibounds = inferenceContext.asInstTypes(uv.hibounds, types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return insttypes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Infer cyclic inference variables as described in 15.12.2.8.
|
* Infer cyclic inference variables as described in 15.12.2.8.
|
||||||
*/
|
*/
|
||||||
private List<Type> instantiateAsUninferredVars(List<Type> undetvars, List<Type> tvars) {
|
private void instantiateAsUninferredVars(InferenceContext inferenceContext) {
|
||||||
Assert.check(undetvars.length() == tvars.length());
|
|
||||||
ListBuffer<Type> insttypes = ListBuffer.lb();
|
|
||||||
ListBuffer<Type> todo = ListBuffer.lb();
|
ListBuffer<Type> todo = ListBuffer.lb();
|
||||||
//step 1 - create fresh tvars
|
//step 1 - create fresh tvars
|
||||||
for (Type t : undetvars) {
|
for (Type t : inferenceContext.undetvars) {
|
||||||
UndetVar uv = (UndetVar)t;
|
UndetVar uv = (UndetVar)t;
|
||||||
if (uv.inst == null) {
|
if (uv.inst == null) {
|
||||||
TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
|
TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
|
||||||
|
@ -257,25 +239,23 @@ public class Infer {
|
||||||
todo.append(uv);
|
todo.append(uv);
|
||||||
uv.inst = fresh_tvar.type;
|
uv.inst = fresh_tvar.type;
|
||||||
}
|
}
|
||||||
insttypes.append(uv.inst);
|
|
||||||
}
|
}
|
||||||
//step 2 - replace fresh tvars in their bounds
|
//step 2 - replace fresh tvars in their bounds
|
||||||
List<Type> formals = tvars;
|
List<Type> formals = inferenceContext.inferenceVars();
|
||||||
for (Type t : todo) {
|
for (Type t : todo) {
|
||||||
UndetVar uv = (UndetVar)t;
|
UndetVar uv = (UndetVar)t;
|
||||||
TypeVar ct = (TypeVar)uv.inst;
|
TypeVar ct = (TypeVar)uv.inst;
|
||||||
ct.bound = types.glb(types.subst(types.getBounds(ct), tvars, insttypes.toList()));
|
ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types));
|
||||||
if (ct.bound.isErroneous()) {
|
if (ct.bound.isErroneous()) {
|
||||||
//report inference error if glb fails
|
//report inference error if glb fails
|
||||||
reportBoundError(uv, BoundErrorKind.BAD_UPPER);
|
reportBoundError(uv, BoundErrorKind.BAD_UPPER);
|
||||||
}
|
}
|
||||||
formals = formals.tail;
|
formals = formals.tail;
|
||||||
}
|
}
|
||||||
return insttypes.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Instantiate method type `mt' by finding instantiations of
|
/** Instantiate a generic method type by finding instantiations for all its
|
||||||
* `tvars' so that method can be applied to `argtypes'.
|
* inference variables so that it can be applied to a given argument type list.
|
||||||
*/
|
*/
|
||||||
public Type instantiateMethod(Env<AttrContext> env,
|
public Type instantiateMethod(Env<AttrContext> env,
|
||||||
List<Type> tvars,
|
List<Type> tvars,
|
||||||
|
@ -287,83 +267,61 @@ public class Infer {
|
||||||
boolean useVarargs,
|
boolean useVarargs,
|
||||||
Warner warn) throws InferenceException {
|
Warner warn) throws InferenceException {
|
||||||
//-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
|
//-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
|
||||||
List<Type> undetvars = makeUndetvars(tvars);
|
final InferenceContext inferenceContext = new InferenceContext(tvars, types);
|
||||||
|
inferenceException.clear();
|
||||||
|
|
||||||
List<Type> capturedArgs =
|
try {
|
||||||
rs.checkRawArgumentsAcceptable(env, undetvars, argtypes, mt.getParameterTypes(),
|
rs.checkRawArgumentsAcceptable(env, inferenceContext, argtypes, mt.getParameterTypes(),
|
||||||
allowBoxing, useVarargs, warn, new InferenceCheckHandler(undetvars));
|
allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext));
|
||||||
|
|
||||||
// minimize as yet undetermined type variables
|
// minimize as yet undetermined type variables
|
||||||
for (Type t : undetvars)
|
for (Type t : inferenceContext.undetvars) {
|
||||||
minimizeInst((UndetVar) t, warn);
|
minimizeInst((UndetVar)t, warn);
|
||||||
|
|
||||||
/** Type variables instantiated to bottom */
|
|
||||||
ListBuffer<Type> restvars = new ListBuffer<Type>();
|
|
||||||
|
|
||||||
/** Undet vars instantiated to bottom */
|
|
||||||
final ListBuffer<Type> restundet = new ListBuffer<Type>();
|
|
||||||
|
|
||||||
/** Instantiated types or TypeVars if under-constrained */
|
|
||||||
ListBuffer<Type> insttypes = new ListBuffer<Type>();
|
|
||||||
|
|
||||||
/** Instantiated types or UndetVars if under-constrained */
|
|
||||||
ListBuffer<Type> undettypes = new ListBuffer<Type>();
|
|
||||||
|
|
||||||
for (Type t : undetvars) {
|
|
||||||
UndetVar uv = (UndetVar)t;
|
|
||||||
if (uv.inst.tag == BOT) {
|
|
||||||
restvars.append(uv.qtype);
|
|
||||||
restundet.append(uv);
|
|
||||||
insttypes.append(uv.qtype);
|
|
||||||
undettypes.append(uv);
|
|
||||||
uv.inst = null;
|
|
||||||
} else {
|
|
||||||
insttypes.append(uv.inst);
|
|
||||||
undettypes.append(uv.inst);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
checkWithinBounds(tvars, undetvars, insttypes.toList(), warn);
|
|
||||||
|
|
||||||
mt = (MethodType)types.subst(mt, tvars, insttypes.toList());
|
checkWithinBounds(inferenceContext, warn);
|
||||||
|
|
||||||
if (!restvars.isEmpty() && resultInfo != null) {
|
mt = (MethodType)inferenceContext.asInstType(mt, types);
|
||||||
List<Type> restInferred =
|
|
||||||
instantiateUninferred(env.tree.pos(), restundet.toList(), restvars.toList(), mt, resultInfo, warn);
|
List<Type> restvars = inferenceContext.restvars();
|
||||||
checkWithinBounds(tvars, undetvars,
|
|
||||||
types.subst(insttypes.toList(), restvars.toList(), restInferred), warn);
|
if (!restvars.isEmpty()) {
|
||||||
mt = (MethodType)types.subst(mt, restvars.toList(), restInferred);
|
if (resultInfo != null) {
|
||||||
if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
|
instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn);
|
||||||
log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
|
checkWithinBounds(inferenceContext, warn);
|
||||||
|
mt = (MethodType)inferenceContext.asInstType(mt, types);
|
||||||
|
if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) {
|
||||||
|
log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (restvars.isEmpty() || resultInfo != null) {
|
// return instantiated version of method type
|
||||||
// check that actuals conform to inferred formals
|
return mt;
|
||||||
checkArgumentsAcceptable(env, capturedArgs, mt.getParameterTypes(), allowBoxing, useVarargs, warn);
|
} finally {
|
||||||
|
inferenceContext.notifyChange(types);
|
||||||
}
|
}
|
||||||
// return instantiated version of method type
|
|
||||||
return mt;
|
|
||||||
}
|
}
|
||||||
//where
|
//where
|
||||||
|
|
||||||
/** inference check handler **/
|
/** inference check handler **/
|
||||||
class InferenceCheckHandler implements Resolve.MethodCheckHandler {
|
class InferenceCheckHandler implements Resolve.MethodCheckHandler {
|
||||||
|
|
||||||
List<Type> undetvars;
|
InferenceContext inferenceContext;
|
||||||
|
|
||||||
public InferenceCheckHandler(List<Type> undetvars) {
|
public InferenceCheckHandler(InferenceContext inferenceContext) {
|
||||||
this.undetvars = undetvars;
|
this.inferenceContext = inferenceContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InapplicableMethodException arityMismatch() {
|
public InapplicableMethodException arityMismatch() {
|
||||||
return inferenceException.setMessage("infer.arg.length.mismatch", inferenceVars(undetvars));
|
return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars());
|
||||||
}
|
}
|
||||||
public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
|
public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) {
|
||||||
String key = varargs ?
|
String key = varargs ?
|
||||||
"infer.varargs.argument.mismatch" :
|
"infer.varargs.argument.mismatch" :
|
||||||
"infer.no.conforming.assignment.exists";
|
"infer.no.conforming.assignment.exists";
|
||||||
return inferenceException.setMessage(key,
|
return inferenceException.setMessage(key,
|
||||||
inferenceVars(undetvars), details);
|
inferenceContext.inferenceVars(), details);
|
||||||
}
|
}
|
||||||
public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
|
public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) {
|
||||||
return inferenceException.setMessage("inaccessible.varargs.type",
|
return inferenceException.setMessage("inaccessible.varargs.type",
|
||||||
|
@ -371,51 +329,37 @@ public class Infer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkArgumentsAcceptable(Env<AttrContext> env, List<Type> actuals, List<Type> formals,
|
|
||||||
boolean allowBoxing, boolean useVarargs, Warner warn) {
|
|
||||||
try {
|
|
||||||
rs.checkRawArgumentsAcceptable(env, actuals, formals,
|
|
||||||
allowBoxing, useVarargs, warn);
|
|
||||||
}
|
|
||||||
catch (InapplicableMethodException ex) {
|
|
||||||
// inferred method is not applicable
|
|
||||||
throw inferenceException.setMessage(ex.getDiagnostic());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** check that type parameters are within their bounds.
|
/** check that type parameters are within their bounds.
|
||||||
*/
|
*/
|
||||||
void checkWithinBounds(List<Type> tvars,
|
void checkWithinBounds(InferenceContext inferenceContext,
|
||||||
List<Type> undetvars,
|
|
||||||
List<Type> arguments,
|
|
||||||
Warner warn)
|
Warner warn)
|
||||||
throws InferenceException {
|
throws InferenceException {
|
||||||
List<Type> args = arguments;
|
List<Type> tvars = inferenceContext.inferenceVars();
|
||||||
for (Type t : undetvars) {
|
for (Type t : inferenceContext.undetvars) {
|
||||||
UndetVar uv = (UndetVar)t;
|
UndetVar uv = (UndetVar)t;
|
||||||
uv.hibounds = types.subst(uv.hibounds, tvars, arguments);
|
uv.hibounds = inferenceContext.asInstTypes(uv.hibounds, types);
|
||||||
uv.lobounds = types.subst(uv.lobounds, tvars, arguments);
|
uv.lobounds = inferenceContext.asInstTypes(uv.lobounds, types);
|
||||||
uv.eq = types.subst(uv.eq, tvars, arguments);
|
uv.eq = inferenceContext.asInstTypes(uv.eq, types);
|
||||||
checkCompatibleUpperBounds(uv, tvars);
|
checkCompatibleUpperBounds(uv, inferenceContext.inferenceVars());
|
||||||
if (args.head.tag != TYPEVAR || !args.head.containsAny(tvars)) {
|
if (!inferenceContext.restvars().contains(tvars.head)) {
|
||||||
Type inst = args.head;
|
Type inst = inferenceContext.asInstType(t, types);
|
||||||
for (Type u : uv.hibounds) {
|
for (Type u : uv.hibounds) {
|
||||||
if (!types.isSubtypeUnchecked(inst, types.subst(u, tvars, undetvars), warn)) {
|
if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u, types), warn)) {
|
||||||
reportBoundError(uv, BoundErrorKind.UPPER);
|
reportBoundError(uv, BoundErrorKind.UPPER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Type l : uv.lobounds) {
|
for (Type l : uv.lobounds) {
|
||||||
if (!types.isSubtypeUnchecked(types.subst(l, tvars, undetvars), inst, warn)) {
|
if (!types.isSubtypeUnchecked(inferenceContext.asFree(l, types), inst, warn)) {
|
||||||
reportBoundError(uv, BoundErrorKind.LOWER);
|
reportBoundError(uv, BoundErrorKind.LOWER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Type e : uv.eq) {
|
for (Type e : uv.eq) {
|
||||||
if (!types.isSameType(inst, types.subst(e, tvars, undetvars))) {
|
if (!types.isSameType(inst, inferenceContext.asFree(e, types))) {
|
||||||
reportBoundError(uv, BoundErrorKind.EQ);
|
reportBoundError(uv, BoundErrorKind.EQ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args = args.tail;
|
tvars = tvars.tail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,7 +367,7 @@ public class Infer {
|
||||||
// VGJ: sort of inlined maximizeInst() below. Adding
|
// VGJ: sort of inlined maximizeInst() below. Adding
|
||||||
// bounds can cause lobounds that are above hibounds.
|
// bounds can cause lobounds that are above hibounds.
|
||||||
ListBuffer<Type> hiboundsNoVars = ListBuffer.lb();
|
ListBuffer<Type> hiboundsNoVars = ListBuffer.lb();
|
||||||
for (Type t : Type.filter(uv.hibounds, errorFilter)) {
|
for (Type t : Type.filter(uv.hibounds, boundFilter)) {
|
||||||
if (!t.containsAny(tvars)) {
|
if (!t.containsAny(tvars)) {
|
||||||
hiboundsNoVars.append(t);
|
hiboundsNoVars.append(t);
|
||||||
}
|
}
|
||||||
|
@ -531,4 +475,199 @@ public class Infer {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping that turns inference variables into undet vars
|
||||||
|
* (used by inference context)
|
||||||
|
*/
|
||||||
|
static Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") {
|
||||||
|
public Type apply(Type t) {
|
||||||
|
if (t.tag == TYPEVAR) return new UndetVar(t);
|
||||||
|
else return t.map(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
static class InferenceContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single-method-interface for defining inference callbacks. Certain actions
|
||||||
|
* (i.e. subtyping checks) might need to be redone after all inference variables
|
||||||
|
* have been fixed.
|
||||||
|
*/
|
||||||
|
interface FreeTypeListener {
|
||||||
|
void typesInferred(InferenceContext inferenceContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** list of inference vars as undet vars */
|
||||||
|
List<Type> undetvars;
|
||||||
|
|
||||||
|
/** list of inference vars in this context */
|
||||||
|
List<Type> inferencevars;
|
||||||
|
|
||||||
|
java.util.Map<FreeTypeListener, List<Type>> freeTypeListeners =
|
||||||
|
new java.util.HashMap<FreeTypeListener, List<Type>>();
|
||||||
|
|
||||||
|
List<FreeTypeListener> freetypeListeners = List.nil();
|
||||||
|
|
||||||
|
public InferenceContext(List<Type> inferencevars, Types types) {
|
||||||
|
this.undetvars = Type.map(inferencevars, fromTypeVarFun);
|
||||||
|
this.inferencevars = inferencevars;
|
||||||
|
for (Type t : this.undetvars) {
|
||||||
|
UndetVar uv = (UndetVar)t;
|
||||||
|
uv.hibounds = types.getBounds((TypeVar)uv.qtype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the list of free variables (as type-variables) in this
|
||||||
|
* inference context
|
||||||
|
*/
|
||||||
|
List<Type> inferenceVars() {
|
||||||
|
return inferencevars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the list of uninstantiated variables (as type-variables) in this
|
||||||
|
* inference context (usually called after instantiate())
|
||||||
|
*/
|
||||||
|
List<Type> restvars() {
|
||||||
|
List<Type> undetvars = this.undetvars;
|
||||||
|
ListBuffer<Type> restvars = ListBuffer.lb();
|
||||||
|
for (Type t : instTypes()) {
|
||||||
|
UndetVar uv = (UndetVar)undetvars.head;
|
||||||
|
if (uv.qtype == t) {
|
||||||
|
restvars.append(t);
|
||||||
|
}
|
||||||
|
undetvars = undetvars.tail;
|
||||||
|
}
|
||||||
|
return restvars.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is this type free?
|
||||||
|
*/
|
||||||
|
final boolean free(Type t) {
|
||||||
|
return t.containsAny(inferencevars);
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean free(List<Type> ts) {
|
||||||
|
for (Type t : ts) {
|
||||||
|
if (free(t)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of free variables in a given type
|
||||||
|
*/
|
||||||
|
final List<Type> freeVarsIn(Type t) {
|
||||||
|
ListBuffer<Type> buf = ListBuffer.lb();
|
||||||
|
for (Type iv : inferenceVars()) {
|
||||||
|
if (t.contains(iv)) {
|
||||||
|
buf.add(iv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Type> freeVarsIn(List<Type> ts) {
|
||||||
|
ListBuffer<Type> buf = ListBuffer.lb();
|
||||||
|
for (Type t : ts) {
|
||||||
|
buf.appendList(freeVarsIn(t));
|
||||||
|
}
|
||||||
|
ListBuffer<Type> buf2 = ListBuffer.lb();
|
||||||
|
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 asFree(Type t, Types types) {
|
||||||
|
return types.subst(t, inferencevars, undetvars);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Type> asFree(List<Type> ts, Types types) {
|
||||||
|
ListBuffer<Type> buf = ListBuffer.lb();
|
||||||
|
for (Type t : ts) {
|
||||||
|
buf.append(asFree(t, types));
|
||||||
|
}
|
||||||
|
return buf.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Type> instTypes() {
|
||||||
|
ListBuffer<Type> buf = ListBuffer.lb();
|
||||||
|
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, Types types) {
|
||||||
|
return types.subst(t, inferencevars, instTypes());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Type> asInstTypes(List<Type> ts, Types types) {
|
||||||
|
ListBuffer<Type> buf = ListBuffer.lb();
|
||||||
|
for (Type t : ts) {
|
||||||
|
buf.append(asInstType(t, types));
|
||||||
|
}
|
||||||
|
return buf.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add custom hook for performing post-inference action
|
||||||
|
*/
|
||||||
|
void addFreeTypeListener(List<Type> types, FreeTypeListener ftl) {
|
||||||
|
freeTypeListeners.put(ftl, freeVarsIn(types));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the inference context as complete and trigger evaluation
|
||||||
|
* of all deferred checks.
|
||||||
|
*/
|
||||||
|
void notifyChange(Types types) {
|
||||||
|
InferenceException thrownEx = null;
|
||||||
|
for (Map.Entry<FreeTypeListener, List<Type>> entry :
|
||||||
|
new HashMap<FreeTypeListener, List<Type>>(freeTypeListeners).entrySet()) {
|
||||||
|
if (!Type.containsAny(entry.getValue(), restvars())) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), types);
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ import com.sun.tools.javac.code.Type.*;
|
||||||
import com.sun.tools.javac.code.Symbol.*;
|
import com.sun.tools.javac.code.Symbol.*;
|
||||||
import com.sun.tools.javac.comp.Attr.ResultInfo;
|
import com.sun.tools.javac.comp.Attr.ResultInfo;
|
||||||
import com.sun.tools.javac.comp.Check.CheckContext;
|
import com.sun.tools.javac.comp.Check.CheckContext;
|
||||||
|
import com.sun.tools.javac.comp.Infer.InferenceContext;
|
||||||
|
import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
|
||||||
import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
|
import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate;
|
||||||
import com.sun.tools.javac.jvm.*;
|
import com.sun.tools.javac.jvm.*;
|
||||||
import com.sun.tools.javac.tree.*;
|
import com.sun.tools.javac.tree.*;
|
||||||
|
@ -586,7 +588,7 @@ public class Resolve {
|
||||||
boolean allowBoxing,
|
boolean allowBoxing,
|
||||||
boolean useVarargs,
|
boolean useVarargs,
|
||||||
Warner warn) {
|
Warner warn) {
|
||||||
checkRawArgumentsAcceptable(env, List.<Type>nil(), argtypes, formals,
|
checkRawArgumentsAcceptable(env, infer.emptyContext, argtypes, formals,
|
||||||
allowBoxing, useVarargs, warn, resolveHandler);
|
allowBoxing, useVarargs, warn, resolveHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,8 +608,8 @@ public class Resolve {
|
||||||
*
|
*
|
||||||
* A method check handler (see above) is used in order to report errors.
|
* A method check handler (see above) is used in order to report errors.
|
||||||
*/
|
*/
|
||||||
List<Type> checkRawArgumentsAcceptable(Env<AttrContext> env,
|
void checkRawArgumentsAcceptable(final Env<AttrContext> env,
|
||||||
List<Type> undetvars,
|
final Infer.InferenceContext inferenceContext,
|
||||||
List<Type> argtypes,
|
List<Type> argtypes,
|
||||||
List<Type> formals,
|
List<Type> formals,
|
||||||
boolean allowBoxing,
|
boolean allowBoxing,
|
||||||
|
@ -623,7 +625,7 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (argtypes.nonEmpty() && formals.head != varargsFormal) {
|
while (argtypes.nonEmpty() && formals.head != varargsFormal) {
|
||||||
ResultInfo resultInfo = methodCheckResult(formals.head, allowBoxing, false, undetvars, handler, warn);
|
ResultInfo resultInfo = methodCheckResult(formals.head, allowBoxing, false, inferenceContext, handler, warn);
|
||||||
checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
|
checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
|
||||||
argtypes = argtypes.tail;
|
argtypes = argtypes.tail;
|
||||||
formals = formals.tail;
|
formals = formals.tail;
|
||||||
|
@ -638,17 +640,29 @@ public class Resolve {
|
||||||
//the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
|
//the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5)
|
||||||
Type elt = types.elemtype(varargsFormal);
|
Type elt = types.elemtype(varargsFormal);
|
||||||
while (argtypes.nonEmpty()) {
|
while (argtypes.nonEmpty()) {
|
||||||
ResultInfo resultInfo = methodCheckResult(elt, allowBoxing, true, undetvars, handler, warn);
|
ResultInfo resultInfo = methodCheckResult(elt, allowBoxing, true, inferenceContext, handler, warn);
|
||||||
checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
|
checkedArgs.append(resultInfo.check(env.tree.pos(), argtypes.head));
|
||||||
argtypes = argtypes.tail;
|
argtypes = argtypes.tail;
|
||||||
}
|
}
|
||||||
//check varargs element type accessibility
|
//check varargs element type accessibility
|
||||||
if (undetvars.isEmpty() && !isAccessible(env, elt)) {
|
varargsAccessible(env, elt, handler, inferenceContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void varargsAccessible(final Env<AttrContext> env, final Type t, final Resolve.MethodCheckHandler handler, final InferenceContext inferenceContext) {
|
||||||
|
if (inferenceContext.free(t)) {
|
||||||
|
inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() {
|
||||||
|
@Override
|
||||||
|
public void typesInferred(InferenceContext inferenceContext) {
|
||||||
|
varargsAccessible(env, inferenceContext.asInstType(t, types), handler, inferenceContext);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!isAccessible(env, t)) {
|
||||||
Symbol location = env.enclClass.sym;
|
Symbol location = env.enclClass.sym;
|
||||||
throw handler.inaccessibleVarargs(location, elt);
|
throw handler.inaccessibleVarargs(location, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return checkedArgs.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -659,13 +673,13 @@ public class Resolve {
|
||||||
|
|
||||||
MethodCheckHandler handler;
|
MethodCheckHandler handler;
|
||||||
boolean useVarargs;
|
boolean useVarargs;
|
||||||
List<Type> undetvars;
|
Infer.InferenceContext inferenceContext;
|
||||||
Warner rsWarner;
|
Warner rsWarner;
|
||||||
|
|
||||||
public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs, List<Type> undetvars, Warner rsWarner) {
|
public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs, Infer.InferenceContext inferenceContext, Warner rsWarner) {
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.useVarargs = useVarargs;
|
this.useVarargs = useVarargs;
|
||||||
this.undetvars = undetvars;
|
this.inferenceContext = inferenceContext;
|
||||||
this.rsWarner = rsWarner;
|
this.rsWarner = rsWarner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,6 +690,10 @@ public class Resolve {
|
||||||
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
|
public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
|
||||||
return rsWarner;
|
return rsWarner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InferenceContext inferenceContext() {
|
||||||
|
return inferenceContext;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -684,12 +702,12 @@ public class Resolve {
|
||||||
*/
|
*/
|
||||||
class StrictMethodContext extends MethodCheckContext {
|
class StrictMethodContext extends MethodCheckContext {
|
||||||
|
|
||||||
public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs, List<Type> undetvars, Warner rsWarner) {
|
public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs, Infer.InferenceContext inferenceContext, Warner rsWarner) {
|
||||||
super(handler, useVarargs, undetvars, rsWarner);
|
super(handler, useVarargs, inferenceContext, rsWarner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean compatible(Type found, Type req, Warner warn) {
|
public boolean compatible(Type found, Type req, Warner warn) {
|
||||||
return types.isSubtypeUnchecked(found, infer.asUndetType(req, undetvars), warn);
|
return types.isSubtypeUnchecked(found, inferenceContext.asFree(req, types), warn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,12 +717,12 @@ public class Resolve {
|
||||||
*/
|
*/
|
||||||
class LooseMethodContext extends MethodCheckContext {
|
class LooseMethodContext extends MethodCheckContext {
|
||||||
|
|
||||||
public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs, List<Type> undetvars, Warner rsWarner) {
|
public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs, Infer.InferenceContext inferenceContext, Warner rsWarner) {
|
||||||
super(handler, useVarargs, undetvars, rsWarner);
|
super(handler, useVarargs, inferenceContext, rsWarner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean compatible(Type found, Type req, Warner warn) {
|
public boolean compatible(Type found, Type req, Warner warn) {
|
||||||
return types.isConvertible(found, infer.asUndetType(req, undetvars), warn);
|
return types.isConvertible(found, inferenceContext.asFree(req, types), warn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,10 +730,10 @@ public class Resolve {
|
||||||
* Create a method check context to be used during method applicability check
|
* Create a method check context to be used during method applicability check
|
||||||
*/
|
*/
|
||||||
ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs,
|
ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs,
|
||||||
List<Type> undetvars, MethodCheckHandler methodHandler, Warner rsWarner) {
|
Infer.InferenceContext inferenceContext, MethodCheckHandler methodHandler, Warner rsWarner) {
|
||||||
MethodCheckContext checkContext = allowBoxing ?
|
MethodCheckContext checkContext = allowBoxing ?
|
||||||
new LooseMethodContext(methodHandler, useVarargs, undetvars, rsWarner) :
|
new LooseMethodContext(methodHandler, useVarargs, inferenceContext, rsWarner) :
|
||||||
new StrictMethodContext(methodHandler, useVarargs, undetvars, rsWarner);
|
new StrictMethodContext(methodHandler, useVarargs, inferenceContext, rsWarner);
|
||||||
return attr.new ResultInfo(VAL, to, checkContext) {
|
return attr.new ResultInfo(VAL, to, checkContext) {
|
||||||
@Override
|
@Override
|
||||||
protected Type check(DiagnosticPosition pos, Type found) {
|
protected Type check(DiagnosticPosition pos, Type found) {
|
||||||
|
@ -735,16 +753,13 @@ public class Resolve {
|
||||||
this.diags = diags;
|
this.diags = diags;
|
||||||
}
|
}
|
||||||
InapplicableMethodException setMessage() {
|
InapplicableMethodException setMessage() {
|
||||||
this.diagnostic = null;
|
return setMessage((JCDiagnostic)null);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
InapplicableMethodException setMessage(String key) {
|
InapplicableMethodException setMessage(String key) {
|
||||||
this.diagnostic = key != null ? diags.fragment(key) : null;
|
return setMessage(key != null ? diags.fragment(key) : null);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
InapplicableMethodException setMessage(String key, Object... args) {
|
InapplicableMethodException setMessage(String key, Object... args) {
|
||||||
this.diagnostic = key != null ? diags.fragment(key, args) : null;
|
return setMessage(key != null ? diags.fragment(key, args) : null);
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
InapplicableMethodException setMessage(JCDiagnostic diag) {
|
InapplicableMethodException setMessage(JCDiagnostic diag) {
|
||||||
this.diagnostic = diag;
|
this.diagnostic = diag;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
T6638712c.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, sort, T[],java.util.Comparator<? super T>, java.lang.Enum[],java.util.Comparator<java.lang.Enum<?>>, kindname.class, T6638712c, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.util.Comparator<java.lang.Enum<?>>, java.util.Comparator<? super java.lang.Enum>))
|
T6638712c.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, sort, T[],java.util.Comparator<? super T>, java.lang.Enum[],java.util.Comparator<java.lang.Enum<?>>, kindname.class, T6638712c, (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.inconvertible.types: java.util.Comparator<java.lang.Enum<?>>, java.util.Comparator<? super java.lang.Enum>))
|
||||||
1 error
|
1 error
|
||||||
|
|
59
langtools/test/tools/javac/varargs/6313164/T7175433.java
Normal file
59
langtools/test/tools/javac/varargs/6313164/T7175433.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012, 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.
|
||||||
|
*
|
||||||
|
* 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 7175433 6313164
|
||||||
|
* @summary Inference cleanup: add helper class to handle inference variables
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
|
||||||
|
private class Foo { }
|
||||||
|
|
||||||
|
<Z> List<Z> m(Object... o) { T7175433.assertTrue(true); return null; }
|
||||||
|
<Z> List<Z> m(Foo... o) { T7175433.assertTrue(false); return null; }
|
||||||
|
|
||||||
|
Foo getFoo() { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class T7175433 {
|
||||||
|
|
||||||
|
static int assertionCount;
|
||||||
|
|
||||||
|
static void assertTrue(boolean b) {
|
||||||
|
assertionCount++;
|
||||||
|
if (!b) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Bar b = new Bar();
|
||||||
|
b.m(b.getFoo());
|
||||||
|
assertTrue(assertionCount == 1);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue