833 protected ResultInfo dup(CheckContext newContext) { |
836 protected ResultInfo dup(CheckContext newContext) { |
834 return new MethodResultInfo(pt, newContext); |
837 return new MethodResultInfo(pt, newContext); |
835 } |
838 } |
836 } |
839 } |
837 |
840 |
|
841 /** |
|
842 * Most specific method applicability routine. Given a list of actual types A, |
|
843 * a list of formal types F1, and a list of formal types F2, the routine determines |
|
844 * as to whether the types in F1 can be considered more specific than those in F2 w.r.t. |
|
845 * argument types A. |
|
846 */ |
|
847 class MostSpecificCheck implements MethodCheck { |
|
848 |
|
849 boolean strict; |
|
850 List<Type> actuals; |
|
851 |
|
852 MostSpecificCheck(boolean strict, List<Type> actuals) { |
|
853 this.strict = strict; |
|
854 this.actuals = actuals; |
|
855 } |
|
856 |
|
857 @Override |
|
858 public void argumentsAcceptable(final Env<AttrContext> env, |
|
859 DeferredAttrContext deferredAttrContext, |
|
860 List<Type> formals1, |
|
861 List<Type> formals2, |
|
862 Warner warn) { |
|
863 formals2 = adjustArgs(formals2, deferredAttrContext.msym, formals1.length(), deferredAttrContext.phase.isVarargsRequired()); |
|
864 while (formals2.nonEmpty()) { |
|
865 ResultInfo mresult = methodCheckResult(formals2.head, deferredAttrContext, warn, actuals.head); |
|
866 mresult.check(null, formals1.head); |
|
867 formals1 = formals1.tail; |
|
868 formals2 = formals2.tail; |
|
869 actuals = actuals.isEmpty() ? actuals : actuals.tail; |
|
870 } |
|
871 } |
|
872 |
|
873 /** |
|
874 * Create a method check context to be used during the most specific applicability check |
|
875 */ |
|
876 ResultInfo methodCheckResult(Type to, DeferredAttr.DeferredAttrContext deferredAttrContext, |
|
877 Warner rsWarner, Type actual) { |
|
878 return attr.new ResultInfo(Kinds.VAL, to, |
|
879 new MostSpecificCheckContext(strict, deferredAttrContext, rsWarner, actual)); |
|
880 } |
|
881 |
|
882 /** |
|
883 * Subclass of method check context class that implements most specific |
|
884 * method conversion. If the actual type under analysis is a deferred type |
|
885 * a full blown structural analysis is carried out. |
|
886 */ |
|
887 class MostSpecificCheckContext extends MethodCheckContext { |
|
888 |
|
889 Type actual; |
|
890 |
|
891 public MostSpecificCheckContext(boolean strict, DeferredAttrContext deferredAttrContext, Warner rsWarner, Type actual) { |
|
892 super(strict, deferredAttrContext, rsWarner); |
|
893 this.actual = actual; |
|
894 } |
|
895 |
|
896 public boolean compatible(Type found, Type req, Warner warn) { |
|
897 if (!allowStructuralMostSpecific || actual == null) { |
|
898 return super.compatible(found, req, warn); |
|
899 } else { |
|
900 switch (actual.getTag()) { |
|
901 case DEFERRED: |
|
902 DeferredType dt = (DeferredType) actual; |
|
903 DeferredType.SpeculativeCache.Entry e = dt.speculativeCache.get(deferredAttrContext.msym, deferredAttrContext.phase); |
|
904 return (e == null || e.speculativeTree == deferredAttr.stuckTree) |
|
905 ? false : mostSpecific(found, req, e.speculativeTree, warn); |
|
906 default: |
|
907 return standaloneMostSpecific(found, req, actual, warn); |
|
908 } |
|
909 } |
|
910 } |
|
911 |
|
912 private boolean mostSpecific(Type t, Type s, JCTree tree, Warner warn) { |
|
913 MostSpecificChecker msc = new MostSpecificChecker(t, s, warn); |
|
914 msc.scan(tree); |
|
915 return msc.result; |
|
916 } |
|
917 |
|
918 boolean polyMostSpecific(Type t1, Type t2, Warner warn) { |
|
919 return (!t1.isPrimitive() && t2.isPrimitive()) |
|
920 ? true : super.compatible(t1, t2, warn); |
|
921 } |
|
922 |
|
923 boolean standaloneMostSpecific(Type t1, Type t2, Type exprType, Warner warn) { |
|
924 return (exprType.isPrimitive() == t1.isPrimitive() |
|
925 && exprType.isPrimitive() != t2.isPrimitive()) |
|
926 ? true : super.compatible(t1, t2, warn); |
|
927 } |
|
928 |
|
929 /** |
|
930 * Structural checker for most specific. |
|
931 */ |
|
932 class MostSpecificChecker extends DeferredAttr.PolyScanner { |
|
933 |
|
934 final Type t; |
|
935 final Type s; |
|
936 final Warner warn; |
|
937 boolean result; |
|
938 |
|
939 MostSpecificChecker(Type t, Type s, Warner warn) { |
|
940 this.t = t; |
|
941 this.s = s; |
|
942 this.warn = warn; |
|
943 result = true; |
|
944 } |
|
945 |
|
946 @Override |
|
947 void skip(JCTree tree) { |
|
948 result &= standaloneMostSpecific(t, s, tree.type, warn); |
|
949 } |
|
950 |
|
951 @Override |
|
952 public void visitConditional(JCConditional tree) { |
|
953 if (tree.polyKind == PolyKind.STANDALONE) { |
|
954 result &= standaloneMostSpecific(t, s, tree.type, warn); |
|
955 } else { |
|
956 super.visitConditional(tree); |
|
957 } |
|
958 } |
|
959 |
|
960 @Override |
|
961 public void visitApply(JCMethodInvocation tree) { |
|
962 result &= (tree.polyKind == PolyKind.STANDALONE) |
|
963 ? standaloneMostSpecific(t, s, tree.type, warn) |
|
964 : polyMostSpecific(t, s, warn); |
|
965 } |
|
966 |
|
967 @Override |
|
968 public void visitNewClass(JCNewClass tree) { |
|
969 result &= (tree.polyKind == PolyKind.STANDALONE) |
|
970 ? standaloneMostSpecific(t, s, tree.type, warn) |
|
971 : polyMostSpecific(t, s, warn); |
|
972 } |
|
973 |
|
974 @Override |
|
975 public void visitReference(JCMemberReference tree) { |
|
976 if (types.isFunctionalInterface(t.tsym) && |
|
977 types.isFunctionalInterface(s.tsym) && |
|
978 types.asSuper(t, s.tsym) == null && |
|
979 types.asSuper(s, t.tsym) == null) { |
|
980 Type desc_t = types.findDescriptorType(t); |
|
981 Type desc_s = types.findDescriptorType(s); |
|
982 if (types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) { |
|
983 if (!desc_s.getReturnType().hasTag(VOID)) { |
|
984 //perform structural comparison |
|
985 Type ret_t = desc_t.getReturnType(); |
|
986 Type ret_s = desc_s.getReturnType(); |
|
987 result &= ((tree.refPolyKind == PolyKind.STANDALONE) |
|
988 ? standaloneMostSpecific(ret_t, ret_s, tree.type, warn) |
|
989 : polyMostSpecific(ret_t, ret_s, warn)); |
|
990 } else { |
|
991 return; |
|
992 } |
|
993 } else { |
|
994 result &= false; |
|
995 } |
|
996 } else { |
|
997 result &= MostSpecificCheckContext.super.compatible(t, s, warn); |
|
998 } |
|
999 } |
|
1000 |
|
1001 @Override |
|
1002 public void visitLambda(JCLambda tree) { |
|
1003 if (types.isFunctionalInterface(t.tsym) && |
|
1004 types.isFunctionalInterface(s.tsym) && |
|
1005 types.asSuper(t, s.tsym) == null && |
|
1006 types.asSuper(s, t.tsym) == null) { |
|
1007 Type desc_t = types.findDescriptorType(t); |
|
1008 Type desc_s = types.findDescriptorType(s); |
|
1009 if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT |
|
1010 || types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) { |
|
1011 if (!desc_s.getReturnType().hasTag(VOID)) { |
|
1012 //perform structural comparison |
|
1013 Type ret_t = desc_t.getReturnType(); |
|
1014 Type ret_s = desc_s.getReturnType(); |
|
1015 scanLambdaBody(tree, ret_t, ret_s); |
|
1016 } else { |
|
1017 return; |
|
1018 } |
|
1019 } else { |
|
1020 result &= false; |
|
1021 } |
|
1022 } else { |
|
1023 result &= MostSpecificCheckContext.super.compatible(t, s, warn); |
|
1024 } |
|
1025 } |
|
1026 //where |
|
1027 |
|
1028 void scanLambdaBody(JCLambda lambda, final Type t, final Type s) { |
|
1029 if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) { |
|
1030 result &= MostSpecificCheckContext.this.mostSpecific(t, s, lambda.body, warn); |
|
1031 } else { |
|
1032 DeferredAttr.LambdaReturnScanner lambdaScanner = |
|
1033 new DeferredAttr.LambdaReturnScanner() { |
|
1034 @Override |
|
1035 public void visitReturn(JCReturn tree) { |
|
1036 if (tree.expr != null) { |
|
1037 result &= MostSpecificCheckContext.this.mostSpecific(t, s, tree.expr, warn); |
|
1038 } |
|
1039 } |
|
1040 }; |
|
1041 lambdaScanner.scan(lambda.body); |
|
1042 } |
|
1043 } |
|
1044 } |
|
1045 } |
|
1046 } |
|
1047 |
838 public static class InapplicableMethodException extends RuntimeException { |
1048 public static class InapplicableMethodException extends RuntimeException { |
839 private static final long serialVersionUID = 0; |
1049 private static final long serialVersionUID = 0; |
840 |
1050 |
841 JCDiagnostic diagnostic; |
1051 JCDiagnostic diagnostic; |
842 JCDiagnostic.Factory diags; |
1052 JCDiagnostic.Factory diags; |
1140 throw new AssertionError(); |
1350 throw new AssertionError(); |
1141 } |
1351 } |
1142 } |
1352 } |
1143 //where |
1353 //where |
1144 private boolean signatureMoreSpecific(List<Type> actuals, Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) { |
1354 private boolean signatureMoreSpecific(List<Type> actuals, Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) { |
1145 Symbol m12 = adjustVarargs(m1, m2, useVarargs); |
1355 noteWarner.clear(); |
1146 Symbol m22 = adjustVarargs(m2, m1, useVarargs); |
1356 int maxLength = Math.max( |
1147 Type mtype1 = types.memberType(site, m12); |
1357 Math.max(m1.type.getParameterTypes().length(), actuals.length()), |
1148 Type mtype2 = types.memberType(site, m22); |
1358 m2.type.getParameterTypes().length()); |
1149 |
1359 Type mst = instantiate(env, site, m2, null, |
1150 //check if invocation is more specific |
1360 adjustArgs(types.lowerBounds(types.memberType(site, m1).getParameterTypes()), m1, maxLength, useVarargs), null, |
1151 if (invocationMoreSpecific(env, site, m22, mtype1.getParameterTypes(), allowBoxing, useVarargs)) { |
1361 allowBoxing, useVarargs, new MostSpecificCheck(!allowBoxing, actuals), noteWarner); |
1152 return true; |
1362 return mst != null && |
1153 } |
1363 !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); |
1154 |
1364 } |
1155 //perform structural check |
1365 private List<Type> adjustArgs(List<Type> args, Symbol msym, int length, boolean allowVarargs) { |
1156 |
1366 if ((msym.flags() & VARARGS) != 0 && allowVarargs) { |
1157 List<Type> formals1 = mtype1.getParameterTypes(); |
1367 Type varargsElem = types.elemtype(args.last()); |
1158 Type lastFormal1 = formals1.last(); |
1368 if (varargsElem == null) { |
1159 List<Type> formals2 = mtype2.getParameterTypes(); |
1369 Assert.error("Bad varargs = " + args.last() + " " + msym); |
1160 Type lastFormal2 = formals2.last(); |
1370 } |
1161 ListBuffer<Type> newFormals = ListBuffer.lb(); |
1371 List<Type> newArgs = args.reverse().tail.prepend(varargsElem).reverse(); |
1162 |
1372 while (newArgs.length() < length) { |
1163 boolean hasStructuralPoly = false; |
1373 newArgs = newArgs.append(newArgs.last()); |
1164 for (Type actual : actuals) { |
1374 } |
1165 //perform formal argument adaptation in case actuals > formals (varargs) |
1375 return newArgs; |
1166 Type f1 = formals1.isEmpty() ? |
|
1167 lastFormal1 : formals1.head; |
|
1168 Type f2 = formals2.isEmpty() ? |
|
1169 lastFormal2 : formals2.head; |
|
1170 |
|
1171 //is this a structural actual argument? |
|
1172 boolean isStructuralPoly = actual.hasTag(DEFERRED) && |
|
1173 (((DeferredType)actual).tree.hasTag(LAMBDA) || |
|
1174 ((DeferredType)actual).tree.hasTag(REFERENCE)); |
|
1175 |
|
1176 Type newFormal = f1; |
|
1177 |
|
1178 if (isStructuralPoly) { |
|
1179 //for structural arguments only - check that corresponding formals |
|
1180 //are related - if so replace formal with <null> |
|
1181 hasStructuralPoly = true; |
|
1182 DeferredType dt = (DeferredType)actual; |
|
1183 Type t1 = deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, m1, currentResolutionContext.step).apply(dt); |
|
1184 Type t2 = deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, m2, currentResolutionContext.step).apply(dt); |
|
1185 if (t1.isErroneous() || t2.isErroneous() || !isStructuralSubtype(t1, t2)) { |
|
1186 //not structural subtypes - simply fail |
|
1187 return false; |
|
1188 } else { |
|
1189 newFormal = syms.botType; |
|
1190 } |
|
1191 } |
|
1192 |
|
1193 newFormals.append(newFormal); |
|
1194 if (newFormals.length() > mtype2.getParameterTypes().length()) { |
|
1195 //expand m2's type so as to fit the new formal arity (varargs) |
|
1196 m22.type = types.createMethodTypeWithParameters(m22.type, m22.type.getParameterTypes().append(f2)); |
|
1197 } |
|
1198 |
|
1199 formals1 = formals1.isEmpty() ? formals1 : formals1.tail; |
|
1200 formals2 = formals2.isEmpty() ? formals2 : formals2.tail; |
|
1201 } |
|
1202 |
|
1203 if (!hasStructuralPoly) { |
|
1204 //if no structural actual was found, we're done |
|
1205 return false; |
|
1206 } |
|
1207 //perform additional adaptation if actuals < formals (varargs) |
|
1208 for (Type t : formals1) { |
|
1209 newFormals.append(t); |
|
1210 } |
|
1211 //check if invocation (with tweaked args) is more specific |
|
1212 return invocationMoreSpecific(env, site, m22, newFormals.toList(), allowBoxing, useVarargs); |
|
1213 } |
|
1214 //where |
|
1215 private boolean invocationMoreSpecific(Env<AttrContext> env, Type site, Symbol m2, List<Type> argtypes1, boolean allowBoxing, boolean useVarargs) { |
|
1216 MethodResolutionContext prevContext = currentResolutionContext; |
|
1217 try { |
|
1218 currentResolutionContext = new MethodResolutionContext(); |
|
1219 currentResolutionContext.step = allowBoxing ? BOX : BASIC; |
|
1220 noteWarner.clear(); |
|
1221 Type mst = instantiate(env, site, m2, null, |
|
1222 types.lowerBounds(argtypes1), null, |
|
1223 allowBoxing, false, resolveMethodCheck, noteWarner); |
|
1224 return mst != null && |
|
1225 !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); |
|
1226 } finally { |
|
1227 currentResolutionContext = prevContext; |
|
1228 } |
|
1229 } |
|
1230 //where |
|
1231 private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) { |
|
1232 List<Type> fromArgs = from.type.getParameterTypes(); |
|
1233 List<Type> toArgs = to.type.getParameterTypes(); |
|
1234 if (useVarargs && |
|
1235 (from.flags() & VARARGS) != 0 && |
|
1236 (to.flags() & VARARGS) != 0) { |
|
1237 Type varargsTypeFrom = fromArgs.last(); |
|
1238 Type varargsTypeTo = toArgs.last(); |
|
1239 ListBuffer<Type> args = ListBuffer.lb(); |
|
1240 if (toArgs.length() < fromArgs.length()) { |
|
1241 //if we are checking a varargs method 'from' against another varargs |
|
1242 //method 'to' (where arity of 'to' < arity of 'from') then expand signature |
|
1243 //of 'to' to 'fit' arity of 'from' (this means adding fake formals to 'to' |
|
1244 //until 'to' signature has the same arity as 'from') |
|
1245 while (fromArgs.head != varargsTypeFrom) { |
|
1246 args.append(toArgs.head == varargsTypeTo ? types.elemtype(varargsTypeTo) : toArgs.head); |
|
1247 fromArgs = fromArgs.tail; |
|
1248 toArgs = toArgs.head == varargsTypeTo ? |
|
1249 toArgs : |
|
1250 toArgs.tail; |
|
1251 } |
|
1252 } else { |
|
1253 //formal argument list is same as original list where last |
|
1254 //argument (array type) is removed |
|
1255 args.appendList(toArgs.reverse().tail.reverse()); |
|
1256 } |
|
1257 //append varargs element type as last synthetic formal |
|
1258 args.append(types.elemtype(varargsTypeTo)); |
|
1259 Type mtype = types.createMethodTypeWithParameters(to.type, args.toList()); |
|
1260 return new MethodSymbol(to.flags_field & ~VARARGS, to.name, mtype, to.owner); |
|
1261 } else { |
1376 } else { |
1262 return to; |
1377 return args; |
1263 } |
1378 } |
1264 } |
|
1265 //where |
|
1266 boolean isStructuralSubtype(Type s, Type t) { |
|
1267 |
|
1268 Type ret_s = types.findDescriptorType(s).getReturnType(); |
|
1269 Type ret_t = types.findDescriptorType(t).getReturnType(); |
|
1270 |
|
1271 //covariant most specific check for function descriptor return type |
|
1272 if (!types.isSubtype(ret_s, ret_t)) { |
|
1273 return false; |
|
1274 } |
|
1275 |
|
1276 List<Type> args_s = types.findDescriptorType(s).getParameterTypes(); |
|
1277 List<Type> args_t = types.findDescriptorType(t).getParameterTypes(); |
|
1278 |
|
1279 //arity must be identical |
|
1280 if (args_s.length() != args_t.length()) { |
|
1281 return false; |
|
1282 } |
|
1283 |
|
1284 //invariant most specific check for function descriptor parameter types |
|
1285 if (!types.isSameTypes(args_t, args_s)) { |
|
1286 return false; |
|
1287 } |
|
1288 |
|
1289 return true; |
|
1290 } |
1379 } |
1291 //where |
1380 //where |
1292 Type mostSpecificReturnType(Type mt1, Type mt2) { |
1381 Type mostSpecificReturnType(Type mt1, Type mt2) { |
1293 Type rt1 = mt1.getReturnType(); |
1382 Type rt1 = mt1.getReturnType(); |
1294 Type rt2 = mt2.getReturnType(); |
1383 Type rt2 = mt2.getReturnType(); |