|
21 | 21 | import org.apache.groovy.util.Maps;
|
22 | 22 | import org.codehaus.groovy.GroovyBugError;
|
23 | 23 | import org.codehaus.groovy.ast.ClassNode;
|
| 24 | +import org.codehaus.groovy.ast.ConstructorNode; |
24 | 25 | import org.codehaus.groovy.ast.GenericsType;
|
25 | 26 | import org.codehaus.groovy.ast.GenericsType.GenericsTypeName;
|
26 | 27 | import org.codehaus.groovy.ast.InnerClassNode;
|
|
71 | 72 | import java.util.regex.Matcher;
|
72 | 73 | import java.util.stream.BaseStream;
|
73 | 74 |
|
74 |
| -import static java.lang.Math.min; |
75 | 75 | import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedMethod;
|
76 | 76 | import static org.apache.groovy.ast.tools.ClassNodeUtils.samePackageName;
|
77 | 77 | import static org.apache.groovy.ast.tools.ExpressionUtils.isNullConstant;
|
@@ -457,7 +457,7 @@ static int lastArgMatchesVarg(final Parameter[] parameters, final ClassNode... a
|
457 | 457 | ClassNode elementType = arrayType.getComponentType();
|
458 | 458 | ClassNode argumentType = argumentTypes[argumentTypes.length - 1];
|
459 | 459 | if (isNumberType(elementType) && isNumberType(argumentType) && !getWrapper(elementType).equals(getWrapper(argumentType))) return -1;
|
460 |
| - return isAssignableTo(argumentType, elementType) ? min(getDistance(argumentType, arrayType), getDistance(argumentType, elementType)) : -1; |
| 460 | + return isAssignableTo(argumentType, elementType) ? Math.min(getDistance(argumentType, arrayType), getDistance(argumentType, elementType)) : -1; |
461 | 461 | }
|
462 | 462 |
|
463 | 463 | /**
|
@@ -1433,39 +1433,45 @@ private static boolean typeCheckMethodsWithGenerics(final ClassNode receiver, fi
|
1433 | 1433 | }
|
1434 | 1434 |
|
1435 | 1435 | boolean failure = false;
|
| 1436 | + Set<GenericsTypeName> fixedPlaceHolders = Collections.emptySet(); |
| 1437 | + Map<GenericsTypeName, GenericsType> resolvedMethodGenerics = new HashMap<>(); |
1436 | 1438 | // correct receiver for inner class
|
1437 | 1439 | // we assume the receiver is an instance of the declaring class of the
|
1438 | 1440 | // candidate method, but findMethod returns also outer class methods
|
1439 | 1441 | // for that receiver. For now we skip receiver based checks in that case
|
1440 | 1442 | // TODO: correct generics for when receiver is to be skipped
|
1441 | 1443 | boolean skipBecauseOfInnerClassNotReceiver = !implementsInterfaceOrIsSubclassOf(receiver, candidateMethod.getDeclaringClass());
|
1442 |
| - // we have here different generics contexts we have to deal with. |
1443 |
| - // There is firstly the context given through the class, and the method. |
1444 |
| - // The method context may hide generics given through the class, but use |
1445 |
| - // the non-hidden ones. |
1446 |
| - Map<GenericsTypeName, GenericsType> resolvedMethodGenerics = new HashMap<>(); |
1447 | 1444 | if (!skipBecauseOfInnerClassNotReceiver) {
|
1448 |
| - addMethodLevelDeclaredGenerics(candidateMethod, resolvedMethodGenerics); |
1449 |
| - if (!resolvedMethodGenerics.isEmpty()) { |
1450 |
| - // first remove hidden generics |
1451 |
| - Map<GenericsTypeName, GenericsType> receiverGenerics = GenericsUtils.extractPlaceholders(receiver); |
1452 |
| - receiverGenerics.keySet().removeAll(resolvedMethodGenerics.keySet()); |
1453 |
| - // then use the remaining information to refine the method generics |
1454 |
| - applyGenericsConnections(receiverGenerics, resolvedMethodGenerics); |
1455 |
| - } |
1456 |
| - // and then start our checks with the receiver |
1457 |
| - failure = inferenceCheck(Collections.emptySet(), resolvedMethodGenerics, candidateMethod.getDeclaringClass(), receiver, false); |
1458 |
| - } |
1459 |
| - // the outside context parts till now define placeholder we are not allowed to |
1460 |
| - // generalize, thus we save that for later use... |
1461 |
| - // extension methods are special, since they set the receiver as |
1462 |
| - // first parameter. While we normally allow generalization for the first |
1463 |
| - // parameter, in case of an extension method we must not. |
1464 |
| - Set<GenericsTypeName> fixedPlaceHolders = extractResolvedPlaceHolders(resolvedMethodGenerics); |
| 1445 | + if (candidateMethod instanceof ConstructorNode) { |
| 1446 | + resolvedMethodGenerics = GenericsUtils.extractPlaceholders(receiver); |
| 1447 | + fixedPlaceHolders = new HashSet<>(resolvedMethodGenerics.keySet()); |
| 1448 | + } else { |
| 1449 | + // we have here different generics contexts we have to deal with. |
| 1450 | + // There is firstly the context given through the class, and the method. |
| 1451 | + // The method context may hide generics given through the class, but use |
| 1452 | + // the non-hidden ones. |
| 1453 | + addMethodLevelDeclaredGenerics(candidateMethod, resolvedMethodGenerics); |
| 1454 | + if (!resolvedMethodGenerics.isEmpty()) { |
| 1455 | + // first remove hidden generics |
| 1456 | + Map<GenericsTypeName, GenericsType> receiverGenerics = GenericsUtils.extractPlaceholders(receiver); |
| 1457 | + receiverGenerics.keySet().removeAll(resolvedMethodGenerics.keySet()); |
| 1458 | + // then use the remaining information to refine the method generics |
| 1459 | + applyGenericsConnections(receiverGenerics, resolvedMethodGenerics); |
| 1460 | + } |
| 1461 | + // and then start our checks with the receiver |
| 1462 | + failure = inferenceCheck(fixedPlaceHolders, resolvedMethodGenerics, candidateMethod.getDeclaringClass(), receiver, false); |
| 1463 | + // the outside context parts till now define placeholder we are not allowed to |
| 1464 | + // generalize, thus we save that for later use... |
| 1465 | + // extension methods are special, since they set the receiver as |
| 1466 | + // first parameter. While we normally allow generalization for the first |
| 1467 | + // parameter, in case of an extension method we must not. |
| 1468 | + fixedPlaceHolders = extractResolvedPlaceHolders(resolvedMethodGenerics); |
| 1469 | + } |
| 1470 | + } |
1465 | 1471 |
|
1466 | 1472 | int lastParamIndex = parameters.length - 1;
|
1467 | 1473 | for (int i = 0, n = argumentTypes.length; i < n; i += 1) {
|
1468 |
| - ClassNode parameterType = parameters[min(i, lastParamIndex)].getOriginType(); |
| 1474 | + ClassNode parameterType = parameters[Math.min(i, lastParamIndex)].getOriginType(); |
1469 | 1475 | ClassNode argumentType = StaticTypeCheckingVisitor.wrapTypeIfNecessary(argumentTypes[i]);
|
1470 | 1476 | failure |= inferenceCheck(fixedPlaceHolders, resolvedMethodGenerics, parameterType, argumentType, i >= lastParamIndex);
|
1471 | 1477 |
|
@@ -1524,6 +1530,8 @@ private static boolean inferenceCheck(final Set<GenericsTypeName> fixedPlaceHold
|
1524 | 1530 | }
|
1525 | 1531 | }
|
1526 | 1532 |
|
| 1533 | + connections.keySet().removeAll(fixedPlaceHolders); // GROOVY-10337 |
| 1534 | + |
1527 | 1535 | // apply the new information to refine the method level information so
|
1528 | 1536 | // that the information slowly becomes information for the callsite
|
1529 | 1537 | applyGenericsConnections(connections, resolvedMethodGenerics);
|
|
0 commit comments