changeset 752:81019709553d

Conversion support clean-up. Got rid of the ConversionResult class and simplified both Types.isAssignable/Types.isConvertible. Now an unchecked exception is used in order to propagate a detailed diagnostic message about what went wrong during a conversion --- this is more in sync with the rest of the javac code.
author mcimadamore
date Fri, 12 Nov 2010 15:49:29 +0000
parents 9a1ae3fc0a88
children 4335e2277cbd
files src/share/classes/com/sun/tools/apt/mirror/util/TypesImpl.java src/share/classes/com/sun/tools/javac/code/Type.java src/share/classes/com/sun/tools/javac/code/Types.java src/share/classes/com/sun/tools/javac/comp/Check.java src/share/classes/com/sun/tools/javac/comp/Infer.java src/share/classes/com/sun/tools/javac/comp/Resolve.java src/share/classes/com/sun/tools/javac/model/JavacTypes.java
diffstat 7 files changed, 148 insertions(+), 151 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/apt/mirror/util/TypesImpl.java	Fri Nov 12 12:49:12 2010 +0000
+++ b/src/share/classes/com/sun/tools/apt/mirror/util/TypesImpl.java	Fri Nov 12 15:49:29 2010 +0000
@@ -39,6 +39,7 @@
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Warner;
 
 
 /**
@@ -80,7 +81,7 @@
      */
     public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
         return env.jctypes.isAssignableNoCheck(((TypeMirrorImpl) t1).type,
-                                        ((TypeMirrorImpl) t2).type);
+                                        ((TypeMirrorImpl) t2).type, Warner.noWarnings);
     }
 
     /**
--- a/src/share/classes/com/sun/tools/javac/code/Type.java	Fri Nov 12 12:49:12 2010 +0000
+++ b/src/share/classes/com/sun/tools/javac/code/Type.java	Fri Nov 12 15:49:29 2010 +0000
@@ -27,7 +27,6 @@
 
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.comp.Resolve;
 
 import javax.lang.model.type.*;
 
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Fri Nov 12 12:49:12 2010 +0000
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Fri Nov 12 15:49:29 2010 +0000
@@ -81,6 +81,7 @@
     final Check chk;
     List<Warner> warnStack = List.nil();
     final Name capturedName;
+    final ConversionException conversionException;
 
     // <editor-fold defaultstate="collapsed" desc="Instantiating">
     public static Types instance(Context context) {
@@ -101,6 +102,7 @@
         chk = Check.instance(context);
         capturedName = names.fromString("<captured wildcard>");
         messages = JavacMessages.instance(context);
+        conversionException = new ConversionException();
     }
     // </editor-fold>
 
@@ -276,12 +278,8 @@
         return isConvertible(env, t, s, Warner.noWarnings);
     }
 
-    public boolean isConvertible(Env<AttrContext> env, Type t, Type s, Warner warn) {
-        return isConvertible(t, s, warn).check(env);
-    }
-
     private boolean isConvertibleNoCheck(Type t, Type s, Warner warn) {
-        return isConvertible(t, s, warn).isSuccess();
+        return isConvertible(null, t, s, warn);
     }
 
     Type boxedTypeOrType(Type t) {
@@ -297,51 +295,59 @@
         }
         return buf.toList();
     }
+
+    public boolean isConvertible(Env<AttrContext> env, final Type t, final Type s, final Warner warn) {
+        try {
+            rawIsConvertible(env, t, s, warn);
+            return true;
+        } catch (ConversionException ex) {
+            return false;
+        }
+    }
     
-    public ConversionResult isConvertible(final Type t, final Type s, final Warner warn) {
+    public void rawIsConvertible(Env<AttrContext> env, final Type t, final Type s, final Warner warn) throws ConversionException {
         if (isFunctionType(t) &&
-                (s.tsym.kind == Kinds.TYP)) {
-            return new ConversionResult(true) {
-                @Override
-                public boolean check(Env<AttrContext> env) {
-                    final SAMResult samRes = findSAM(s, env);
-                    if (samRes.isErroneous()) {
-                        setKey(samRes.errKey).setArgs(samRes.args);
-                        return false;
-                    }
-                    Type mtype = samRes.getTargetType();
-                    //the order is important here because of type-inference
-                    //(reference types first)
-                    boolean isReturnOk = t.getReturnType().tag == NONE || (t.getReturnType() == syms.voidType ?
-                        (isSameType(mtype.getReturnType(), boxedClass(syms.voidType).type) ||
-                            isSameType(mtype.getReturnType(), syms.voidType)) :
-                        containsType(boxedTypeOrType(mtype.getReturnType()), boxedTypeOrType(t.getReturnType())));
-
-                    boolean argsOk = t.getParameterTypes().size() == mtype.getParameterTypes().size() &&
-                        containsType(mtype.getParameterTypes(), t.getParameterTypes());
-
-                    boolean thrownOk = t.getThrownTypes() == Type.noTypes ||
-                            chk.unhandled(t.getThrownTypes(), mtype.getThrownTypes()).isEmpty();
-                    if (!isReturnOk || !argsOk || !thrownOk) {
-                        //target method is not compatible
-                        setKey("incompatible.target.in.lambda.conv").setArgs(samRes.getTargetName(),
-                                Kinds.kindName(s.tsym),
-                                s.tsym);
-                        return false;
-                    }
-                    return true;
-                }
-            };
+                (s.tsym.kind == Kinds.TYP) &&
+                env != null) {
+            final SAMResult samRes = findSAM(s, env);
+            if (samRes.isErroneous()) {
+                throw conversionException.setMessage(samRes.errKey, samRes.args);
+            }
+            Type mtype = samRes.getTargetType();
+            //the order is important here because of type-inference
+            //(reference types first)
+            boolean isReturnOk = t.getReturnType().tag == NONE || (t.getReturnType() == syms.voidType ?
+                (isSameType(mtype.getReturnType(), boxedClass(syms.voidType).type) ||
+                    isSameType(mtype.getReturnType(), syms.voidType)) :
+                containsType(boxedTypeOrType(mtype.getReturnType()), boxedTypeOrType(t.getReturnType())));
+
+            boolean argsOk = t.getParameterTypes().size() == mtype.getParameterTypes().size() &&
+                containsType(mtype.getParameterTypes(), t.getParameterTypes());
+
+            boolean thrownOk = t.getThrownTypes() == Type.noTypes ||
+                    chk.unhandled(t.getThrownTypes(), mtype.getThrownTypes()).isEmpty();
+            if (!isReturnOk || !argsOk || !thrownOk) {
+                //target method is not compatible
+                throw conversionException.setMessage("incompatible.target.in.lambda.conv",
+                        samRes.getTargetName(),
+                        Kinds.kindName(s.tsym),
+                        s.tsym);
+            }
+            return;
         }
         else {
             boolean tPrimitive = t.isPrimitive();
             boolean sPrimitive = s.isPrimitive();
-            if (tPrimitive == sPrimitive)
-                return new ConversionResult(isSubtypeUnchecked(t, s, warn));
-            if (!allowBoxing) return ConversionResult.FAILURE;
-            return new ConversionResult(tPrimitive
+            if (tPrimitive == sPrimitive) {
+                if (!isSubtypeUnchecked(t, s, warn)) throw conversionException.setMessage(null);
+                return;
+            }
+            if (!allowBoxing) throw conversionException.setMessage(null);
+            boolean works = tPrimitive
                 ? isSubtype(boxedClass(t).type, s)
-                : isSubtype(unboxedType(t), s));
+                : isSubtype(unboxedType(t), s);
+            if (!works)
+                throw conversionException.setMessage(null);
         }
     }
 
@@ -355,50 +361,22 @@
      * has failed; this info can be leveraged when a diagnostic message is
      * generated by javac.
      */
