--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Mar 26 15:27:51 2012 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Mar 26 15:28:22 2012 +0100
@@ -269,23 +269,6 @@
else return syms.errType;
}
- /** Report a type error.
- * @param pos Position to be used for error reporting.
- * @param problem A string describing the error.
- * @param found The type that was found.
- * @param req The type that was required.
- */
- Type typeError(DiagnosticPosition pos, Object problem, Type found, Type req) {
- log.error(pos, "prob.found.req",
- problem, found, req);
- return types.createErrorType(found);
- }
-
- Type typeError(DiagnosticPosition pos, String problem, Type found, Type req, Object explanation) {
- log.error(pos, "prob.found.req.1", problem, found, req, explanation);
- return types.createErrorType(found);
- }
-
/** Report an error that wrong type tag was found.
* @param pos Position to be used for error reporting.
* @param required An internationalized string describing the type tag
@@ -430,6 +413,86 @@
* Type Checking
**************************************************************************/
+ /**
+ * A check context is an object that can be used to perform compatibility
+ * checks - depending on the check context, meaning of 'compatibility' might
+ * vary significantly.
+ */
+ interface CheckContext {
+ /**
+ * Is type 'found' compatible with type 'req' in given context
+ */
+ boolean compatible(Type found, Type req, Warner warn);
+ /**
+ * Instantiate a ForAll type against a given target type 'req' in given context
+ */
+ Type rawInstantiatePoly(ForAll found, Type req, Warner warn);
+ /**
+ * Report a check error
+ */
+ void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details);
+ /**
+ * Obtain a warner for this check context
+ */
+ public Warner checkWarner(DiagnosticPosition pos, Type found, Type req);
+ }
+
+ /**
+ * This class represent a check context that is nested within another check
+ * context - useful to check sub-expressions. The default behavior simply
+ * redirects all method calls to the enclosing check context leveraging
+ * the forwarding pattern.
+ */
+ static class NestedCheckContext implements CheckContext {
+ CheckContext enclosingContext;
+
+ NestedCheckContext(CheckContext enclosingContext) {
+ this.enclosingContext = enclosingContext;
+ }
+
+ public boolean compatible(Type found, Type req, Warner warn) {
+ return enclosingContext.compatible(found, req, warn);
+ }
+
+ public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) {
+ return enclosingContext.rawInstantiatePoly(found, req, warn);
+ }
+
+ public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) {
+ enclosingContext.report(pos, found, req, details);
+ }
+
+ public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
+ return enclosingContext.checkWarner(pos, found, req);
+ }
+ }
+
+ /**
+ * Check context to be used when evaluating assignment/return statements
+ */
+ CheckContext basicHandler = new CheckContext() {
+ public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) {
+ if (details == null) {
+ log.error(pos, "prob.found.req", found, req);
+ } else {
+ log.error(pos, "prob.found.req.1", details);
+ }
+ }
+ public boolean compatible(Type found, Type req, Warner warn) {
+ return types.isAssignable(found, req, warn);
+ }
+
+ public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) {
+ if (req.tag == NONE)
+ req = found.qtype.tag <= VOID ? found.qtype : syms.objectType;
+ return infer.instantiateExpr(found, req, warn);
+ }
+
+ public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
+ return convertWarner(pos, found, req);
+ }
+ };
+
/** Check that a given type is assignable to a given proto-type.
* If it is, return the type, otherwise return errType.
* @param pos Position to be used for error reporting.
@@ -437,64 +500,54 @@
* @param req The type that was required.
*/
Type checkType(DiagnosticPosition pos, Type found, Type req) {
- return checkType(pos, found, req, "incompatible.types");
+ return checkType(pos, found, req, basicHandler);
}
- Type checkType(DiagnosticPosition pos, Type found, Type req, String errKey) {
+ Type checkType(final DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) {
if (req.tag == ERROR)
return req;
- if (found.tag == FORALL)
- return instantiatePoly(pos, (ForAll)found, req, convertWarner(pos, found, req));
+ if (found.tag == FORALL) {
+ ForAll fa = (ForAll)found;
+ Type owntype = instantiatePoly(pos, checkContext, fa, req, checkContext.checkWarner(pos, found, req));
+ return checkType(pos, owntype, req, checkContext);
+ }
if (req.tag == NONE)
return found;
- if (types.isAssignable(found, req, convertWarner(pos, found, req)))
+ if (checkContext.compatible(found, req, checkContext.checkWarner(pos, found, req))) {
return found;
- if (found.tag <= DOUBLE && req.tag <= DOUBLE)
- return typeError(pos, diags.fragment("possible.loss.of.precision"), found, req);
- if (found.isSuperBound()) {
- log.error(pos, "assignment.from.super-bound", found);
+ } else {
+ if (found.tag <= DOUBLE && req.tag <= DOUBLE) {
+ checkContext.report(pos, found, req, diags.fragment("possible.loss.of.precision"));
+ return types.createErrorType(found);
+ }
+ checkContext.report(pos, found, req, null);
return types.createErrorType(found);
}
- if (req.isExtendsBound()) {
- log.error(pos, "assignment.to.extends-bound", req);
- return types.createErrorType(found);
- }
- return typeError(pos, diags.fragment(errKey), found, req);
}
/** Instantiate polymorphic type to some prototype, unless
* prototype is `anyPoly' in which case polymorphic type
* is returned unchanged.
*/
- Type instantiatePoly(DiagnosticPosition pos, ForAll t, Type pt, Warner warn) throws Infer.NoInstanceException {
- if (pt == Infer.anyPoly && complexInference) {
- return t;
- } else if (pt == Infer.anyPoly || pt.tag == NONE) {
- Type newpt = t.qtype.tag <= VOID ? t.qtype : syms.objectType;
- return instantiatePoly(pos, t, newpt, warn);
- } else if (pt.tag == ERROR) {
- return pt;
- } else {
- try {
- return infer.instantiateExpr(t, pt, warn);
- } catch (Infer.NoInstanceException ex) {
+ Type instantiatePoly(DiagnosticPosition pos, CheckContext checkContext, ForAll t, Type pt, Warner warn) throws Infer.NoInstanceException {
+ try {
+ return checkContext.rawInstantiatePoly(t, pt, warn);
+ } catch (final Infer.NoInstanceException ex) {
+ JCDiagnostic d = ex.getDiagnostic();
+ if (d != null) {
if (ex.isAmbiguous) {
- JCDiagnostic d = ex.getDiagnostic();
- log.error(pos,
- "undetermined.type" + (d!=null ? ".1" : ""),
- t, d);
- return types.createErrorType(pt);
- } else {
- JCDiagnostic d = ex.getDiagnostic();
- return typeError(pos,
- diags.fragment("incompatible.types" + (d!=null ? ".1" : ""), d),
- t, pt);
+ d = diags.fragment("undetermined.type", t, d);
}
- } catch (Infer.InvalidInstanceException ex) {
- JCDiagnostic d = ex.getDiagnostic();
- log.error(pos, "invalid.inferred.types", t.tvars, d);
- return types.createErrorType(pt);
}
+ checkContext.report(pos, t, pt, d);
+ return types.createErrorType(pt);
+ } catch (Infer.InvalidInstanceException ex) {
+ JCDiagnostic d = ex.getDiagnostic();
+ if (d != null) {
+ d = diags.fragment("invalid.inferred.types", t.tvars, d);
+ }
+ checkContext.report(pos, t, pt, d);
+ return types.createErrorType(pt);
}
}
@@ -505,15 +558,17 @@
* @param req The target type of the cast.
*/
Type checkCastable(DiagnosticPosition pos, Type found, Type req) {
+ return checkCastable(pos, found, req, basicHandler);
+ }
+ Type checkCastable(DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) {
if (found.tag == FORALL) {
- instantiatePoly(pos, (ForAll) found, req, castWarner(pos, found, req));
+ instantiatePoly(pos, basicHandler, (ForAll) found, req, castWarner(pos, found, req));
return req;
} else if (types.isCastable(found, req, castWarner(pos, found, req))) {
return req;
} else {
- return typeError(pos,
- diags.fragment("inconvertible.types"),
- found, req);
+ checkContext.report(pos, found, req, diags.fragment("inconvertible.types", found, req));
+ return types.createErrorType(found);
}
}
@@ -867,14 +922,6 @@
&& types.isSubtype(actual, types.supertype(formal))
&& types.isSubtypeUnchecked(actual, types.interfaces(formal), warn))
return;
-
- if (false) {
- // TODO: make assertConvertible work
- typeError(tree.pos(), diags.fragment("incompatible.types"), actual, formal);
- throw new AssertionError("Tree: " + tree
- + " actual:" + actual
- + " formal: " + formal);
- }
}
/**