1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Mar 26 15:27:51 2012 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Mar 26 15:28:22 2012 +0100 1.3 @@ -269,23 +269,6 @@ 1.4 else return syms.errType; 1.5 } 1.6 1.7 - /** Report a type error. 1.8 - * @param pos Position to be used for error reporting. 1.9 - * @param problem A string describing the error. 1.10 - * @param found The type that was found. 1.11 - * @param req The type that was required. 1.12 - */ 1.13 - Type typeError(DiagnosticPosition pos, Object problem, Type found, Type req) { 1.14 - log.error(pos, "prob.found.req", 1.15 - problem, found, req); 1.16 - return types.createErrorType(found); 1.17 - } 1.18 - 1.19 - Type typeError(DiagnosticPosition pos, String problem, Type found, Type req, Object explanation) { 1.20 - log.error(pos, "prob.found.req.1", problem, found, req, explanation); 1.21 - return types.createErrorType(found); 1.22 - } 1.23 - 1.24 /** Report an error that wrong type tag was found. 1.25 * @param pos Position to be used for error reporting. 1.26 * @param required An internationalized string describing the type tag 1.27 @@ -430,6 +413,86 @@ 1.28 * Type Checking 1.29 **************************************************************************/ 1.30 1.31 + /** 1.32 + * A check context is an object that can be used to perform compatibility 1.33 + * checks - depending on the check context, meaning of 'compatibility' might 1.34 + * vary significantly. 1.35 + */ 1.36 + interface CheckContext { 1.37 + /** 1.38 + * Is type 'found' compatible with type 'req' in given context 1.39 + */ 1.40 + boolean compatible(Type found, Type req, Warner warn); 1.41 + /** 1.42 + * Instantiate a ForAll type against a given target type 'req' in given context 1.43 + */ 1.44 + Type rawInstantiatePoly(ForAll found, Type req, Warner warn); 1.45 + /** 1.46 + * Report a check error 1.47 + */ 1.48 + void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details); 1.49 + /** 1.50 + * Obtain a warner for this check context 1.51 + */ 1.52 + public Warner checkWarner(DiagnosticPosition pos, Type found, Type req); 1.53 + } 1.54 + 1.55 + /** 1.56 + * This class represent a check context that is nested within another check 1.57 + * context - useful to check sub-expressions. The default behavior simply 1.58 + * redirects all method calls to the enclosing check context leveraging 1.59 + * the forwarding pattern. 1.60 + */ 1.61 + static class NestedCheckContext implements CheckContext { 1.62 + CheckContext enclosingContext; 1.63 + 1.64 + NestedCheckContext(CheckContext enclosingContext) { 1.65 + this.enclosingContext = enclosingContext; 1.66 + } 1.67 + 1.68 + public boolean compatible(Type found, Type req, Warner warn) { 1.69 + return enclosingContext.compatible(found, req, warn); 1.70 + } 1.71 + 1.72 + public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) { 1.73 + return enclosingContext.rawInstantiatePoly(found, req, warn); 1.74 + } 1.75 + 1.76 + public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) { 1.77 + enclosingContext.report(pos, found, req, details); 1.78 + } 1.79 + 1.80 + public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) { 1.81 + return enclosingContext.checkWarner(pos, found, req); 1.82 + } 1.83 + } 1.84 + 1.85 + /** 1.86 + * Check context to be used when evaluating assignment/return statements 1.87 + */ 1.88 + CheckContext basicHandler = new CheckContext() { 1.89 + public void report(DiagnosticPosition pos, Type found, Type req, JCDiagnostic details) { 1.90 + if (details == null) { 1.91 + log.error(pos, "prob.found.req", found, req); 1.92 + } else { 1.93 + log.error(pos, "prob.found.req.1", details); 1.94 + } 1.95 + } 1.96 + public boolean compatible(Type found, Type req, Warner warn) { 1.97 + return types.isAssignable(found, req, warn); 1.98 + } 1.99 + 1.100 + public Type rawInstantiatePoly(ForAll found, Type req, Warner warn) { 1.101 + if (req.tag == NONE) 1.102 + req = found.qtype.tag <= VOID ? found.qtype : syms.objectType; 1.103 + return infer.instantiateExpr(found, req, warn); 1.104 + } 1.105 + 1.106 + public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) { 1.107 + return convertWarner(pos, found, req); 1.108 + } 1.109 + }; 1.110 + 1.111 /** Check that a given type is assignable to a given proto-type. 1.112 * If it is, return the type, otherwise return errType. 1.113 * @param pos Position to be used for error reporting. 1.114 @@ -437,64 +500,54 @@ 1.115 * @param req The type that was required. 1.116 */ 1.117 Type checkType(DiagnosticPosition pos, Type found, Type req) { 1.118 - return checkType(pos, found, req, "incompatible.types"); 1.119 + return checkType(pos, found, req, basicHandler); 1.120 } 1.121 1.122 - Type checkType(DiagnosticPosition pos, Type found, Type req, String errKey) { 1.123 + Type checkType(final DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) { 1.124 if (req.tag == ERROR) 1.125 return req; 1.126 - if (found.tag == FORALL) 1.127 - return instantiatePoly(pos, (ForAll)found, req, convertWarner(pos, found, req)); 1.128 + if (found.tag == FORALL) { 1.129 + ForAll fa = (ForAll)found; 1.130 + Type owntype = instantiatePoly(pos, checkContext, fa, req, checkContext.checkWarner(pos, found, req)); 1.131 + return checkType(pos, owntype, req, checkContext); 1.132 + } 1.133 if (req.tag == NONE) 1.134 return found; 1.135 - if (types.isAssignable(found, req, convertWarner(pos, found, req))) 1.136 + if (checkContext.compatible(found, req, checkContext.checkWarner(pos, found, req))) { 1.137 return found; 1.138 - if (found.tag <= DOUBLE && req.tag <= DOUBLE) 1.139 - return typeError(pos, diags.fragment("possible.loss.of.precision"), found, req); 1.140 - if (found.isSuperBound()) { 1.141 - log.error(pos, "assignment.from.super-bound", found); 1.142 + } else { 1.143 + if (found.tag <= DOUBLE && req.tag <= DOUBLE) { 1.144 + checkContext.report(pos, found, req, diags.fragment("possible.loss.of.precision")); 1.145 + return types.createErrorType(found); 1.146 + } 1.147 + checkContext.report(pos, found, req, null); 1.148 return types.createErrorType(found); 1.149 } 1.150 - if (req.isExtendsBound()) { 1.151 - log.error(pos, "assignment.to.extends-bound", req); 1.152 - return types.createErrorType(found); 1.153 - } 1.154 - return typeError(pos, diags.fragment(errKey), found, req); 1.155 } 1.156 1.157 /** Instantiate polymorphic type to some prototype, unless 1.158 * prototype is `anyPoly' in which case polymorphic type 1.159 * is returned unchanged. 1.160 */ 1.161 - Type instantiatePoly(DiagnosticPosition pos, ForAll t, Type pt, Warner warn) throws Infer.NoInstanceException { 1.162 - if (pt == Infer.anyPoly && complexInference) { 1.163 - return t; 1.164 - } else if (pt == Infer.anyPoly || pt.tag == NONE) { 1.165 - Type newpt = t.qtype.tag <= VOID ? t.qtype : syms.objectType; 1.166 - return instantiatePoly(pos, t, newpt, warn); 1.167 - } else if (pt.tag == ERROR) { 1.168 - return pt; 1.169 - } else { 1.170 - try { 1.171 - return infer.instantiateExpr(t, pt, warn); 1.172 - } catch (Infer.NoInstanceException ex) { 1.173 + Type instantiatePoly(DiagnosticPosition pos, CheckContext checkContext, ForAll t, Type pt, Warner warn) throws Infer.NoInstanceException { 1.174 + try { 1.175 + return checkContext.rawInstantiatePoly(t, pt, warn); 1.176 + } catch (final Infer.NoInstanceException ex) { 1.177 + JCDiagnostic d = ex.getDiagnostic(); 1.178 + if (d != null) { 1.179 if (ex.isAmbiguous) { 1.180 - JCDiagnostic d = ex.getDiagnostic(); 1.181 - log.error(pos, 1.182 - "undetermined.type" + (d!=null ? ".1" : ""), 1.183 - t, d); 1.184 - return types.createErrorType(pt); 1.185 - } else { 1.186 - JCDiagnostic d = ex.getDiagnostic(); 1.187 - return typeError(pos, 1.188 - diags.fragment("incompatible.types" + (d!=null ? ".1" : ""), d), 1.189 - t, pt); 1.190 + d = diags.fragment("undetermined.type", t, d); 1.191 } 1.192 - } catch (Infer.InvalidInstanceException ex) { 1.193 - JCDiagnostic d = ex.getDiagnostic(); 1.194 - log.error(pos, "invalid.inferred.types", t.tvars, d); 1.195 - return types.createErrorType(pt); 1.196 } 1.197 + checkContext.report(pos, t, pt, d); 1.198 + return types.createErrorType(pt); 1.199 + } catch (Infer.InvalidInstanceException ex) { 1.200 + JCDiagnostic d = ex.getDiagnostic(); 1.201 + if (d != null) { 1.202 + d = diags.fragment("invalid.inferred.types", t.tvars, d); 1.203 + } 1.204 + checkContext.report(pos, t, pt, d); 1.205 + return types.createErrorType(pt); 1.206 } 1.207 } 1.208 1.209 @@ -505,15 +558,17 @@ 1.210 * @param req The target type of the cast. 1.211 */ 1.212 Type checkCastable(DiagnosticPosition pos, Type found, Type req) { 1.213 + return checkCastable(pos, found, req, basicHandler); 1.214 + } 1.215 + Type checkCastable(DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) { 1.216 if (found.tag == FORALL) { 1.217 - instantiatePoly(pos, (ForAll) found, req, castWarner(pos, found, req)); 1.218 + instantiatePoly(pos, basicHandler, (ForAll) found, req, castWarner(pos, found, req)); 1.219 return req; 1.220 } else if (types.isCastable(found, req, castWarner(pos, found, req))) { 1.221 return req; 1.222 } else { 1.223 - return typeError(pos, 1.224 - diags.fragment("inconvertible.types"), 1.225 - found, req); 1.226 + checkContext.report(pos, found, req, diags.fragment("inconvertible.types", found, req)); 1.227 + return types.createErrorType(found); 1.228 } 1.229 } 1.230 1.231 @@ -867,14 +922,6 @@ 1.232 && types.isSubtype(actual, types.supertype(formal)) 1.233 && types.isSubtypeUnchecked(actual, types.interfaces(formal), warn)) 1.234 return; 1.235 - 1.236 - if (false) { 1.237 - // TODO: make assertConvertible work 1.238 - typeError(tree.pos(), diags.fragment("incompatible.types"), actual, formal); 1.239 - throw new AssertionError("Tree: " + tree 1.240 - + " actual:" + actual 1.241 - + " formal: " + formal); 1.242 - } 1.243 } 1.244 1.245 /**