-    public static class ConversionResult {
-
-        private boolean success;
+    public static class ConversionException extends RuntimeException {
+        
         private String detailsKey;
         private Object[] detailsArgs;
 
-        ConversionResult(boolean success) {
-            this(success, null);
-        }
-
-        ConversionResult(String key, Object... args) {
-            this(false, key, args);
-        }
-
-        ConversionResult(boolean success, String key, Object... args) {
-            this.success = success;
+        public ConversionException setMessage(String key, Object... args) {
             this.detailsKey = key;
             this.detailsArgs = args;
+            return this;
         }
 
-        public static final ConversionResult SUCCESS = new ConversionResult(true);
-        public static final ConversionResult FAILURE = new ConversionResult(false);
-
-        public boolean check(Env<AttrContext> env) { return success; }
-
         public JCDiagnostic getDiagnostic(JCDiagnostic.Factory diags) {
             return detailsKey != null ?
                 diags.fragment(detailsKey, detailsArgs) :
                 null;
         }
-
-        protected ConversionResult setKey(String key) {
-            this.detailsKey = key;
-            return this;
-        }
-
-        protected ConversionResult setArgs(Object... args) {
-            this.detailsArgs = args;
-            return this;
-        }
-
-        protected boolean isSuccess() {
-            return success;
-        }
     }
 
     // <editor-fold defaultstate="collapsed" desc="findSam">
@@ -2058,19 +2036,11 @@
         return isAssignable(env, t, s, Warner.noWarnings);
     }
 
-    public boolean isAssignable(Env<AttrContext> env, Type t, Type s, Warner warn) {        
-        return isAssignable(t, s, warn).check(env);
-    }
-
     //the following methods should be private, but they need to be accessed from
     //deprecated methods in JavacTypes (for backward compatibility)
 
-    public boolean isAssignableNoCheck(Type t, Type s) {
-        return isAssignableNoCheck(t, s, Warner.noWarnings);
-    }
-
-    public boolean isAssignableNoCheck(Type t, Type s, Warner warn) {
-        return isAssignable(t, s, warn).isSuccess();
+    public boolean isAssignableNoCheck(Type t, Type s, Warner warner) {
+        return isAssignable(null, t, s, warner);
     }
 
     /**
@@ -2079,37 +2049,53 @@
      * types.<br>
      * (not defined for Method and ForAll types)
      */
-    public ConversionResult isAssignable(Type t, Type s, Warner warn) {
+    /**
+     * Is t assignable to s?<br>
+     * Equivalent to subtype except for constant values and raw
+     * types.<br>
+     * (not defined for Method and ForAll types)
+     */
+    public boolean isAssignable(Env<AttrContext> env, Type t, Type s, Warner warn) {
+        try {
+            rawIsAssignable(env, t, s, warn);
+            return true;
+        } catch(ConversionException ex) {
+            return false;
+        }
+    }
+
+    public void rawIsAssignable(Env<AttrContext> env, Type t, Type s, Warner warn) throws ConversionException {
         if (t.tag == ERROR)
-            return ConversionResult.SUCCESS;
+            return;
         if (t.tag <= INT && t.constValue() != null) {
             int value = ((Number)t.constValue()).intValue();
             switch (s.tag) {
             case BYTE:
                 if (Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE)
-                    return ConversionResult.SUCCESS;
+                    return;
                 break;
             case CHAR:
                 if (Character.MIN_VALUE <= value && value <= Character.MAX_VALUE)
-                    return ConversionResult.SUCCESS;
+                    return;
                 break;
             case SHORT:
                 if (Short.MIN_VALUE <= value && value <= Short.MAX_VALUE)
-                    return ConversionResult.SUCCESS;
+                    return;
                 break;
             case INT:
-                return ConversionResult.SUCCESS;
+                return;
             case CLASS:
                 switch (unboxedType(s).tag) {
                 case BYTE:
                 case CHAR:
                 case SHORT:
-                    return isAssignable(t, unboxedType(s), warn);
+                    rawIsAssignable(env, t, unboxedType(s), warn);
+                    return;
                 }
                 break;
             }
         }
-        return isConvertible(t, s, warn);
+        rawIsConvertible(env, t, s, warn);
     }
     // </editor-fold>
 
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Nov 12 12:49:12 2010 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Fri Nov 12 15:49:29 2010 +0000
@@ -412,9 +412,14 @@
             return instantiatePoly(pos, env, (ForAll)found, req, convertWarner(pos, found, req));
         if (req.tag == NONE)
             return found;
-        Types.ConversionResult res = types.isAssignable(found, req, convertWarner(pos, found, req));
-        if (res.check(env))
+        JCDiagnostic details = null;
+        try {
+            types.rawIsAssignable(env, found, req, convertWarner(pos, found, req));
             return found;
+        }
+        catch (Types.ConversionException ex) {
+            details = ex.getDiagnostic(diags);
+        }
         if (found.tag <= DOUBLE && req.tag <= DOUBLE)
             return typeError(pos, diags.fragment("possible.loss.of.precision"), found, req);
         if (found.isSuperBound()) {
@@ -425,12 +430,21 @@
             log.error(pos, "assignment.to.extends-bound", req);
             return types.createErrorType(found);
         }
-        JCDiagnostic subDiag = res != null && res.getDiagnostic(diags) != null ?
-            diags.fragment(errKey + ".1", res.getDiagnostic(diags)) :
+        JCDiagnostic subDiag = details != null ?
+            diags.fragment(errKey + ".1", details) :
             diags.fragment(errKey);
         return typeError(pos, subDiag, found, req);
     }
 
+    boolean checkArgument(Env<AttrContext> env, Type actual, Type formal, boolean allowBoxing, Warner warn) {
+        if (allowBoxing) {
+            types.rawIsConvertible(env, actual, formal, warn);
+            return true;
+        } else {
+            return types.isSubtypeUnchecked(actual, formal, warn);
+        }
+    }
+
     /** Instantiate polymorphic type to some prototype, unless
      *  prototype is `anyPoly' in which case polymorphic type
      *  is returned unchanged.
--- a/src/share/classes/com/sun/tools/javac/comp/Infer.java	Fri Nov 12 12:49:12 2010 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Infer.java	Fri Nov 12 15:49:29 2010 +0000
@@ -417,33 +417,16 @@
                 else {
                     capturedArgs.append(actual = types.capture(actual));
                 }
-
                 boolean works = false;
                 JCDiagnostic problem = null;
-                if (allowBoxing) {
-                    Types.ConversionResult res = types.isConvertible(actual, undetFormal, warn);
-                    works = res.check(env);
-                    problem = res.getDiagnostic(diags);
-                } else {
-                    works = types.isSubtypeUnchecked(actual, undetFormal, warn);
+                try {
+                    works = chk.checkArgument(env, actual, undetFormal, allowBoxing, warn);
+                }
+                catch (Types.ConversionException ex) {
+                    problem = ex.getDiagnostic(diags);
                 }
                 if (!works) {
-                    if (tvars.nonEmpty()) {
-                        String errKey = problem == null ?
-                            "infer.no.conforming.assignment.exists" :
-                            "infer.no.conforming.assignment.exists.1";
-                        throw unambiguousNoInstanceException
-                            .setMessage(errKey,
-                                        tvars, actualNoCapture, formal, problem);
-                    }
-                    else {
-                        String errKey = problem == null ?
-                            "no.conforming.assignment.exists" :
-                            "no.conforming.assignment.exists.1";
-                        throw unambiguousNoInstanceException
-                            .setMessage(errKey,
-                                        actualNoCapture, formal, problem);
-                    }
+                    argumentMismatch(tvars, actualNoCapture, formal, problem);
                 }
                 formals = formals.tail;
                 actuals = actuals.tail;
@@ -473,26 +456,16 @@
                     } else {
                         capturedArgs.append(actual = types.capture(actual));
                     }
-                    Types.ConversionResult res = types.isConvertible(actual, elemUndet, warn);
-                    boolean works = res.check(env);
-                    JCDiagnostic problem = res.getDiagnostic(diags);
+                    boolean works = false;
+                    JCDiagnostic problem = null;
+                    try {
+                        works = chk.checkArgument(env, actual, elemUndet, allowBoxing, warn);
+                    }
+                    catch (Types.ConversionException ex) {
+                        problem = ex.getDiagnostic(diags);
+                    }
                     if (!works) {
-                        if (tvars.nonEmpty()) {
-                            String errKey = problem == null ?
-                                "infer.no.conforming.assignment.exists" :
-                                "infer.no.conforming.assignment.exists.1";
-                            throw unambiguousNoInstanceException
-                                .setMessage(errKey,
-                                            tvars, actualNoCapture, elemType);
-                        }
-                        else {
-                            String errKey = problem == null ?
-                                "no.conforming.assignment.exists" :
-                                "no.conforming.assignment.exists.1";
-                            throw unambiguousNoInstanceException
-                                .setMessage(errKey,
-                                        actualNoCapture, elemType);
-                        }
+                        argumentMismatch(tvars, actualNoCapture, elemType, problem);
                     }
                     actuals = actuals.tail;
                     actualsNoCapture = actualsNoCapture.tail;
@@ -606,6 +579,25 @@
             }
         };
     }
+    //where
+    private void argumentMismatch(List<Type> tvars, Type actual, Type formal, JCDiagnostic problem) throws InferenceException {
+        if (tvars.nonEmpty()) {
+            String errKey = problem == null ?
+                "infer.no.conforming.assignment.exists" :
+                "infer.no.conforming.assignment.exists.1";
+            throw unambiguousNoInstanceException
+                .setMessage(errKey,
+                            tvars, actual, formal, problem);
+        }
+        else {
+            String errKey = problem == null ?
+                "no.conforming.assignment.exists" :
+                "no.conforming.assignment.exists.1";
+            throw unambiguousNoInstanceException
+                .setMessage(errKey,
+                            actual, formal, problem);
+        }
+    }
 
     private List<Type> getConstraints(List<Type> undetvars, TypeVar tv, EnumSet<ConstraintKind> constraints, List<Type> tvars, List<Type> inferred) {
         for (Type t : undetvars) {
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Nov 12 12:49:12 2010 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Nov 12 15:49:29 2010 +0000
@@ -456,12 +456,11 @@
                 argtypes.head;
             boolean works = false;
             JCDiagnostic problem = null;
-            if (allowBoxing) {
-                Types.ConversionResult res = types.isConvertible(actual, formals.head, warn);
-                works = res.check(env);
-                problem = res.getDiagnostic(diags);
-            } else {
-                works = types.isSubtypeUnchecked(actual, formals.head, warn);
+            try {
+                works = chk.checkArgument(env, actual, formals.head, allowBoxing, warn);
+            }
+            catch (Types.ConversionException ex) {
+                problem = ex.getDiagnostic(diags);
             }
             if (!works) {
                 String errKey = problem == null ?
@@ -484,9 +483,15 @@
     	        Type actual = argtypes.head.tag == FORALL ?
     	            infer.instantiateArg(env, (ForAll)argtypes.head, elt, warn, phase) :
                     argtypes.head;
-                Types.ConversionResult res = types.isConvertible(actual, elt, warn);
-    	        if (!res.check(env)) {
-                    JCDiagnostic problem = res.getDiagnostic(diags);
+                boolean works = false;
+                JCDiagnostic problem = null;
+                try {
+                    works = chk.checkArgument(env, actual, elt, allowBoxing, warn);
+                }
+                catch (Types.ConversionException ex) {
+                    problem = ex.getDiagnostic(diags);
+                }
+    	        if (!works) {
                     String errKey = problem == null ?
                         "varargs.argument.mismatch" :
                         "varargs.argument.mismatch.1";
--- a/src/share/classes/com/sun/tools/javac/model/JavacTypes.java	Fri Nov 12 12:49:12 2010 +0000
+++ b/src/share/classes/com/sun/tools/javac/model/JavacTypes.java	Fri Nov 12 15:49:29 2010 +0000
@@ -97,7 +97,7 @@
     public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
         validateTypeNotIn(t1, EXEC_OR_PKG);
         validateTypeNotIn(t2, EXEC_OR_PKG);
-        return types.isAssignableNoCheck((Type) t1, (Type) t2);
+        return types.isAssignableNoCheck((Type) t1, (Type) t2, Warner.noWarnings);
     }
     
     public boolean contains(TypeMirror t1, TypeMirror t2) {